mirror of
https://github.com/wxWidgets/Phoenix.git
synced 2025-12-15 17:20:07 +01:00
Merge branch 'swt2c-sip6'
This commit is contained in:
81
build.py
81
build.py
@@ -46,7 +46,6 @@ from buildtools.config import Config, msg, opj, posixjoin, loadETG, etg2sip, fi
|
||||
getVcsRev, runcmd, textfile_open, getSipFiles, \
|
||||
getVisCVersion, getToolsPlatformName, updateLicenseFiles, \
|
||||
TemporaryDirectory, getMSVCInfo
|
||||
from buildtools.wxpysip import sip_runner
|
||||
|
||||
import buildtools.version as version
|
||||
|
||||
@@ -1259,7 +1258,7 @@ def cmd_sip(options, args):
|
||||
base = os.path.basename(os.path.splitext(src_name)[0])
|
||||
sbf = posixjoin(cfg.SIPOUT, base) + '.sbf'
|
||||
pycode = base[1:] # remove the leading _
|
||||
pycode = posixjoin(cfg.PKGDIR, pycode) + '.py'
|
||||
pycode = opj(cfg.ROOT_DIR, cfg.PKGDIR, pycode) + '.py'
|
||||
|
||||
# Check if any of the included files are newer than the .sbf file
|
||||
# produced by the previous run of sip. If not then we don't need to
|
||||
@@ -1277,23 +1276,54 @@ def cmd_sip(options, args):
|
||||
# module's .py file
|
||||
pycode = 'pycode'+base+':'+pycode
|
||||
|
||||
sip_runner(src_name,
|
||||
abi_version = cfg.SIP_ABI, # siplib abi version
|
||||
warnings = True, # enable warning messages
|
||||
docstrings = True, # enable the automatic generation of docstrings
|
||||
release_gil = True, # always release and reacquire the GIL
|
||||
sip_module = 'wx.siplib', # the fully qualified name of the sip module
|
||||
sbf_file=sbf, # File to write the generated file lists to
|
||||
exceptions = False, # enable support for exceptions
|
||||
tracing = cfg.SIP_TRACE, # generate code with tracing enabled
|
||||
sources_dir = tmpdir, # the name of the code directory
|
||||
extracts = [pycode], # add <ID:FILE> to the list of extracts to generate
|
||||
pyi_extract=pyi_extract, # the name of the .pyi stub file
|
||||
include_dirs = [
|
||||
os.path.join(phoenixDir(), 'src'),
|
||||
os.path.join(phoenixDir(), 'sip', 'gen'),
|
||||
])
|
||||
# Write out a pyproject.toml to configure sip
|
||||
pyproject_toml = (
|
||||
'[build-system]\n'
|
||||
'requires = ["sip >=5.5.0, <7"]\n'
|
||||
'build-backend = "sipbuild.api"\n'
|
||||
'\n'
|
||||
'[tool.sip.metadata]\n'
|
||||
'name = "{base}"\n'
|
||||
'\n'
|
||||
'[tool.sip.bindings.{base}]\n'
|
||||
'docstrings = true\n'
|
||||
'release-gil = true\n'
|
||||
'exceptions = false\n'
|
||||
'tracing = {tracing}\n'
|
||||
'protected-is-public = false\n'
|
||||
'generate-extracts = [\'{extracts}\']\n'
|
||||
'pep484-pyi = false\n'
|
||||
'\n'
|
||||
'[tool.sip.project]\n'
|
||||
'abi-version = "{abi_version}"\n'
|
||||
'sip-files-dir = \'{sip_gen_dir}\'\n'
|
||||
'sip-include-dirs = [\'{src_dir}\']\n'
|
||||
'sip-module = "wx.siplib"\n'
|
||||
).format(
|
||||
base=base,
|
||||
abi_version=cfg.SIP_ABI,
|
||||
tracing=str(cfg.SIP_TRACE).lower(),
|
||||
extracts=pycode,
|
||||
src_dir=opj(phoenixDir(), 'src'),
|
||||
sip_gen_dir=opj(phoenixDir(), 'sip', 'gen'),
|
||||
)
|
||||
with open(opj(tmpdir, 'pyproject.toml'), 'w') as f:
|
||||
f.write(pyproject_toml)
|
||||
|
||||
sip_pwd = pushDir(tmpdir)
|
||||
cmd = 'sip-build --no-compile'
|
||||
runcmd(cmd)
|
||||
del sip_pwd
|
||||
|
||||
# Write out a sip build file (no longer done by sip itself)
|
||||
sip_tmp_out_dir = opj(tmpdir, 'build', base)
|
||||
sip_pwd = pushDir(sip_tmp_out_dir)
|
||||
header = glob.glob('*.h')[0]
|
||||
sources = glob.glob('*.cpp')
|
||||
del sip_pwd
|
||||
with open(sbf, 'w') as f:
|
||||
f.write("sources = {}\n".format(' '.join(sources)))
|
||||
f.write("headers = {}\n".format(header))
|
||||
|
||||
classesNeedingClassInfo = { 'sip_corewxTreeCtrl.cpp' : 'wxTreeCtrl', }
|
||||
|
||||
@@ -1302,7 +1332,7 @@ def cmd_sip(options, args):
|
||||
srcTxt = f.read()
|
||||
if keepHashLines:
|
||||
# Either just fix the pathnames in the #line lines...
|
||||
srcTxt = srcTxt.replace(tmpdir, cfg.SIPOUT)
|
||||
srcTxt = srcTxt.replace(sip_tmp_out_dir, cfg.SIPOUT)
|
||||
else:
|
||||
# ...or totally remove them by replacing those lines with ''
|
||||
import re
|
||||
@@ -1333,7 +1363,7 @@ def cmd_sip(options, args):
|
||||
# Check each file in tmpdir to see if it is different than the same file
|
||||
# in cfg.SIPOUT. If so then copy the new one to cfg.SIPOUT, otherwise
|
||||
# ignore it.
|
||||
for src in glob.glob(tmpdir + '/*'):
|
||||
for src in glob.glob(sip_tmp_out_dir + '/*'):
|
||||
dest = opj(cfg.SIPOUT, os.path.basename(src))
|
||||
if not os.path.exists(dest):
|
||||
msg('%s is a new file, copying...' % os.path.basename(src))
|
||||
@@ -1356,6 +1386,17 @@ def cmd_sip(options, args):
|
||||
# Remove tmpdir and its contents
|
||||
shutil.rmtree(tmpdir)
|
||||
|
||||
# Generate sip module code
|
||||
deleteIfExists(cfg.SIPINC)
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
cmd = 'sip-module --sdist --abi-version {} --target-dir {} wx.siplib'.format(cfg.SIP_ABI, tmpdir)
|
||||
runcmd(cmd)
|
||||
tf_name = glob.glob(tmpdir + '/*.tar*')[0]
|
||||
tf_dir = os.path.splitext(os.path.splitext(tf_name)[0])[0]
|
||||
with tarfile.open(tf_name) as tf:
|
||||
tf.extractall(tmpdir)
|
||||
shutil.move(tf_dir, cfg.SIPINC)
|
||||
|
||||
|
||||
def cmd_touch(options, args):
|
||||
cmdTimer = CommandTimer('touch')
|
||||
|
||||
@@ -1,110 +0,0 @@
|
||||
#----------------------------------------------------------------------
|
||||
# Name: buildtools.wxpysip
|
||||
# Purpose: Code to help migrate to SIP 5 with as little disruption
|
||||
# as possible.
|
||||
#
|
||||
# Author: Robin Dunn
|
||||
#
|
||||
# Created: 4-Jan-2021
|
||||
# Copyright: (c) 2021 by Total Control Software
|
||||
# License: wxWindows License
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
# NOTE: This code is mostly copied, adapted, and extended from the
|
||||
# sipbuild.legacy.sip5 module. The main intent is to make it easy to run
|
||||
# sip the same way as the legacy sip5 entry point, but without needing to
|
||||
# run a subprocess, and to also add a little missing sip 4 functionality
|
||||
# that we were depending on with the old SIP.
|
||||
import os
|
||||
|
||||
from sipbuild.code_generator import (set_globals, parse, generateCode,
|
||||
generateExtracts, generateAPI, generateXML, generateTypeHints)
|
||||
from sipbuild.exceptions import handle_exception, UserException
|
||||
from sipbuild.module import resolve_abi_version
|
||||
from sipbuild.version import SIP_VERSION, SIP_VERSION_STR
|
||||
|
||||
|
||||
def sip_runner(
|
||||
specification, # the name of the specification file [default stdin]
|
||||
sources_dir=None, # the name of the code output directory [default not generated]
|
||||
include_dirs=[], # add <DIR> to the list of directories to search when importing or including .sip files
|
||||
warnings=False, # enable warning messages [default disabled]
|
||||
docstrings=False, # enable the automatic generation of docstrings [default disabled]
|
||||
release_gil=False, # always release and reacquire the GIL [default only when specified]
|
||||
sip_module=None, # the fully qualified name of the sip module
|
||||
api_extract=None, # the name of the QScintilla API file [default not generated
|
||||
exceptions=False, # enable support for C++ exceptions [default disabled]
|
||||
tracing=False, # generate code with tracing enabled [default disabled]
|
||||
extracts=[], # add <ID:FILE> to the list of extracts to generate
|
||||
pyi_extract=None, # the name of the .pyi stub file [default not generated]
|
||||
sbf_file=None, # File to write the generated file lists to [default not generated]
|
||||
abi_version=None, # the sip ABI version
|
||||
backstops=[], # add <TAG> to the list of timeline backstops
|
||||
py_debug=False, # generate code for a debug build of Python
|
||||
warnings_are_errors=False, # warnings are handled as errors
|
||||
parts=0, # split the generated code into <FILES> files [default 1 per class]
|
||||
xml_extract=None, # file to write sip xml to
|
||||
protected_is_public=False, # enable the protected/public hack [default disabled]
|
||||
source_suffix=None, # the suffix to use for C or C++ source files [default \".c\" or \".cpp\"]
|
||||
tags=[], # add <TAG> to the list of versions/platforms to generate code for
|
||||
disabled_features=[], # add <FEATURE> to the list of disabled features
|
||||
):
|
||||
|
||||
print("Running SIP code generator on: {}".format(specification))
|
||||
|
||||
generated_files = []
|
||||
try:
|
||||
# The code generator requires the name of the sip module.
|
||||
if sources_dir is not None and sip_module is None:
|
||||
raise UserException("the name of the sip module must be given")
|
||||
|
||||
# Check the ABI version.
|
||||
abi_major, abi_minor = resolve_abi_version(abi_version).split('.')
|
||||
|
||||
# Set the globals.
|
||||
set_globals(SIP_VERSION, SIP_VERSION_STR, int(abi_major), int(abi_minor),
|
||||
UserException, include_dirs)
|
||||
|
||||
# Parse the input file.
|
||||
pt, _, _, _, tags, disabled_features = parse(specification,
|
||||
(xml_extract is None), tags, backstops, disabled_features,
|
||||
protected_is_public)
|
||||
|
||||
# Generate the bindings.
|
||||
if sources_dir is not None:
|
||||
generated_files = generateCode(pt, sources_dir, source_suffix,
|
||||
exceptions, tracing, release_gil, parts, tags,
|
||||
disabled_features, docstrings, py_debug, sip_module)
|
||||
|
||||
if sbf_file is not None:
|
||||
generateBuildFile(sbf_file, generated_files)
|
||||
|
||||
# Generate any extracts.
|
||||
generateExtracts(pt, extracts)
|
||||
|
||||
# Generate the API file.
|
||||
if api_extract is not None:
|
||||
generateAPI(pt, api_extract)
|
||||
|
||||
# Generate the type hints file.
|
||||
if pyi_extract is not None:
|
||||
generateTypeHints(pt, pyi_extract)
|
||||
|
||||
# Generate the XML file.
|
||||
if xml_extract is not None:
|
||||
generateXML(pt, xml_extract)
|
||||
|
||||
except Exception as e:
|
||||
handle_exception(e)
|
||||
|
||||
return generated_files
|
||||
|
||||
|
||||
def generateBuildFile(sbf_file, generated_files):
|
||||
header, sources = generated_files
|
||||
header = os.path.basename(header)
|
||||
sources = [os.path.basename(n) for n in sources]
|
||||
with open(sbf_file, 'w') as f:
|
||||
f.write("sources = {}\n".format(' '.join(sources)))
|
||||
f.write("headers = {}\n".format(header))
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
appdirs
|
||||
setuptools < 45 ; python_version < '3.0'
|
||||
setuptools ; python_version >= '3.0'
|
||||
sip == 5.5.0
|
||||
sip == 6.6.2
|
||||
|
||||
wheel
|
||||
twine
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
RIVERBANK COMPUTING LIMITED LICENSE AGREEMENT FOR SIP
|
||||
|
||||
1. This LICENSE AGREEMENT is between Riverbank Computing Limited ("Riverbank"),
|
||||
and the Individual or Organization ("Licensee") accessing and otherwise using
|
||||
SIP software in source or binary form and its associated documentation. SIP
|
||||
comprises a software tool for generating Python bindings for software C and C++
|
||||
libraries, and a Python extension module used at runtime by those generated
|
||||
bindings.
|
||||
|
||||
2. Subject to the terms and conditions of this License Agreement, Riverbank
|
||||
hereby grants Licensee a nonexclusive, royalty-free, world-wide license to
|
||||
reproduce, analyze, test, perform and/or display publicly, prepare derivative
|
||||
works, distribute, and otherwise use SIP alone or in any derivative version,
|
||||
provided, however, that Riverbank's License Agreement and Riverbank's notice of
|
||||
copyright, e.g., "Copyright (c) 2015 Riverbank Computing Limited; All Rights
|
||||
Reserved" are retained in SIP alone or in any derivative version prepared by
|
||||
Licensee.
|
||||
|
||||
3. In the event Licensee prepares a derivative work that is based on or
|
||||
incorporates SIP or any part thereof, and wants to make the derivative work
|
||||
available to others as provided herein, then Licensee hereby agrees to include
|
||||
in any such work a brief summary of the changes made to SIP.
|
||||
|
||||
4. Licensee may not use SIP to generate Python bindings for any C or C++
|
||||
library for which bindings are already provided by Riverbank.
|
||||
|
||||
5. Riverbank is making SIP available to Licensee on an "AS IS" basis.
|
||||
RIVERBANK MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY
|
||||
OF EXAMPLE, BUT NOT LIMITATION, RIVERBANK MAKES NO AND DISCLAIMS ANY
|
||||
REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR
|
||||
PURPOSE OR THAT THE USE OF SIP WILL NOT INFRINGE ANY THIRD PARTY RIGHTS.
|
||||
|
||||
6. RIVERBANK SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF SIP FOR ANY
|
||||
INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF MODIFYING,
|
||||
DISTRIBUTING, OR OTHERWISE USING SIP, OR ANY DERIVATIVE THEREOF, EVEN IF
|
||||
ADVISED OF THE POSSIBILITY THEREOF.
|
||||
|
||||
7. This License Agreement will automatically terminate upon a material breach
|
||||
of its terms and conditions.
|
||||
|
||||
8. Nothing in this License Agreement shall be deemed to create any relationship
|
||||
of agency, partnership, or joint venture between Riverbank and Licensee. This
|
||||
License Agreement does not grant permission to use Riverbank trademarks or
|
||||
trade name in a trademark sense to endorse or promote products or services of
|
||||
Licensee, or any third party.
|
||||
|
||||
9. By copying, installing or otherwise using SIP, Licensee agrees to be bound
|
||||
by the terms and conditions of this License Agreement.
|
||||
@@ -1,11 +0,0 @@
|
||||
This folder contains a copy of the SIP runtime library code. It is
|
||||
here so we can make it part of the wxPython build instead of needing
|
||||
to have a dependency upon SIP already being installed on user
|
||||
machines.
|
||||
|
||||
3rd party extension modules that need to use or interact with wxPython
|
||||
types or other items will need to ensure that they #include the sip.h
|
||||
located in this folder so they will know the proper module name to
|
||||
import to find this version of the runtime library. This feature was
|
||||
added in SIP 4.12.
|
||||
|
||||
@@ -1,300 +0,0 @@
|
||||
/*
|
||||
* The implementation of the support for setting API versions.
|
||||
*
|
||||
* Copyright (c) 2019 Riverbank Computing Limited <info@riverbankcomputing.com>
|
||||
*
|
||||
* This file is part of SIP.
|
||||
*
|
||||
* This copy of SIP is licensed for use under the terms of the SIP License
|
||||
* Agreement. See the file LICENSE for more details.
|
||||
*
|
||||
* This copy of SIP may also used under the terms of the GNU General Public
|
||||
* License v2 or v3 as published by the Free Software Foundation which can be
|
||||
* found in the files LICENSE-GPL2 and LICENSE-GPL3 included in this package.
|
||||
*
|
||||
* SIP is supplied WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*/
|
||||
|
||||
|
||||
#include <Python.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "sipint.h"
|
||||
|
||||
|
||||
/*
|
||||
* The structure that defines the version number of an API.
|
||||
*/
|
||||
typedef struct _apiVersionDef {
|
||||
/* The name of the API. */
|
||||
const char *api_name;
|
||||
|
||||
/*
|
||||
* The version number of the API. This will either be set explicitly via
|
||||
* a call to sip.setapi() or implicitly by an imported module.
|
||||
*/
|
||||
int version_nr;
|
||||
|
||||
/* The next in the list of APIs. */
|
||||
struct _apiVersionDef *next;
|
||||
} apiVersionDef;
|
||||
|
||||
|
||||
/*
|
||||
* The list of API versions.
|
||||
*/
|
||||
static apiVersionDef *api_versions = NULL;
|
||||
|
||||
|
||||
/*
|
||||
* Forward declarations.
|
||||
*/
|
||||
static int add_api(const char *api, int version_nr);
|
||||
static apiVersionDef *find_api(const char *api);
|
||||
|
||||
|
||||
/*
|
||||
* See if a range of versions of a particular API is enabled.
|
||||
*/
|
||||
int sip_api_is_api_enabled(const char *name, int from, int to)
|
||||
{
|
||||
const apiVersionDef *avd;
|
||||
|
||||
if ((avd = find_api(name)) == NULL)
|
||||
return FALSE;
|
||||
|
||||
if (from > 0 && avd->version_nr < from)
|
||||
return FALSE;
|
||||
|
||||
if (to > 0 && avd->version_nr >= to)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Initialise the the API for a module and return a negative value on error.
|
||||
*/
|
||||
int sipInitAPI(sipExportedModuleDef *em, PyObject *mod_dict)
|
||||
{
|
||||
int *apis, i;
|
||||
sipVersionedFunctionDef *vf;
|
||||
sipTypeDef **tdp;
|
||||
|
||||
/* See if the module defines any APIs. */
|
||||
if ((apis = em->em_versions) != NULL)
|
||||
{
|
||||
while (apis[0] >= 0)
|
||||
{
|
||||
/*
|
||||
* See if it is an API definition rather than a range
|
||||
* definition.
|
||||
*/
|
||||
if (apis[2] < 0)
|
||||
{
|
||||
const char *api_name;
|
||||
const apiVersionDef *avd;
|
||||
|
||||
api_name = sipNameFromPool(em, apis[0]);
|
||||
|
||||
/* Use the default version if not already set explicitly. */
|
||||
if ((avd = find_api(api_name)) == NULL)
|
||||
if (add_api(api_name, apis[1]) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
apis += 3;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add any versioned global functions to the module dictionary. */
|
||||
if ((vf = em->em_versioned_functions) != NULL)
|
||||
{
|
||||
while (vf->vf_name >= 0)
|
||||
{
|
||||
if (sipIsRangeEnabled(em, vf->vf_api_range))
|
||||
{
|
||||
const char *func_name = sipNameFromPool(em, vf->vf_name);
|
||||
PyMethodDef *pmd;
|
||||
PyObject *py_func;
|
||||
|
||||
if ((pmd = sip_api_malloc(sizeof (PyMethodDef))) == NULL)
|
||||
return -1;
|
||||
|
||||
pmd->ml_name = func_name;
|
||||
pmd->ml_meth = vf->vf_function;
|
||||
pmd->ml_flags = vf->vf_flags;
|
||||
pmd->ml_doc = vf->vf_docstring;
|
||||
|
||||
if ((py_func = PyCFunction_New(pmd, NULL)) == NULL)
|
||||
return -1;
|
||||
|
||||
if (PyDict_SetItemString(mod_dict, func_name, py_func) < 0)
|
||||
{
|
||||
Py_DECREF(py_func);
|
||||
return -1;
|
||||
}
|
||||
|
||||
Py_DECREF(py_func);
|
||||
}
|
||||
|
||||
++vf;
|
||||
}
|
||||
}
|
||||
|
||||
/* Update the types table according to any version information. */
|
||||
for (tdp = em->em_types, i = 0; i < em->em_nrtypes; ++i, ++tdp)
|
||||
{
|
||||
sipTypeDef *td;
|
||||
|
||||
if ((td = *tdp) != NULL && td->td_version >= 0)
|
||||
{
|
||||
do
|
||||
{
|
||||
if (sipIsRangeEnabled(em, td->td_version))
|
||||
{
|
||||
/* Update the type with the enabled version. */
|
||||
*tdp = td;
|
||||
break;
|
||||
}
|
||||
}
|
||||
while ((td = td->td_next_version) != NULL);
|
||||
|
||||
/*
|
||||
* If there is no enabled version then stub the disabled version
|
||||
* so that we don't lose the name from the (sorted) types table.
|
||||
*/
|
||||
if (td == NULL)
|
||||
sipTypeSetStub(*tdp);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Get the version number for an API.
|
||||
*/
|
||||
PyObject *sipGetAPI(PyObject *self, PyObject *args)
|
||||
{
|
||||
const char *api;
|
||||
const apiVersionDef *avd;
|
||||
|
||||
(void)self;
|
||||
|
||||
if (sip_api_deprecated(NULL, "getapi") < 0)
|
||||
return NULL;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "s:getapi", &api))
|
||||
return NULL;
|
||||
|
||||
if ((avd = find_api(api)) == NULL)
|
||||
{
|
||||
PyErr_Format(PyExc_ValueError, "unknown API '%s'", api);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return PyLong_FromLong(avd->version_nr);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Set the version number for an API.
|
||||
*/
|
||||
PyObject *sipSetAPI(PyObject *self, PyObject *args)
|
||||
{
|
||||
const char *api;
|
||||
int version_nr;
|
||||
const apiVersionDef *avd;
|
||||
|
||||
(void)self;
|
||||
|
||||
if (sip_api_deprecated(NULL, "setapi") < 0)
|
||||
return NULL;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "si:setapi", &api, &version_nr))
|
||||
return NULL;
|
||||
|
||||
if (version_nr < 1)
|
||||
{
|
||||
PyErr_Format(PyExc_ValueError,
|
||||
"API version numbers must be greater or equal to 1, not %d",
|
||||
version_nr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((avd = find_api(api)) == NULL)
|
||||
{
|
||||
char *api_copy;
|
||||
|
||||
/* Make a deep copy of the name. */
|
||||
if ((api_copy = sip_api_malloc(strlen(api) + 1)) == NULL)
|
||||
return NULL;
|
||||
|
||||
strcpy(api_copy, api);
|
||||
|
||||
if (add_api(api_copy, version_nr) < 0)
|
||||
return NULL;
|
||||
}
|
||||
else if (avd->version_nr != version_nr)
|
||||
{
|
||||
PyErr_Format(PyExc_ValueError,
|
||||
"API '%s' has already been set to version %d", api,
|
||||
avd->version_nr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Add a new API to the global list returning a negative value on error.
|
||||
*/
|
||||
static int add_api(const char *api, int version_nr)
|
||||
{
|
||||
apiVersionDef *avd;
|
||||
|
||||
if ((avd = sip_api_malloc(sizeof (apiVersionDef))) == NULL)
|
||||
return -1;
|
||||
|
||||
avd->api_name = api;
|
||||
avd->version_nr = version_nr;
|
||||
avd->next = api_versions;
|
||||
|
||||
api_versions = avd;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Return the definition for the given API, or NULL if there was none.
|
||||
*/
|
||||
static apiVersionDef *find_api(const char *api)
|
||||
{
|
||||
apiVersionDef *avd;
|
||||
|
||||
for (avd = api_versions; avd != NULL; avd = avd->next)
|
||||
if (strcmp(avd->api_name, api) == 0)
|
||||
break;
|
||||
|
||||
return avd;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Return TRUE if a range defined by a range index is enabled.
|
||||
*/
|
||||
int sipIsRangeEnabled(sipExportedModuleDef *em, int range_index)
|
||||
{
|
||||
int *range = &em->em_versions[range_index * 3];
|
||||
const char *api_name = sipNameFromPool(em, range[0]);
|
||||
|
||||
return sip_api_is_api_enabled(api_name, range[1], range[2]);
|
||||
}
|
||||
@@ -1,703 +0,0 @@
|
||||
/*
|
||||
* This file implements the API for the array type.
|
||||
*
|
||||
* Copyright (c) 2019 Riverbank Computing Limited <info@riverbankcomputing.com>
|
||||
*
|
||||
* This file is part of SIP.
|
||||
*
|
||||
* This copy of SIP is licensed for use under the terms of the SIP License
|
||||
* Agreement. See the file LICENSE for more details.
|
||||
*
|
||||
* This copy of SIP may also used under the terms of the GNU General Public
|
||||
* License v2 or v3 as published by the Free Software Foundation which can be
|
||||
* found in the files LICENSE-GPL2 and LICENSE-GPL3 included in this package.
|
||||
*
|
||||
* SIP is supplied WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*/
|
||||
|
||||
|
||||
#include <Python.h>
|
||||
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "sipint.h"
|
||||
|
||||
#include "array.h"
|
||||
|
||||
|
||||
/* The object data structure. */
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
void *data;
|
||||
const sipTypeDef *td;
|
||||
const char *format;
|
||||
size_t stride;
|
||||
Py_ssize_t len;
|
||||
int flags;
|
||||
PyObject *owner;
|
||||
} sipArrayObject;
|
||||
|
||||
|
||||
static int check_writable(sipArrayObject *array);
|
||||
static int check_index(sipArrayObject *array, Py_ssize_t idx);
|
||||
static void *get_value(sipArrayObject *array, PyObject *value);
|
||||
static void *get_slice(sipArrayObject *array, PyObject *value, Py_ssize_t len);
|
||||
static void bad_key(PyObject *key);
|
||||
static void *element(sipArrayObject *array, Py_ssize_t idx);
|
||||
static PyObject *make_array(void *data, const sipTypeDef *td,
|
||||
const char *format, size_t stride, Py_ssize_t len, int flags,
|
||||
PyObject *owner);
|
||||
|
||||
|
||||
/*
|
||||
* Implement len() for the type.
|
||||
*/
|
||||
static Py_ssize_t sipArray_length(PyObject *self)
|
||||
{
|
||||
return ((sipArrayObject *)self)->len;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Implement sequence item sub-script for the type.
|
||||
*/
|
||||
static PyObject *sipArray_item(PyObject *self, Py_ssize_t idx)
|
||||
{
|
||||
sipArrayObject *array = (sipArrayObject *)self;
|
||||
PyObject *py_item;
|
||||
void *data;
|
||||
|
||||
if (check_index(array, idx) < 0)
|
||||
return NULL;
|
||||
|
||||
data = element(array, idx);
|
||||
|
||||
if (array->td != NULL)
|
||||
{
|
||||
py_item = sip_api_convert_from_type(data, array->td, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (*array->format)
|
||||
{
|
||||
case 'b':
|
||||
py_item = PyLong_FromLong(*(char *)data);
|
||||
break;
|
||||
|
||||
case 'B':
|
||||
py_item = PyLong_FromUnsignedLong(*(unsigned char *)data);
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
py_item = PyLong_FromLong(*(short *)data);
|
||||
break;
|
||||
|
||||
case 'H':
|
||||
py_item = PyLong_FromUnsignedLong(*(unsigned short *)data);
|
||||
break;
|
||||
|
||||
case 'i':
|
||||
py_item = PyLong_FromLong(*(int *)data);
|
||||
break;
|
||||
|
||||
case 'I':
|
||||
py_item = PyLong_FromUnsignedLong(*(unsigned int *)data);
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
py_item = PyFloat_FromDouble(*(float *)data);
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
py_item = PyFloat_FromDouble(*(double *)data);
|
||||
break;
|
||||
|
||||
default:
|
||||
py_item = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return py_item;
|
||||
}
|
||||
|
||||
|
||||
/* The sequence methods data structure. */
|
||||
static PySequenceMethods sipArray_SequenceMethods = {
|
||||
sipArray_length, /* sq_length */
|
||||
0, /* sq_concat */
|
||||
0, /* sq_repeat */
|
||||
sipArray_item, /* sq_item */
|
||||
0, /* sq_slice */
|
||||
0, /* sq_ass_item */
|
||||
0, /* sq_ass_slice */
|
||||
0, /* sq_contains */
|
||||
0, /* sq_inplace_concat */
|
||||
0, /* sq_inplace_repeat */
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Implement mapping sub-script for the type.
|
||||
*/
|
||||
static PyObject *sipArray_subscript(PyObject *self, PyObject *key)
|
||||
{
|
||||
sipArrayObject *array = (sipArrayObject *)self;
|
||||
|
||||
if (PyIndex_Check(key))
|
||||
{
|
||||
Py_ssize_t idx = PyNumber_AsSsize_t(key, PyExc_IndexError);
|
||||
|
||||
if (idx == -1 && PyErr_Occurred())
|
||||
return NULL;
|
||||
|
||||
if (idx < 0)
|
||||
idx += array->len;
|
||||
|
||||
return sipArray_item(self, idx);
|
||||
}
|
||||
|
||||
if (PySlice_Check(key))
|
||||
{
|
||||
Py_ssize_t start, stop, step, slicelength;
|
||||
|
||||
if (sip_api_convert_from_slice_object(key, array->len, &start, &stop, &step, &slicelength) < 0)
|
||||
return NULL;
|
||||
|
||||
if (step != 1)
|
||||
{
|
||||
PyErr_SetNone(PyExc_NotImplementedError);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return make_array(element(array->data, start), array->td,
|
||||
array->format, array->stride, slicelength,
|
||||
(array->flags & ~SIP_OWNS_MEMORY), array->owner);
|
||||
}
|
||||
|
||||
bad_key(key);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Implement mapping assignment sub-script for the type.
|
||||
*/
|
||||
static int sipArray_ass_subscript(PyObject *self, PyObject *key,
|
||||
PyObject *value)
|
||||
{
|
||||
sipArrayObject *array = (sipArrayObject *)self;
|
||||
Py_ssize_t start, len;
|
||||
void *value_data;
|
||||
|
||||
if (check_writable(array) < 0)
|
||||
return -1;
|
||||
|
||||
if (PyIndex_Check(key))
|
||||
{
|
||||
start = PyNumber_AsSsize_t(key, PyExc_IndexError);
|
||||
|
||||
if (start == -1 && PyErr_Occurred())
|
||||
return -1;
|
||||
|
||||
if (start < 0)
|
||||
start += array->len;
|
||||
|
||||
if (check_index(array, start) < 0)
|
||||
return -1;
|
||||
|
||||
if ((value_data = get_value(array, value)) == NULL)
|
||||
return -1;
|
||||
|
||||
len = 1;
|
||||
}
|
||||
else if (PySlice_Check(key))
|
||||
{
|
||||
Py_ssize_t stop, step;
|
||||
|
||||
if (sip_api_convert_from_slice_object(key, array->len, &start, &stop, &step, &len) < 0)
|
||||
return -1;
|
||||
|
||||
if (step != 1)
|
||||
{
|
||||
PyErr_SetNone(PyExc_NotImplementedError);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((value_data = get_slice(array, value, len)) == NULL)
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
bad_key(key);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
memmove(element(array, start), value_data, len * array->stride);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* The mapping methods data structure. */
|
||||
static PyMappingMethods sipArray_MappingMethods = {
|
||||
sipArray_length, /* mp_length */
|
||||
sipArray_subscript, /* mp_subscript */
|
||||
sipArray_ass_subscript, /* mp_ass_subscript */
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* The buffer implementation for Python v2.6.3 and later.
|
||||
*/
|
||||
static int sipArray_getbuffer(PyObject *self, Py_buffer *view, int flags)
|
||||
{
|
||||
sipArrayObject *array = (sipArrayObject *)self;
|
||||
|
||||
if (view == NULL)
|
||||
return 0;
|
||||
|
||||
if (((flags & PyBUF_WRITABLE) == PyBUF_WRITABLE) && (array->flags & SIP_READ_ONLY))
|
||||
{
|
||||
PyErr_SetString(PyExc_BufferError, "object is not writable.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
view->obj = self;
|
||||
Py_INCREF(self);
|
||||
|
||||
view->buf = array->data;
|
||||
view->len = array->len;
|
||||
view->readonly = (array->flags & SIP_READ_ONLY);
|
||||
view->itemsize = array->stride;
|
||||
|
||||
view->format = NULL;
|
||||
if ((flags & PyBUF_FORMAT) == PyBUF_FORMAT)
|
||||
view->format = (char *)array->format;
|
||||
|
||||
view->ndim = 1;
|
||||
|
||||
view->shape = NULL;
|
||||
if ((flags & PyBUF_ND) == PyBUF_ND)
|
||||
view->shape = &view->len;
|
||||
|
||||
view->strides = NULL;
|
||||
if ((flags & PyBUF_STRIDES) == PyBUF_STRIDES)
|
||||
view->strides = &view->itemsize;
|
||||
|
||||
view->suboffsets = NULL;
|
||||
view->internal = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* The buffer methods data structure. */
|
||||
static PyBufferProcs sipArray_BufferProcs = {
|
||||
sipArray_getbuffer, /* bf_getbuffer */
|
||||
0 /* bf_releasebuffer */
|
||||
};
|
||||
|
||||
|
||||
/* The instance deallocation function. */
|
||||
static void sipArray_dealloc(PyObject *self)
|
||||
{
|
||||
sipArrayObject *array = (sipArrayObject *)self;
|
||||
|
||||
if (array->flags & SIP_OWNS_MEMORY)
|
||||
sip_api_free(array->data);
|
||||
else
|
||||
Py_XDECREF(array->owner);
|
||||
}
|
||||
|
||||
|
||||
/* The type data structure. */
|
||||
PyTypeObject sipArray_Type = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0)
|
||||
"sip.array", /* tp_name */
|
||||
sizeof (sipArrayObject), /* tp_basicsize */
|
||||
0, /* tp_itemsize */
|
||||
sipArray_dealloc, /* tp_dealloc */
|
||||
0, /* tp_print */
|
||||
0, /* tp_getattr */
|
||||
0, /* tp_setattr */
|
||||
0, /* tp_reserved */
|
||||
0, /* tp_repr */
|
||||
0, /* tp_as_number */
|
||||
&sipArray_SequenceMethods, /* tp_as_sequence */
|
||||
&sipArray_MappingMethods, /* tp_as_mapping */
|
||||
0, /* tp_hash */
|
||||
0, /* tp_call */
|
||||
0, /* tp_str */
|
||||
0, /* tp_getattro */
|
||||
0, /* tp_setattro */
|
||||
&sipArray_BufferProcs, /* tp_as_buffer */
|
||||
#if defined(Py_TPFLAGS_HAVE_NEWBUFFER)
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_NEWBUFFER, /* tp_flags */
|
||||
#else
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
|
||||
#endif
|
||||
0, /* tp_doc */
|
||||
0, /* tp_traverse */
|
||||
0, /* tp_clear */
|
||||
0, /* tp_richcompare */
|
||||
0, /* 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 */
|
||||
0, /* tp_new */
|
||||
0, /* 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, /* tp_version_tag */
|
||||
0, /* tp_finalize */
|
||||
#if PY_VERSION_HEX >= 0x03080000
|
||||
0, /* tp_vectorcall */
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Check that an array is writable.
|
||||
*/
|
||||
static int check_writable(sipArrayObject *array)
|
||||
{
|
||||
if (array->flags & SIP_READ_ONLY)
|
||||
{
|
||||
PyErr_SetString(PyExc_TypeError, "sip.array object is read-only");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Check that an index is valid for an array.
|
||||
*/
|
||||
static int check_index(sipArrayObject *array, Py_ssize_t idx)
|
||||
{
|
||||
if (idx >= 0 && idx < array->len)
|
||||
return 0;
|
||||
|
||||
PyErr_SetString(PyExc_IndexError, "index out of bounds");
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Raise an exception about a bad sub-script key.
|
||||
*/
|
||||
static void bad_key(PyObject *key)
|
||||
{
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"cannot index a sip.array object using '%s'",
|
||||
Py_TYPE(key)->tp_name);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Get the address of an element of an array.
|
||||
*/
|
||||
static void *element(sipArrayObject *array, Py_ssize_t idx)
|
||||
{
|
||||
return (unsigned char *)(array->data) + idx * array->stride;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Get the address of a value that will be copied to an array.
|
||||
*/
|
||||
static void *get_value(sipArrayObject *array, PyObject *value)
|
||||
{
|
||||
static union {
|
||||
signed char s_char_t;
|
||||
unsigned char u_char_t;
|
||||
signed short s_short_t;
|
||||
unsigned short u_short_t;
|
||||
signed int s_int_t;
|
||||
unsigned int u_int_t;
|
||||
float float_t;
|
||||
double double_t;
|
||||
} static_data;
|
||||
|
||||
void *data;
|
||||
|
||||
if (array->td != NULL)
|
||||
{
|
||||
int iserr = FALSE;
|
||||
|
||||
data = sip_api_force_convert_to_type(value, array->td, NULL,
|
||||
SIP_NOT_NONE|SIP_NO_CONVERTORS, NULL, &iserr);
|
||||
}
|
||||
else
|
||||
{
|
||||
PyErr_Clear();
|
||||
|
||||
switch (*array->format)
|
||||
{
|
||||
case 'b':
|
||||
static_data.s_char_t = sip_api_long_as_char(value);
|
||||
data = &static_data.s_char_t;
|
||||
break;
|
||||
|
||||
case 'B':
|
||||
static_data.u_char_t = sip_api_long_as_unsigned_char(value);
|
||||
data = &static_data.u_char_t;
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
static_data.s_short_t = sip_api_long_as_short(value);
|
||||
data = &static_data.s_short_t;
|
||||
break;
|
||||
|
||||
case 'H':
|
||||
static_data.u_short_t = sip_api_long_as_unsigned_short(value);
|
||||
data = &static_data.u_short_t;
|
||||
break;
|
||||
|
||||
case 'i':
|
||||
static_data.s_int_t = sip_api_long_as_int(value);
|
||||
data = &static_data.s_int_t;
|
||||
break;
|
||||
|
||||
case 'I':
|
||||
static_data.u_int_t = sip_api_long_as_unsigned_int(value);
|
||||
data = &static_data.u_int_t;
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
static_data.float_t = (float)PyFloat_AsDouble(value);
|
||||
data = &static_data.float_t;
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
static_data.double_t = PyFloat_AsDouble(value);
|
||||
data = &static_data.double_t;
|
||||
break;
|
||||
|
||||
default:
|
||||
data = NULL;
|
||||
}
|
||||
|
||||
if (PyErr_Occurred())
|
||||
data = NULL;
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Get the address of an value that will be copied to an array slice.
|
||||
*/
|
||||
static void *get_slice(sipArrayObject *array, PyObject *value, Py_ssize_t len)
|
||||
{
|
||||
sipArrayObject *other = (sipArrayObject *)value;
|
||||
|
||||
if (!PyObject_IsInstance(value, (PyObject *)&sipArray_Type) || array->td != other->td || strcmp(array->format, other->format) != 0)
|
||||
{
|
||||
const char *type;
|
||||
|
||||
if (array->td != NULL)
|
||||
{
|
||||
type = sipTypeName(array->td);
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (*array->format)
|
||||
{
|
||||
case 'b':
|
||||
type = "char";
|
||||
break;
|
||||
|
||||
case 'B':
|
||||
type = "unsigned char";
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
type = "short";
|
||||
break;
|
||||
|
||||
case 'H':
|
||||
type = "unsigned short";
|
||||
break;
|
||||
|
||||
case 'i':
|
||||
type = "int";
|
||||
break;
|
||||
|
||||
case 'I':
|
||||
type = "unsigned int";
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
type = "float";
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
type = "double";
|
||||
break;
|
||||
|
||||
default:
|
||||
type = "";
|
||||
}
|
||||
}
|
||||
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"can only assign another array of %s to the slice", type);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (other->len != len)
|
||||
{
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"the array being assigned must have length %zd", len);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (other->stride == array->stride)
|
||||
{
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"the array being assigned must have stride %zu",
|
||||
array->stride);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return other->data;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Do the work of creating an array.
|
||||
*/
|
||||
static PyObject *make_array(void *data, const sipTypeDef *td,
|
||||
const char *format, size_t stride, Py_ssize_t len, int flags,
|
||||
PyObject *owner)
|
||||
{
|
||||
sipArrayObject *array;
|
||||
|
||||
if ((array = PyObject_NEW(sipArrayObject, &sipArray_Type)) == NULL)
|
||||
return NULL;
|
||||
|
||||
array->data = data;
|
||||
array->td = td;
|
||||
array->format = format;
|
||||
array->stride = stride;
|
||||
array->len = len;
|
||||
array->flags = flags;
|
||||
|
||||
if (flags & SIP_OWNS_MEMORY)
|
||||
{
|
||||
/* This is a borrowed reference to itself. */
|
||||
array->owner = (PyObject *)array;
|
||||
}
|
||||
else
|
||||
{
|
||||
Py_XINCREF(owner);
|
||||
array->owner = owner;
|
||||
}
|
||||
|
||||
return (PyObject *)array;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Wrap an array of instances of a fundamental type. At the moment format must
|
||||
* be either "b" (char), "B" (unsigned char), "h" (short), "H" (unsigned
|
||||
* short), "i" (int), "I" (unsigned int), "f" (float) or "d" (double).
|
||||
*/
|
||||
PyObject *sip_api_convert_to_array(void *data, const char *format,
|
||||
Py_ssize_t len, int flags)
|
||||
{
|
||||
size_t stride;
|
||||
|
||||
if (data == NULL)
|
||||
{
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
switch (*format)
|
||||
{
|
||||
case 'b':
|
||||
stride = sizeof (char);
|
||||
break;
|
||||
|
||||
case 'B':
|
||||
stride = sizeof (unsigned char);
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
stride = sizeof (short);
|
||||
break;
|
||||
|
||||
case 'H':
|
||||
stride = sizeof (unsigned short);
|
||||
break;
|
||||
|
||||
case 'i':
|
||||
stride = sizeof (int);
|
||||
break;
|
||||
|
||||
case 'I':
|
||||
stride = sizeof (unsigned int);
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
stride = sizeof (float);
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
stride = sizeof (double);
|
||||
break;
|
||||
|
||||
default:
|
||||
stride = 0;
|
||||
}
|
||||
|
||||
assert(stride > 0);
|
||||
assert(len >= 0);
|
||||
|
||||
return make_array(data, NULL, format, stride, len, flags, NULL);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Wrap an array of instances of a defined type.
|
||||
*/
|
||||
PyObject *sip_api_convert_to_typed_array(void *data, const sipTypeDef *td,
|
||||
const char *format, size_t stride, Py_ssize_t len, int flags)
|
||||
{
|
||||
if (data == NULL)
|
||||
{
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
assert(stride > 0);
|
||||
assert(len >= 0);
|
||||
|
||||
return make_array(data, td, format, stride, len, flags, NULL);
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
/*
|
||||
* This file defines the API for the array type.
|
||||
*
|
||||
* Copyright (c) 2019 Riverbank Computing Limited <info@riverbankcomputing.com>
|
||||
*
|
||||
* This file is part of SIP.
|
||||
*
|
||||
* This copy of SIP is licensed for use under the terms of the SIP License
|
||||
* Agreement. See the file LICENSE for more details.
|
||||
*
|
||||
* This copy of SIP may also used under the terms of the GNU General Public
|
||||
* License v2 or v3 as published by the Free Software Foundation which can be
|
||||
* found in the files LICENSE-GPL2 and LICENSE-GPL3 included in this package.
|
||||
*
|
||||
* SIP is supplied WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _ARRAY_H
|
||||
#define _ARRAY_H
|
||||
|
||||
|
||||
#include <Python.h>
|
||||
|
||||
#include "sipint.h"
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
extern PyTypeObject sipArray_Type;
|
||||
|
||||
PyObject *sip_api_convert_to_array(void *data, const char *format,
|
||||
Py_ssize_t len, int flags);
|
||||
PyObject *sip_api_convert_to_typed_array(void *data, const sipTypeDef *td,
|
||||
const char *format, size_t stride, Py_ssize_t len, int flags);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,22 +0,0 @@
|
||||
// This contains all the C++ code that is needed by the sip module.
|
||||
//
|
||||
// Copyright (c) 2015 Riverbank Computing Limited <info@riverbankcomputing.com>
|
||||
//
|
||||
// This file is part of SIP.
|
||||
//
|
||||
// This copy of SIP is licensed for use under the terms of the SIP License
|
||||
// Agreement. See the file LICENSE for more details.
|
||||
//
|
||||
// This copy of SIP may also used under the terms of the GNU General Public
|
||||
// License v2 or v3 as published by the Free Software Foundation which can be
|
||||
// found in the files LICENSE-GPL2 and LICENSE-GPL3 included in this package.
|
||||
//
|
||||
// SIP is supplied WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
|
||||
// Set a C++ bool for the main C implementation of the module.
|
||||
extern "C" void sipSetBool(void *ptr, int val)
|
||||
{
|
||||
*reinterpret_cast<bool *>(ptr) = !!val;
|
||||
}
|
||||
@@ -1,478 +0,0 @@
|
||||
/*
|
||||
* The implementation of the different descriptors.
|
||||
*
|
||||
* Copyright (c) 2019 Riverbank Computing Limited <info@riverbankcomputing.com>
|
||||
*
|
||||
* This file is part of SIP.
|
||||
*
|
||||
* This copy of SIP is licensed for use under the terms of the SIP License
|
||||
* Agreement. See the file LICENSE for more details.
|
||||
*
|
||||
* This copy of SIP may also used under the terms of the GNU General Public
|
||||
* License v2 or v3 as published by the Free Software Foundation which can be
|
||||
* found in the files LICENSE-GPL2 and LICENSE-GPL3 included in this package.
|
||||
*
|
||||
* SIP is supplied WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*/
|
||||
|
||||
|
||||
#include <Python.h>
|
||||
|
||||
#include "sipint.h"
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* A method descriptor. We don't use the similar Python descriptor because it
|
||||
* doesn't support a method having static and non-static overloads, and we
|
||||
* handle mixins via a delegate.
|
||||
*****************************************************************************/
|
||||
|
||||
|
||||
/* Forward declarations of slots. */
|
||||
static PyObject *sipMethodDescr_descr_get(PyObject *self, PyObject *obj,
|
||||
PyObject *type);
|
||||
static PyObject *sipMethodDescr_repr(PyObject *self);
|
||||
static int sipMethodDescr_traverse(PyObject *self, visitproc visit, void *arg);
|
||||
static int sipMethodDescr_clear(PyObject *self);
|
||||
static void sipMethodDescr_dealloc(PyObject *self);
|
||||
|
||||
|
||||
/*
|
||||
* The object data structure.
|
||||
*/
|
||||
typedef struct _sipMethodDescr {
|
||||
PyObject_HEAD
|
||||
|
||||
/* The method definition. */
|
||||
PyMethodDef *pmd;
|
||||
|
||||
/* The mixin name, if any. */
|
||||
PyObject *mixin_name;
|
||||
} sipMethodDescr;
|
||||
|
||||
|
||||
/*
|
||||
* The type data structure.
|
||||
*/
|
||||
PyTypeObject sipMethodDescr_Type = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0)
|
||||
"sip.methoddescriptor", /* tp_name */
|
||||
sizeof (sipMethodDescr), /* tp_basicsize */
|
||||
0, /* tp_itemsize */
|
||||
sipMethodDescr_dealloc, /* tp_dealloc */
|
||||
0, /* tp_print */
|
||||
0, /* tp_getattr */
|
||||
0, /* tp_setattr */
|
||||
0, /* tp_compare */
|
||||
sipMethodDescr_repr, /* 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|Py_TPFLAGS_HAVE_GC, /* tp_flags */
|
||||
0, /* tp_doc */
|
||||
sipMethodDescr_traverse,/* tp_traverse */
|
||||
sipMethodDescr_clear, /* tp_clear */
|
||||
0, /* tp_richcompare */
|
||||
0, /* tp_weaklistoffset */
|
||||
0, /* tp_iter */
|
||||
0, /* tp_iternext */
|
||||
0, /* tp_methods */
|
||||
0, /* tp_members */
|
||||
0, /* tp_getset */
|
||||
0, /* tp_base */
|
||||
0, /* tp_dict */
|
||||
sipMethodDescr_descr_get, /* tp_descr_get */
|
||||
0, /* tp_descr_set */
|
||||
0, /* tp_dictoffset */
|
||||
0, /* tp_init */
|
||||
0, /* tp_alloc */
|
||||
0, /* tp_new */
|
||||
0, /* 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, /* tp_version_tag */
|
||||
0, /* tp_finalize */
|
||||
#if PY_VERSION_HEX >= 0x03080000
|
||||
0, /* tp_vectorcall */
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Return a new method descriptor for the given method.
|
||||
*/
|
||||
PyObject *sipMethodDescr_New(PyMethodDef *pmd)
|
||||
{
|
||||
PyObject *descr = PyType_GenericAlloc(&sipMethodDescr_Type, 0);
|
||||
|
||||
if (descr != NULL)
|
||||
{
|
||||
((sipMethodDescr *)descr)->pmd = pmd;
|
||||
((sipMethodDescr *)descr)->mixin_name = NULL;
|
||||
}
|
||||
|
||||
return descr;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Return a new method descriptor based on an existing one and a mixin name.
|
||||
*/
|
||||
PyObject *sipMethodDescr_Copy(PyObject *orig, PyObject *mixin_name)
|
||||
{
|
||||
PyObject *descr = PyType_GenericAlloc(&sipMethodDescr_Type, 0);
|
||||
|
||||
if (descr != NULL)
|
||||
{
|
||||
((sipMethodDescr *)descr)->pmd = ((sipMethodDescr *)orig)->pmd;
|
||||
((sipMethodDescr *)descr)->mixin_name = mixin_name;
|
||||
Py_INCREF(mixin_name);
|
||||
}
|
||||
|
||||
return descr;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The descriptor's descriptor get slot.
|
||||
*/
|
||||
static PyObject *sipMethodDescr_descr_get(PyObject *self, PyObject *obj,
|
||||
PyObject *type)
|
||||
{
|
||||
sipMethodDescr *md = (sipMethodDescr *)self;
|
||||
|
||||
(void)type;
|
||||
|
||||
if (obj == Py_None)
|
||||
obj = NULL;
|
||||
else if (md->mixin_name != NULL)
|
||||
obj = PyObject_GetAttr(obj, md->mixin_name);
|
||||
|
||||
return PyCFunction_New(md->pmd, obj);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The descriptor's repr slot. This is for the benefit of cProfile which seems
|
||||
* to determine attribute names differently to the rest of Python.
|
||||
*/
|
||||
static PyObject *sipMethodDescr_repr(PyObject *self)
|
||||
{
|
||||
sipMethodDescr *md = (sipMethodDescr *)self;
|
||||
|
||||
return PyUnicode_FromFormat("<built-in method %s>", md->pmd->ml_name);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The descriptor's traverse slot.
|
||||
*/
|
||||
static int sipMethodDescr_traverse(PyObject *self, visitproc visit, void *arg)
|
||||
{
|
||||
if (((sipMethodDescr *)self)->mixin_name != NULL)
|
||||
{
|
||||
int vret = visit(((sipMethodDescr *)self)->mixin_name, arg);
|
||||
|
||||
if (vret != 0)
|
||||
return vret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The descriptor's clear slot.
|
||||
*/
|
||||
static int sipMethodDescr_clear(PyObject *self)
|
||||
{
|
||||
PyObject *tmp = ((sipMethodDescr *)self)->mixin_name;
|
||||
|
||||
((sipMethodDescr *)self)->mixin_name = NULL;
|
||||
Py_XDECREF(tmp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The descriptor's dealloc slot.
|
||||
*/
|
||||
static void sipMethodDescr_dealloc(PyObject *self)
|
||||
{
|
||||
sipMethodDescr_clear(self);
|
||||
Py_TYPE(self)->tp_free(self);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* A variable descriptor. We don't use the similar Python descriptor because
|
||||
* it doesn't support static variables.
|
||||
*****************************************************************************/
|
||||
|
||||
|
||||
/* Forward declarations of slots. */
|
||||
static PyObject *sipVariableDescr_descr_get(PyObject *self, PyObject *obj,
|
||||
PyObject *type);
|
||||
static int sipVariableDescr_descr_set(PyObject *self, PyObject *obj,
|
||||
PyObject *value);
|
||||
static int sipVariableDescr_traverse(PyObject *self, visitproc visit,
|
||||
void *arg);
|
||||
static int sipVariableDescr_clear(PyObject *self);
|
||||
static void sipVariableDescr_dealloc(PyObject *self);
|
||||
|
||||
|
||||
/*
|
||||
* The object data structure.
|
||||
*/
|
||||
typedef struct _sipVariableDescr {
|
||||
PyObject_HEAD
|
||||
|
||||
/* The getter/setter definition. */
|
||||
sipVariableDef *vd;
|
||||
|
||||
/* The generated type definition. */
|
||||
const sipTypeDef *td;
|
||||
|
||||
/* The generated container definition. */
|
||||
const sipContainerDef *cod;
|
||||
|
||||
/* The mixin name, if any. */
|
||||
PyObject *mixin_name;
|
||||
} sipVariableDescr;
|
||||
|
||||
|
||||
/*
|
||||
* The type data structure.
|
||||
*/
|
||||
PyTypeObject sipVariableDescr_Type = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0)
|
||||
"sip.variabledescriptor", /* tp_name */
|
||||
sizeof (sipVariableDescr), /* tp_basicsize */
|
||||
0, /* tp_itemsize */
|
||||
sipVariableDescr_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|Py_TPFLAGS_HAVE_GC, /* tp_flags */
|
||||
0, /* tp_doc */
|
||||
sipVariableDescr_traverse, /* tp_traverse */
|
||||
sipVariableDescr_clear, /* tp_clear */
|
||||
0, /* tp_richcompare */
|
||||
0, /* tp_weaklistoffset */
|
||||
0, /* tp_iter */
|
||||
0, /* tp_iternext */
|
||||
0, /* tp_methods */
|
||||
0, /* tp_members */
|
||||
0, /* tp_getset */
|
||||
0, /* tp_base */
|
||||
0, /* tp_dict */
|
||||
sipVariableDescr_descr_get, /* tp_descr_get */
|
||||
sipVariableDescr_descr_set, /* tp_descr_set */
|
||||
0, /* tp_dictoffset */
|
||||
0, /* tp_init */
|
||||
0, /* tp_alloc */
|
||||
0, /* tp_new */
|
||||
0, /* 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, /* tp_version_tag */
|
||||
0, /* tp_finalize */
|
||||
#if PY_VERSION_HEX >= 0x03080000
|
||||
0, /* tp_vectorcall */
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
/* Forward declarations. */
|
||||
static int get_instance_address(sipVariableDescr *vd, PyObject *obj,
|
||||
void **addrp);
|
||||
|
||||
|
||||
/*
|
||||
* Return a new method descriptor for the given getter/setter.
|
||||
*/
|
||||
PyObject *sipVariableDescr_New(sipVariableDef *vd, const sipTypeDef *td,
|
||||
const sipContainerDef *cod)
|
||||
{
|
||||
PyObject *descr = PyType_GenericAlloc(&sipVariableDescr_Type, 0);
|
||||
|
||||
if (descr != NULL)
|
||||
{
|
||||
((sipVariableDescr *)descr)->vd = vd;
|
||||
((sipVariableDescr *)descr)->td = td;
|
||||
((sipVariableDescr *)descr)->cod = cod;
|
||||
((sipVariableDescr *)descr)->mixin_name = NULL;
|
||||
}
|
||||
|
||||
return descr;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Return a new variable descriptor based on an existing one and a mixin name.
|
||||
*/
|
||||
PyObject *sipVariableDescr_Copy(PyObject *orig, PyObject *mixin_name)
|
||||
{
|
||||
PyObject *descr = PyType_GenericAlloc(&sipVariableDescr_Type, 0);
|
||||
|
||||
if (descr != NULL)
|
||||
{
|
||||
((sipVariableDescr *)descr)->vd = ((sipVariableDescr *)orig)->vd;
|
||||
((sipVariableDescr *)descr)->td = ((sipVariableDescr *)orig)->td;
|
||||
((sipVariableDescr *)descr)->cod = ((sipVariableDescr *)orig)->cod;
|
||||
((sipVariableDescr *)descr)->mixin_name = mixin_name;
|
||||
Py_INCREF(mixin_name);
|
||||
}
|
||||
|
||||
return descr;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The descriptor's descriptor get slot.
|
||||
*/
|
||||
static PyObject *sipVariableDescr_descr_get(PyObject *self, PyObject *obj,
|
||||
PyObject *type)
|
||||
{
|
||||
sipVariableDescr *vd = (sipVariableDescr *)self;
|
||||
void *addr;
|
||||
|
||||
if (get_instance_address(vd, obj, &addr) < 0)
|
||||
return NULL;
|
||||
|
||||
return ((sipVariableGetterFunc)vd->vd->vd_getter)(addr, obj, type);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The descriptor's descriptor set slot.
|
||||
*/
|
||||
static int sipVariableDescr_descr_set(PyObject *self, PyObject *obj,
|
||||
PyObject *value)
|
||||
{
|
||||
sipVariableDescr *vd = (sipVariableDescr *)self;
|
||||
void *addr;
|
||||
|
||||
/* Check that the value isn't const. */
|
||||
if (vd->vd->vd_setter == NULL)
|
||||
{
|
||||
PyErr_Format(PyExc_AttributeError,
|
||||
"'%s' object attribute '%s' is read-only",
|
||||
sipPyNameOfContainer(vd->cod, vd->td), vd->vd->vd_name);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (get_instance_address(vd, obj, &addr) < 0)
|
||||
return -1;
|
||||
|
||||
return ((sipVariableSetterFunc)vd->vd->vd_setter)(addr, value, obj);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Return the C/C++ address of any instance.
|
||||
*/
|
||||
static int get_instance_address(sipVariableDescr *vd, PyObject *obj,
|
||||
void **addrp)
|
||||
{
|
||||
void *addr;
|
||||
|
||||
if (vd->vd->vd_type == ClassVariable)
|
||||
{
|
||||
addr = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Check that access was via an instance. */
|
||||
if (obj == NULL || obj == Py_None)
|
||||
{
|
||||
PyErr_Format(PyExc_AttributeError,
|
||||
"'%s' object attribute '%s' is an instance attribute",
|
||||
sipPyNameOfContainer(vd->cod, vd->td), vd->vd->vd_name);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (vd->mixin_name != NULL)
|
||||
obj = PyObject_GetAttr(obj, vd->mixin_name);
|
||||
|
||||
/* Get the C++ instance. */
|
||||
if ((addr = sip_api_get_cpp_ptr((sipSimpleWrapper *)obj, vd->td)) == NULL)
|
||||
return -1;
|
||||
}
|
||||
|
||||
*addrp = addr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The descriptor's traverse slot.
|
||||
*/
|
||||
static int sipVariableDescr_traverse(PyObject *self, visitproc visit, void *arg)
|
||||
{
|
||||
if (((sipVariableDescr *)self)->mixin_name != NULL)
|
||||
{
|
||||
int vret = visit(((sipVariableDescr *)self)->mixin_name, arg);
|
||||
|
||||
if (vret != 0)
|
||||
return vret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The descriptor's clear slot.
|
||||
*/
|
||||
static int sipVariableDescr_clear(PyObject *self)
|
||||
{
|
||||
PyObject *tmp = ((sipVariableDescr *)self)->mixin_name;
|
||||
|
||||
((sipVariableDescr *)self)->mixin_name = NULL;
|
||||
Py_XDECREF(tmp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The descriptor's dealloc slot.
|
||||
*/
|
||||
static void sipVariableDescr_dealloc(PyObject *self)
|
||||
{
|
||||
sipVariableDescr_clear(self);
|
||||
Py_TYPE(self)->tp_free(self);
|
||||
}
|
||||
@@ -1,358 +0,0 @@
|
||||
/*
|
||||
* The implementation of the Python object to C/C++ integer converters.
|
||||
*
|
||||
* Copyright (c) 2019 Riverbank Computing Limited <info@riverbankcomputing.com>
|
||||
*
|
||||
* This file is part of SIP.
|
||||
*
|
||||
* This copy of SIP is licensed for use under the terms of the SIP License
|
||||
* Agreement. See the file LICENSE for more details.
|
||||
*
|
||||
* This copy of SIP may also used under the terms of the GNU General Public
|
||||
* License v2 or v3 as published by the Free Software Foundation which can be
|
||||
* found in the files LICENSE-GPL2 and LICENSE-GPL3 included in this package.
|
||||
*
|
||||
* SIP is supplied WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* NOTES
|
||||
*
|
||||
* The legacy integer conversions (ie. without support for overflow checking)
|
||||
* are flawed and inconsistent. Large Python signed values were converted to
|
||||
* -1 whereas small values were truncated. When converting function arguments
|
||||
* all overlows were ignored, however when converting the results returned by
|
||||
* Python re-implementations then large Python values raised an exception
|
||||
* whereas small values were truncated.
|
||||
*
|
||||
* With the new integer conversions large Python signed values will always
|
||||
* raise an overflow exception (even if overflow checking is disabled). This
|
||||
* is because a truncated value is not available - it would have to be
|
||||
* computed. This may cause new exceptions to be raised but is justified in
|
||||
* that the value that was being used bore no relation to the original value.
|
||||
*/
|
||||
|
||||
|
||||
#include <Python.h>
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#include "sipint.h"
|
||||
|
||||
|
||||
/* Wrappers to deal with lack of long long support. */
|
||||
#if defined(HAVE_LONG_LONG)
|
||||
#define SIPLong_AsLongLong PyLong_AsLongLong
|
||||
#define SIP_LONG_LONG PY_LONG_LONG
|
||||
#define SIP_LONG_LONG_FORMAT "%lld"
|
||||
#define SIP_UNSIGNED_LONG_LONG_FORMAT "%llu"
|
||||
#else
|
||||
#define SIPLong_AsLongLong PyLong_AsLong
|
||||
#define SIP_LONG_LONG long
|
||||
#define SIP_LONG_LONG_FORMAT "%ld"
|
||||
#define SIP_UNSIGNED_LONG_LONG_FORMAT "%lu"
|
||||
#endif
|
||||
|
||||
|
||||
static int overflow_checking = FALSE; /* Check for overflows. */
|
||||
|
||||
static SIP_LONG_LONG long_as_long_long(PyObject *o, SIP_LONG_LONG min,
|
||||
SIP_LONG_LONG max);
|
||||
static unsigned long long_as_unsigned_long(PyObject *o, unsigned long max);
|
||||
static void raise_signed_overflow(SIP_LONG_LONG min, SIP_LONG_LONG max);
|
||||
static void raise_unsigned_overflow(unsigned SIP_LONG_LONG max);
|
||||
|
||||
|
||||
/*
|
||||
* Enable or disable overflow checking (Python API).
|
||||
*/
|
||||
PyObject *sipEnableOverflowChecking(PyObject *self, PyObject *args)
|
||||
{
|
||||
int enable;
|
||||
|
||||
(void)self;
|
||||
|
||||
if (PyArg_ParseTuple(args, "i:enableoverflowchecking", &enable))
|
||||
{
|
||||
PyObject *res;
|
||||
|
||||
res = (sip_api_enable_overflow_checking(enable) ? Py_True : Py_False);
|
||||
|
||||
Py_INCREF(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Enable or disable overflow checking (C API).
|
||||
*/
|
||||
int sip_api_enable_overflow_checking(int enable)
|
||||
{
|
||||
int was_enabled = overflow_checking;
|
||||
|
||||
overflow_checking = enable;
|
||||
|
||||
return was_enabled;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Convert a Python object to a C++ bool (returned as an int).
|
||||
*/
|
||||
int sip_api_convert_to_bool(PyObject *o)
|
||||
{
|
||||
int was_enabled, v;
|
||||
|
||||
/* Convert the object to an int while checking for overflow. */
|
||||
was_enabled = sip_api_enable_overflow_checking(TRUE);
|
||||
v = sip_api_long_as_int(o);
|
||||
sip_api_enable_overflow_checking(was_enabled);
|
||||
|
||||
if (PyErr_Occurred())
|
||||
{
|
||||
if (PyErr_ExceptionMatches(PyExc_OverflowError))
|
||||
{
|
||||
PyErr_Clear();
|
||||
|
||||
/* The value must have been non-zero. */
|
||||
v = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
PyErr_Format(PyExc_TypeError, "a 'bool' is expected not '%s'",
|
||||
Py_TYPE(o)->tp_name);
|
||||
|
||||
v = -1;
|
||||
}
|
||||
}
|
||||
else if (v != 0)
|
||||
{
|
||||
v = 1;
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Convert a Python object to a C char.
|
||||
*/
|
||||
char sip_api_long_as_char(PyObject *o)
|
||||
{
|
||||
return (char)long_as_long_long(o, CHAR_MIN, CHAR_MAX);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Convert a Python object to a C signed char.
|
||||
*/
|
||||
signed char sip_api_long_as_signed_char(PyObject *o)
|
||||
{
|
||||
return (signed char)long_as_long_long(o, SCHAR_MIN, SCHAR_MAX);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Convert a Python object to a C unsigned char.
|
||||
*/
|
||||
unsigned char sip_api_long_as_unsigned_char(PyObject *o)
|
||||
{
|
||||
return (unsigned char)long_as_unsigned_long(o, UCHAR_MAX);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Convert a Python object to a C short.
|
||||
*/
|
||||
short sip_api_long_as_short(PyObject *o)
|
||||
{
|
||||
return (short)long_as_long_long(o, SHRT_MIN, SHRT_MAX);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Convert a Python object to a C unsigned short.
|
||||
*/
|
||||
unsigned short sip_api_long_as_unsigned_short(PyObject *o)
|
||||
{
|
||||
return (unsigned short)long_as_unsigned_long(o, USHRT_MAX);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Convert a Python object to a C int.
|
||||
*/
|
||||
int sip_api_long_as_int(PyObject *o)
|
||||
{
|
||||
return (int)long_as_long_long(o, INT_MIN, INT_MAX);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Convert a Python object to a C unsigned int.
|
||||
*/
|
||||
unsigned sip_api_long_as_unsigned_int(PyObject *o)
|
||||
{
|
||||
return (unsigned)long_as_unsigned_long(o, UINT_MAX);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Convert a Python object to a C size_t.
|
||||
*/
|
||||
size_t sip_api_long_as_size_t(PyObject *o)
|
||||
{
|
||||
return (size_t)long_as_unsigned_long(o, SIZE_MAX);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Convert a Python object to a C long.
|
||||
*/
|
||||
long sip_api_long_as_long(PyObject *o)
|
||||
{
|
||||
return (long)long_as_long_long(o, LONG_MIN, LONG_MAX);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Convert a Python object to a C unsigned long.
|
||||
*/
|
||||
unsigned long sip_api_long_as_unsigned_long(PyObject *o)
|
||||
{
|
||||
return long_as_unsigned_long(o, ULONG_MAX);
|
||||
}
|
||||
|
||||
|
||||
#if defined(HAVE_LONG_LONG)
|
||||
/*
|
||||
* Convert a Python object to a C long long.
|
||||
*/
|
||||
PY_LONG_LONG sip_api_long_as_long_long(PyObject *o)
|
||||
{
|
||||
return long_as_long_long(o, LLONG_MIN, LLONG_MAX);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Convert a Python object to a C unsigned long long.
|
||||
*/
|
||||
unsigned PY_LONG_LONG sip_api_long_as_unsigned_long_long(PyObject *o)
|
||||
{
|
||||
unsigned PY_LONG_LONG value;
|
||||
|
||||
/*
|
||||
* Note that this doesn't handle Python v2 int objects, but the old
|
||||
* converters didn't either.
|
||||
*/
|
||||
|
||||
PyErr_Clear();
|
||||
|
||||
if (overflow_checking)
|
||||
{
|
||||
value = PyLong_AsUnsignedLongLong(o);
|
||||
|
||||
if (PyErr_Occurred())
|
||||
{
|
||||
/* Provide a better exception message. */
|
||||
if (PyErr_ExceptionMatches(PyExc_OverflowError))
|
||||
raise_unsigned_overflow(ULLONG_MAX);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
value = PyLong_AsUnsignedLongLongMask(o);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Convert a Python object to a long long checking that the value is within a
|
||||
* range if overflow checking is enabled.
|
||||
*/
|
||||
static SIP_LONG_LONG long_as_long_long(PyObject *o, SIP_LONG_LONG min,
|
||||
SIP_LONG_LONG max)
|
||||
{
|
||||
SIP_LONG_LONG value;
|
||||
|
||||
PyErr_Clear();
|
||||
|
||||
value = SIPLong_AsLongLong(o);
|
||||
|
||||
if (PyErr_Occurred())
|
||||
{
|
||||
/* Provide a better exception message. */
|
||||
if (PyErr_ExceptionMatches(PyExc_OverflowError))
|
||||
raise_signed_overflow(min, max);
|
||||
}
|
||||
else if (overflow_checking && (value < min || value > max))
|
||||
{
|
||||
raise_signed_overflow(min, max);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Convert a Python object to an unsigned long checking that the value is
|
||||
* within a range if overflow checking is enabled.
|
||||
*/
|
||||
static unsigned long long_as_unsigned_long(PyObject *o, unsigned long max)
|
||||
{
|
||||
unsigned long value;
|
||||
|
||||
PyErr_Clear();
|
||||
|
||||
if (overflow_checking)
|
||||
{
|
||||
value = PyLong_AsUnsignedLong(o);
|
||||
|
||||
if (PyErr_Occurred())
|
||||
{
|
||||
/* Provide a better exception message. */
|
||||
if (PyErr_ExceptionMatches(PyExc_OverflowError))
|
||||
raise_unsigned_overflow(max);
|
||||
}
|
||||
else if (value > max)
|
||||
{
|
||||
raise_unsigned_overflow(max);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
value = PyLong_AsUnsignedLongMask(o);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Raise an overflow exception if a signed value is out of range.
|
||||
*/
|
||||
static void raise_signed_overflow(SIP_LONG_LONG min, SIP_LONG_LONG max)
|
||||
{
|
||||
PyErr_Format(PyExc_OverflowError,
|
||||
"value must be in the range " SIP_LONG_LONG_FORMAT " to " SIP_LONG_LONG_FORMAT,
|
||||
min, max);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Raise an overflow exception if an unsigned value is out of range.
|
||||
*/
|
||||
static void raise_unsigned_overflow(unsigned SIP_LONG_LONG max)
|
||||
{
|
||||
PyErr_Format(PyExc_OverflowError,
|
||||
"value must be in the range 0 to " SIP_UNSIGNED_LONG_LONG_FORMAT,
|
||||
max);
|
||||
}
|
||||
@@ -1,489 +0,0 @@
|
||||
/*
|
||||
* This module implements a hash table class for mapping C/C++ addresses to the
|
||||
* corresponding wrapped Python object.
|
||||
*
|
||||
* Copyright (c) 2017 Riverbank Computing Limited <info@riverbankcomputing.com>
|
||||
*
|
||||
* This file is part of SIP.
|
||||
*
|
||||
* This copy of SIP is licensed for use under the terms of the SIP License
|
||||
* Agreement. See the file LICENSE for more details.
|
||||
*
|
||||
* This copy of SIP may also used under the terms of the GNU General Public
|
||||
* License v2 or v3 as published by the Free Software Foundation which can be
|
||||
* found in the files LICENSE-GPL2 and LICENSE-GPL3 included in this package.
|
||||
*
|
||||
* SIP is supplied WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*/
|
||||
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "sipint.h"
|
||||
|
||||
|
||||
#define hash_1(k,s) (((unsigned long)(k)) % (s))
|
||||
#define hash_2(k,s) ((s) - 2 - (hash_1((k),(s)) % ((s) - 2)))
|
||||
|
||||
|
||||
/* Prime numbers to use as hash table sizes. */
|
||||
static unsigned long hash_primes[] = {
|
||||
521, 1031, 2053, 4099,
|
||||
8209, 16411, 32771, 65537, 131101, 262147,
|
||||
524309, 1048583, 2097169, 4194319, 8388617, 16777259,
|
||||
33554467, 67108879, 134217757, 268435459, 536870923, 1073741827,
|
||||
2147483659U,0
|
||||
};
|
||||
|
||||
|
||||
static sipHashEntry *newHashTable(unsigned long);
|
||||
static sipHashEntry *findHashEntry(sipObjectMap *,void *);
|
||||
static void add_object(sipObjectMap *om, void *addr, sipSimpleWrapper *val);
|
||||
static void add_aliases(sipObjectMap *om, void *addr, sipSimpleWrapper *val,
|
||||
const sipClassTypeDef *base_ctd, const sipClassTypeDef *ctd);
|
||||
static int remove_object(sipObjectMap *om, void *addr, sipSimpleWrapper *val);
|
||||
static void remove_aliases(sipObjectMap *om, void *addr, sipSimpleWrapper *val,
|
||||
const sipClassTypeDef *base_ctd, const sipClassTypeDef *ctd);
|
||||
static void reorganiseMap(sipObjectMap *om);
|
||||
static void *getUnguardedPointer(sipSimpleWrapper *w);
|
||||
|
||||
|
||||
/*
|
||||
* Initialise an object map.
|
||||
*/
|
||||
void sipOMInit(sipObjectMap *om)
|
||||
{
|
||||
om -> primeIdx = 0;
|
||||
om -> unused = om -> size = hash_primes[om -> primeIdx];
|
||||
om -> stale = 0;
|
||||
om -> hash_array = newHashTable(om -> size);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Finalise an object map.
|
||||
*/
|
||||
void sipOMFinalise(sipObjectMap *om)
|
||||
{
|
||||
sip_api_free(om -> hash_array);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Allocate and initialise a new hash table.
|
||||
*/
|
||||
static sipHashEntry *newHashTable(unsigned long size)
|
||||
{
|
||||
size_t nbytes;
|
||||
sipHashEntry *hashtab;
|
||||
|
||||
nbytes = sizeof (sipHashEntry) * size;
|
||||
|
||||
if ((hashtab = (sipHashEntry *)sip_api_malloc(nbytes)) != NULL)
|
||||
memset(hashtab,0,nbytes);
|
||||
|
||||
return hashtab;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Return a pointer to the hash entry that is used, or should be used, for the
|
||||
* given C/C++ address.
|
||||
*/
|
||||
static sipHashEntry *findHashEntry(sipObjectMap *om,void *key)
|
||||
{
|
||||
unsigned long hash, inc;
|
||||
void *hek;
|
||||
|
||||
hash = hash_1(key,om -> size);
|
||||
inc = hash_2(key,om -> size);
|
||||
|
||||
while ((hek = om -> hash_array[hash].key) != NULL && hek != key)
|
||||
hash = (hash + inc) % om -> size;
|
||||
|
||||
return &om -> hash_array[hash];
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Return the wrapped Python object of a specific type for a C/C++ address or
|
||||
* NULL if it wasn't found.
|
||||
*/
|
||||
sipSimpleWrapper *sipOMFindObject(sipObjectMap *om, void *key,
|
||||
const sipTypeDef *td)
|
||||
{
|
||||
sipHashEntry *he = findHashEntry(om, key);
|
||||
sipSimpleWrapper *sw;
|
||||
PyTypeObject *py_type = sipTypeAsPyTypeObject(td);
|
||||
|
||||
/* Go through each wrapped object at this address. */
|
||||
for (sw = he->first; sw != NULL; sw = sw->next)
|
||||
{
|
||||
sipSimpleWrapper *unaliased;
|
||||
|
||||
unaliased = (sipIsAlias(sw) ? (sipSimpleWrapper *)sw->data : sw);
|
||||
|
||||
/*
|
||||
* If the reference count is 0 then it is in the process of being
|
||||
* deleted, so ignore it. It's not completely clear how this can
|
||||
* happen (but it can) because it implies that the garbage collection
|
||||
* code is being re-entered (and there are guards in place to prevent
|
||||
* this).
|
||||
*/
|
||||
if (Py_REFCNT(unaliased) == 0)
|
||||
continue;
|
||||
|
||||
/* Ignore it if the C/C++ address is no longer valid. */
|
||||
if (sip_api_get_address(unaliased) == NULL)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* If this wrapped object is of the given type, or a sub-type of it,
|
||||
* then we assume it is the same C++ object.
|
||||
*/
|
||||
if (PyObject_TypeCheck(unaliased, py_type))
|
||||
return unaliased;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Add a C/C++ address and the corresponding wrapped Python object to the map.
|
||||
*/
|
||||
void sipOMAddObject(sipObjectMap *om, sipSimpleWrapper *val)
|
||||
{
|
||||
void *addr = getUnguardedPointer(val);
|
||||
const sipClassTypeDef *base_ctd;
|
||||
|
||||
/* Add the object. */
|
||||
add_object(om, addr, val);
|
||||
|
||||
/* Add any aliases. */
|
||||
base_ctd = (const sipClassTypeDef *)((sipWrapperType *)Py_TYPE(val))->wt_td;
|
||||
add_aliases(om, addr, val, base_ctd, base_ctd);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Add an alias for any address that is different when cast to a super-type.
|
||||
*/
|
||||
static void add_aliases(sipObjectMap *om, void *addr, sipSimpleWrapper *val,
|
||||
const sipClassTypeDef *base_ctd, const sipClassTypeDef *ctd)
|
||||
{
|
||||
const sipEncodedTypeDef *sup;
|
||||
|
||||
/* See if there are any super-classes. */
|
||||
if ((sup = ctd->ctd_supers) != NULL)
|
||||
{
|
||||
sipClassTypeDef *sup_ctd = sipGetGeneratedClassType(sup, ctd);
|
||||
|
||||
/* Recurse up the hierarchy for the first super-class. */
|
||||
add_aliases(om, addr, val, base_ctd, sup_ctd);
|
||||
|
||||
/*
|
||||
* We only check for aliases for subsequent super-classes because the
|
||||
* first one can never need one.
|
||||
*/
|
||||
while (!sup++->sc_flag)
|
||||
{
|
||||
void *sup_addr;
|
||||
|
||||
sup_ctd = sipGetGeneratedClassType(sup, ctd);
|
||||
|
||||
/* Recurse up the hierarchy for the remaining super-classes. */
|
||||
add_aliases(om, addr, val, base_ctd, sup_ctd);
|
||||
|
||||
sup_addr = (*base_ctd->ctd_cast)(addr, (sipTypeDef *)sup_ctd);
|
||||
|
||||
if (sup_addr != addr)
|
||||
{
|
||||
sipSimpleWrapper *alias;
|
||||
|
||||
/* Note that we silently ignore errors. */
|
||||
if ((alias = sip_api_malloc(sizeof (sipSimpleWrapper))) != NULL)
|
||||
{
|
||||
/*
|
||||
* An alias is basically a bit-wise copy of the Python
|
||||
* object but only to ensure the fields we are subverting
|
||||
* are in the right place. An alias should never be passed
|
||||
* to the Python API.
|
||||
*/
|
||||
*alias = *val;
|
||||
|
||||
alias->sw_flags = (val->sw_flags & SIP_SHARE_MAP) | SIP_ALIAS;
|
||||
alias->data = val;
|
||||
alias->next = NULL;
|
||||
|
||||
add_object(om, sup_addr, alias);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Add a wrapper (which may be an alias) to the map.
|
||||
*/
|
||||
static void add_object(sipObjectMap *om, void *addr, sipSimpleWrapper *val)
|
||||
{
|
||||
sipHashEntry *he = findHashEntry(om, addr);
|
||||
|
||||
/*
|
||||
* If the bucket is in use then we appear to have several objects at the
|
||||
* same address.
|
||||
*/
|
||||
if (he->first != NULL)
|
||||
{
|
||||
/*
|
||||
* This can happen for three reasons. A variable of one class can be
|
||||
* declared at the start of another class. Therefore there are two
|
||||
* objects, of different classes, with the same address. The second
|
||||
* reason is that the old C/C++ object has been deleted by C/C++ but we
|
||||
* didn't get to find out for some reason, and a new C/C++ instance has
|
||||
* been created at the same address. The third reason is if we are in
|
||||
* the process of deleting a Python object but the C++ object gets
|
||||
* wrapped again because the C++ dtor called a method that has been
|
||||
* re-implemented in Python. The absence of the SIP_SHARE_MAP flag
|
||||
* tells us that a new C++ instance has just been created and so we
|
||||
* know the second reason is the correct one so we mark the old
|
||||
* pointers as invalid and reuse the entry. Otherwise we just add this
|
||||
* one to the existing list of objects at this address.
|
||||
*/
|
||||
if (!(val->sw_flags & SIP_SHARE_MAP))
|
||||
{
|
||||
sipSimpleWrapper *sw = he->first;
|
||||
|
||||
he->first = NULL;
|
||||
|
||||
while (sw != NULL)
|
||||
{
|
||||
sipSimpleWrapper *next = sw->next;
|
||||
|
||||
if (sipIsAlias(sw))
|
||||
{
|
||||
sip_api_free(sw);
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* We are removing it from the map here. However, note
|
||||
* that we first have to call the destructor before marking
|
||||
* it as not being in the map, as the destructor itself
|
||||
* might end up trying to remove the wrapper and its
|
||||
* aliases from the map. In that case, if the wrapper is
|
||||
* already marked as not in the map, the removal will just
|
||||
* return early, leaving any potential aliases as stale
|
||||
* entries in the map. If we later try to wrap a different
|
||||
* object at the same address, we end up retrieving the
|
||||
* stale alias entry from the object map, triggering a
|
||||
* use-after-free when accessing its C++ object.
|
||||
*/
|
||||
sip_api_instance_destroyed(sw);
|
||||
sipSetNotInMap(sw);
|
||||
}
|
||||
|
||||
sw = next;
|
||||
}
|
||||
}
|
||||
|
||||
val->next = he->first;
|
||||
he->first = val;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* See if the bucket was unused or stale. */
|
||||
if (he->key == NULL)
|
||||
{
|
||||
he->key = addr;
|
||||
om->unused--;
|
||||
}
|
||||
else
|
||||
{
|
||||
om->stale--;
|
||||
}
|
||||
|
||||
/* Add the rest of the new value. */
|
||||
he->first = val;
|
||||
val->next = NULL;
|
||||
|
||||
reorganiseMap(om);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Reorganise a map if it is running short of space.
|
||||
*/
|
||||
static void reorganiseMap(sipObjectMap *om)
|
||||
{
|
||||
unsigned long old_size, i;
|
||||
sipHashEntry *ohe, *old_tab;
|
||||
|
||||
/* Don't bother if it still has more than 12% available. */
|
||||
if (om -> unused > om -> size >> 3)
|
||||
return;
|
||||
|
||||
/*
|
||||
* If reorganising (ie. making the stale buckets unused) using the same
|
||||
* sized table would make 25% available then do that. Otherwise use a
|
||||
* bigger table (if possible).
|
||||
*/
|
||||
if (om -> unused + om -> stale < om -> size >> 2 && hash_primes[om -> primeIdx + 1] != 0)
|
||||
om -> primeIdx++;
|
||||
|
||||
old_size = om -> size;
|
||||
old_tab = om -> hash_array;
|
||||
|
||||
om -> unused = om -> size = hash_primes[om -> primeIdx];
|
||||
om -> stale = 0;
|
||||
om -> hash_array = newHashTable(om -> size);
|
||||
|
||||
/* Transfer the entries from the old table to the new one. */
|
||||
ohe = old_tab;
|
||||
|
||||
for (i = 0; i < old_size; ++i)
|
||||
{
|
||||
if (ohe -> key != NULL && ohe -> first != NULL)
|
||||
{
|
||||
*findHashEntry(om,ohe -> key) = *ohe;
|
||||
om -> unused--;
|
||||
}
|
||||
|
||||
++ohe;
|
||||
}
|
||||
|
||||
sip_api_free(old_tab);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Remove a C/C++ object from the table. Return 0 if it was removed
|
||||
* successfully.
|
||||
*/
|
||||
int sipOMRemoveObject(sipObjectMap *om, sipSimpleWrapper *val)
|
||||
{
|
||||
void *addr;
|
||||
const sipClassTypeDef *base_ctd;
|
||||
|
||||
/* Handle the trivial case. */
|
||||
if (sipNotInMap(val))
|
||||
return 0;
|
||||
|
||||
if ((addr = getUnguardedPointer(val)) == NULL)
|
||||
return 0;
|
||||
|
||||
/* Remove any aliases. */
|
||||
base_ctd = (const sipClassTypeDef *)((sipWrapperType *)Py_TYPE(val))->wt_td;
|
||||
remove_aliases(om, addr, val, base_ctd, base_ctd);
|
||||
|
||||
/* Remove the object. */
|
||||
return remove_object(om, addr, val);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Remove an alias for any address that is different when cast to a super-type.
|
||||
*/
|
||||
static void remove_aliases(sipObjectMap *om, void *addr, sipSimpleWrapper *val,
|
||||
const sipClassTypeDef *base_ctd, const sipClassTypeDef *ctd)
|
||||
{
|
||||
const sipEncodedTypeDef *sup;
|
||||
|
||||
/* See if there are any super-classes. */
|
||||
if ((sup = ctd->ctd_supers) != NULL)
|
||||
{
|
||||
sipClassTypeDef *sup_ctd = sipGetGeneratedClassType(sup, ctd);
|
||||
|
||||
/* Recurse up the hierarchy for the first super-class. */
|
||||
remove_aliases(om, addr, val, base_ctd, sup_ctd);
|
||||
|
||||
/*
|
||||
* We only check for aliases for subsequent super-classes because the
|
||||
* first one can never need one.
|
||||
*/
|
||||
while (!sup++->sc_flag)
|
||||
{
|
||||
void *sup_addr;
|
||||
|
||||
sup_ctd = sipGetGeneratedClassType(sup, ctd);
|
||||
|
||||
/* Recurse up the hierarchy for the remaining super-classes. */
|
||||
remove_aliases(om, addr, val, base_ctd, sup_ctd);
|
||||
|
||||
sup_addr = (*base_ctd->ctd_cast)(addr, (sipTypeDef *)sup_ctd);
|
||||
|
||||
if (sup_addr != addr)
|
||||
remove_object(om, sup_addr, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Remove a wrapper from the map.
|
||||
*/
|
||||
static int remove_object(sipObjectMap *om, void *addr, sipSimpleWrapper *val)
|
||||
{
|
||||
sipHashEntry *he = findHashEntry(om, addr);
|
||||
sipSimpleWrapper **swp;
|
||||
|
||||
for (swp = &he->first; *swp != NULL; swp = &(*swp)->next)
|
||||
{
|
||||
sipSimpleWrapper *sw, *next;
|
||||
int do_remove;
|
||||
|
||||
sw = *swp;
|
||||
next = sw->next;
|
||||
|
||||
if (sipIsAlias(sw))
|
||||
{
|
||||
if (sw->data == val)
|
||||
{
|
||||
sip_api_free(sw);
|
||||
do_remove = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
do_remove = FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
do_remove = (sw == val);
|
||||
}
|
||||
|
||||
if (do_remove)
|
||||
{
|
||||
*swp = next;
|
||||
|
||||
/*
|
||||
* If the bucket is now empty then count it as stale. Note that we
|
||||
* do not NULL the key and count it as unused because that might
|
||||
* throw out the search for another entry that wanted to go here,
|
||||
* found it already occupied, and was put somewhere else. In other
|
||||
* words, searches must be repeatable until we reorganise the
|
||||
* table.
|
||||
*/
|
||||
if (he->first == NULL)
|
||||
om->stale++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Return the unguarded pointer to a C/C++ instance, ie. the pointer was valid
|
||||
* but may longer be.
|
||||
*/
|
||||
static void *getUnguardedPointer(sipSimpleWrapper *w)
|
||||
{
|
||||
return (w->access_func != NULL) ? w->access_func(w, UnguardedPointer) : w->data;
|
||||
}
|
||||
@@ -1,686 +0,0 @@
|
||||
/*
|
||||
* The SIP library code that implements the interface to the optional module
|
||||
* supplied Qt support.
|
||||
*
|
||||
* Copyright (c) 2020 Riverbank Computing Limited <info@riverbankcomputing.com>
|
||||
*
|
||||
* This file is part of SIP.
|
||||
*
|
||||
* This copy of SIP is licensed for use under the terms of the SIP License
|
||||
* Agreement. See the file LICENSE for more details.
|
||||
*
|
||||
* This copy of SIP may also used under the terms of the GNU General Public
|
||||
* License v2 or v3 as published by the Free Software Foundation which can be
|
||||
* found in the files LICENSE-GPL2 and LICENSE-GPL3 included in this package.
|
||||
*
|
||||
* SIP is supplied WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*/
|
||||
|
||||
|
||||
#include <Python.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "sipint.h"
|
||||
|
||||
|
||||
/* This is how Qt "types" signals and slots. */
|
||||
#define isQtSlot(s) (*(s) == '1')
|
||||
#define isQtSignal(s) (*(s) == '2')
|
||||
|
||||
|
||||
static PyObject *getWeakRef(PyObject *obj);
|
||||
static char *sipStrdup(const char *);
|
||||
static void *createUniversalSlot(sipWrapper *txSelf, const char *sig,
|
||||
PyObject *rxObj, const char *slot, const char **member, int flags);
|
||||
static void *findSignal(void *txrx, const char **sig);
|
||||
static void *newSignal(void *txrx, const char **sig);
|
||||
|
||||
|
||||
/*
|
||||
* Find an existing signal.
|
||||
*/
|
||||
static void *findSignal(void *txrx, const char **sig)
|
||||
{
|
||||
if (sipQtSupport->qt_find_universal_signal != NULL)
|
||||
txrx = sipQtSupport->qt_find_universal_signal(txrx, sig);
|
||||
|
||||
return txrx;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Return a usable signal, creating a new universal signal if needed.
|
||||
*/
|
||||
static void *newSignal(void *txrx, const char **sig)
|
||||
{
|
||||
void *new_txrx = findSignal(txrx, sig);
|
||||
|
||||
if (new_txrx == NULL && sipQtSupport->qt_create_universal_signal != NULL)
|
||||
new_txrx = sipQtSupport->qt_create_universal_signal(txrx, sig);
|
||||
|
||||
return new_txrx;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Create a universal slot. Returns a pointer to it or 0 if there was an
|
||||
* error.
|
||||
*/
|
||||
static void *createUniversalSlot(sipWrapper *txSelf, const char *sig,
|
||||
PyObject *rxObj, const char *slot, const char **member, int flags)
|
||||
{
|
||||
void *us;
|
||||
|
||||
assert(sipQtSupport->qt_create_universal_slot);
|
||||
|
||||
us = sipQtSupport->qt_create_universal_slot(txSelf, sig, rxObj, slot,
|
||||
member, flags);
|
||||
|
||||
if (us && txSelf)
|
||||
sipSetPossibleProxy((sipSimpleWrapper *)txSelf);
|
||||
|
||||
return us;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Invoke a single slot (Qt or Python) and return the result. Don't check if
|
||||
* any receiver C++ object still exists.
|
||||
*/
|
||||
PyObject *sip_api_invoke_slot(const sipSlot *slot, PyObject *sigargs)
|
||||
{
|
||||
return sip_api_invoke_slot_ex(slot, sigargs, TRUE);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Invoke a single slot (Qt or Python) and return the result. Optionally check
|
||||
* that any receiver C++ object still exist.
|
||||
*/
|
||||
PyObject *sip_api_invoke_slot_ex(const sipSlot *slot, PyObject *sigargs,
|
||||
int no_receiver_check)
|
||||
{
|
||||
PyObject *sa, *oxtype, *oxvalue, *oxtb, *sfunc, *sref;
|
||||
|
||||
assert(sipQtSupport);
|
||||
|
||||
/* Keep some compilers quiet. */
|
||||
oxtype = oxvalue = oxtb = NULL;
|
||||
|
||||
/* Fan out Qt signals. (Only PyQt3 would do this.) */
|
||||
if (slot->name != NULL && slot->name[0] != '\0')
|
||||
{
|
||||
assert(sipQtSupport->qt_emit_signal);
|
||||
|
||||
if (sipQtSupport->qt_emit_signal(slot->pyobj, slot->name, sigargs) < 0)
|
||||
return NULL;
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
/* Get the object to call, resolving any weak references. */
|
||||
if (slot->weakSlot == Py_True)
|
||||
{
|
||||
/*
|
||||
* The slot is guaranteed to be Ok because it has an extra reference or
|
||||
* is None.
|
||||
*/
|
||||
sref = slot->pyobj;
|
||||
Py_INCREF(sref);
|
||||
}
|
||||
else if (slot -> weakSlot == NULL)
|
||||
sref = NULL;
|
||||
else if ((sref = PyWeakref_GetObject(slot -> weakSlot)) == NULL)
|
||||
return NULL;
|
||||
else
|
||||
Py_INCREF(sref);
|
||||
|
||||
if (sref == Py_None)
|
||||
{
|
||||
/*
|
||||
* If the real object has gone then we pretend everything is Ok. This
|
||||
* mimics the Qt behaviour of not caring if a receiving object has been
|
||||
* deleted.
|
||||
*/
|
||||
Py_DECREF(sref);
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
if (slot -> pyobj == NULL)
|
||||
{
|
||||
PyObject *self = (sref != NULL ? sref : slot->meth.mself);
|
||||
|
||||
/*
|
||||
* If the receiver wraps a C++ object then ignore the call if it no
|
||||
* longer exists.
|
||||
*/
|
||||
if (!no_receiver_check &&
|
||||
PyObject_TypeCheck(self, (PyTypeObject *)&sipSimpleWrapper_Type) &&
|
||||
sip_api_get_address((sipSimpleWrapper *)self) == NULL)
|
||||
{
|
||||
Py_XDECREF(sref);
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
if ((sfunc = PyMethod_New(slot->meth.mfunc, self)) == NULL)
|
||||
{
|
||||
Py_XDECREF(sref);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else if (slot -> name != NULL)
|
||||
{
|
||||
char *mname = slot -> name + 1;
|
||||
PyObject *self = (sref != NULL ? sref : slot->pyobj);
|
||||
|
||||
if ((sfunc = PyObject_GetAttrString(self, mname)) == NULL || !PyCFunction_Check(sfunc))
|
||||
{
|
||||
/*
|
||||
* Note that in earlier versions of SIP this error would be
|
||||
* detected when the slot was connected.
|
||||
*/
|
||||
PyErr_Format(PyExc_NameError,"Invalid slot %s",mname);
|
||||
|
||||
Py_XDECREF(sfunc);
|
||||
Py_XDECREF(sref);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sfunc = slot->pyobj;
|
||||
Py_INCREF(sfunc);
|
||||
}
|
||||
|
||||
/*
|
||||
* We make repeated attempts to call a slot. If we work out that it failed
|
||||
* because of an immediate type error we try again with one less argument.
|
||||
* We keep going until we run out of arguments to drop. This emulates the
|
||||
* Qt ability of the slot to accept fewer arguments than a signal provides.
|
||||
*/
|
||||
sa = sigargs;
|
||||
Py_INCREF(sa);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
PyObject *nsa, *xtype, *xvalue, *xtb, *resobj;
|
||||
|
||||
if ((resobj = PyObject_CallObject(sfunc, sa)) != NULL)
|
||||
{
|
||||
Py_DECREF(sfunc);
|
||||
Py_XDECREF(sref);
|
||||
|
||||
/* Remove any previous exception. */
|
||||
|
||||
if (sa != sigargs)
|
||||
{
|
||||
Py_XDECREF(oxtype);
|
||||
Py_XDECREF(oxvalue);
|
||||
Py_XDECREF(oxtb);
|
||||
PyErr_Clear();
|
||||
}
|
||||
|
||||
Py_DECREF(sa);
|
||||
|
||||
return resobj;
|
||||
}
|
||||
|
||||
/* Get the exception. */
|
||||
PyErr_Fetch(&xtype,&xvalue,&xtb);
|
||||
|
||||
/*
|
||||
* See if it is unacceptable. An acceptable failure is a type error
|
||||
* with no traceback - so long as we can still reduce the number of
|
||||
* arguments and try again.
|
||||
*/
|
||||
if (!PyErr_GivenExceptionMatches(xtype,PyExc_TypeError) ||
|
||||
xtb != NULL ||
|
||||
PyTuple_GET_SIZE(sa) == 0)
|
||||
{
|
||||
/*
|
||||
* If there is a traceback then we must have called the slot and
|
||||
* the exception was later on - so report the exception as is.
|
||||
*/
|
||||
if (xtb != NULL)
|
||||
{
|
||||
if (sa != sigargs)
|
||||
{
|
||||
Py_XDECREF(oxtype);
|
||||
Py_XDECREF(oxvalue);
|
||||
Py_XDECREF(oxtb);
|
||||
}
|
||||
|
||||
PyErr_Restore(xtype,xvalue,xtb);
|
||||
}
|
||||
else if (sa == sigargs)
|
||||
PyErr_Restore(xtype,xvalue,xtb);
|
||||
else
|
||||
{
|
||||
/*
|
||||
* Discard the latest exception and restore the original one.
|
||||
*/
|
||||
Py_XDECREF(xtype);
|
||||
Py_XDECREF(xvalue);
|
||||
Py_XDECREF(xtb);
|
||||
|
||||
PyErr_Restore(oxtype,oxvalue,oxtb);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* If this is the first attempt, save the exception. */
|
||||
if (sa == sigargs)
|
||||
{
|
||||
oxtype = xtype;
|
||||
oxvalue = xvalue;
|
||||
oxtb = xtb;
|
||||
}
|
||||
else
|
||||
{
|
||||
Py_XDECREF(xtype);
|
||||
Py_XDECREF(xvalue);
|
||||
Py_XDECREF(xtb);
|
||||
}
|
||||
|
||||
/* Create the new argument tuple. */
|
||||
if ((nsa = PyTuple_GetSlice(sa,0,PyTuple_GET_SIZE(sa) - 1)) == NULL)
|
||||
{
|
||||
/* Tidy up. */
|
||||
Py_XDECREF(oxtype);
|
||||
Py_XDECREF(oxvalue);
|
||||
Py_XDECREF(oxtb);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
Py_DECREF(sa);
|
||||
sa = nsa;
|
||||
}
|
||||
|
||||
Py_DECREF(sfunc);
|
||||
Py_XDECREF(sref);
|
||||
|
||||
Py_DECREF(sa);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Compare two slots to see if they are the same.
|
||||
*/
|
||||
int sip_api_same_slot(const sipSlot *sp, PyObject *rxObj, const char *slot)
|
||||
{
|
||||
assert(sipQtSupport);
|
||||
assert(sipQtSupport->qt_same_name);
|
||||
|
||||
/* See if they are signals or Qt slots, ie. they have a name. */
|
||||
if (slot != NULL)
|
||||
{
|
||||
if (sp->name == NULL || sp->name[0] == '\0')
|
||||
return 0;
|
||||
|
||||
return (sipQtSupport->qt_same_name(sp->name, slot) && sp->pyobj == rxObj);
|
||||
}
|
||||
|
||||
/* See if they are pure Python methods. */
|
||||
if (PyMethod_Check(rxObj))
|
||||
{
|
||||
if (sp->pyobj != NULL)
|
||||
return 0;
|
||||
|
||||
return (sp->meth.mfunc == PyMethod_GET_FUNCTION(rxObj)
|
||||
&& sp->meth.mself == PyMethod_GET_SELF(rxObj));
|
||||
}
|
||||
|
||||
/* See if they are wrapped C++ methods. */
|
||||
if (PyCFunction_Check(rxObj))
|
||||
{
|
||||
if (sp->name == NULL || sp->name[0] != '\0')
|
||||
return 0;
|
||||
|
||||
return (sp->pyobj == PyCFunction_GET_SELF(rxObj) &&
|
||||
strcmp(&sp->name[1], ((PyCFunctionObject *)rxObj)->m_ml->ml_name) == 0);
|
||||
}
|
||||
|
||||
/* The objects must be the same. */
|
||||
return (sp->pyobj == rxObj);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Convert a valid Python signal or slot to an existing universal slot.
|
||||
*/
|
||||
void *sipGetRx(sipSimpleWrapper *txSelf, const char *sigargs, PyObject *rxObj,
|
||||
const char *slot, const char **memberp)
|
||||
{
|
||||
assert(sipQtSupport);
|
||||
assert(sipQtSupport->qt_find_slot);
|
||||
|
||||
if (slot != NULL)
|
||||
if (isQtSlot(slot) || isQtSignal(slot))
|
||||
{
|
||||
void *rx;
|
||||
|
||||
*memberp = slot;
|
||||
|
||||
if ((rx = sip_api_get_cpp_ptr((sipSimpleWrapper *)rxObj, sipQObjectType)) == NULL)
|
||||
return NULL;
|
||||
|
||||
if (isQtSignal(slot))
|
||||
rx = findSignal(rx, memberp);
|
||||
|
||||
return rx;
|
||||
}
|
||||
|
||||
/*
|
||||
* The slot was either a Python callable or PyQt3 Python signal so there
|
||||
* should be a universal slot.
|
||||
*/
|
||||
return sipQtSupport->qt_find_slot(sip_api_get_address(txSelf), sigargs, rxObj, slot, memberp);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Convert a Python receiver (either a Python signal or slot or a Qt signal or
|
||||
* slot) to a Qt receiver. It is only ever called when the signal is a Qt
|
||||
* signal. Return NULL is there was an error.
|
||||
*/
|
||||
void *sip_api_convert_rx(sipWrapper *txSelf, const char *sigargs,
|
||||
PyObject *rxObj, const char *slot, const char **memberp, int flags)
|
||||
{
|
||||
assert(sipQtSupport);
|
||||
|
||||
if (slot == NULL)
|
||||
return createUniversalSlot(txSelf, sigargs, rxObj, NULL, memberp, flags);
|
||||
|
||||
if (isQtSlot(slot) || isQtSignal(slot))
|
||||
{
|
||||
void *rx;
|
||||
|
||||
*memberp = slot;
|
||||
|
||||
if ((rx = sip_api_get_cpp_ptr((sipSimpleWrapper *)rxObj, sipQObjectType)) == NULL)
|
||||
return NULL;
|
||||
|
||||
if (isQtSignal(slot))
|
||||
rx = newSignal(rx, memberp);
|
||||
|
||||
return rx;
|
||||
}
|
||||
|
||||
/* The slot is a Python signal so we need a universal slot to catch it. */
|
||||
return createUniversalSlot(txSelf, sigargs, rxObj, slot, memberp, 0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Connect a Qt signal or a Python signal to a Qt slot, a Qt signal, a Python
|
||||
* slot or a Python signal. This is all possible combinations.
|
||||
*/
|
||||
PyObject *sip_api_connect_rx(PyObject *txObj, const char *sig, PyObject *rxObj,
|
||||
const char *slot, int type)
|
||||
{
|
||||
assert(sipQtSupport);
|
||||
assert(sipQtSupport->qt_connect);
|
||||
|
||||
/* Handle Qt signals. */
|
||||
if (isQtSignal(sig))
|
||||
{
|
||||
void *tx, *rx;
|
||||
const char *member, *real_sig;
|
||||
int res;
|
||||
|
||||
if ((tx = sip_api_get_cpp_ptr((sipSimpleWrapper *)txObj, sipQObjectType)) == NULL)
|
||||
return NULL;
|
||||
|
||||
real_sig = sig;
|
||||
|
||||
if ((tx = newSignal(tx, &real_sig)) == NULL)
|
||||
return NULL;
|
||||
|
||||
if ((rx = sip_api_convert_rx((sipWrapper *)txObj, sig, rxObj, slot, &member, 0)) == NULL)
|
||||
return NULL;
|
||||
|
||||
res = sipQtSupport->qt_connect(tx, real_sig, rx, member, type);
|
||||
|
||||
return PyBool_FromLong(res);
|
||||
}
|
||||
|
||||
/* Handle Python signals. Only PyQt3 would get this far. */
|
||||
assert(sipQtSupport->qt_connect_py_signal);
|
||||
|
||||
if (sipQtSupport->qt_connect_py_signal(txObj, sig, rxObj, slot) < 0)
|
||||
return NULL;
|
||||
|
||||
Py_INCREF(Py_True);
|
||||
return Py_True;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Disconnect a signal to a signal or a Qt slot.
|
||||
*/
|
||||
PyObject *sip_api_disconnect_rx(PyObject *txObj,const char *sig,
|
||||
PyObject *rxObj,const char *slot)
|
||||
{
|
||||
assert(sipQtSupport);
|
||||
assert(sipQtSupport->qt_disconnect);
|
||||
assert(sipQtSupport->qt_destroy_universal_slot);
|
||||
|
||||
/* Handle Qt signals. */
|
||||
if (isQtSignal(sig))
|
||||
{
|
||||
sipSimpleWrapper *txSelf = (sipSimpleWrapper *)txObj;
|
||||
void *tx, *rx;
|
||||
const char *member;
|
||||
int res;
|
||||
|
||||
if ((tx = sip_api_get_cpp_ptr(txSelf, sipQObjectType)) == NULL)
|
||||
return NULL;
|
||||
|
||||
if ((rx = sipGetRx(txSelf, sig, rxObj, slot, &member)) == NULL)
|
||||
{
|
||||
Py_INCREF(Py_False);
|
||||
return Py_False;
|
||||
}
|
||||
|
||||
/* Handle Python signals. */
|
||||
tx = findSignal(tx, &sig);
|
||||
|
||||
res = sipQtSupport->qt_disconnect(tx, sig, rx, member);
|
||||
|
||||
/*
|
||||
* Delete it if it is a universal slot as this will be it's only
|
||||
* connection. If the slot is actually a universal signal then it
|
||||
* should leave it in place.
|
||||
*/
|
||||
sipQtSupport->qt_destroy_universal_slot(rx);
|
||||
|
||||
return PyBool_FromLong(res);
|
||||
}
|
||||
|
||||
/* Handle Python signals. Only PyQt3 would get this far. */
|
||||
assert(sipQtSupport->qt_disconnect_py_signal);
|
||||
|
||||
sipQtSupport->qt_disconnect_py_signal(txObj, sig, rxObj, slot);
|
||||
|
||||
Py_INCREF(Py_True);
|
||||
return Py_True;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Free the resources of a slot.
|
||||
*/
|
||||
void sip_api_free_sipslot(sipSlot *slot)
|
||||
{
|
||||
assert(sipQtSupport);
|
||||
|
||||
if (slot->name != NULL)
|
||||
{
|
||||
sip_api_free(slot->name);
|
||||
}
|
||||
else if (slot->weakSlot == Py_True)
|
||||
{
|
||||
Py_DECREF(slot->pyobj);
|
||||
}
|
||||
|
||||
/* Remove any weak reference. */
|
||||
Py_XDECREF(slot->weakSlot);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Implement strdup() using sip_api_malloc().
|
||||
*/
|
||||
static char *sipStrdup(const char *s)
|
||||
{
|
||||
char *d;
|
||||
|
||||
if ((d = (char *)sip_api_malloc(strlen(s) + 1)) != NULL)
|
||||
strcpy(d,s);
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Initialise a slot, returning 0 if there was no error. If the signal was a
|
||||
* Qt signal, then the slot may be a Python signal or a Python slot. If the
|
||||
* signal was a Python signal, then the slot may be anything.
|
||||
*/
|
||||
int sip_api_save_slot(sipSlot *sp, PyObject *rxObj, const char *slot)
|
||||
{
|
||||
assert(sipQtSupport);
|
||||
|
||||
sp -> weakSlot = NULL;
|
||||
|
||||
if (slot == NULL)
|
||||
{
|
||||
sp -> name = NULL;
|
||||
|
||||
if (PyMethod_Check(rxObj))
|
||||
{
|
||||
/*
|
||||
* Python creates methods on the fly. We could increment the
|
||||
* reference count to keep it alive, but that would keep "self"
|
||||
* alive as well and would probably be a circular reference.
|
||||
* Instead we remember the component parts and hope they are still
|
||||
* valid when we re-create the method when we need it.
|
||||
*/
|
||||
sipSaveMethod(&sp -> meth,rxObj);
|
||||
|
||||
/* Notice if the class instance disappears. */
|
||||
sp -> weakSlot = getWeakRef(sp -> meth.mself);
|
||||
|
||||
/* This acts a flag to say that the slot is a method. */
|
||||
sp -> pyobj = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
PyObject *self;
|
||||
|
||||
/*
|
||||
* We know that it is another type of callable, ie. a
|
||||
* function/builtin.
|
||||
*/
|
||||
|
||||
if (PyCFunction_Check(rxObj) &&
|
||||
(self = PyCFunction_GET_SELF(rxObj)) != NULL &&
|
||||
PyObject_TypeCheck(self, (PyTypeObject *)&sipSimpleWrapper_Type))
|
||||
{
|
||||
/*
|
||||
* It is a wrapped C++ class method. We can't keep a copy
|
||||
* because they are generated on the fly and we can't take a
|
||||
* reference as that may keep the instance (ie. self) alive.
|
||||
* We therefore treat it as if the user had specified the slot
|
||||
* at "obj, SLOT('meth()')" rather than "obj.meth" (see below).
|
||||
*/
|
||||
|
||||
const char *meth;
|
||||
|
||||
/* Get the method name. */
|
||||
meth = ((PyCFunctionObject *)rxObj) -> m_ml -> ml_name;
|
||||
|
||||
if ((sp -> name = (char *)sip_api_malloc(strlen(meth) + 2)) == NULL)
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* Copy the name and set the marker that it needs converting to
|
||||
* a built-in method.
|
||||
*/
|
||||
sp -> name[0] = '\0';
|
||||
strcpy(&sp -> name[1],meth);
|
||||
|
||||
sp -> pyobj = self;
|
||||
sp -> weakSlot = getWeakRef(self);
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* Give the slot an extra reference to keep it alive and
|
||||
* remember we have done so by treating weakSlot specially.
|
||||
*/
|
||||
Py_INCREF(rxObj);
|
||||
sp->pyobj = rxObj;
|
||||
|
||||
Py_INCREF(Py_True);
|
||||
sp->weakSlot = Py_True;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ((sp -> name = sipStrdup(slot)) == NULL)
|
||||
return -1;
|
||||
else if (isQtSlot(slot))
|
||||
{
|
||||
/*
|
||||
* The user has decided to connect a Python signal to a Qt slot and
|
||||
* specified the slot as "obj, SLOT('meth()')" rather than "obj.meth".
|
||||
*/
|
||||
|
||||
char *tail;
|
||||
|
||||
/* Remove any arguments. */
|
||||
if ((tail = strchr(sp -> name,'(')) != NULL)
|
||||
*tail = '\0';
|
||||
|
||||
/*
|
||||
* A bit of a hack to indicate that this needs converting to a built-in
|
||||
* method.
|
||||
*/
|
||||
sp -> name[0] = '\0';
|
||||
|
||||
/* Notice if the class instance disappears. */
|
||||
sp -> weakSlot = getWeakRef(rxObj);
|
||||
|
||||
sp -> pyobj = rxObj;
|
||||
}
|
||||
else
|
||||
/* It's a Qt signal. */
|
||||
sp -> pyobj = rxObj;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Return a weak reference to the given object.
|
||||
*/
|
||||
static PyObject *getWeakRef(PyObject *obj)
|
||||
{
|
||||
PyObject *wr;
|
||||
|
||||
if ((wr = PyWeakref_NewRef(obj,NULL)) == NULL)
|
||||
PyErr_Clear();
|
||||
|
||||
return wr;
|
||||
}
|
||||
1909
sip/siplib/sip.h
1909
sip/siplib/sip.h
File diff suppressed because it is too large
Load Diff
@@ -1,189 +0,0 @@
|
||||
/*
|
||||
* This file defines the SIP library internal interfaces.
|
||||
*
|
||||
* Copyright (c) 2020 Riverbank Computing Limited <info@riverbankcomputing.com>
|
||||
*
|
||||
* This file is part of SIP.
|
||||
*
|
||||
* This copy of SIP is licensed for use under the terms of the SIP License
|
||||
* Agreement. See the file LICENSE for more details.
|
||||
*
|
||||
* This copy of SIP may also used under the terms of the GNU General Public
|
||||
* License v2 or v3 as published by the Free Software Foundation which can be
|
||||
* found in the files LICENSE-GPL2 and LICENSE-GPL3 included in this package.
|
||||
*
|
||||
* SIP is supplied WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _SIPINT_H
|
||||
#define _SIPINT_H
|
||||
|
||||
|
||||
#include <Python.h>
|
||||
|
||||
#include "sip.h"
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#undef TRUE
|
||||
#define TRUE 1
|
||||
|
||||
#undef FALSE
|
||||
#define FALSE 0
|
||||
|
||||
|
||||
/*
|
||||
* This defines a single entry in an object map's hash table.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
void *key; /* The C/C++ address. */
|
||||
sipSimpleWrapper *first; /* The first object at this address. */
|
||||
} sipHashEntry;
|
||||
|
||||
|
||||
/*
|
||||
* This defines the interface to a hash table class for mapping C/C++ addresses
|
||||
* to the corresponding wrapped Python object.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
int primeIdx; /* Index into table sizes. */
|
||||
unsigned long size; /* Size of hash table. */
|
||||
unsigned long unused; /* Nr. unused in hash table. */
|
||||
unsigned long stale; /* Nr. stale in hash table. */
|
||||
sipHashEntry *hash_array; /* Current hash table. */
|
||||
} sipObjectMap;
|
||||
|
||||
|
||||
/*
|
||||
* Support for the descriptors.
|
||||
*/
|
||||
extern PyTypeObject sipMethodDescr_Type;
|
||||
PyObject *sipMethodDescr_New(PyMethodDef *pmd);
|
||||
PyObject *sipMethodDescr_Copy(PyObject *orig, PyObject *mixin_name);
|
||||
|
||||
extern PyTypeObject sipVariableDescr_Type;
|
||||
PyObject *sipVariableDescr_New(sipVariableDef *vd, const sipTypeDef *td,
|
||||
const sipContainerDef *cod);
|
||||
PyObject *sipVariableDescr_Copy(PyObject *orig, PyObject *mixin_name);
|
||||
|
||||
|
||||
/*
|
||||
* Support for API versions.
|
||||
*/
|
||||
PyObject *sipGetAPI(PyObject *self, PyObject *args);
|
||||
PyObject *sipSetAPI(PyObject *self, PyObject *args);
|
||||
int sip_api_is_api_enabled(const char *name, int from, int to);
|
||||
int sipIsRangeEnabled(sipExportedModuleDef *em, int range_index);
|
||||
int sipInitAPI(sipExportedModuleDef *em, PyObject *mod_dict);
|
||||
|
||||
|
||||
/*
|
||||
* Support for void pointers.
|
||||
*/
|
||||
extern PyTypeObject sipVoidPtr_Type;
|
||||
void *sip_api_convert_to_void_ptr(PyObject *obj);
|
||||
PyObject *sip_api_convert_from_void_ptr(void *val);
|
||||
PyObject *sip_api_convert_from_const_void_ptr(const void *val);
|
||||
PyObject *sip_api_convert_from_void_ptr_and_size(void *val, Py_ssize_t size);
|
||||
PyObject *sip_api_convert_from_const_void_ptr_and_size(const void *val,
|
||||
Py_ssize_t size);
|
||||
|
||||
|
||||
/*
|
||||
* Support for int converters.
|
||||
*/
|
||||
PyObject *sipEnableOverflowChecking(PyObject *self, PyObject *args);
|
||||
int sip_api_enable_overflow_checking(int enable);
|
||||
int sip_api_convert_to_bool(PyObject *o);
|
||||
char sip_api_long_as_char(PyObject *o);
|
||||
signed char sip_api_long_as_signed_char(PyObject *o);
|
||||
unsigned char sip_api_long_as_unsigned_char(PyObject *o);
|
||||
short sip_api_long_as_short(PyObject *o);
|
||||
unsigned short sip_api_long_as_unsigned_short(PyObject *o);
|
||||
int sip_api_long_as_int(PyObject *o);
|
||||
unsigned int sip_api_long_as_unsigned_int(PyObject *o);
|
||||
long sip_api_long_as_long(PyObject *o);
|
||||
unsigned long sip_api_long_as_unsigned_long(PyObject *o);
|
||||
#if defined(HAVE_LONG_LONG)
|
||||
PY_LONG_LONG sip_api_long_as_long_long(PyObject *o);
|
||||
unsigned PY_LONG_LONG sip_api_long_as_unsigned_long_long(PyObject *o);
|
||||
#endif
|
||||
size_t sip_api_long_as_size_t(PyObject *o);
|
||||
|
||||
|
||||
extern sipQtAPI *sipQtSupport; /* The Qt support API. */
|
||||
extern sipWrapperType sipSimpleWrapper_Type; /* The simple wrapper type. */
|
||||
extern sipTypeDef *sipQObjectType; /* The QObject type. */
|
||||
|
||||
void *sipGetRx(sipSimpleWrapper *txSelf, const char *sigargs, PyObject *rxObj,
|
||||
const char *slot, const char **memberp);
|
||||
PyObject *sip_api_connect_rx(PyObject *txObj, const char *sig, PyObject *rxObj,
|
||||
const char *slot, int type);
|
||||
PyObject *sip_api_disconnect_rx(PyObject *txObj, const char *sig,
|
||||
PyObject *rxObj,const char *slot);
|
||||
|
||||
|
||||
/*
|
||||
* These are part of the SIP API but are also used within the SIP module.
|
||||
*/
|
||||
void *sip_api_malloc(size_t nbytes);
|
||||
void sip_api_free(void *mem);
|
||||
void *sip_api_get_address(sipSimpleWrapper *w);
|
||||
void *sip_api_get_cpp_ptr(sipSimpleWrapper *w, const sipTypeDef *td);
|
||||
PyObject *sip_api_convert_from_type(void *cppPtr, const sipTypeDef *td,
|
||||
PyObject *transferObj);
|
||||
void sip_api_instance_destroyed(sipSimpleWrapper *sipSelf);
|
||||
void sip_api_end_thread(void);
|
||||
void *sip_api_force_convert_to_type(PyObject *pyObj, const sipTypeDef *td,
|
||||
PyObject *transferObj, int flags, int *statep, int *iserrp);
|
||||
void sip_api_free_sipslot(sipSlot *slot);
|
||||
int sip_api_same_slot(const sipSlot *sp, PyObject *rxObj, const char *slot);
|
||||
PyObject *sip_api_invoke_slot(const sipSlot *slot, PyObject *sigargs);
|
||||
PyObject *sip_api_invoke_slot_ex(const sipSlot *slot, PyObject *sigargs,
|
||||
int no_receiver_check);
|
||||
void *sip_api_convert_rx(sipWrapper *txSelf, const char *sigargs,
|
||||
PyObject *rxObj, const char *slot, const char **memberp, int flags);
|
||||
int sip_api_save_slot(sipSlot *sp, PyObject *rxObj, const char *slot);
|
||||
int sip_api_convert_from_slice_object(PyObject *slice, Py_ssize_t length,
|
||||
Py_ssize_t *start, Py_ssize_t *stop, Py_ssize_t *step,
|
||||
Py_ssize_t *slicelength);
|
||||
int sip_api_deprecated(const char *classname, const char *method);
|
||||
|
||||
|
||||
/*
|
||||
* These are not part of the SIP API but are used within the SIP module.
|
||||
*/
|
||||
sipClassTypeDef *sipGetGeneratedClassType(const sipEncodedTypeDef *enc,
|
||||
const sipClassTypeDef *ctd);
|
||||
void sipSaveMethod(sipPyMethod *pm,PyObject *meth);
|
||||
int sipGetPending(void **pp, sipWrapper **op, int *fp);
|
||||
int sipIsPending(void);
|
||||
PyObject *sipWrapInstance(void *cpp, PyTypeObject *py_type, PyObject *args,
|
||||
sipWrapper *owner, int flags);
|
||||
void *sipConvertRxEx(sipWrapper *txSelf, const char *sigargs,
|
||||
PyObject *rxObj, const char *slot, const char **memberp, int flags);
|
||||
|
||||
void sipOMInit(sipObjectMap *om);
|
||||
void sipOMFinalise(sipObjectMap *om);
|
||||
sipSimpleWrapper *sipOMFindObject(sipObjectMap *om, void *key,
|
||||
const sipTypeDef *td);
|
||||
void sipOMAddObject(sipObjectMap *om, sipSimpleWrapper *val);
|
||||
int sipOMRemoveObject(sipObjectMap *om, sipSimpleWrapper *val);
|
||||
|
||||
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
|
||||
#define sipSetBool(p, v) (*(_Bool *)(p) = (v))
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
13281
sip/siplib/siplib.c
13281
sip/siplib/siplib.c
File diff suppressed because it is too large
Load Diff
@@ -1,218 +0,0 @@
|
||||
/*
|
||||
* Thread support for the SIP library. This module provides the hooks for
|
||||
* C++ classes that provide a thread interface to interact properly with the
|
||||
* Python threading infrastructure.
|
||||
*
|
||||
* Copyright (c) 2020 Riverbank Computing Limited <info@riverbankcomputing.com>
|
||||
*
|
||||
* This file is part of SIP.
|
||||
*
|
||||
* This copy of SIP is licensed for use under the terms of the SIP License
|
||||
* Agreement. See the file LICENSE for more details.
|
||||
*
|
||||
* This copy of SIP may also used under the terms of the GNU General Public
|
||||
* License v2 or v3 as published by the Free Software Foundation which can be
|
||||
* found in the files LICENSE-GPL2 and LICENSE-GPL3 included in this package.
|
||||
*
|
||||
* SIP is supplied WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*/
|
||||
|
||||
|
||||
#include "sipint.h"
|
||||
|
||||
|
||||
/*
|
||||
* The data associated with pending request to wrap an object.
|
||||
*/
|
||||
typedef struct _pendingDef {
|
||||
void *cpp; /* The C/C++ object ot be wrapped. */
|
||||
sipWrapper *owner; /* The owner of the object. */
|
||||
int flags; /* The flags. */
|
||||
} pendingDef;
|
||||
|
||||
|
||||
#ifdef WITH_THREAD
|
||||
|
||||
#include <pythread.h>
|
||||
|
||||
|
||||
/*
|
||||
* The per thread data we need to maintain.
|
||||
*/
|
||||
typedef struct _threadDef {
|
||||
long thr_ident; /* The thread identifier. */
|
||||
pendingDef pending; /* An object waiting to be wrapped. */
|
||||
struct _threadDef *next; /* Next in the list. */
|
||||
} threadDef;
|
||||
|
||||
static threadDef *threads = NULL; /* Linked list of threads. */
|
||||
|
||||
static threadDef *currentThreadDef(int auto_alloc);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
static pendingDef *get_pending(int auto_alloc);
|
||||
|
||||
|
||||
/*
|
||||
* Get the address etc. of any C/C++ object waiting to be wrapped.
|
||||
*/
|
||||
int sipGetPending(void **pp, sipWrapper **op, int *fp)
|
||||
{
|
||||
pendingDef *pd;
|
||||
|
||||
if ((pd = get_pending(TRUE)) == NULL)
|
||||
return -1;
|
||||
|
||||
*pp = pd->cpp;
|
||||
*op = pd->owner;
|
||||
*fp = pd->flags;
|
||||
|
||||
/* Clear in case we execute Python code before finishing this wrapping. */
|
||||
pd->cpp = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Return TRUE if anything is pending.
|
||||
*/
|
||||
int sipIsPending(void)
|
||||
{
|
||||
pendingDef *pd;
|
||||
|
||||
if ((pd = get_pending(FALSE)) == NULL)
|
||||
return FALSE;
|
||||
|
||||
return (pd->cpp != NULL);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Convert a new C/C++ pointer to a Python instance.
|
||||
*/
|
||||
PyObject *sipWrapInstance(void *cpp, PyTypeObject *py_type, PyObject *args,
|
||||
sipWrapper *owner, int flags)
|
||||
{
|
||||
pendingDef old_pending, *pd;
|
||||
PyObject *self;
|
||||
|
||||
if (cpp == NULL)
|
||||
{
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
/*
|
||||
* Object creation can trigger the Python garbage collector which in turn
|
||||
* can execute arbitrary Python code which can then call this function
|
||||
* recursively. Therefore we save any existing pending object before
|
||||
* setting the new one.
|
||||
*/
|
||||
if ((pd = get_pending(TRUE)) == NULL)
|
||||
return NULL;
|
||||
|
||||
old_pending = *pd;
|
||||
|
||||
pd->cpp = cpp;
|
||||
pd->owner = owner;
|
||||
pd->flags = flags;
|
||||
|
||||
self = PyObject_Call((PyObject *)py_type, args, NULL);
|
||||
|
||||
*pd = old_pending;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Handle the termination of a thread.
|
||||
*/
|
||||
void sip_api_end_thread(void)
|
||||
{
|
||||
#ifdef WITH_THREAD
|
||||
threadDef *thread;
|
||||
PyGILState_STATE gil = PyGILState_Ensure();
|
||||
|
||||
if ((thread = currentThreadDef(FALSE)) != NULL)
|
||||
thread->thr_ident = 0;
|
||||
|
||||
PyGILState_Release(gil);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Return the pending data for the current thread, allocating it if necessary,
|
||||
* or NULL if there was an error.
|
||||
*/
|
||||
static pendingDef *get_pending(int auto_alloc)
|
||||
{
|
||||
#ifdef WITH_THREAD
|
||||
threadDef *thread;
|
||||
|
||||
if ((thread = currentThreadDef(auto_alloc)) == NULL)
|
||||
return NULL;
|
||||
|
||||
return &thread->pending;
|
||||
#else
|
||||
static pendingDef pending;
|
||||
|
||||
return &pending;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#ifdef WITH_THREAD
|
||||
|
||||
/*
|
||||
* Return the thread data for the current thread, allocating it if necessary,
|
||||
* or NULL if there was an error.
|
||||
*/
|
||||
static threadDef *currentThreadDef(int auto_alloc)
|
||||
{
|
||||
threadDef *thread, *empty = NULL;
|
||||
long ident = PyThread_get_thread_ident();
|
||||
|
||||
/* See if we already know about the thread. */
|
||||
for (thread = threads; thread != NULL; thread = thread->next)
|
||||
{
|
||||
if (thread->thr_ident == ident)
|
||||
return thread;
|
||||
|
||||
if (thread->thr_ident == 0)
|
||||
empty = thread;
|
||||
}
|
||||
|
||||
if (!auto_alloc)
|
||||
{
|
||||
/* This is not an error. */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (empty != NULL)
|
||||
{
|
||||
/* Use an empty entry in the list. */
|
||||
thread = empty;
|
||||
}
|
||||
else if ((thread = sip_api_malloc(sizeof (threadDef))) == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
thread->next = threads;
|
||||
threads = thread;
|
||||
}
|
||||
|
||||
thread->thr_ident = ident;
|
||||
thread->pending.cpp = NULL;
|
||||
|
||||
return thread;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,752 +0,0 @@
|
||||
/*
|
||||
* SIP library code.
|
||||
*
|
||||
* Copyright (c) 2019 Riverbank Computing Limited <info@riverbankcomputing.com>
|
||||
*
|
||||
* This file is part of SIP.
|
||||
*
|
||||
* This copy of SIP is licensed for use under the terms of the SIP License
|
||||
* Agreement. See the file LICENSE for more details.
|
||||
*
|
||||
* This copy of SIP may also used under the terms of the GNU General Public
|
||||
* License v2 or v3 as published by the Free Software Foundation which can be
|
||||
* found in the files LICENSE-GPL2 and LICENSE-GPL3 included in this package.
|
||||
*
|
||||
* SIP is supplied WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*/
|
||||
|
||||
|
||||
#include <Python.h>
|
||||
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "sipint.h"
|
||||
#include "array.h"
|
||||
|
||||
|
||||
/* The object data structure. */
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
void *voidptr;
|
||||
Py_ssize_t size;
|
||||
int rw;
|
||||
} sipVoidPtrObject;
|
||||
|
||||
|
||||
/* The structure used to hold the results of a voidptr conversion. */
|
||||
struct vp_values {
|
||||
void *voidptr;
|
||||
Py_ssize_t size;
|
||||
int rw;
|
||||
};
|
||||
|
||||
|
||||
static int check_size(PyObject *self);
|
||||
static int check_rw(PyObject *self);
|
||||
static int check_index(PyObject *self, Py_ssize_t idx);
|
||||
static void bad_key(PyObject *key);
|
||||
static int check_slice_size(Py_ssize_t size, Py_ssize_t value_size);
|
||||
static PyObject *make_voidptr(void *voidptr, Py_ssize_t size, int rw);
|
||||
static int vp_convertor(PyObject *arg, struct vp_values *vp);
|
||||
static Py_ssize_t get_size_from_arg(sipVoidPtrObject *v, Py_ssize_t size);
|
||||
|
||||
|
||||
/*
|
||||
* Implement ascapsule() for the type.
|
||||
*/
|
||||
static PyObject *sipVoidPtr_ascapsule(sipVoidPtrObject *v, PyObject *arg)
|
||||
{
|
||||
(void)arg;
|
||||
|
||||
return PyCapsule_New(v->voidptr, NULL, NULL);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Implement asarray() for the type.
|
||||
*/
|
||||
static PyObject *sipVoidPtr_asarray(sipVoidPtrObject *v, PyObject *args,
|
||||
PyObject *kw)
|
||||
{
|
||||
static char *kwlist[] = {"size", NULL};
|
||||
|
||||
Py_ssize_t size = -1;
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kw, "|n:asarray", kwlist, &size))
|
||||
return NULL;
|
||||
|
||||
if ((size = get_size_from_arg(v, size)) < 0)
|
||||
return NULL;
|
||||
|
||||
return sip_api_convert_to_array(v->voidptr, "B", size,
|
||||
(v->rw ? 0 : SIP_READ_ONLY));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Implement asstring() for the type.
|
||||
*/
|
||||
static PyObject *sipVoidPtr_asstring(sipVoidPtrObject *v, PyObject *args,
|
||||
PyObject *kw)
|
||||
{
|
||||
static char *kwlist[] = {"size", NULL};
|
||||
|
||||
Py_ssize_t size = -1;
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kw, "|n:asstring", kwlist, &size))
|
||||
return NULL;
|
||||
|
||||
if ((size = get_size_from_arg(v, size)) < 0)
|
||||
return NULL;
|
||||
|
||||
return PyBytes_FromStringAndSize(v->voidptr, size);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Implement getsize() for the type.
|
||||
*/
|
||||
static PyObject *sipVoidPtr_getsize(sipVoidPtrObject *v, PyObject *arg)
|
||||
{
|
||||
(void)arg;
|
||||
|
||||
return PyLong_FromSsize_t(v->size);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Implement setsize() for the type.
|
||||
*/
|
||||
static PyObject *sipVoidPtr_setsize(sipVoidPtrObject *v, PyObject *arg)
|
||||
{
|
||||
Py_ssize_t size = PyLong_AsSsize_t(arg);
|
||||
|
||||
if (PyErr_Occurred())
|
||||
return NULL;
|
||||
|
||||
v->size = size;
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Implement getwriteable() for the type.
|
||||
*/
|
||||
static PyObject *sipVoidPtr_getwriteable(sipVoidPtrObject *v, PyObject *arg)
|
||||
{
|
||||
(void)arg;
|
||||
|
||||
return PyBool_FromLong(v->rw);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Implement setwriteable() for the type.
|
||||
*/
|
||||
static PyObject *sipVoidPtr_setwriteable(sipVoidPtrObject *v, PyObject *arg)
|
||||
{
|
||||
int rw;
|
||||
|
||||
if ((rw = PyObject_IsTrue(arg)) < 0)
|
||||
return NULL;
|
||||
|
||||
v->rw = rw;
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
|
||||
/* The methods data structure. */
|
||||
static PyMethodDef sipVoidPtr_Methods[] = {
|
||||
{"asarray", (PyCFunction)sipVoidPtr_asarray, METH_VARARGS|METH_KEYWORDS, NULL},
|
||||
{"ascapsule", (PyCFunction)sipVoidPtr_ascapsule, METH_NOARGS, NULL},
|
||||
{"asstring", (PyCFunction)sipVoidPtr_asstring, METH_VARARGS|METH_KEYWORDS, NULL},
|
||||
{"getsize", (PyCFunction)sipVoidPtr_getsize, METH_NOARGS, NULL},
|
||||
{"setsize", (PyCFunction)sipVoidPtr_setsize, METH_O, NULL},
|
||||
{"getwriteable", (PyCFunction)sipVoidPtr_getwriteable, METH_NOARGS, NULL},
|
||||
{"setwriteable", (PyCFunction)sipVoidPtr_setwriteable, METH_O, NULL},
|
||||
{NULL, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Implement bool() for the type.
|
||||
*/
|
||||
static int sipVoidPtr_bool(PyObject *self)
|
||||
{
|
||||
return (((sipVoidPtrObject *)self)->voidptr != NULL);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Implement int() for the type.
|
||||
*/
|
||||
static PyObject *sipVoidPtr_int(PyObject *self)
|
||||
{
|
||||
return PyLong_FromVoidPtr(((sipVoidPtrObject *)self)->voidptr);
|
||||
}
|
||||
|
||||
|
||||
/* The number methods data structure. */
|
||||
static PyNumberMethods sipVoidPtr_NumberMethods = {
|
||||
0, /* nb_add */
|
||||
0, /* nb_subtract */
|
||||
0, /* nb_multiply */
|
||||
0, /* nb_remainder */
|
||||
0, /* nb_divmod */
|
||||
0, /* nb_power */
|
||||
0, /* nb_negative */
|
||||
0, /* nb_positive */
|
||||
0, /* nb_absolute */
|
||||
sipVoidPtr_bool, /* nb_bool */
|
||||
0, /* nb_invert */
|
||||
0, /* nb_lshift */
|
||||
0, /* nb_rshift */
|
||||
0, /* nb_and */
|
||||
0, /* nb_xor */
|
||||
0, /* nb_or */
|
||||
sipVoidPtr_int, /* nb_int */
|
||||
0, /* nb_reserved */
|
||||
0, /* nb_float */
|
||||
0, /* nb_inplace_add */
|
||||
0, /* nb_inplace_subtract */
|
||||
0, /* nb_inplace_multiply */
|
||||
0, /* nb_inplace_remainder */
|
||||
0, /* nb_inplace_power */
|
||||
0, /* nb_inplace_lshift */
|
||||
0, /* nb_inplace_rshift */
|
||||
0, /* nb_inplace_and */
|
||||
0, /* nb_inplace_xor */
|
||||
0, /* nb_inplace_or */
|
||||
0, /* nb_floor_divide */
|
||||
0, /* nb_true_divide */
|
||||
0, /* nb_inplace_floor_divide */
|
||||
0, /* nb_inplace_true_divide */
|
||||
0, /* nb_index */
|
||||
0, /* nb_matrix_multiply */
|
||||
0, /* nb_inplace_matrix_multiply */
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Implement len() for the type.
|
||||
*/
|
||||
static Py_ssize_t sipVoidPtr_length(PyObject *self)
|
||||
{
|
||||
if (check_size(self) < 0)
|
||||
return -1;
|
||||
|
||||
return ((sipVoidPtrObject *)self)->size;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Implement sequence item sub-script for the type.
|
||||
*/
|
||||
static PyObject *sipVoidPtr_item(PyObject *self, Py_ssize_t idx)
|
||||
{
|
||||
if (check_size(self) < 0 || check_index(self, idx) < 0)
|
||||
return NULL;
|
||||
|
||||
return PyBytes_FromStringAndSize(
|
||||
(char *)((sipVoidPtrObject *)self)->voidptr + idx, 1);
|
||||
}
|
||||
|
||||
|
||||
/* The sequence methods data structure. */
|
||||
static PySequenceMethods sipVoidPtr_SequenceMethods = {
|
||||
sipVoidPtr_length, /* sq_length */
|
||||
0, /* sq_concat */
|
||||
0, /* sq_repeat */
|
||||
sipVoidPtr_item, /* sq_item */
|
||||
0, /* sq_slice */
|
||||
0, /* sq_ass_item */
|
||||
0, /* sq_ass_slice */
|
||||
0, /* sq_contains */
|
||||
0, /* sq_inplace_concat */
|
||||
0, /* sq_inplace_repeat */
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Implement mapping sub-script for the type.
|
||||
*/
|
||||
static PyObject *sipVoidPtr_subscript(PyObject *self, PyObject *key)
|
||||
{
|
||||
sipVoidPtrObject *v;
|
||||
|
||||
if (check_size(self) < 0)
|
||||
return NULL;
|
||||
|
||||
v = (sipVoidPtrObject *)self;
|
||||
|
||||
if (PyIndex_Check(key))
|
||||
{
|
||||
Py_ssize_t idx = PyNumber_AsSsize_t(key, PyExc_IndexError);
|
||||
|
||||
if (idx == -1 && PyErr_Occurred())
|
||||
return NULL;
|
||||
|
||||
if (idx < 0)
|
||||
idx += v->size;
|
||||
|
||||
return sipVoidPtr_item(self, idx);
|
||||
}
|
||||
|
||||
if (PySlice_Check(key))
|
||||
{
|
||||
Py_ssize_t start, stop, step, slicelength;
|
||||
|
||||
if (sip_api_convert_from_slice_object(key, v->size, &start, &stop, &step, &slicelength) < 0)
|
||||
return NULL;
|
||||
|
||||
if (step != 1)
|
||||
{
|
||||
PyErr_SetNone(PyExc_NotImplementedError);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return make_voidptr((char *)v->voidptr + start, slicelength, v->rw);
|
||||
}
|
||||
|
||||
bad_key(key);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Implement mapping assignment sub-script for the type.
|
||||
*/
|
||||
static int sipVoidPtr_ass_subscript(PyObject *self, PyObject *key,
|
||||
PyObject *value)
|
||||
{
|
||||
sipVoidPtrObject *v;
|
||||
Py_ssize_t start, size;
|
||||
Py_buffer value_view;
|
||||
|
||||
if (check_rw(self) < 0 || check_size(self) < 0)
|
||||
return -1;
|
||||
|
||||
v = (sipVoidPtrObject *)self;
|
||||
|
||||
if (PyIndex_Check(key))
|
||||
{
|
||||
start = PyNumber_AsSsize_t(key, PyExc_IndexError);
|
||||
|
||||
if (start == -1 && PyErr_Occurred())
|
||||
return -1;
|
||||
|
||||
if (start < 0)
|
||||
start += v->size;
|
||||
|
||||
if (check_index(self, start) < 0)
|
||||
return -1;
|
||||
|
||||
size = 1;
|
||||
}
|
||||
else if (PySlice_Check(key))
|
||||
{
|
||||
Py_ssize_t stop, step;
|
||||
|
||||
if (sip_api_convert_from_slice_object(key, v->size, &start, &stop, &step, &size) < 0)
|
||||
return -1;
|
||||
|
||||
if (step != 1)
|
||||
{
|
||||
PyErr_SetNone(PyExc_NotImplementedError);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bad_key(key);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (PyObject_GetBuffer(value, &value_view, PyBUF_CONTIG_RO) < 0)
|
||||
return -1;
|
||||
|
||||
/* We could allow any item size... */
|
||||
if (value_view.itemsize != 1)
|
||||
{
|
||||
PyErr_Format(PyExc_TypeError, "'%s' must have an item size of 1",
|
||||
Py_TYPE(value_view.obj)->tp_name);
|
||||
|
||||
PyBuffer_Release(&value_view);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (check_slice_size(size, value_view.len) < 0)
|
||||
{
|
||||
PyBuffer_Release(&value_view);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memmove((char *)v->voidptr + start, value_view.buf, size);
|
||||
|
||||
PyBuffer_Release(&value_view);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* The mapping methods data structure. */
|
||||
static PyMappingMethods sipVoidPtr_MappingMethods = {
|
||||
sipVoidPtr_length, /* mp_length */
|
||||
sipVoidPtr_subscript, /* mp_subscript */
|
||||
sipVoidPtr_ass_subscript, /* mp_ass_subscript */
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* The buffer implementation for Python v2.6.3 and later.
|
||||
*/
|
||||
static int sipVoidPtr_getbuffer(PyObject *self, Py_buffer *buf, int flags)
|
||||
{
|
||||
sipVoidPtrObject *v;
|
||||
|
||||
if (check_size(self) < 0)
|
||||
return -1;
|
||||
|
||||
v = (sipVoidPtrObject *)self;
|
||||
|
||||
return PyBuffer_FillInfo(buf, self, v->voidptr, v->size, !v->rw, flags);
|
||||
}
|
||||
|
||||
|
||||
/* The buffer methods data structure. */
|
||||
static PyBufferProcs sipVoidPtr_BufferProcs = {
|
||||
sipVoidPtr_getbuffer, /* bf_getbuffer */
|
||||
0 /* bf_releasebuffer */
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Implement __new__ for the type.
|
||||
*/
|
||||
static PyObject *sipVoidPtr_new(PyTypeObject *subtype, PyObject *args,
|
||||
PyObject *kw)
|
||||
{
|
||||
static char *kwlist[] = {"address", "size", "writeable", NULL};
|
||||
|
||||
struct vp_values vp_conversion;
|
||||
Py_ssize_t size = -1;
|
||||
int rw = -1;
|
||||
PyObject *obj;
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kw, "O&|ni:voidptr", kwlist, vp_convertor, &vp_conversion, &size, &rw))
|
||||
return NULL;
|
||||
|
||||
/* Use the explicit size if one was given. */
|
||||
if (size >= 0)
|
||||
vp_conversion.size = size;
|
||||
|
||||
/* Use the explicit writeable flag if one was given. */
|
||||
if (rw >= 0)
|
||||
vp_conversion.rw = rw;
|
||||
|
||||
/* Create the instance. */
|
||||
if ((obj = subtype->tp_alloc(subtype, 0)) == NULL)
|
||||
return NULL;
|
||||
|
||||
/* Save the values. */
|
||||
((sipVoidPtrObject *)obj)->voidptr = vp_conversion.voidptr;
|
||||
((sipVoidPtrObject *)obj)->size = vp_conversion.size;
|
||||
((sipVoidPtrObject *)obj)->rw = vp_conversion.rw;
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
||||
/* The type data structure. */
|
||||
PyTypeObject sipVoidPtr_Type = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0)
|
||||
"sip.voidptr", /* tp_name */
|
||||
sizeof (sipVoidPtrObject), /* tp_basicsize */
|
||||
0, /* tp_itemsize */
|
||||
0, /* tp_dealloc */
|
||||
0, /* tp_print */
|
||||
0, /* tp_getattr */
|
||||
0, /* tp_setattr */
|
||||
0, /* tp_reserved (Python v3), tp_compare (Python v2) */
|
||||
0, /* tp_repr */
|
||||
&sipVoidPtr_NumberMethods, /* tp_as_number */
|
||||
&sipVoidPtr_SequenceMethods, /* tp_as_sequence */
|
||||
&sipVoidPtr_MappingMethods, /* tp_as_mapping */
|
||||
0, /* tp_hash */
|
||||
0, /* tp_call */
|
||||
0, /* tp_str */
|
||||
0, /* tp_getattro */
|
||||
0, /* tp_setattro */
|
||||
&sipVoidPtr_BufferProcs, /* tp_as_buffer */
|
||||
#if defined(Py_TPFLAGS_HAVE_NEWBUFFER)
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_NEWBUFFER, /* tp_flags */
|
||||
#else
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
|
||||
#endif
|
||||
0, /* tp_doc */
|
||||
0, /* tp_traverse */
|
||||
0, /* tp_clear */
|
||||
0, /* tp_richcompare */
|
||||
0, /* tp_weaklistoffset */
|
||||
0, /* tp_iter */
|
||||
0, /* tp_iternext */
|
||||
sipVoidPtr_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 */
|
||||
sipVoidPtr_new, /* tp_new */
|
||||
0, /* 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, /* tp_version_tag */
|
||||
0, /* tp_finalize */
|
||||
#if PY_VERSION_HEX >= 0x03080000
|
||||
0, /* tp_vectorcall */
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* A convenience function to convert a C/C++ void pointer from a Python object.
|
||||
*/
|
||||
void *sip_api_convert_to_void_ptr(PyObject *obj)
|
||||
{
|
||||
struct vp_values vp;
|
||||
|
||||
if (obj == NULL)
|
||||
{
|
||||
PyErr_SetString(PyExc_TypeError, "sip.voidptr is NULL");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (vp_convertor(obj, &vp))
|
||||
return vp.voidptr;
|
||||
|
||||
return PyLong_AsVoidPtr(obj);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Convert a C/C++ void pointer to a sip.voidptr object.
|
||||
*/
|
||||
PyObject *sip_api_convert_from_void_ptr(void *val)
|
||||
{
|
||||
return make_voidptr(val, -1, TRUE);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Convert a C/C++ void pointer to a sip.voidptr object.
|
||||
*/
|
||||
PyObject *sip_api_convert_from_const_void_ptr(const void *val)
|
||||
{
|
||||
return make_voidptr((void *)val, -1, FALSE);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Convert a sized C/C++ void pointer to a sip.voidptr object.
|
||||
*/
|
||||
PyObject *sip_api_convert_from_void_ptr_and_size(void *val, Py_ssize_t size)
|
||||
{
|
||||
return make_voidptr(val, size, TRUE);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Convert a sized C/C++ const void pointer to a sip.voidptr object.
|
||||
*/
|
||||
PyObject *sip_api_convert_from_const_void_ptr_and_size(const void *val,
|
||||
Py_ssize_t size)
|
||||
{
|
||||
return make_voidptr((void *)val, size, FALSE);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Check that a void pointer has an explicit size and raise an exception if it
|
||||
* hasn't.
|
||||
*/
|
||||
static int check_size(PyObject *self)
|
||||
{
|
||||
if (((sipVoidPtrObject *)self)->size >= 0)
|
||||
return 0;
|
||||
|
||||
PyErr_SetString(PyExc_IndexError,
|
||||
"sip.voidptr object has an unknown size");
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Check that a void pointer is writable.
|
||||
*/
|
||||
static int check_rw(PyObject *self)
|
||||
{
|
||||
if (((sipVoidPtrObject *)self)->rw)
|
||||
return 0;
|
||||
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"cannot modify a read-only sip.voidptr object");
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Check that an index is valid for a void pointer.
|
||||
*/
|
||||
static int check_index(PyObject *self, Py_ssize_t idx)
|
||||
{
|
||||
if (idx >= 0 && idx < ((sipVoidPtrObject *)self)->size)
|
||||
return 0;
|
||||
|
||||
PyErr_SetString(PyExc_IndexError, "index out of bounds");
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Raise an exception about a bad sub-script key.
|
||||
*/
|
||||
static void bad_key(PyObject *key)
|
||||
{
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"cannot index a sip.voidptr object using '%s'",
|
||||
Py_TYPE(key)->tp_name);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Check that the size of a value is the same as the size of the slice it is
|
||||
* replacing.
|
||||
*/
|
||||
static int check_slice_size(Py_ssize_t size, Py_ssize_t value_size)
|
||||
{
|
||||
if (value_size == size)
|
||||
return 0;
|
||||
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"cannot modify the size of a sip.voidptr object");
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Do the work of converting a void pointer.
|
||||
*/
|
||||
static PyObject *make_voidptr(void *voidptr, Py_ssize_t size, int rw)
|
||||
{
|
||||
sipVoidPtrObject *self;
|
||||
|
||||
if (voidptr == NULL)
|
||||
{
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
if ((self = PyObject_NEW(sipVoidPtrObject, &sipVoidPtr_Type)) == NULL)
|
||||
return NULL;
|
||||
|
||||
self->voidptr = voidptr;
|
||||
self->size = size;
|
||||
self->rw = rw;
|
||||
|
||||
return (PyObject *)self;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Convert a Python object to the values needed to create a voidptr.
|
||||
*/
|
||||
static int vp_convertor(PyObject *arg, struct vp_values *vp)
|
||||
{
|
||||
void *ptr;
|
||||
Py_ssize_t size = -1;
|
||||
int rw = TRUE;
|
||||
|
||||
if (arg == Py_None)
|
||||
{
|
||||
ptr = NULL;
|
||||
}
|
||||
else if (PyCapsule_CheckExact(arg))
|
||||
{
|
||||
ptr = PyCapsule_GetPointer(arg, NULL);
|
||||
}
|
||||
else if (PyObject_TypeCheck(arg, &sipVoidPtr_Type))
|
||||
{
|
||||
ptr = ((sipVoidPtrObject *)arg)->voidptr;
|
||||
size = ((sipVoidPtrObject *)arg)->size;
|
||||
rw = ((sipVoidPtrObject *)arg)->rw;
|
||||
}
|
||||
else if (PyObject_CheckBuffer(arg))
|
||||
{
|
||||
Py_buffer view;
|
||||
|
||||
if (PyObject_GetBuffer(arg, &view, PyBUF_SIMPLE) < 0)
|
||||
return 0;
|
||||
|
||||
ptr = view.buf;
|
||||
size = view.len;
|
||||
rw = !view.readonly;
|
||||
|
||||
PyBuffer_Release(&view);
|
||||
}
|
||||
else
|
||||
{
|
||||
PyErr_Clear();
|
||||
ptr = PyLong_AsVoidPtr(arg);
|
||||
|
||||
if (PyErr_Occurred())
|
||||
{
|
||||
PyErr_SetString(PyExc_TypeError, "a single integer, Capsule, None, bytes-like object or another sip.voidptr object is required");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
vp->voidptr = ptr;
|
||||
vp->size = size;
|
||||
vp->rw = rw;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Get a size possibly supplied as an argument, otherwise get it from the
|
||||
* object. Raise an exception if there was no size specified.
|
||||
*/
|
||||
static Py_ssize_t get_size_from_arg(sipVoidPtrObject *v, Py_ssize_t size)
|
||||
{
|
||||
/* Use the current size if one wasn't explicitly given. */
|
||||
if (size < 0)
|
||||
size = v->size;
|
||||
|
||||
if (size < 0)
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"a size must be given or the sip.voidptr object must have a size");
|
||||
|
||||
return size;
|
||||
}
|
||||
2
wscript
2
wscript
@@ -563,12 +563,12 @@ def build(bld):
|
||||
features = 'c cxx cshlib cxxshlib pyext',
|
||||
target = makeTargetName(bld, 'siplib'),
|
||||
source = ['sip/siplib/apiversions.c',
|
||||
'sip/siplib/array.c',
|
||||
'sip/siplib/bool.cpp',
|
||||
'sip/siplib/descriptors.c',
|
||||
'sip/siplib/int_convertors.c',
|
||||
'sip/siplib/objmap.c',
|
||||
'sip/siplib/qtlib.c',
|
||||
'sip/siplib/sip_array.c',
|
||||
'sip/siplib/siplib.c',
|
||||
'sip/siplib/threads.c',
|
||||
'sip/siplib/voidptr.c',
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user