[cairo-commit] rcairo/gen gen.rb,NONE,1.1 gen_api_sig.rb,NONE,1.1 load_api.rb,NONE,1.1
Evan Martin
commit at pdx.freedesktop.org
Tue Oct 28 10:27:24 PST 2003
- Previous message: [cairo-commit] rcairo/tests - New directory
- Next message: [cairo-commit] rcairo/src cairo.c,NONE,1.1 extconf.rb,NONE,1.1 image.c,NONE,1.1 shared.h,NONE,1.1 xlib.c,NONE,1.1
- Messages sorted by:
[ date ]
[ thread ]
[ subject ]
[ author ]
Committed by: martine
Update of /cvs/cairo/rcairo/gen
In directory pdx:/tmp/cvs-serv31046/gen
Added Files:
gen.rb gen_api_sig.rb load_api.rb
Log Message:
Initial import of Ruby/Cairo.
I just moved the code around a bit in anticipation of wanting to do it later,
and I haven't tested if it broke anything yet, so don't be surprised if it
doesn't quite build yet.
--- NEW FILE: gen.rb ---
#!/usr/bin/env ruby
# ruby-cairo - Ruby bindings for Cairo.
# Copyright (C) 2003 Evan Martin <martine at danga.com>
#
# vim: tabstop=4 shiftwidth=4 noexpandtab :
require 'load_api'
$funcs, $structs, enums = load_api(ARGV[0])
$enums = {}
enums.each { |type, defs|
$enums[type] = defs
}
structs_to_r = {
'cairo_t *' => "Cairo",
'cairo_surface_t *' => "Surface",
'cairo_matrix_t *' => "Matrix",
}
special = {}
[
# functions handled by ruby objects
'cairo_create',
'cairo_reference',
'cairo_destroy',
'cairo_copy',
'cairo_set_target_image', # need special Cairo::Image class
'cairo_set_dash', # takes an array of dashes via double* ?
# take points and modify them directly
'cairo_transform_point',
'cairo_transform_distance',
'cairo_inverse_transform_point',
'cairo_inverse_transform_distance',
'cairo_stroke', # special-cased so you can pass blocks.
'cairo_fill',
'cairo_text_extents', # get a whole bunch of attributes
'cairo_current_rgb_color', # returns a color triple
# surfaces
'cairo_surface_create_for_image',
'cairo_surface_create_similar',
'cairo_surface_create_similar_solid',
'cairo_surface_reference',
'cairo_surface_destroy',
'cairo_surface_get_matrix',
# matrices
'cairo_matrix_create',
'cairo_matrix_destroy',
'cairo_matrix_copy',
].each { |func| special[func] = 1 }
def r_from_c(type)
map = {
'const char *' => 'rb_str_new2',
'double' => 'rb_float_new',
'cairo_surface_t *' => 'rsurface_new_from',
}
return map[type] if map.has_key? type
return 'INT2FIX' if $enums.has_key? type
return nil
end
def c_from_r(arg)
c_from_r = {
'cairo_matrix_t *' => 'rmatrix_get_matrix',
'cairo_surface_t *' => 'rsurface_get_surface',
'double' => 'NUM2DBL',
'const char *' => 'STR2CSTR',
'const unsigned char *' => 'STR2CSTR',
'int' => 'FIX2INT'
}
return c_from_r[arg] if c_from_r.has_key? arg
return 'NUM2INT' if $enums.has_key? arg
return nil
end
class GMethod
attr_accessor :cname, :name, :ret, :args
def initialize(cname, name, ret, args)
@cname = cname; @name = name; @ret = ret; @args = args
end
def header
"static VALUE\nr#{@cname}(VALUE self" + \
@args.map { |type, name| ", VALUE #{name}" }.join("") + ") {"
end
def args_to_c
if @args
@args.map { |type, name|
", #{c_from_r(type)}(#{name})"
}.join("")
else
""
end
end
end
def mappable_args(args)
args.each { |type, name|
unless c_from_r(type)
dputs "don't know how to automatically handle #{type}"
return false
end
}
return true
end
class GClass
attr_accessor :name, :setters, :getters, :methods
def initialize(name, cname, ctype)
@name = name
@rname = name.gsub(/^Cairo(.+)/) { $1 }
@cname = cname
@ctype = ctype
@setters = []
@getters = []
@methods = []
end
def unwrap_str
"r#{@cname}_get_#{@cname}(self)"
end
def out_setters(out)
@setters.each { |m|
out << m.header + "\n"
out << "\t#{m.cname}(#{unwrap_str}" + m.args_to_c + ");\n"
out << "\treturn Qnil;\n"
out << "}\n"
}
end
def out_getters(out)
@getters.each { |m|
out << m.header + "\n"
ret = r_from_c(m.ret) || 'XXX'
out << "\treturn #{ret}(#{m.cname}(#{unwrap_str}));\n"
out << "}\n"
}
end
def out_methods(out)
@methods.each { |m|
out << m.header + "\n"
out << "\t#{m.cname}(#{unwrap_str}" + m.args_to_c + ");\n"
out << "\treturn Qnil;\n"
out << "}\n"
}
end
def out_defs(out)
out << "\tc#{@name} = rb_define_class_under(mCairo, \"#{@rname}\", rb_cObject);\n"
@methods.each { |m|
out << "\trb_define_method(c#{@name}, \"#{m.name}\", r#{m.cname}, #{m.args.length});\n"
}
@setters.each { |m|
out << "\trb_define_method(c#{@name}, \"set_#{m.name}\", r#{m.cname}, #{m.args.length});\n"
if m.args.length == 1
out << "\trb_define_method(c#{@name}, \"#{m.name}=\", r#{m.cname}, #{m.args.length});\n"
end
}
@getters.each { |m|
out << "\trb_define_method(c#{@name}, \"#{m.name}\", r#{m.cname}, 0);\n"
}
end
def add_method(m)
return false unless m.args[0][0] == @ctype and # methods must operate on this, and
(m.args.length < 2 or mappable_args(m.args[1..-1])) # we must know how to handle args
type, subname = $1, $2 if m.name =~ /(.+?)_(.+)/
m.args.shift
if m.ret and c_from_r(m.ret) and m.args.length == 0
m.name = subname if type == 'get' or type == 'current'
@getters << m
elsif type == 'set'
m.name = subname
@setters << m
elsif not m.ret
@methods << m
else
return false
end
return true
end
def write(out)
p out
out << '/* ruby-cairo - Ruby bindings for Cairo.
* Copyright (C) 2003 Evan Martin <martine at danga.com>
*
* vim: tabstop=4 shiftwidth=4 noexpandtab :
*/
/* this file was autogenerated by gen.rb, available in the ruby-cairo cvs. */
#include "shared.h"'
EOT
out_setters(out)
out << "\n"
out_getters(out)
out << "\n"
out_methods(out)
out << "\n"
out << "VALUE gen_#{@name}(void) {\n"
out_defs(out)
out << "\treturn c#{@name};\n"
out << "}\n"
end
end
$classes = {
'Cairo' => GClass.new("Cairo", 'cairo', 'cairo_t *'),
'Surface' => GClass.new("CairoSurface", 'surface', 'cairo_surface_t *'),
'Matrix' => GClass.new("CairoMatrix", 'matrix', 'cairo_matrix_t *'),
}
def dputs(*args)
$stdout.puts(*args)
end
$funcs.each { |func, ret, args|
if special.has_key? func
dputs "* #{func} is marked for special handling"
next
end
added = case func
when /cairo_matrix_(\w+)/
$classes['Matrix'].add_method(GMethod.new(func, $1, ret, args))
when /cairo_surface_(\w+)/
$classes['Surface'].add_method(GMethod.new(func, $1, ret, args))
when /cairo_(\w+)/
$classes['Cairo'].add_method(GMethod.new(func, $1, ret, args))
else
false
end
if added
dputs "* #{func}"
else
dputs " -> don't know what to do with #{func}"
end
}
$classes.each_value { |c|
File.open("../src/gen-#{c.name}.c", "w") { |f|
c.write(f)
}
}
--- NEW FILE: gen_api_sig.rb ---
#!/usr/bin/env ruby
# vim: set ts=2 sw=2 et :
require 'load_api'
funcs, structs, enums = load_api(ARGV[0])
funcs.each { |func, ret, args|
if args
argstr = args.map { |type, name| "#{name} : #{type}" }.join(', ')
else
argstr = ""
end
retstr = " : #{ret}" if ret
puts "#{func} (#{argstr})#{retstr}"
}
puts
structs.each { |type|
puts "#{type}"
}
puts
enums.each { |type, vals|
puts "#{type}:"
vals.each { |v|
puts " #{v}"
}
}
puts
--- NEW FILE: load_api.rb ---
#!/usr/bin/env ruby
# vim: set ts=2 sw=2 et :
def load_api(fn)
funcs = []
structs = []
enums = []
file = File.open(fn).read
file.gsub!(/\/\*.*?\*\//m, '')
file.gsub!(/^#.*?\n/, '')
file.gsub!(/^extern "C" \{\s*/, '')
file.gsub!(/\}\s*$/, '')
file.gsub!(/\n\n/, "\n")
file.gsub!(/^\s*/, "")
file.split(/;\s*/).each { |decl|
decl.gsub!(/\n/, " ")
decl.gsub!(/\s+/, " ")
case decl
when /^extern (.+?) (?:__external_linkage) (\w+) \((.+?)\)$/
ret, func, args = $1, $2, $3.strip
ret = nil if ret == 'void'
if args == 'void'
args = nil
else
args = args.split(/\s*,\s*/).map { |arg|
arg.gsub!(/\s+/, ' ')
if arg == 'void'
nil
elsif arg =~ /^(.+?)\s*(\w+)$/
[$1, $2]
else
raise ArgumentError # just some error.
end
}
end
#puts "-->func<-- #{ret} :: #{func} :: #{args.inspect}"
funcs << [func, ret, args]
when /^typedef struct (.*?) (\w+)$/
decl, type = $1, $2
#puts "-->type<-- #{type}"
structs << type
when /^typedef enum (.*?) \{(.*?)\} (\w+)$/
tag, content, type = $1, $2, $3
defs = content.split(/,\s*/).map { |value|
value.gsub!(/^\s*(\w+).*?$/) { $1 }
}
#puts "-->type<-- #{type} [#{defs.join(':')}]"
enums << [type, defs]
else
puts "-->err<-- #{decl}"
end
}
[funcs, structs, enums]
end
- Previous message: [cairo-commit] rcairo/tests - New directory
- Next message: [cairo-commit] rcairo/src cairo.c,NONE,1.1 extconf.rb,NONE,1.1 image.c,NONE,1.1 shared.h,NONE,1.1 xlib.c,NONE,1.1
- Messages sorted by:
[ date ]
[ thread ]
[ subject ]
[ author ]
More information about the cairo-commit
mailing list