### Home Classes Methods

### In Files

- lib/ffi/tools/struct_generator.rb

### Parent

Object

### Namespace

- CLASS FFI::StructGenerator::Field

### Methods

- ::new
- ::options
- ::options=
- #calculate
- #dump_config
- #field
- #found?
- #generate_layout
- #get_field
- #include
- #name

### Files

- History.txt
- README.rdoc

### Class/Module Index

Quicksearch

- FFI
- FFI::AutoPointer
- FFI::AutoPointer::CallableReleaser
- FFI::AutoPointer::DefaultReleaser
- FFI::AutoPointer::Releaser
- FFI::ConstGenerator
- FFI::ConstGenerator::Constant
- FFI::Enum
- FFI::Enums
- FFI::Generator
- FFI::Generator::Task
- FFI::IO
- FFI::Library
- FFI::ManagedStruct
- FFI::NotFoundError
- FFI::Platform
- FFI::PlatformError
- FFI::Pointer
- FFI::StrPtrConverter
- FFI::Struct
- FFI::Struct::ManagedStructConverter
- FFI::StructGenerator
- FFI::StructGenerator::Field
- FFI::StructLayout
- FFI::StructLayout::Enum
- FFI::StructLayout::InnerStruct
- FFI::StructLayout::Mapped
- FFI::StructLayoutBuilder
- FFI::TypesGenerator
- FFI::Union
- FFI::VariadicInvoker

No matching classes.

# FFI::StructGenerator

Generates an FFI Struct layout.

Given the @@@ portion in:

    module Zlib::ZStream < FFI::Struct
      @@@
      name "struct z_stream_s"
      include "zlib.h"

      field :next_in,   :pointer
      field :avail_in,  :uint
      field :total_in,  :ulong

      # ...
      @@@
    end

StructGenerator will create the layout:

    layout :next_in, :pointer, 0,
           :avail_in, :uint, 4,
           :total_in, :ulong, 8,
           # ...

StructGenerator does its best to pad the layout it produces to preserve line numbers. Place the struct definition as close to the top of the file for best results.

### Attributes

fields[R]
size[RW]

### Public Class Methods

new(name, options = {}) click to toggle source

    # File lib/ffi/tools/struct_generator.rb, line 39
    def initialize(name, options = {})
      @name = name
      @struct_name = nil
      @includes = []
      @fields = []
      @found = false
      @size = nil

      if block_given? then
        yield self
        calculate self.class.options.merge(options)
      end
    end

options() click to toggle source

    # File lib/ffi/tools/struct_generator.rb, line 55
    def self.options
      @options
    end

options=(options) click to toggle source

    # File lib/ffi/tools/struct_generator.rb, line 52
    def self.options=(options)
      @options = options
    end

### Public Instance Methods

calculate(options = {}) click to toggle source

    # File lib/ffi/tools/struct_generator.rb, line 58
    def calculate(options = {})
      binary = File.join Dir.tmpdir, "rb_struct_gen_bin_#{Process.pid}"

      raise "struct name not set" if @struct_name.nil?

      Tempfile.open("#{@name}.struct_generator") do |f|
        f.puts "#include <stdio.h>"

        @includes.each do |inc|
          f.puts "#include <#{inc}>"
        end

        f.puts "#include <stddef.h>\n\n"
        f.puts "int main(int argc, char **argv)\n{"
        f.puts "  #{@struct_name} s;"
        f.puts %[  printf("sizeof(#{@struct_name}) %u\\n", (unsigned int) sizeof(#{@struct_name}));]

        @fields.each do |field|
          f.puts     printf("#{field.name} %u %u\\n", (unsigned int) offsetof(#{@struct_name}, #{field.name}),           (unsigned int) sizeof(s.#{field.name}));
        end

        f.puts "\n  return 0;\n}"
        f.flush

        output = `gcc #{options[:cppflags]} #{options[:cflags]} -D_DARWIN_USE_64_BIT_INODE -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -x c -Wall -Werror #{f.path} -o #{binary} 2>&1`

        unless $?.success? then
          @found = false
          output = output.split("\n").map { |l| "\t#{l}" }.join "\n"
          raise "Compilation error generating struct #{@name} (#{@struct_name}):\n#{output}"
        end
      end

      output = `#{binary}`.split "\n"
      File.unlink(binary + (FFI::Platform.windows? ? ".exe" : ""))
      sizeof = output.shift
      unless @size
        m = /\s*sizeof\([^)]+\) (\d+)/.match sizeof
        @size = m[1]
      end

      line_no = 0
      output.each do |line|
        md = line.match(/.+ (\d+) (\d+)/)
        @fields[line_no].offset = md[1].to_i
        @fields[line_no].size   = md[2].to_i

        line_no += 1
      end

      @found = true
    end

dump_config(io) click to toggle source

    # File lib/ffi/tools/struct_generator.rb, line 124
    def dump_config(io)
      io.puts "rbx.platform.#{@name}.sizeof = #{@size}"

      @fields.each { |field| io.puts field.to_config(@name) }
    end

field(name, type=nil) click to toggle source

    # File lib/ffi/tools/struct_generator.rb, line 114
    def field(name, type=nil)
      field = Field.new(name, type)
      @fields << field
      return field
    end

found?() click to toggle source

    # File lib/ffi/tools/struct_generator.rb, line 120
    def found?
      @found
    end

generate_layout() click to toggle source

    # File lib/ffi/tools/struct_generator.rb, line 130
    def generate_layout
      buf = ""

      @fields.each_with_index do |field, i|
        if buf.empty?
          buf << "layout :#{field.name}, :#{field.type}, #{field.offset}"
        else
          buf << "       :#{field.name}, :#{field.type}, #{field.offset}"
        end

        if i < @fields.length - 1
          buf << ",\n"
        end
      end

      buf
    end

get_field(name) click to toggle source

    # File lib/ffi/tools/struct_generator.rb, line 148
    def get_field(name)
      @fields.find { |f| name == f.name }
    end

include(i) click to toggle source

    # File lib/ffi/tools/struct_generator.rb, line 152
    def include(i)
      @includes << i
    end

name(n) click to toggle source

    # File lib/ffi/tools/struct_generator.rb, line 156
    def name(n)
      @struct_name = n
    end

[Validate]

Generated with the Darkfish Rdoc Generator 2.