mummy  1.0.2
MummyCsharpExportLayerGenerator.cxx
Go to the documentation of this file.
00001 //----------------------------------------------------------------------------
00002 //
00003 //  $Id: MummyCsharpExportLayerGenerator.cxx 2 2007-12-17 18:15:56Z david.cole $
00004 //
00005 //  $Author: david.cole $
00006 //  $Date: 2007-12-17 13:15:56 -0500 (Mon, 17 Dec 2007) $
00007 //  $Revision: 2 $
00008 //
00009 //  Copyright (C) 2006-2007 Kitware, Inc.
00010 //
00011 //----------------------------------------------------------------------------
00012 
00013 #include "MummyCsharpExportLayerGenerator.h"
00014 #include "MummyCsharpGenerator.h"
00015 #include "MummyLog.h"
00016 #include "MummySettings.h"
00017 
00018 #include "cableClass.h"
00019 #include "cableClassType.h"
00020 #include "cableConstructor.h"
00021 #include "cableFunctionType.h"
00022 #include "cableMethod.h"
00023 #include "cablePointerType.h"
00024 #include "cableReferenceType.h"
00025 #include "cxxCvQualifiedType.h"
00026 #include "cxxFunctionType.h"
00027 #include "cxxPointerType.h"
00028 #include "cxxType.h"
00029 
00030 #include "gxsys/stl/set"
00031 #include "gxsys/SystemTools.hxx"
00032 
00033 
00034 //----------------------------------------------------------------------------
00035 MummyCsharpExportLayerGenerator::MummyCsharpExportLayerGenerator()
00036 {
00037   this->CsharpGenerator = 0;
00038 }
00039 
00040 
00041 //----------------------------------------------------------------------------
00042 MummyCsharpExportLayerGenerator::~MummyCsharpExportLayerGenerator()
00043 {
00044 }
00045 
00046 
00047 //----------------------------------------------------------------------------
00048 bool MummyCsharpExportLayerGenerator::GenerateWrappers()
00049 {
00050   this->EmitClassForExportLayer(*GetStream(), GetTargetClass());
00051   return false;
00052 }
00053 
00054 
00055 //----------------------------------------------------------------------------
00056 MummyCsharpGenerator* MummyCsharpExportLayerGenerator::GetCsharpGenerator()
00057 {
00058   return this->CsharpGenerator;
00059 }
00060 
00061 
00062 //----------------------------------------------------------------------------
00063 void MummyCsharpExportLayerGenerator::SetCsharpGenerator(MummyCsharpGenerator* generator)
00064 {
00065   this->CsharpGenerator = generator;
00066 }
00067 
00068 
00069 //----------------------------------------------------------------------------
00070 //bool MummyCsharpExportLayerGenerator::FundamentalTypeIsWrappable(const cable::Type* t)
00071 //{
00072 //  return this->GetCsharpGenerator()->FundamentalTypeIsWrappable(t);
00073 //}
00074 
00075 
00076 //----------------------------------------------------------------------------
00077 //bool MummyCsharpExportLayerGenerator::TypeIsWrappable(const cable::Type* t)
00078 //{
00079 //  return this->GetCsharpGenerator()->TypeIsWrappable(t);
00080 //}
00081 
00082 
00083 //----------------------------------------------------------------------------
00084 //bool MummyCsharpExportLayerGenerator::FunctionTypeIsWrappable(const cable::FunctionType* ft)
00085 //{
00086 //  return this->GetCsharpGenerator()->FunctionTypeIsWrappable(ft);
00087 //}
00088 
00089 
00090 //----------------------------------------------------------------------------
00091 //bool MummyCsharpExportLayerGenerator::MethodIsWrappable(const cable::Method* m, const cable::Context::Access& access)
00092 //{
00093 //  return this->GetCsharpGenerator()->MethodIsWrappable(m, access);
00094 //}
00095 
00096 
00097 //----------------------------------------------------------------------------
00098 //bool MummyCsharpExportLayerGenerator::ClassIsWrappable(const cable::Class* c)
00099 //{
00100 //  return this->GetCsharpGenerator()->ClassIsWrappable(c);
00101 //}
00102 
00103 
00104 //----------------------------------------------------------------------------
00105 const char *MummyCsharpExportLayerGenerator::GetArgName(cable::FunctionType *ftype, unsigned int i)
00106 {
00107   return this->GetCsharpGenerator()->GetArgName(ftype, i);
00108 }
00109 
00110 
00111 //----------------------------------------------------------------------------
00112 gxsys_stl::string MummyCsharpExportLayerGenerator::GetExportLayerFunctionName(const cable::Class *c, const cable::Method *m, const gxsys_stl::string& mname)
00113 {
00114   return this->GetCsharpGenerator()->GetExportLayerFunctionName(c, m, mname);
00115 }
00116 
00117 
00118 //----------------------------------------------------------------------------
00119 gxsys_stl::string GetExportLayerActualType(cable::Type *t, bool stripConst)
00120 {
00121   gxsys_stl::string s(t->GetCxxType().GetName());
00122 
00123   if (stripConst)
00124     {
00125     s = t->GetCxxType().GetType()->GenerateName("", false, false);
00126     }
00127 
00128   return s;
00129 }
00130 
00131 
00132 //----------------------------------------------------------------------------
00133 gxsys_stl::string GetExportLayerMappedType(cable::Type *t, bool stripConst)
00134 {
00135   gxsys_stl::string s;
00136 
00137   if (HasMapToType(t))
00138     {
00139     // 't' should be either a class or a reference to a class...
00140     //
00141     cable::Class* c = 0;
00142 
00143     if (cable::Type::ClassTypeId == t->GetTypeId())
00144       {
00145       c = cable::ClassType::SafeDownCast(t)->GetClass();
00146       }
00147     else if (cable::Type::ReferenceTypeId == t->GetTypeId())
00148       {
00149       c = cable::ClassType::SafeDownCast(
00150         cable::ReferenceType::SafeDownCast(t)->GetTarget())->GetClass();
00151       }
00152 
00153     if (c)
00154       {
00155       s = ExtractMapToType(c);
00156       }
00157 
00158     // Abstract "string" type translates to "const char*" in the export layer:
00159     //
00160     if (s == "string")
00161       {
00162       if (stripConst)
00163         {
00164         s = "char*";
00165         }
00166       else
00167         {
00168         s = "const char*";
00169         }
00170       }
00171     else
00172       {
00173       s = "ERROR_unknown_mapped_to_type_or_null_class_type_in_the_export_layer";
00174       LogError(me_InternalError, << s.c_str());
00175       }
00176     }
00177   else
00178     {
00179     s = GetExportLayerActualType(t, stripConst);
00180     }
00181 
00182   return s;
00183 }
00184 
00185 
00186 //----------------------------------------------------------------------------
00187 gxsys_stl::string MummyCsharpExportLayerGenerator::GetArgTypeAndNameString(cable::Type *argType, const char *name, bool stripConst)
00188 {
00189   gxsys_stl::string s;
00190 
00191   if ((argType->GetTypeId() == cable::Type::PointerTypeId) &&
00192     (cable::PointerType::SafeDownCast(argType)->GetTarget()->GetTypeId() == cable::Type::FunctionTypeId)
00193     )
00194     {
00195     if (EquivalentTypedefNameExists(this->GetTargetClass(), cable::FunctionType::SafeDownCast(cable::PointerType::SafeDownCast(argType)->GetTarget()), s))
00196       {
00197       s = gxsys_stl::string(GetFullyQualifiedNameForCPlusPlus(this->GetTargetClass())) + "::" + s;
00198       }
00199     else
00200       {
00201       s = "ERROR - cannot generate argTypeAndName string for function pointer - add a typedef for the function pointer...";
00202       LogError(me_InternalError, << s.c_str());
00203       }
00204     }
00205   else
00206     {
00207     s = GetExportLayerMappedType(argType, stripConst);
00208     }
00209 
00210   if (name)
00211     {
00212     s += " ";
00213     s += name;
00214     }
00215 
00216   return s;
00217 }
00218 
00219 
00220 //----------------------------------------------------------------------------
00221 void MummyCsharpExportLayerGenerator::EmitClassMethodDeclarationForExportLayer(gxsys_ios::ostream &os, const cable::Class *c, const cable::Method *m, const gxsys_stl::string& mname, bool emitExceptionParams)
00222 {
00223   gxsys_stl::string cname(GetFullyQualifiedNameForCPlusPlus(c));
00224   gxsys_stl::string s;
00225   cable::FunctionType *ft = m->GetFunctionType();
00226   unsigned int cArgs = ft->GetNumberOfArguments();
00227   unsigned int cArgsEmitted = 0;
00228   unsigned int i = 0;
00229   cable::Type *retType = ft->GetReturns();
00230   cable::Type *argType = 0;
00231   cable::Class* cByRefClass = 0;
00232 
00233   // Extern "C":
00234   Emit(os, "extern \"C\" ");
00235 
00236   // Export declspec:
00237   Emit(os, "MUMMY_DLL_EXPORT\n");
00238 
00239   // Special case "new" and "delete" -- the rest are strictly according to the
00240   // method definition as given by 'm'...
00241   //
00242   if (mname == "new")
00243     {
00244     // Return type:
00245     Emit(os, cname.c_str());
00246     Emit(os, "* ");
00247 
00248     // Exported function name:
00249     Emit(os, GetExportLayerFunctionName(c, m, mname).c_str());
00250 
00251     Emit(os, "(unsigned int* mteStatus, unsigned int* mteIndex, unsigned int* rawRefCount");
00252     cArgsEmitted += 3;
00253 
00254     if (emitExceptionParams)
00255       {
00256       Emit(os, ", unsigned int* mteExceptionIndex, void** clonedException");
00257       cArgsEmitted += 2;
00258       }
00259 
00260     Emit(os, ")\n");
00261     }
00262   else if (mname == "delete")
00263     {
00264     // Return type:
00265     Emit(os, "void");
00266     Emit(os, " ");
00267 
00268     // Exported function name:
00269     Emit(os, GetExportLayerFunctionName(c, m, mname).c_str());
00270 
00271     Emit(os, "(");
00272     Emit(os, cname.c_str());
00273     Emit(os, "* pThis");
00274     cArgsEmitted += 1;
00275 
00276     if (emitExceptionParams)
00277       {
00278       Emit(os, ", unsigned int* mteExceptionIndex, void** clonedException");
00279       cArgsEmitted += 2;
00280       }
00281 
00282     Emit(os, ")\n");
00283     }
00284   else
00285     {
00286     // Return type:
00287     Emit(os, GetArgTypeAndNameString(retType, 0, false).c_str());
00288     Emit(os, " ");
00289 
00290     // Exported function name:
00291     Emit(os, GetExportLayerFunctionName(c, m, mname).c_str());
00292 
00293     // Open args:
00294     Emit(os, "(");
00295 
00296     // The "this" arg:
00297     if (!m->GetStatic())
00298       {
00299       Emit(os, cname.c_str());
00300       Emit(os, "* pThis");
00301       cArgsEmitted += 1;
00302 
00303       if (cArgs!=0)
00304         {
00305         Emit(os, ", ");
00306         }
00307       }
00308 
00309     // The real args:
00310     for (i= 0; i<cArgs; ++i)
00311       {
00312       argType = ft->GetArgument(i);
00313 
00314       // Utility classes get marshalled as copies across the boundary from C#
00315       // even if in C++ they are & (byref) arguments... So they need to be
00316       // declared as just plain old stack-based by value arguments here.
00317       //
00318       cByRefClass = 0;
00319 
00320       if (cable::Type::ReferenceTypeId == argType->GetTypeId())
00321         {
00322         cable::ClassType* classType = cable::ClassType::SafeDownCast(
00323           cable::ReferenceType::SafeDownCast(argType)->GetTarget());
00324         if (classType)
00325           {
00326           cByRefClass = classType->GetClass();
00327           }
00328         }
00329 
00330       if (cByRefClass && IsUtilityClass(cByRefClass))
00331         {
00332         Emit(os, GetFullyQualifiedNameForCPlusPlus(cByRefClass).c_str());
00333         Emit(os, " ");
00334         Emit(os, GetArgName(ft, i));
00335         }
00336       else
00337         {
00338         Emit(os, GetArgTypeAndNameString(argType, GetArgName(ft, i), false).c_str());
00339         }
00340 
00341       cArgsEmitted += 1;
00342 
00343       if (i<cArgs-1)
00344         {
00345         Emit(os, ", ");
00346         }
00347       }
00348 
00349     // Add "generated args" to method signatures that return object pointers:
00350     //
00351     if (!HasMapToType(retType) && IsObjectPointer(retType))
00352       {
00353       if (cArgsEmitted)
00354         {
00355         Emit(os, ", ");
00356         }
00357 
00358       Emit(os, "unsigned int* mteStatus, unsigned int* mteIndex, unsigned int* rawRefCount");
00359       cArgsEmitted += 3;
00360       }
00361 
00362     if (emitExceptionParams)
00363       {
00364       if (cArgsEmitted)
00365         {
00366         Emit(os, ", ");
00367         }
00368 
00369       Emit(os, "unsigned int* mteExceptionIndex, void** clonedException");
00370       cArgsEmitted += 2;
00371       }
00372 
00373     // Close args:
00374     Emit(os, ")\n");
00375     }
00376 }
00377 
00378 
00379 //----------------------------------------------------------------------------
00380 void MummyCsharpExportLayerGenerator::EmitSpecialHandlingForObjectPointerReturns(gxsys_ios::ostream &os, const gxsys_stl::string& cname, const cable::Method *, const gxsys_stl::string&, const unsigned int indent)
00381 {
00382   ClassWrappingSettings cws;
00383   if (!this->GetSettings()->FindClassWrappingSettings(cname.c_str(), &cws))
00384     {
00385     LogError(me_NoClassWrappingSettings,
00386       << "error: no ClassWrappingSettings for class " << cname.c_str());
00387     }
00388 
00389   EmitIndent(os, indent);
00390   Emit(os, "if (0 != rv)\n");
00391   EmitIndent(os, indent+1);
00392   Emit(os, "{\n");
00393 
00394   gxsys_stl::string registerMethod = cws.registerMethod;
00395   gxsys_stl::string registerBaseClass = cws.registerBaseClass;
00396   gxsys_stl::string getRefCountMethod = cws.getRefCountMethod;
00397   gxsys_stl::string getMummyTypeEntryMethod = cws.getMummyTypeEntryMethod;
00398   gxsys_stl::string setMummyTypeEntryMethod = cws.setMummyTypeEntryMethod;
00399 
00400   if (!registerMethod.empty())
00401     {
00402     EmitIndent(os, indent+1);
00403     Emit(os, registerBaseClass.c_str());
00404     Emit(os, "* ro = (");
00405     Emit(os, registerBaseClass.c_str());
00406     Emit(os, "*) (void*) rv;\n");
00407     }
00408 
00409 
00410   if (!registerMethod.empty() && !getMummyTypeEntryMethod.empty())
00411     {
00412     // If object supports MummyTypeEntry caching:
00413     //
00414     EmitIndent(os, indent+1);
00415     Emit(os, "Kitware::mummy::TypeEntry* entry = ro->");
00416     Emit(os, getMummyTypeEntryMethod.c_str());
00417     Emit(os, "();\n");
00418     EmitIndent(os, indent+1);
00419     Emit(os, "if (!entry)\n");
00420     EmitIndent(os, indent+2);
00421     Emit(os, "{\n");
00422     EmitIndent(os, indent+2);
00423     Emit(os, "entry = Kitware::mummy::Runtime::GetTypeEntry((void*) rv, typeid(*ro).name());\n");
00424     EmitIndent(os, indent+2);
00425     Emit(os, "ro->");
00426     Emit(os, setMummyTypeEntryMethod.c_str());
00427     Emit(os, "(entry);\n");
00428     EmitIndent(os, indent+2);
00429     Emit(os, "*mteStatus = 1;\n");
00430     EmitIndent(os, indent+2);
00431     Emit(os, "}\n");
00432     EmitIndent(os, indent+1);
00433     Emit(os, "else\n");
00434     EmitIndent(os, indent+2);
00435     Emit(os, "{\n");
00436     EmitIndent(os, indent+2);
00437     Emit(os, "*mteStatus = 2;\n");
00438     EmitIndent(os, indent+2);
00439     Emit(os, "}\n");
00440     }
00441   else
00442     {
00443     // ...otherwise always call Runtime::GetTypeEntry:
00444     //
00445     EmitIndent(os, indent+1);
00446     Emit(os, "Kitware::mummy::TypeEntry* entry = Kitware::mummy::Runtime::GetTypeEntry(\n");
00447 
00448     EmitIndent(os, indent+2);
00449     Emit(os, "(void*) rv, typeid(*");
00450     if (!registerMethod.empty())
00451       {
00452       // Prefer "ro" (if we have it) to "rv" simply because
00453       // typeid(*obj).name() is really really stupid.
00454       //
00455       Emit(os, "ro");
00456       }
00457     else
00458       {
00459       Emit(os, "rv");
00460       }
00461     Emit(os, ").name());\n");
00462 
00463     EmitIndent(os, indent+1);
00464     Emit(os, "*mteStatus = 0;\n");
00465     }
00466 
00467   // So here we always have an entry:
00468   //
00469   EmitIndent(os, indent+1);
00470   Emit(os, "*mteIndex = entry->GetIndex();\n");
00471 
00472   if (!registerMethod.empty() && !getRefCountMethod.empty())
00473     {
00474     EmitIndent(os, indent+1);
00475     Emit(os, "*rawRefCount = (unsigned int) ro->");
00476     Emit(os, getRefCountMethod.c_str());
00477     Emit(os, ";\n");
00478     }
00479   else
00480     {
00481     EmitIndent(os, indent+1);
00482     Emit(os, "*rawRefCount = (unsigned int) -86;\n");
00483     }
00484 
00485   EmitIndent(os, indent+1);
00486   Emit(os, "}\n");
00487 }
00488 
00489 
00490 //----------------------------------------------------------------------------
00491 void MummyCsharpExportLayerGenerator::EmitClassMethodForExportLayer(gxsys_ios::ostream &os, const cable::Class *c, const cable::Method *m, const gxsys_stl::string& mname)
00492 {
00493   gxsys_stl::string cname(GetFullyQualifiedNameForCPlusPlus(c));
00494   cable::FunctionType *ft = m->GetFunctionType();
00495   unsigned int cArgs = ft->GetNumberOfArguments();
00496   unsigned int i = 0;
00497   unsigned int indent = 1;
00498   cable::Type *retType = ft->GetReturns();
00499   cable::PointerType::Pointer fakeRetType;
00500   bool voidReturn = false;
00501   bool mappedReturnType = false;
00502   bool emitExceptionBlock = false;
00503   gxsys_stl::string rvTypeStr;
00504   bool needsInit = false;
00505   gxsys_stl::string initExpression;
00506 
00507   ClassWrappingSettings cws;
00508   if (!this->GetSettings()->FindClassWrappingSettings(GetFullyQualifiedNameForCPlusPlus(c).c_str(), &cws))
00509     {
00510     LogError(me_NoClassWrappingSettings,
00511       << "error: no ClassWrappingSettings for class " << GetFullyQualifiedNameForCPlusPlus(c).c_str());
00512     }
00513 
00514   emitExceptionBlock = !cws.exceptionBaseClass.empty();
00515 
00516   // If mname is "new" fake retType:
00517   //
00518   if (mname == "new")
00519     {
00520     fakeRetType = cable::PointerType::New();
00521     fakeRetType->SetTarget(c->GetClassType());
00522     fakeRetType->CreateCxxType(this->GetSourceRepresentation()->GetTypeSystem());
00523     retType = fakeRetType;
00524     }
00525 
00526   // Is there a return value? Do we need to map/transform it to a different type?
00527   //
00528   if (IsVoid(retType))
00529     {
00530     voidReturn = true;
00531     }
00532   else if (HasMapToType(retType))
00533     {
00534     mappedReturnType = true;
00535     }
00536 
00537   // Declaration:
00538   EmitClassMethodDeclarationForExportLayer(os, c, m, mname, emitExceptionBlock);
00539 
00540   // Open body:
00541   Emit(os, "{\n");
00542 
00543   // Declare return value "rv":
00544   if (!voidReturn)
00545     {
00546     if (cable::Type::ReferenceTypeId == retType->GetTypeId())
00547       {
00548       rvTypeStr = gxsys_stl::string("ref<") + GetArgTypeAndNameString(
00549         cable::ReferenceType::SafeDownCast(retType)->GetTarget(), 0, false) + ">";
00550       needsInit = false;
00551       }
00552     else if (mappedReturnType)
00553       {
00554       rvTypeStr = GetArgTypeAndNameString(retType, 0, true);
00555       needsInit = true;
00556 
00557       initExpression = "cast";
00558       // david.cole::fix -- this works for the only mapped type we currently
00559       // support ("string" / "const char*") -- it needs to be generalized
00560       // to generate correct code if we ever introduce more mapped types...
00561       }
00562     else
00563       {
00564       rvTypeStr = GetArgTypeAndNameString(retType, 0, true);
00565       needsInit = true;
00566 
00567       initExpression = GetCPlusPlusZeroInitializerExpression(retType);
00568       }
00569 
00570     EmitIndent(os);
00571     Emit(os, rvTypeStr.c_str());
00572     Emit(os, " rv");
00573 
00574     if (needsInit)
00575       {
00576       if (initExpression == "memset")
00577         {
00578         Emit(os, ";\n");
00579         EmitIndent(os);
00580         Emit(os, "memset(&rv, 0, sizeof(rv))");
00581         }
00582       else if (initExpression == "cast")
00583         {
00584         Emit(os, " = (");
00585         Emit(os, rvTypeStr.c_str());
00586         Emit(os, ") 0");
00587         }
00588       else
00589         {
00590         Emit(os, " = ");
00591         Emit(os, initExpression.c_str());
00592         }
00593       }
00594 
00595     Emit(os, ";");
00596     Emit(os, "\n");
00597     Emit(os, "\n");
00598     }
00599 
00600   // Open exception try block:
00601   if (emitExceptionBlock)
00602     {
00603     EmitIndent(os);
00604     Emit(os, "try\n");
00605     EmitIndent(os);
00606     Emit(os, "{\n");
00607 
00608     indent++;
00609     }
00610 
00611   // Delegate the call to the real underlying object:
00612   EmitIndent(os, indent);
00613 
00614   if (!voidReturn)
00615     {
00616     if (mappedReturnType)
00617       {
00618       Emit(os, GetExportLayerActualType(retType, true).c_str());
00619       Emit(os, " rvmi = ");
00620       }
00621     else
00622       {
00623       Emit(os, "rv = ");
00624       }
00625     }
00626 
00627   // Special case "new" and "delete" -- the rest are strictly according to the
00628   // method definition as given by 'm'...
00629   //
00630   if (mname == "new")
00631     {
00632     Emit(os, "new ");
00633     Emit(os, cname.c_str());
00634     Emit(os, ";");
00635     Emit(os, "\n");
00636     }
00637   else if (mname == "delete")
00638     {
00639     Emit(os, "delete pThis;");
00640     Emit(os, "\n");
00641     }
00642   else
00643     {
00644     if (!m->GetStatic())
00645       {
00646       Emit(os, "pThis->");
00647       }
00648     else
00649       {
00650       Emit(os, cname.c_str());
00651       Emit(os, "::");
00652       }
00653 
00654     Emit(os, mname.c_str());
00655     Emit(os, "(");
00656     for (i= 0; i<cArgs; ++i)
00657       {
00658       Emit(os, GetArgName(ft, i));
00659 
00660       if (i<cArgs-1)
00661         {
00662         Emit(os, ", ");
00663         }
00664       }
00665     Emit(os, ");");
00666     Emit(os, "\n");
00667     }
00668 
00669 
00670   // Map return type from "rvmi" to "rv":
00671   //
00672   if (mappedReturnType)
00673     {
00674     gxsys_stl::string map_to_type = GetMapToType(retType);
00675     gxsys_stl::string mapping_method = GetStringMethod(retType);
00676 
00677     Emit(os, "\n");
00678 
00679     EmitIndent(os, indent);
00680     Emit(os, GetExportLayerMappedType(retType, false).c_str());
00681     Emit(os, " rvm = rvmi.");
00682     Emit(os, mapping_method.c_str());
00683     Emit(os, "();\n");
00684 
00685     if (map_to_type == "string")
00686       {
00687       EmitIndent(os, indent);
00688       Emit(os, "size_t n = 0;\n");
00689       Emit(os, "\n");
00690       EmitIndent(os, indent);
00691       Emit(os, "if (rvm)\n");
00692       EmitIndent(os, indent+1);
00693       Emit(os, "{\n");
00694       EmitIndent(os, indent+1);
00695       Emit(os, "n = strlen(rvm);\n");
00696       EmitIndent(os, indent+1);
00697       Emit(os, "}\n");
00698       Emit(os, "\n");
00699       EmitIndent(os, indent);
00700       Emit(os, "rv = (char*) MUMMY_STRING_ALLOC(n+1);\n");
00701       EmitIndent(os, indent);
00702       Emit(os, "if (rv)\n");
00703       EmitIndent(os, indent+1);
00704       Emit(os, "{\n");
00705       EmitIndent(os, indent+1);
00706       Emit(os, "strncpy(rv, rvm, n);\n");
00707       EmitIndent(os, indent+1);
00708       Emit(os, "rv[n] = 0;\n");
00709       EmitIndent(os, indent+1);
00710       Emit(os, "}\n");
00711       Emit(os, "\n");
00712       }
00713     else
00714       {
00715       LogFileLineErrorMsg(m->GetFile(), m->GetLine(), me_UnknownMapToType,
00716         << "Unknown iwhMapToType for return type of method '" << m->GetName() << "'");
00717       }
00718     }
00719   else if (IsObjectPointer(retType))
00720     {
00721     const cable::Class* cRetType = cable::ClassType::SafeDownCast(
00722       cable::PointerType::SafeDownCast(retType)->GetTarget()
00723       )->GetClass();
00724 
00725     this->EmitSpecialHandlingForObjectPointerReturns(os, GetFullyQualifiedNameForCPlusPlus(cRetType), m, mname, indent);
00726     }
00727 
00728   // Close exception try block:
00729   if (emitExceptionBlock)
00730     {
00731     EmitIndent(os);
00732     Emit(os, "}\n");
00733     EmitIndent(os);
00734     Emit(os, "catch(");
00735     Emit(os, cws.exceptionBaseClass.c_str());
00736     Emit(os, "& mel_exc)\n");
00737     EmitIndent(os);
00738     Emit(os, "{\n");
00739 
00740     EmitIndent(os, 2);
00741     Emit(os, cws.exceptionBaseClass.c_str());
00742     Emit(os, "* mel_exc_clone = mel_exc.");
00743     Emit(os, cws.exceptionCloneMethod.c_str());
00744     Emit(os, "();\n");
00745 
00746     EmitIndent(os, 2);
00747     Emit(os, "Kitware::mummy::TypeEntry* entry = Kitware::mummy::Runtime::GetTypeEntry(\n");
00748 
00749     EmitIndent(os, 3);
00750     Emit(os, "(void*) mel_exc_clone, typeid(*mel_exc_clone).name());\n");
00751 
00752     EmitIndent(os, 2);
00753     Emit(os, "*clonedException = mel_exc_clone;\n");
00754 
00755     EmitIndent(os, 2);
00756     Emit(os, "*mteExceptionIndex = entry->GetIndex();\n");
00757 
00758     EmitIndent(os);
00759     Emit(os, "}\n");
00760     }
00761 
00762   // Return statement:
00763   if (!voidReturn)
00764     {
00765     Emit(os, "\n");
00766     EmitIndent(os);
00767     Emit(os, "return rv;\n");
00768     }
00769 
00770   // Close body:
00771   Emit(os, "}\n");
00772 }
00773 
00774 
00775 //----------------------------------------------------------------------------
00776 void MummyCsharpExportLayerGenerator::EmitClassForExportLayer(gxsys_ios::ostream &os, const cable::Class *c)
00777 {
00778   gxsys_stl::string header(c->GetFile());
00779 
00780   ClassWrappingSettings cws;
00781   if (!this->GetSettings()->FindClassWrappingSettings(GetFullyQualifiedNameForCPlusPlus(c).c_str(), &cws))
00782     {
00783     LogError(me_NoClassWrappingSettings,
00784       << "error: no ClassWrappingSettings for class " << GetFullyQualifiedNameForCPlusPlus(c).c_str());
00785     }
00786 
00787   // Emit code:
00788   //
00789   EmitMummyVersionComments(os, "//");
00790 
00791   // If the class maps directly to a builtin type, then DO NOT emit any code.
00792   //
00793   gxsys_stl::string mapToType = ExtractMapToType(c);
00794   if (mapToType != "")
00795     {
00796     Emit(os, "\n");
00797     Emit(os, "//----------------------------------------------------------------------------\n");
00798     Emit(os, "// Unmanaged class '");
00799     Emit(os, GetFullyQualifiedNameForCPlusPlus(c).c_str());
00800     Emit(os, "' maps directly to type '");
00801     Emit(os, mapToType.c_str());
00802     Emit(os, "'.\n");
00803     Emit(os, "// No code generated for '");
00804     Emit(os, GetFullyQualifiedNameForCPlusPlus(c).c_str());
00805     Emit(os, "'...\n");
00806 
00807     LogVerboseInfo(<< "Skipping code generation because class maps directly to native type.");
00808 
00809     return;
00810     }
00811 
00812   Emit(os, "\n");
00813   Emit(os, "//----------------------------------------------------------------------------\n");
00814   Emit(os, "// You can use this symbol in your header files if there are bits of your\n");
00815   Emit(os, "// code that should be conditionally compiled in this export layer.\n");
00816   Emit(os, "//\n");
00817   Emit(os, "#define MUMMY_EXPORT_LAYER_CXX\n");
00818   Emit(os, "\n");
00819   Emit(os, "//----------------------------------------------------------------------------\n");
00820   Emit(os, "// Do not emit the silly C4996 warning for strncpy use:\n");
00821   Emit(os, "//\n");
00822   Emit(os, "#ifndef _CRT_SECURE_NO_DEPRECATE\n");
00823   Emit(os, "#define _CRT_SECURE_NO_DEPRECATE\n");
00824   Emit(os, "#endif\n");
00825   Emit(os, "\n");
00826   Emit(os, "//----------------------------------------------------------------------------\n");
00827   Emit(os, "// Forward declare functions that generated code might call...\n");
00828   Emit(os, "//\n");
00829   Emit(os, "#ifdef _WIN64\n");
00830   Emit(os, "extern \"C\" __declspec(dllimport) void* __stdcall CoTaskMemAlloc(unsigned __int64 cb);\n");
00831   Emit(os, "#define MUMMY_STRING_ALLOC ::CoTaskMemAlloc\n");
00832   Emit(os, "#else\n");
00833   Emit(os, "#ifdef _WIN32\n");
00834   Emit(os, "extern \"C\" __declspec(dllimport) void* __stdcall CoTaskMemAlloc(unsigned long cb);\n");
00835   Emit(os, "#define MUMMY_STRING_ALLOC ::CoTaskMemAlloc\n");
00836   Emit(os, "#endif\n");
00837   Emit(os, "#endif\n");
00838   Emit(os, "\n");
00839   Emit(os, "#ifndef MUMMY_STRING_ALLOC\n");
00840   Emit(os, "#define MUMMY_STRING_ALLOC malloc\n");
00841   Emit(os, "#endif\n");
00842   Emit(os, "\n");
00843   Emit(os, "//----------------------------------------------------------------------------\n");
00844   Emit(os, "// Macro for exporting functions implemented in this file...\n");
00845   Emit(os, "//\n");
00846   Emit(os, "#ifdef _WIN32\n");
00847   Emit(os, "#define MUMMY_DLL_EXPORT __declspec(dllexport)\n");
00848   Emit(os, "#else\n");
00849   Emit(os, "#define MUMMY_DLL_EXPORT\n");
00850   Emit(os, "#endif\n");
00851   Emit(os, "\n");
00852   Emit(os, "//----------------------------------------------------------------------------\n");
00853   Emit(os, "#include \"");
00854   Emit(os, header.c_str());
00855   Emit(os, "\"\n");
00856   Emit(os, "\n");
00857 
00858 
00859   if (IsUtilityClass(c))
00860     {
00861     // No export layer necessary...
00862     }
00863   else
00864     {
00865     // Gather wrapped elements:
00866     //
00867     gxsys_stl::vector<cable::Method*> wrapped_methods;
00868     cable::Method *factoryM = 0;
00869     cable::Method *disposalM = 0;
00870     cable::Method *registerM = 0;
00871     cable::Method *unRegisterM = 0;
00872 
00873     this->GetCsharpGenerator()->GatherWrappedMethods(c, wrapped_methods, factoryM, disposalM, registerM, unRegisterM, false);
00874 
00875     const cable::Constructor* ctor = FindNonAbstractPublicDefaultConstructor(c);
00876 
00877     bool hasMethodsThatReturnRefs = false;
00878     for(gxsys_stl::vector<cable::Method*>::iterator mit = wrapped_methods.begin();
00879       !hasMethodsThatReturnRefs && mit != wrapped_methods.end(); ++mit)
00880       {
00881       cable::FunctionType *ft = (*mit)->GetFunctionType();
00882       cable::Type *retType = ft->GetReturns();
00883       if (cable::Type::ReferenceTypeId == retType->GetTypeId())
00884         {
00885         hasMethodsThatReturnRefs = true;
00886         }
00887       }
00888 
00889     if (hasMethodsThatReturnRefs)
00890       {
00891       Emit(os, "//----------------------------------------------------------------------------\n");
00892       Emit(os, "// Thanks to Brad King for the magic of the ref converter helper class:\n");
00893       Emit(os, "template <typename T>\n");
00894       Emit(os, "class ref\n");
00895       Emit(os, "{\n");
00896       Emit(os, "public:\n");
00897       EmitIndent(os);
00898       Emit(os, "ref() throw(): p_(0) {}\n");
00899       EmitIndent(os);
00900       Emit(os, "ref<T>& operator=(T& r) throw() { this->p_ = &r; return *this; }\n");
00901       EmitIndent(os);
00902       Emit(os, "operator T&() throw() { return *this->p_; }\n");
00903       Emit(os, "\n");
00904       Emit(os, "private:\n");
00905       EmitIndent(os);
00906       Emit(os, "T* p_;\n");
00907       Emit(os, "};\n");
00908       }
00909 
00910 
00911     // Emit include statements for any ref counted base classes involved in method return
00912     // values. Collect them into a set and then emit the set; has the nice effect of
00913     // eliminating duplicates and emitting the include statements in sorted order...
00914     //
00915     gxsys_stl::set<gxsys_stl::string> includeStatements;
00916 
00917     gxsys_stl::string registerInclude;
00918     if (ctor)
00919       {
00920       registerInclude = this->GetSettings()->GetRegisterInclude(c);
00921       if (!registerInclude.empty())
00922         {
00923         includeStatements.insert(registerInclude);
00924         }
00925       }
00926 
00927     for(gxsys_stl::vector<cable::Method*>::iterator mit = wrapped_methods.begin();
00928       mit != wrapped_methods.end(); ++mit)
00929       {
00930       cable::FunctionType *ft = (*mit)->GetFunctionType();
00931       cable::Type *retType = ft->GetReturns();
00932       if (!HasMapToType(retType) && IsObjectPointer(retType))
00933         {
00934         const cable::Class* cRetType = cable::ClassType::SafeDownCast(
00935           cable::PointerType::SafeDownCast(retType)->GetTarget()
00936           )->GetClass();
00937         registerInclude = this->GetSettings()->GetRegisterInclude(cRetType);
00938         if (!registerInclude.empty())
00939           {
00940           includeStatements.insert(registerInclude);
00941           }
00942         }
00943       }
00944 
00945     includeStatements.insert("#include \"MummyRuntime.h\"");
00946     includeStatements.insert("#include \"string.h\" // for possible memset use");
00947 
00948     if (!cws.exceptionInclude.empty())
00949       {
00950       includeStatements.insert(cws.exceptionInclude);
00951       }
00952 
00953     if (!includeStatements.empty())
00954       {
00955       Emit(os, "\n");
00956       Emit(os, "//----------------------------------------------------------------------------\n");
00957 
00958       for(gxsys_stl::set<gxsys_stl::string>::iterator sit = includeStatements.begin();
00959         sit != includeStatements.end(); ++sit)
00960         {
00961         Emit(os, sit->c_str());
00962         Emit(os, "\n");
00963         }
00964       }
00965 
00966 
00967     // Special methods first, then iterate the remainder in wrapped_methods:
00968     //
00969     if (factoryM)
00970       {
00971       Emit(os, "\n");
00972       Emit(os, "\n");
00973       Emit(os, "//----------------------------------------------------------------------------\n");
00974       EmitClassMethodForExportLayer(os, c, factoryM, factoryM->GetName());
00975       }
00976 
00977     if (disposalM)
00978       {
00979       Emit(os, "\n");
00980       Emit(os, "\n");
00981       Emit(os, "//----------------------------------------------------------------------------\n");
00982       EmitClassMethodForExportLayer(os, c, disposalM, disposalM->GetName());
00983       }
00984 
00985     if (registerM)
00986       {
00987       Emit(os, "\n");
00988       Emit(os, "\n");
00989       Emit(os, "//----------------------------------------------------------------------------\n");
00990       EmitClassMethodForExportLayer(os, c, registerM, registerM->GetName());
00991       }
00992 
00993     if (unRegisterM)
00994       {
00995       Emit(os, "\n");
00996       Emit(os, "\n");
00997       Emit(os, "//----------------------------------------------------------------------------\n");
00998       EmitClassMethodForExportLayer(os, c, unRegisterM, unRegisterM->GetName());
00999       }
01000 
01001     // If there's a public default constructor for concrete class 'c', emit "_new"
01002     // and "_delete" export layer functions:
01003     //
01004     if (ctor)
01005       {
01006       Emit(os, "\n");
01007       Emit(os, "\n");
01008       Emit(os, "//----------------------------------------------------------------------------\n");
01009       EmitClassMethodForExportLayer(os, c, ctor, "new");
01010 
01011       Emit(os, "\n");
01012       Emit(os, "\n");
01013       Emit(os, "//----------------------------------------------------------------------------\n");
01014       EmitClassMethodForExportLayer(os, c, ctor, "delete");
01015       }
01016 
01017     for(gxsys_stl::vector<cable::Method*>::iterator mit = wrapped_methods.begin();
01018       mit != wrapped_methods.end(); ++mit)
01019       {
01020       Emit(os, "\n");
01021       Emit(os, "\n");
01022       Emit(os, "//----------------------------------------------------------------------------\n");
01023       EmitClassMethodForExportLayer(os, c, *mit, (*mit)->GetName());
01024       }
01025     }
01026 
01027   // If there is extraExportLayerCode, emit it at the bottom of the file.
01028   // If it's there, it's the name of a file that we are to include in
01029   // its entirety...
01030   //
01031   gxsys_stl::string extraCode = this->GetSettings()->GetExtraExportLayerCode(c);
01032   if (extraCode != "")
01033     {
01034     Emit(os, "\n");
01035     Emit(os, "\n");
01036     Emit(os, "//----------------------------------------------------------------------------\n");
01037     Emit(os, "// Begin extraExportLayerCode\n");
01038     Emit(os, "\n");
01039     EmitFile(os, extraCode.c_str());
01040     Emit(os, "\n");
01041     Emit(os, "// End extraExportLayerCode\n");
01042     }
01043 }