Martin DeMello wrote:
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”}