ffi 0.6.0 → 0.6.4

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/History.txt ADDED
@@ -0,0 +1,102 @@
1
+ == 0.5.0 / 2009-10-06
2
+
3
+ * Major improvements
4
+ * New Function class
5
+ * Structs can be passed and returned by value
6
+ * Implement a custom trampoline for x86_64, resulting in roughly 30% speedup
7
+ * Improve dispatch of functions which take (0..6) char/short/int/long/pointer arguments by between 50% and 200% on x86_64
8
+ * Callbacks are now approximately 100% faster on x86_64
9
+ * Minor improvements
10
+ * Add support for MacOSX Snow Leopard
11
+ * Improve support for Windows releasing fat binaries on rubyforge
12
+ * Better introspection in structs:
13
+ * Add StructLayout::Field#type, size, offset, alignment and name
14
+ methods
15
+ * Add StructLayout#fields which returns an array of
16
+ StructLayout::Field objects
17
+ * Add automagic deducing of library name from module name.
18
+ Idea and prototype implementation from Matt Hulse
19
+ * Callback fields in structs can now be both read and written
20
+ * Add a bunch of new benchmarks
21
+ * Lots of refactoring
22
+ * Experimental features
23
+ * blocking functions (i.e. native code that blocks the thread) support
24
+ * Bug fixes
25
+ * Fix RUBY-FFI_43 (rake gem dependency)
26
+
27
+ == 0.4.0 / 2009-08-05
28
+
29
+ * Major improvements
30
+ * Add support for boolean types
31
+ * Add support for methods as callbacks
32
+ * Add FFI::IO.read as described in JRUBY-3636
33
+ * Minor improvements
34
+ * Add Pointer::NULL constant
35
+ * Add AbstractMemory#get_array_of_string()
36
+ * Implement Pointer.new(address) and Pointer.new(:type, address)
37
+ * Bug fixes
38
+ * Fix RUBY_FFI-38
39
+ * Fix issues related to 1.9.1 build
40
+ * Fix issues related to OSX build
41
+ * Fix issues related to FreeBSD build
42
+ * Fix issues related to OpenSolaris build
43
+
44
+ == 0.3.5 / 2009-05-08
45
+
46
+ * Bug fixes
47
+ * Fix RUBY_FFI-17
48
+ * Fix RUBY_FFI-21
49
+
50
+ == 0.3.4 / 2009-05-01
51
+
52
+ * Minor improvements
53
+ * Add return statements to functions that call rb_raise(), in case
54
+ rb_raise is not declared noreturn, to avoid gcc warnings.
55
+
56
+ == 0.3.3 / 2009-04-27
57
+
58
+ * Minor improvements
59
+ * Implement RUBY_FFI-16 - Add support for anonymous callbacks
60
+ * Add support for callback parameters in callbacks
61
+ * Add support for function pointer return values
62
+ * Callbacks can now coerce proc objects into function pointers for
63
+ return values.
64
+ * Implement FFI::Type and FFI::Type::Builtin
65
+ * Add support for enumerations
66
+ * Bug fixes
67
+ * Fix RUBY_FFI-19
68
+ * Fix RUBY_FFI-15
69
+
70
+ == 0.3.2 / 2009-05-01
71
+
72
+ * Bug fixes
73
+ * Fix JRUBY-3527 by passing RTLD_GLOBAL instead of RTLD_LOCAL
74
+
75
+ == 0.3.1 / 2009-03-23
76
+
77
+ * Bug fixes
78
+ * Correctly save errno/GetLastError after each call.
79
+
80
+ == 0.3.0 / 2009-03-19
81
+
82
+ * Switch compilation to rake-compiler
83
+ * Makes cross-compilation from linux -> win32 super easy
84
+ * win32 support is available now, but highly experimental
85
+ * Performance improvements
86
+ * struct field access approx 3x faster than 0.2.0
87
+ * function invocation approx 20% faster than 0.2.0
88
+ * A bunch of minor improvements
89
+ * Struct instances can now be passed as :pointer parameters without calling
90
+ Struct#pointer
91
+ * Support for array struct members
92
+ * Structs are now padded correctly to the alignment of the struct's
93
+ largest field
94
+ * Global library variables
95
+ * Callbacks in global library variables
96
+ * Strings passed in as :string arguments are scrubbed to avoid
97
+ poison-null-byte attacks.
98
+ * Union support
99
+ * nil can be passed as a :string argument (passed as NULL)
100
+ * Structs can now be fields inside another struct
101
+ * Lots of internal cleanups and refactorings.
102
+
data/README.md ADDED
@@ -0,0 +1,109 @@
1
+ # ruby-ffi http://wiki.github.com/ffi/ffi [![Build Status](https://travis-ci.org/ffi/ffi.png?branch=master)](https://travis-ci.org/ffi/ffi)
2
+
3
+ ## Description
4
+
5
+ Ruby-FFI is a ruby extension for programmatically loading dynamic
6
+ libraries, binding functions within them, and calling those functions
7
+ from Ruby code. Moreover, a Ruby-FFI extension works without changes
8
+ on Ruby and JRuby. Discover why should you write your next extension
9
+ using Ruby-FFI [here](http://wiki.github.com/ffi/ffi/why-use-ffi).
10
+
11
+ ## Features/problems
12
+
13
+ * Intuitive DSL
14
+ * Supports all C native types
15
+ * C structs (also nested), enums and global variables
16
+ * Callbacks from C to ruby
17
+ * Automatic garbage collection of native memory
18
+
19
+ ## Synopsis
20
+
21
+ ```ruby
22
+ require 'ffi'
23
+
24
+ module MyLib
25
+ extend FFI::Library
26
+ ffi_lib 'c'
27
+ attach_function :puts, [ :string ], :int
28
+ end
29
+
30
+ MyLib.puts 'Hello, World using libc!'
31
+ ```
32
+
33
+ For less minimalistic and more sane examples you may look at:
34
+
35
+ * the samples/ folder
36
+ * the examples on the [wiki](http://wiki.github.com/ffi/ffi)
37
+ * the projects using FFI listed on this page (http://wiki.github.com/ffi/ffi/projects-using-ffi)
38
+
39
+ ## Requirements
40
+
41
+ You need a sane building environment in order to compile the extension.
42
+ At a minimum, you will need:
43
+ * A C compiler (e.g. Xcode on OSX, gcc on everything else)
44
+ * libffi development library - this is commonly in the libffi-dev or libffi-devel
45
+
46
+ ## Installation
47
+
48
+ From rubygems:
49
+
50
+ [sudo] gem install ffi
51
+
52
+ or from the git repository on github:
53
+
54
+ git clone git://github.com/ffi/ffi.git
55
+ cd ffi
56
+ rake gem:install
57
+
58
+ ## License
59
+
60
+ The ffi library is covered by the LGPL3 license, also see the LICENSE file.
61
+ The specs are shared with Rubyspec and are licensed by the same license
62
+ as Rubyspec, see the LICENSE.SPECS file.
63
+
64
+ ## Credits
65
+
66
+ The following people have submitted code, bug reports, or otherwide contributed to the success of this project:
67
+
68
+ * Alban Peignier <alban.peignier@free.fr>
69
+ * Aman Gupta <aman@tmm1.net>
70
+ * Andrea Fazzi <andrea.fazzi@alcacoop.it>
71
+ * Andreas Niederl <rico32@gmx.net>
72
+ * Andrew Cholakian <andrew@andrewvc.com>
73
+ * Antonio Terceiro <terceiro@softwarelivre.org>
74
+ * Brian Candler <B.Candler@pobox.com>
75
+ * Brian D. Burns <burns180@gmail.com>
76
+ * Bryan Kearney <bkearney@redhat.com>
77
+ * Charlie Savage <cfis@zerista.com>
78
+ * Chikanaga Tomoyuki <nagachika00@gmail.com>
79
+ * Hongli Lai <hongli@phusion.nl>
80
+ * Ian MacLeod <ian@nevir.net>
81
+ * Jake Douglas <jake@shiftedlabs.com>
82
+ * Jean-Dominique Morani <jdmorani@mac.com>
83
+ * Jeremy Hinegardner <jeremy@hinegardner.org>
84
+ * Jesús García Sáez <blaxter@gmail.com>
85
+ * Joe Khoobyar <joe@ankhcraft.com>
86
+ * Jurij Smakov <jurij@wooyd.org>
87
+ * KISHIMOTO, Makoto <ksmakoto@dd.iij4u.or.jp>
88
+ * Kim Burgestrand <kim@burgestrand.se>
89
+ * Lars Kanis <kanis@comcard.de>
90
+ * Luc Heinrich <luc@honk-honk.com>
91
+ * Luis Lavena <luislavena@gmail.com>
92
+ * Matijs van Zuijlen <matijs@matijs.net>
93
+ * Matthew King <automatthew@gmail.com>
94
+ * Mike Dalessio <mike.dalessio@gmail.com>
95
+ * NARUSE, Yui <naruse@airemix.jp>
96
+ * Park Heesob <phasis@gmail.com>
97
+ * Shin Yee <shinyee@speedgocomputing.com>
98
+ * Stephen Bannasch <stephen.bannasch@gmail.com>
99
+ * Suraj N. Kurapati <sunaku@gmail.com>
100
+ * Sylvain Daubert <sylvain.daubert@laposte.net>
101
+ * Victor Costan
102
+ * beoran@gmail.com
103
+ * ctide <christide@christide.com>
104
+ * emboss <Martin.Bosslet@googlemail.com>
105
+ * hobophobe <unusualtears@gmail.com>
106
+ * meh <meh@paranoici.org>
107
+ * postmodern <postmodern.mod3@gmail.com>
108
+ * wycats@gmail.com <wycats@gmail.com>
109
+ * Wayne Meissner <wmeissner@gmail.com>
data/Rakefile CHANGED
@@ -1,32 +1,31 @@
1
1
  require 'rubygems'
2
+ require 'rubygems/package_task'
2
3
  require 'rbconfig'
3
4
 
4
5
  USE_RAKE_COMPILER = (RUBY_PLATFORM =~ /java/) ? false : true
5
6
  if USE_RAKE_COMPILER
6
7
  gem 'rake-compiler', '>=0.6.0'
7
8
  require 'rake/extensiontask'
8
- ENV['RUBY_CC_VERSION'] = '1.8.6:1.9.1'
9
9
  end
10
10
 
11
11
  require 'date'
12
12
  require 'fileutils'
13
13
  require 'rbconfig'
14
14
 
15
- load 'tasks/setup.rb'
16
15
 
17
- LIBEXT = case Config::CONFIG['host_os'].downcase
16
+ LIBEXT = case RbConfig::CONFIG['host_os'].downcase
18
17
  when /darwin/
19
18
  "dylib"
20
19
  when /mswin|mingw/
21
20
  "dll"
22
21
  else
23
- Config::CONFIG['DLEXT']
22
+ RbConfig::CONFIG['DLEXT']
24
23
  end
25
24
 
26
- CPU = case Config::CONFIG['host_cpu'].downcase
25
+ CPU = case RbConfig::CONFIG['host_cpu'].downcase
27
26
  when /i[3456]86/
28
27
  # Darwin always reports i686, even when running in 64bit mode
29
- if Config::CONFIG['host_os'] =~ /darwin/ && 0xfee1deadbeef.is_a?(Fixnum)
28
+ if RbConfig::CONFIG['host_os'] =~ /darwin/ && 0xfee1deadbeef.is_a?(Fixnum)
30
29
  "x86_64"
31
30
  else
32
31
  "i386"
@@ -41,11 +40,14 @@ CPU = case Config::CONFIG['host_cpu'].downcase
41
40
  when /ppc|powerpc/
42
41
  "powerpc"
43
42
 
43
+ when /^arm/
44
+ "arm"
45
+
44
46
  else
45
- Config::CONFIG['host_cpu']
47
+ RbConfig::CONFIG['host_cpu']
46
48
  end
47
49
 
48
- OS = case Config::CONFIG['host_os'].downcase
50
+ OS = case RbConfig::CONFIG['host_os'].downcase
49
51
  when /linux/
50
52
  "linux"
51
53
  when /darwin/
@@ -59,78 +61,48 @@ OS = case Config::CONFIG['host_os'].downcase
59
61
  when /mswin|mingw/
60
62
  "win32"
61
63
  else
62
- Config::CONFIG['host_os'].downcase
64
+ RbConfig::CONFIG['host_os'].downcase
63
65
  end
64
66
 
65
- CC=ENV['CC'] || Config::CONFIG['CC'] || "gcc"
67
+ CC = ENV['CC'] || RbConfig::CONFIG['CC'] || "gcc"
66
68
 
67
- GMAKE = Config::CONFIG['host_os'].downcase =~ /bsd|solaris/ ? "gmake" : "make"
69
+ GMAKE = system('which gmake >/dev/null') && 'gmake' || 'make'
68
70
 
69
71
  LIBTEST = "build/libtest.#{LIBEXT}"
70
72
  BUILD_DIR = "build"
71
- BUILD_EXT_DIR = File.join(BUILD_DIR, "#{Config::CONFIG['arch']}", 'ffi_c', RUBY_VERSION)
72
-
73
- # Project general information
74
- PROJ.name = 'ffi'
75
- PROJ.authors = 'Wayne Meissner'
76
- PROJ.email = 'wmeissner@gmail.com'
77
- PROJ.url = 'http://wiki.github.com/ffi/ffi'
78
- PROJ.version = '0.6.0'
79
- PROJ.rubyforge.name = 'ffi'
80
- PROJ.readme_file = 'README.rdoc'
81
-
82
- # Annoucement
83
- PROJ.ann.paragraphs << 'FEATURES' << 'SYNOPSIS' << 'REQUIREMENTS' << 'DOWNLOAD/INSTALL' << 'CREDITS' << 'LICENSE'
84
-
85
- PROJ.ann.email[:from] = 'andrea.fazzi@alcacoop.it'
86
- PROJ.ann.email[:to] = ['ruby-ffi@googlegroups.com']
87
- PROJ.ann.email[:server] = 'smtp.gmail.com'
88
-
89
- # Gem specifications
90
- PROJ.gem.need_tar = false
91
- PROJ.gem.files = %w(LICENSE README.rdoc Rakefile) + Dir.glob("{ext,gen,lib,spec}/**/*")
92
- PROJ.gem.platform = Gem::Platform::RUBY
93
-
94
- # Override Mr. Bones autogenerated extensions and force ours in
95
- PROJ.gem.extras['extensions'] = %w(ext/ffi_c/extconf.rb gen/Rakefile)
96
-
97
- # RDoc
98
- PROJ.rdoc.exclude << '^ext\/'
99
- PROJ.rdoc.opts << '-x' << 'ext'
100
-
101
- # Ruby
102
- PROJ.ruby_opts = []
103
- PROJ.ruby_opts << '-I' << BUILD_EXT_DIR unless RUBY_PLATFORM == "java"
73
+ BUILD_EXT_DIR = File.join(BUILD_DIR, "#{RbConfig::CONFIG['arch']}", 'ffi_c', RUBY_VERSION)
104
74
 
105
- # RSpec
106
- PROJ.spec.files.exclude /rbx/
107
- PROJ.spec.opts << '--color' << '-fs'
108
-
109
- # Dependencies
75
+ def gem_spec
76
+ @gem_spec ||= Gem::Specification.load('ffi.gemspec')
77
+ end
110
78
 
111
- depend_on 'rake', '>=0.8.7'
79
+ Gem::PackageTask.new(gem_spec) do |pkg|
80
+ pkg.need_zip = true
81
+ pkg.need_tar = true
82
+ pkg.package_dir = 'pkg'
83
+ end
112
84
 
113
85
  TEST_DEPS = [ LIBTEST ]
114
86
  if RUBY_PLATFORM == "java"
115
87
  desc "Run all specs"
116
88
  task :specs => TEST_DEPS do
117
- sh %{#{Gem.ruby} -S spec #{Dir["spec/ffi/*_spec.rb"].join(" ")} -fs --color}
89
+ sh %{#{Gem.ruby} -w -S rspec #{Dir["spec/ffi/*_spec.rb"].join(" ")} -fs --color}
118
90
  end
119
91
  desc "Run rubinius specs"
120
92
  task :rbxspecs => TEST_DEPS do
121
- sh %{#{Gem.ruby} -S spec #{Dir["spec/ffi/rbx/*_spec.rb"].join(" ")} -fs --color}
93
+ sh %{#{Gem.ruby} -w -S rspec #{Dir["spec/ffi/rbx/*_spec.rb"].join(" ")} -fs --color}
122
94
  end
123
95
  else
124
96
  TEST_DEPS.unshift :compile
125
97
  desc "Run all specs"
126
98
  task :specs => TEST_DEPS do
127
99
  ENV["MRI_FFI"] = "1"
128
- sh %{#{Gem.ruby} -Ilib -I#{BUILD_EXT_DIR} -S spec #{Dir["spec/ffi/*_spec.rb"].join(" ")} -fs --color}
100
+ sh %{#{Gem.ruby} -w -Ilib -I#{BUILD_EXT_DIR} -S rspec #{Dir["spec/ffi/*_spec.rb"].join(" ")} -fs --color}
129
101
  end
130
102
  desc "Run rubinius specs"
131
103
  task :rbxspecs => TEST_DEPS do
132
104
  ENV["MRI_FFI"] = "1"
133
- sh %{#{Gem.ruby} -Ilib -I#{BUILD_EXT_DIR} -S spec #{Dir["spec/ffi/rbx/*_spec.rb"].join(" ")} -fs --color}
105
+ sh %{#{Gem.ruby} -w -Ilib -I#{BUILD_EXT_DIR} -S rspec #{Dir["spec/ffi/rbx/*_spec.rb"].join(" ")} -fs --color}
134
106
  end
135
107
  end
136
108
 
@@ -140,20 +112,26 @@ task :package => 'gem:package'
140
112
  desc "Install the gem locally"
141
113
  task :install => 'gem:install'
142
114
 
115
+ namespace :gem do
116
+ task :install => :gem do
117
+ ruby %{ -S gem install pkg/ffi-#{gem_spec.version}.gem }
118
+ end
119
+ end
143
120
 
144
121
  desc "Clean all built files"
145
122
  task :distclean => :clobber do
146
123
  FileUtils.rm_rf('build')
147
- FileUtils.rm_rf(Dir["lib/**/ffi_c.#{Config::CONFIG['DLEXT']}"])
124
+ FileUtils.rm_rf(Dir["lib/**/ffi_c.#{RbConfig::CONFIG['DLEXT']}"])
148
125
  FileUtils.rm_rf('lib/1.8')
149
126
  FileUtils.rm_rf('lib/1.9')
127
+ FileUtils.rm_rf('lib/ffi/types.conf')
150
128
  FileUtils.rm_rf('conftest.dSYM')
151
129
  FileUtils.rm_rf('pkg')
152
130
  end
153
131
 
154
132
 
155
133
  desc "Build the native test lib"
156
- task "build/libtest.#{LIBEXT}" do
134
+ file "build/libtest.#{LIBEXT}" => FileList['libtest/**/*.[ch]'] do
157
135
  sh %{#{GMAKE} -f libtest/GNUmakefile CPU=#{CPU} OS=#{OS} }
158
136
  end
159
137
 
@@ -186,3 +164,54 @@ task 'spec:specdoc' => TEST_DEPS
186
164
 
187
165
  task :default => :specs
188
166
 
167
+ task 'gem:win32' do
168
+ sh("rake cross native gem RUBY_CC_VERSION='1.8.7:1.9.3'") || raise("win32 build failed!")
169
+ end
170
+
171
+
172
+ namespace 'java' do
173
+
174
+ java_gem_spec = Gem::Specification.new do |s|
175
+ s.name = gem_spec.name
176
+ s.version = gem_spec.version
177
+ s.author = gem_spec.author
178
+ s.email = gem_spec.email
179
+ s.homepage = gem_spec.homepage
180
+ s.summary = gem_spec.summary
181
+ s.description = gem_spec.description
182
+ s.files = %w(History.txt LICENSE COPYING COPYING.LESSER README.md Rakefile)
183
+ s.has_rdoc = false
184
+ s.license = gem_spec.license
185
+ s.platform = 'java'
186
+ end
187
+
188
+ Gem::PackageTask.new(java_gem_spec) do |pkg|
189
+ pkg.need_zip = true
190
+ pkg.need_tar = true
191
+ pkg.package_dir = 'pkg'
192
+ end
193
+ end
194
+
195
+ task 'gem:java' => 'java:gem'
196
+
197
+
198
+ if USE_RAKE_COMPILER
199
+ Rake::ExtensionTask.new('ffi_c', gem_spec) do |ext|
200
+ ext.name = 'ffi_c' # indicate the name of the extension.
201
+ # ext.lib_dir = BUILD_DIR # put binaries into this folder.
202
+ ext.tmp_dir = BUILD_DIR # temporary folder used during compilation.
203
+ ext.cross_compile = true # enable cross compilation (requires cross compile toolchain)
204
+ ext.cross_platform = 'i386-mingw32' # forces the Windows platform instead of the default one
205
+ end
206
+ end
207
+
208
+ begin
209
+ require 'yard'
210
+
211
+ namespace :doc do
212
+ YARD::Rake::YardocTask.new do |yard|
213
+ end
214
+ end
215
+ rescue LoadError
216
+ warn "[warn] YARD unavailable"
217
+ end
data/ext/ffi_c/Call.c CHANGED
@@ -142,10 +142,10 @@ rbffi_SetupCallParams(int argc, VALUE* argv, int paramCount, NativeType* paramTy
142
142
 
143
143
  case NATIVE_BOOL:
144
144
  if (type != T_TRUE && type != T_FALSE) {
145
- rb_raise(rb_eTypeError, "Expected a Boolean parameter");
145
+ rb_raise(rb_eTypeError, "wrong argument type (expected a boolean parameter)");
146
146
  }
147
- param->s32 = argv[argidx++] == Qtrue;
148
- ADJ(param, INT32);
147
+ param->s8 = argv[argidx++] == Qtrue;
148
+ ADJ(param, INT8);
149
149
  break;
150
150
 
151
151
 
@@ -0,0 +1,12 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <module type="RUBY_MODULE" version="4">
3
+ <component name="NewModuleRootManager" inherit-compiler-output="true">
4
+ <exclude-output />
5
+ <content url="file://$MODULE_DIR$">
6
+ <sourceFolder url="file://$MODULE_DIR$" isTestSource="false" />
7
+ </content>
8
+ <orderEntry type="inheritedJdk" />
9
+ <orderEntry type="sourceFolder" forTests="false" />
10
+ </component>
11
+ </module>
12
+
data/ext/ffi_c/Function.c CHANGED
@@ -374,7 +374,7 @@ callback_invoke(ffi_cif* cif, void* retval, void** parameters, void* user_data)
374
374
  param = rbffi_Pointer_NewInstance(*(void **) parameters[i]);
375
375
  break;
376
376
  case NATIVE_BOOL:
377
- param = (*(void **) parameters[i]) ? Qtrue : Qfalse;
377
+ param = (*(uint8_t *) parameters[i]) ? Qtrue : Qfalse;
378
378
  break;
379
379
 
380
380
  case NATIVE_FUNCTION:
@@ -428,8 +428,9 @@ callback_invoke(ffi_cif* cif, void* retval, void** parameters, void* user_data)
428
428
  *((void **) retval) = NULL;
429
429
  }
430
430
  break;
431
+
431
432
  case NATIVE_BOOL:
432
- *((ffi_sarg *) retval) = TYPE(rbReturnValue) == T_TRUE ? 1 : 0;
433
+ *((ffi_arg *) retval) = rbReturnValue == Qtrue;
433
434
  break;
434
435
 
435
436
  case NATIVE_FUNCTION:
data/ext/ffi_c/Struct.c CHANGED
@@ -71,6 +71,8 @@ typedef struct InlineArray_ {
71
71
  static void struct_mark(Struct *);
72
72
  static void struct_layout_builder_mark(StructLayoutBuilder *);
73
73
  static void struct_layout_builder_free(StructLayoutBuilder *);
74
+ static VALUE struct_class_layout(VALUE klass);
75
+ static void struct_malloc(Struct* s);
74
76
  static void inline_array_mark(InlineArray *);
75
77
 
76
78
  static inline int align(int offset, int align);
@@ -116,10 +118,8 @@ struct_initialize(int argc, VALUE* argv, VALUE self)
116
118
  /* Call up into ruby code to adjust the layout */
117
119
  if (nargs > 1) {
118
120
  s->rbLayout = rb_funcall2(CLASS_OF(self), id_layout, RARRAY_LEN(rest), RARRAY_PTR(rest));
119
- } else if (rb_cvar_defined(klass, id_layout_ivar)) {
120
- s->rbLayout = rb_cvar_get(klass, id_layout_ivar);
121
121
  } else {
122
- rb_raise(rb_eRuntimeError, "No Struct layout configured");
122
+ s->rbLayout = struct_class_layout(klass);
123
123
  }
124
124
 
125
125
  if (!rb_obj_is_kind_of(s->rbLayout, rbffi_StructLayoutClass)) {
@@ -132,13 +132,74 @@ struct_initialize(int argc, VALUE* argv, VALUE self)
132
132
  s->pointer = MEMORY(rbPointer);
133
133
  s->rbPointer = rbPointer;
134
134
  } else {
135
- s->rbPointer = rbffi_MemoryPointer_NewInstance(s->layout->size, 1, true);
136
- s->pointer = (AbstractMemory *) DATA_PTR(s->rbPointer);
135
+ struct_malloc(s);
137
136
  }
138
137
 
139
138
  return self;
140
139
  }
141
140
 
141
+ static VALUE
142
+ struct_class_layout(VALUE klass)
143
+ {
144
+ VALUE layout;
145
+ if (!rb_cvar_defined(klass, id_layout_ivar)) {
146
+ rb_raise(rb_eRuntimeError, "no Struct layout configured for %s", rb_class2name(klass));
147
+ }
148
+
149
+ layout = rb_cvar_get(klass, id_layout_ivar);
150
+ if (!rb_obj_is_kind_of(layout, rbffi_StructLayoutClass)) {
151
+ rb_raise(rb_eRuntimeError, "invalid Struct layout for %s", rb_class2name(klass));
152
+ }
153
+
154
+ return layout;
155
+ }
156
+
157
+ static StructLayout*
158
+ struct_layout(VALUE self)
159
+ {
160
+ Struct* s = (Struct *) DATA_PTR(self);
161
+ if (s->layout != NULL) {
162
+ return s->layout;
163
+ }
164
+
165
+ if (s->layout == NULL) {
166
+ s->rbLayout = struct_class_layout(CLASS_OF(self));
167
+ Data_Get_Struct(s->rbLayout, StructLayout, s->layout);
168
+ }
169
+
170
+ return s->layout;
171
+ }
172
+
173
+ static Struct*
174
+ struct_validate(VALUE self)
175
+ {
176
+ Struct* s;
177
+ Data_Get_Struct(self, Struct, s);
178
+
179
+ if (struct_layout(self) == NULL) {
180
+ rb_raise(rb_eRuntimeError, "struct layout == null");
181
+ }
182
+
183
+ if (s->pointer == NULL) {
184
+ struct_malloc(s);
185
+ }
186
+
187
+ return s;
188
+ }
189
+
190
+ static void
191
+ struct_malloc(Struct* s)
192
+ {
193
+ if (s->rbPointer == Qnil) {
194
+ s->rbPointer = rbffi_MemoryPointer_NewInstance(s->layout->size, 1, true);
195
+
196
+ } else if (!rb_obj_is_kind_of(s->rbPointer, rbffi_AbstractMemoryClass)) {
197
+ rb_raise(rb_eRuntimeError, "invalid pointer in struct");
198
+ }
199
+
200
+ s->pointer = (AbstractMemory *) DATA_PTR(s->rbPointer);
201
+ }
202
+
142
203
  static void
143
204
  struct_mark(Struct *s)
144
205
  {
@@ -151,9 +212,6 @@ struct_field(Struct* s, VALUE fieldName)
151
212
  {
152
213
  StructLayout* layout = s->layout;
153
214
  VALUE rbField;
154
- if (layout == NULL) {
155
- rb_raise(rb_eRuntimeError, "layout not set for Struct");
156
- }
157
215
 
158
216
  rbField = rb_hash_aref(layout->rbFieldMap, fieldName);
159
217
  if (rbField == Qnil) {
@@ -170,8 +228,9 @@ struct_aref(VALUE self, VALUE fieldName)
170
228
  Struct* s;
171
229
  VALUE rbField;
172
230
  StructField* f;
173
-
174
- Data_Get_Struct(self, Struct, s);
231
+
232
+ s = struct_validate(self);
233
+
175
234
  rbField = struct_field(s, fieldName);
176
235
  f = (StructField *) DATA_PTR(rbField);
177
236
 
@@ -196,7 +255,8 @@ struct_aset(VALUE self, VALUE fieldName, VALUE value)
196
255
  StructField* f;
197
256
 
198
257
 
199
- Data_Get_Struct(self, Struct, s);
258
+ s = struct_validate(self);
259
+
200
260
  rbField = struct_field(s, fieldName);
201
261
  f = (StructField *) DATA_PTR(rbField);
202
262
  if (f->put != NULL) {
@@ -221,12 +281,25 @@ static VALUE
221
281
  struct_set_pointer(VALUE self, VALUE pointer)
222
282
  {
223
283
  Struct* s;
284
+ StructLayout* layout;
285
+ AbstractMemory* memory;
224
286
 
225
287
  if (!rb_obj_is_kind_of(pointer, rbffi_AbstractMemoryClass)) {
226
- rb_raise(rb_eArgError, "Invalid pointer");
288
+ rb_raise(rb_eTypeError, "wrong argument type %s (expected Pointer or Buffer)",
289
+ rb_obj_classname(pointer));
290
+ return Qnil;
227
291
  }
228
292
 
293
+
229
294
  Data_Get_Struct(self, Struct, s);
295
+ Data_Get_Struct(pointer, AbstractMemory, memory);
296
+ layout = struct_layout(self);
297
+
298
+ if (layout->base.ffiType->size > memory->size) {
299
+ rb_raise(rb_eArgError, "memory of %d bytes too small for struct %s (expected at least %d)",
300
+ memory->size, rb_obj_classname(self), layout->base.ffiType->size);
301
+ }
302
+
230
303
  s->pointer = MEMORY(pointer);
231
304
  s->rbPointer = pointer;
232
305
  rb_ivar_set(self, id_pointer_ivar, pointer);
@@ -251,7 +324,9 @@ struct_set_layout(VALUE self, VALUE layout)
251
324
  Data_Get_Struct(self, Struct, s);
252
325
 
253
326
  if (!rb_obj_is_kind_of(layout, rbffi_StructLayoutClass)) {
254
- rb_raise(rb_eArgError, "Invalid Struct layout");
327
+ rb_raise(rb_eTypeError, "wrong argument type %s (expected %s)",
328
+ rb_obj_classname(layout), rb_class2name(rbffi_StructLayoutClass));
329
+ return Qnil;
255
330
  }
256
331
 
257
332
  Data_Get_Struct(layout, StructLayout, s->layout);
@@ -360,7 +360,8 @@ struct_layout_initialize(VALUE self, VALUE field_names, VALUE fields, VALUE size
360
360
  rb_raise(rb_eTypeError, "wrong type for field %d.", i);
361
361
  }
362
362
 
363
- Data_Get_Struct(rbField, StructField, field = layout->fields[i]);
363
+ field = layout->fields[i];
364
+ Data_Get_Struct(rbField, StructField, field);
364
365
 
365
366
  if (field->type == NULL || field->type->ffiType == NULL) {
366
367
  rb_raise(rb_eRuntimeError, "type of field %d not supported", i);
data/ext/ffi_c/Types.c CHANGED
@@ -76,7 +76,7 @@ rbffi_NativeValue_ToRuby(Type* type, VALUE rbType, const void* ptr, VALUE enums)
76
76
  case NATIVE_POINTER:
77
77
  return rbffi_Pointer_NewInstance(*(void **) ptr);
78
78
  case NATIVE_BOOL:
79
- return ((int) *(ffi_arg *) ptr) ? Qtrue : Qfalse;
79
+ return ((unsigned char) *(ffi_arg *) ptr) ? Qtrue : Qfalse;
80
80
  case NATIVE_ENUM:
81
81
  return rb_funcall(rbType, id_find, 1, INT2NUM((unsigned int) *(ffi_arg *) ptr));
82
82
 
@@ -9021,7 +9021,7 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
9021
9021
  old_archive_from_new_cmds='true'
9022
9022
  # FIXME: Should let the user specify the lib program.
9023
9023
  old_archive_cmds='lib -OUT:$oldlib$oldobjs$old_deplibs'
9024
- fix_srcfile_path='`cygpath -w "$srcfile"`'
9024
+ # fix_srcfile_path='`cygpath -w "$srcfile"`'
9025
9025
  enable_shared_with_static_runtimes=yes
9026
9026
  ;;
9027
9027