Module: Fiddle::Importer

Included in:
LibUI::FFI
Defined in:
lib/libui/ffi.rb

Instance Method Summary collapse

Instance Method Details

#extern(signature, *opts) ⇒ Object



42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/libui/ffi.rb', line 42

def extern(signature, *opts)
  symname, ctype, argtype, callback_argument_types = parse_signature(signature, type_alias)
  opt = parse_bind_options(opts)
  func = import_function(symname, ctype, argtype, opt[:call_type])

  func.callback_argument_types = callback_argument_types                    # Added
  # Ruby 2.7 Fiddle::Function dose not have @argument_types
  # Ruby 3.0 Fiddle::Function has @argument_types
  func.argument_types = argtype

  name = symname.gsub(/@.+/, '')
  @func_map[name] = func
  # define_method(name){|*args,&block| f.call(*args,&block)}
  begin
    /^(.+?):(\d+)/ =~ caller.first
    file = Regexp.last_match(1)
    line = Regexp.last_match(2).to_i
  rescue StandardError
    file, line = __FILE__, __LINE__ + 3
  end
  module_eval(<<-EOS, file, line)
    def #{name}(*args, &block)
      @func_map['#{name}'].call(*args,&block)
    end
  EOS
  module_function(name)
  func
end

#parse_signature(signature, tymap = nil) ⇒ Object



15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/libui/ffi.rb', line 15

def parse_signature(signature, tymap = nil)
  tymap ||= {}
  ctype, func, args = case compact(signature)
                      when /^(?:[\w\*\s]+)\(\*(\w+)\((.*?)\)\)(?:\[\w*\]|\(.*?\));?$/
                        [TYPE_VOIDP, Regexp.last_match(1), Regexp.last_match(2)]
                      when /^([\w\*\s]+[*\s])(\w+)\((.*?)\);?$/
                        [parse_ctype(Regexp.last_match(1).strip, tymap), Regexp.last_match(2), Regexp.last_match(3)]
                      else
                        raise("can't parserake the function prototype: #{signature}")
                      end
  symname = func
  callback_argument_types = {}                                              # Added
  argtype = split_arguments(args).collect.with_index do |arg, idx|          # Added with_index
    # Check if it is a function pointer or not
    if arg =~ /\(\*.*\)\(.*\)/                                              # Added
      # From the arguments, create a notation that looks like a function declaration
      # int(*f)(int *, void *) -> int f(int *, void *)
      func_arg = arg.sub('(*', ' ').sub(')', '')                            # Added
      # Use Fiddle's parse_signature method again.
      callback_argument_types[idx] = parse_signature(func_arg)              # Added
    end
    parse_ctype(arg, tymap)
  end
  # Added callback_argument_types. Original method return only 3 values.
  [symname, ctype, argtype, callback_argument_types]
end