#ifndef FFI_PLATYPUS_H
#define FFI_PLATYPUS_H
#include <ffi.h>
#include "ffi_platypus_config.h"
#ifdef HAVE_DLFCN_H
#ifndef PERL_OS_WINDOWS
#include <dlfcn.h>
#endif
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_STDDEF_H
#include <stddef.h>
#endif
#ifdef HAVE_STDINT_H
#include <stdint.h>
#endif
#ifdef HAVE_INTTYPES_H
#include <inttypes.h>
#endif
#ifdef HAVE_ALLOCA_H
#include <alloca.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#ifdef HAVE_COMPLEX_H
#include <complex.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif
#ifdef PERL_OS_WINDOWS
void *windlopen(const char *, int);
const char *windlerror(void);
void *windlsym(void *, const char *);
int windlclose(void *);
#define dlopen(filename, flag) windlopen(filename, flag)
#define dlerror() windlerror()
#define dlsym(handle, symbol) windlsym(handle, symbol)
#define dlclose(handle) windlclose(handle)
#endif
typedef enum _ffi_pl_type_code {
/*
* the first three bits represent the
* native unit size for each type.
*/
FFI_PL_SIZE_0 = 0x0000,
FFI_PL_SIZE_8 = 0x0001,
FFI_PL_SIZE_16 = 0x0002,
FFI_PL_SIZE_32 = 0x0003,
FFI_PL_SIZE_64 = 0x0004,
FFI_PL_SIZE_128 = 0x0005,
FFI_PL_SIZE_256 = 0x0006,
FFI_PL_SIZE_512 = 0x0007,
#if SIZEOF_VOIDP == 4
FFI_PL_SIZE_PTR = FFI_PL_SIZE_32,
#elif SIZEOF_VOIDP == 8
FFI_PL_SIZE_PTR = FFI_PL_SIZE_64,
#else
#error "strange pointer size"
#endif
FFI_PL_SIZE_MASK = 0x0007,
/*
* The next nine bits represent the type:
* basics: void, integer, float, complex
*
* opaque is a pointer to something, a void*
*
* string is a pointer to a null terminated string
* (a c string, basically)
*
* closure is a pointer to a function, usually a
* Perl function, enclosed within a FFI::Platypus::Closure
*
* record is a fixed bitmap, could be either a struct,
* or a fixed length string.
*/
FFI_PL_BASE_VOID = 0x0008,
FFI_PL_BASE_SINT = 0x0010,
FFI_PL_BASE_UINT = 0x0020,
FFI_PL_BASE_FLOAT = 0x0040,
FFI_PL_BASE_COMPLEX = 0x0080,
FFI_PL_BASE_OPAQUE = 0x0100,
FFI_PL_BASE_STRING = 0x0200,
FFI_PL_BASE_CLOSURE = 0x0400,
FFI_PL_BASE_RECORD = 0x0800,
FFI_PL_BASE_MASK = 0x0ff8,
/*
* The shape describes how the data is organized.
* sclar is a simple value, pointer is usually used
* for pass by reference, array is a list of objects
* and custom types allow users to create their own
* custom types.
*/
FFI_PL_SHAPE_SCALAR = 0x0000,
FFI_PL_SHAPE_POINTER = 0x1000,
FFI_PL_SHAPE_ARRAY = 0x2000,
FFI_PL_SHAPE_CUSTOM_PERL = 0x3000,
FFI_PL_SHAPE_OBJECT = 0x4000,
FFI_PL_SHAPE_MASK = 0xf000,
/*
* You can or together the different bit fields above to
* describe a type. An int for example (usually signed 32 bit integer)
* is `FFI_PL_SIZE_32 | FFI_PL_BASE_SINT`. Not all combinations
* have meaning, for example `FFI_PL_SIZE_8 | FFI_PL_BASE_FLOAT`
* is gibberish
*/
FFI_PL_TYPE_VOID = FFI_PL_SIZE_0 | FFI_PL_BASE_VOID,
FFI_PL_TYPE_SINT8 = FFI_PL_SIZE_8 | FFI_PL_BASE_SINT,
FFI_PL_TYPE_SINT16 = FFI_PL_SIZE_16 | FFI_PL_BASE_SINT,
FFI_PL_TYPE_SINT32 = FFI_PL_SIZE_32 | FFI_PL_BASE_SINT,
FFI_PL_TYPE_SINT64 = FFI_PL_SIZE_64 | FFI_PL_BASE_SINT,
FFI_PL_TYPE_UINT8 = FFI_PL_SIZE_8 | FFI_PL_BASE_UINT,
FFI_PL_TYPE_UINT16 = FFI_PL_SIZE_16 | FFI_PL_BASE_UINT,
FFI_PL_TYPE_UINT32 = FFI_PL_SIZE_32 | FFI_PL_BASE_UINT,
FFI_PL_TYPE_UINT64 = FFI_PL_SIZE_64 | FFI_PL_BASE_UINT,
FFI_PL_TYPE_FLOAT = FFI_PL_SIZE_32 | FFI_PL_BASE_FLOAT,
FFI_PL_TYPE_DOUBLE = FFI_PL_SIZE_64 | FFI_PL_BASE_FLOAT,
FFI_PL_TYPE_LONG_DOUBLE = FFI_PL_SIZE_128 | FFI_PL_BASE_FLOAT,
FFI_PL_TYPE_COMPLEX_FLOAT = FFI_PL_SIZE_64 | FFI_PL_BASE_COMPLEX,
FFI_PL_TYPE_COMPLEX_DOUBLE = FFI_PL_SIZE_128 | FFI_PL_BASE_COMPLEX,
FFI_PL_TYPE_OPAQUE = FFI_PL_SIZE_PTR | FFI_PL_BASE_OPAQUE,
/*
* These types are passed as pointers, and act like opaque types
* in terms of sizeof, alignof, etc, but get passed differently.
*/
FFI_PL_TYPE_STRING = FFI_PL_TYPE_OPAQUE | FFI_PL_BASE_STRING,
FFI_PL_TYPE_CLOSURE = FFI_PL_TYPE_OPAQUE | FFI_PL_BASE_CLOSURE,
FFI_PL_TYPE_RECORD = FFI_PL_TYPE_OPAQUE | FFI_PL_BASE_RECORD,
FFI_PL_TYPE_RECORD_VALUE = FFI_PL_BASE_RECORD,
} ffi_pl_type_code;
typedef enum _platypus_string_type {
FFI_PL_TYPE_STRING_RO = 0,
FFI_PL_TYPE_STRING_RW = 1
} platypus_string_type;
typedef struct _ffi_pl_type_extra_object {
char *class; /* base class */
} ffi_pl_type_extra_object;
typedef struct _ffi_pl_record_meta_t {
ffi_type ffi_type;
int can_return_from_closure;
ffi_type *elements[0];
} ffi_pl_record_meta_t;
typedef struct _ffi_pl_type_extra_record {
size_t size;
char *class; /* base class */
ffi_pl_record_meta_t *meta;
} ffi_pl_type_extra_record;
typedef struct _ffi_pl_type_extra_custom_perl {
union {
ffi_pl_type_extra_record record;
} ox;
void *perl_to_native;
void *native_to_perl;
void *perl_to_native_post;
int argument_count;
} ffi_pl_type_extra_custom_perl;
typedef struct _ffi_pl_type_extra_array {
int element_count;
} ffi_pl_type_extra_array;
struct _ffi_pl_type;
typedef struct _ffi_pl_type_extra_closure {
ffi_cif ffi_cif;
int flags;
struct _ffi_pl_type *return_type;
struct _ffi_pl_type *argument_types[0];
} ffi_pl_type_extra_closure;
typedef union _ffi_pl_type_extra {
ffi_pl_type_extra_custom_perl custom_perl;
ffi_pl_type_extra_array array;
ffi_pl_type_extra_closure closure;
ffi_pl_type_extra_record record;
ffi_pl_type_extra_object object;
} ffi_pl_type_extra;
typedef struct _ffi_pl_type {
unsigned short type_code;
unsigned short sub_type;
ffi_pl_type_extra extra[0];
} ffi_pl_type;
typedef struct _ffi_pl_function {
void *address;
void *platypus_sv; /* really a Perl SV* */
int platypus_api;
ffi_cif ffi_cif;
ffi_pl_type *return_type;
ffi_pl_type *argument_types[0];
} ffi_pl_function;
typedef struct _ffi_pl_closure {
ffi_closure *ffi_closure;
void *function_pointer; /* C function pointer */
void *coderef; /* Perl HV* pointing to FFI::Platypus::Closure object */
ffi_pl_type *type;
} ffi_pl_closure;
typedef const char *ffi_pl_string;
typedef union _ffi_pl_result {
void *pointer;
const char *string;
int8_t sint8;
uint8_t uint8;
#if defined FFI_PL_PROBE_BIGENDIAN
int8_t sint8_array[4];
uint8_t uint8_array[4];
#elif defined FFI_PL_PROBE_BIGENDIAN64
int8_t sint8_array[8];
uint8_t uint8_array[8];
#endif
int16_t sint16;
uint16_t uint16;
#if defined FFI_PL_PROBE_BIGENDIAN
int16_t sint16_array[2];
uint16_t uint16_array[2];
#elif defined FFI_PL_PROBE_BIGENDIAN64
int16_t sint16_array[4];
uint16_t uint16_array[4];
#endif
int32_t sint32;
uint32_t uint32;
#if defined FFI_PL_PROBE_BIGENDIAN64
uint32_t uint32_array[2];
int32_t sint32_array[2];
#endif
int64_t sint64;
uint64_t uint64;
float xfloat;
double xdouble;
#ifdef FFI_PL_PROBE_LONGDOUBLE
long double longdouble;
#endif
#ifdef FFI_TARGET_HAS_COMPLEX_TYPE
#ifdef SIZEOF_FLOAT_COMPLEX
float complex complex_float;
#endif
#ifdef SIZEOF_DOUBLE_COMPLEX
double complex complex_double;
#endif
#endif
} ffi_pl_result;
typedef union _ffi_pl_argument {
void *pointer;
const char *string;
int8_t sint8;
uint8_t uint8;
int16_t sint16;
uint16_t uint16;
int32_t sint32;
uint32_t uint32;
int64_t sint64;
uint64_t uint64;
float xfloat;
double xdouble;
} ffi_pl_argument;
typedef struct _ffi_pl_arguments {
int count;
int reserved;
ffi_pl_argument slot[0];
} ffi_pl_arguments;
typedef struct _ffi_pl_record_member {
int offset;
int count;
} ffi_pl_record_member;
#define ffi_pl_arguments_count(arguments) (arguments->count)
#define ffi_pl_arguments_set_pointer(arguments, i, value) (arguments->slot[i].pointer = value)
#define ffi_pl_arguments_get_pointer(arguments, i) (arguments->slot[i].pointer)
#define ffi_pl_arguments_set_string(arguments, i, value) (arguments->slot[i].string = value)
#define ffi_pl_arguments_get_string(arguments, i) (arguments->slot[i].string)
#define ffi_pl_arguments_set_sint8(arguments, i, value) (arguments->slot[i].sint8 = value)
#define ffi_pl_arguments_get_sint8(arguments, i) (arguments->slot[i].sint8)
#define ffi_pl_arguments_set_uint8(arguments, i, value) (arguments->slot[i].uint8 = value)
#define ffi_pl_arguments_get_uint8(arguments, i) (arguments->slot[i].uint8)
#define ffi_pl_arguments_set_sint16(arguments, i, value) (arguments->slot[i].sint16 = value)
#define ffi_pl_arguments_get_sint16(arguments, i) (arguments->slot[i].sint16)
#define ffi_pl_arguments_set_uint16(arguments, i, value) (arguments->slot[i].uint16 = value)
#define ffi_pl_arguments_get_uint16(arguments, i) (arguments->slot[i].uint16)
#define ffi_pl_arguments_set_sint32(arguments, i, value) (arguments->slot[i].sint32 = value)
#define ffi_pl_arguments_get_sint32(arguments, i) (arguments->slot[i].sint32)
#define ffi_pl_arguments_set_uint32(arguments, i, value) (arguments->slot[i].uint32 = value)
#define ffi_pl_arguments_get_uint32(arguments, i) (arguments->slot[i].uint32)
#define ffi_pl_arguments_set_sint64(arguments, i, value) (arguments->slot[i].sint64 = value)
#define ffi_pl_arguments_get_sint64(arguments, i) (arguments->slot[i].sint64)
#define ffi_pl_arguments_set_uint64(arguments, i, value) (arguments->slot[i].uint64 = value)
#define ffi_pl_arguments_get_uint64(arguments, i) (arguments->slot[i].uint64)
#define ffi_pl_arguments_set_float(arguments, i, value) (arguments->slot[i].xfloat = value)
#define ffi_pl_arguments_get_float(arguments, i) (arguments->slot[i].xfloat)
#define ffi_pl_arguments_set_double(arguments, i, value) (arguments->slot[i].xdouble = value)
#define ffi_pl_arguments_get_double(arguments, i) (arguments->slot[i].xdouble)
#define ffi_pl_arguments_pointers(arguments) ((void**)&arguments->slot[arguments->count])
typedef struct _ffi_pl_heap {
void *_this;
void *_next;
} ffi_pl_heap;
#define ffi_pl_heap_add(ptr, count, type) { \
ffi_pl_heap *n; \
Newx(ptr, count, type); \
Newx(n, 1, ffi_pl_heap); \
n->_this = ptr; \
n->_next = (void*) heap; \
heap = n; \
}
#define ffi_pl_heap_add_ptr(ptr) { \
ffi_pl_heap *n; \
Newx(n, 1, ffi_pl_heap); \
n->_this = ptr; \
n->_next = (void*) heap; \
heap = n; \
}
#define ffi_pl_heap_free() { \
while(heap != NULL) \
{ \
ffi_pl_heap *old = heap; \
heap = (ffi_pl_heap *) old->_next; \
Safefree(old->_this); \
Safefree(old); \
} \
}
#define ffi_pl_croak \
ffi_pl_heap_free(); \
croak
#if defined(_MSC_VER)
#define Newx_or_alloca(ptr, count, type) ptr = _alloca(sizeof(type)*count)
#elif defined(FFI_PL_PROBE_ALLOCA)
#define Newx_or_alloca(ptr, count, type) ptr = alloca(sizeof(type)*count)
#else
#define Newx_or_alloca(ptr, count, type) ffi_pl_heap_add(ptr, count, type)
#endif
ffi_type *ffi_pl_type_to_libffi_type(ffi_pl_type *type);
ffi_pl_type *ffi_pl_type_new(size_t size);
#if SIZEOF_VOIDP == 4
uint64_t cast0(void);
#else
void *cast0(void);
#endif
#if SIZEOF_VOIDP == 4
uint64_t cast1(uint64_t value);
#else
void *cast1(void *value);
#endif
#ifdef __cplusplus
}
#endif
#endif