diff options
| author | Jonathan McCrohan <jmccrohan@gmail.com> | 2011-12-01 22:56:23 +0000 | 
|---|---|---|
| committer | Jonathan McCrohan <jmccrohan@gmail.com> | 2011-12-01 22:56:23 +0000 | 
| commit | 429e46051dba814e7d6c74368eb1bba550222cbe (patch) | |
| tree | ed1dd43cd23c69f156aae2165006a16a66262cef /contrib/libconfig-ruby/ext | |
| parent | 58bf1382be0cbcf3f9649286fd2719b789a1595f (diff) | |
| download | libconfig-upstream/1.4.8.tar.gz | |
Imported Upstream version 1.4.8upstream/1.4.8
Diffstat (limited to 'contrib/libconfig-ruby/ext')
| -rw-r--r-- | contrib/libconfig-ruby/ext/extconf.rb | 11 | ||||
| -rw-r--r-- | contrib/libconfig-ruby/ext/rconfig.c | 700 | 
2 files changed, 711 insertions, 0 deletions
| diff --git a/contrib/libconfig-ruby/ext/extconf.rb b/contrib/libconfig-ruby/ext/extconf.rb new file mode 100644 index 0000000..e6d65ca --- /dev/null +++ b/contrib/libconfig-ruby/ext/extconf.rb @@ -0,0 +1,11 @@ +#!/usr/bin/ruby +require "mkmf" + +unless pkg_config('libconfig') +  puts 'failure: need libconfig' +  exit 1 +end + +have_func('rb_block_call', 'ruby/ruby.h') + +create_makefile("rconfig") diff --git a/contrib/libconfig-ruby/ext/rconfig.c b/contrib/libconfig-ruby/ext/rconfig.c new file mode 100644 index 0000000..c111cd6 --- /dev/null +++ b/contrib/libconfig-ruby/ext/rconfig.c @@ -0,0 +1,700 @@ +#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)->float_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); +} | 
