xbot/include/libconfig-1.7.3/contrib/libconfig-ruby/ext/rconfig.c

701 lines
24 KiB
C
Executable File

#include <ruby.h>
#include <libconfig.h>
static VALUE cConfig, cConfigBaseSetting, cConfigSetting, cConfigAggregate;
static VALUE cConfigFormatDefault, cConfigFormatHex;
static VALUE cConfigFixnum, cConfigBignum, cConfigFloat, cConfigBoolean, cConfigString;
static VALUE cConfigGroup, cConfigList, cConfigArray;
static VALUE rSettingNameRegexp;
static VALUE aConfigSettings, aConfigScalars, aConfigAggregates;
static VALUE eConfigParseError, eSettingNotFoundError, eSettingFormatError, eSettingNameError;
static VALUE rconfig_wrap_value(config_setting_t* setting)
{
switch(config_setting_type(setting)) {
case CONFIG_TYPE_INT:
return LONG2FIX(config_setting_get_int(setting));
case CONFIG_TYPE_INT64:
return rb_ll2inum(config_setting_get_int64(setting));
case CONFIG_TYPE_FLOAT:
return rb_float_new(config_setting_get_float(setting));
case CONFIG_TYPE_STRING:
return rb_str_new2(config_setting_get_string(setting));
case CONFIG_TYPE_BOOL:
return config_setting_get_bool(setting) ? Qtrue : Qfalse;
default:
rb_bug("unknown value type %d", config_setting_type(setting));
}
}
static void rconfig_free_setting(config_setting_t* setting)
{
// dummy
}
static VALUE rconfig_prepare_setting(config_setting_t* setting)
{
VALUE wrapper = Data_Wrap_Struct(rb_cObject, 0, rconfig_free_setting, setting);
config_setting_set_hook(setting, (void*) wrapper);
return wrapper;
}
static void rconfig_destroy_setting(void* hook)
{
if(hook != NULL) {
VALUE wrapper = (VALUE) hook;
rb_iv_set(wrapper, "@setting", Qnil);
}
}
static VALUE rconfig_wrap_setting(config_setting_t* setting)
{
VALUE rbSetting = rconfig_prepare_setting(setting);
switch(config_setting_type(setting)) {
case CONFIG_TYPE_INT:
return rb_funcall(cConfigFixnum, rb_intern("new"), 2, LONG2FIX(config_setting_get_int(setting)), rbSetting);
case CONFIG_TYPE_INT64:
return rb_funcall(cConfigBignum, rb_intern("new"), 2, rb_ll2inum(config_setting_get_int64(setting)), rbSetting);
case CONFIG_TYPE_FLOAT:
return rb_funcall(cConfigFloat, rb_intern("new"), 2, rb_float_new(config_setting_get_float(setting)), rbSetting);
case CONFIG_TYPE_STRING:
return rb_funcall(cConfigString, rb_intern("new"), 2, rb_str_new2(config_setting_get_string(setting)), rbSetting);
case CONFIG_TYPE_BOOL:
return rb_funcall(cConfigBoolean, rb_intern("new"), 2, config_setting_get_bool(setting) ? Qtrue : Qfalse, rbSetting);
case CONFIG_TYPE_ARRAY:
return rb_funcall(cConfigArray, rb_intern("new"), 2, Qnil, rbSetting);
case CONFIG_TYPE_LIST:
return rb_funcall(cConfigList, rb_intern("new"), 1, rbSetting);
case CONFIG_TYPE_GROUP:
return rb_funcall(cConfigGroup, rb_intern("new"), 1, rbSetting);
default:
rb_bug("[r] unknown setting type %d", config_setting_type(setting));
}
}
static void rconfig_update_setting(config_setting_t* setting, VALUE value)
{
switch(config_setting_type(setting)) {
case CONFIG_TYPE_INT:
config_setting_set_int(setting, FIX2LONG(value));
break;
case CONFIG_TYPE_INT64:
if(TYPE(value) == T_BIGNUM)
config_setting_set_int64(setting, rb_big2ll(value));
else // T_FIXNUM
config_setting_set_int64(setting, FIX2INT(value));
break;
case CONFIG_TYPE_FLOAT:
// ruby1.9 check
#if HAVE_RB_BLOCK_CALL
config_setting_set_float(setting, RFLOAT_VALUE(value));
#else
config_setting_set_float(setting, RFLOAT_VALUE(value));
#endif
break;
case CONFIG_TYPE_STRING:
config_setting_set_string(setting, RSTRING_PTR(value));
break;
case CONFIG_TYPE_BOOL:
config_setting_set_bool(setting, value == Qtrue);
break;
default:
rb_bug("[w] unknown setting type %d", config_setting_type(setting));
}
}
static void rconfig_check_setting_type(VALUE object, VALUE value)
{
if(rb_obj_class(object) == cConfigFixnum) {
Check_Type(value, T_FIXNUM);
} else if(rb_obj_class(object) == cConfigBignum) {
if(TYPE(value) != T_BIGNUM && TYPE(value) != T_FIXNUM)
rb_raise(rb_eTypeError, "wrong argument type %s (expected Fixnum or Bignum)", rb_obj_classname(value));
} else if(rb_obj_class(object) == cConfigFloat) {
Check_Type(value, T_FLOAT);
} else if(rb_obj_class(object) == cConfigString) {
Check_Type(value, T_STRING);
} else if(rb_obj_class(object) == cConfigBoolean) {
if(value != Qtrue && value != Qfalse)
rb_raise(rb_eTypeError, "wrong argument type %s (expected boolean)", rb_obj_classname(value));
} else {
rb_raise(rb_eException, "never use Config::Setting itself");
}
}
static int rconfig_do_append(config_setting_t* setting, VALUE target, VALUE name)
{
int type;
if(rb_obj_class(target) == cConfigFixnum)
type = CONFIG_TYPE_INT;
else if(rb_obj_class(target) == cConfigBignum)
type = CONFIG_TYPE_INT64;
else if(rb_obj_class(target) == cConfigFloat)
type = CONFIG_TYPE_FLOAT;
else if(rb_obj_class(target) == cConfigString)
type = CONFIG_TYPE_STRING;
else if(rb_obj_class(target) == cConfigBoolean)
type = CONFIG_TYPE_BOOL;
else if(rb_obj_class(target) == cConfigGroup)
type = CONFIG_TYPE_GROUP;
else if(rb_obj_class(target) == cConfigList)
type = CONFIG_TYPE_LIST;
else if(rb_obj_class(target) == cConfigArray)
type = CONFIG_TYPE_ARRAY;
else
rb_bug("unknown setting class %s", rb_obj_classname(target));
config_setting_t* new_setting;
if(name == Qnil) {
new_setting = config_setting_add(setting, NULL, type);
} else {
Check_Type(name, T_STRING);
new_setting = config_setting_add(setting, RSTRING_PTR(name), type);
}
if(new_setting == NULL)
return 0;
VALUE rbNewSetting = rconfig_prepare_setting(new_setting);
rb_iv_set(target, "@setting", rbNewSetting);
if(rb_ary_includes(aConfigScalars, rb_obj_class(target)) == Qtrue)
rconfig_update_setting(new_setting, rb_iv_get(target, "@value"));
if(rb_ary_includes(aConfigAggregates, rb_obj_class(target)) == Qtrue) {
if(rb_obj_class(target) == cConfigGroup) {
VALUE hash = rb_iv_get(target, "@hash");
VALUE children = rb_funcall(hash, rb_intern("keys"), 0);
int i;
for(i = 0; i < RARRAY_LEN(children); i++) {
VALUE key = RARRAY_PTR(children)[i];
rconfig_do_append(new_setting, rb_hash_aref(hash, key), key);
}
} else {
VALUE children = rb_iv_get(target, "@list");
int i;
for(i = 0; i < RARRAY_LEN(children); i++) {
rconfig_do_append(new_setting, RARRAY_PTR(children)[i], Qnil);
}
}
}
return 1;
}
static VALUE rbConfigBaseSetting_initialize(VALUE self, VALUE setting)
{
if(setting != Qnil)
Check_Type(setting, T_DATA);
rb_iv_set(self, "@setting", setting);
return self;
}
static VALUE rbConfigBaseSetting_name(VALUE self)
{
if(rb_iv_get(self, "@setting") != Qnil) {
config_setting_t* setting = NULL;
Data_Get_Struct(rb_iv_get(self, "@setting"), config_setting_t, setting);
return rb_str_new2(config_setting_name(setting));
} else {
return Qnil;
}
}
static VALUE rbConfigBaseSetting_parent(VALUE self)
{
if(rb_iv_get(self, "@setting") != Qnil) {
config_setting_t* setting = NULL;
Data_Get_Struct(rb_iv_get(self, "@setting"), config_setting_t, setting);
return rconfig_wrap_setting(config_setting_parent(setting));
} else {
return Qnil;
}
}
static VALUE rbConfigBaseSetting_is_root(VALUE self)
{
if(rb_iv_get(self, "@setting") != Qnil) {
config_setting_t* setting = NULL;
Data_Get_Struct(rb_iv_get(self, "@setting"), config_setting_t, setting);
return config_setting_is_root(setting) ? Qtrue : Qfalse;
} else {
return Qnil;
}
}
static VALUE rbConfigBaseSetting_index(VALUE self)
{
if(rb_iv_get(self, "@setting") != Qnil) {
config_setting_t* setting = NULL;
Data_Get_Struct(rb_iv_get(self, "@setting"), config_setting_t, setting);
return INT2FIX(config_setting_index(setting));
} else {
return Qnil;
}
}
static VALUE rbConfigBaseSetting_line(VALUE self)
{
if(rb_iv_get(self, "@setting") != Qnil) {
config_setting_t* setting = NULL;
Data_Get_Struct(rb_iv_get(self, "@setting"), config_setting_t, setting);
return INT2FIX(config_setting_source_line(setting));
} else {
return Qnil;
}
}
static VALUE rbConfigSetting_initialize(int argc, VALUE* argv, VALUE self)
{
VALUE value, setting;
rb_scan_args(argc, argv, "11", &value, &setting);
rb_call_super(1, &setting);
rconfig_check_setting_type(self, value);
rb_iv_set(self, "@value", value);
if(rb_iv_get(self, "@setting") != Qnil) {
config_setting_t* c_setting = NULL;
Data_Get_Struct(rb_iv_get(self, "@setting"), config_setting_t, c_setting);
rb_iv_set(self, "@format", INT2FIX(config_setting_get_format(c_setting)));
} else {
rb_iv_set(self, "@format", cConfigFormatDefault);
}
return self;
}
static VALUE rbConfigSetting_get_value(VALUE self)
{
if(rb_iv_get(self, "@setting") != Qnil) {
config_setting_t* setting;
Data_Get_Struct(rb_iv_get(self, "@setting"), config_setting_t, setting);
return rconfig_wrap_value(setting);
} else {
return rb_iv_get(self, "@value");
}
}
static VALUE rbConfigSetting_set_value(VALUE self, VALUE new_value)
{
rconfig_check_setting_type(self, new_value);
if(rb_iv_get(self, "@setting") != Qnil) {
config_setting_t* setting;
Data_Get_Struct(rb_iv_get(self, "@setting"), config_setting_t, setting);
rconfig_update_setting(setting, new_value);
}
rb_iv_set(self, "@value", new_value);
return new_value;
}
static VALUE rbConfigSetting_get_format(VALUE self)
{
if(rb_iv_get(self, "@setting") != Qnil) {
config_setting_t* setting;
Data_Get_Struct(rb_iv_get(self, "@setting"), config_setting_t, setting);
return INT2FIX(config_setting_get_format(setting));
} else {
return rb_iv_get(self, "format");
}
}
static VALUE rbConfigSetting_set_format(VALUE self, VALUE new_format)
{
if(rb_iv_get(self, "@setting") != Qnil) {
config_setting_t* setting;
Data_Get_Struct(rb_iv_get(self, "@setting"), config_setting_t, setting);
if(!config_setting_set_format(setting, FIX2INT(new_format)))
rb_raise(eSettingFormatError, "invalid setting format %d", FIX2INT(new_format));
}
rb_iv_set(self, "@format", new_format);
return new_format;
}
static VALUE rbConfigAggregate_get(VALUE self, VALUE index);
static VALUE rbConfigAggregate_initialize(int argc, VALUE* argv, VALUE self)
{
VALUE setting = Qnil;
if(rb_obj_class(self) == cConfigGroup || rb_obj_class(self) == cConfigList) {
rb_scan_args(argc, argv, "01", &setting);
} else if(rb_obj_class(self) == cConfigArray) {
VALUE type = Qnil;
rb_scan_args(argc, argv, "02", &type, &setting);
if(type != Qnil && rb_ary_includes(aConfigScalars, type) != Qtrue)
rb_raise(rb_eTypeError, "invalid setting array type %s", rb_class2name(type));
rb_iv_set(self, "@type", type);
} else {
rb_raise(rb_eException, "never create Config::Aggregate itself");
}
rb_call_super(1, &setting);
rb_iv_set(self, "@list", rb_ary_new());
if(rb_obj_class(self) == cConfigGroup)
rb_iv_set(self, "@hash", rb_hash_new());
if(setting != Qnil && rb_obj_class(self) == cConfigArray) {
config_setting_t* c_setting;
Data_Get_Struct(setting, config_setting_t, c_setting);
if(config_setting_length(c_setting) > 0)
rb_iv_set(self, "@type", rb_obj_class(rbConfigAggregate_get(self, INT2FIX(0))));
}
return self;
}
static VALUE rbConfigAggregate_size(VALUE self)
{
config_setting_t* setting = NULL;
if(rb_iv_get(self, "@setting") != Qnil)
Data_Get_Struct(rb_iv_get(self, "@setting"), config_setting_t, setting);
if(setting)
return INT2FIX(config_setting_length(setting));
else
return INT2FIX(RARRAY_LEN(rb_iv_get(self, "@list")));
}
static VALUE rbConfigAggregate_get(VALUE self, VALUE index)
{
config_setting_t* setting = NULL;
if(rb_iv_get(self, "@setting") != Qnil)
Data_Get_Struct(rb_iv_get(self, "@setting"), config_setting_t, setting);
VALUE rbTarget = Qnil;
if(TYPE(index) == T_STRING && rb_obj_class(self) == cConfigGroup) {
if(setting) {
config_setting_t* target = config_setting_get_member(setting, RSTRING_PTR(index));
if(target)
rbTarget = rconfig_wrap_setting(target);
} else {
rbTarget = rb_hash_aref(rb_iv_get(self, "@hash"), index);
}
} else if(TYPE(index) == T_FIXNUM) {
if(setting) {
config_setting_t* target = config_setting_get_elem(setting, FIX2INT(index));
if(target)
rbTarget = rconfig_wrap_setting(target);
} else {
rbTarget = rb_ary_entry(rb_iv_get(self, "@list"), FIX2INT(index));
}
} else {
rb_raise(rb_eTypeError, "wrong argument type %s (expected String or Fixnum)", rb_obj_classname(index));
}
if(rbTarget == Qnil)
if(TYPE(index) == T_STRING)
rb_raise(eSettingNotFoundError, "setting `%s' not found", RSTRING_PTR(index));
else
rb_raise(eSettingNotFoundError, "setting [%d] not found", FIX2INT(index));
return rbTarget;
}
static VALUE rbConfigAggregate_append(VALUE self, VALUE target)
{
config_setting_t* setting = NULL;
if(rb_iv_get(self, "@setting") != Qnil)
Data_Get_Struct(rb_iv_get(self, "@setting"), config_setting_t, setting);
Check_Type(target, T_OBJECT);
VALUE type = rb_iv_get(self, "@type");
if(rb_obj_class(self) == cConfigArray) {
if(type != Qnil && type != rb_obj_class(target))
rb_raise(rb_eTypeError, "wrong argument type %s (expected %s)", rb_obj_classname(target), rb_class2name(type));
if(type == Qnil && rb_ary_includes(aConfigScalars, rb_obj_class(target)) != Qtrue)
rb_raise(rb_eTypeError, "invalid setting array type %s", rb_obj_classname(target));
}
if(rb_ary_includes(aConfigSettings, rb_obj_class(target)) == Qtrue) {
if(setting)
rconfig_do_append(setting, target, Qnil);
rb_ary_push(rb_iv_get(self, "@list"), target);
} else {
rb_raise(rb_eTypeError, "wrong argument type %s (expected Config::BaseSetting)", rb_obj_classname(target));
}
if(rb_obj_class(self) == cConfigArray && type == Qnil)
rb_iv_set(self, "@type", rb_obj_class(target));
return target;
}
static VALUE rbConfigGroup_append(VALUE self, VALUE name, VALUE target)
{
Check_Type(name, T_STRING);
Check_Type(target, T_OBJECT);
config_setting_t* setting = NULL;
if(rb_iv_get(self, "@setting") != Qnil)
Data_Get_Struct(rb_iv_get(self, "@setting"), config_setting_t, setting);
if(rb_ary_includes(aConfigSettings, rb_obj_class(target)) == Qtrue) {
if(rb_reg_match(rSettingNameRegexp, name) == Qnil)
rb_raise(eSettingNameError, "setting name `%s' contains invalid characters", RSTRING_PTR(name));
if(setting) {
if(!rconfig_do_append(setting, target, name))
rb_raise(eSettingNameError, "setting `%s' already exists", RSTRING_PTR(name));
} else if(rb_hash_aref(rb_iv_get(self, "@hash"), name) != Qnil) {
rb_raise(eSettingNameError, "setting `%s' already exists", RSTRING_PTR(name));
}
rb_ary_push(rb_iv_get(self, "@list"), target);
rb_hash_aset(rb_iv_get(self, "@hash"), name, target);
} else {
rb_raise(rb_eTypeError, "wrong argument type %s (expected Config::BaseSetting)", rb_obj_classname(target));
}
return target;
}
static VALUE rbConfigAggregate_delete(VALUE self, VALUE target)
{
config_setting_t* setting = NULL;
if(rb_iv_get(self, "@setting") != Qnil)
Data_Get_Struct(rb_iv_get(self, "@setting"), config_setting_t, setting);
VALUE hash = rb_iv_get(self, "@hash"), list = rb_iv_get(self, "@list");
if(TYPE(target) == T_STRING && rb_obj_class(self) == cConfigGroup) {
if(setting)
config_setting_remove(setting, RSTRING_PTR(target));
rb_ary_delete_at(list, rb_hash_aref(hash, target));
rb_hash_delete(hash, target);
} else if(TYPE(target) == T_FIXNUM) {
int index = FIX2INT(target);
if(setting)
config_setting_remove_elem(setting, index);
if(rb_obj_class(self) == cConfigGroup)
rb_hash_delete(hash, rbConfigBaseSetting_name(rb_ary_entry(list, index)));
rb_ary_delete_at(list, index);
} else if(rb_ary_includes(aConfigSettings, rb_obj_class(target)) == Qtrue) {
VALUE name = rbConfigBaseSetting_name(target);
if(setting)
config_setting_remove(setting, RSTRING_PTR(name));
if(rb_obj_class(self) == cConfigGroup)
rb_hash_delete(hash, name);
rb_ary_delete(list, target);
} else {
if(rb_obj_class(self) == cConfigGroup)
rb_raise(rb_eTypeError, "wrong argument type %s (expected String, Fixnum or Config::BaseSetting)", rb_obj_classname(target));
else
rb_raise(rb_eTypeError, "wrong argument type %s (expected Fixnum or Config::BaseSetting)", rb_obj_classname(target));
}
return Qnil;
}
static VALUE rbConfig_initialize(VALUE self)
{
config_t* config = (config_t*) malloc(sizeof(config_t));
config_init(config);
config_set_destructor(config, &rconfig_destroy_setting);
VALUE rbConfig = Data_Wrap_Struct(rb_cObject, 0, config_destroy, config);
rb_iv_set(self, "@config", rbConfig);
return self;
}
static VALUE rbConfig_read_bang(VALUE self, VALUE path)
{
Check_Type(path, T_STRING);
config_t* config;
Data_Get_Struct(rb_iv_get(self, "@config"), config_t, config);
if(!config_read_file(config, RSTRING_PTR(path))) {
if(config_error_line(config) == 0)
rb_raise(rb_eIOError, "cannot load config: I/O error");
else
rb_raise(eConfigParseError, "cannot parse config on line %d: `%s'",
config_error_line(config), config_error_text(config));
}
return Qtrue;
}
static VALUE rbConfig_write_bang(VALUE self, VALUE path)
{
Check_Type(path, T_STRING);
config_t* config;
Data_Get_Struct(rb_iv_get(self, "@config"), config_t, config);
if(!config_write_file(config, RSTRING_PTR(path)))
rb_raise(rb_eIOError, "cannot save config: I/O error");
return Qtrue;
}
static VALUE rbConfig_read(VALUE self, VALUE path)
{
Check_Type(path, T_STRING);
config_t* config;
Data_Get_Struct(rb_iv_get(self, "@config"), config_t, config);
return config_read_file(config, RSTRING_PTR(path)) ? Qtrue : Qfalse;
}
static VALUE rbConfig_write(VALUE self, VALUE path)
{
Check_Type(path, T_STRING);
config_t* config;
Data_Get_Struct(rb_iv_get(self, "@config"), config_t, config);
return config_write_file(config, RSTRING_PTR(path)) ? Qtrue : Qfalse;
}
static VALUE rbConfig_root(VALUE self)
{
config_t* config;
Data_Get_Struct(rb_iv_get(self, "@config"), config_t, config);
return rconfig_wrap_setting(config_root_setting(config));
}
static VALUE rbConfig_lookup(VALUE self, VALUE handle)
{
if(TYPE(handle) == T_STRING) {
config_t* config;
Data_Get_Struct(rb_iv_get(self, "@config"), config_t, config);
config_setting_t* setting;
setting = config_lookup(config, RSTRING_PTR(handle));
if(setting == NULL)
rb_raise(eSettingNotFoundError, "setting `%s' not found", RSTRING_PTR(handle));
return rconfig_wrap_setting(setting);
} else if(TYPE(handle) == T_FIXNUM) {
return rbConfigAggregate_get(rbConfig_root(self), handle);
} else {
rb_raise(rb_eTypeError, "wrong argument type %s (expected String or Fixnum)", rb_obj_classname(handle));
}
}
static VALUE rbConfig_append(VALUE self, VALUE name, VALUE target)
{
return rbConfigGroup_append(rbConfig_root(self), name, target);
}
static VALUE rbConfig_delete(VALUE self, VALUE name)
{
return rbConfigAggregate_delete(rbConfig_root(self), name);
}
static VALUE rbConfig_size(VALUE self)
{
return rbConfigAggregate_size(rbConfig_root(self));
}
void Init_rconfig()
{
cConfig = rb_define_class("Config", rb_cObject);
rb_define_method(cConfig, "initialize", rbConfig_initialize, 0);
rb_define_method(cConfig, "read!", rbConfig_read_bang, 1);
rb_define_method(cConfig, "write!", rbConfig_write_bang, 1);
rb_define_method(cConfig, "read", rbConfig_read, 1);
rb_define_method(cConfig, "write", rbConfig_write, 1);
rb_define_method(cConfig, "root", rbConfig_root, 0);
rb_define_method(cConfig, "lookup", rbConfig_lookup, 1);
rb_define_method(cConfig, "[]", rbConfig_lookup, 1);
rb_define_method(cConfig, "append", rbConfig_append, 2);
rb_define_method(cConfig, "delete", rbConfig_delete, 1);
rb_define_method(cConfig, "size", rbConfig_size, 0);
cConfigBaseSetting = rb_define_class_under(cConfig, "BaseSetting", rb_cObject);
rb_define_method(cConfigBaseSetting, "initialize", rbConfigBaseSetting_initialize, 1);
rb_define_method(cConfigBaseSetting, "name", rbConfigBaseSetting_name, 0);
rb_define_method(cConfigBaseSetting, "parent", rbConfigBaseSetting_parent, 0);
rb_define_method(cConfigBaseSetting, "root?", rbConfigBaseSetting_is_root, 0);
rb_define_method(cConfigBaseSetting, "index", rbConfigBaseSetting_index, 0);
rb_define_method(cConfigBaseSetting, "line", rbConfigBaseSetting_line, 0);
cConfigSetting = rb_define_class_under(cConfig, "Setting", cConfigBaseSetting);
rb_define_method(cConfigSetting, "initialize", rbConfigSetting_initialize, -1);
rb_define_method(cConfigSetting, "value", rbConfigSetting_get_value, 0);
rb_define_method(cConfigSetting, "value=", rbConfigSetting_set_value, 1);
rb_define_method(cConfigSetting, "format", rbConfigSetting_get_format, 0);
rb_define_method(cConfigSetting, "format=", rbConfigSetting_set_format, 1);
cConfigFormatDefault = INT2FIX(CONFIG_FORMAT_DEFAULT);
rb_define_const(cConfig, "FORMAT_DEFAULT", cConfigFormatDefault);
cConfigFormatHex = INT2FIX(CONFIG_FORMAT_HEX);
rb_define_const(cConfig, "FORMAT_HEX", cConfigFormatHex);
cConfigFixnum = rb_define_class_under(cConfig, "Fixnum", cConfigSetting);
cConfigBignum = rb_define_class_under(cConfig, "Bignum", cConfigSetting);
cConfigFloat = rb_define_class_under(cConfig, "Float", cConfigSetting);
cConfigBoolean = rb_define_class_under(cConfig, "Boolean", cConfigSetting);
cConfigString = rb_define_class_under(cConfig, "String", cConfigSetting);
cConfigAggregate = rb_define_class_under(cConfig, "Aggregate", cConfigBaseSetting);
rb_define_method(cConfigAggregate, "initialize", rbConfigAggregate_initialize, -1);
rb_define_method(cConfigAggregate, "size", rbConfigAggregate_size, 0);
rb_define_method(cConfigAggregate, "get", rbConfigAggregate_get, 1);
rb_define_method(cConfigAggregate, "[]", rbConfigAggregate_get, 1);
rb_define_method(cConfigAggregate, "delete", rbConfigAggregate_delete, 1);
cConfigGroup = rb_define_class_under(cConfig, "Group", cConfigAggregate);
rb_define_method(cConfigGroup, "append", rbConfigGroup_append, 2);
cConfigArray = rb_define_class_under(cConfig, "Array", cConfigAggregate);
rb_define_method(cConfigArray, "append", rbConfigAggregate_append, 1);
rb_define_method(cConfigArray, "<<", rbConfigAggregate_append, 1);
cConfigList = rb_define_class_under(cConfig, "List", cConfigAggregate);
rb_define_method(cConfigList, "append", rbConfigAggregate_append, 1);
rb_define_method(cConfigList, "<<", rbConfigAggregate_append, 1);
aConfigScalars = rb_ary_new3(5, cConfigFixnum, cConfigBignum, cConfigFloat, cConfigBoolean, cConfigString);
aConfigAggregates = rb_ary_new3(3, cConfigGroup, cConfigArray, cConfigList);
aConfigSettings = rb_ary_plus(aConfigScalars, aConfigAggregates);
rb_define_const(cConfig, "SCALARS", aConfigScalars);
rb_define_const(cConfig, "AGGREGATES", aConfigAggregates);
rb_define_const(cConfig, "SETTINGS", aConfigSettings);
char* settingNameRegexp = "^[A-Za-z*][A-Za-z\\-_*]*$";
rSettingNameRegexp = rb_reg_new(settingNameRegexp, strlen(settingNameRegexp), 0);
eConfigParseError = rb_define_class("ConfigParseError", rb_eException);
eSettingNotFoundError = rb_define_class("SettingNotFoundError", rb_eException);
eSettingFormatError = rb_define_class("SettingFormatError", rb_eException);
eSettingNameError = rb_define_class("SettingNameError", rb_eException);
}