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