PageRenderTime 50ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/Ice-3.4.2/rb/src/IceRuby/Util.cpp

#
C++ | 560 lines | 490 code | 44 blank | 26 comment | 48 complexity | 0715280b42aa05e0ce272f0842604030 MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause
  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. // **********************************************************************
  9. #include <Util.h>
  10. #include <Ice/LocalException.h>
  11. #include <stdarg.h>
  12. using namespace std;
  13. using namespace IceRuby;
  14. extern "C"
  15. VALUE
  16. IceRuby_stringVersion(int /*argc*/, VALUE* /*argv*/, VALUE /*self*/)
  17. {
  18. ICE_RUBY_TRY
  19. {
  20. string s = ICE_STRING_VERSION;
  21. return createString(s);
  22. }
  23. ICE_RUBY_CATCH
  24. return Qnil;
  25. }
  26. extern "C"
  27. VALUE
  28. IceRuby_intVersion(int /*argc*/, VALUE* /*argv*/, VALUE /*self*/)
  29. {
  30. ICE_RUBY_TRY
  31. {
  32. return INT2FIX(ICE_INT_VERSION);
  33. }
  34. ICE_RUBY_CATCH
  35. return Qnil;
  36. }
  37. void
  38. IceRuby::initUtil(VALUE iceModule)
  39. {
  40. rb_define_module_function(iceModule, "stringVersion", CAST_METHOD(IceRuby_stringVersion), -1);
  41. rb_define_module_function(iceModule, "intVersion", CAST_METHOD(IceRuby_intVersion), -1);
  42. }
  43. IceRuby::RubyException::RubyException()
  44. {
  45. ex = rb_gv_get("$!");
  46. }
  47. IceRuby::RubyException::RubyException(VALUE exv) :
  48. ex(exv)
  49. {
  50. }
  51. IceRuby::RubyException::RubyException(VALUE exClass, const char* fmt, ...)
  52. {
  53. va_list args;
  54. char buf[BUFSIZ];
  55. va_start(args, fmt);
  56. vsnprintf(buf, BUFSIZ, fmt, args);
  57. buf[BUFSIZ - 1] = '\0';
  58. va_end(args);
  59. ex = callRuby(rb_exc_new2, exClass, buf);
  60. }
  61. ostream&
  62. IceRuby::RubyException::operator<<(ostream& ostr) const
  63. {
  64. volatile VALUE cls = rb_class_path(CLASS_OF(ex));
  65. volatile VALUE msg = rb_obj_as_string(ex);
  66. ostr << RSTRING_PTR(cls) << ": " << RSTRING_PTR(msg);
  67. return ostr;
  68. }
  69. bool
  70. IceRuby::isString(VALUE val)
  71. {
  72. return TYPE(val) == T_STRING || callRuby(rb_respond_to, val, rb_intern("to_str")) != 0;
  73. }
  74. bool
  75. IceRuby::isArray(VALUE val)
  76. {
  77. return TYPE(val) == T_ARRAY || callRuby(rb_respond_to, val, rb_intern("to_arr")) != 0;
  78. }
  79. bool
  80. IceRuby::isHash(VALUE val)
  81. {
  82. return TYPE(val) == T_HASH || callRuby(rb_respond_to, val, rb_intern("to_hash")) != 0;
  83. }
  84. string
  85. IceRuby::getString(VALUE val)
  86. {
  87. volatile VALUE result = callRuby(rb_string_value, &val);
  88. return string(RSTRING_PTR(result), RSTRING_LEN(result));
  89. }
  90. VALUE
  91. IceRuby::createString(const string& str)
  92. {
  93. return callRuby(rb_str_new, str.c_str(), static_cast<long>(str.size()));
  94. }
  95. long
  96. IceRuby::getInteger(VALUE val)
  97. {
  98. if(!FIXNUM_P(val) && TYPE(val) != T_BIGNUM)
  99. {
  100. val = callRuby(rb_Integer, val);
  101. }
  102. if(FIXNUM_P(val))
  103. {
  104. return FIX2LONG(val);
  105. }
  106. else if(TYPE(val) == T_BIGNUM)
  107. {
  108. Ice::Long l = getLong(val);
  109. if(l >= static_cast<Ice::Long>(INT_MIN) && l <= static_cast<Ice::Long>(INT_MAX))
  110. {
  111. return static_cast<long>(l);
  112. }
  113. }
  114. throw RubyException(rb_eTypeError, "unable to convert value to an integer");
  115. }
  116. #define BITSPERDIG (SIZEOF_BDIGITS*CHAR_BIT)
  117. #define BIGUP(x) ((BDIGIT_DBL)(x) << BITSPERDIG)
  118. Ice::Long
  119. IceRuby::getLong(VALUE val)
  120. {
  121. //
  122. // The rb_num2ll function raises exceptions, but we can't call it using callProtected
  123. // because its return type is long long and not VALUE.
  124. //
  125. volatile VALUE v = callRuby(rb_Integer, val);
  126. if(NIL_P(v))
  127. {
  128. throw RubyException(rb_eTypeError, "unable to convert value to a long");
  129. }
  130. if(FIXNUM_P(v))
  131. {
  132. return FIX2LONG(v);
  133. }
  134. else
  135. {
  136. assert(TYPE(v) == T_BIGNUM);
  137. long len = RBIGNUM_LEN(v);
  138. if(len > SIZEOF_LONG_LONG/SIZEOF_BDIGITS)
  139. {
  140. throw RubyException(rb_eRangeError, "bignum too big to convert into long");
  141. }
  142. BDIGIT *ds = RBIGNUM_DIGITS(v);
  143. BDIGIT_DBL num = 0;
  144. while(len--)
  145. {
  146. num = BIGUP(num);
  147. num += ds[len];
  148. }
  149. Ice::Long l = static_cast<Ice::Long>(num);
  150. if(l < 0 && (RBIGNUM_SIGN(v) || l != LLONG_MIN))
  151. {
  152. throw RubyException(rb_eRangeError, "bignum too big to convert into long");
  153. }
  154. if (!RBIGNUM_SIGN(v))
  155. {
  156. return -l;
  157. }
  158. return l;
  159. }
  160. }
  161. bool
  162. IceRuby::arrayToStringSeq(VALUE val, vector<string>& seq)
  163. {
  164. volatile VALUE arr = callRuby(rb_check_array_type, val);
  165. if(NIL_P(arr))
  166. {
  167. return false;
  168. }
  169. for(long i = 0; i < RARRAY_LEN(arr); ++i)
  170. {
  171. string s = getString(RARRAY_PTR(arr)[i]);
  172. seq.push_back(getString(RARRAY_PTR(arr)[i]));
  173. }
  174. return true;
  175. }
  176. VALUE
  177. IceRuby::stringSeqToArray(const vector<string>& seq)
  178. {
  179. volatile VALUE result = createArray(seq.size());
  180. long i = 0;
  181. if(seq.size() > 0)
  182. {
  183. for(vector<string>::const_iterator p = seq.begin(); p != seq.end(); ++p, ++i)
  184. {
  185. RARRAY_PTR(result)[i] = createString(*p);
  186. }
  187. }
  188. return result;
  189. }
  190. namespace
  191. {
  192. struct HashToContextIterator : public IceRuby::HashIterator
  193. {
  194. HashToContextIterator(Ice::Context& c) : ctx(c)
  195. {
  196. }
  197. virtual void element(VALUE key, VALUE value)
  198. {
  199. string kstr = IceRuby::getString(key);
  200. string vstr = IceRuby::getString(value);
  201. ctx[kstr] = vstr;
  202. }
  203. Ice::Context& ctx;
  204. };
  205. }
  206. bool
  207. IceRuby::hashToContext(VALUE val, Ice::Context& ctx)
  208. {
  209. if(TYPE(val) != T_HASH)
  210. {
  211. val = callRuby(rb_convert_type, val, T_HASH, "Hash", "to_hash");
  212. if(NIL_P(val))
  213. {
  214. return false;
  215. }
  216. }
  217. HashToContextIterator iter(ctx);
  218. hashIterate(val, iter);
  219. return true;
  220. }
  221. VALUE
  222. IceRuby::contextToHash(const Ice::Context& ctx)
  223. {
  224. volatile VALUE result = callRuby(rb_hash_new);
  225. for(Ice::Context::const_iterator p = ctx.begin(); p != ctx.end(); ++p)
  226. {
  227. volatile VALUE key = callRuby(rb_str_new, p->first.c_str(), static_cast<long>(p->first.size()));
  228. volatile VALUE value = callRuby(rb_str_new, p->second.c_str(), static_cast<long>(p->second.size()));
  229. callRuby(rb_hash_aset, result, key, value);
  230. }
  231. return result;
  232. }
  233. extern "C"
  234. VALUE
  235. IceRuby_Util_hash_foreach_callback(VALUE val, VALUE arg)
  236. {
  237. VALUE key = rb_ary_entry(val, 0);
  238. VALUE value = rb_ary_entry(val, 1);
  239. //
  240. // We can't allow any C++ exceptions to propagate out of this function.
  241. //
  242. ICE_RUBY_TRY
  243. {
  244. IceRuby::HashIterator* iter = reinterpret_cast<IceRuby::HashIterator*>(arg);
  245. iter->element(key, value);
  246. }
  247. ICE_RUBY_CATCH
  248. return val;
  249. }
  250. extern "C"
  251. {
  252. typedef VALUE (*ICE_RUBY_HASH_FOREACH_CALLBACK)(...);
  253. }
  254. void
  255. IceRuby::hashIterate(VALUE h, HashIterator& iter)
  256. {
  257. assert(TYPE(h) == T_HASH);
  258. callRuby(rb_iterate, rb_each, h,
  259. reinterpret_cast<ICE_RUBY_HASH_FOREACH_CALLBACK>(IceRuby_Util_hash_foreach_callback),
  260. reinterpret_cast<VALUE>(&iter));
  261. }
  262. Ice::Identity
  263. IceRuby::getIdentity(VALUE v)
  264. {
  265. volatile VALUE cls = callRuby(rb_path2class, "Ice::Identity");
  266. assert(!NIL_P(cls));
  267. if(callRuby(rb_obj_is_kind_of, v, cls) == Qfalse)
  268. {
  269. throw RubyException(rb_eTypeError, "value is not an Ice::Identity");
  270. }
  271. volatile VALUE name = callRuby(rb_iv_get, v, "@name");
  272. volatile VALUE category = callRuby(rb_iv_get, v, "@category");
  273. if(!NIL_P(category) && !isString(category))
  274. {
  275. throw RubyException(rb_eTypeError, "identity category must be a string");
  276. }
  277. if(NIL_P(name) || !isString(name))
  278. {
  279. throw RubyException(rb_eTypeError, "identity name must be a string");
  280. }
  281. Ice::Identity result;
  282. result.name = getString(name);
  283. if(!NIL_P(category))
  284. {
  285. result.category = getString(category);
  286. }
  287. return result;
  288. }
  289. VALUE
  290. IceRuby::createIdentity(const Ice::Identity& id)
  291. {
  292. volatile VALUE cls = callRuby(rb_path2class, "Ice::Identity");
  293. assert(!NIL_P(cls));
  294. volatile VALUE result = callRuby(rb_class_new_instance, 0, reinterpret_cast<VALUE*>(0), cls);
  295. volatile VALUE name = callRuby(rb_str_new, id.name.c_str(), static_cast<long>(id.name.size()));
  296. volatile VALUE category = callRuby(rb_str_new, id.category.c_str(), static_cast<long>(id.category.size()));
  297. callRuby(rb_iv_set, result, "@name", name);
  298. callRuby(rb_iv_set, result, "@category", category);
  299. return result;
  300. }
  301. VALUE
  302. IceRuby::callProtected(RubyFunction func, VALUE arg)
  303. {
  304. int error = 0;
  305. volatile VALUE result = rb_protect(func, arg, &error);
  306. if(error)
  307. {
  308. throw RubyException();
  309. }
  310. return result;
  311. }
  312. static void
  313. setExceptionMembers(const Ice::LocalException& ex, VALUE p)
  314. {
  315. //
  316. // Transfer data members from Ice exception to Ruby exception.
  317. //
  318. try
  319. {
  320. ex.ice_throw();
  321. }
  322. catch(const Ice::InitializationException& e)
  323. {
  324. volatile VALUE v = createString(e.reason);
  325. callRuby(rb_iv_set, p, "@reason", v);
  326. }
  327. catch(const Ice::PluginInitializationException& e)
  328. {
  329. volatile VALUE v = createString(e.reason);
  330. callRuby(rb_iv_set, p, "@reason", v);
  331. }
  332. catch(const Ice::AlreadyRegisteredException& e)
  333. {
  334. volatile VALUE v;
  335. v = createString(e.kindOfObject);
  336. callRuby(rb_iv_set, p, "@kindOfObject", v);
  337. v = createString(e.id);
  338. callRuby(rb_iv_set, p, "@id", v);
  339. }
  340. catch(const Ice::NotRegisteredException& e)
  341. {
  342. volatile VALUE v;
  343. v = createString(e.kindOfObject);
  344. callRuby(rb_iv_set, p, "@kindOfObject", v);
  345. v = createString(e.id);
  346. callRuby(rb_iv_set, p, "@id", v);
  347. }
  348. catch(const Ice::TwowayOnlyException& e)
  349. {
  350. volatile VALUE v = createString(e.operation);
  351. callRuby(rb_iv_set, p, "@operation", v);
  352. }
  353. catch(const Ice::UnknownException& e)
  354. {
  355. volatile VALUE v = createString(e.unknown);
  356. callRuby(rb_iv_set, p, "@unknown", v);
  357. }
  358. catch(const Ice::ObjectAdapterDeactivatedException& e)
  359. {
  360. volatile VALUE v = createString(e.name);
  361. callRuby(rb_iv_set, p, "@name", v);
  362. }
  363. catch(const Ice::ObjectAdapterIdInUseException& e)
  364. {
  365. volatile VALUE v = createString(e.id);
  366. callRuby(rb_iv_set, p, "@id", v);
  367. }
  368. catch(const Ice::NoEndpointException& e)
  369. {
  370. volatile VALUE v = createString(e.proxy);
  371. callRuby(rb_iv_set, p, "@proxy", v);
  372. }
  373. catch(const Ice::EndpointParseException& e)
  374. {
  375. volatile VALUE v = createString(e.str);
  376. callRuby(rb_iv_set, p, "@str", v);
  377. }
  378. catch(const Ice::IdentityParseException& e)
  379. {
  380. volatile VALUE v = createString(e.str);
  381. callRuby(rb_iv_set, p, "@str", v);
  382. }
  383. catch(const Ice::ProxyParseException& e)
  384. {
  385. volatile VALUE v = createString(e.str);
  386. callRuby(rb_iv_set, p, "@str", v);
  387. }
  388. catch(const Ice::IllegalIdentityException& e)
  389. {
  390. volatile VALUE v = IceRuby::createIdentity(e.id);
  391. callRuby(rb_iv_set, p, "@id", v);
  392. }
  393. catch(const Ice::RequestFailedException& e)
  394. {
  395. volatile VALUE v;
  396. v = IceRuby::createIdentity(e.id);
  397. callRuby(rb_iv_set, p, "@id", v);
  398. v = createString(e.facet);
  399. callRuby(rb_iv_set, p, "@facet", v);
  400. v = createString(e.operation);
  401. callRuby(rb_iv_set, p, "@operation", v);
  402. }
  403. catch(const Ice::FileException& e)
  404. {
  405. volatile VALUE v = INT2FIX(e.error);
  406. callRuby(rb_iv_set, p, "@error", v);
  407. v = createString(e.path);
  408. callRuby(rb_iv_set, p, "@path", v);
  409. }
  410. catch(const Ice::SyscallException& e) // This must appear after all subclasses of SyscallException.
  411. {
  412. volatile VALUE v = INT2FIX(e.error);
  413. callRuby(rb_iv_set, p, "@error", v);
  414. }
  415. catch(const Ice::DNSException& e)
  416. {
  417. volatile VALUE v;
  418. v = INT2FIX(e.error);
  419. callRuby(rb_iv_set, p, "@error", v);
  420. v = createString(e.host);
  421. callRuby(rb_iv_set, p, "@host", v);
  422. }
  423. catch(const Ice::UnsupportedProtocolException& e)
  424. {
  425. callRuby(rb_iv_set, p, "@badMajor", INT2FIX(e.badMajor));
  426. callRuby(rb_iv_set, p, "@badMinor", INT2FIX(e.badMinor));
  427. callRuby(rb_iv_set, p, "@major", INT2FIX(e.major));
  428. callRuby(rb_iv_set, p, "@minor", INT2FIX(e.minor));
  429. }
  430. catch(const Ice::UnsupportedEncodingException& e)
  431. {
  432. callRuby(rb_iv_set, p, "@badMajor", INT2FIX(e.badMajor));
  433. callRuby(rb_iv_set, p, "@badMinor", INT2FIX(e.badMinor));
  434. callRuby(rb_iv_set, p, "@major", INT2FIX(e.major));
  435. callRuby(rb_iv_set, p, "@minor", INT2FIX(e.minor));
  436. }
  437. catch(const Ice::NoObjectFactoryException& e)
  438. {
  439. volatile VALUE v;
  440. v = createString(e.reason);
  441. callRuby(rb_iv_set, p, "@reason", v);
  442. v = createString(e.type);
  443. callRuby(rb_iv_set, p, "@type", v);
  444. }
  445. catch(const Ice::UnexpectedObjectException& e)
  446. {
  447. volatile VALUE v;
  448. v = createString(e.reason);
  449. callRuby(rb_iv_set, p, "@reason", v);
  450. v = createString(e.type);
  451. callRuby(rb_iv_set, p, "@type", v);
  452. v = createString(e.expectedType);
  453. callRuby(rb_iv_set, p, "@expectedType", v);
  454. }
  455. catch(const Ice::ProtocolException& e) // This must appear after all subclasses of ProtocolException.
  456. {
  457. volatile VALUE v = createString(e.reason);
  458. callRuby(rb_iv_set, p, "@reason", v);
  459. }
  460. catch(const Ice::FeatureNotSupportedException& e)
  461. {
  462. volatile VALUE v = createString(e.unsupportedFeature);
  463. callRuby(rb_iv_set, p, "@unsupportedFeature", v);
  464. }
  465. catch(const Ice::SecurityException& e)
  466. {
  467. volatile VALUE v = createString(e.reason);
  468. callRuby(rb_iv_set, p, "@reason", v);
  469. }
  470. catch(const Ice::LocalException&)
  471. {
  472. //
  473. // Nothing to do.
  474. //
  475. }
  476. }
  477. VALUE
  478. IceRuby::createArrayHelper(long sz)
  479. {
  480. VALUE arr = callRuby(rb_ary_new2, sz);
  481. if(sz > 0)
  482. {
  483. callRubyVoid(rb_ary_store, arr, sz - 1, Qnil);
  484. }
  485. return arr;
  486. }
  487. VALUE
  488. IceRuby::convertLocalException(const Ice::LocalException& ex)
  489. {
  490. //
  491. // We cannot throw a C++ exception or raise a Ruby exception. If an error
  492. // occurs while we are converting the exception, we do our best to return
  493. // an appropriate Ruby exception.
  494. //
  495. try
  496. {
  497. string name = ex.ice_name();
  498. volatile VALUE cls = callRuby(rb_path2class, name.c_str());
  499. if(NIL_P(cls))
  500. {
  501. throw RubyException(rb_eRuntimeError, "exception class `%s' not found", name.c_str());
  502. }
  503. volatile VALUE result = callRuby(rb_class_new_instance, 0, reinterpret_cast<VALUE*>(0), cls);
  504. setExceptionMembers(ex, result);
  505. return result;
  506. }
  507. catch(const RubyException& e)
  508. {
  509. return e.ex;
  510. }
  511. catch(...)
  512. {
  513. string msg = "failure occurred while converting exception " + ex.ice_name();
  514. return rb_exc_new2(rb_eRuntimeError, msg.c_str());
  515. }
  516. }