Joel VanderWerf
6/12/2009 9:23:00 PM
Martin DeMello wrote:
> On Fri, Jun 12, 2009 at 7:01 PM, Jason Roelofs<jameskilton@gmail.com> wrote:
>> Even using FFI, you'll need to define the wrapping between C constant to
>> Ruby constant, and using Ruby's API, you'll be define_const-ing every one of
>> those, then putting them into an array. Just define them in the Ruby
>> yourself, there isn't a faster way to do it.
>
> I was afraid of that :( The docs are a bit on the sketchy side too. I
> guess some sort of code generation would be the way to go then (swig
> seems like overkill). Will give cgenerator a look.
>
> martin
Cgenerator will work, and might be a good idea if the source (the list
of values and strings) changes from time to time, and you would rather
have your program regenerate the ruby extension (and data structure)
automatically.
Here's how it works, assuming your source files are flag.c and flag.h:
$ ls
flag.c flag.h flag.rb
$ cat flag.h
struct flag_str {
unsigned int val;
const char *str;
};
extern struct flag_str extent_flags[];
typedef enum {
FIEMAP_EXTENT_LAST = 1,
FIEMAP_EXTENT_UNKNOWN,
FIEMAP_EXTENT_DELALLOC,
FIEMAP_EXTENT_NO_BYPASS,
FIEMAP_EXTENT_SECONDARY,
FIEMAP_EXTENT_NET,
FIEMAP_EXTENT_DATA_COMPRESSED,
FIEMAP_EXTENT_DATA_ENCRYPTED,
FIEMAP_EXTENT_NOT_ALIGNED,
FIEMAP_EXTENT_DATA_INLINE,
FIEMAP_EXTENT_DATA_TAIL,
FIEMAP_EXTENT_UNWRITTEN,
FIEMAP_EXTENT_MERGED
} FIEMAP_EXTENT;
$ cat flag.c
#include "flag.h"
#ifndef NULL
#define NULL 0
#endif
struct flag_str extent_flags[] = {
{ FIEMAP_EXTENT_LAST, "last" },
{ FIEMAP_EXTENT_UNKNOWN, "unkown" },
{ FIEMAP_EXTENT_DELALLOC, "delalloc" },
{ FIEMAP_EXTENT_NO_BYPASS, "no_bypass" },
{ FIEMAP_EXTENT_SECONDARY, "secondary" },
{ FIEMAP_EXTENT_NET, "net" },
{ FIEMAP_EXTENT_DATA_COMPRESSED, "data_compressed" },
{ FIEMAP_EXTENT_DATA_ENCRYPTED, "data_encrypted" },
{ FIEMAP_EXTENT_NOT_ALIGNED, "not_aligned" },
{ FIEMAP_EXTENT_DATA_INLINE, "data_inline" },
{ FIEMAP_EXTENT_DATA_TAIL, "data_tail" },
{ FIEMAP_EXTENT_UNWRITTEN, "unwritten" },
{ FIEMAP_EXTENT_MERGED, "merged" },
{ 0, NULL },
};
$ cat flag.rb
#!/usr/bin/env ruby
require 'cgen/cgen'
require 'fileutils'
module Flag; end
# Generate the extension source code.
lib = CGenerator::Library.new "flag_lib"
lib.include "flag.h"
lib.define_c_singleton_method(Flag, :extent_flags).instance_eval {
# no args
body %{ VALUE a;
struct flag_str *pfs;
a = rb_ary_new();
for (pfs = extent_flags; pfs->val; pfs++) {
rb_ary_push(a,
rb_ary_new3(2,
INT2NUM(pfs->val),
rb_str_new2(pfs->str)
));
}
}
returns "a"
}
# Normally, this isn't needed, but we need to set up the external files
# as symlinks in this dir before calling commit.
FileUtils.mkdir_p("flag_lib")
# Put links to sources where they will be found.
Dir.chdir "flag_lib" do
%w{ flag.h flag.c }.each do |file|
FileUtils.ln_s("../#{file}", file) rescue nil
end
end
# Write and build
lib.commit
# Use the library
Flag::EXTENT_FLAGS = Hash[*Flag.extent_flags.flatten]
p Flag::EXTENT_FLAGS
$ ruby flag.rb
{5=>"secondary", 11=>"data_tail", 6=>"net", 12=>"unwritten", 1=>"last",
7=>"data_compressed", 13=>"merged", 2=>"unkown", 8=>"data_encrypted",
3=>"delalloc", 9=>"not_aligned", 4=>"no_bypass", 10=>"data_inline"}
--
vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407