/test-unit/ruby/1.9.1/gems/ffi-1.0.9-x86-mingw32/lib/ffi/tools/const_generator.rb

https://github.com/nrpathak/liveapp · Ruby · 177 lines · 119 code · 36 blank · 22 comment · 9 complexity · 1d2ef530950fd2590d14e796271f2343 MD5 · raw file

  1. require 'tempfile'
  2. require 'open3'
  3. module FFI
  4. ##
  5. # ConstGenerator turns C constants into ruby values.
  6. class ConstGenerator
  7. @options = {}
  8. attr_reader :constants
  9. ##
  10. # Creates a new constant generator that uses +prefix+ as a name, and an
  11. # options hash.
  12. #
  13. # The only option is :required, which if set to true raises an error if a
  14. # constant you have requested was not found.
  15. #
  16. # When passed a block, #calculate is automatically called at the end of
  17. # the block, otherwise you must call it yourself.
  18. def initialize(prefix = nil, options = {})
  19. @includes = []
  20. @constants = {}
  21. @prefix = prefix
  22. @required = options[:required]
  23. @options = options
  24. if block_given? then
  25. yield self
  26. calculate self.class.options.merge(options)
  27. end
  28. end
  29. def self.options=(options)
  30. @options = options
  31. end
  32. def self.options
  33. @options
  34. end
  35. def [](name)
  36. @constants[name].value
  37. end
  38. ##
  39. # Request the value for C constant +name+. +format+ is a printf format
  40. # string to print the value out, and +cast+ is a C cast for the value.
  41. # +ruby_name+ allows you to give the constant an alternate ruby name for
  42. # #to_ruby. +converter+ or +converter_proc+ allow you to convert the
  43. # value from a string to the appropriate type for #to_ruby.
  44. def const(name, format = nil, cast = '', ruby_name = nil, converter = nil,
  45. &converter_proc)
  46. format ||= '%d'
  47. cast ||= ''
  48. if converter_proc and converter then
  49. raise ArgumentError, "Supply only converter or converter block"
  50. end
  51. converter = converter_proc if converter.nil?
  52. const = Constant.new name, format, cast, ruby_name, converter
  53. @constants[name.to_s] = const
  54. return const
  55. end
  56. def calculate(options = {})
  57. binary = File.join Dir.tmpdir, "rb_const_gen_bin_#{Process.pid}"
  58. Tempfile.open("#{@prefix}.const_generator") do |f|
  59. f.puts "#include <stdio.h>"
  60. @includes.each do |inc|
  61. f.puts "#include <#{inc}>"
  62. end
  63. f.puts "#include <stddef.h>\n\n"
  64. f.puts "int main(int argc, char **argv)\n{"
  65. @constants.each_value do |const|
  66. f.puts <<-EOF
  67. #ifdef #{const.name}
  68. printf("#{const.name} #{const.format}\\n", #{const.cast}#{const.name});
  69. #endif
  70. EOF
  71. end
  72. f.puts "\n\treturn 0;\n}"
  73. f.flush
  74. output = `gcc #{options[:cppflags]} -D_DARWIN_USE_64_BIT_INODE -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -x c -Wall -Werror #{f.path} -o #{binary} 2>&1`
  75. unless $?.success? then
  76. output = output.split("\n").map { |l| "\t#{l}" }.join "\n"
  77. raise "Compilation error generating constants #{@prefix}:\n#{output}"
  78. end
  79. end
  80. output = `#{binary}`
  81. File.unlink(binary + (FFI::Platform.windows? ? ".exe" : ""))
  82. output.each_line do |line|
  83. line =~ /^(\S+)\s(.*)$/
  84. const = @constants[$1]
  85. const.value = $2
  86. end
  87. missing_constants = @constants.select do |name, constant|
  88. constant.value.nil?
  89. end.map { |name,| name }
  90. if @required and not missing_constants.empty? then
  91. raise "Missing required constants for #{@prefix}: #{missing_constants.join ', '}"
  92. end
  93. end
  94. def dump_constants(io)
  95. @constants.each do |name, constant|
  96. name = [@prefix, name].join '.' if @prefix
  97. io.puts "#{name} = #{constant.converted_value}"
  98. end
  99. end
  100. ##
  101. # Outputs values for discovered constants. If the constant's value was
  102. # not discovered it is not omitted.
  103. def to_ruby
  104. @constants.sort_by { |name,| name }.map do |name, constant|
  105. if constant.value.nil? then
  106. "# #{name} not available"
  107. else
  108. constant.to_ruby
  109. end
  110. end.join "\n"
  111. end
  112. def include(i)
  113. @includes << i
  114. end
  115. end
  116. class ConstGenerator::Constant
  117. attr_reader :name, :format, :cast
  118. attr_accessor :value
  119. def initialize(name, format, cast, ruby_name = nil, converter=nil)
  120. @name = name
  121. @format = format
  122. @cast = cast
  123. @ruby_name = ruby_name
  124. @converter = converter
  125. @value = nil
  126. end
  127. def converted_value
  128. if @converter
  129. @converter.call(@value)
  130. else
  131. @value
  132. end
  133. end
  134. def ruby_name
  135. @ruby_name || @name
  136. end
  137. def to_ruby
  138. "#{ruby_name} = #{converted_value}"
  139. end
  140. end
  141. end