ICE 3.4.2
[php5-ice-freebsdport.git] / rb / src / IceRuby / Util.cpp
blobcf5fb0aaf756a6270502402abb309c8802e1b660
1 // **********************************************************************
2 //
3 // Copyright (c) 2003-2011 ZeroC, Inc. All rights reserved.
4 //
5 // This copy of Ice is licensed to you under the terms described in the
6 // ICE_LICENSE file included in this distribution.
7 //
8 // **********************************************************************
10 #include <Util.h>
11 #include <Ice/LocalException.h>
12 #include <stdarg.h>
14 using namespace std;
15 using namespace IceRuby;
17 extern "C"
18 VALUE
19 IceRuby_stringVersion(int /*argc*/, VALUE* /*argv*/, VALUE /*self*/)
21 ICE_RUBY_TRY
23 string s = ICE_STRING_VERSION;
24 return createString(s);
26 ICE_RUBY_CATCH
27 return Qnil;
30 extern "C"
31 VALUE
32 IceRuby_intVersion(int /*argc*/, VALUE* /*argv*/, VALUE /*self*/)
34 ICE_RUBY_TRY
36 return INT2FIX(ICE_INT_VERSION);
38 ICE_RUBY_CATCH
39 return Qnil;
42 void
43 IceRuby::initUtil(VALUE iceModule)
45 rb_define_module_function(iceModule, "stringVersion", CAST_METHOD(IceRuby_stringVersion), -1);
46 rb_define_module_function(iceModule, "intVersion", CAST_METHOD(IceRuby_intVersion), -1);
49 IceRuby::RubyException::RubyException()
51 ex = rb_gv_get("$!");
54 IceRuby::RubyException::RubyException(VALUE exv) :
55 ex(exv)
59 IceRuby::RubyException::RubyException(VALUE exClass, const char* fmt, ...)
61 va_list args;
62 char buf[BUFSIZ];
64 va_start(args, fmt);
65 vsnprintf(buf, BUFSIZ, fmt, args);
66 buf[BUFSIZ - 1] = '\0';
67 va_end(args);
69 ex = callRuby(rb_exc_new2, exClass, buf);
72 ostream&
73 IceRuby::RubyException::operator<<(ostream& ostr) const
75 volatile VALUE cls = rb_class_path(CLASS_OF(ex));
76 volatile VALUE msg = rb_obj_as_string(ex);
77 ostr << RSTRING_PTR(cls) << ": " << RSTRING_PTR(msg);
78 return ostr;
81 bool
82 IceRuby::isString(VALUE val)
84 return TYPE(val) == T_STRING || callRuby(rb_respond_to, val, rb_intern("to_str")) != 0;
87 bool
88 IceRuby::isArray(VALUE val)
90 return TYPE(val) == T_ARRAY || callRuby(rb_respond_to, val, rb_intern("to_arr")) != 0;
93 bool
94 IceRuby::isHash(VALUE val)
96 return TYPE(val) == T_HASH || callRuby(rb_respond_to, val, rb_intern("to_hash")) != 0;
99 string
100 IceRuby::getString(VALUE val)
102 volatile VALUE result = callRuby(rb_string_value, &val);
103 return string(RSTRING_PTR(result), RSTRING_LEN(result));
106 VALUE
107 IceRuby::createString(const string& str)
109 return callRuby(rb_str_new, str.c_str(), static_cast<long>(str.size()));
112 long
113 IceRuby::getInteger(VALUE val)
115 if(!FIXNUM_P(val) && TYPE(val) != T_BIGNUM)
117 val = callRuby(rb_Integer, val);
119 if(FIXNUM_P(val))
121 return FIX2LONG(val);
123 else if(TYPE(val) == T_BIGNUM)
125 Ice::Long l = getLong(val);
126 if(l >= static_cast<Ice::Long>(INT_MIN) && l <= static_cast<Ice::Long>(INT_MAX))
128 return static_cast<long>(l);
131 throw RubyException(rb_eTypeError, "unable to convert value to an integer");
134 #define BITSPERDIG (SIZEOF_BDIGITS*CHAR_BIT)
135 #define BIGUP(x) ((BDIGIT_DBL)(x) << BITSPERDIG)
137 Ice::Long
138 IceRuby::getLong(VALUE val)
141 // The rb_num2ll function raises exceptions, but we can't call it using callProtected
142 // because its return type is long long and not VALUE.
144 volatile VALUE v = callRuby(rb_Integer, val);
145 if(NIL_P(v))
147 throw RubyException(rb_eTypeError, "unable to convert value to a long");
149 if(FIXNUM_P(v))
151 return FIX2LONG(v);
153 else
155 assert(TYPE(v) == T_BIGNUM);
156 long len = RBIGNUM_LEN(v);
157 if(len > SIZEOF_LONG_LONG/SIZEOF_BDIGITS)
159 throw RubyException(rb_eRangeError, "bignum too big to convert into long");
161 BDIGIT *ds = RBIGNUM_DIGITS(v);
162 BDIGIT_DBL num = 0;
163 while(len--)
165 num = BIGUP(num);
166 num += ds[len];
168 Ice::Long l = static_cast<Ice::Long>(num);
169 if(l < 0 && (RBIGNUM_SIGN(v) || l != LLONG_MIN))
171 throw RubyException(rb_eRangeError, "bignum too big to convert into long");
173 if (!RBIGNUM_SIGN(v))
175 return -l;
177 return l;
181 bool
182 IceRuby::arrayToStringSeq(VALUE val, vector<string>& seq)
184 volatile VALUE arr = callRuby(rb_check_array_type, val);
185 if(NIL_P(arr))
187 return false;
189 for(long i = 0; i < RARRAY_LEN(arr); ++i)
191 string s = getString(RARRAY_PTR(arr)[i]);
192 seq.push_back(getString(RARRAY_PTR(arr)[i]));
194 return true;
197 VALUE
198 IceRuby::stringSeqToArray(const vector<string>& seq)
200 volatile VALUE result = createArray(seq.size());
201 long i = 0;
202 if(seq.size() > 0)
204 for(vector<string>::const_iterator p = seq.begin(); p != seq.end(); ++p, ++i)
206 RARRAY_PTR(result)[i] = createString(*p);
209 return result;
212 namespace
215 struct HashToContextIterator : public IceRuby::HashIterator
217 HashToContextIterator(Ice::Context& c) : ctx(c)
221 virtual void element(VALUE key, VALUE value)
223 string kstr = IceRuby::getString(key);
224 string vstr = IceRuby::getString(value);
225 ctx[kstr] = vstr;
228 Ice::Context& ctx;
233 bool
234 IceRuby::hashToContext(VALUE val, Ice::Context& ctx)
236 if(TYPE(val) != T_HASH)
238 val = callRuby(rb_convert_type, val, T_HASH, "Hash", "to_hash");
239 if(NIL_P(val))
241 return false;
244 HashToContextIterator iter(ctx);
245 hashIterate(val, iter);
246 return true;
249 VALUE
250 IceRuby::contextToHash(const Ice::Context& ctx)
252 volatile VALUE result = callRuby(rb_hash_new);
253 for(Ice::Context::const_iterator p = ctx.begin(); p != ctx.end(); ++p)
255 volatile VALUE key = callRuby(rb_str_new, p->first.c_str(), static_cast<long>(p->first.size()));
256 volatile VALUE value = callRuby(rb_str_new, p->second.c_str(), static_cast<long>(p->second.size()));
257 callRuby(rb_hash_aset, result, key, value);
259 return result;
262 extern "C"
263 VALUE
264 IceRuby_Util_hash_foreach_callback(VALUE val, VALUE arg)
266 VALUE key = rb_ary_entry(val, 0);
267 VALUE value = rb_ary_entry(val, 1);
270 // We can't allow any C++ exceptions to propagate out of this function.
272 ICE_RUBY_TRY
274 IceRuby::HashIterator* iter = reinterpret_cast<IceRuby::HashIterator*>(arg);
275 iter->element(key, value);
277 ICE_RUBY_CATCH
278 return val;
281 extern "C"
283 typedef VALUE (*ICE_RUBY_HASH_FOREACH_CALLBACK)(...);
286 void
287 IceRuby::hashIterate(VALUE h, HashIterator& iter)
289 assert(TYPE(h) == T_HASH);
290 callRuby(rb_iterate, rb_each, h,
291 reinterpret_cast<ICE_RUBY_HASH_FOREACH_CALLBACK>(IceRuby_Util_hash_foreach_callback),
292 reinterpret_cast<VALUE>(&iter));
295 Ice::Identity
296 IceRuby::getIdentity(VALUE v)
298 volatile VALUE cls = callRuby(rb_path2class, "Ice::Identity");
299 assert(!NIL_P(cls));
301 if(callRuby(rb_obj_is_kind_of, v, cls) == Qfalse)
303 throw RubyException(rb_eTypeError, "value is not an Ice::Identity");
306 volatile VALUE name = callRuby(rb_iv_get, v, "@name");
307 volatile VALUE category = callRuby(rb_iv_get, v, "@category");
309 if(!NIL_P(category) && !isString(category))
311 throw RubyException(rb_eTypeError, "identity category must be a string");
314 if(NIL_P(name) || !isString(name))
316 throw RubyException(rb_eTypeError, "identity name must be a string");
319 Ice::Identity result;
320 result.name = getString(name);
321 if(!NIL_P(category))
323 result.category = getString(category);
325 return result;
328 VALUE
329 IceRuby::createIdentity(const Ice::Identity& id)
331 volatile VALUE cls = callRuby(rb_path2class, "Ice::Identity");
332 assert(!NIL_P(cls));
334 volatile VALUE result = callRuby(rb_class_new_instance, 0, reinterpret_cast<VALUE*>(0), cls);
335 volatile VALUE name = callRuby(rb_str_new, id.name.c_str(), static_cast<long>(id.name.size()));
336 volatile VALUE category = callRuby(rb_str_new, id.category.c_str(), static_cast<long>(id.category.size()));
337 callRuby(rb_iv_set, result, "@name", name);
338 callRuby(rb_iv_set, result, "@category", category);
339 return result;
342 VALUE
343 IceRuby::callProtected(RubyFunction func, VALUE arg)
345 int error = 0;
346 volatile VALUE result = rb_protect(func, arg, &error);
347 if(error)
349 throw RubyException();
351 return result;
354 static void
355 setExceptionMembers(const Ice::LocalException& ex, VALUE p)
358 // Transfer data members from Ice exception to Ruby exception.
362 ex.ice_throw();
364 catch(const Ice::InitializationException& e)
366 volatile VALUE v = createString(e.reason);
367 callRuby(rb_iv_set, p, "@reason", v);
369 catch(const Ice::PluginInitializationException& e)
371 volatile VALUE v = createString(e.reason);
372 callRuby(rb_iv_set, p, "@reason", v);
374 catch(const Ice::AlreadyRegisteredException& e)
376 volatile VALUE v;
377 v = createString(e.kindOfObject);
378 callRuby(rb_iv_set, p, "@kindOfObject", v);
379 v = createString(e.id);
380 callRuby(rb_iv_set, p, "@id", v);
382 catch(const Ice::NotRegisteredException& e)
384 volatile VALUE v;
385 v = createString(e.kindOfObject);
386 callRuby(rb_iv_set, p, "@kindOfObject", v);
387 v = createString(e.id);
388 callRuby(rb_iv_set, p, "@id", v);
390 catch(const Ice::TwowayOnlyException& e)
392 volatile VALUE v = createString(e.operation);
393 callRuby(rb_iv_set, p, "@operation", v);
395 catch(const Ice::UnknownException& e)
397 volatile VALUE v = createString(e.unknown);
398 callRuby(rb_iv_set, p, "@unknown", v);
400 catch(const Ice::ObjectAdapterDeactivatedException& e)
402 volatile VALUE v = createString(e.name);
403 callRuby(rb_iv_set, p, "@name", v);
405 catch(const Ice::ObjectAdapterIdInUseException& e)
407 volatile VALUE v = createString(e.id);
408 callRuby(rb_iv_set, p, "@id", v);
410 catch(const Ice::NoEndpointException& e)
412 volatile VALUE v = createString(e.proxy);
413 callRuby(rb_iv_set, p, "@proxy", v);
415 catch(const Ice::EndpointParseException& e)
417 volatile VALUE v = createString(e.str);
418 callRuby(rb_iv_set, p, "@str", v);
420 catch(const Ice::IdentityParseException& e)
422 volatile VALUE v = createString(e.str);
423 callRuby(rb_iv_set, p, "@str", v);
425 catch(const Ice::ProxyParseException& e)
427 volatile VALUE v = createString(e.str);
428 callRuby(rb_iv_set, p, "@str", v);
430 catch(const Ice::IllegalIdentityException& e)
432 volatile VALUE v = IceRuby::createIdentity(e.id);
433 callRuby(rb_iv_set, p, "@id", v);
435 catch(const Ice::RequestFailedException& e)
437 volatile VALUE v;
438 v = IceRuby::createIdentity(e.id);
439 callRuby(rb_iv_set, p, "@id", v);
440 v = createString(e.facet);
441 callRuby(rb_iv_set, p, "@facet", v);
442 v = createString(e.operation);
443 callRuby(rb_iv_set, p, "@operation", v);
445 catch(const Ice::FileException& e)
447 volatile VALUE v = INT2FIX(e.error);
448 callRuby(rb_iv_set, p, "@error", v);
449 v = createString(e.path);
450 callRuby(rb_iv_set, p, "@path", v);
452 catch(const Ice::SyscallException& e) // This must appear after all subclasses of SyscallException.
454 volatile VALUE v = INT2FIX(e.error);
455 callRuby(rb_iv_set, p, "@error", v);
457 catch(const Ice::DNSException& e)
459 volatile VALUE v;
460 v = INT2FIX(e.error);
461 callRuby(rb_iv_set, p, "@error", v);
462 v = createString(e.host);
463 callRuby(rb_iv_set, p, "@host", v);
465 catch(const Ice::UnsupportedProtocolException& e)
467 callRuby(rb_iv_set, p, "@badMajor", INT2FIX(e.badMajor));
468 callRuby(rb_iv_set, p, "@badMinor", INT2FIX(e.badMinor));
469 callRuby(rb_iv_set, p, "@major", INT2FIX(e.major));
470 callRuby(rb_iv_set, p, "@minor", INT2FIX(e.minor));
472 catch(const Ice::UnsupportedEncodingException& e)
474 callRuby(rb_iv_set, p, "@badMajor", INT2FIX(e.badMajor));
475 callRuby(rb_iv_set, p, "@badMinor", INT2FIX(e.badMinor));
476 callRuby(rb_iv_set, p, "@major", INT2FIX(e.major));
477 callRuby(rb_iv_set, p, "@minor", INT2FIX(e.minor));
479 catch(const Ice::NoObjectFactoryException& e)
481 volatile VALUE v;
482 v = createString(e.reason);
483 callRuby(rb_iv_set, p, "@reason", v);
484 v = createString(e.type);
485 callRuby(rb_iv_set, p, "@type", v);
487 catch(const Ice::UnexpectedObjectException& e)
489 volatile VALUE v;
490 v = createString(e.reason);
491 callRuby(rb_iv_set, p, "@reason", v);
492 v = createString(e.type);
493 callRuby(rb_iv_set, p, "@type", v);
494 v = createString(e.expectedType);
495 callRuby(rb_iv_set, p, "@expectedType", v);
497 catch(const Ice::ProtocolException& e) // This must appear after all subclasses of ProtocolException.
499 volatile VALUE v = createString(e.reason);
500 callRuby(rb_iv_set, p, "@reason", v);
502 catch(const Ice::FeatureNotSupportedException& e)
504 volatile VALUE v = createString(e.unsupportedFeature);
505 callRuby(rb_iv_set, p, "@unsupportedFeature", v);
507 catch(const Ice::SecurityException& e)
509 volatile VALUE v = createString(e.reason);
510 callRuby(rb_iv_set, p, "@reason", v);
512 catch(const Ice::LocalException&)
515 // Nothing to do.
520 VALUE
521 IceRuby::createArrayHelper(long sz)
523 VALUE arr = callRuby(rb_ary_new2, sz);
524 if(sz > 0)
526 callRubyVoid(rb_ary_store, arr, sz - 1, Qnil);
528 return arr;
531 VALUE
532 IceRuby::convertLocalException(const Ice::LocalException& ex)
535 // We cannot throw a C++ exception or raise a Ruby exception. If an error
536 // occurs while we are converting the exception, we do our best to return
537 // an appropriate Ruby exception.
541 string name = ex.ice_name();
542 volatile VALUE cls = callRuby(rb_path2class, name.c_str());
543 if(NIL_P(cls))
545 throw RubyException(rb_eRuntimeError, "exception class `%s' not found", name.c_str());
547 volatile VALUE result = callRuby(rb_class_new_instance, 0, reinterpret_cast<VALUE*>(0), cls);
548 setExceptionMembers(ex, result);
549 return result;
551 catch(const RubyException& e)
553 return e.ex;
555 catch(...)
557 string msg = "failure occurred while converting exception " + ex.ice_name();
558 return rb_exc_new2(rb_eRuntimeError, msg.c_str());