ghazel-ffi_gen 1.3.9.1 → 1.3.9.2

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8a0d67dc3a56cc1b5a4d73a74f89316005b61f70
4
- data.tar.gz: c5b89dbc227b3bc2c6bb597368419e301aee368d
3
+ metadata.gz: e74a49ab6949c362c786be977bee1502716b0a41
4
+ data.tar.gz: c17d96a9b1c0b418dd1daece53e5ca39d0626a9c
5
5
  SHA512:
6
- metadata.gz: ac7353f0a2543473fb4e299c2291614cd0e8b62e01961295ea3a9c7e4281e75a8712b51430231115dddb8ee270e952d25b391d2940f596aa6e504a561aa6bbc2
7
- data.tar.gz: 8745ddb1d5b14852e96d91b361098ed4ab1321104121df97d0770c19875a9d04a9fb1a80f8a4ddea300ab655f56912888f535a13d8463e302ab9717581c7b77c
6
+ metadata.gz: 0a221f2f05ffb6c4b47286805d7d874e7b67129ffaeecc98402c089ca531b4ed4fb0e2ac3eb50442f16334199d25259de148090ec529ae9d70b46b9b2fa7fb74
7
+ data.tar.gz: eda187d248897255b28b2769258b9bf3f00d0e2a5805662c2163578d87ea3bcede5b792fe8ac6a7dc31b482764ccc71f0b34512e3dd3e05bf3bd603b84dbd085
data/lib/ffi_gen.rb CHANGED
@@ -204,8 +204,9 @@ class FFIGen
204
204
  end
205
205
 
206
206
  class PrimitiveType < Type
207
- def initialize(clang_type)
207
+ def initialize(clang_type, full_type)
208
208
  @clang_type = clang_type
209
+ @full_type = full_type
209
210
  end
210
211
 
211
212
  def name
@@ -219,7 +220,21 @@ class FFIGen
219
220
  end
220
221
  end
221
222
 
223
+ class ByReferenceType < Type
224
+ attr_accessor :inner_type
225
+
226
+ def initialize(inner_type)
227
+ @inner_type = inner_type
228
+ end
229
+
230
+ def name
231
+ @inner_type.name
232
+ end
233
+ end
234
+
222
235
  class ByValueType < Type
236
+ attr_accessor :inner_type
237
+
223
238
  def initialize(inner_type)
224
239
  @inner_type = inner_type
225
240
  end
@@ -415,7 +430,8 @@ class FFIGen
415
430
  Enum.new self, name, constants, enum_description
416
431
 
417
432
  when :struct_decl, :union_decl
418
- struct = @declarations_by_type[Clang.get_cursor_type(declaration_cursor)] || StructOrUnion.new(self, name, (declaration_cursor[:kind] == :union_decl))
433
+ @declarations_by_type[Clang.get_cursor_type(declaration_cursor)] ||= StructOrUnion.new(self, name, (declaration_cursor[:kind] == :union_decl))
434
+ struct = @declarations_by_type[Clang.get_cursor_type(declaration_cursor)]
419
435
  raise if not struct.fields.empty?
420
436
  struct.description.concat comment
421
437
 
@@ -514,16 +530,58 @@ class FFIGen
514
530
  typedef_children = Clang.get_children declaration_cursor
515
531
  underlying = Clang.get_typedef_decl_underlying_type(declaration_cursor)
516
532
  function_proto = Clang.get_canonical_type(Clang.get_pointee_type(underlying))
517
- if function_proto[:kind] == :function_proto
533
+ if function_proto[:kind] == :function_proto || function_proto[:kind] == :function_no_proto
534
+
535
+ function_description = []
536
+ return_value_description = []
537
+ parameter_descriptions = {}
538
+ current_description = function_description
539
+ comment.each do |line|
540
+ if line.gsub!(/\\param (.*?) /, '')
541
+ current_description = []
542
+ parameter_descriptions[$1] = current_description
543
+ end
544
+ current_description = return_value_description if line.gsub! '\\returns ', ''
545
+ current_description << line
546
+ end
547
+
518
548
  return_type = resolve_type Clang.get_result_type(function_proto)
519
549
  parameters = []
520
- Clang.get_num_arg_types(function_proto).times do |i|
521
- param_type = resolve_type Clang.get_arg_type(function_proto, i)
522
- # XXX: TODO: get arg name, somehow
523
- param_name = Name.new ['arg', i.to_s]
524
- parameters << { name:param_name, type: param_type, description: [] }
550
+ Clang.get_children(declaration_cursor).each do |function_child|
551
+ next if function_child[:kind] != :parm_decl
552
+ param_name = read_name function_child
553
+ tokens = Clang.get_tokens translation_unit, Clang.get_cursor_extent(function_child)
554
+ is_array = tokens.any? { |t| Clang.get_token_spelling(translation_unit, t).to_s_and_dispose == "[" }
555
+ param_type = resolve_type Clang.get_cursor_type(function_child), is_array
556
+ param_name ||= param_type.name
557
+ param_name ||= Name.new []
558
+ first_parameter_type ||= Clang.get_cursor_type function_child
559
+ parameters << { name: param_name, type: param_type }
525
560
  end
526
- FunctionOrCallback.new self, name, parameters, return_type, true, false, comment, []
561
+
562
+ parameters.each_with_index do |parameter, index|
563
+ parameter[:description] = parameter[:name] && parameter_descriptions[parameter[:name].raw]
564
+ parameter[:description] ||= parameter_descriptions.values[index] if parameter_descriptions.size == parameters.size # workaround for wrong names
565
+ parameter[:description] ||= []
566
+ end
567
+
568
+ function = FunctionOrCallback.new self, name, parameters, return_type, true, false, function_description, return_value_description
569
+
570
+ pointee_declaration = first_parameter_type && get_pointee_declaration(first_parameter_type)
571
+ if pointee_declaration
572
+ type_prefix = pointee_declaration.name.parts.join.downcase
573
+ function_name_parts = name.parts.dup
574
+ while type_prefix.start_with? function_name_parts.first.downcase
575
+ type_prefix = type_prefix[function_name_parts.first.size..-1]
576
+ function_name_parts.shift
577
+ break if function_name_parts.empty?
578
+ end
579
+ if type_prefix.empty?
580
+ pointee_declaration.oo_functions << [Name.new(function_name_parts), function]
581
+ end
582
+ end
583
+
584
+ function
527
585
  elsif typedef_children.size == 1
528
586
  child_declaration = @declarations_by_type[Clang.get_cursor_type(typedef_children.first)]
529
587
  child_declaration.name = name if child_declaration and child_declaration.name.nil?
@@ -653,7 +711,7 @@ class FFIGen
653
711
  canonical_type = Clang.get_canonical_type full_type
654
712
  data_array = case canonical_type[:kind]
655
713
  when :void, :bool, :u_char, :u_short, :u_int, :u_long, :u_long_long, :char_s, :s_char, :short, :int, :long, :long_long, :float, :double
656
- PrimitiveType.new canonical_type[:kind]
714
+ PrimitiveType.new canonical_type[:kind], Clang.get_type_spelling(full_type).to_s_and_dispose
657
715
  when :pointer
658
716
  if is_array
659
717
  ArrayType.new resolve_type(Clang.get_pointee_type(canonical_type)), nil
@@ -663,8 +721,9 @@ class FFIGen
663
721
  when :char_s
664
722
  StringType.new
665
723
  when :record
666
- @declarations_by_type[Clang.get_cursor_type(Clang.get_type_declaration(pointee_type))]
667
- when :function_proto
724
+ type = @declarations_by_type[Clang.get_cursor_type(Clang.get_type_declaration(pointee_type))]
725
+ type &&= ByReferenceType.new(type)
726
+ when :function_proto, :function_no_proto
668
727
  @declarations_by_type[full_type]
669
728
  else
670
729
  nil
data/lib/ffi_gen/clang.rb CHANGED
@@ -4,7 +4,7 @@ require 'ffi'
4
4
 
5
5
  module FFIGen::Clang
6
6
  extend FFI::Library
7
- ffi_lib ["libclang-3.5.so.1", "libclang.so.1", "clang"]
7
+ ffi_lib ["libclang-3.5.so.1", "libclang.so.1", "clang", '/usr/local/lib/libclang.dylib']
8
8
 
9
9
  def self.attach_function(name, *_)
10
10
  begin; super; rescue FFI::NotFoundError => e
@@ -15,7 +15,7 @@ class FFIGen
15
15
  end
16
16
  writer.puts ""
17
17
 
18
- writer.puts "private interface #{@module_name}Interface extends Library {"
18
+ writer.puts "interface #{@module_name}Interface extends Library {"
19
19
  writer.indent do
20
20
  writer.puts "", *IO.readlines(File.join(File.dirname(__FILE__), "java_interface.java")).map(&:rstrip), ""
21
21
  writer.puts "static class JnaInstanceCreator {"
@@ -120,22 +120,34 @@ class FFIGen
120
120
  writer.puts "public static class #{java_name} extends #{@is_union ? 'Union' : (@fields.empty? ? 'PointerType' : 'Structure')} {"
121
121
  writer.indent do
122
122
  @fields.each do |field|
123
- writer.puts "public #{field[:type].java_jna_type} #{field[:name].raw};"
123
+ if field[:type].is_a? ByReferenceType and not field[:type].inner_type.fields.empty?
124
+ writer.puts "public volatile #{field[:type].java_jna_type}.ByReference #{field[:name].to_java_downcase};"
125
+ else
126
+ writer.puts "public volatile #{field[:type].java_jna_type} #{field[:name].to_java_downcase};"
127
+ end
124
128
  end
125
129
  writer.puts "// hidden structure" if @fields.empty?
126
- end
127
- writer.indent do
128
- writer.puts "public static class ByValue extends #{java_name} implements Structure.ByValue {}"
130
+
129
131
  writer.puts "protected List<String> getFieldOrder() {"
130
132
  writer.indent do
131
- fs = @fields.map{|f| '"' + f[:name].raw + '"'}.join(", ")
133
+ fs = @fields.map{|f| '"' + f[:name].to_java_downcase + '"'}.join(", ")
132
134
  writer.puts "return Arrays.asList(new String[] { #{fs} } );"
133
135
  end
134
136
  writer.puts "}"
137
+
138
+ if not @fields.empty?
139
+ writer.puts "public static class ByValue extends #{java_name} implements Structure.ByValue {}"
140
+ writer.puts "public static class ByReference extends #{java_name} implements Structure.ByReference {"
141
+ writer.indent do
142
+ writer.puts "public ByReference() { }"
143
+ writer.puts "public ByReference(Pointer p) { super(p); read(); }"
144
+ end
145
+ writer.puts "}"
146
+ writer.puts "public #{java_name}() { }"
147
+ writer.puts "public #{java_name}(Pointer p) { super(p); read(); }"
148
+ end
135
149
  end
136
150
  writer.puts "}", ""
137
-
138
- @written = true
139
151
  end
140
152
 
141
153
  def java_name
@@ -143,11 +155,11 @@ class FFIGen
143
155
  end
144
156
 
145
157
  def java_jna_type
146
- @written ? java_name : "Pointer"
158
+ java_name
147
159
  end
148
160
 
149
161
  def java_description
150
- @written ? java_name : "FFI::Pointer(*#{java_name})"
162
+ java_name
151
163
  end
152
164
  end
153
165
 
@@ -157,14 +169,14 @@ class FFIGen
157
169
  writer.puts "public static interface #{java_name.split('.').last} extends Callback {"
158
170
  writer.indent do
159
171
  jna_signature = "#{@parameters.map{ |parameter| "#{parameter[:type].java_jna_type} #{parameter[:name].to_java_downcase}" }.join(', ')}"
160
- writer.puts "#{@return_type.java_jna_type} invoke(#{jna_signature});"
172
+ writer.puts "#{java_jna_return_type} invoke(#{jna_signature});"
161
173
  end
162
174
  writer.puts "}", ""
163
175
  return
164
176
  end
165
177
 
166
178
  jna_signature = "#{@parameters.map{ |parameter| "#{parameter[:type].java_jna_type} #{parameter[:name].to_java_downcase}" }.join(', ')}"
167
- writer.puts "@NativeName(\"#{@name.raw}\")", "#{@return_type.java_jna_type} #{java_name}(#{jna_signature});", ""
179
+ writer.puts "@NativeName(\"#{@name.raw}\")", "#{java_jna_return_type} #{java_name}(#{jna_signature});", ""
168
180
  end
169
181
 
170
182
  def write_static_java(writer)
@@ -174,10 +186,10 @@ class FFIGen
174
186
  parameters = []
175
187
  lp = nil
176
188
  @parameters.each do |p|
177
- if lp && lp[:type].is_a?(PointerType) && lp[:type].pointee_type.respond_to?(:clang_type) && lp[:type].pointee_type.clang_type == :u_char && p[:type].clang_type == :u_long
189
+ if lp and lp[:type].is_a?(PointerType) and lp[:type].pointee_type.respond_to?(:clang_type) and lp[:type].pointee_type.clang_type == :u_char and [:u_long, :u_long_long].include?(p[:type].clang_type)
178
190
  n = lp[:name].to_java_downcase
179
191
  replace[n] = "bytesToPointer(#{n})"
180
- replace[p[:name].to_java_downcase] = "new NativeLong(#{n}.length)";
192
+ replace[p[:name].to_java_downcase] = "#{n}.length";
181
193
  d = lp.dup
182
194
  d[:type] = ArrayType.new(lp[:type].pointee_type, nil)
183
195
  parameters << d
@@ -209,7 +221,7 @@ class FFIGen
209
221
  replace[n] || n
210
222
  }.join(', ')
211
223
  jna_signature = "#{parameters.map{ |parameter| "#{parameter[:type].java_jna_type} #{parameter[:name].to_java_downcase}" }.join(', ')}"
212
- writer.puts "public static #{@return_type.java_jna_type} #{java_name}(#{jna_signature}) {"
224
+ writer.puts "public static #{java_jna_return_type} #{java_name}(#{jna_signature}) {"
213
225
  writer.indent do
214
226
  call = "INSTANCE.#{java_name}(#{args});"
215
227
  if @return_type.respond_to? :clang_type and @return_type.clang_type == :void
@@ -230,6 +242,13 @@ class FFIGen
230
242
  java_name
231
243
  end
232
244
 
245
+ def java_jna_return_type
246
+ if @return_type.is_a? ByReferenceType and not @return_type.inner_type.fields.empty?
247
+ return "#{@return_type.java_jna_type}.ByReference"
248
+ end
249
+ @return_type.java_jna_type
250
+ end
251
+
233
252
  def java_description
234
253
  "Proc(_callback_#{java_name}_)"
235
254
  end
@@ -260,6 +279,9 @@ class FFIGen
260
279
  attr_accessor :clang_type
261
280
 
262
281
  def java_name
282
+ if @full_type == 'boolean'
283
+ return 'Boolean'
284
+ end
263
285
  case @clang_type
264
286
  when :void
265
287
  "nil"
@@ -273,6 +295,9 @@ class FFIGen
273
295
  end
274
296
 
275
297
  def java_jna_type
298
+ if @full_type == 'boolean'
299
+ return 'boolean'
300
+ end
276
301
  case @clang_type
277
302
  when :void then "void"
278
303
  when :bool then "boolean"
@@ -302,13 +327,23 @@ class FFIGen
302
327
  end
303
328
  end
304
329
 
330
+ class ByReferenceType
331
+ def java_name
332
+ @inner_type.java_name
333
+ end
334
+
335
+ def java_jna_type
336
+ @inner_type.java_jna_type
337
+ end
338
+ end
339
+
305
340
  class ByValueType
306
341
  def java_name
307
342
  @inner_type.java_name
308
343
  end
309
344
 
310
345
  def java_jna_type
311
- @inner_type.java_jna_type
346
+ "#{@inner_type.java_jna_type}.ByValue"
312
347
  end
313
348
  end
314
349
 
@@ -3,7 +3,14 @@ interface NativeEnum {
3
3
  }
4
4
 
5
5
  static Pointer bytesToPointer(byte[] b) {
6
+ if (b.length == 0) {
7
+ return null;
8
+ }
6
9
  Pointer p = new Memory(b.length);
7
10
  p.write(0, b, 0, b.length);
8
11
  return p;
9
12
  }
13
+
14
+ static byte[] pointerToBytes(Pointer p, long length) {
15
+ return p.getByteArray(0, (int)length);
16
+ }
@@ -109,7 +109,7 @@ class FFIGen
109
109
  end
110
110
  writer.puts "def #{name.to_ruby_downcase}(#{parameter_names.join(', ')})"
111
111
  writer.indent do
112
- cast = function.return_type.is_a?(StructOrUnion) ? "#{function.return_type.ruby_name}.new " : ""
112
+ cast = function.ruby_ffi_return_type.is_a?(StructOrUnion) ? "#{function.return_type.ruby_name}.new " : ""
113
113
  writer.puts "#{cast}#{@generator.module_name}.#{function.ruby_name}(#{(["self"] + parameter_names).join(', ')})"
114
114
  end
115
115
  writer.puts "end"
@@ -169,6 +169,13 @@ class FFIGen
169
169
  @ruby_name ||= @name.to_ruby_downcase
170
170
  end
171
171
 
172
+ def ruby_ffi_return_type
173
+ if @return_type.is_a? ByReferenceType and not @return_type.inner_type.fields.empty?
174
+ return @return_type.inner_type
175
+ end
176
+ @return_type
177
+ end
178
+
172
179
  def ruby_ffi_type
173
180
  ":#{ruby_name}"
174
181
  end
@@ -247,6 +254,16 @@ class FFIGen
247
254
  end
248
255
  end
249
256
 
257
+ class ByReferenceType
258
+ def ruby_name
259
+ @inner_type.ruby_name
260
+ end
261
+
262
+ def ruby_ffi_type
263
+ @inner_type.ruby_ffi_type
264
+ end
265
+ end
266
+
250
267
  class ByValueType
251
268
  def ruby_name
252
269
  @inner_type.ruby_name
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ghazel-ffi_gen
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.9.1
4
+ version: 1.3.9.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Richard Musiol