Skip to content

Instantly share code, notes, and snippets.

@dougm
Created August 24, 2011 04:26
Show Gist options
  • Save dougm/1167312 to your computer and use it in GitHub Desktop.
Save dougm/1167312 to your computer and use it in GitHub Desktop.
#only dealing with opaque types here; no struct gen
require 'cast'
CallbackTypes = {}
def ffi_type(t)
if t.Pointer?
if t.type.Char?
:string
elsif t.type.CustomType? and CallbackTypes[t.type.name]
t.type.name
else
:pointer
end
elsif t.Char?
:string
elsif t.CustomType? and t.name == "Bool"
:bool
else
t
end
end
header = ARGV[0]
libname = ARGV[1] || File.basename(header.gsub(".h", ""))
code = IO.popen("cpp #{header}").readlines.select { |line| not line.match(/^#/) }
tree = C::Parser.new.parse(code)
indent = " " * 4
ffi = { :functions => [], :enums => [], :constants => [] }
tree.entities.select {|n| n.Declaration? }.each do |node|
if node.type.Enum?
if typedef_node = [node, node.prev].select { |n| n.typedef? }.first
name = typedef_node.declarators.first.name
ffi[:enums] << "#{indent}enum :#{name}, ["
node.type.members.each do |enum|
e = "#{indent} :#{enum.name},"
e << " #{enum.val}," unless enum.val.nil?
ffi[:enums] << e
end
ffi[:enums] << "#{indent}]"
else
node.type.members.each do |enum|
ffi[:constants] << "#{indent}#{enum.name} = #{enum.val}"
end
end
elsif node.typedef?
node.declarators.each do |decl|
CallbackTypes[decl.name] = true if decl.type.Function?
end
else
node.declarators.each do |decl|
if decl.type.Function?
params = decl.type.params.collect { |p| ":#{ffi_type(p.type)}" }
if decl.type.var_args?
params << ':varargs'
end
ffi[:functions] << "#{indent}attach_function :#{decl.name}, [#{params.join(", ")}], :#{ffi_type(node.type)}"
end
end
end
end
ffi.each do |name,code|
#... echo code > name.rb
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment