1*2e9d4914SAndroid Build Coastguard Worker #include <ruby.h>
2*2e9d4914SAndroid Build Coastguard Worker #include <libconfig.h>
3*2e9d4914SAndroid Build Coastguard Worker
4*2e9d4914SAndroid Build Coastguard Worker static VALUE cConfig, cConfigBaseSetting, cConfigSetting, cConfigAggregate;
5*2e9d4914SAndroid Build Coastguard Worker static VALUE cConfigFormatDefault, cConfigFormatHex;
6*2e9d4914SAndroid Build Coastguard Worker static VALUE cConfigFixnum, cConfigBignum, cConfigFloat, cConfigBoolean, cConfigString;
7*2e9d4914SAndroid Build Coastguard Worker static VALUE cConfigGroup, cConfigList, cConfigArray;
8*2e9d4914SAndroid Build Coastguard Worker
9*2e9d4914SAndroid Build Coastguard Worker static VALUE rSettingNameRegexp;
10*2e9d4914SAndroid Build Coastguard Worker static VALUE aConfigSettings, aConfigScalars, aConfigAggregates;
11*2e9d4914SAndroid Build Coastguard Worker static VALUE eConfigParseError, eSettingNotFoundError, eSettingFormatError, eSettingNameError;
12*2e9d4914SAndroid Build Coastguard Worker
rconfig_wrap_value(config_setting_t * setting)13*2e9d4914SAndroid Build Coastguard Worker static VALUE rconfig_wrap_value(config_setting_t* setting)
14*2e9d4914SAndroid Build Coastguard Worker {
15*2e9d4914SAndroid Build Coastguard Worker switch(config_setting_type(setting)) {
16*2e9d4914SAndroid Build Coastguard Worker case CONFIG_TYPE_INT:
17*2e9d4914SAndroid Build Coastguard Worker return LONG2FIX(config_setting_get_int(setting));
18*2e9d4914SAndroid Build Coastguard Worker
19*2e9d4914SAndroid Build Coastguard Worker case CONFIG_TYPE_INT64:
20*2e9d4914SAndroid Build Coastguard Worker return rb_ll2inum(config_setting_get_int64(setting));
21*2e9d4914SAndroid Build Coastguard Worker
22*2e9d4914SAndroid Build Coastguard Worker case CONFIG_TYPE_FLOAT:
23*2e9d4914SAndroid Build Coastguard Worker return rb_float_new(config_setting_get_float(setting));
24*2e9d4914SAndroid Build Coastguard Worker
25*2e9d4914SAndroid Build Coastguard Worker case CONFIG_TYPE_STRING:
26*2e9d4914SAndroid Build Coastguard Worker return rb_str_new2(config_setting_get_string(setting));
27*2e9d4914SAndroid Build Coastguard Worker
28*2e9d4914SAndroid Build Coastguard Worker case CONFIG_TYPE_BOOL:
29*2e9d4914SAndroid Build Coastguard Worker return config_setting_get_bool(setting) ? Qtrue : Qfalse;
30*2e9d4914SAndroid Build Coastguard Worker
31*2e9d4914SAndroid Build Coastguard Worker default:
32*2e9d4914SAndroid Build Coastguard Worker rb_bug("unknown value type %d", config_setting_type(setting));
33*2e9d4914SAndroid Build Coastguard Worker }
34*2e9d4914SAndroid Build Coastguard Worker }
35*2e9d4914SAndroid Build Coastguard Worker
rconfig_free_setting(config_setting_t * setting)36*2e9d4914SAndroid Build Coastguard Worker static void rconfig_free_setting(config_setting_t* setting)
37*2e9d4914SAndroid Build Coastguard Worker {
38*2e9d4914SAndroid Build Coastguard Worker // dummy
39*2e9d4914SAndroid Build Coastguard Worker }
40*2e9d4914SAndroid Build Coastguard Worker
rconfig_prepare_setting(config_setting_t * setting)41*2e9d4914SAndroid Build Coastguard Worker static VALUE rconfig_prepare_setting(config_setting_t* setting)
42*2e9d4914SAndroid Build Coastguard Worker {
43*2e9d4914SAndroid Build Coastguard Worker VALUE wrapper = Data_Wrap_Struct(rb_cObject, 0, rconfig_free_setting, setting);
44*2e9d4914SAndroid Build Coastguard Worker config_setting_set_hook(setting, (void*) wrapper);
45*2e9d4914SAndroid Build Coastguard Worker return wrapper;
46*2e9d4914SAndroid Build Coastguard Worker }
47*2e9d4914SAndroid Build Coastguard Worker
rconfig_destroy_setting(void * hook)48*2e9d4914SAndroid Build Coastguard Worker static void rconfig_destroy_setting(void* hook)
49*2e9d4914SAndroid Build Coastguard Worker {
50*2e9d4914SAndroid Build Coastguard Worker if(hook != NULL) {
51*2e9d4914SAndroid Build Coastguard Worker VALUE wrapper = (VALUE) hook;
52*2e9d4914SAndroid Build Coastguard Worker rb_iv_set(wrapper, "@setting", Qnil);
53*2e9d4914SAndroid Build Coastguard Worker }
54*2e9d4914SAndroid Build Coastguard Worker }
55*2e9d4914SAndroid Build Coastguard Worker
rconfig_wrap_setting(config_setting_t * setting)56*2e9d4914SAndroid Build Coastguard Worker static VALUE rconfig_wrap_setting(config_setting_t* setting)
57*2e9d4914SAndroid Build Coastguard Worker {
58*2e9d4914SAndroid Build Coastguard Worker VALUE rbSetting = rconfig_prepare_setting(setting);
59*2e9d4914SAndroid Build Coastguard Worker
60*2e9d4914SAndroid Build Coastguard Worker switch(config_setting_type(setting)) {
61*2e9d4914SAndroid Build Coastguard Worker case CONFIG_TYPE_INT:
62*2e9d4914SAndroid Build Coastguard Worker return rb_funcall(cConfigFixnum, rb_intern("new"), 2, LONG2FIX(config_setting_get_int(setting)), rbSetting);
63*2e9d4914SAndroid Build Coastguard Worker
64*2e9d4914SAndroid Build Coastguard Worker case CONFIG_TYPE_INT64:
65*2e9d4914SAndroid Build Coastguard Worker return rb_funcall(cConfigBignum, rb_intern("new"), 2, rb_ll2inum(config_setting_get_int64(setting)), rbSetting);
66*2e9d4914SAndroid Build Coastguard Worker
67*2e9d4914SAndroid Build Coastguard Worker case CONFIG_TYPE_FLOAT:
68*2e9d4914SAndroid Build Coastguard Worker return rb_funcall(cConfigFloat, rb_intern("new"), 2, rb_float_new(config_setting_get_float(setting)), rbSetting);
69*2e9d4914SAndroid Build Coastguard Worker
70*2e9d4914SAndroid Build Coastguard Worker case CONFIG_TYPE_STRING:
71*2e9d4914SAndroid Build Coastguard Worker return rb_funcall(cConfigString, rb_intern("new"), 2, rb_str_new2(config_setting_get_string(setting)), rbSetting);
72*2e9d4914SAndroid Build Coastguard Worker
73*2e9d4914SAndroid Build Coastguard Worker case CONFIG_TYPE_BOOL:
74*2e9d4914SAndroid Build Coastguard Worker return rb_funcall(cConfigBoolean, rb_intern("new"), 2, config_setting_get_bool(setting) ? Qtrue : Qfalse, rbSetting);
75*2e9d4914SAndroid Build Coastguard Worker
76*2e9d4914SAndroid Build Coastguard Worker case CONFIG_TYPE_ARRAY:
77*2e9d4914SAndroid Build Coastguard Worker return rb_funcall(cConfigArray, rb_intern("new"), 2, Qnil, rbSetting);
78*2e9d4914SAndroid Build Coastguard Worker
79*2e9d4914SAndroid Build Coastguard Worker case CONFIG_TYPE_LIST:
80*2e9d4914SAndroid Build Coastguard Worker return rb_funcall(cConfigList, rb_intern("new"), 1, rbSetting);
81*2e9d4914SAndroid Build Coastguard Worker
82*2e9d4914SAndroid Build Coastguard Worker case CONFIG_TYPE_GROUP:
83*2e9d4914SAndroid Build Coastguard Worker return rb_funcall(cConfigGroup, rb_intern("new"), 1, rbSetting);
84*2e9d4914SAndroid Build Coastguard Worker
85*2e9d4914SAndroid Build Coastguard Worker default:
86*2e9d4914SAndroid Build Coastguard Worker rb_bug("[r] unknown setting type %d", config_setting_type(setting));
87*2e9d4914SAndroid Build Coastguard Worker }
88*2e9d4914SAndroid Build Coastguard Worker }
89*2e9d4914SAndroid Build Coastguard Worker
rconfig_update_setting(config_setting_t * setting,VALUE value)90*2e9d4914SAndroid Build Coastguard Worker static void rconfig_update_setting(config_setting_t* setting, VALUE value)
91*2e9d4914SAndroid Build Coastguard Worker {
92*2e9d4914SAndroid Build Coastguard Worker switch(config_setting_type(setting)) {
93*2e9d4914SAndroid Build Coastguard Worker case CONFIG_TYPE_INT:
94*2e9d4914SAndroid Build Coastguard Worker config_setting_set_int(setting, FIX2LONG(value));
95*2e9d4914SAndroid Build Coastguard Worker break;
96*2e9d4914SAndroid Build Coastguard Worker
97*2e9d4914SAndroid Build Coastguard Worker case CONFIG_TYPE_INT64:
98*2e9d4914SAndroid Build Coastguard Worker if(TYPE(value) == T_BIGNUM)
99*2e9d4914SAndroid Build Coastguard Worker config_setting_set_int64(setting, rb_big2ll(value));
100*2e9d4914SAndroid Build Coastguard Worker else // T_FIXNUM
101*2e9d4914SAndroid Build Coastguard Worker config_setting_set_int64(setting, FIX2INT(value));
102*2e9d4914SAndroid Build Coastguard Worker break;
103*2e9d4914SAndroid Build Coastguard Worker
104*2e9d4914SAndroid Build Coastguard Worker case CONFIG_TYPE_FLOAT:
105*2e9d4914SAndroid Build Coastguard Worker // ruby1.9 check
106*2e9d4914SAndroid Build Coastguard Worker #if HAVE_RB_BLOCK_CALL
107*2e9d4914SAndroid Build Coastguard Worker config_setting_set_float(setting, RFLOAT_VALUE(value));
108*2e9d4914SAndroid Build Coastguard Worker #else
109*2e9d4914SAndroid Build Coastguard Worker config_setting_set_float(setting, RFLOAT_VALUE(value));
110*2e9d4914SAndroid Build Coastguard Worker #endif
111*2e9d4914SAndroid Build Coastguard Worker break;
112*2e9d4914SAndroid Build Coastguard Worker
113*2e9d4914SAndroid Build Coastguard Worker case CONFIG_TYPE_STRING:
114*2e9d4914SAndroid Build Coastguard Worker config_setting_set_string(setting, RSTRING_PTR(value));
115*2e9d4914SAndroid Build Coastguard Worker break;
116*2e9d4914SAndroid Build Coastguard Worker
117*2e9d4914SAndroid Build Coastguard Worker case CONFIG_TYPE_BOOL:
118*2e9d4914SAndroid Build Coastguard Worker config_setting_set_bool(setting, value == Qtrue);
119*2e9d4914SAndroid Build Coastguard Worker break;
120*2e9d4914SAndroid Build Coastguard Worker
121*2e9d4914SAndroid Build Coastguard Worker default:
122*2e9d4914SAndroid Build Coastguard Worker rb_bug("[w] unknown setting type %d", config_setting_type(setting));
123*2e9d4914SAndroid Build Coastguard Worker }
124*2e9d4914SAndroid Build Coastguard Worker }
125*2e9d4914SAndroid Build Coastguard Worker
rconfig_check_setting_type(VALUE object,VALUE value)126*2e9d4914SAndroid Build Coastguard Worker static void rconfig_check_setting_type(VALUE object, VALUE value)
127*2e9d4914SAndroid Build Coastguard Worker {
128*2e9d4914SAndroid Build Coastguard Worker if(rb_obj_class(object) == cConfigFixnum) {
129*2e9d4914SAndroid Build Coastguard Worker Check_Type(value, T_FIXNUM);
130*2e9d4914SAndroid Build Coastguard Worker } else if(rb_obj_class(object) == cConfigBignum) {
131*2e9d4914SAndroid Build Coastguard Worker if(TYPE(value) != T_BIGNUM && TYPE(value) != T_FIXNUM)
132*2e9d4914SAndroid Build Coastguard Worker rb_raise(rb_eTypeError, "wrong argument type %s (expected Fixnum or Bignum)", rb_obj_classname(value));
133*2e9d4914SAndroid Build Coastguard Worker } else if(rb_obj_class(object) == cConfigFloat) {
134*2e9d4914SAndroid Build Coastguard Worker Check_Type(value, T_FLOAT);
135*2e9d4914SAndroid Build Coastguard Worker } else if(rb_obj_class(object) == cConfigString) {
136*2e9d4914SAndroid Build Coastguard Worker Check_Type(value, T_STRING);
137*2e9d4914SAndroid Build Coastguard Worker } else if(rb_obj_class(object) == cConfigBoolean) {
138*2e9d4914SAndroid Build Coastguard Worker if(value != Qtrue && value != Qfalse)
139*2e9d4914SAndroid Build Coastguard Worker rb_raise(rb_eTypeError, "wrong argument type %s (expected boolean)", rb_obj_classname(value));
140*2e9d4914SAndroid Build Coastguard Worker } else {
141*2e9d4914SAndroid Build Coastguard Worker rb_raise(rb_eException, "never use Config::Setting itself");
142*2e9d4914SAndroid Build Coastguard Worker }
143*2e9d4914SAndroid Build Coastguard Worker }
144*2e9d4914SAndroid Build Coastguard Worker
rconfig_do_append(config_setting_t * setting,VALUE target,VALUE name)145*2e9d4914SAndroid Build Coastguard Worker static int rconfig_do_append(config_setting_t* setting, VALUE target, VALUE name)
146*2e9d4914SAndroid Build Coastguard Worker {
147*2e9d4914SAndroid Build Coastguard Worker int type;
148*2e9d4914SAndroid Build Coastguard Worker if(rb_obj_class(target) == cConfigFixnum)
149*2e9d4914SAndroid Build Coastguard Worker type = CONFIG_TYPE_INT;
150*2e9d4914SAndroid Build Coastguard Worker else if(rb_obj_class(target) == cConfigBignum)
151*2e9d4914SAndroid Build Coastguard Worker type = CONFIG_TYPE_INT64;
152*2e9d4914SAndroid Build Coastguard Worker else if(rb_obj_class(target) == cConfigFloat)
153*2e9d4914SAndroid Build Coastguard Worker type = CONFIG_TYPE_FLOAT;
154*2e9d4914SAndroid Build Coastguard Worker else if(rb_obj_class(target) == cConfigString)
155*2e9d4914SAndroid Build Coastguard Worker type = CONFIG_TYPE_STRING;
156*2e9d4914SAndroid Build Coastguard Worker else if(rb_obj_class(target) == cConfigBoolean)
157*2e9d4914SAndroid Build Coastguard Worker type = CONFIG_TYPE_BOOL;
158*2e9d4914SAndroid Build Coastguard Worker else if(rb_obj_class(target) == cConfigGroup)
159*2e9d4914SAndroid Build Coastguard Worker type = CONFIG_TYPE_GROUP;
160*2e9d4914SAndroid Build Coastguard Worker else if(rb_obj_class(target) == cConfigList)
161*2e9d4914SAndroid Build Coastguard Worker type = CONFIG_TYPE_LIST;
162*2e9d4914SAndroid Build Coastguard Worker else if(rb_obj_class(target) == cConfigArray)
163*2e9d4914SAndroid Build Coastguard Worker type = CONFIG_TYPE_ARRAY;
164*2e9d4914SAndroid Build Coastguard Worker else
165*2e9d4914SAndroid Build Coastguard Worker rb_bug("unknown setting class %s", rb_obj_classname(target));
166*2e9d4914SAndroid Build Coastguard Worker
167*2e9d4914SAndroid Build Coastguard Worker config_setting_t* new_setting;
168*2e9d4914SAndroid Build Coastguard Worker if(name == Qnil) {
169*2e9d4914SAndroid Build Coastguard Worker new_setting = config_setting_add(setting, NULL, type);
170*2e9d4914SAndroid Build Coastguard Worker } else {
171*2e9d4914SAndroid Build Coastguard Worker Check_Type(name, T_STRING);
172*2e9d4914SAndroid Build Coastguard Worker new_setting = config_setting_add(setting, RSTRING_PTR(name), type);
173*2e9d4914SAndroid Build Coastguard Worker }
174*2e9d4914SAndroid Build Coastguard Worker
175*2e9d4914SAndroid Build Coastguard Worker if(new_setting == NULL)
176*2e9d4914SAndroid Build Coastguard Worker return 0;
177*2e9d4914SAndroid Build Coastguard Worker
178*2e9d4914SAndroid Build Coastguard Worker VALUE rbNewSetting = rconfig_prepare_setting(new_setting);
179*2e9d4914SAndroid Build Coastguard Worker rb_iv_set(target, "@setting", rbNewSetting);
180*2e9d4914SAndroid Build Coastguard Worker
181*2e9d4914SAndroid Build Coastguard Worker if(rb_ary_includes(aConfigScalars, rb_obj_class(target)) == Qtrue)
182*2e9d4914SAndroid Build Coastguard Worker rconfig_update_setting(new_setting, rb_iv_get(target, "@value"));
183*2e9d4914SAndroid Build Coastguard Worker
184*2e9d4914SAndroid Build Coastguard Worker if(rb_ary_includes(aConfigAggregates, rb_obj_class(target)) == Qtrue) {
185*2e9d4914SAndroid Build Coastguard Worker if(rb_obj_class(target) == cConfigGroup) {
186*2e9d4914SAndroid Build Coastguard Worker VALUE hash = rb_iv_get(target, "@hash");
187*2e9d4914SAndroid Build Coastguard Worker VALUE children = rb_funcall(hash, rb_intern("keys"), 0);
188*2e9d4914SAndroid Build Coastguard Worker int i;
189*2e9d4914SAndroid Build Coastguard Worker for(i = 0; i < RARRAY_LEN(children); i++) {
190*2e9d4914SAndroid Build Coastguard Worker VALUE key = RARRAY_PTR(children)[i];
191*2e9d4914SAndroid Build Coastguard Worker rconfig_do_append(new_setting, rb_hash_aref(hash, key), key);
192*2e9d4914SAndroid Build Coastguard Worker }
193*2e9d4914SAndroid Build Coastguard Worker } else {
194*2e9d4914SAndroid Build Coastguard Worker VALUE children = rb_iv_get(target, "@list");
195*2e9d4914SAndroid Build Coastguard Worker int i;
196*2e9d4914SAndroid Build Coastguard Worker for(i = 0; i < RARRAY_LEN(children); i++) {
197*2e9d4914SAndroid Build Coastguard Worker rconfig_do_append(new_setting, RARRAY_PTR(children)[i], Qnil);
198*2e9d4914SAndroid Build Coastguard Worker }
199*2e9d4914SAndroid Build Coastguard Worker }
200*2e9d4914SAndroid Build Coastguard Worker }
201*2e9d4914SAndroid Build Coastguard Worker
202*2e9d4914SAndroid Build Coastguard Worker return 1;
203*2e9d4914SAndroid Build Coastguard Worker }
204*2e9d4914SAndroid Build Coastguard Worker
rbConfigBaseSetting_initialize(VALUE self,VALUE setting)205*2e9d4914SAndroid Build Coastguard Worker static VALUE rbConfigBaseSetting_initialize(VALUE self, VALUE setting)
206*2e9d4914SAndroid Build Coastguard Worker {
207*2e9d4914SAndroid Build Coastguard Worker if(setting != Qnil)
208*2e9d4914SAndroid Build Coastguard Worker Check_Type(setting, T_DATA);
209*2e9d4914SAndroid Build Coastguard Worker rb_iv_set(self, "@setting", setting);
210*2e9d4914SAndroid Build Coastguard Worker
211*2e9d4914SAndroid Build Coastguard Worker return self;
212*2e9d4914SAndroid Build Coastguard Worker }
213*2e9d4914SAndroid Build Coastguard Worker
rbConfigBaseSetting_name(VALUE self)214*2e9d4914SAndroid Build Coastguard Worker static VALUE rbConfigBaseSetting_name(VALUE self)
215*2e9d4914SAndroid Build Coastguard Worker {
216*2e9d4914SAndroid Build Coastguard Worker if(rb_iv_get(self, "@setting") != Qnil) {
217*2e9d4914SAndroid Build Coastguard Worker config_setting_t* setting = NULL;
218*2e9d4914SAndroid Build Coastguard Worker Data_Get_Struct(rb_iv_get(self, "@setting"), config_setting_t, setting);
219*2e9d4914SAndroid Build Coastguard Worker return rb_str_new2(config_setting_name(setting));
220*2e9d4914SAndroid Build Coastguard Worker } else {
221*2e9d4914SAndroid Build Coastguard Worker return Qnil;
222*2e9d4914SAndroid Build Coastguard Worker }
223*2e9d4914SAndroid Build Coastguard Worker }
224*2e9d4914SAndroid Build Coastguard Worker
rbConfigBaseSetting_parent(VALUE self)225*2e9d4914SAndroid Build Coastguard Worker static VALUE rbConfigBaseSetting_parent(VALUE self)
226*2e9d4914SAndroid Build Coastguard Worker {
227*2e9d4914SAndroid Build Coastguard Worker if(rb_iv_get(self, "@setting") != Qnil) {
228*2e9d4914SAndroid Build Coastguard Worker config_setting_t* setting = NULL;
229*2e9d4914SAndroid Build Coastguard Worker Data_Get_Struct(rb_iv_get(self, "@setting"), config_setting_t, setting);
230*2e9d4914SAndroid Build Coastguard Worker return rconfig_wrap_setting(config_setting_parent(setting));
231*2e9d4914SAndroid Build Coastguard Worker } else {
232*2e9d4914SAndroid Build Coastguard Worker return Qnil;
233*2e9d4914SAndroid Build Coastguard Worker }
234*2e9d4914SAndroid Build Coastguard Worker }
235*2e9d4914SAndroid Build Coastguard Worker
rbConfigBaseSetting_is_root(VALUE self)236*2e9d4914SAndroid Build Coastguard Worker static VALUE rbConfigBaseSetting_is_root(VALUE self)
237*2e9d4914SAndroid Build Coastguard Worker {
238*2e9d4914SAndroid Build Coastguard Worker if(rb_iv_get(self, "@setting") != Qnil) {
239*2e9d4914SAndroid Build Coastguard Worker config_setting_t* setting = NULL;
240*2e9d4914SAndroid Build Coastguard Worker Data_Get_Struct(rb_iv_get(self, "@setting"), config_setting_t, setting);
241*2e9d4914SAndroid Build Coastguard Worker return config_setting_is_root(setting) ? Qtrue : Qfalse;
242*2e9d4914SAndroid Build Coastguard Worker } else {
243*2e9d4914SAndroid Build Coastguard Worker return Qnil;
244*2e9d4914SAndroid Build Coastguard Worker }
245*2e9d4914SAndroid Build Coastguard Worker }
246*2e9d4914SAndroid Build Coastguard Worker
rbConfigBaseSetting_index(VALUE self)247*2e9d4914SAndroid Build Coastguard Worker static VALUE rbConfigBaseSetting_index(VALUE self)
248*2e9d4914SAndroid Build Coastguard Worker {
249*2e9d4914SAndroid Build Coastguard Worker if(rb_iv_get(self, "@setting") != Qnil) {
250*2e9d4914SAndroid Build Coastguard Worker config_setting_t* setting = NULL;
251*2e9d4914SAndroid Build Coastguard Worker Data_Get_Struct(rb_iv_get(self, "@setting"), config_setting_t, setting);
252*2e9d4914SAndroid Build Coastguard Worker return INT2FIX(config_setting_index(setting));
253*2e9d4914SAndroid Build Coastguard Worker } else {
254*2e9d4914SAndroid Build Coastguard Worker return Qnil;
255*2e9d4914SAndroid Build Coastguard Worker }
256*2e9d4914SAndroid Build Coastguard Worker }
257*2e9d4914SAndroid Build Coastguard Worker
rbConfigBaseSetting_line(VALUE self)258*2e9d4914SAndroid Build Coastguard Worker static VALUE rbConfigBaseSetting_line(VALUE self)
259*2e9d4914SAndroid Build Coastguard Worker {
260*2e9d4914SAndroid Build Coastguard Worker if(rb_iv_get(self, "@setting") != Qnil) {
261*2e9d4914SAndroid Build Coastguard Worker config_setting_t* setting = NULL;
262*2e9d4914SAndroid Build Coastguard Worker Data_Get_Struct(rb_iv_get(self, "@setting"), config_setting_t, setting);
263*2e9d4914SAndroid Build Coastguard Worker return INT2FIX(config_setting_source_line(setting));
264*2e9d4914SAndroid Build Coastguard Worker } else {
265*2e9d4914SAndroid Build Coastguard Worker return Qnil;
266*2e9d4914SAndroid Build Coastguard Worker }
267*2e9d4914SAndroid Build Coastguard Worker }
268*2e9d4914SAndroid Build Coastguard Worker
rbConfigSetting_initialize(int argc,VALUE * argv,VALUE self)269*2e9d4914SAndroid Build Coastguard Worker static VALUE rbConfigSetting_initialize(int argc, VALUE* argv, VALUE self)
270*2e9d4914SAndroid Build Coastguard Worker {
271*2e9d4914SAndroid Build Coastguard Worker VALUE value, setting;
272*2e9d4914SAndroid Build Coastguard Worker rb_scan_args(argc, argv, "11", &value, &setting);
273*2e9d4914SAndroid Build Coastguard Worker
274*2e9d4914SAndroid Build Coastguard Worker rb_call_super(1, &setting);
275*2e9d4914SAndroid Build Coastguard Worker
276*2e9d4914SAndroid Build Coastguard Worker rconfig_check_setting_type(self, value);
277*2e9d4914SAndroid Build Coastguard Worker rb_iv_set(self, "@value", value);
278*2e9d4914SAndroid Build Coastguard Worker
279*2e9d4914SAndroid Build Coastguard Worker if(rb_iv_get(self, "@setting") != Qnil) {
280*2e9d4914SAndroid Build Coastguard Worker config_setting_t* c_setting = NULL;
281*2e9d4914SAndroid Build Coastguard Worker Data_Get_Struct(rb_iv_get(self, "@setting"), config_setting_t, c_setting);
282*2e9d4914SAndroid Build Coastguard Worker rb_iv_set(self, "@format", INT2FIX(config_setting_get_format(c_setting)));
283*2e9d4914SAndroid Build Coastguard Worker } else {
284*2e9d4914SAndroid Build Coastguard Worker rb_iv_set(self, "@format", cConfigFormatDefault);
285*2e9d4914SAndroid Build Coastguard Worker }
286*2e9d4914SAndroid Build Coastguard Worker
287*2e9d4914SAndroid Build Coastguard Worker return self;
288*2e9d4914SAndroid Build Coastguard Worker }
289*2e9d4914SAndroid Build Coastguard Worker
rbConfigSetting_get_value(VALUE self)290*2e9d4914SAndroid Build Coastguard Worker static VALUE rbConfigSetting_get_value(VALUE self)
291*2e9d4914SAndroid Build Coastguard Worker {
292*2e9d4914SAndroid Build Coastguard Worker if(rb_iv_get(self, "@setting") != Qnil) {
293*2e9d4914SAndroid Build Coastguard Worker config_setting_t* setting;
294*2e9d4914SAndroid Build Coastguard Worker Data_Get_Struct(rb_iv_get(self, "@setting"), config_setting_t, setting);
295*2e9d4914SAndroid Build Coastguard Worker return rconfig_wrap_value(setting);
296*2e9d4914SAndroid Build Coastguard Worker } else {
297*2e9d4914SAndroid Build Coastguard Worker return rb_iv_get(self, "@value");
298*2e9d4914SAndroid Build Coastguard Worker }
299*2e9d4914SAndroid Build Coastguard Worker }
300*2e9d4914SAndroid Build Coastguard Worker
rbConfigSetting_set_value(VALUE self,VALUE new_value)301*2e9d4914SAndroid Build Coastguard Worker static VALUE rbConfigSetting_set_value(VALUE self, VALUE new_value)
302*2e9d4914SAndroid Build Coastguard Worker {
303*2e9d4914SAndroid Build Coastguard Worker rconfig_check_setting_type(self, new_value);
304*2e9d4914SAndroid Build Coastguard Worker
305*2e9d4914SAndroid Build Coastguard Worker if(rb_iv_get(self, "@setting") != Qnil) {
306*2e9d4914SAndroid Build Coastguard Worker config_setting_t* setting;
307*2e9d4914SAndroid Build Coastguard Worker Data_Get_Struct(rb_iv_get(self, "@setting"), config_setting_t, setting);
308*2e9d4914SAndroid Build Coastguard Worker rconfig_update_setting(setting, new_value);
309*2e9d4914SAndroid Build Coastguard Worker }
310*2e9d4914SAndroid Build Coastguard Worker
311*2e9d4914SAndroid Build Coastguard Worker rb_iv_set(self, "@value", new_value);
312*2e9d4914SAndroid Build Coastguard Worker
313*2e9d4914SAndroid Build Coastguard Worker return new_value;
314*2e9d4914SAndroid Build Coastguard Worker }
315*2e9d4914SAndroid Build Coastguard Worker
rbConfigSetting_get_format(VALUE self)316*2e9d4914SAndroid Build Coastguard Worker static VALUE rbConfigSetting_get_format(VALUE self)
317*2e9d4914SAndroid Build Coastguard Worker {
318*2e9d4914SAndroid Build Coastguard Worker if(rb_iv_get(self, "@setting") != Qnil) {
319*2e9d4914SAndroid Build Coastguard Worker config_setting_t* setting;
320*2e9d4914SAndroid Build Coastguard Worker Data_Get_Struct(rb_iv_get(self, "@setting"), config_setting_t, setting);
321*2e9d4914SAndroid Build Coastguard Worker return INT2FIX(config_setting_get_format(setting));
322*2e9d4914SAndroid Build Coastguard Worker } else {
323*2e9d4914SAndroid Build Coastguard Worker return rb_iv_get(self, "format");
324*2e9d4914SAndroid Build Coastguard Worker }
325*2e9d4914SAndroid Build Coastguard Worker }
326*2e9d4914SAndroid Build Coastguard Worker
rbConfigSetting_set_format(VALUE self,VALUE new_format)327*2e9d4914SAndroid Build Coastguard Worker static VALUE rbConfigSetting_set_format(VALUE self, VALUE new_format)
328*2e9d4914SAndroid Build Coastguard Worker {
329*2e9d4914SAndroid Build Coastguard Worker if(rb_iv_get(self, "@setting") != Qnil) {
330*2e9d4914SAndroid Build Coastguard Worker config_setting_t* setting;
331*2e9d4914SAndroid Build Coastguard Worker Data_Get_Struct(rb_iv_get(self, "@setting"), config_setting_t, setting);
332*2e9d4914SAndroid Build Coastguard Worker if(!config_setting_set_format(setting, FIX2INT(new_format)))
333*2e9d4914SAndroid Build Coastguard Worker rb_raise(eSettingFormatError, "invalid setting format %d", FIX2INT(new_format));
334*2e9d4914SAndroid Build Coastguard Worker }
335*2e9d4914SAndroid Build Coastguard Worker
336*2e9d4914SAndroid Build Coastguard Worker rb_iv_set(self, "@format", new_format);
337*2e9d4914SAndroid Build Coastguard Worker
338*2e9d4914SAndroid Build Coastguard Worker return new_format;
339*2e9d4914SAndroid Build Coastguard Worker }
340*2e9d4914SAndroid Build Coastguard Worker
341*2e9d4914SAndroid Build Coastguard Worker static VALUE rbConfigAggregate_get(VALUE self, VALUE index);
342*2e9d4914SAndroid Build Coastguard Worker
rbConfigAggregate_initialize(int argc,VALUE * argv,VALUE self)343*2e9d4914SAndroid Build Coastguard Worker static VALUE rbConfigAggregate_initialize(int argc, VALUE* argv, VALUE self)
344*2e9d4914SAndroid Build Coastguard Worker {
345*2e9d4914SAndroid Build Coastguard Worker VALUE setting = Qnil;
346*2e9d4914SAndroid Build Coastguard Worker if(rb_obj_class(self) == cConfigGroup || rb_obj_class(self) == cConfigList) {
347*2e9d4914SAndroid Build Coastguard Worker rb_scan_args(argc, argv, "01", &setting);
348*2e9d4914SAndroid Build Coastguard Worker } else if(rb_obj_class(self) == cConfigArray) {
349*2e9d4914SAndroid Build Coastguard Worker VALUE type = Qnil;
350*2e9d4914SAndroid Build Coastguard Worker rb_scan_args(argc, argv, "02", &type, &setting);
351*2e9d4914SAndroid Build Coastguard Worker
352*2e9d4914SAndroid Build Coastguard Worker if(type != Qnil && rb_ary_includes(aConfigScalars, type) != Qtrue)
353*2e9d4914SAndroid Build Coastguard Worker rb_raise(rb_eTypeError, "invalid setting array type %s", rb_class2name(type));
354*2e9d4914SAndroid Build Coastguard Worker
355*2e9d4914SAndroid Build Coastguard Worker rb_iv_set(self, "@type", type);
356*2e9d4914SAndroid Build Coastguard Worker } else {
357*2e9d4914SAndroid Build Coastguard Worker rb_raise(rb_eException, "never create Config::Aggregate itself");
358*2e9d4914SAndroid Build Coastguard Worker }
359*2e9d4914SAndroid Build Coastguard Worker
360*2e9d4914SAndroid Build Coastguard Worker rb_call_super(1, &setting);
361*2e9d4914SAndroid Build Coastguard Worker
362*2e9d4914SAndroid Build Coastguard Worker rb_iv_set(self, "@list", rb_ary_new());
363*2e9d4914SAndroid Build Coastguard Worker if(rb_obj_class(self) == cConfigGroup)
364*2e9d4914SAndroid Build Coastguard Worker rb_iv_set(self, "@hash", rb_hash_new());
365*2e9d4914SAndroid Build Coastguard Worker
366*2e9d4914SAndroid Build Coastguard Worker if(setting != Qnil && rb_obj_class(self) == cConfigArray) {
367*2e9d4914SAndroid Build Coastguard Worker config_setting_t* c_setting;
368*2e9d4914SAndroid Build Coastguard Worker Data_Get_Struct(setting, config_setting_t, c_setting);
369*2e9d4914SAndroid Build Coastguard Worker if(config_setting_length(c_setting) > 0)
370*2e9d4914SAndroid Build Coastguard Worker rb_iv_set(self, "@type", rb_obj_class(rbConfigAggregate_get(self, INT2FIX(0))));
371*2e9d4914SAndroid Build Coastguard Worker }
372*2e9d4914SAndroid Build Coastguard Worker
373*2e9d4914SAndroid Build Coastguard Worker return self;
374*2e9d4914SAndroid Build Coastguard Worker }
375*2e9d4914SAndroid Build Coastguard Worker
rbConfigAggregate_size(VALUE self)376*2e9d4914SAndroid Build Coastguard Worker static VALUE rbConfigAggregate_size(VALUE self)
377*2e9d4914SAndroid Build Coastguard Worker {
378*2e9d4914SAndroid Build Coastguard Worker config_setting_t* setting = NULL;
379*2e9d4914SAndroid Build Coastguard Worker if(rb_iv_get(self, "@setting") != Qnil)
380*2e9d4914SAndroid Build Coastguard Worker Data_Get_Struct(rb_iv_get(self, "@setting"), config_setting_t, setting);
381*2e9d4914SAndroid Build Coastguard Worker
382*2e9d4914SAndroid Build Coastguard Worker if(setting)
383*2e9d4914SAndroid Build Coastguard Worker return INT2FIX(config_setting_length(setting));
384*2e9d4914SAndroid Build Coastguard Worker else
385*2e9d4914SAndroid Build Coastguard Worker return INT2FIX(RARRAY_LEN(rb_iv_get(self, "@list")));
386*2e9d4914SAndroid Build Coastguard Worker }
387*2e9d4914SAndroid Build Coastguard Worker
rbConfigAggregate_get(VALUE self,VALUE index)388*2e9d4914SAndroid Build Coastguard Worker static VALUE rbConfigAggregate_get(VALUE self, VALUE index)
389*2e9d4914SAndroid Build Coastguard Worker {
390*2e9d4914SAndroid Build Coastguard Worker config_setting_t* setting = NULL;
391*2e9d4914SAndroid Build Coastguard Worker if(rb_iv_get(self, "@setting") != Qnil)
392*2e9d4914SAndroid Build Coastguard Worker Data_Get_Struct(rb_iv_get(self, "@setting"), config_setting_t, setting);
393*2e9d4914SAndroid Build Coastguard Worker
394*2e9d4914SAndroid Build Coastguard Worker VALUE rbTarget = Qnil;
395*2e9d4914SAndroid Build Coastguard Worker
396*2e9d4914SAndroid Build Coastguard Worker if(TYPE(index) == T_STRING && rb_obj_class(self) == cConfigGroup) {
397*2e9d4914SAndroid Build Coastguard Worker if(setting) {
398*2e9d4914SAndroid Build Coastguard Worker config_setting_t* target = config_setting_get_member(setting, RSTRING_PTR(index));
399*2e9d4914SAndroid Build Coastguard Worker if(target)
400*2e9d4914SAndroid Build Coastguard Worker rbTarget = rconfig_wrap_setting(target);
401*2e9d4914SAndroid Build Coastguard Worker } else {
402*2e9d4914SAndroid Build Coastguard Worker rbTarget = rb_hash_aref(rb_iv_get(self, "@hash"), index);
403*2e9d4914SAndroid Build Coastguard Worker }
404*2e9d4914SAndroid Build Coastguard Worker } else if(TYPE(index) == T_FIXNUM) {
405*2e9d4914SAndroid Build Coastguard Worker if(setting) {
406*2e9d4914SAndroid Build Coastguard Worker config_setting_t* target = config_setting_get_elem(setting, FIX2INT(index));
407*2e9d4914SAndroid Build Coastguard Worker if(target)
408*2e9d4914SAndroid Build Coastguard Worker rbTarget = rconfig_wrap_setting(target);
409*2e9d4914SAndroid Build Coastguard Worker } else {
410*2e9d4914SAndroid Build Coastguard Worker rbTarget = rb_ary_entry(rb_iv_get(self, "@list"), FIX2INT(index));
411*2e9d4914SAndroid Build Coastguard Worker }
412*2e9d4914SAndroid Build Coastguard Worker } else {
413*2e9d4914SAndroid Build Coastguard Worker rb_raise(rb_eTypeError, "wrong argument type %s (expected String or Fixnum)", rb_obj_classname(index));
414*2e9d4914SAndroid Build Coastguard Worker }
415*2e9d4914SAndroid Build Coastguard Worker
416*2e9d4914SAndroid Build Coastguard Worker if(rbTarget == Qnil)
417*2e9d4914SAndroid Build Coastguard Worker if(TYPE(index) == T_STRING)
418*2e9d4914SAndroid Build Coastguard Worker rb_raise(eSettingNotFoundError, "setting `%s' not found", RSTRING_PTR(index));
419*2e9d4914SAndroid Build Coastguard Worker else
420*2e9d4914SAndroid Build Coastguard Worker rb_raise(eSettingNotFoundError, "setting [%d] not found", FIX2INT(index));
421*2e9d4914SAndroid Build Coastguard Worker
422*2e9d4914SAndroid Build Coastguard Worker return rbTarget;
423*2e9d4914SAndroid Build Coastguard Worker }
424*2e9d4914SAndroid Build Coastguard Worker
rbConfigAggregate_append(VALUE self,VALUE target)425*2e9d4914SAndroid Build Coastguard Worker static VALUE rbConfigAggregate_append(VALUE self, VALUE target)
426*2e9d4914SAndroid Build Coastguard Worker {
427*2e9d4914SAndroid Build Coastguard Worker config_setting_t* setting = NULL;
428*2e9d4914SAndroid Build Coastguard Worker if(rb_iv_get(self, "@setting") != Qnil)
429*2e9d4914SAndroid Build Coastguard Worker Data_Get_Struct(rb_iv_get(self, "@setting"), config_setting_t, setting);
430*2e9d4914SAndroid Build Coastguard Worker
431*2e9d4914SAndroid Build Coastguard Worker Check_Type(target, T_OBJECT);
432*2e9d4914SAndroid Build Coastguard Worker
433*2e9d4914SAndroid Build Coastguard Worker VALUE type = rb_iv_get(self, "@type");
434*2e9d4914SAndroid Build Coastguard Worker if(rb_obj_class(self) == cConfigArray) {
435*2e9d4914SAndroid Build Coastguard Worker if(type != Qnil && type != rb_obj_class(target))
436*2e9d4914SAndroid Build Coastguard Worker rb_raise(rb_eTypeError, "wrong argument type %s (expected %s)", rb_obj_classname(target), rb_class2name(type));
437*2e9d4914SAndroid Build Coastguard Worker if(type == Qnil && rb_ary_includes(aConfigScalars, rb_obj_class(target)) != Qtrue)
438*2e9d4914SAndroid Build Coastguard Worker rb_raise(rb_eTypeError, "invalid setting array type %s", rb_obj_classname(target));
439*2e9d4914SAndroid Build Coastguard Worker }
440*2e9d4914SAndroid Build Coastguard Worker
441*2e9d4914SAndroid Build Coastguard Worker if(rb_ary_includes(aConfigSettings, rb_obj_class(target)) == Qtrue) {
442*2e9d4914SAndroid Build Coastguard Worker if(setting)
443*2e9d4914SAndroid Build Coastguard Worker rconfig_do_append(setting, target, Qnil);
444*2e9d4914SAndroid Build Coastguard Worker rb_ary_push(rb_iv_get(self, "@list"), target);
445*2e9d4914SAndroid Build Coastguard Worker } else {
446*2e9d4914SAndroid Build Coastguard Worker rb_raise(rb_eTypeError, "wrong argument type %s (expected Config::BaseSetting)", rb_obj_classname(target));
447*2e9d4914SAndroid Build Coastguard Worker }
448*2e9d4914SAndroid Build Coastguard Worker
449*2e9d4914SAndroid Build Coastguard Worker if(rb_obj_class(self) == cConfigArray && type == Qnil)
450*2e9d4914SAndroid Build Coastguard Worker rb_iv_set(self, "@type", rb_obj_class(target));
451*2e9d4914SAndroid Build Coastguard Worker
452*2e9d4914SAndroid Build Coastguard Worker return target;
453*2e9d4914SAndroid Build Coastguard Worker }
454*2e9d4914SAndroid Build Coastguard Worker
rbConfigGroup_append(VALUE self,VALUE name,VALUE target)455*2e9d4914SAndroid Build Coastguard Worker static VALUE rbConfigGroup_append(VALUE self, VALUE name, VALUE target)
456*2e9d4914SAndroid Build Coastguard Worker {
457*2e9d4914SAndroid Build Coastguard Worker Check_Type(name, T_STRING);
458*2e9d4914SAndroid Build Coastguard Worker Check_Type(target, T_OBJECT);
459*2e9d4914SAndroid Build Coastguard Worker
460*2e9d4914SAndroid Build Coastguard Worker config_setting_t* setting = NULL;
461*2e9d4914SAndroid Build Coastguard Worker if(rb_iv_get(self, "@setting") != Qnil)
462*2e9d4914SAndroid Build Coastguard Worker Data_Get_Struct(rb_iv_get(self, "@setting"), config_setting_t, setting);
463*2e9d4914SAndroid Build Coastguard Worker
464*2e9d4914SAndroid Build Coastguard Worker if(rb_ary_includes(aConfigSettings, rb_obj_class(target)) == Qtrue) {
465*2e9d4914SAndroid Build Coastguard Worker if(rb_reg_match(rSettingNameRegexp, name) == Qnil)
466*2e9d4914SAndroid Build Coastguard Worker rb_raise(eSettingNameError, "setting name `%s' contains invalid characters", RSTRING_PTR(name));
467*2e9d4914SAndroid Build Coastguard Worker if(setting) {
468*2e9d4914SAndroid Build Coastguard Worker if(!rconfig_do_append(setting, target, name))
469*2e9d4914SAndroid Build Coastguard Worker rb_raise(eSettingNameError, "setting `%s' already exists", RSTRING_PTR(name));
470*2e9d4914SAndroid Build Coastguard Worker } else if(rb_hash_aref(rb_iv_get(self, "@hash"), name) != Qnil) {
471*2e9d4914SAndroid Build Coastguard Worker rb_raise(eSettingNameError, "setting `%s' already exists", RSTRING_PTR(name));
472*2e9d4914SAndroid Build Coastguard Worker }
473*2e9d4914SAndroid Build Coastguard Worker rb_ary_push(rb_iv_get(self, "@list"), target);
474*2e9d4914SAndroid Build Coastguard Worker rb_hash_aset(rb_iv_get(self, "@hash"), name, target);
475*2e9d4914SAndroid Build Coastguard Worker } else {
476*2e9d4914SAndroid Build Coastguard Worker rb_raise(rb_eTypeError, "wrong argument type %s (expected Config::BaseSetting)", rb_obj_classname(target));
477*2e9d4914SAndroid Build Coastguard Worker }
478*2e9d4914SAndroid Build Coastguard Worker
479*2e9d4914SAndroid Build Coastguard Worker return target;
480*2e9d4914SAndroid Build Coastguard Worker }
481*2e9d4914SAndroid Build Coastguard Worker
rbConfigAggregate_delete(VALUE self,VALUE target)482*2e9d4914SAndroid Build Coastguard Worker static VALUE rbConfigAggregate_delete(VALUE self, VALUE target)
483*2e9d4914SAndroid Build Coastguard Worker {
484*2e9d4914SAndroid Build Coastguard Worker config_setting_t* setting = NULL;
485*2e9d4914SAndroid Build Coastguard Worker if(rb_iv_get(self, "@setting") != Qnil)
486*2e9d4914SAndroid Build Coastguard Worker Data_Get_Struct(rb_iv_get(self, "@setting"), config_setting_t, setting);
487*2e9d4914SAndroid Build Coastguard Worker
488*2e9d4914SAndroid Build Coastguard Worker VALUE hash = rb_iv_get(self, "@hash"), list = rb_iv_get(self, "@list");
489*2e9d4914SAndroid Build Coastguard Worker
490*2e9d4914SAndroid Build Coastguard Worker if(TYPE(target) == T_STRING && rb_obj_class(self) == cConfigGroup) {
491*2e9d4914SAndroid Build Coastguard Worker if(setting)
492*2e9d4914SAndroid Build Coastguard Worker config_setting_remove(setting, RSTRING_PTR(target));
493*2e9d4914SAndroid Build Coastguard Worker
494*2e9d4914SAndroid Build Coastguard Worker rb_ary_delete_at(list, rb_hash_aref(hash, target));
495*2e9d4914SAndroid Build Coastguard Worker rb_hash_delete(hash, target);
496*2e9d4914SAndroid Build Coastguard Worker } else if(TYPE(target) == T_FIXNUM) {
497*2e9d4914SAndroid Build Coastguard Worker int index = FIX2INT(target);
498*2e9d4914SAndroid Build Coastguard Worker if(setting)
499*2e9d4914SAndroid Build Coastguard Worker config_setting_remove_elem(setting, index);
500*2e9d4914SAndroid Build Coastguard Worker
501*2e9d4914SAndroid Build Coastguard Worker if(rb_obj_class(self) == cConfigGroup)
502*2e9d4914SAndroid Build Coastguard Worker rb_hash_delete(hash, rbConfigBaseSetting_name(rb_ary_entry(list, index)));
503*2e9d4914SAndroid Build Coastguard Worker rb_ary_delete_at(list, index);
504*2e9d4914SAndroid Build Coastguard Worker } else if(rb_ary_includes(aConfigSettings, rb_obj_class(target)) == Qtrue) {
505*2e9d4914SAndroid Build Coastguard Worker VALUE name = rbConfigBaseSetting_name(target);
506*2e9d4914SAndroid Build Coastguard Worker if(setting)
507*2e9d4914SAndroid Build Coastguard Worker config_setting_remove(setting, RSTRING_PTR(name));
508*2e9d4914SAndroid Build Coastguard Worker
509*2e9d4914SAndroid Build Coastguard Worker if(rb_obj_class(self) == cConfigGroup)
510*2e9d4914SAndroid Build Coastguard Worker rb_hash_delete(hash, name);
511*2e9d4914SAndroid Build Coastguard Worker rb_ary_delete(list, target);
512*2e9d4914SAndroid Build Coastguard Worker } else {
513*2e9d4914SAndroid Build Coastguard Worker if(rb_obj_class(self) == cConfigGroup)
514*2e9d4914SAndroid Build Coastguard Worker rb_raise(rb_eTypeError, "wrong argument type %s (expected String, Fixnum or Config::BaseSetting)", rb_obj_classname(target));
515*2e9d4914SAndroid Build Coastguard Worker else
516*2e9d4914SAndroid Build Coastguard Worker rb_raise(rb_eTypeError, "wrong argument type %s (expected Fixnum or Config::BaseSetting)", rb_obj_classname(target));
517*2e9d4914SAndroid Build Coastguard Worker }
518*2e9d4914SAndroid Build Coastguard Worker
519*2e9d4914SAndroid Build Coastguard Worker return Qnil;
520*2e9d4914SAndroid Build Coastguard Worker }
521*2e9d4914SAndroid Build Coastguard Worker
rbConfig_initialize(VALUE self)522*2e9d4914SAndroid Build Coastguard Worker static VALUE rbConfig_initialize(VALUE self)
523*2e9d4914SAndroid Build Coastguard Worker {
524*2e9d4914SAndroid Build Coastguard Worker config_t* config = (config_t*) malloc(sizeof(config_t));
525*2e9d4914SAndroid Build Coastguard Worker config_init(config);
526*2e9d4914SAndroid Build Coastguard Worker config_set_destructor(config, &rconfig_destroy_setting);
527*2e9d4914SAndroid Build Coastguard Worker
528*2e9d4914SAndroid Build Coastguard Worker VALUE rbConfig = Data_Wrap_Struct(rb_cObject, 0, config_destroy, config);
529*2e9d4914SAndroid Build Coastguard Worker rb_iv_set(self, "@config", rbConfig);
530*2e9d4914SAndroid Build Coastguard Worker
531*2e9d4914SAndroid Build Coastguard Worker return self;
532*2e9d4914SAndroid Build Coastguard Worker }
533*2e9d4914SAndroid Build Coastguard Worker
rbConfig_read_bang(VALUE self,VALUE path)534*2e9d4914SAndroid Build Coastguard Worker static VALUE rbConfig_read_bang(VALUE self, VALUE path)
535*2e9d4914SAndroid Build Coastguard Worker {
536*2e9d4914SAndroid Build Coastguard Worker Check_Type(path, T_STRING);
537*2e9d4914SAndroid Build Coastguard Worker
538*2e9d4914SAndroid Build Coastguard Worker config_t* config;
539*2e9d4914SAndroid Build Coastguard Worker Data_Get_Struct(rb_iv_get(self, "@config"), config_t, config);
540*2e9d4914SAndroid Build Coastguard Worker
541*2e9d4914SAndroid Build Coastguard Worker if(!config_read_file(config, RSTRING_PTR(path))) {
542*2e9d4914SAndroid Build Coastguard Worker if(config_error_line(config) == 0)
543*2e9d4914SAndroid Build Coastguard Worker rb_raise(rb_eIOError, "cannot load config: I/O error");
544*2e9d4914SAndroid Build Coastguard Worker else
545*2e9d4914SAndroid Build Coastguard Worker rb_raise(eConfigParseError, "cannot parse config on line %d: `%s'",
546*2e9d4914SAndroid Build Coastguard Worker config_error_line(config), config_error_text(config));
547*2e9d4914SAndroid Build Coastguard Worker }
548*2e9d4914SAndroid Build Coastguard Worker
549*2e9d4914SAndroid Build Coastguard Worker return Qtrue;
550*2e9d4914SAndroid Build Coastguard Worker }
551*2e9d4914SAndroid Build Coastguard Worker
rbConfig_write_bang(VALUE self,VALUE path)552*2e9d4914SAndroid Build Coastguard Worker static VALUE rbConfig_write_bang(VALUE self, VALUE path)
553*2e9d4914SAndroid Build Coastguard Worker {
554*2e9d4914SAndroid Build Coastguard Worker Check_Type(path, T_STRING);
555*2e9d4914SAndroid Build Coastguard Worker
556*2e9d4914SAndroid Build Coastguard Worker config_t* config;
557*2e9d4914SAndroid Build Coastguard Worker Data_Get_Struct(rb_iv_get(self, "@config"), config_t, config);
558*2e9d4914SAndroid Build Coastguard Worker
559*2e9d4914SAndroid Build Coastguard Worker if(!config_write_file(config, RSTRING_PTR(path)))
560*2e9d4914SAndroid Build Coastguard Worker rb_raise(rb_eIOError, "cannot save config: I/O error");
561*2e9d4914SAndroid Build Coastguard Worker
562*2e9d4914SAndroid Build Coastguard Worker return Qtrue;
563*2e9d4914SAndroid Build Coastguard Worker }
564*2e9d4914SAndroid Build Coastguard Worker
rbConfig_read(VALUE self,VALUE path)565*2e9d4914SAndroid Build Coastguard Worker static VALUE rbConfig_read(VALUE self, VALUE path)
566*2e9d4914SAndroid Build Coastguard Worker {
567*2e9d4914SAndroid Build Coastguard Worker Check_Type(path, T_STRING);
568*2e9d4914SAndroid Build Coastguard Worker
569*2e9d4914SAndroid Build Coastguard Worker config_t* config;
570*2e9d4914SAndroid Build Coastguard Worker Data_Get_Struct(rb_iv_get(self, "@config"), config_t, config);
571*2e9d4914SAndroid Build Coastguard Worker
572*2e9d4914SAndroid Build Coastguard Worker return config_read_file(config, RSTRING_PTR(path)) ? Qtrue : Qfalse;
573*2e9d4914SAndroid Build Coastguard Worker }
574*2e9d4914SAndroid Build Coastguard Worker
rbConfig_write(VALUE self,VALUE path)575*2e9d4914SAndroid Build Coastguard Worker static VALUE rbConfig_write(VALUE self, VALUE path)
576*2e9d4914SAndroid Build Coastguard Worker {
577*2e9d4914SAndroid Build Coastguard Worker Check_Type(path, T_STRING);
578*2e9d4914SAndroid Build Coastguard Worker
579*2e9d4914SAndroid Build Coastguard Worker config_t* config;
580*2e9d4914SAndroid Build Coastguard Worker Data_Get_Struct(rb_iv_get(self, "@config"), config_t, config);
581*2e9d4914SAndroid Build Coastguard Worker
582*2e9d4914SAndroid Build Coastguard Worker return config_write_file(config, RSTRING_PTR(path)) ? Qtrue : Qfalse;
583*2e9d4914SAndroid Build Coastguard Worker }
584*2e9d4914SAndroid Build Coastguard Worker
rbConfig_root(VALUE self)585*2e9d4914SAndroid Build Coastguard Worker static VALUE rbConfig_root(VALUE self)
586*2e9d4914SAndroid Build Coastguard Worker {
587*2e9d4914SAndroid Build Coastguard Worker config_t* config;
588*2e9d4914SAndroid Build Coastguard Worker Data_Get_Struct(rb_iv_get(self, "@config"), config_t, config);
589*2e9d4914SAndroid Build Coastguard Worker
590*2e9d4914SAndroid Build Coastguard Worker return rconfig_wrap_setting(config_root_setting(config));
591*2e9d4914SAndroid Build Coastguard Worker }
592*2e9d4914SAndroid Build Coastguard Worker
rbConfig_lookup(VALUE self,VALUE handle)593*2e9d4914SAndroid Build Coastguard Worker static VALUE rbConfig_lookup(VALUE self, VALUE handle)
594*2e9d4914SAndroid Build Coastguard Worker {
595*2e9d4914SAndroid Build Coastguard Worker if(TYPE(handle) == T_STRING) {
596*2e9d4914SAndroid Build Coastguard Worker config_t* config;
597*2e9d4914SAndroid Build Coastguard Worker Data_Get_Struct(rb_iv_get(self, "@config"), config_t, config);
598*2e9d4914SAndroid Build Coastguard Worker
599*2e9d4914SAndroid Build Coastguard Worker config_setting_t* setting;
600*2e9d4914SAndroid Build Coastguard Worker setting = config_lookup(config, RSTRING_PTR(handle));
601*2e9d4914SAndroid Build Coastguard Worker
602*2e9d4914SAndroid Build Coastguard Worker if(setting == NULL)
603*2e9d4914SAndroid Build Coastguard Worker rb_raise(eSettingNotFoundError, "setting `%s' not found", RSTRING_PTR(handle));
604*2e9d4914SAndroid Build Coastguard Worker
605*2e9d4914SAndroid Build Coastguard Worker return rconfig_wrap_setting(setting);
606*2e9d4914SAndroid Build Coastguard Worker } else if(TYPE(handle) == T_FIXNUM) {
607*2e9d4914SAndroid Build Coastguard Worker return rbConfigAggregate_get(rbConfig_root(self), handle);
608*2e9d4914SAndroid Build Coastguard Worker } else {
609*2e9d4914SAndroid Build Coastguard Worker rb_raise(rb_eTypeError, "wrong argument type %s (expected String or Fixnum)", rb_obj_classname(handle));
610*2e9d4914SAndroid Build Coastguard Worker }
611*2e9d4914SAndroid Build Coastguard Worker }
612*2e9d4914SAndroid Build Coastguard Worker
rbConfig_append(VALUE self,VALUE name,VALUE target)613*2e9d4914SAndroid Build Coastguard Worker static VALUE rbConfig_append(VALUE self, VALUE name, VALUE target)
614*2e9d4914SAndroid Build Coastguard Worker {
615*2e9d4914SAndroid Build Coastguard Worker return rbConfigGroup_append(rbConfig_root(self), name, target);
616*2e9d4914SAndroid Build Coastguard Worker }
617*2e9d4914SAndroid Build Coastguard Worker
rbConfig_delete(VALUE self,VALUE name)618*2e9d4914SAndroid Build Coastguard Worker static VALUE rbConfig_delete(VALUE self, VALUE name)
619*2e9d4914SAndroid Build Coastguard Worker {
620*2e9d4914SAndroid Build Coastguard Worker return rbConfigAggregate_delete(rbConfig_root(self), name);
621*2e9d4914SAndroid Build Coastguard Worker }
622*2e9d4914SAndroid Build Coastguard Worker
rbConfig_size(VALUE self)623*2e9d4914SAndroid Build Coastguard Worker static VALUE rbConfig_size(VALUE self)
624*2e9d4914SAndroid Build Coastguard Worker {
625*2e9d4914SAndroid Build Coastguard Worker return rbConfigAggregate_size(rbConfig_root(self));
626*2e9d4914SAndroid Build Coastguard Worker }
627*2e9d4914SAndroid Build Coastguard Worker
Init_rconfig()628*2e9d4914SAndroid Build Coastguard Worker void Init_rconfig()
629*2e9d4914SAndroid Build Coastguard Worker {
630*2e9d4914SAndroid Build Coastguard Worker cConfig = rb_define_class("Config", rb_cObject);
631*2e9d4914SAndroid Build Coastguard Worker rb_define_method(cConfig, "initialize", rbConfig_initialize, 0);
632*2e9d4914SAndroid Build Coastguard Worker rb_define_method(cConfig, "read!", rbConfig_read_bang, 1);
633*2e9d4914SAndroid Build Coastguard Worker rb_define_method(cConfig, "write!", rbConfig_write_bang, 1);
634*2e9d4914SAndroid Build Coastguard Worker rb_define_method(cConfig, "read", rbConfig_read, 1);
635*2e9d4914SAndroid Build Coastguard Worker rb_define_method(cConfig, "write", rbConfig_write, 1);
636*2e9d4914SAndroid Build Coastguard Worker rb_define_method(cConfig, "root", rbConfig_root, 0);
637*2e9d4914SAndroid Build Coastguard Worker rb_define_method(cConfig, "lookup", rbConfig_lookup, 1);
638*2e9d4914SAndroid Build Coastguard Worker rb_define_method(cConfig, "[]", rbConfig_lookup, 1);
639*2e9d4914SAndroid Build Coastguard Worker rb_define_method(cConfig, "append", rbConfig_append, 2);
640*2e9d4914SAndroid Build Coastguard Worker rb_define_method(cConfig, "delete", rbConfig_delete, 1);
641*2e9d4914SAndroid Build Coastguard Worker rb_define_method(cConfig, "size", rbConfig_size, 0);
642*2e9d4914SAndroid Build Coastguard Worker
643*2e9d4914SAndroid Build Coastguard Worker cConfigBaseSetting = rb_define_class_under(cConfig, "BaseSetting", rb_cObject);
644*2e9d4914SAndroid Build Coastguard Worker rb_define_method(cConfigBaseSetting, "initialize", rbConfigBaseSetting_initialize, 1);
645*2e9d4914SAndroid Build Coastguard Worker rb_define_method(cConfigBaseSetting, "name", rbConfigBaseSetting_name, 0);
646*2e9d4914SAndroid Build Coastguard Worker rb_define_method(cConfigBaseSetting, "parent", rbConfigBaseSetting_parent, 0);
647*2e9d4914SAndroid Build Coastguard Worker rb_define_method(cConfigBaseSetting, "root?", rbConfigBaseSetting_is_root, 0);
648*2e9d4914SAndroid Build Coastguard Worker rb_define_method(cConfigBaseSetting, "index", rbConfigBaseSetting_index, 0);
649*2e9d4914SAndroid Build Coastguard Worker rb_define_method(cConfigBaseSetting, "line", rbConfigBaseSetting_line, 0);
650*2e9d4914SAndroid Build Coastguard Worker
651*2e9d4914SAndroid Build Coastguard Worker cConfigSetting = rb_define_class_under(cConfig, "Setting", cConfigBaseSetting);
652*2e9d4914SAndroid Build Coastguard Worker rb_define_method(cConfigSetting, "initialize", rbConfigSetting_initialize, -1);
653*2e9d4914SAndroid Build Coastguard Worker rb_define_method(cConfigSetting, "value", rbConfigSetting_get_value, 0);
654*2e9d4914SAndroid Build Coastguard Worker rb_define_method(cConfigSetting, "value=", rbConfigSetting_set_value, 1);
655*2e9d4914SAndroid Build Coastguard Worker rb_define_method(cConfigSetting, "format", rbConfigSetting_get_format, 0);
656*2e9d4914SAndroid Build Coastguard Worker rb_define_method(cConfigSetting, "format=", rbConfigSetting_set_format, 1);
657*2e9d4914SAndroid Build Coastguard Worker
658*2e9d4914SAndroid Build Coastguard Worker cConfigFormatDefault = INT2FIX(CONFIG_FORMAT_DEFAULT);
659*2e9d4914SAndroid Build Coastguard Worker rb_define_const(cConfig, "FORMAT_DEFAULT", cConfigFormatDefault);
660*2e9d4914SAndroid Build Coastguard Worker cConfigFormatHex = INT2FIX(CONFIG_FORMAT_HEX);
661*2e9d4914SAndroid Build Coastguard Worker rb_define_const(cConfig, "FORMAT_HEX", cConfigFormatHex);
662*2e9d4914SAndroid Build Coastguard Worker
663*2e9d4914SAndroid Build Coastguard Worker cConfigFixnum = rb_define_class_under(cConfig, "Fixnum", cConfigSetting);
664*2e9d4914SAndroid Build Coastguard Worker cConfigBignum = rb_define_class_under(cConfig, "Bignum", cConfigSetting);
665*2e9d4914SAndroid Build Coastguard Worker cConfigFloat = rb_define_class_under(cConfig, "Float", cConfigSetting);
666*2e9d4914SAndroid Build Coastguard Worker cConfigBoolean = rb_define_class_under(cConfig, "Boolean", cConfigSetting);
667*2e9d4914SAndroid Build Coastguard Worker cConfigString = rb_define_class_under(cConfig, "String", cConfigSetting);
668*2e9d4914SAndroid Build Coastguard Worker
669*2e9d4914SAndroid Build Coastguard Worker cConfigAggregate = rb_define_class_under(cConfig, "Aggregate", cConfigBaseSetting);
670*2e9d4914SAndroid Build Coastguard Worker rb_define_method(cConfigAggregate, "initialize", rbConfigAggregate_initialize, -1);
671*2e9d4914SAndroid Build Coastguard Worker rb_define_method(cConfigAggregate, "size", rbConfigAggregate_size, 0);
672*2e9d4914SAndroid Build Coastguard Worker rb_define_method(cConfigAggregate, "get", rbConfigAggregate_get, 1);
673*2e9d4914SAndroid Build Coastguard Worker rb_define_method(cConfigAggregate, "[]", rbConfigAggregate_get, 1);
674*2e9d4914SAndroid Build Coastguard Worker rb_define_method(cConfigAggregate, "delete", rbConfigAggregate_delete, 1);
675*2e9d4914SAndroid Build Coastguard Worker
676*2e9d4914SAndroid Build Coastguard Worker cConfigGroup = rb_define_class_under(cConfig, "Group", cConfigAggregate);
677*2e9d4914SAndroid Build Coastguard Worker rb_define_method(cConfigGroup, "append", rbConfigGroup_append, 2);
678*2e9d4914SAndroid Build Coastguard Worker cConfigArray = rb_define_class_under(cConfig, "Array", cConfigAggregate);
679*2e9d4914SAndroid Build Coastguard Worker rb_define_method(cConfigArray, "append", rbConfigAggregate_append, 1);
680*2e9d4914SAndroid Build Coastguard Worker rb_define_method(cConfigArray, "<<", rbConfigAggregate_append, 1);
681*2e9d4914SAndroid Build Coastguard Worker cConfigList = rb_define_class_under(cConfig, "List", cConfigAggregate);
682*2e9d4914SAndroid Build Coastguard Worker rb_define_method(cConfigList, "append", rbConfigAggregate_append, 1);
683*2e9d4914SAndroid Build Coastguard Worker rb_define_method(cConfigList, "<<", rbConfigAggregate_append, 1);
684*2e9d4914SAndroid Build Coastguard Worker
685*2e9d4914SAndroid Build Coastguard Worker aConfigScalars = rb_ary_new3(5, cConfigFixnum, cConfigBignum, cConfigFloat, cConfigBoolean, cConfigString);
686*2e9d4914SAndroid Build Coastguard Worker aConfigAggregates = rb_ary_new3(3, cConfigGroup, cConfigArray, cConfigList);
687*2e9d4914SAndroid Build Coastguard Worker aConfigSettings = rb_ary_plus(aConfigScalars, aConfigAggregates);
688*2e9d4914SAndroid Build Coastguard Worker
689*2e9d4914SAndroid Build Coastguard Worker rb_define_const(cConfig, "SCALARS", aConfigScalars);
690*2e9d4914SAndroid Build Coastguard Worker rb_define_const(cConfig, "AGGREGATES", aConfigAggregates);
691*2e9d4914SAndroid Build Coastguard Worker rb_define_const(cConfig, "SETTINGS", aConfigSettings);
692*2e9d4914SAndroid Build Coastguard Worker
693*2e9d4914SAndroid Build Coastguard Worker char* settingNameRegexp = "^[A-Za-z*][A-Za-z\\-_*]*$";
694*2e9d4914SAndroid Build Coastguard Worker rSettingNameRegexp = rb_reg_new(settingNameRegexp, strlen(settingNameRegexp), 0);
695*2e9d4914SAndroid Build Coastguard Worker
696*2e9d4914SAndroid Build Coastguard Worker eConfigParseError = rb_define_class("ConfigParseError", rb_eException);
697*2e9d4914SAndroid Build Coastguard Worker eSettingNotFoundError = rb_define_class("SettingNotFoundError", rb_eException);
698*2e9d4914SAndroid Build Coastguard Worker eSettingFormatError = rb_define_class("SettingFormatError", rb_eException);
699*2e9d4914SAndroid Build Coastguard Worker eSettingNameError = rb_define_class("SettingNameError", rb_eException);
700*2e9d4914SAndroid Build Coastguard Worker }
701