ffi 0.3.1 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.rdoc +51 -1
- data/Rakefile +38 -28
- data/ext/ffi_c/AbstractMemory.c +74 -70
- data/ext/ffi_c/AbstractMemory.h +8 -4
- data/ext/ffi_c/AutoPointer.c +8 -9
- data/ext/ffi_c/AutoPointer.h +2 -2
- data/ext/ffi_c/Buffer.c +42 -24
- data/ext/ffi_c/Callback.c +85 -33
- data/ext/ffi_c/Callback.h +11 -5
- data/ext/ffi_c/{NativeLibrary.c → DynamicLibrary.c} +83 -16
- data/ext/ffi_c/{NativeLibrary.h → DynamicLibrary.h} +1 -1
- data/ext/ffi_c/Invoker.c +152 -192
- data/ext/ffi_c/LastError.c +135 -0
- data/ext/ffi_c/LastError.h +18 -0
- data/ext/ffi_c/MemoryPointer.c +27 -20
- data/ext/ffi_c/MemoryPointer.h +3 -3
- data/ext/ffi_c/NullPointer.c +51 -47
- data/ext/ffi_c/Platform.c +9 -10
- data/ext/ffi_c/Platform.h +1 -1
- data/ext/ffi_c/Pointer.c +52 -21
- data/ext/ffi_c/Pointer.h +8 -6
- data/ext/ffi_c/Struct.c +70 -61
- data/ext/ffi_c/Struct.h +2 -2
- data/ext/ffi_c/Type.c +230 -0
- data/ext/ffi_c/Type.h +28 -0
- data/ext/ffi_c/Types.c +48 -6
- data/ext/ffi_c/Types.h +8 -2
- data/ext/ffi_c/endian.h +40 -0
- data/ext/ffi_c/extconf.rb +6 -5
- data/ext/ffi_c/ffi.c +21 -44
- data/ext/ffi_c/libffi.bsd.mk +34 -0
- data/ext/ffi_c/libffi.darwin.mk +30 -10
- data/ext/ffi_c/libffi.gnu.mk +29 -0
- data/ext/ffi_c/libffi.mk +4 -2
- data/ext/ffi_c/rbffi.h +6 -8
- data/gen/Rakefile +12 -0
- data/lib/ffi/autopointer.rb +1 -1
- data/lib/ffi/enum.rb +78 -0
- data/lib/ffi/ffi.rb +5 -6
- data/lib/ffi/io.rb +15 -1
- data/lib/ffi/library.rb +79 -18
- data/lib/ffi/pointer.rb +2 -2
- data/lib/ffi/struct.rb +68 -14
- data/lib/ffi/types.rb +6 -3
- data/lib/ffi/variadic.rb +2 -2
- data/lib/ffi.rb +10 -1
- data/spec/ffi/bool_spec.rb +24 -0
- data/spec/ffi/callback_spec.rb +217 -17
- data/spec/ffi/enum_spec.rb +164 -0
- data/spec/ffi/managed_struct_spec.rb +6 -1
- data/spec/ffi/number_spec.rb +30 -0
- data/spec/ffi/pointer_spec.rb +33 -8
- data/spec/ffi/rbx/memory_pointer_spec.rb +0 -6
- data/spec/ffi/spec_helper.rb +5 -1
- data/spec/ffi/string_spec.rb +65 -4
- data/spec/ffi/struct_callback_spec.rb +41 -0
- data/spec/ffi/struct_initialize_spec.rb +30 -0
- data/spec/ffi/struct_spec.rb +44 -21
- metadata +31 -69
- data/ext/ffi_c/ffi.mk +0 -23
- data/nbproject/Makefile-Default.mk +0 -57
- data/nbproject/Makefile-impl.mk +0 -123
- data/nbproject/Package-Default.bash +0 -72
- data/nbproject/configurations.xml +0 -293
- data/nbproject/private/configurations.xml +0 -22
- data/nbproject/private/private.xml +0 -7
- data/nbproject/project.properties +0 -0
- data/nbproject/project.xml +0 -15
- data/samples/getlogin.rb +0 -7
- data/samples/getpid.rb +0 -7
- data/samples/gettimeofday.rb +0 -17
- data/samples/hello.rb +0 -6
- data/samples/inotify.rb +0 -59
- data/samples/pty.rb +0 -75
- data/samples/qsort.rb +0 -20
- data/samples/sample_helper.rb +0 -6
data/ext/ffi_c/extconf.rb
CHANGED
|
@@ -16,15 +16,16 @@ $defs << "-DHAVE_EXTCONF_H" if $defs.empty? # needed so create_header works
|
|
|
16
16
|
create_makefile("ffi_c")
|
|
17
17
|
create_header("extconf.h")
|
|
18
18
|
File.open("Makefile", "a") do |mf|
|
|
19
|
-
mf.puts "CPPFLAGS += -Werror -Wunused -Wformat"
|
|
19
|
+
mf.puts "CPPFLAGS += -Werror -Wunused -Wformat -Wimplicit -Wreturn-type"
|
|
20
20
|
unless libffi_ok
|
|
21
|
-
mf.puts "include $(srcdir)/ffi.mk"
|
|
22
21
|
mf.puts "LIBFFI_HOST=--host=#{Config::CONFIG['host_alias']}" if Config::CONFIG.has_key?("host_alias")
|
|
23
22
|
mf.puts "FFI_MMAP_EXEC=-DFFI_MMAP_EXEC_WRIT=#{Config::CONFIG['host_os'] =~ /win/ ? 0 : 1}"
|
|
24
|
-
if Config::CONFIG['host_os'] =~ /darwin/
|
|
25
|
-
mf.puts "include $
|
|
23
|
+
if Config::CONFIG['host_os'].downcase =~ /darwin/
|
|
24
|
+
mf.puts "include ${srcdir}/libffi.darwin.mk"
|
|
25
|
+
elsif Config::CONFIG['host_os'].downcase =~ /bsd/
|
|
26
|
+
mf.puts '.include "${srcdir}/libffi.bsd.mk"'
|
|
26
27
|
else
|
|
27
|
-
mf.puts "include $
|
|
28
|
+
mf.puts "include ${srcdir}/libffi.mk"
|
|
28
29
|
end
|
|
29
30
|
end
|
|
30
31
|
end
|
data/ext/ffi_c/ffi.c
CHANGED
|
@@ -10,20 +10,21 @@
|
|
|
10
10
|
#include "MemoryPointer.h"
|
|
11
11
|
#include "AutoPointer.h"
|
|
12
12
|
#include "Struct.h"
|
|
13
|
-
#include "
|
|
13
|
+
#include "Callback.h"
|
|
14
|
+
#include "DynamicLibrary.h"
|
|
14
15
|
#include "Platform.h"
|
|
15
16
|
#include "Types.h"
|
|
17
|
+
#include "LastError.h"
|
|
16
18
|
|
|
17
19
|
|
|
18
20
|
void Init_ffi_c();
|
|
19
21
|
|
|
20
22
|
static VALUE moduleFFI = Qnil;
|
|
21
|
-
static VALUE moduleNativeType = Qnil;
|
|
22
23
|
static VALUE typeMap = Qnil, sizeMap = Qnil;
|
|
23
24
|
static ID type_size_id = 0, size_id;
|
|
24
25
|
|
|
25
26
|
int
|
|
26
|
-
|
|
27
|
+
rbffi_type_size(VALUE type)
|
|
27
28
|
{
|
|
28
29
|
int t = TYPE(type);
|
|
29
30
|
if (t == T_FIXNUM || t == T_BIGNUM) {
|
|
@@ -40,9 +41,9 @@ rb_FFI_type_size(VALUE type)
|
|
|
40
41
|
}
|
|
41
42
|
}
|
|
42
43
|
// Not found - call up to the ruby version to resolve
|
|
43
|
-
return
|
|
44
|
+
return NUM2INT(rb_funcall2(moduleFFI, type_size_id, 1, &type));
|
|
44
45
|
} else {
|
|
45
|
-
return
|
|
46
|
+
return NUM2INT(rb_funcall2(type, size_id, 0, NULL));
|
|
46
47
|
}
|
|
47
48
|
}
|
|
48
49
|
|
|
@@ -50,50 +51,26 @@ void
|
|
|
50
51
|
Init_ffi_c() {
|
|
51
52
|
moduleFFI = rb_define_module("FFI");
|
|
52
53
|
rb_global_variable(&moduleFFI);
|
|
53
|
-
moduleNativeType = rb_define_module_under(moduleFFI, "NativeType");
|
|
54
54
|
rb_define_const(moduleFFI, "TypeDefs", typeMap = rb_hash_new());
|
|
55
55
|
rb_define_const(moduleFFI, "SizeTypes", sizeMap = rb_hash_new());
|
|
56
56
|
rb_global_variable(&typeMap);
|
|
57
57
|
rb_global_variable(&sizeMap);
|
|
58
58
|
type_size_id = rb_intern("type_size");
|
|
59
59
|
size_id = rb_intern("size");
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
rb_define_const(moduleNativeType, "CHAR_ARRAY", INT2FIX(NATIVE_CHAR_ARRAY));
|
|
76
|
-
rb_define_const(moduleNativeType, "BUFFER_IN", INT2FIX(NATIVE_BUFFER_IN));
|
|
77
|
-
rb_define_const(moduleNativeType, "BUFFER_OUT", INT2FIX(NATIVE_BUFFER_OUT));
|
|
78
|
-
rb_define_const(moduleNativeType, "BUFFER_INOUT", INT2FIX(NATIVE_BUFFER_INOUT));
|
|
79
|
-
rb_define_const(moduleNativeType, "VARARGS", INT2FIX(NATIVE_VARARGS));
|
|
80
|
-
if (sizeof(long) == 4) {
|
|
81
|
-
rb_define_const(moduleNativeType, "LONG", INT2FIX(NATIVE_INT32));
|
|
82
|
-
rb_define_const(moduleNativeType, "ULONG", INT2FIX(NATIVE_UINT32));
|
|
83
|
-
} else {
|
|
84
|
-
rb_define_const(moduleNativeType, "LONG", INT2FIX(NATIVE_INT64));
|
|
85
|
-
rb_define_const(moduleNativeType, "ULONG", INT2FIX(NATIVE_UINT64));
|
|
86
|
-
}
|
|
87
|
-
rb_FFI_Platform_Init();
|
|
88
|
-
rb_FFI_AbstractMemory_Init();
|
|
89
|
-
rb_FFI_Pointer_Init();
|
|
90
|
-
rb_FFI_AutoPointer_Init();
|
|
91
|
-
rb_FFI_NullPointer_Init();
|
|
92
|
-
rb_FFI_MemoryPointer_Init();
|
|
93
|
-
rb_FFI_Buffer_Init();
|
|
94
|
-
rb_FFI_Callback_Init();
|
|
95
|
-
rb_FFI_Struct_Init(0);
|
|
96
|
-
rb_FFI_NativeLibrary_Init();
|
|
97
|
-
rb_FFI_Invoker_Init();
|
|
60
|
+
|
|
61
|
+
rbffi_Type_Init(moduleFFI);
|
|
62
|
+
rbffi_LastError_Init(moduleFFI);
|
|
63
|
+
rbffi_Platform_Init(moduleFFI);
|
|
64
|
+
rbffi_AbstractMemory_Init(moduleFFI);
|
|
65
|
+
rbffi_Pointer_Init(moduleFFI);
|
|
66
|
+
rbffi_AutoPointer_Init(moduleFFI);
|
|
67
|
+
rbffi_NullPointer_Init(moduleFFI);
|
|
68
|
+
rbffi_MemoryPointer_Init(moduleFFI);
|
|
69
|
+
rbffi_Buffer_Init(moduleFFI);
|
|
70
|
+
rbffi_Callback_Init(moduleFFI);
|
|
71
|
+
rbffi_Struct_Init(moduleFFI);
|
|
72
|
+
rbffi_DynamicLibrary_Init(moduleFFI);
|
|
73
|
+
rbffi_Invoker_Init(moduleFFI);
|
|
74
|
+
rbffi_Types_Init(moduleFFI);
|
|
98
75
|
}
|
|
99
76
|
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# -*- makefile -*-
|
|
2
|
+
#
|
|
3
|
+
# Makefile for BSD systems
|
|
4
|
+
#
|
|
5
|
+
|
|
6
|
+
INCFLAGS += -I${LIBFFI_BUILD_DIR}/include
|
|
7
|
+
LOCAL_LIBS += ${LIBFFI} -lpthread
|
|
8
|
+
|
|
9
|
+
LIBFFI_CFLAGS = ${FFI_MMAP_EXEC} -pthread
|
|
10
|
+
LIBFFI_BUILD_DIR = ${.CURDIR}/libffi
|
|
11
|
+
|
|
12
|
+
.if "${srcdir}" == "."
|
|
13
|
+
LIBFFI_SRC_DIR := ${.CURDIR}/libffi
|
|
14
|
+
.else
|
|
15
|
+
LIBFFI_SRC_DIR := ${srcdir}/libffi
|
|
16
|
+
.endif
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
LIBFFI = ${LIBFFI_BUILD_DIR}/.libs/libffi_convenience.a
|
|
20
|
+
LIBFFI_CONFIGURE = ${LIBFFI_SRC_DIR}/configure --disable-static \
|
|
21
|
+
--with-pic=yes --disable-dependency-tracking
|
|
22
|
+
|
|
23
|
+
$(OBJS): ${LIBFFI}
|
|
24
|
+
|
|
25
|
+
$(LIBFFI):
|
|
26
|
+
@mkdir -p ${LIBFFI_BUILD_DIR}
|
|
27
|
+
@if [ ! -f ${LIBFFI_BUILD_DIR}/Makefile ]; then \
|
|
28
|
+
echo "Configuring libffi"; \
|
|
29
|
+
cd ${LIBFFI_BUILD_DIR} && \
|
|
30
|
+
/usr/bin/env CC="${CC}" LD="${LD}" CFLAGS="${LIBFFI_CFLAGS}" \
|
|
31
|
+
/bin/sh ${LIBFFI_CONFIGURE} ${LIBFFI_HOST} > /dev/null; \
|
|
32
|
+
fi
|
|
33
|
+
@cd ${LIBFFI_BUILD_DIR} && ${MAKE}
|
|
34
|
+
|
data/ext/ffi_c/libffi.darwin.mk
CHANGED
|
@@ -1,32 +1,52 @@
|
|
|
1
1
|
# -*- makefile -*-
|
|
2
|
-
|
|
2
|
+
|
|
3
|
+
include ${srcdir}/libffi.gnu.mk
|
|
4
|
+
|
|
3
5
|
CCACHE := $(shell type -p ccache)
|
|
6
|
+
BUILD_DIR := $(shell pwd)
|
|
7
|
+
|
|
8
|
+
INCFLAGS += -I${BUILD_DIR}
|
|
9
|
+
|
|
10
|
+
# Work out which arches we need to compile the lib for
|
|
11
|
+
ARCHES :=
|
|
4
12
|
ifneq ($(findstring -arch ppc,$(CFLAGS)),)
|
|
5
13
|
ARCHES += ppc
|
|
6
14
|
endif
|
|
15
|
+
|
|
7
16
|
ifneq ($(findstring -arch i386,$(CFLAGS)),)
|
|
8
17
|
ARCHES += i386
|
|
9
18
|
endif
|
|
19
|
+
|
|
10
20
|
ifneq ($(findstring -arch x86_64,$(CFLAGS)),)
|
|
11
21
|
ARCHES += x86_64
|
|
12
22
|
endif
|
|
13
|
-
ifeq ($(ARCHES),)
|
|
14
|
-
ARCHES = $(shell arch)
|
|
15
|
-
endif
|
|
16
23
|
|
|
24
|
+
ifeq ($(strip $(ARCHES)),)
|
|
25
|
+
# Just build the one (default) architecture
|
|
26
|
+
$(LIBFFI):
|
|
27
|
+
@mkdir -p $(LIBFFI_BUILD_DIR)
|
|
28
|
+
@if [ ! -f $(LIBFFI_BUILD_DIR)/Makefile ]; then \
|
|
29
|
+
echo "Configuring libffi"; \
|
|
30
|
+
cd $(LIBFFI_BUILD_DIR) && \
|
|
31
|
+
/usr/bin/env CC="$(CC)" LD="$(LD)" CFLAGS="$(LIBFFI_CFLAGS)" \
|
|
32
|
+
/bin/sh $(LIBFFI_CONFIGURE) $(LIBFFI_HOST) > /dev/null; \
|
|
33
|
+
fi
|
|
34
|
+
cd $(LIBFFI_BUILD_DIR) && $(MAKE)
|
|
35
|
+
|
|
36
|
+
else
|
|
37
|
+
# Build a fat binary and assemble
|
|
17
38
|
build_ffi = \
|
|
18
39
|
mkdir -p $(BUILD_DIR)/libffi-$(1); \
|
|
19
40
|
(if [ ! -f $(BUILD_DIR)/libffi-$(1)/Makefile ]; then \
|
|
20
41
|
echo "Configuring libffi for $(1)"; \
|
|
21
42
|
cd $(BUILD_DIR)/libffi-$(1) && \
|
|
22
|
-
env CC="$(CCACHE) $(CC)" CFLAGS="-arch $(1) $(
|
|
23
|
-
$(
|
|
43
|
+
env CC="$(CCACHE) $(CC)" CFLAGS="-arch $(1) $(LIBFFI_CFLAGS)" LDFLAGS="-arch $(1)" \
|
|
44
|
+
$(LIBFFI_CONFIGURE) --host=$(1)-apple-darwin > /dev/null; \
|
|
24
45
|
fi); \
|
|
25
46
|
env MACOSX_DEPLOYMENT_TARGET=10.4 $(MAKE) -C $(BUILD_DIR)/libffi-$(1)
|
|
26
|
-
|
|
47
|
+
|
|
27
48
|
$(LIBFFI):
|
|
28
|
-
@for arch in $(ARCHES); do $(call build_ffi,$$arch);done
|
|
29
|
-
|
|
49
|
+
@for arch in $(ARCHES); do $(call build_ffi,$$arch);done
|
|
30
50
|
# Assemble into a FAT (i386, ppc) library
|
|
31
51
|
@mkdir -p $(BUILD_DIR)/libffi/.libs
|
|
32
52
|
env MACOSX_DEPLOYMENT_TARGET=10.4 /usr/bin/libtool -static -o $@ \
|
|
@@ -51,5 +71,5 @@ $(LIBFFI):
|
|
|
51
71
|
printf "#include \"libffi-ppc/include/ffitarget.h\"\n";\
|
|
52
72
|
printf "#endif\n";\
|
|
53
73
|
) > $(LIBFFI_BUILD_DIR)/include/ffitarget.h
|
|
54
|
-
|
|
55
74
|
|
|
75
|
+
endif
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# -*- makefile -*-
|
|
2
|
+
#
|
|
3
|
+
# Common definitions for all systems that use GNU make
|
|
4
|
+
#
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
# Tack the extra deps onto the autogenerated variables
|
|
8
|
+
INCFLAGS += -I$(LIBFFI_BUILD_DIR)/include
|
|
9
|
+
LOCAL_LIBS += $(LIBFFI)
|
|
10
|
+
BUILD_DIR = $(shell pwd)
|
|
11
|
+
LIBFFI_CFLAGS = $(FFI_MMAP_EXEC)
|
|
12
|
+
LIBFFI_BUILD_DIR = $(BUILD_DIR)/libffi
|
|
13
|
+
|
|
14
|
+
ifeq ($(srcdir),.)
|
|
15
|
+
LIBFFI_SRC_DIR := $(shell pwd)/libffi
|
|
16
|
+
else
|
|
17
|
+
LIBFFI_SRC_DIR := $(srcdir)/libffi
|
|
18
|
+
endif
|
|
19
|
+
|
|
20
|
+
LIBFFI = $(LIBFFI_BUILD_DIR)/.libs/libffi_convenience.a
|
|
21
|
+
LIBFFI_CONFIGURE = $(LIBFFI_SRC_DIR)/configure --disable-static \
|
|
22
|
+
--with-pic=yes --disable-dependency-tracking
|
|
23
|
+
|
|
24
|
+
$(OBJS): $(LIBFFI)
|
|
25
|
+
|
|
26
|
+
#
|
|
27
|
+
# libffi.mk or libffi.darwin.mk contains rules for building the actual library
|
|
28
|
+
#
|
|
29
|
+
|
data/ext/ffi_c/libffi.mk
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
# -*- makefile -*-
|
|
2
2
|
|
|
3
|
+
include ${srcdir}/libffi.gnu.mk
|
|
4
|
+
|
|
3
5
|
$(LIBFFI):
|
|
4
6
|
@mkdir -p $(LIBFFI_BUILD_DIR)
|
|
5
7
|
@if [ ! -f $(LIBFFI_BUILD_DIR)/Makefile ]; then \
|
|
6
8
|
echo "Configuring libffi"; \
|
|
7
9
|
cd $(LIBFFI_BUILD_DIR) && \
|
|
8
|
-
/usr/bin/env CC="$(CC)" LD="$(LD)" CFLAGS="$(
|
|
9
|
-
/bin/sh $(
|
|
10
|
+
/usr/bin/env CC="$(CC)" LD="$(LD)" CFLAGS="$(LIBFFI_CFLAGS)" \
|
|
11
|
+
/bin/sh $(LIBFFI_CONFIGURE) $(LIBFFI_HOST) > /dev/null; \
|
|
10
12
|
fi
|
|
11
13
|
cd $(LIBFFI_BUILD_DIR) && $(MAKE)
|
data/ext/ffi_c/rbffi.h
CHANGED
|
@@ -8,14 +8,12 @@ extern "C" {
|
|
|
8
8
|
#endif
|
|
9
9
|
|
|
10
10
|
#define MAX_PARAMETERS (32)
|
|
11
|
-
|
|
12
|
-
extern void
|
|
13
|
-
extern void
|
|
14
|
-
extern void
|
|
15
|
-
extern
|
|
16
|
-
extern
|
|
17
|
-
extern VALUE rb_FFI_AbstractMemory_class;
|
|
18
|
-
extern int rb_FFI_type_size(VALUE type);
|
|
11
|
+
|
|
12
|
+
extern void rbffi_Type_Init(VALUE ffiModule);
|
|
13
|
+
extern void rbffi_Buffer_Init(VALUE ffiModule);
|
|
14
|
+
extern void rbffi_Invoker_Init(VALUE ffiModule);
|
|
15
|
+
extern VALUE rbffi_AbstractMemoryClass, rbffi_InvokerClass;
|
|
16
|
+
extern int rbffi_type_size(VALUE type);
|
|
19
17
|
|
|
20
18
|
#ifdef __cplusplus
|
|
21
19
|
}
|
data/gen/Rakefile
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
require 'fileutils'
|
|
2
|
+
require "#{File.join(ENV['RUBYLIBDIR'], 'ffi', 'tools', 'types_generator.rb')}"
|
|
3
|
+
types_conf = File.join(ENV['RUBYLIBDIR'], 'ffi', 'types.conf')
|
|
4
|
+
file types_conf do |task|
|
|
5
|
+
options = {}
|
|
6
|
+
FileUtils.mkdir_p(File.dirname(task.name), { :mode => 0755 })
|
|
7
|
+
File.open(task.name, File::CREAT|File::TRUNC|File::RDWR, 0644) do |f|
|
|
8
|
+
f.puts FFI::TypesGenerator.generate(options)
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
task :default => types_conf do
|
|
12
|
+
end
|
data/lib/ffi/autopointer.rb
CHANGED
|
@@ -28,7 +28,7 @@ module FFI
|
|
|
28
28
|
# release(), which by default does nothing.
|
|
29
29
|
#
|
|
30
30
|
def initialize(ptr, proc=nil, &block)
|
|
31
|
-
raise
|
|
31
|
+
raise TypeError, "Invalid pointer" if ptr.nil? || !ptr.kind_of?(Pointer) \
|
|
32
32
|
|| ptr.kind_of?(MemoryPointer) || ptr.kind_of?(AutoPointer)
|
|
33
33
|
free_lambda = if proc and proc.is_a? Method
|
|
34
34
|
AutoPointer.finalize(ptr, AutoPointer.method_to_proc(proc))
|
data/lib/ffi/enum.rb
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
module FFI
|
|
2
|
+
|
|
3
|
+
class Enums
|
|
4
|
+
|
|
5
|
+
def initialize
|
|
6
|
+
@all_enums = Array.new
|
|
7
|
+
@tagged_enums = Hash.new
|
|
8
|
+
@symbol_map = Hash.new
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def <<(enum)
|
|
12
|
+
@all_enums << enum
|
|
13
|
+
@tagged_enums[enum.tag] = enum unless enum.tag.nil?
|
|
14
|
+
@symbol_map.merge!(enum.symbol_map)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def find(query)
|
|
18
|
+
if @tagged_enums.has_key?(query)
|
|
19
|
+
@tagged_enums[query]
|
|
20
|
+
else
|
|
21
|
+
@all_enums.detect { |enum| enum.symbols.include?(query) }
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def __map_symbol(symbol)
|
|
26
|
+
@symbol_map[symbol]
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
class Enum
|
|
32
|
+
attr_reader :tag
|
|
33
|
+
|
|
34
|
+
def initialize(info, tag=nil)
|
|
35
|
+
@tag = tag
|
|
36
|
+
@kv_map = Hash.new
|
|
37
|
+
@vk_map = Hash.new
|
|
38
|
+
unless info.nil?
|
|
39
|
+
last_cst = nil
|
|
40
|
+
value = 0
|
|
41
|
+
info.each do |i|
|
|
42
|
+
case i
|
|
43
|
+
when Symbol
|
|
44
|
+
@kv_map[i] = value
|
|
45
|
+
@vk_map[value] = i
|
|
46
|
+
last_cst = i
|
|
47
|
+
value += 1
|
|
48
|
+
when Integer
|
|
49
|
+
@kv_map[last_cst] = i
|
|
50
|
+
@vk_map[i] = last_cst
|
|
51
|
+
value = i+1
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def symbols
|
|
58
|
+
@kv_map.keys
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def [](query)
|
|
62
|
+
case query
|
|
63
|
+
when Symbol
|
|
64
|
+
@kv_map[query]
|
|
65
|
+
when Integer
|
|
66
|
+
@vk_map[query]
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
alias find []
|
|
70
|
+
|
|
71
|
+
def symbol_map
|
|
72
|
+
@kv_map
|
|
73
|
+
end
|
|
74
|
+
alias to_h symbol_map
|
|
75
|
+
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
end
|
data/lib/ffi/ffi.rb
CHANGED
|
@@ -30,8 +30,6 @@ module FFI
|
|
|
30
30
|
# Specialised error classes
|
|
31
31
|
class NativeError < LoadError; end
|
|
32
32
|
|
|
33
|
-
class TypeError < NativeError; end
|
|
34
|
-
|
|
35
33
|
class SignatureError < NativeError; end
|
|
36
34
|
|
|
37
35
|
class NotFoundError < NativeError
|
|
@@ -54,6 +52,7 @@ require 'ffi/callback'
|
|
|
54
52
|
require 'ffi/io'
|
|
55
53
|
require 'ffi/autopointer'
|
|
56
54
|
require 'ffi/variadic'
|
|
55
|
+
require 'ffi/enum'
|
|
57
56
|
|
|
58
57
|
module FFI
|
|
59
58
|
|
|
@@ -67,7 +66,7 @@ module FFI
|
|
|
67
66
|
end
|
|
68
67
|
lib
|
|
69
68
|
end
|
|
70
|
-
def self.create_invoker(lib, name, args,
|
|
69
|
+
def self.create_invoker(lib, name, args, ret_type, native_ret_type, options = { :convention => :default })
|
|
71
70
|
# Current artificial limitation based on JRuby::FFI limit
|
|
72
71
|
raise SignatureError, 'FFI functions may take max 32 arguments!' if args.size > 32
|
|
73
72
|
|
|
@@ -82,14 +81,14 @@ module FFI
|
|
|
82
81
|
else
|
|
83
82
|
raise LoadError, "Invalid library '#{lib}'"
|
|
84
83
|
end
|
|
85
|
-
function = library.
|
|
84
|
+
function = library.find_function(name)
|
|
86
85
|
raise NotFoundError.new(name, library.name) unless function
|
|
87
86
|
|
|
88
87
|
args = args.map {|e| find_type(e) }
|
|
89
88
|
if args.length > 0 && args[args.length - 1] == FFI::NativeType::VARARGS
|
|
90
|
-
invoker = FFI::VariadicInvoker.new(
|
|
89
|
+
invoker = FFI::VariadicInvoker.new(function, args, ret_type, find_type(native_ret_type), options)
|
|
91
90
|
else
|
|
92
|
-
invoker = FFI::Invoker.new(
|
|
91
|
+
invoker = FFI::Invoker.new(function, args, ret_type, find_type(native_ret_type), options[:convention].to_s, options[:enums])
|
|
93
92
|
end
|
|
94
93
|
raise NotFoundError.new(name, library.name) unless invoker
|
|
95
94
|
return invoker
|
data/lib/ffi/io.rb
CHANGED
|
@@ -3,5 +3,19 @@ module FFI
|
|
|
3
3
|
def self.for_fd(fd, mode = "r")
|
|
4
4
|
::IO.for_fd(fd, mode)
|
|
5
5
|
end
|
|
6
|
+
|
|
7
|
+
#
|
|
8
|
+
# A version of IO#read that reads into a native buffer
|
|
9
|
+
#
|
|
10
|
+
# This will be optimized at some future time to eliminate the double copy
|
|
11
|
+
#
|
|
12
|
+
def self.native_read(io, buf, len)
|
|
13
|
+
tmp = io.read(len)
|
|
14
|
+
return -1 unless tmp
|
|
15
|
+
buf.put_bytes(0, tmp)
|
|
16
|
+
tmp.length
|
|
17
|
+
end
|
|
18
|
+
|
|
6
19
|
end
|
|
7
|
-
end
|
|
20
|
+
end
|
|
21
|
+
|
data/lib/ffi/library.rb
CHANGED
|
@@ -3,19 +3,26 @@ module FFI::Library
|
|
|
3
3
|
|
|
4
4
|
def ffi_lib(*names)
|
|
5
5
|
ffi_libs = []
|
|
6
|
+
errors = {}
|
|
6
7
|
names.each do |name|
|
|
7
8
|
[ name, FFI.map_library_name(name) ].each do |libname|
|
|
8
9
|
begin
|
|
9
|
-
lib = FFI::DynamicLibrary.open(libname, FFI::DynamicLibrary::RTLD_LAZY | FFI::DynamicLibrary::
|
|
10
|
+
lib = FFI::DynamicLibrary.open(libname, FFI::DynamicLibrary::RTLD_LAZY | FFI::DynamicLibrary::RTLD_GLOBAL)
|
|
10
11
|
if lib
|
|
11
12
|
ffi_libs << lib
|
|
12
13
|
break
|
|
13
14
|
end
|
|
14
|
-
rescue
|
|
15
|
+
rescue Exception => ex
|
|
16
|
+
errors[name] = ex
|
|
15
17
|
end
|
|
16
18
|
end
|
|
17
19
|
end
|
|
18
|
-
|
|
20
|
+
if ffi_libs.empty?
|
|
21
|
+
msgs = []
|
|
22
|
+
errors.each {|name, ex| msgs << "Failed to load library '#{name}': #{ex.message}" }
|
|
23
|
+
raise LoadError.new(msgs.join('\n'))
|
|
24
|
+
end
|
|
25
|
+
|
|
19
26
|
@ffi_libs = ffi_libs
|
|
20
27
|
end
|
|
21
28
|
def ffi_convention(convention)
|
|
@@ -33,20 +40,21 @@ module FFI::Library
|
|
|
33
40
|
|
|
34
41
|
def attach_function(mname, a3, a4, a5=nil)
|
|
35
42
|
cname, arg_types, ret_type = a5 ? [ a3, a4, a5 ] : [ mname.to_s, a3, a4 ]
|
|
36
|
-
libraries = defined?(@ffi_libs) ? @ffi_libs : [ DEFAULT ]
|
|
37
|
-
convention = defined?(@ffi_convention) ? @ffi_convention : :default
|
|
38
43
|
|
|
39
44
|
# Convert :foo to the native type
|
|
40
45
|
arg_types.map! { |e| find_type(e) }
|
|
41
46
|
has_callback = arg_types.any? {|t| t.kind_of?(FFI::CallbackInfo)}
|
|
42
47
|
options = Hash.new
|
|
43
|
-
options[:convention] =
|
|
48
|
+
options[:convention] = defined?(@ffi_convention) ? @ffi_convention : :default
|
|
44
49
|
options[:type_map] = @ffi_typedefs if defined?(@ffi_typedefs)
|
|
50
|
+
options[:enums] = @ffi_enums if defined?(@ffi_enums)
|
|
51
|
+
|
|
45
52
|
# Try to locate the function in any of the libraries
|
|
46
53
|
invokers = []
|
|
54
|
+
libraries = defined?(@ffi_libs) ? @ffi_libs : [ DEFAULT ]
|
|
47
55
|
libraries.each do |lib|
|
|
48
56
|
begin
|
|
49
|
-
invokers << FFI.create_invoker(lib, cname.to_s, arg_types, find_type(ret_type), options)
|
|
57
|
+
invokers << FFI.create_invoker(lib, cname.to_s, arg_types, ret_type, find_type(ret_type), options)
|
|
50
58
|
rescue LoadError => ex
|
|
51
59
|
end if invokers.empty?
|
|
52
60
|
end
|
|
@@ -87,7 +95,7 @@ module FFI::Library
|
|
|
87
95
|
address = nil
|
|
88
96
|
libraries.each do |lib|
|
|
89
97
|
begin
|
|
90
|
-
address = lib.
|
|
98
|
+
address = lib.find_variable(cname.to_s)
|
|
91
99
|
break unless address.nil?
|
|
92
100
|
rescue LoadError
|
|
93
101
|
end
|
|
@@ -120,7 +128,7 @@ module FFI::Library
|
|
|
120
128
|
if ffi_type.is_a?(FFI::CallbackInfo)
|
|
121
129
|
op = :callback
|
|
122
130
|
else
|
|
123
|
-
raise
|
|
131
|
+
raise TypeError, "Cannot access library variable of type #{type}"
|
|
124
132
|
end
|
|
125
133
|
end
|
|
126
134
|
#
|
|
@@ -150,20 +158,72 @@ module FFI::Library
|
|
|
150
158
|
end
|
|
151
159
|
address
|
|
152
160
|
end
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
161
|
+
|
|
162
|
+
def callback(*args)
|
|
163
|
+
raise ArgError, "wrong number of arguments" if args.length < 2 || args.length > 3
|
|
164
|
+
name, params, ret = if args.length == 3
|
|
165
|
+
args
|
|
166
|
+
else
|
|
167
|
+
[ nil, args[0], args[1] ]
|
|
168
|
+
end
|
|
169
|
+
cb = FFI::CallbackInfo.new(find_type(ret), params.map { |e| find_type(e) })
|
|
170
|
+
|
|
171
|
+
# Add to the symbol -> type map (unless there was no name)
|
|
172
|
+
unless name.nil?
|
|
173
|
+
@ffi_callbacks = Hash.new unless defined?(@ffi_callbacks)
|
|
174
|
+
@ffi_callbacks[name] = cb
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
cb
|
|
156
178
|
end
|
|
157
|
-
|
|
179
|
+
|
|
180
|
+
def typedef(current, add, info=nil)
|
|
158
181
|
@ffi_typedefs = Hash.new unless defined?(@ffi_typedefs)
|
|
159
|
-
if current.kind_of?
|
|
160
|
-
|
|
182
|
+
code = if current.kind_of?(FFI::Type)
|
|
183
|
+
current
|
|
184
|
+
elsif current == :enum
|
|
185
|
+
if add.kind_of?(Array)
|
|
186
|
+
self.enum(add)
|
|
187
|
+
else
|
|
188
|
+
self.enum(info, add)
|
|
189
|
+
end
|
|
161
190
|
else
|
|
162
|
-
|
|
191
|
+
@ffi_typedefs[current] || FFI.find_type(current)
|
|
163
192
|
end
|
|
164
193
|
|
|
165
194
|
@ffi_typedefs[add] = code
|
|
166
195
|
end
|
|
196
|
+
|
|
197
|
+
def enum(*args)
|
|
198
|
+
#
|
|
199
|
+
# enum can be called as:
|
|
200
|
+
# enum :zero, :one, :two # unnamed enum
|
|
201
|
+
# enum [ :zero, :one, :two ] # equivalent to above
|
|
202
|
+
# enum :foo, [ :zero, :one, :two ] create an enum named :foo
|
|
203
|
+
#
|
|
204
|
+
name, values = if args[0].kind_of?(Symbol) && args[1].kind_of?(Array)
|
|
205
|
+
[ args[0], args[1] ]
|
|
206
|
+
elsif args[0].kind_of?(Array)
|
|
207
|
+
[ nil, args[0] ]
|
|
208
|
+
else
|
|
209
|
+
[ nil, args ]
|
|
210
|
+
end
|
|
211
|
+
@ffi_enums = FFI::Enums.new unless defined?(@ffi_enums)
|
|
212
|
+
@ffi_enums << (e = FFI::Enum.new(values, name))
|
|
213
|
+
|
|
214
|
+
# If called as enum :foo, [ :zero, :one, :two ], add a typedef alias
|
|
215
|
+
typedef(e, name) if name
|
|
216
|
+
e
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
def enum_type(name)
|
|
220
|
+
@ffi_enums.find(name) if defined?(@ffi_enums)
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
def enum_value(symbol)
|
|
224
|
+
@ffi_enums.__map_symbol(symbol)
|
|
225
|
+
end
|
|
226
|
+
|
|
167
227
|
def find_type(name)
|
|
168
228
|
code = if defined?(@ffi_typedefs) && @ffi_typedefs.has_key?(name)
|
|
169
229
|
@ffi_typedefs[name]
|
|
@@ -171,12 +231,13 @@ module FFI::Library
|
|
|
171
231
|
@ffi_callbacks[name]
|
|
172
232
|
elsif name.is_a?(Class) && name < FFI::Struct
|
|
173
233
|
FFI::NativeType::POINTER
|
|
234
|
+
elsif name.kind_of?(FFI::Type)
|
|
235
|
+
name
|
|
174
236
|
end
|
|
175
|
-
code = name if !code && name.kind_of?(FFI::CallbackInfo)
|
|
176
237
|
if code.nil? || code.kind_of?(Symbol)
|
|
177
238
|
FFI.find_type(name)
|
|
178
239
|
else
|
|
179
240
|
code
|
|
180
241
|
end
|
|
181
242
|
end
|
|
182
|
-
end
|
|
243
|
+
end
|
data/lib/ffi/pointer.rb
CHANGED
|
@@ -52,13 +52,13 @@ module FFI
|
|
|
52
52
|
|
|
53
53
|
def read_string(len=nil)
|
|
54
54
|
if len
|
|
55
|
-
|
|
55
|
+
get_bytes(0, len)
|
|
56
56
|
else
|
|
57
57
|
get_string(0)
|
|
58
58
|
end
|
|
59
59
|
end
|
|
60
60
|
def read_string_length(len)
|
|
61
|
-
|
|
61
|
+
get_bytes(0, len)
|
|
62
62
|
end
|
|
63
63
|
def read_string_to_null
|
|
64
64
|
get_string(0)
|