fiddle 1.0.9 → 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/ext/fiddle/pointer.c CHANGED
@@ -6,13 +6,13 @@
6
6
  #include <ruby/ruby.h>
7
7
  #include <ruby/io.h>
8
8
 
9
+ #include <ctype.h>
10
+ #include <fiddle.h>
11
+
9
12
  #ifdef HAVE_RUBY_MEMORY_VIEW_H
10
13
  # include <ruby/memory_view.h>
11
14
  #endif
12
15
 
13
- #include <ctype.h>
14
- #include <fiddle.h>
15
-
16
16
  #ifdef PRIsVALUE
17
17
  # define RB_OBJ_CLASSNAME(obj) rb_obj_class(obj)
18
18
  # define RB_OBJ_STRING(obj) (obj)
@@ -24,7 +24,7 @@
24
24
 
25
25
  VALUE rb_cPointer;
26
26
 
27
- typedef void (*freefunc_t)(void*);
27
+ typedef rb_fiddle_freefunc_t freefunc_t;
28
28
 
29
29
  struct ptr_data {
30
30
  void *ptr;
@@ -92,7 +92,7 @@ static const rb_data_type_t fiddle_ptr_data_type = {
92
92
  {fiddle_ptr_mark, fiddle_ptr_free, fiddle_ptr_memsize,},
93
93
  };
94
94
 
95
- #ifdef FIDDLE_MEMORY_VIEW
95
+ #ifdef HAVE_RUBY_MEMORY_VIEW_H
96
96
  static struct ptr_data *
97
97
  fiddle_ptr_check_memory_view(VALUE obj)
98
98
  {
@@ -125,7 +125,7 @@ static const rb_memory_view_entry_t fiddle_ptr_memory_view_entry = {
125
125
  #endif
126
126
 
127
127
  static VALUE
128
- rb_fiddle_ptr_new2(VALUE klass, void *ptr, long size, freefunc_t func)
128
+ rb_fiddle_ptr_new2(VALUE klass, void *ptr, long size, freefunc_t func, VALUE wrap0, VALUE wrap1)
129
129
  {
130
130
  struct ptr_data *data;
131
131
  VALUE val;
@@ -135,14 +135,22 @@ rb_fiddle_ptr_new2(VALUE klass, void *ptr, long size, freefunc_t func)
135
135
  data->free = func;
136
136
  data->freed = false;
137
137
  data->size = size;
138
+ data->wrap[0] = wrap0;
139
+ data->wrap[1] = wrap1;
138
140
 
139
141
  return val;
140
142
  }
141
143
 
144
+ VALUE
145
+ rb_fiddle_ptr_new_wrap(void *ptr, long size, freefunc_t func, VALUE wrap0, VALUE wrap1)
146
+ {
147
+ return rb_fiddle_ptr_new2(rb_cPointer, ptr, size, func, wrap0, wrap1);
148
+ }
149
+
142
150
  static VALUE
143
151
  rb_fiddle_ptr_new(void *ptr, long size, freefunc_t func)
144
152
  {
145
- return rb_fiddle_ptr_new2(rb_cPointer, ptr, size, func);
153
+ return rb_fiddle_ptr_new2(rb_cPointer, ptr, size, func, 0, 0);
146
154
  }
147
155
 
148
156
  static VALUE
@@ -152,7 +160,7 @@ rb_fiddle_ptr_malloc(VALUE klass, long size, freefunc_t func)
152
160
 
153
161
  ptr = ruby_xmalloc((size_t)size);
154
162
  memset(ptr,0,(size_t)size);
155
- return rb_fiddle_ptr_new2(klass, ptr, size, func);
163
+ return rb_fiddle_ptr_new2(klass, ptr, size, func, 0, 0);
156
164
  }
157
165
 
158
166
  static void *
@@ -833,7 +841,7 @@ Init_fiddle_pointer(void)
833
841
  rb_define_method(rb_cPointer, "size", rb_fiddle_ptr_size_get, 0);
834
842
  rb_define_method(rb_cPointer, "size=", rb_fiddle_ptr_size_set, 1);
835
843
 
836
- #ifdef FIDDLE_MEMORY_VIEW
844
+ #ifdef HAVE_RUBY_MEMORY_VIEW_H
837
845
  rb_memory_view_register(rb_cPointer, &fiddle_ptr_memory_view_entry);
838
846
  #endif
839
847
 
data/fiddle.gemspec CHANGED
@@ -20,15 +20,12 @@ Gem::Specification.new do |spec|
20
20
  "LICENSE.txt",
21
21
  "README.md",
22
22
  "Rakefile",
23
- "bin/downloader.rb",
24
- "bin/extlibs.rb",
25
23
  "ext/fiddle/closure.c",
26
24
  "ext/fiddle/closure.h",
27
25
  "ext/fiddle/conversions.c",
28
26
  "ext/fiddle/conversions.h",
29
27
  "ext/fiddle/depend",
30
28
  "ext/fiddle/extconf.rb",
31
- "ext/fiddle/extlibs",
32
29
  "ext/fiddle/fiddle.c",
33
30
  "ext/fiddle/fiddle.h",
34
31
  "ext/fiddle/function.c",
@@ -56,11 +53,7 @@ Gem::Specification.new do |spec|
56
53
  spec.require_paths = ["lib"]
57
54
  spec.extensions = ["ext/fiddle/extconf.rb"]
58
55
 
59
- spec.required_ruby_version = ">= 2.3.0"
60
-
61
- spec.add_development_dependency "bundler"
62
- spec.add_development_dependency "rake"
63
- spec.add_development_dependency "rake-compiler"
56
+ spec.required_ruby_version = ">= 2.5.0"
64
57
 
65
58
  spec.metadata["msys2_mingw_dependencies"] = "libffi"
66
59
  end
@@ -1,6 +1,31 @@
1
1
  # frozen_string_literal: true
2
2
  module Fiddle
3
3
  class Closure
4
+ class << self
5
+ # Create a new closure. If a block is given, the created closure
6
+ # is automatically freed after the given block is executed.
7
+ #
8
+ # The all given arguments are passed to Fiddle::Closure.new. So
9
+ # using this method without block equals to Fiddle::Closure.new.
10
+ #
11
+ # == Example
12
+ #
13
+ # Fiddle::Closure.create(TYPE_INT, [TYPE_INT]) do |closure|
14
+ # # closure is freed automatically when this block is finished.
15
+ # end
16
+ def create(*args)
17
+ if block_given?
18
+ closure = new(*args)
19
+ begin
20
+ yield(closure)
21
+ ensure
22
+ closure.free
23
+ end
24
+ else
25
+ new(*args)
26
+ end
27
+ end
28
+ end
4
29
 
5
30
  # the C type of the return of the FFI closure
6
31
  attr_reader :ctype
@@ -164,23 +164,23 @@ module Fiddle
164
164
  unless Fiddle.const_defined?(:TYPE_LONG_LONG)
165
165
  raise(RuntimeError, "unsupported type: #{ty}")
166
166
  end
167
- return -TYPE_LONG_LONG
167
+ return TYPE_ULONG_LONG
168
168
  when /\A(?:signed\s+)?long(?:\s+int\s+)?(?:\s+\w+)?\z/
169
169
  return TYPE_LONG
170
170
  when /\Aunsigned\s+long(?:\s+int\s+)?(?:\s+\w+)?\z/
171
- return -TYPE_LONG
171
+ return TYPE_ULONG
172
172
  when /\A(?:signed\s+)?int(?:\s+\w+)?\z/
173
173
  return TYPE_INT
174
174
  when /\A(?:unsigned\s+int|uint)(?:\s+\w+)?\z/
175
- return -TYPE_INT
175
+ return TYPE_UINT
176
176
  when /\A(?:signed\s+)?short(?:\s+int\s+)?(?:\s+\w+)?\z/
177
177
  return TYPE_SHORT
178
178
  when /\Aunsigned\s+short(?:\s+int\s+)?(?:\s+\w+)?\z/
179
- return -TYPE_SHORT
179
+ return TYPE_USHORT
180
180
  when /\A(?:signed\s+)?char(?:\s+\w+)?\z/
181
181
  return TYPE_CHAR
182
182
  when /\Aunsigned\s+char(?:\s+\w+)?\z/
183
- return -TYPE_CHAR
183
+ return TYPE_UCHAR
184
184
  when /\Aint8_t(?:\s+\w+)?\z/
185
185
  unless Fiddle.const_defined?(:TYPE_INT8_T)
186
186
  raise(RuntimeError, "unsupported type: #{ty}")
@@ -190,7 +190,7 @@ module Fiddle
190
190
  unless Fiddle.const_defined?(:TYPE_INT8_T)
191
191
  raise(RuntimeError, "unsupported type: #{ty}")
192
192
  end
193
- return -TYPE_INT8_T
193
+ return TYPE_UINT8_T
194
194
  when /\Aint16_t(?:\s+\w+)?\z/
195
195
  unless Fiddle.const_defined?(:TYPE_INT16_T)
196
196
  raise(RuntimeError, "unsupported type: #{ty}")
@@ -200,7 +200,7 @@ module Fiddle
200
200
  unless Fiddle.const_defined?(:TYPE_INT16_T)
201
201
  raise(RuntimeError, "unsupported type: #{ty}")
202
202
  end
203
- return -TYPE_INT16_T
203
+ return TYPE_UINT16_T
204
204
  when /\Aint32_t(?:\s+\w+)?\z/
205
205
  unless Fiddle.const_defined?(:TYPE_INT32_T)
206
206
  raise(RuntimeError, "unsupported type: #{ty}")
@@ -210,7 +210,7 @@ module Fiddle
210
210
  unless Fiddle.const_defined?(:TYPE_INT32_T)
211
211
  raise(RuntimeError, "unsupported type: #{ty}")
212
212
  end
213
- return -TYPE_INT32_T
213
+ return TYPE_UINT32_T
214
214
  when /\Aint64_t(?:\s+\w+)?\z/
215
215
  unless Fiddle.const_defined?(:TYPE_INT64_T)
216
216
  raise(RuntimeError, "unsupported type: #{ty}")
@@ -220,7 +220,7 @@ module Fiddle
220
220
  unless Fiddle.const_defined?(:TYPE_INT64_T)
221
221
  raise(RuntimeError, "unsupported type: #{ty}")
222
222
  end
223
- return -TYPE_INT64_T
223
+ return TYPE_UINT64_T
224
224
  when /\Afloat(?:\s+\w+)?\z/
225
225
  return TYPE_FLOAT
226
226
  when /\Adouble(?:\s+\w+)?\z/
data/lib/fiddle/pack.rb CHANGED
@@ -11,24 +11,24 @@ module Fiddle
11
11
  TYPE_LONG => ALIGN_LONG,
12
12
  TYPE_FLOAT => ALIGN_FLOAT,
13
13
  TYPE_DOUBLE => ALIGN_DOUBLE,
14
- -TYPE_CHAR => ALIGN_CHAR,
15
- -TYPE_SHORT => ALIGN_SHORT,
16
- -TYPE_INT => ALIGN_INT,
17
- -TYPE_LONG => ALIGN_LONG,
14
+ TYPE_UCHAR => ALIGN_CHAR,
15
+ TYPE_USHORT => ALIGN_SHORT,
16
+ TYPE_UINT => ALIGN_INT,
17
+ TYPE_ULONG => ALIGN_LONG,
18
18
  }
19
19
 
20
20
  PACK_MAP = {
21
- TYPE_VOIDP => "l!",
21
+ TYPE_VOIDP => "L!",
22
22
  TYPE_CHAR => "c",
23
23
  TYPE_SHORT => "s!",
24
24
  TYPE_INT => "i!",
25
25
  TYPE_LONG => "l!",
26
26
  TYPE_FLOAT => "f",
27
27
  TYPE_DOUBLE => "d",
28
- -TYPE_CHAR => "c",
29
- -TYPE_SHORT => "s!",
30
- -TYPE_INT => "i!",
31
- -TYPE_LONG => "l!",
28
+ TYPE_UCHAR => "C",
29
+ TYPE_USHORT => "S!",
30
+ TYPE_UINT => "I!",
31
+ TYPE_ULONG => "L!",
32
32
  }
33
33
 
34
34
  SIZE_MAP = {
@@ -39,16 +39,17 @@ module Fiddle
39
39
  TYPE_LONG => SIZEOF_LONG,
40
40
  TYPE_FLOAT => SIZEOF_FLOAT,
41
41
  TYPE_DOUBLE => SIZEOF_DOUBLE,
42
- -TYPE_CHAR => SIZEOF_CHAR,
43
- -TYPE_SHORT => SIZEOF_SHORT,
44
- -TYPE_INT => SIZEOF_INT,
45
- -TYPE_LONG => SIZEOF_LONG,
42
+ TYPE_UCHAR => SIZEOF_CHAR,
43
+ TYPE_USHORT => SIZEOF_SHORT,
44
+ TYPE_UINT => SIZEOF_INT,
45
+ TYPE_ULONG => SIZEOF_LONG,
46
46
  }
47
47
  if defined?(TYPE_LONG_LONG)
48
- ALIGN_MAP[TYPE_LONG_LONG] = ALIGN_MAP[-TYPE_LONG_LONG] = ALIGN_LONG_LONG
49
- PACK_MAP[TYPE_LONG_LONG] = PACK_MAP[-TYPE_LONG_LONG] = "q"
50
- SIZE_MAP[TYPE_LONG_LONG] = SIZE_MAP[-TYPE_LONG_LONG] = SIZEOF_LONG_LONG
51
- PACK_MAP[TYPE_VOIDP] = "q" if SIZEOF_LONG_LONG == SIZEOF_VOIDP
48
+ ALIGN_MAP[TYPE_LONG_LONG] = ALIGN_MAP[TYPE_ULONG_LONG] = ALIGN_LONG_LONG
49
+ PACK_MAP[TYPE_LONG_LONG] = "q"
50
+ PACK_MAP[TYPE_ULONG_LONG] = "Q"
51
+ SIZE_MAP[TYPE_LONG_LONG] = SIZE_MAP[TYPE_ULONG_LONG] = SIZEOF_LONG_LONG
52
+ PACK_MAP[TYPE_VOIDP] = "Q" if SIZEOF_LONG_LONG == SIZEOF_VOIDP
52
53
  end
53
54
 
54
55
  def align(addr, align)
data/lib/fiddle/struct.rb CHANGED
@@ -13,6 +13,58 @@ module Fiddle
13
13
  CStructEntity
14
14
  end
15
15
 
16
+ def self.offsetof(name, members, types) # :nodoc:
17
+ offset = 0
18
+ worklist = name.split('.')
19
+ this_type = self
20
+ while search_name = worklist.shift
21
+ index = 0
22
+ member_index = members.index(search_name)
23
+
24
+ unless member_index
25
+ # Possibly a sub-structure
26
+ member_index = members.index { |member_name, _|
27
+ member_name == search_name
28
+ }
29
+ return unless member_index
30
+ end
31
+
32
+ types.each { |type, count = 1|
33
+ orig_offset = offset
34
+ if type.respond_to?(:entity_class)
35
+ align = type.alignment
36
+ type_size = type.size
37
+ else
38
+ align = PackInfo::ALIGN_MAP[type]
39
+ type_size = PackInfo::SIZE_MAP[type]
40
+ end
41
+
42
+ # Unions shouldn't advance the offset
43
+ if this_type.entity_class == CUnionEntity
44
+ type_size = 0
45
+ end
46
+
47
+ offset = PackInfo.align(orig_offset, align)
48
+
49
+ if worklist.empty?
50
+ return offset if index == member_index
51
+ else
52
+ if index == member_index
53
+ subtype = types[member_index]
54
+ members = subtype.members
55
+ types = subtype.types
56
+ this_type = subtype
57
+ break
58
+ end
59
+ end
60
+
61
+ offset += (type_size * count)
62
+ index += 1
63
+ }
64
+ end
65
+ nil
66
+ end
67
+
16
68
  def each
17
69
  return enum_for(__function__) unless block_given?
18
70
 
@@ -75,6 +127,10 @@ module Fiddle
75
127
  def CUnion.entity_class
76
128
  CUnionEntity
77
129
  end
130
+
131
+ def self.offsetof(name, members, types) # :nodoc:
132
+ 0
133
+ end
78
134
  end
79
135
 
80
136
  # Wrapper for arrays within a struct
@@ -172,6 +228,21 @@ module Fiddle
172
228
  define_method(:to_i){ @entity.to_i }
173
229
  define_singleton_method(:types) { types }
174
230
  define_singleton_method(:members) { members }
231
+
232
+ # Return the offset of a struct member given its name.
233
+ # For example:
234
+ #
235
+ # MyStruct = struct [
236
+ # "int64_t i",
237
+ # "char c",
238
+ # ]
239
+ #
240
+ # MyStruct.offsetof("i") # => 0
241
+ # MyStruct.offsetof("c") # => 8
242
+ #
243
+ define_singleton_method(:offsetof) { |name|
244
+ klass.offsetof(name, members, types)
245
+ }
175
246
  members.each{|name|
176
247
  name = name[0] if name.is_a?(Array) # name is a nested struct
177
248
  next if method_defined?(name)
@@ -1,3 +1,3 @@
1
1
  module Fiddle
2
- VERSION = "1.0.9"
2
+ VERSION = "1.1.1"
3
3
  end
data/lib/fiddle.rb CHANGED
@@ -58,7 +58,36 @@ module Fiddle
58
58
  #
59
59
  # See Fiddle::Handle.new for more.
60
60
  def dlopen library
61
- Fiddle::Handle.new library
61
+ begin
62
+ Fiddle::Handle.new(library)
63
+ rescue DLError => error
64
+ case RUBY_PLATFORM
65
+ when /linux/
66
+ case error.message
67
+ when /\A(\/.+?): (?:invalid ELF header|file too short)/
68
+ # This may be a linker script:
69
+ # https://sourceware.org/binutils/docs/ld.html#Scripts
70
+ path = $1
71
+ else
72
+ raise
73
+ end
74
+ else
75
+ raise
76
+ end
77
+
78
+ File.open(path) do |input|
79
+ input.each_line do |line|
80
+ case line
81
+ when /\A\s*(?:INPUT|GROUP)\s*\(\s*([^\s,\)]+)/
82
+ # TODO: Should we support multiple files?
83
+ return dlopen($1)
84
+ end
85
+ end
86
+ end
87
+
88
+ # Not found
89
+ raise
90
+ end
62
91
  end
63
92
  module_function :dlopen
64
93
 
@@ -67,4 +96,8 @@ module Fiddle
67
96
  RTLD_GLOBAL = Handle::RTLD_GLOBAL # :nodoc:
68
97
  RTLD_LAZY = Handle::RTLD_LAZY # :nodoc:
69
98
  RTLD_NOW = Handle::RTLD_NOW # :nodoc:
99
+
100
+ Fiddle::Types.constants.each do |type|
101
+ const_set "TYPE_#{type}", Fiddle::Types.const_get(type)
102
+ end
70
103
  end
metadata CHANGED
@@ -1,58 +1,16 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fiddle
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.9
4
+ version: 1.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aaron Patterson
8
8
  - SHIBATA Hiroshi
9
- autorequire:
9
+ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2021-06-19 00:00:00.000000000 Z
13
- dependencies:
14
- - !ruby/object:Gem::Dependency
15
- name: bundler
16
- requirement: !ruby/object:Gem::Requirement
17
- requirements:
18
- - - ">="
19
- - !ruby/object:Gem::Version
20
- version: '0'
21
- type: :development
22
- prerelease: false
23
- version_requirements: !ruby/object:Gem::Requirement
24
- requirements:
25
- - - ">="
26
- - !ruby/object:Gem::Version
27
- version: '0'
28
- - !ruby/object:Gem::Dependency
29
- name: rake
30
- requirement: !ruby/object:Gem::Requirement
31
- requirements:
32
- - - ">="
33
- - !ruby/object:Gem::Version
34
- version: '0'
35
- type: :development
36
- prerelease: false
37
- version_requirements: !ruby/object:Gem::Requirement
38
- requirements:
39
- - - ">="
40
- - !ruby/object:Gem::Version
41
- version: '0'
42
- - !ruby/object:Gem::Dependency
43
- name: rake-compiler
44
- requirement: !ruby/object:Gem::Requirement
45
- requirements:
46
- - - ">="
47
- - !ruby/object:Gem::Version
48
- version: '0'
49
- type: :development
50
- prerelease: false
51
- version_requirements: !ruby/object:Gem::Requirement
52
- requirements:
53
- - - ">="
54
- - !ruby/object:Gem::Version
55
- version: '0'
12
+ date: 2022-12-08 00:00:00.000000000 Z
13
+ dependencies: []
56
14
  description: A libffi wrapper for Ruby.
57
15
  email:
58
16
  - aaron@tenderlovemaking.com
@@ -65,15 +23,12 @@ files:
65
23
  - LICENSE.txt
66
24
  - README.md
67
25
  - Rakefile
68
- - bin/downloader.rb
69
- - bin/extlibs.rb
70
26
  - ext/fiddle/closure.c
71
27
  - ext/fiddle/closure.h
72
28
  - ext/fiddle/conversions.c
73
29
  - ext/fiddle/conversions.h
74
30
  - ext/fiddle/depend
75
31
  - ext/fiddle/extconf.rb
76
- - ext/fiddle/extlibs
77
32
  - ext/fiddle/fiddle.c
78
33
  - ext/fiddle/fiddle.h
79
34
  - ext/fiddle/function.c
@@ -103,7 +58,7 @@ licenses:
103
58
  - BSD-2-Clause
104
59
  metadata:
105
60
  msys2_mingw_dependencies: libffi
106
- post_install_message:
61
+ post_install_message:
107
62
  rdoc_options: []
108
63
  require_paths:
109
64
  - lib
@@ -111,15 +66,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
111
66
  requirements:
112
67
  - - ">="
113
68
  - !ruby/object:Gem::Version
114
- version: 2.3.0
69
+ version: 2.5.0
115
70
  required_rubygems_version: !ruby/object:Gem::Requirement
116
71
  requirements:
117
72
  - - ">="
118
73
  - !ruby/object:Gem::Version
119
74
  version: '0'
120
75
  requirements: []
121
- rubygems_version: 3.3.0.dev
122
- signing_key:
76
+ rubygems_version: 3.4.0.dev
77
+ signing_key:
123
78
  specification_version: 4
124
79
  summary: A libffi wrapper for Ruby.
125
80
  test_files: []