cpython/Modules/_ctypes/cfield.c

#ifndef Py_BUILD_CORE_BUILTIN
#define Py_BUILD_CORE_MODULE
#endif

#include "Python.h"
// windows.h must be included before pycore internal headers
#ifdef MS_WIN32
#  include <windows.h>
#endif

#include "pycore_bitutils.h"      // _Py_bswap32()
#include "pycore_call.h"          // _PyObject_CallNoArgs()

#include <ffi.h>
#include "ctypes.h"

#if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TARGET_HAS_COMPLEX_TYPE)
#  include "../_complex.h"        // complex
#endif

#define CTYPES_CFIELD_CAPSULE_NAME_PYMEM

static void pymem_destructor(PyObject *ptr)
{}


/******************************************************************/
/*
  PyCField_Type
*/

static inline
Py_ssize_t round_down(Py_ssize_t numToRound, Py_ssize_t multiple)
{}

static inline
Py_ssize_t round_up(Py_ssize_t numToRound, Py_ssize_t multiple)
{}

static inline
Py_ssize_t NUM_BITS(Py_ssize_t bitsize);
static inline
Py_ssize_t LOW_BIT(Py_ssize_t offset);
static inline
Py_ssize_t BUILD_SIZE(Py_ssize_t bitsize, Py_ssize_t offset);

/* PyCField_FromDesc creates and returns a struct/union field descriptor.

The function expects to be called repeatedly for all fields in a struct or
union.  It uses helper functions PyCField_FromDesc_gcc and
PyCField_FromDesc_msvc to simulate the corresponding compilers.

GCC mode places fields one after another, bit by bit.  But "each bit field must
fit within a single object of its specified type" (GCC manual, section 15.8
"Bit Field Packing"). When it doesn't, we insert a few bits of padding to
avoid that.

MSVC mode works similar except for bitfield packing.  Adjacent bit-fields are
packed into the same 1-, 2-, or 4-byte allocation unit if the integral types
are the same size and if the next bit-field fits into the current allocation
unit without crossing the boundary imposed by the common alignment requirements
of the bit-fields.

See https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html#index-mms-bitfields for details.

We do not support zero length bitfields.  In fact we use bitsize != 0 elsewhere
to indicate a bitfield. Here, non-bitfields need bitsize set to size*8.

PyCField_FromDesc manages:
- *psize: the size of the structure / union so far.
- *poffset, *pbitofs: 8* (*poffset) + *pbitofs points to where the next field
  would start.
- *palign: the alignment requirements of the last field we placed.
*/

static int
PyCField_FromDesc_gcc(Py_ssize_t bitsize, Py_ssize_t *pbitofs,
                Py_ssize_t *psize, Py_ssize_t *poffset, Py_ssize_t *palign,
                CFieldObject* self, StgInfo* info,
                int is_bitfield
                )
{}

static int
PyCField_FromDesc_msvc(
                Py_ssize_t *pfield_size, Py_ssize_t bitsize,
                Py_ssize_t *pbitofs, Py_ssize_t *psize, Py_ssize_t *poffset,
                Py_ssize_t *palign, int pack,
                CFieldObject* self, StgInfo* info,
                int is_bitfield
                )
{}

PyObject *
PyCField_FromDesc(ctypes_state *st, PyObject *desc, Py_ssize_t index,
                Py_ssize_t *pfield_size, Py_ssize_t bitsize,
                Py_ssize_t *pbitofs, Py_ssize_t *psize, Py_ssize_t *poffset, Py_ssize_t *palign,
                int pack, int big_endian, LayoutMode layout_mode)
{}

static int
PyCField_set(CFieldObject *self, PyObject *inst, PyObject *value)
{}

static PyObject *
PyCField_get(CFieldObject *self, PyObject *inst, PyTypeObject *type)
{}

static PyObject *
PyCField_get_offset(PyObject *self, void *data)
{}

static PyObject *
PyCField_get_size(PyObject *self, void *data)
{}

static PyGetSetDef PyCField_getset[] =;

static int
PyCField_traverse(CFieldObject *self, visitproc visit, void *arg)
{}

static int
PyCField_clear(CFieldObject *self)
{}

static void
PyCField_dealloc(PyObject *self)
{}

static PyObject *
PyCField_repr(CFieldObject *self)
{}

static PyType_Slot cfield_slots[] =;

PyType_Spec cfield_spec =;


/******************************************************************/
/*
  Accessor functions
*/

/* Derived from Modules/structmodule.c:
   Helper routine to get a Python integer and raise the appropriate error
   if it isn't one */

static int
get_long(PyObject *v, long *p)
{}

/* Same, but handling unsigned long */

static int
get_ulong(PyObject *v, unsigned long *p)
{}

/* Same, but handling native long long. */

static int
get_longlong(PyObject *v, long long *p)
{}

/* Same, but handling native unsigned long long. */

static int
get_ulonglong(PyObject *v, unsigned long long *p)
{}

/*****************************************************************
 * Integer fields, with bitfield support
 */

/* how to decode the size field, for integer get/set functions */
static inline
Py_ssize_t LOW_BIT(Py_ssize_t offset) {}
static inline
Py_ssize_t NUM_BITS(Py_ssize_t bitsize) {}

static inline
Py_ssize_t BUILD_SIZE(Py_ssize_t bitsize, Py_ssize_t offset) {}

/* Doesn't work if NUM_BITS(size) == 0, but it never happens in SET() call. */
#define BIT_MASK(type, size)

/* This macro CHANGES the first parameter IN PLACE. For proper sign handling,
   we must first shift left, then right.
*/
#define GET_BITFIELD(v, size)

/* This macro RETURNS the first parameter with the bit field CHANGED. */
#define SET(type, x, v, size)

#if SIZEOF_SHORT == 2
#define SWAP_SHORT
#else
#  error "unsupported short size"
#endif

#if SIZEOF_INT == 4
#define SWAP_INT
#else
#  error "unsupported int size"
#endif

#if SIZEOF_LONG == 4
#define SWAP_LONG
#elif SIZEOF_LONG == 8
#define SWAP_LONG
#else
#  error "unsupported long size"
#endif

#if SIZEOF_LONG_LONG == 8
#define SWAP_LONG_LONG
#else
#  error "unsupported long long size"
#endif

/*****************************************************************
 * The setter methods return an object which must be kept alive, to keep the
 * data valid which has been stored in the memory block.  The ctypes object
 * instance inserts this object into its 'b_objects' list.
 *
 * For simple Python types like integers or characters, there is nothing that
 * has to been kept alive, so Py_None is returned in these cases.  But this
 * makes inspecting the 'b_objects' list, which is accessible from Python for
 * debugging, less useful.
 *
 * So, defining the _CTYPES_DEBUG_KEEP symbol returns the original value
 * instead of Py_None.
 */

#ifdef _CTYPES_DEBUG_KEEP
#define _RET
#else
#define _RET(X)
#endif

/*****************************************************************
 * integer accessor methods, supporting bit fields
 */

static PyObject *
b_set(void *ptr, PyObject *value, Py_ssize_t size)
{}


static PyObject *
b_get(void *ptr, Py_ssize_t size)
{}

static PyObject *
B_set(void *ptr, PyObject *value, Py_ssize_t size)
{}


static PyObject *
B_get(void *ptr, Py_ssize_t size)
{}

static PyObject *
h_set(void *ptr, PyObject *value, Py_ssize_t size)
{}


static PyObject *
h_set_sw(void *ptr, PyObject *value, Py_ssize_t size)
{}

static PyObject *
h_get(void *ptr, Py_ssize_t size)
{}

static PyObject *
h_get_sw(void *ptr, Py_ssize_t size)
{}

static PyObject *
H_set(void *ptr, PyObject *value, Py_ssize_t size)
{}

static PyObject *
H_set_sw(void *ptr, PyObject *value, Py_ssize_t size)
{}


static PyObject *
H_get(void *ptr, Py_ssize_t size)
{}

static PyObject *
H_get_sw(void *ptr, Py_ssize_t size)
{}

static PyObject *
i_set(void *ptr, PyObject *value, Py_ssize_t size)
{}

static PyObject *
i_set_sw(void *ptr, PyObject *value, Py_ssize_t size)
{}


static PyObject *
i_get(void *ptr, Py_ssize_t size)
{}

static PyObject *
i_get_sw(void *ptr, Py_ssize_t size)
{}

#ifndef MS_WIN32
/* http://msdn.microsoft.com/en-us/library/cc237864.aspx */
#define VARIANT_FALSE
#define VARIANT_TRUE
#endif
/* short BOOL - VARIANT_BOOL */
static PyObject *
vBOOL_set(void *ptr, PyObject *value, Py_ssize_t size)
{}

static PyObject *
vBOOL_get(void *ptr, Py_ssize_t size)
{}

static PyObject *
bool_set(void *ptr, PyObject *value, Py_ssize_t size)
{}

static PyObject *
bool_get(void *ptr, Py_ssize_t size)
{}

static PyObject *
I_set(void *ptr, PyObject *value, Py_ssize_t size)
{}

static PyObject *
I_set_sw(void *ptr, PyObject *value, Py_ssize_t size)
{}


static PyObject *
I_get(void *ptr, Py_ssize_t size)
{}

static PyObject *
I_get_sw(void *ptr, Py_ssize_t size)
{}

static PyObject *
l_set(void *ptr, PyObject *value, Py_ssize_t size)
{}

static PyObject *
l_set_sw(void *ptr, PyObject *value, Py_ssize_t size)
{}


static PyObject *
l_get(void *ptr, Py_ssize_t size)
{}

static PyObject *
l_get_sw(void *ptr, Py_ssize_t size)
{}

static PyObject *
L_set(void *ptr, PyObject *value, Py_ssize_t size)
{}

static PyObject *
L_set_sw(void *ptr, PyObject *value, Py_ssize_t size)
{}


static PyObject *
L_get(void *ptr, Py_ssize_t size)
{}

static PyObject *
L_get_sw(void *ptr, Py_ssize_t size)
{}

static PyObject *
q_set(void *ptr, PyObject *value, Py_ssize_t size)
{}

static PyObject *
q_set_sw(void *ptr, PyObject *value, Py_ssize_t size)
{}

static PyObject *
q_get(void *ptr, Py_ssize_t size)
{}

static PyObject *
q_get_sw(void *ptr, Py_ssize_t size)
{}

static PyObject *
Q_set(void *ptr, PyObject *value, Py_ssize_t size)
{}

static PyObject *
Q_set_sw(void *ptr, PyObject *value, Py_ssize_t size)
{}

static PyObject *
Q_get(void *ptr, Py_ssize_t size)
{}

static PyObject *
Q_get_sw(void *ptr, Py_ssize_t size)
{}

/*****************************************************************
 * non-integer accessor methods, not supporting bit fields
 */


static PyObject *
g_set(void *ptr, PyObject *value, Py_ssize_t size)
{}

static PyObject *
g_get(void *ptr, Py_ssize_t size)
{}

static PyObject *
d_set(void *ptr, PyObject *value, Py_ssize_t size)
{}

static PyObject *
d_get(void *ptr, Py_ssize_t size)
{}

#if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TARGET_HAS_COMPLEX_TYPE)
static PyObject *
C_set(void *ptr, PyObject *value, Py_ssize_t size)
{}

static PyObject *
C_get(void *ptr, Py_ssize_t size)
{}

static PyObject *
E_set(void *ptr, PyObject *value, Py_ssize_t size)
{}

static PyObject *
E_get(void *ptr, Py_ssize_t size)
{}

static PyObject *
F_set(void *ptr, PyObject *value, Py_ssize_t size)
{}

static PyObject *
F_get(void *ptr, Py_ssize_t size)
{}
#endif

static PyObject *
d_set_sw(void *ptr, PyObject *value, Py_ssize_t size)
{}

static PyObject *
d_get_sw(void *ptr, Py_ssize_t size)
{}

static PyObject *
f_set(void *ptr, PyObject *value, Py_ssize_t size)
{}

static PyObject *
f_get(void *ptr, Py_ssize_t size)
{}

static PyObject *
f_set_sw(void *ptr, PyObject *value, Py_ssize_t size)
{}

static PyObject *
f_get_sw(void *ptr, Py_ssize_t size)
{}

/*
  py_object refcounts:

  1. If we have a py_object instance, O_get must Py_INCREF the returned
  object, of course.  If O_get is called from a function result, no py_object
  instance is created - so callproc.c::GetResult has to call Py_DECREF.

  2. The memory block in py_object owns a refcount.  So, py_object must call
  Py_DECREF on destruction.  Maybe only when b_needsfree is non-zero.
*/
static PyObject *
O_get(void *ptr, Py_ssize_t size)
{}

static PyObject *
O_set(void *ptr, PyObject *value, Py_ssize_t size)
{}


static PyObject *
c_set(void *ptr, PyObject *value, Py_ssize_t size)
{}


static PyObject *
c_get(void *ptr, Py_ssize_t size)
{}

/* u - a single wchar_t character */
static PyObject *
u_set(void *ptr, PyObject *value, Py_ssize_t size)
{}


static PyObject *
u_get(void *ptr, Py_ssize_t size)
{}

/* U - a unicode string */
static PyObject *
U_get(void *ptr, Py_ssize_t size)
{}

static PyObject *
U_set(void *ptr, PyObject *value, Py_ssize_t length)
{}


static PyObject *
s_get(void *ptr, Py_ssize_t size)
{}

static PyObject *
s_set(void *ptr, PyObject *value, Py_ssize_t length)
{}

static PyObject *
z_set(void *ptr, PyObject *value, Py_ssize_t size)
{}

static PyObject *
z_get(void *ptr, Py_ssize_t size)
{}

static PyObject *
Z_set(void *ptr, PyObject *value, Py_ssize_t size)
{}

static PyObject *
Z_get(void *ptr, Py_ssize_t size)
{}


#ifdef MS_WIN32
static PyObject *
BSTR_set(void *ptr, PyObject *value, Py_ssize_t size)
{
    BSTR bstr;

    /* convert value into a PyUnicodeObject or NULL */
    if (Py_None == value) {
        value = NULL;
    } else if (!PyUnicode_Check(value)) {
        PyErr_Format(PyExc_TypeError,
                        "unicode string expected instead of %s instance",
                        Py_TYPE(value)->tp_name);
        return NULL;
    }

    /* create a BSTR from value */
    if (value) {
        Py_ssize_t wsize;
        wchar_t *wvalue = PyUnicode_AsWideCharString(value, &wsize);
        if (wvalue == NULL) {
            return NULL;
        }
        if ((unsigned) wsize != wsize) {
            PyErr_SetString(PyExc_ValueError, "String too long for BSTR");
            PyMem_Free(wvalue);
            return NULL;
        }
        bstr = SysAllocStringLen(wvalue, (unsigned)wsize);
        PyMem_Free(wvalue);
    } else
        bstr = NULL;

    /* free the previous contents, if any */
    if (*(BSTR *)ptr)
        SysFreeString(*(BSTR *)ptr);

    /* and store it */
    *(BSTR *)ptr = bstr;

    /* We don't need to keep any other object */
    _RET(value);
}


static PyObject *
BSTR_get(void *ptr, Py_ssize_t size)
{
    BSTR p;
    p = *(BSTR *)ptr;
    if (p)
        return PyUnicode_FromWideChar(p, SysStringLen(p));
    else {
        /* Hm, it seems NULL pointer and zero length string are the
           same in BSTR, see Don Box, p 81
        */
        Py_RETURN_NONE;
    }
}
#endif

static PyObject *
P_set(void *ptr, PyObject *value, Py_ssize_t size)
{}

static PyObject *
P_get(void *ptr, Py_ssize_t size)
{}

static struct fielddesc formattable[] =;

/*
  Ideas: Implement VARIANT in this table, using 'V' code.
  Use '?' as code for BOOL.
*/

/* Delayed initialization. Windows cannot statically reference dynamically
   loaded addresses from DLLs. */
void
_ctypes_init_fielddesc(void)
{}

struct fielddesc *
_ctypes_get_fielddesc(const char *fmt)
{}

/*---------------- EOF ----------------*/