/* -*- mode: C++; c-file-style: "bsd" c-basic-offset: 4 -*- */
#include "pomni.h"
#undef minor
const I32 OFFSET = 0x10000000;
const I32 OPERATION_BASE = 0;
const I32 GETTER_BASE = OPERATION_BASE + OFFSET;
const I32 SETTER_BASE = GETTER_BASE + OFFSET;
static char *repoid_key = "_repoid";
static CORBA::Repository_ptr iface_repository = CORBA::Repository::_nil();
POmniIfaceInfo *
pomni_find_interface_description (pTHX_ const char *repoid)
{
HV *hv = get_hv("CORBA::omniORB::_interfaces", TRUE);
SV **result = hv_fetch (hv, (char *)repoid, strlen(repoid), 0);
if (!result)
return NULL;
else
return (POmniIfaceInfo *)INT2PTR(void *, SvIV(*result));
}
void
pomni_clear_interface (pTHX_ const char *repoid)
{
HV *hv = get_hv("CORBA::omniORB::_interfaces", TRUE);
SV **result = hv_fetch (hv, (char *)repoid, strlen(repoid), 0);
if (result) {
CM_DEBUG(("Clearing interface %s\n", repoid));
delete (POmniIfaceInfo *)INT2PTR(void *, SvIV(*result));
}
}
static POmniIfaceInfo *
store_interface_description (pTHX_ CORBA::InterfaceDef_ptr iface)
{
assert (iface != NULL);
CORBA::InterfaceDef::FullInterfaceDescription *desc =
iface->describe_interface();
const char *repoid = desc->id;
U32 len = strlen(repoid);
HV *hv = get_hv("CORBA::omniORB::_interfaces", TRUE);
SV **result = hv_fetch (hv, (char *)repoid, len, 0);
if (result) {
delete (POmniIfaceInfo *)INT2PTR(void *, SvIV(*result));
}
{
CORBA::String_var pkg = iface->absolute_name();
const char *pkgname;
if (!strncmp(pkg, "::", 2)) //FIXME:: always starts from '::' ?
pkgname = pkg + 2;
else
pkgname = pkg;
POmniIfaceInfo *info = new POmniIfaceInfo (pkgname,
CORBA::InterfaceDef::_duplicate(iface),
desc);
hv_store (hv, (char *)repoid, len, newSViv(PTR2IV((void *)info)), 0);
SV *pkg_sv = get_sv ( (char *)(std::string (pkg) + "::" + repoid_key).c_str(), TRUE );
sv_setpv (pkg_sv, repoid);
return info;
}
return NULL;
}
bool
pomni_is_a(pTHX_ const char *object_repoid, const char *interface_repoid)
{
CM_DEBUG(("pomni_is_a(%s, %s)\n", object_repoid, interface_repoid));
if(omni::ptrStrMatch(object_repoid, interface_repoid))
return true;
POmniIfaceInfo *object_info
= pomni_find_interface_description (aTHX_ object_repoid);
if(!object_info)
object_info = pomni_load_contained (aTHX_
CORBA::Contained::_nil(), NULL,
object_repoid);
if(!object_info)
return false;
CORBA::InterfaceDef::FullInterfaceDescription *desc = object_info->desc;
for(unsigned i = 0; i < desc->base_interfaces.length(); i++) {
if(pomni_is_a(aTHX_ desc->base_interfaces[i], interface_repoid))
return true;
}
return false;
}
static SV *
decode_exception (pTHX_
CORBA::Exception *ex,
CORBA::OperationDescription *opr)
{
CORBA::UnknownUserException *uuex
= CORBA::UnknownUserException::_downcast(ex);
CM_DEBUG(("decode_exception(ex='%s')\n", ex->_rep_id()));
if (uuex) {
// A user exception, check against the possible exceptions for
// this call.
CORBA::TypeCode_var tc = uuex->exception().type();
const char *repoid = (const char *) tc->id();
CM_DEBUG(("decode_exception():_except_repoid='%s')\n", repoid));
if (opr) {
for (unsigned int i = 0 ; i<opr->exceptions.length() ; i++) {
if (!strcmp(opr->exceptions[i].id, repoid)) {
SV *e = pomni_from_any (aTHX_ &uuex->exception());
delete ex;
return e;
}
}
}
delete ex;
return pomni_system_except (aTHX_
"IDL:omg.org/CORBA/UNKNOWN:1.0",
0, CORBA::COMPLETED_MAYBE);
}
else {
CORBA::SystemException *sysex = CORBA::SystemException::_downcast(ex);
if (sysex) {
SV *e = pomni_system_except(aTHX_
sysex->_rep_id(),
sysex->minor(),
sysex->completed());
delete ex;
return e;
}
else {
throw POmniCroak(aTHX_ "Panic: caught an impossible exception");
}
}
}
XS(_pomni_callStub)
{
dXSARGS;
try {
CORBA::ULong i, j;
I32 index = XSANY.any_i32;
SV **repoidp
= hv_fetch(CvSTASH(cv), repoid_key, strlen(repoid_key), 0);
if (!repoidp)
throw POmniCroak(aTHX_
"_pomni_callStub called with bad package (no %s)",
repoid_key);
char *repoid = SvPV(GvSV(*repoidp), PL_na);
POmniIfaceInfo *info = pomni_find_interface_description (aTHX_ repoid);
if (!info)
throw POmniCroak(aTHX_
"_pomni_callStub called on undefined interface");
CORBA::InterfaceDef::FullInterfaceDescription *desc = info->desc;
std::string name;
if (index >= OPERATION_BASE && index < GETTER_BASE) {
char *n = desc->operations[index - OPERATION_BASE].name;
name = std::string (n);
}
else if (index >= GETTER_BASE && index < SETTER_BASE) {
name = "_get_"
+ std::string(desc->attributes[index - GETTER_BASE].name);
}
else if (index >= SETTER_BASE) {
name = "_set_"
+ std::string(desc->attributes[index - SETTER_BASE].name);
}
CM_DEBUG(("calling operation %s (index %d) of %s\n",
name.c_str(), index, repoid));
// Get the discriminator
if (items < 1)
throw POmniCroak(aTHX_ "%s::%s must have object as first argument",
HvNAME(CvSTASH(cv)), name.c_str());
CORBA::Object_ptr obj = pomni_sv_to_objref(aTHX_ ST(0)); // may croak
if( CORBA::is_nil (obj) )
throw POmniCroak(aTHX_ "%s::%s is nil object",
HvNAME(CvSTASH(cv)), name.c_str ());
// Form the request
CORBA::Request_var req = obj->_request(name.c_str());
if (index >= OPERATION_BASE && index < GETTER_BASE) {
CORBA::OperationDescription *opr
= &desc->operations[index - OPERATION_BASE];
j = 1;
for (i = 0 ; i < opr->parameters.length(); i++) {
SV *arg = (j < (CORBA::ULong) items) ? ST(j) : &PL_sv_undef;
switch (opr->parameters[i].mode) {
case CORBA::PARAM_IN:
{
CORBA::Any argany( opr->parameters[i].type, 0 );
if (!pomni_to_any (aTHX_ &argany, arg))
throw POmniCroak (aTHX_
"Error marshalling "
"parameter '%s'",
(char *) opr->parameters[i].name);
req->add_in_arg (opr->parameters[i].name) = argany;
}
j++;
break;
case CORBA::PARAM_INOUT:
if (!SvROK(arg))
throw POmniCroak(aTHX_
"INOUT parameter must be a reference");
{
CORBA::Any argany(opr->parameters[i].type, 0 );
if (!pomni_to_any (aTHX_ &argany , SvRV(arg)))
throw POmniCroak (aTHX_
"Error marshalling "
"parameter '%s'",
(char *) opr->parameters[i].name);
req->add_inout_arg ( opr->parameters[i].name ) = argany;
}
j++;
break;
case CORBA::PARAM_OUT:
{
CORBA::Any argany(opr->parameters[i].type, 0 );
req->add_out_arg(opr->parameters[i].name) = argany;
break;
}
}
}
req->set_return_type(opr->result);
for (i = 0; i < opr->exceptions.length(); i++) {
req->exceptions()->add(opr->exceptions[i].type);
}
}
else if (index >= GETTER_BASE && index < SETTER_BASE) {
req->set_return_type ( desc->attributes[index-GETTER_BASE].type );
}
else if (index >= SETTER_BASE) {
if (items < 2)
throw POmniCroak(aTHX_ "%s::%s called without second argument",
HvNAME(CvSTASH(cv)), name.c_str());
CORBA::Any argany(desc->attributes[index - SETTER_BASE].type, 0);
if (!pomni_to_any (aTHX_ &argany, ST(1)))
throw POmniCroak(aTHX_ "Error marshalling attribute value");
req->add_in_arg ( "_value" ) = argany;
req->set_return_type (CORBA::_tc_void);
}
// Invoke request
PUTBACK;
try {
POmniPerlEntryUnlocker ul(aTHX);
req->invoke();
}
catch (CORBA::Exception &e) {
}
SPAGAIN;
CORBA::Exception *excp
= CORBA::Exception::_duplicate(req->env()->exception());
if (excp) {
CM_DEBUG(("_pomni_callStub():excp->_repoid='%s'\n",
excp->_rep_id()));
CORBA::OperationDescription *opr;
if (index >= OPERATION_BASE && index < GETTER_BASE) {
opr = &desc->operations[index - OPERATION_BASE];
}
else {
opr = NULL;
}
throw POmniThrowable(decode_exception(aTHX_ excp, opr));
// Will not return
}
// Get return and inout, and inout parameters
I32 return_count = 0;
CORBA::Any *result = req->result()->value();
CORBA::TypeCode_var result_tc = result->type();
if (result_tc->kind() != CORBA::tk_void) {
// FIXME, do the right thing in array and scalar contexts
SV *res = pomni_from_any (aTHX_ result);
if (res)
ST(0) = sv_2mortal(res); // we have at least 1 argument
else
ST(0) = &PL_sv_undef;
return_count++;
}
j = 1;
for (i = 0; i < req->arguments()->count() ; i++) {
CORBA::NamedValue *item = req->arguments()->item(i);
CM_DEBUG(("item %s has flags %#x\n",
(const char *) item->name(), item->flags()));
if (item->flags() == CORBA::ARG_INOUT) {
SV *res = pomni_from_any (aTHX_ item->value());
if (res)
sv_setsv (SvRV(ST(j)), res);
else
sv_setsv (SvRV(ST(j)), &PL_sv_undef);
j++;
} else if (item->flags () == CORBA::ARG_IN) {
j++;
}
}
for (i = 0; i < req->arguments()->count() ; i++) {
CORBA::NamedValue *item = req->arguments()->item(i);
if (item->flags() == CORBA::ARG_OUT) {
SV *res = pomni_from_any (aTHX_ item->value());
if (return_count >= items)
EXTEND(sp,1);
if (res)
ST(return_count) = sv_2mortal (res);
else
ST(return_count) = &PL_sv_undef;
return_count++;
}
}
XSRETURN(return_count);
}
CATCH_POMNI_TRAMPOLINE;
}
XS(_pomni_repoid) {
dXSARGS;
ST(0) = (SV *)CvXSUBANY(cv).any_ptr;
XSRETURN(1);
}
XS(_pomni_narrow) {
dXSARGS;
if (items != 2)
Perl_croak(aTHX_ "Usage: $class->_narrow(obj)");
try {
CORBA::Object *obj = pomni_sv_to_objref (aTHX_ ST(1));
if(!obj || obj->_NP_is_nil() || obj->_NP_is_pseudo()) {
ST(1) = newSVsv(&PL_sv_undef);
}
else {
char *narrow_repoid = SvPV_nolen((SV *)CvXSUBANY(cv).any_ptr);
const char *obj_repoid = obj->_PR_getobj()->_mostDerivedRepoId();
CM_DEBUG(("narrow %s to %s\n", obj_repoid, narrow_repoid));
if(obj_repoid[0] != '\0'
&& pomni_is_a(aTHX_ obj_repoid, narrow_repoid)) {
ST(0) = newSVsv(ST(1));
}
else if(obj->_is_a(narrow_repoid)) {
omniObjRef *oosource = obj->_PR_getobj();
omniIOR* ior = oosource->_getIOR()->duplicate();
omniObjRef *oodest;
{
omni_tracedmutex_lock sync(*omni::internalLock);
//oodest->pd_flags.forward_location
// = oosource->pd_flags.forward_location;
oodest = omni::createObjRef(narrow_repoid, ior, 1,
oosource->_identity());
oodest->_noExistentCheck();
}
void *e = oodest->_ptrToObjRef(CORBA::Object::_PD_repoId);
ST(0) = pomni_objref_to_sv(aTHX_ (CORBA::Object_ptr) e,
narrow_repoid);
}
else {
ST(0) = newSVsv(&PL_sv_undef);
}
}
}
CATCH_POMNI_SYSTEMEXCEPTION;
sv_2mortal(ST(0));
XSRETURN(1);
}
static void
define_exception (pTHX_ const char *repoid)
{
CM_DEBUG(("define_exception('%s')\n",repoid));
if (pomni_find_exception(aTHX_ repoid))
return;
CORBA::Contained_var contained(iface_repository->lookup_id (repoid));
CORBA::String_var pack(contained->absolute_name());
char *pkg = pack;
if (!strncmp(pkg, "::", 2))
pkg += 2;
pomni_setup_exception (aTHX_ repoid, pkg, "CORBA::UserException");
}
void
pomni_define_exception(pTHX_ const char *pkg, const char *repoid)
{
pomni_setup_exception (aTHX_ repoid, pkg, "CORBA::UserException");
}
static void
define_method (pTHX_ const char *pkg, const char *prefix, const char *name, I32 index)
{
std::string fullname = std::string (pkg) + prefix + name;
if( get_cv( (char *)fullname.c_str(), 0 ) ) {
return;
}
CV *method_cv = newXS ((char *)fullname.c_str(),
_pomni_callStub, __FILE__);
CvXSUBANY(method_cv).any_i32 = index;
CvSTASH (method_cv) = gv_stashpv ((char *)pkg, 0);
}
static void
ensure_iface_repository (CORBA::ORB_ptr _orb)
{
if (CORBA::is_nil(iface_repository)) {
CORBA::ORB_var orb = CORBA::ORB::_duplicate(_orb);
if (CORBA::is_nil(orb))
orb = CORBA::ORB::_duplicate(pomni_orb);
CORBA::Object_var obj =
orb->resolve_initial_references("InterfaceRepository");
try {
iface_repository = CORBA::Repository::_narrow(obj);
} catch(...) {
// exit below
}
}
if (CORBA::is_nil(iface_repository))
croak("Cannot contact interface repository");
}
#ifdef MEMCHECK
void
pomni_clear_iface_repository(pTHX)
{
CORBA::release(iface_repository);
iface_repository = CORBA::Repository::_nil();
}
#endif
static void
define_interface(pTHX_ POmniIfaceInfo *info, const char *id)
{
CORBA::InterfaceDef::FullInterfaceDescription *desc = info->desc;
if (!id)
id = desc->id;
// Set up the interface's operations and attributes
unsigned int i;
for ( i = 0 ; i < desc->operations.length() ; i++) {
CORBA::OperationDescription *opr = &desc->operations[i];
define_method (aTHX_ info->pkg.c_str(), "::", opr->name, OPERATION_BASE + i);
for ( unsigned int j = 0 ; j < opr->exceptions.length() ; j++)
define_exception (aTHX_ opr->exceptions[j].id);
}
for ( i = 0 ; i < desc->attributes.length() ; i++) {
if (desc->attributes[i].mode == CORBA::ATTR_NORMAL) {
define_method (aTHX_ info->pkg.c_str(), "::_set_", desc->attributes[i].name,
SETTER_BASE + i);
}
define_method (aTHX_ info->pkg.c_str(), "::_get_", desc->attributes[i].name,
GETTER_BASE + i);
}
// Register the base interfaces
AV *isa_av = get_av ( (char *)(info->pkg + "::ISA").c_str(), TRUE );
for ( i = 0 ; i < desc->base_interfaces.length() ; i++) {
POmniIfaceInfo *info = pomni_find_interface_description(aTHX_ desc->base_interfaces[i]);
if (!info) {
CORBA::Contained_var base = iface_repository->lookup_id (desc->base_interfaces[i]);
if (!CORBA::is_nil (base) &&
(base->def_kind() == CORBA::dk_Interface)) {
CORBA::InterfaceDef_var intf = CORBA::InterfaceDef::_narrow (base);
info = pomni_load_contained (aTHX_ intf, NULL, NULL);
}
}
if (info)
av_push (isa_av, newSVpv((char *)info->pkg.c_str(), 0));
}
if (desc->base_interfaces.length() == 0) {
av_push (isa_av, newSVpv("CORBA::Object", 0));
}
// Set up the server side package
isa_av = get_av ( (char *)("POA_" + info->pkg + "::ISA").c_str(), TRUE );
av_push (isa_av, newSVpv("PortableServer::ServantBase", 0));
// Create a package method that will allow us to determine the
// repository id before we have the omniORB object set up
std::string fullname = "POA_" + info->pkg + "::_pomni_repoid";
CV *method_cv = newXS ((char *)fullname.c_str(), _pomni_repoid, __FILE__);
CvXSUBANY(method_cv).any_ptr = (void *)newSVpv((char *)id, 0);
// Create a package method for performing a narrowing operation
fullname = info->pkg + "::_narrow";
method_cv = newXS ((char *)fullname.c_str(), _pomni_narrow, __FILE__);
CvXSUBANY(method_cv).any_ptr = (void *)newSVpv((char *)id, 0);
}
static POmniIfaceInfo *
pomni_init_interface (pTHX_ CORBA::InterfaceDef_ptr iface, const char *id)
{
// Save the interface description for later reference
POmniIfaceInfo *info = store_interface_description (aTHX_ iface);
define_interface(aTHX_ info, id);
return info;
}
void
pomni_define_interface(pTHX_ const char *pkg,
CORBA::InterfaceDef::FullInterfaceDescription *desc)
{
const char *repoid = desc->id;
U32 len = strlen(repoid);
POmniIfaceInfo *info
= new POmniIfaceInfo (pkg, CORBA::InterfaceDef::_nil(), desc);
HV *hv = get_hv("CORBA::omniORB::_interfaces", TRUE);
hv_store (hv, (char *)repoid, len, newSViv(PTR2IV((void *) info)), 0);
SV *pkg_sv = get_sv((char *)(std::string (pkg) + "::" + repoid_key).c_str(), TRUE );
sv_setpv (pkg_sv, repoid);
define_interface(aTHX_ info, NULL);
}
void
pomni_init_constant (pTHX_ const char *pkgname, CORBA::ConstantDef_ptr cd)
{
CORBA::String_var name = cd->name();
// Extract the value
CORBA::Any *value = cd->value();
SV *sv = pomni_from_any (aTHX_ value);
delete value;
// Create a constant-valued sub with that value
HV *stash = gv_stashpv ((char *)pkgname, TRUE);
newCONSTSUB (stash, name, sv);
}
POmniIfaceInfo *
pomni_load_contained (pTHX_
CORBA::Contained_ptr _contained, CORBA::ORB_ptr _orb,
const char *_id)
{
assert (_contained != NULL || _id != NULL);
CM_DEBUG(("pomni_load_contained(%p,%p,'%s')\n",_contained,_orb,_id));
CORBA::Contained_var contained = CORBA::Contained::_duplicate (_contained);
if (CORBA::is_nil(contained)) {
ensure_iface_repository (_orb);
contained = iface_repository->lookup_id((char *)_id);
if (CORBA::is_nil(contained))
croak("Cannot find '%s' in interface repository", _id);
}
if (CORBA::is_nil(iface_repository))
iface_repository = contained->containing_repository();
// If the container is an interface, suck all the information
// out of it for later use.
POmniIfaceInfo *retval;
CORBA::InterfaceDef_var iface = CORBA::InterfaceDef::_narrow (contained);
if (!CORBA::is_nil(iface))
retval = pomni_init_interface (aTHX_ iface, _id);
else
retval = NULL;
// If the container is an exception, define it
CORBA::ExceptionDef_var excp = CORBA::ExceptionDef::_narrow (contained);
if( !CORBA::is_nil(excp) )
define_exception(aTHX_ excp->id());
// Initialize all constants in the container, and all
// enclosed interfaces.
CORBA::Container_var container = CORBA::Container::_narrow (contained);
if (!CORBA::is_nil(container)) {
CORBA::ContainedSeq_var contents =
container->contents (CORBA::dk_Constant, true);
if (contents->length() > 0) {
std::string pkgname;
if (retval)
pkgname = retval->pkg.c_str();
else {
CORBA::String_var pkg = contained->absolute_name();
if (!strncmp(pkg, "::", 2))
pkgname = &pkg[(CORBA::ULong)2];
else
pkgname = pkg;
}
for (CORBA::ULong i = 0; i<contents->length(); i++) {
CORBA::ConstantDef_var cd =
CORBA::ConstantDef::_narrow (contents[i]);
pomni_init_constant (aTHX_ pkgname.c_str(), cd);
}
}
contents = container->contents (CORBA::dk_Interface, true);
for (CORBA::ULong i = 0; i<contents->length(); i++) {
CORBA::String_var id = contents[i]->id();
if (!pomni_find_interface_description (aTHX_ id))
pomni_load_contained (aTHX_ contents[i], _orb, NULL);
}
}
return retval;
}
SV *
store_typecode (pTHX_ const char *id, CORBA::TypeCode_ptr tc)
{
SV *res = newSV(0);
sv_setref_iv (res, "CORBA::TypeCode", PTR2IV((void *) tc));
HV *typecode_cache = get_hv("CORBA::TypeCode::_cache", TRUE);
hv_store (typecode_cache, (char *)id, strlen(id), res, 0);
return res;
}
SV *
pomni_lookup_typecode (pTHX_ const char *id)
{
HV *typecode_cache = get_hv("CORBA::TypeCode::_cache", TRUE);
SV **svp = hv_fetch (typecode_cache, (char *)id, strlen(id), 0);
if (!svp) {
ensure_iface_repository (NULL);
CORBA::Contained_var c = iface_repository->lookup_id ((char *)id);
CORBA::IDLType_var t = CORBA::IDLType::_narrow(c);
if (CORBA::is_nil(t))
return NULL;
CORBA::TypeCode_ptr tc = t->type();
return SvREFCNT_inc(store_typecode (aTHX_ id, tc));
}
return SvREFCNT_inc(*svp);
}
void
pomni_init_typecodes (pTHX)
{
store_typecode (aTHX_ "IDL:CORBA/Short:1.0",
CORBA::TypeCode::_duplicate(CORBA::_tc_short));
store_typecode (aTHX_ "IDL:CORBA/Long:1.0",
CORBA::TypeCode::_duplicate(CORBA::_tc_long));
store_typecode (aTHX_ "IDL:CORBA/UShort:1.0",
CORBA::TypeCode::_duplicate(CORBA::_tc_ushort));
store_typecode (aTHX_ "IDL:CORBA/ULong:1.0",
CORBA::TypeCode::_duplicate(CORBA::_tc_ulong));
store_typecode (aTHX_ "IDL:CORBA/Float:1.0",
CORBA::TypeCode::_duplicate(CORBA::_tc_float));
store_typecode (aTHX_ "IDL:CORBA/Double:1.0",
CORBA::TypeCode::_duplicate(CORBA::_tc_double));
store_typecode (aTHX_ "IDL:CORBA/Boolean:1.0",
CORBA::TypeCode::_duplicate(CORBA::_tc_boolean));
store_typecode (aTHX_ "IDL:CORBA/Char:1.0",
CORBA::TypeCode::_duplicate(CORBA::_tc_char));
store_typecode (aTHX_ "IDL:CORBA/Octet:1.0",
CORBA::TypeCode::_duplicate(CORBA::_tc_octet));
store_typecode (aTHX_ "IDL:CORBA/Any:1.0",
CORBA::TypeCode::_duplicate(CORBA::_tc_any));
store_typecode (aTHX_ "IDL:CORBA/TypeCode:1.0",
CORBA::TypeCode::_duplicate(CORBA::_tc_TypeCode));
store_typecode (aTHX_ "IDL:CORBA/Principal:1.0",
CORBA::TypeCode::_duplicate(CORBA::_tc_Principal));
store_typecode (aTHX_ "IDL:CORBA/Object:1.0",
CORBA::TypeCode::_duplicate(CORBA::_tc_Object));
store_typecode (aTHX_ "IDL:CORBA/String:1.0",
CORBA::TypeCode::_duplicate(CORBA::_tc_string));
}
#ifdef MEMCHECK
void
pomni_clear_typecodes(pTHX)
{
HV *typecode_cache = get_hv("CORBA::TypeCode::_cache", FALSE);
if(!typecode_cache)
return;
hv_undef(typecode_cache);
}
#endif
void
pomni_clone_typecodes(pTHX)
{
HV *typecode_cache = get_hv("CORBA::TypeCode::_cache", FALSE);
if(!typecode_cache)
return;
hv_iterinit(typecode_cache);
HE *entry;
while((entry = hv_iternext(typecode_cache)) != 0) {
SV *ref = hv_iterval(typecode_cache, entry);
if(SvROK(ref)) {
SV *iv = SvRV(ref);
CORBA::TypeCode_ptr tc
= (CORBA::TypeCode_ptr) INT2PTR(void *, SvIV(iv));
sv_setiv(iv, PTR2IV((void *) CORBA::TypeCode::_duplicate(tc)));
}
}
}