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.
Files changed (76) hide show
  1. data/README.rdoc +51 -1
  2. data/Rakefile +38 -28
  3. data/ext/ffi_c/AbstractMemory.c +74 -70
  4. data/ext/ffi_c/AbstractMemory.h +8 -4
  5. data/ext/ffi_c/AutoPointer.c +8 -9
  6. data/ext/ffi_c/AutoPointer.h +2 -2
  7. data/ext/ffi_c/Buffer.c +42 -24
  8. data/ext/ffi_c/Callback.c +85 -33
  9. data/ext/ffi_c/Callback.h +11 -5
  10. data/ext/ffi_c/{NativeLibrary.c → DynamicLibrary.c} +83 -16
  11. data/ext/ffi_c/{NativeLibrary.h → DynamicLibrary.h} +1 -1
  12. data/ext/ffi_c/Invoker.c +152 -192
  13. data/ext/ffi_c/LastError.c +135 -0
  14. data/ext/ffi_c/LastError.h +18 -0
  15. data/ext/ffi_c/MemoryPointer.c +27 -20
  16. data/ext/ffi_c/MemoryPointer.h +3 -3
  17. data/ext/ffi_c/NullPointer.c +51 -47
  18. data/ext/ffi_c/Platform.c +9 -10
  19. data/ext/ffi_c/Platform.h +1 -1
  20. data/ext/ffi_c/Pointer.c +52 -21
  21. data/ext/ffi_c/Pointer.h +8 -6
  22. data/ext/ffi_c/Struct.c +70 -61
  23. data/ext/ffi_c/Struct.h +2 -2
  24. data/ext/ffi_c/Type.c +230 -0
  25. data/ext/ffi_c/Type.h +28 -0
  26. data/ext/ffi_c/Types.c +48 -6
  27. data/ext/ffi_c/Types.h +8 -2
  28. data/ext/ffi_c/endian.h +40 -0
  29. data/ext/ffi_c/extconf.rb +6 -5
  30. data/ext/ffi_c/ffi.c +21 -44
  31. data/ext/ffi_c/libffi.bsd.mk +34 -0
  32. data/ext/ffi_c/libffi.darwin.mk +30 -10
  33. data/ext/ffi_c/libffi.gnu.mk +29 -0
  34. data/ext/ffi_c/libffi.mk +4 -2
  35. data/ext/ffi_c/rbffi.h +6 -8
  36. data/gen/Rakefile +12 -0
  37. data/lib/ffi/autopointer.rb +1 -1
  38. data/lib/ffi/enum.rb +78 -0
  39. data/lib/ffi/ffi.rb +5 -6
  40. data/lib/ffi/io.rb +15 -1
  41. data/lib/ffi/library.rb +79 -18
  42. data/lib/ffi/pointer.rb +2 -2
  43. data/lib/ffi/struct.rb +68 -14
  44. data/lib/ffi/types.rb +6 -3
  45. data/lib/ffi/variadic.rb +2 -2
  46. data/lib/ffi.rb +10 -1
  47. data/spec/ffi/bool_spec.rb +24 -0
  48. data/spec/ffi/callback_spec.rb +217 -17
  49. data/spec/ffi/enum_spec.rb +164 -0
  50. data/spec/ffi/managed_struct_spec.rb +6 -1
  51. data/spec/ffi/number_spec.rb +30 -0
  52. data/spec/ffi/pointer_spec.rb +33 -8
  53. data/spec/ffi/rbx/memory_pointer_spec.rb +0 -6
  54. data/spec/ffi/spec_helper.rb +5 -1
  55. data/spec/ffi/string_spec.rb +65 -4
  56. data/spec/ffi/struct_callback_spec.rb +41 -0
  57. data/spec/ffi/struct_initialize_spec.rb +30 -0
  58. data/spec/ffi/struct_spec.rb +44 -21
  59. metadata +31 -69
  60. data/ext/ffi_c/ffi.mk +0 -23
  61. data/nbproject/Makefile-Default.mk +0 -57
  62. data/nbproject/Makefile-impl.mk +0 -123
  63. data/nbproject/Package-Default.bash +0 -72
  64. data/nbproject/configurations.xml +0 -293
  65. data/nbproject/private/configurations.xml +0 -22
  66. data/nbproject/private/private.xml +0 -7
  67. data/nbproject/project.properties +0 -0
  68. data/nbproject/project.xml +0 -15
  69. data/samples/getlogin.rb +0 -7
  70. data/samples/getpid.rb +0 -7
  71. data/samples/gettimeofday.rb +0 -17
  72. data/samples/hello.rb +0 -6
  73. data/samples/inotify.rb +0 -59
  74. data/samples/pty.rb +0 -75
  75. data/samples/qsort.rb +0 -20
  76. 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 $(srcdir)/libffi.darwin.mk"
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 $(srcdir)/libffi.mk"
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 "NativeLibrary.h"
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
- rb_FFI_type_size(VALUE type)
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 rb_funcall(moduleFFI, rb_intern("type_size"), 1, &type);
44
+ return NUM2INT(rb_funcall2(moduleFFI, type_size_id, 1, &type));
44
45
  } else {
45
- return rb_funcall(type, size_id, 0, NULL);
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
- rb_define_const(moduleNativeType, "VOID", INT2FIX(NATIVE_VOID));
62
- rb_define_const(moduleNativeType, "INT8", INT2FIX(NATIVE_INT8));
63
- rb_define_const(moduleNativeType, "UINT8", INT2FIX(NATIVE_UINT8));
64
- rb_define_const(moduleNativeType, "INT16", INT2FIX(NATIVE_INT16));
65
- rb_define_const(moduleNativeType, "UINT16", INT2FIX(NATIVE_UINT16));
66
- rb_define_const(moduleNativeType, "INT32", INT2FIX(NATIVE_INT32));
67
- rb_define_const(moduleNativeType, "UINT32", INT2FIX(NATIVE_UINT32));
68
- rb_define_const(moduleNativeType, "INT64", INT2FIX(NATIVE_INT64));
69
- rb_define_const(moduleNativeType, "UINT64", INT2FIX(NATIVE_UINT64));
70
- rb_define_const(moduleNativeType, "FLOAT32", INT2FIX(NATIVE_FLOAT32));
71
- rb_define_const(moduleNativeType, "FLOAT64", INT2FIX(NATIVE_FLOAT64));
72
- rb_define_const(moduleNativeType, "POINTER", INT2FIX(NATIVE_POINTER));
73
- rb_define_const(moduleNativeType, "STRING", INT2FIX(NATIVE_STRING));
74
- rb_define_const(moduleNativeType, "RBXSTRING", INT2FIX(NATIVE_RBXSTRING));
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
+
@@ -1,32 +1,52 @@
1
1
  # -*- makefile -*-
2
- ARCHES :=
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) $(FFI_CFLAGS)" LDFLAGS="-arch $(1)" \
23
- $(FFI_CONFIGURE) --host=$(1)-apple-darwin > /dev/null; \
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="$(FFI_CFLAGS)" \
9
- /bin/sh $(FFI_CONFIGURE) $(LIBFFI_HOST) > /dev/null; \
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 rb_FFI_AbstractMemory_Init();
13
- extern void rb_FFI_MemoryPointer_Init();
14
- extern void rb_FFI_Buffer_Init();
15
- extern void rb_FFI_Callback_Init();
16
- extern void rb_FFI_Invoker_Init();
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
@@ -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 ArgumentError, "Invalid pointer" if ptr.nil? || !ptr.kind_of?(Pointer) \
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, ret, options = { :convention => :default })
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.find_symbol(name)
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(library, function, args, find_type(ret), options)
89
+ invoker = FFI::VariadicInvoker.new(function, args, ret_type, find_type(native_ret_type), options)
91
90
  else
92
- invoker = FFI::Invoker.new(library, function, args, find_type(ret), options[:convention].to_s)
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::RTLD_LOCAL)
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 LoadError => ex
15
+ rescue Exception => ex
16
+ errors[name] = ex
15
17
  end
16
18
  end
17
19
  end
18
- raise LoadError, "Could not open any of [#{names.join(", ")}]" if ffi_libs.empty?
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] = 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.find_symbol(cname.to_s)
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 FFI::TypeError, "Cannot access library variable of type #{type}"
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
- def callback(name, args, ret)
154
- @ffi_callbacks = Hash.new unless defined?(@ffi_callbacks)
155
- @ffi_callbacks[name] = FFI::CallbackInfo.new(find_type(ret), args.map { |e| find_type(e) })
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
- def typedef(current, add)
179
+
180
+ def typedef(current, add, info=nil)
158
181
  @ffi_typedefs = Hash.new unless defined?(@ffi_typedefs)
159
- if current.kind_of? Integer
160
- code = current
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
- code = @ffi_typedefs[current] || FFI.find_type(current)
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
- get_string(0, len)
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
- get_string(0, len)
61
+ get_bytes(0, len)
62
62
  end
63
63
  def read_string_to_null
64
64
  get_string(0)