00001 #include "typelib.hh"
00002
00003 #include <typelib/pluginmanager.hh>
00004 #include <typelib/importer.hh>
00005 #include <typelib/exporter.hh>
00006 #include <typelib/registryiterator.hh>
00007 #include <lang/csupport/standard_types.hh>
00008 #include <utilmm/configfile/configset.hh>
00009 #include <set>
00010
00011 using namespace Typelib;
00012 using utilmm::config_set;
00013 using namespace std;
00014 using namespace typelib_ruby;
00015 using cxx2rb::RbRegistry;
00016
00017
00018 namespace typelib_ruby {
00019 VALUE cRegistry = Qnil;
00020 VALUE eNotFound = Qnil;
00021 }
00022
00023
00024
00025
00026
00027
00028
00029
00030 static
00031 void registry_free(void* ptr)
00032 {
00033 using cxx2rb::WrapperMap;
00034 RbRegistry* rbregistry = reinterpret_cast<RbRegistry*>(ptr);
00035 WrapperMap& wrappers = rbregistry->wrappers;
00036 for (WrapperMap::iterator it = wrappers.begin(); it != wrappers.end(); ++it)
00037 {
00038 if (it->second.first)
00039 delete it->first;
00040 }
00041
00042 delete rbregistry;
00043 }
00044
00045 static
00046 void registry_mark(void* ptr)
00047 {
00048 using cxx2rb::WrapperMap;
00049 WrapperMap const& wrappers = reinterpret_cast<RbRegistry const*>(ptr)->wrappers;
00050 for (WrapperMap::const_iterator it = wrappers.begin(); it != wrappers.end(); ++it)
00051 rb_gc_mark(it->second.second);
00052 }
00053
00054 static
00055 VALUE registry_wrap(VALUE klass, Registry* registry)
00056 {
00057 return Data_Wrap_Struct(klass, registry_mark, registry_free, new RbRegistry(registry));
00058 }
00059
00060 static
00061 VALUE registry_alloc(VALUE klass)
00062 {
00063 Registry* registry = new Registry;
00064 return registry_wrap(klass, registry);
00065 }
00066
00067
00068 static
00069 VALUE registry_includes_p(VALUE self, VALUE name)
00070 {
00071 Registry& registry = rb2cxx::object<Registry>(self);
00072 Type const* type = registry.get( StringValuePtr(name) );
00073 return type ? Qtrue : Qfalse;
00074 }
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084 static
00085 VALUE registry_remove(VALUE self, VALUE rbtype)
00086 {
00087 RbRegistry& rbregistry = rb2cxx::object<RbRegistry>(self);
00088 Registry& registry = *(rbregistry.registry);
00089 Type const& type(rb2cxx::object<Type>(rbtype));
00090 std::set<Type*> deleted = registry.remove(type);
00091
00092 VALUE result = rb_ary_new();
00093 std::set<Type*>::iterator it, end;
00094 for (it = deleted.begin(); it != deleted.end(); ++it)
00095 {
00096 rb_ary_push(result, cxx2rb::type_wrap(**it, self));
00097 cxx2rb::WrapperMap::iterator wrapper_it = rbregistry.wrappers.find(*it);
00098 wrapper_it->second.first = true;
00099 }
00100
00101 return result;
00102 }
00103
00104
00105
00106
00107
00108
00109 static
00110 VALUE registry_source_id_of(VALUE self, VALUE rbtype)
00111 {
00112 RbRegistry& rbregistry = rb2cxx::object<RbRegistry>(self);
00113 Registry& registry = *(rbregistry.registry);
00114 Type const& type(rb2cxx::object<Type>(rbtype));
00115
00116 RegistryIterator it = registry.find(type.getName());
00117 if (it == registry.end())
00118 rb_raise(rb_eArgError, "this registry has no type called %s", type.getName().c_str());
00119
00120 std::string source = it.getSource();
00121 if (source.empty()) return Qnil;
00122 return rb_str_new(it.getSource().c_str(), it.getSource().length());
00123 }
00124
00125
00126
00127
00128
00129
00130 static
00131 VALUE registry_reverse_depends(VALUE self, VALUE rbtype)
00132 {
00133 Registry const& registry = rb2cxx::object<Registry>(self);
00134 Type const& type(rb2cxx::object<Type>(rbtype));
00135 std::set<Type const*> rdeps = registry.reverseDepends(type);
00136
00137 VALUE result = rb_ary_new();
00138 std::set<Type const*>::iterator it, end;
00139 for (it = rdeps.begin(); it != rdeps.end(); ++it)
00140 rb_ary_push(result, cxx2rb::type_wrap(**it, self));
00141
00142 return result;
00143 }
00144
00145 static
00146 VALUE registry_do_get(VALUE self, VALUE name)
00147 {
00148 Registry& registry = rb2cxx::object<Registry>(self);
00149 Type const* type = registry.get( StringValuePtr(name) );
00150
00151 if (! type)
00152 rb_raise(eNotFound, "there is no type in this registry with the name '%s'", StringValuePtr(name));
00153 return cxx2rb::type_wrap(*type, self);
00154 }
00155
00156 static
00157 VALUE registry_do_build(VALUE self, VALUE name)
00158 {
00159 Registry& registry = rb2cxx::object<Registry>(self);
00160 try {
00161 Type const* type = registry.build( StringValuePtr(name) );
00162 if (! type)
00163 rb_raise(eNotFound, "cannot find %s in registry", StringValuePtr(name));
00164 return cxx2rb::type_wrap(*type, self);
00165 }
00166 catch(std::exception const& e) { rb_raise(rb_eRuntimeError, "%s", e.what()); }
00167 }
00168
00169
00170
00171
00172
00173
00174
00175 static
00176 VALUE registry_alias(VALUE self, VALUE name, VALUE aliased)
00177 {
00178 Registry& registry = rb2cxx::object<Registry>(self);
00179
00180 try {
00181 registry.alias(StringValuePtr(aliased), StringValuePtr(name));
00182 return self;
00183 } catch(BadName) {
00184 rb_raise(rb_eArgError, "invalid type name %s", StringValuePtr(name));
00185 } catch(Undefined) {
00186 rb_raise(eNotFound, "there is not type in this registry with the name '%s'", StringValuePtr(aliased));
00187 }
00188 }
00189
00190 static
00191 void setup_configset_from_option_array(config_set& config, VALUE options)
00192 {
00193 int options_length = RARRAY_LEN(options);
00194 for (int i = 0; i < options_length; ++i)
00195 {
00196 VALUE entry = RARRAY_PTR(options)[i];
00197 VALUE k = RARRAY_PTR(entry)[0];
00198 VALUE v = RARRAY_PTR(entry)[1];
00199
00200 if ( rb_obj_is_kind_of(v, rb_cArray) )
00201 {
00202 VALUE first_el = rb_ary_entry(v, 0);
00203 if (rb_obj_is_kind_of(first_el, rb_cArray))
00204 {
00205
00206 for (int j = 0; j < RARRAY_LEN(v); ++j)
00207 {
00208 config_set* child = new config_set;
00209 setup_configset_from_option_array(*child, rb_ary_entry(v, j));
00210 config.insert(StringValuePtr(k), child);
00211 }
00212 }
00213 else
00214 {
00215 for (int j = 0; j < RARRAY_LEN(v); ++j)
00216 {
00217 VALUE value = rb_ary_entry(v, j);
00218 config.insert(StringValuePtr(k), StringValuePtr(value));
00219 }
00220 }
00221 }
00222 else if (TYPE(v) == T_TRUE || TYPE(v) == T_FALSE)
00223 config.set(StringValuePtr(k), RTEST(v) ? "true" : "false");
00224 else
00225 config.set(StringValuePtr(k), StringValuePtr(v));
00226 }
00227 }
00228
00229
00230
00231
00232
00233 static
00234 VALUE registry_import(VALUE self, VALUE file, VALUE kind, VALUE merge, VALUE options)
00235 {
00236 Registry& registry = rb2cxx::object<Registry>(self);
00237
00238 config_set config;
00239 setup_configset_from_option_array(config, options);
00240
00241 std::string error_string;
00242 try {
00243 if (RTEST(merge))
00244 {
00245 Registry temp;
00246 PluginManager::load(StringValuePtr(kind), StringValuePtr(file), config, temp);
00247 registry.merge(temp);
00248 }
00249 else
00250 PluginManager::load(StringValuePtr(kind), StringValuePtr(file), config, registry);
00251 return Qnil;
00252 }
00253 catch(boost::bad_lexical_cast e) { error_string = e.what(); }
00254 catch(std::exception const& e) { error_string = e.what(); }
00255
00256 rb_raise(rb_eRuntimeError, "%s", error_string.c_str());
00257 }
00258
00259
00260
00261
00262
00263 static
00264 VALUE registry_export(VALUE self, VALUE kind, VALUE options)
00265 {
00266 Registry& registry = rb2cxx::object<Registry>(self);
00267
00268 config_set config;
00269 setup_configset_from_option_array(config, options);
00270
00271 string error_message;
00272 try {
00273 std::string exported = PluginManager::save(StringValuePtr(kind), config, registry);
00274 return rb_str_new(exported.c_str(), exported.length());
00275 }
00276 catch (std::exception const& e) { error_message = e.what(); }
00277 rb_raise(rb_eRuntimeError, "%s", error_message.c_str());
00278 }
00279
00280
00281
00282
00283
00284
00285
00286
00287 static
00288 VALUE registry_merge(VALUE self, VALUE rb_merged)
00289 {
00290 std::string error_string;
00291
00292 Registry& registry = rb2cxx::object<Registry>(self);
00293 Registry& merged = rb2cxx::object<Registry>(rb_merged);
00294 try {
00295 registry.merge(merged);
00296 return self;
00297 }
00298 catch(std::exception const& e) { error_string = e.what(); }
00299 rb_raise(rb_eRuntimeError, "%s", error_string.c_str());
00300 }
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310 static
00311 VALUE registry_resize(VALUE self, VALUE new_sizes)
00312 {
00313 Registry& registry = rb2cxx::object<Registry>(self);
00314
00315 std::map<std::string, size_t> sizes;
00316 size_t map_size = RARRAY_LEN(new_sizes);
00317 VALUE* map_values = RARRAY_PTR(new_sizes);
00318 for (size_t i = 0; i < map_size; ++i)
00319 {
00320 VALUE* pair = RARRAY_PTR(map_values[i]);
00321 sizes.insert(std::make_pair(
00322 StringValuePtr(pair[0]),
00323 NUM2INT(pair[1])));
00324 }
00325 try {
00326 registry.resize(sizes);
00327 return Qnil;
00328 }
00329 catch(std::exception const& e) {
00330 rb_raise(rb_eRuntimeError, "%s", e.what());
00331 }
00332 }
00333
00334
00335
00336
00337
00338
00339
00340 static
00341 VALUE registry_minimal(VALUE self, VALUE rb_auto, VALUE with_aliases)
00342 {
00343 std::string error_string;
00344 Registry& registry = rb2cxx::object<Registry>(self);
00345
00346 if (rb_obj_is_kind_of(rb_auto, rb_cString))
00347 {
00348 try {
00349 Registry* result = registry.minimal(StringValuePtr(rb_auto), RTEST(with_aliases));
00350 return registry_wrap(cRegistry, result);
00351 }
00352 catch(std::exception const& e)
00353 { rb_raise(rb_eRuntimeError, "%s", e.what()); }
00354 }
00355 else
00356 {
00357 Registry& auto_types = rb2cxx::object<Registry>(rb_auto);
00358 try {
00359 Registry* result = registry.minimal(auto_types);
00360 return registry_wrap(cRegistry, result);
00361 }
00362 catch(std::exception const& e)
00363 { rb_raise(rb_eRuntimeError, "%s", e.what()); }
00364 }
00365 }
00366
00367
00368 static void yield_types(VALUE self, bool with_aliases, RegistryIterator it, RegistryIterator end)
00369 {
00370 if (with_aliases)
00371 {
00372 for (; it != end; ++it)
00373 {
00374 std::string const& type_name = it.getName();
00375 VALUE rb_type_name = rb_str_new(type_name.c_str(), type_name.length());
00376 rb_yield_values(2, rb_type_name, cxx2rb::type_wrap(*it, self));
00377 }
00378 }
00379 else
00380 {
00381 for (; it != end; ++it)
00382 {
00383 if (!it.isAlias())
00384 rb_yield(cxx2rb::type_wrap(*it, self));
00385 }
00386 }
00387 }
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397 static
00398 VALUE registry_each_type(VALUE self, VALUE filter_, VALUE with_aliases_)
00399 {
00400 Registry& registry = rb2cxx::object<Registry>(self);
00401 bool with_aliases = RTEST(with_aliases_);
00402 std::string filter;
00403 if (RTEST(filter_))
00404 filter = StringValuePtr(filter_);
00405
00406 try
00407 {
00408 if (filter.empty())
00409 yield_types(self, with_aliases, registry.begin(), registry.end());
00410 else
00411 yield_types(self, with_aliases, registry.begin(filter), registry.end(filter));
00412
00413 return self;
00414 }
00415 catch(std::exception const& e)
00416 {
00417 rb_raise(rb_eRuntimeError, "%s", e.what());
00418 }
00419 }
00420
00421
00422
00423
00424
00425
00426
00427 static
00428 VALUE registry_merge_xml(VALUE rb_registry, VALUE xml)
00429 {
00430 Registry& registry = rb2cxx::object<Registry>(rb_registry);
00431
00432 std::istringstream istream(StringValuePtr(xml));
00433 config_set config;
00434 try { PluginManager::load("tlb", istream, config, registry); }
00435 catch(boost::bad_lexical_cast e)
00436 { rb_raise(rb_eArgError, "cannot load xml: %s", e.what()); }
00437 catch(std::exception const& e)
00438 { rb_raise(rb_eArgError, "cannot load xml: %s", e.what()); }
00439
00440 return rb_registry;
00441 }
00442
00443
00444
00445
00446
00447
00448
00449 static VALUE registry_aliases_of(VALUE self, VALUE type_)
00450 {
00451 Registry& registry = rb2cxx::object<Registry>(self);
00452 Type const& type(rb2cxx::object<Type>(type_));
00453 std::set<std::string> aliases =
00454 registry.getAliasesOf(type);
00455
00456 VALUE result = rb_ary_new();
00457 for (set<string>::const_iterator it = aliases.begin(); it != aliases.end(); ++it)
00458 rb_ary_push(result, rb_str_new(it->c_str(), it->length()));
00459 return result;
00460 }
00461
00462
00463
00464
00465
00466
00467
00468 static VALUE registry_clear_aliases(VALUE self)
00469 {
00470 Registry& registry = rb2cxx::object<Registry>(self);
00471 registry.clearAliases();
00472 return Qnil;
00473 }
00474
00475
00476
00477
00478
00479
00480
00481 static VALUE registry_size(VALUE self)
00482 {
00483 Registry& registry = rb2cxx::object<Registry>(self);
00484 return INT2NUM(registry.size());
00485 }
00486
00487
00488
00489
00490
00491
00492
00493 static VALUE registry_available_container(VALUE registry_module)
00494 {
00495 Typelib::Container::AvailableContainers containers =
00496 Typelib::Container::availableContainers();
00497
00498 VALUE result = rb_ary_new();
00499 Typelib::Container::AvailableContainers::const_iterator
00500 it = containers.begin(),
00501 end = containers.end();
00502
00503 while (it != end)
00504 {
00505 std::string name = it->first;
00506 rb_ary_push(result, rb_str_new(name.c_str(), name.length()));
00507 ++it;
00508 }
00509 return result;
00510 }
00511
00512
00513
00514
00515
00516
00517
00518
00519
00520
00521
00522
00523
00524 static VALUE registry_define_container(VALUE registry, VALUE kind, VALUE element)
00525 {
00526 Registry& reg = rb2cxx::object<Registry>(registry);
00527 Type const& element_type(rb2cxx::object<Type>(element));
00528
00529 if (!reg.isIncluded(element_type))
00530 rb_raise(rb_eArgError, "the given type object comes from a different type registry");
00531
00532 try {
00533 Container const& new_type = Container::createContainer(reg, StringValuePtr(kind), element_type);
00534 return cxx2rb::type_wrap(new_type, registry);
00535 } catch(Typelib::UnknownContainer) {
00536 rb_raise(eNotFound, "%s is not a known container type", StringValuePtr(kind));
00537 }
00538 }
00539
00540
00541
00542
00543
00544
00545
00546 static VALUE registry_add_standard_cxx_types(VALUE klass, VALUE registry)
00547 {
00548 Registry& reg = rb2cxx::object<Registry>(registry);
00549 try { Typelib::CXX::addStandardTypes(reg); }
00550 catch(Typelib::AlreadyDefined e)
00551 { rb_raise(rb_eArgError, "%s", e.what()); }
00552 return registry;
00553 }
00554
00555
00556
00557
00558
00559
00560
00561 static VALUE registry_create_compound(VALUE registry, VALUE name, VALUE field_defs)
00562 {
00563 Registry& reg = rb2cxx::object<Registry>(registry);
00564
00565 std::auto_ptr<Typelib::Compound> new_t(new Typelib::Compound(StringValuePtr(name)));
00566
00567 int size = RARRAY_LEN(field_defs);
00568 for (int i = 0; i < size; ++i)
00569 {
00570 VALUE field = rb_ary_entry(field_defs, i);
00571
00572 VALUE rb_name = rb_ary_entry(field, 0);
00573 std::string field_name(StringValuePtr(rb_name));
00574 Typelib::Type& field_type(rb2cxx::object<Type>(rb_ary_entry(field, 1)));
00575 int offset(NUM2INT(rb_ary_entry(field, 2)));
00576 new_t->addField(field_name, field_type, offset);
00577 }
00578
00579 Typelib::Compound* type = new_t.release();
00580 try { reg.add(type, true, ""); }
00581 catch(std::runtime_error e)
00582 { rb_raise(rb_eArgError, "%s", e.what()); }
00583 return cxx2rb::type_wrap(*type, registry);
00584 }
00585
00586
00587
00588
00589
00590
00591
00592 static VALUE registry_create_enum(VALUE registry, VALUE name, VALUE symbol_defs)
00593 {
00594 Registry& reg = rb2cxx::object<Registry>(registry);
00595
00596 std::auto_ptr<Typelib::Enum> new_t(new Typelib::Enum(StringValuePtr(name)));
00597
00598 int size = RARRAY_LEN(symbol_defs);
00599 for (int i = 0; i < size; ++i)
00600 {
00601 VALUE sym = rb_ary_entry(symbol_defs, i);
00602
00603 VALUE rb_name = rb_ary_entry(sym, 0);
00604 std::string sym_name(StringValuePtr(rb_name));
00605 int sym_value(NUM2INT(rb_ary_entry(sym, 1)));
00606 new_t->add(sym_name, sym_value);
00607 }
00608
00609 Typelib::Enum* type = new_t.release();
00610 try { reg.add(type, true, ""); }
00611 catch(std::runtime_error e)
00612 { rb_raise(rb_eArgError, "%s", e.what()); }
00613 return cxx2rb::type_wrap(*type, registry);
00614 }
00615
00616
00617
00618
00619
00620
00621
00622 static VALUE registry_create_opaque(VALUE registry, VALUE _name, VALUE _size)
00623 {
00624 Registry& reg = rb2cxx::object<Registry>(registry);
00625 Typelib::Type* type = new Typelib::OpaqueType(StringValuePtr(_name), NUM2INT(_size));
00626 reg.add(type, true, "");
00627 return cxx2rb::type_wrap(*type, registry);
00628 }
00629
00630
00631
00632
00633
00634
00635
00636 static VALUE registry_create_null(VALUE registry, VALUE _name)
00637 {
00638 Registry& reg = rb2cxx::object<Registry>(registry);
00639 Typelib::Type* type = new Typelib::NullType(StringValuePtr(_name));
00640 reg.add(type, true, "");
00641 return cxx2rb::type_wrap(*type, registry);
00642 }
00643
00644 void typelib_ruby::Typelib_init_registry()
00645 {
00646 VALUE mTypelib = rb_define_module("Typelib");
00647 cRegistry = rb_define_class_under(mTypelib, "Registry", rb_cObject);
00648 eNotFound = rb_define_class_under(mTypelib, "NotFound", rb_eRuntimeError);
00649 rb_define_alloc_func(cRegistry, registry_alloc);
00650 rb_define_method(cRegistry, "size", RUBY_METHOD_FUNC(registry_size), 0);
00651 rb_define_method(cRegistry, "get", RUBY_METHOD_FUNC(registry_do_get), 1);
00652 rb_define_method(cRegistry, "build", RUBY_METHOD_FUNC(registry_do_build), 1);
00653 rb_define_method(cRegistry, "each_type", RUBY_METHOD_FUNC(registry_each_type), 2);
00654
00655
00656 rb_define_method(cRegistry, "do_import", RUBY_METHOD_FUNC(registry_import), 4);
00657 rb_define_method(cRegistry, "do_export", RUBY_METHOD_FUNC(registry_export), 2);
00658 rb_define_method(cRegistry, "merge_xml", RUBY_METHOD_FUNC(registry_merge_xml), 1);
00659 rb_define_method(cRegistry, "alias", RUBY_METHOD_FUNC(registry_alias), 2);
00660 rb_define_method(cRegistry, "clear_aliases", RUBY_METHOD_FUNC(registry_clear_aliases), 0);
00661 rb_define_method(cRegistry, "aliases_of", RUBY_METHOD_FUNC(registry_aliases_of), 1);
00662 rb_define_method(cRegistry, "merge", RUBY_METHOD_FUNC(registry_merge), 1);
00663 rb_define_method(cRegistry, "do_minimal", RUBY_METHOD_FUNC(registry_minimal), 2);
00664 rb_define_method(cRegistry, "includes?", RUBY_METHOD_FUNC(registry_includes_p), 1);
00665 rb_define_method(cRegistry, "do_resize", RUBY_METHOD_FUNC(registry_resize), 1);
00666 rb_define_method(cRegistry, "reverse_depends", RUBY_METHOD_FUNC(registry_reverse_depends), 1);
00667 rb_define_method(cRegistry, "remove", RUBY_METHOD_FUNC(registry_remove), 1);
00668 rb_define_method(cRegistry, "source_id_of", RUBY_METHOD_FUNC(registry_source_id_of), 1);
00669 rb_define_method(cRegistry, "do_create_compound", RUBY_METHOD_FUNC(registry_create_compound), 2);
00670 rb_define_method(cRegistry, "do_create_enum", RUBY_METHOD_FUNC(registry_create_enum), 2);
00671 rb_define_method(cRegistry, "create_opaque", RUBY_METHOD_FUNC(registry_create_opaque), 2);
00672 rb_define_method(cRegistry, "create_null", RUBY_METHOD_FUNC(registry_create_null), 1);
00673
00674 rb_define_singleton_method(cRegistry, "add_standard_cxx_types", RUBY_METHOD_FUNC(registry_add_standard_cxx_types), 1);
00675
00676 rb_define_singleton_method(cRegistry, "available_containers", RUBY_METHOD_FUNC(registry_available_container), 0);
00677 rb_define_method(cRegistry, "define_container", RUBY_METHOD_FUNC(registry_define_container), 2);
00678 }
00679