// -*- Mode: C++; -*-
//                            Package   : omniORBpy
// omnipy.cc                  Created on: 1999/06/01
//                            Author    : Duncan Grisby (dpg1)
//
//    Copyright (C) 1999 AT&T Laboratories Cambridge
//
//    This file is part of the omniORBpy library
//
//    The omniORBpy library is free software; you can redistribute it
//    and/or modify it under the terms of the GNU Lesser General
//    Public License as published by the Free Software Foundation;
//    either version 2.1 of the License, or (at your option) any later
//    version.
//
//    This library is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU Lesser General Public License for more details.
//
//    You should have received a copy of the GNU Lesser General Public
//    License along with this library; if not, write to the Free
//    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
//    MA 02111-1307, USA
//
//
// Description:
//    Main entry points for _omnipy Python module

// $Id: omnipy.cc,v 1.1.4.19 2007/09/18 20:03:34 dgrisby Exp $

// $Log: omnipy.cc,v $
// Revision 1.1.4.19  2007/09/18 20:03:34  dgrisby
// Refcount error if cdrUnmarshal raised a Python exception.
//
// Revision 1.1.4.18  2007/01/19 11:11:09  dgrisby
// Avoid assertion failure if an unexpected C++ exception occurs during
// an invocation.
//
// Revision 1.1.4.17  2006/09/05 11:30:22  dgrisby
// Modify stub version check to be more specific.
//
// Revision 1.1.4.16  2006/09/01 13:44:06  dgrisby
// Hard-code version check rather than using pre-processor defines.
//
// Revision 1.1.4.15  2006/07/26 17:49:59  dgrisby
// Support unchecked_narrow.
//
// Revision 1.1.4.14  2006/05/24 18:33:04  dgrisby
// Unlock interpreter lock before clearing value tracker in cdrMarshal /
// cdrUnmarshal.
//
// Revision 1.1.4.13  2006/05/15 10:26:11  dgrisby
// More relaxation of requirements for old-style classes, for Python 2.5.
//
// Revision 1.1.4.12  2006/01/19 17:28:44  dgrisby
// Merge from omnipy2_develop.
//
// Revision 1.1.4.11  2005/11/09 12:33:32  dgrisby
// Support POA LocalObjects.
//
// Revision 1.1.4.10  2005/06/24 17:36:09  dgrisby
// Support for receiving valuetypes inside Anys; relax requirement for
// old style classes in a lot of places.
//
// Revision 1.1.4.9  2005/04/25 18:27:41  dgrisby
// Maintain forwarded location when narrowing forwarded references.
//
// Revision 1.1.4.8  2005/04/11 13:02:38  dgrisby
// Another merge.
//
// Revision 1.1.4.7  2005/03/02 13:39:17  dgrisby
// Another merge from omnipy2_develop.
//
// Revision 1.1.4.6  2005/01/07 00:22:32  dgrisby
// Big merge from omnipy2_develop.
//
// Revision 1.1.4.5  2004/02/16 10:14:17  dgrisby
// Use stream based copy for local calls.
//
// Revision 1.1.4.4  2003/11/06 12:00:34  dgrisby
// ValueType TypeCode support; track ORB core changes.
//
// Revision 1.1.4.3  2003/07/10 22:13:25  dgrisby
// Abstract interface support.
//
// Revision 1.1.4.2  2003/05/20 17:10:23  dgrisby
// Preliminary valuetype support.
//
// Revision 1.1.4.1  2003/03/23 21:51:57  dgrisby
// New omnipy3_develop branch.
//
// Revision 1.1.2.20  2003/03/12 11:17:02  dgrisby
// Registration of external pseudo object creation functions.
//
// Revision 1.1.2.19  2002/05/26 00:55:36  dgrisby
// C++ API to convert object references to/from Python.
//
// Revision 1.1.2.18  2002/02/18 18:48:13  dpg1
// Autoconf support.
//
// Revision 1.1.2.17  2002/01/18 15:49:44  dpg1
// Context support. New system exception construction. Fix None call problem.
//
// Revision 1.1.2.16  2001/12/10 18:10:37  dpg1
// Segfault with narrow on pseudo object.
//
// Revision 1.1.2.15  2001/09/24 10:48:25  dpg1
// Meaningful minor codes.
//
// Revision 1.1.2.14  2001/09/20 14:51:24  dpg1
// Allow ORB reinitialisation after destroy(). Clean up use of omni namespace.
//
// Revision 1.1.2.13  2001/08/21 10:52:40  dpg1
// Update to new ORB core APIs.
//
// Revision 1.1.2.12  2001/08/15 10:37:13  dpg1
// Track ORB core object table changes.
//
// Revision 1.1.2.11  2001/06/22 10:29:26  dpg1
// Add distribution date to logging.
//
// Revision 1.1.2.10  2001/06/11 13:06:25  dpg1
// Support for PortableServer::Current.
//
// Revision 1.1.2.9  2001/06/01 11:09:25  dpg1
// Make use of new omni::ptrStrCmp() and omni::strCmp().
//
// Revision 1.1.2.8  2001/05/14 15:22:00  dpg1
// cdrMarshal() / cdrUnmarshal() are back.
//
// Revision 1.1.2.7  2001/05/14 12:47:20  dpg1
// Fix memory leaks.
//
// Revision 1.1.2.6  2001/05/10 15:16:01  dpg1
// Big update to support new omniORB 4 internals.
//
// Revision 1.1.2.5  2001/04/09 16:28:49  dpg1
// De-uglify ORB_init command line argument eating.
//
// Revision 1.1.2.4  2001/04/09 15:22:15  dpg1
// Fixed point support.
//
// Revision 1.1.2.3  2000/11/22 17:23:03  dpg1
// Twin strings pre-allocated.
//
// Revision 1.1.2.2  2000/11/06 17:06:38  dpg1
// Fix to prevent extra _is_a call after narrow
//
// Revision 1.1.2.1  2000/10/13 13:55:23  dpg1
// Initial support for omniORB 4.
//

#ifdef __WIN32__
#define DLL_EXPORT _declspec(dllexport)
#else
#define DLL_EXPORT
#endif

#include "pydistdate.hh"
#include <omnipy.h>
#include <pyThreadCache.h>
#include <initialiser.h>

OMNI_USING_NAMESPACE(omni)

////////////////////////////////////////////////////////////////////////////
// Global pointers to Python objects                                      //
////////////////////////////////////////////////////////////////////////////

PyInterpreterState* omniPy::pyInterpreter;

PyObject* omniPy::py_omnipymodule;	// The _omnipy extension
PyObject* omniPy::pyCORBAmodule;	// The CORBA module
PyObject* omniPy::pyCORBAsysExcMap;	//  The system exception map
PyObject* omniPy::pyCORBAAnyClass;	//  Any class
PyObject* omniPy::pyCORBATypeCodeClass;	//  TypeCode class
PyObject* omniPy::pyCORBAContextClass;	//  Context class
PyObject* omniPy::pyCORBAValueBase;    	//  ValueBase class
PyObject* omniPy::pyCORBAValueBaseDesc;	//  ValueBase descriptor
PyObject* omniPy::pyomniORBmodule;	// The omniORB module
PyObject* omniPy::pyomniORBobjrefMap;	//  The objref class map
PyObject* omniPy::pyomniORBskeletonMap;	//  The skeleton class map
PyObject* omniPy::pyomniORBtypeMap;     //  The repoId to descriptor mapping
PyObject* omniPy::pyomniORBvalueMap;    //  The repoId to value factory mapping
PyObject* omniPy::pyomniORBwordMap;     //  Reserved word map
PyObject* omniPy::pyomniORBpoaCache;    //  POA cache
PyObject* omniPy::pyomniORBUnknownValueBase;
                                        //  Base class for unknown valuetypes
PyObject* omniPy::pyPortableServerModule;
                                        // Portable server module
PyObject* omniPy::pyServantClass;       // Servant class
PyObject* omniPy::pyCreateTypeCode;	// Function to create a TypeCode object
PyObject* omniPy::pyWorkerThreadClass;  // Worker thread class
PyObject* omniPy::pyWorkerThreadDel;    // Method to delete worker thread
PyObject* omniPy::pyEmptyTuple;         // Zero element tuple.

PyObject* omniPy::pyORB_TWIN;
PyObject* omniPy::pyOBJREF_TWIN;
PyObject* omniPy::pySERVANT_TWIN;
PyObject* omniPy::pyPOA_TWIN;
PyObject* omniPy::pyPOAMANAGER_TWIN;
PyObject* omniPy::pyPOACURRENT_TWIN;
PyObject* omniPy::pyNP_RepositoryId;


////////////////////////////////////////////////////////////////////////////
// Pointer to the ORB                                                     //
////////////////////////////////////////////////////////////////////////////

CORBA::ORB_ptr omniPy::orb;


////////////////////////////////////////////////////////////////////////////
// Constant strings to facilitate comparison by pointer                   //
////////////////////////////////////////////////////////////////////////////

const char* omniPy::string_Py_omniObjRef       = "Py_omniObjRef";
const char* omniPy::string_Py_omniServant      = "Py_omniServant";
const char* omniPy::string_Py_ServantActivator = "Py_ServantActivator";
const char* omniPy::string_Py_ServantLocator   = "Py_ServantLocator";
const char* omniPy::string_Py_AdapterActivator = "Py_AdapterActivator";


////////////////////////////////////////////////////////////////////////////
// Twin type                                                              //
////////////////////////////////////////////////////////////////////////////

extern "C" {

  static void
  omnipyTwin_dealloc(omnipyTwin* tp)
  {
    PyMem_DEL(tp);
  }

  static int
  omnipyTwin_cmp(omnipyTwin* t1, omnipyTwin* t2)
  {
    // Can't use simple t1->ob_twin - t2->ob_twin in case int is
    // smaller than a pointer
    if      (t1->ob_twin == t2->ob_twin) return 0;
    else if (t1->ob_twin >  t2->ob_twin) return 1;
    else                                 return -1;
  }

  static long
  omnipyTwin_hash(omnipyTwin* tp)
  {
    return (long)tp->ob_twin;
  }

  static PyTypeObject omnipyTwinType = {
    PyObject_HEAD_INIT(&PyType_Type)
    0,
    (char*)"omnipyTwin",
    sizeof(omnipyTwin),
    0,
    (destructor)omnipyTwin_dealloc,   /*tp_dealloc*/
    0,			              /*tp_print*/
    0,                                /*tp_getattr*/
    0,				      /*tp_setattr*/
    (cmpfunc)omnipyTwin_cmp,          /*tp_compare*/
    0,                                /*tp_repr*/
    0,				      /*tp_as_number*/
    0,                                /*tp_as_sequence*/
    0,				      /*tp_as_mapping*/
    (hashfunc)omnipyTwin_hash,	      /*tp_hash*/
    0,				      /*tp_call*/
    0,				      /*tp_str*/
    0,				      /*tp_getattro*/
    0,				      /*tp_setattro*/
    0,                                /*tp_as_buffer*/
    0,				      /*tp_flags*/
    0,                                /*tp_doc*/
  };
}

PyObject*
omniPy::newTwin(void* twin)
{
  omnipyTwin* ot = PyMem_NEW(omnipyTwin, 1);
  ot->ob_type = &omnipyTwinType;
  ot->ob_twin = (void*)twin;
  _Py_NewReference((PyObject*)ot);
  return (PyObject*)ot;
}

////////////////////////////////////////////////////////////////////////////
// Module inititaliser to hook orb creation and destruction               //
////////////////////////////////////////////////////////////////////////////

class omni_python_initialiser : public omniInitialiser {
public:
  void attach() {
    omniPy::registerInterceptors();
  }
  void detach() {
    omnipyThreadCache::shutdown();
    if (omniPy::orb) omniPy::orb = 0;
  }
};

static omni_python_initialiser the_omni_python_initialiser;


// Function to generate a list of system exception names
static PyObject*
generateExceptionList()
{
  int i = 0;
# define INCREMENT_COUNT(exc) i++;
  OMNIORB_FOR_EACH_SYS_EXCEPTION(INCREMENT_COUNT)
# undef INCREMENT_COUNT

  PyObject* excs = PyList_New(i);
  i = 0;

# define ADD_EXCEPTION_NAME(exc) \
  PyList_SetItem(excs, i++, PyString_FromString(#exc));
  OMNIORB_FOR_EACH_SYS_EXCEPTION(ADD_EXCEPTION_NAME)
# undef ADD_EXCEPTION_NAME

  return excs;
}



// Things visible to Python:

extern "C" {

  ////////////////////////////////////////////////////////////////////////////
  // omnipy private functions                                               //
  ////////////////////////////////////////////////////////////////////////////

  static PyObject*
  omnipy_checkVersion(PyObject* self, PyObject* args)
  {
    int   maj, min;
    char* mod;

    if (!PyArg_ParseTuple(args, (char*)"iis", &maj, &min, &mod))
      return 0;

    if (maj != 3 || min != 0) {
      if (omniORB::trace(1)) {
	omniORB::logger l;
        l << "\n"
	  << "omniORBpy: WARNING! _omnipy module version "
	  << OMNIPY_MAJOR << "." << OMNIPY_MINOR
          << " expects stubs version 3.0.\n"
	  << "omniORBpy: Stubs in " << mod << " are version "
	  << maj << "." << min << ".\n"
	  << "omniORBpy: You may experience strange errors "
	  << "until you fix the mismatch\n";
      }
    }
    Py_INCREF(Py_None);
    return Py_None;
  }

  static PyObject*
  omnipy_coreVersion(PyObject* self, PyObject* args)
  {
    if (!PyArg_ParseTuple(args, (char*)"")) return 0;
    return Py_BuildValue((char*)"s", omniORB::versionString());
  }

#define OMNIPY_ATTR(x) \
  PyObject_GetAttrString(omniPy::pyomniORBmodule, (char*)x);

  static PyObject*
  omnipy_registerPyObjects(PyObject* self, PyObject* args)
  {
    PyObject* temp;

    // Get a pointer to the interpreter state
    PyThreadState* tstate = PyThreadState_Get();
    omniPy::pyInterpreter = tstate->interp;

    if (!PyArg_ParseTuple(args, (char*)"O", &omniPy::pyomniORBmodule))
      return 0;

    OMNIORB_ASSERT(PyModule_Check(omniPy::pyomniORBmodule));

    omniPy::pyCORBAmodule = OMNIPY_ATTR("CORBA");

    OMNIORB_ASSERT(omniPy::pyCORBAmodule &&
		   PyModule_Check(omniPy::pyCORBAmodule));

    omniPy::pyCORBAsysExcMap = OMNIPY_ATTR("sysExceptionMapping");

    omniPy::pyCORBAAnyClass =
      PyObject_GetAttrString(omniPy::pyCORBAmodule, (char*)"Any");

    omniPy::pyCORBATypeCodeClass =
      PyObject_GetAttrString(omniPy::pyCORBAmodule, (char*)"TypeCode");

    omniPy::pyCORBAContextClass =
      PyObject_GetAttrString(omniPy::pyCORBAmodule, (char*)"Context");

    omniPy::pyCORBAValueBase =
      PyObject_GetAttrString(omniPy::pyCORBAmodule, (char*)"ValueBase");

    omniPy::pyCORBAValueBaseDesc =
      PyObject_GetAttrString(omniPy::pyCORBAmodule, (char*)"_d_ValueBase");

    omniPy::pyomniORBobjrefMap        = OMNIPY_ATTR("objrefMapping");
    omniPy::pyomniORBtypeMap          = OMNIPY_ATTR("typeMapping");
    omniPy::pyomniORBwordMap          = OMNIPY_ATTR("keywordMapping");
    omniPy::pyomniORBpoaCache         = OMNIPY_ATTR("poaCache");
    omniPy::pyPortableServerModule    = OMNIPY_ATTR("PortableServer");
    omniPy::pyomniORBskeletonMap      = OMNIPY_ATTR("skeletonMapping");
    omniPy::pyomniORBvalueMap         = OMNIPY_ATTR("valueFactoryMapping");
    omniPy::pyomniORBUnknownValueBase = OMNIPY_ATTR("UnknownValueBase");

    OMNIORB_ASSERT(omniPy::pyPortableServerModule);
    OMNIORB_ASSERT(PyModule_Check(omniPy::pyPortableServerModule));

    omniPy::pyServantClass =
      PyObject_GetAttrString(omniPy::pyPortableServerModule, (char*)"Servant");

    temp = OMNIPY_ATTR("tcInternal");

    omniPy::pyCreateTypeCode = PyObject_GetAttrString(temp,
						      (char*)"createTypeCode");

    omniPy::pyWorkerThreadClass = OMNIPY_ATTR("WorkerThread");

    omniPy::pyWorkerThreadDel =
      PyObject_GetAttrString(omniPy::pyWorkerThreadClass, (char*)"delete");

    omniPy::pyEmptyTuple = OMNIPY_ATTR("_emptyTuple");

    OMNIORB_ASSERT(omniPy::pyCORBAsysExcMap);
    OMNIORB_ASSERT(PyDict_Check(omniPy::pyCORBAsysExcMap));
    OMNIORB_ASSERT(omniPy::pyCORBAAnyClass);
    OMNIORB_ASSERT(omniPy::pyCORBATypeCodeClass);
    OMNIORB_ASSERT(omniPy::pyCORBAContextClass);
    OMNIORB_ASSERT(omniPy::pyCORBAValueBaseDesc);
    OMNIORB_ASSERT(PyTuple_Check(omniPy::pyCORBAValueBaseDesc));
    OMNIORB_ASSERT(omniPy::pyCORBAValueBase);
    OMNIORB_ASSERT(omniPy::pyomniORBobjrefMap);
    OMNIORB_ASSERT(PyDict_Check(omniPy::pyomniORBobjrefMap));
    OMNIORB_ASSERT(omniPy::pyomniORBskeletonMap);
    OMNIORB_ASSERT(PyDict_Check(omniPy::pyomniORBskeletonMap));
    OMNIORB_ASSERT(omniPy::pyomniORBtypeMap);
    OMNIORB_ASSERT(PyDict_Check(omniPy::pyomniORBtypeMap));
    OMNIORB_ASSERT(omniPy::pyomniORBvalueMap);
    OMNIORB_ASSERT(PyDict_Check(omniPy::pyomniORBvalueMap));
    OMNIORB_ASSERT(omniPy::pyomniORBwordMap);
    OMNIORB_ASSERT(PyDict_Check(omniPy::pyomniORBwordMap));
    OMNIORB_ASSERT(omniPy::pyomniORBUnknownValueBase);
    OMNIORB_ASSERT(omniPy::pyomniORBpoaCache);
    OMNIORB_ASSERT(PyDict_Check(omniPy::pyomniORBpoaCache));
    OMNIORB_ASSERT(omniPy::pyServantClass);
    OMNIORB_ASSERT(omniPy::pyCreateTypeCode);
    OMNIORB_ASSERT(PyFunction_Check(omniPy::pyCreateTypeCode));
    OMNIORB_ASSERT(omniPy::pyWorkerThreadClass);
    OMNIORB_ASSERT(omniPy::pyWorkerThreadDel);
    OMNIORB_ASSERT(PyMethod_Check(omniPy::pyWorkerThreadDel));
    OMNIORB_ASSERT(omniPy::pyEmptyTuple);
    OMNIORB_ASSERT(PyTuple_Check(omniPy::pyEmptyTuple));

    omniPy::pyORB_TWIN        = OMNIPY_ATTR("_ORB_TWIN");
    omniPy::pyOBJREF_TWIN     = OMNIPY_ATTR("_OBJREF_TWIN");
    omniPy::pySERVANT_TWIN    = OMNIPY_ATTR("_SERVANT_TWIN");
    omniPy::pyPOA_TWIN        = OMNIPY_ATTR("_POA_TWIN");
    omniPy::pyPOAMANAGER_TWIN = OMNIPY_ATTR("_POAMANAGER_TWIN");
    omniPy::pyPOACURRENT_TWIN = OMNIPY_ATTR("_POACURRENT_TWIN");
    omniPy::pyNP_RepositoryId = OMNIPY_ATTR("_NP_RepositoryId");

    OMNIORB_ASSERT(omniPy::pyORB_TWIN);
    OMNIORB_ASSERT(omniPy::pyOBJREF_TWIN);
    OMNIORB_ASSERT(omniPy::pySERVANT_TWIN);
    OMNIORB_ASSERT(omniPy::pyPOA_TWIN);
    OMNIORB_ASSERT(omniPy::pyPOAMANAGER_TWIN);
    OMNIORB_ASSERT(omniPy::pyPOACURRENT_TWIN);

    OMNIORB_ASSERT(PyString_Check(omniPy::pyORB_TWIN));
    OMNIORB_ASSERT(PyString_Check(omniPy::pyOBJREF_TWIN));
    OMNIORB_ASSERT(PyString_Check(omniPy::pySERVANT_TWIN));
    OMNIORB_ASSERT(PyString_Check(omniPy::pyPOA_TWIN));
    OMNIORB_ASSERT(PyString_Check(omniPy::pyPOAMANAGER_TWIN));
    OMNIORB_ASSERT(PyString_Check(omniPy::pyPOACURRENT_TWIN));

    Py_INCREF(Py_None);
    return Py_None;
  }

  static PyObject*
  omnipy_need_ORB_init(PyObject* self, PyObject* args)
  {
    if (!PyArg_ParseTuple(args, (char*)""))
      return 0;

    if (omniPy::orb)
      return PyInt_FromLong(0);
    else
      return PyInt_FromLong(1);
  }

  ////////////////////////////////////////////////////////////////////////////
  // CORBA:: functions                                                      //
  ////////////////////////////////////////////////////////////////////////////

  static PyObject*
  omnipy_ORB_init(PyObject* self, PyObject* args)
  {
    PyObject* pyorb;
    PyObject* pyargv;
    char*     orbid;
    int       argc;
    char**    argv;

    OMNIORB_ASSERT(omniPy::orb == 0);

    if (!PyArg_ParseTuple(args, (char*)"OOs", &pyorb, &pyargv, &orbid))
      return 0;

    if (!PyList_Check(pyargv)) {
      PyErr_SetString(PyExc_TypeError,
		      "argument 2: parameter must be an argument list");
      return 0;
    }

    argc = PyList_GET_SIZE(pyargv);
    argv = new char*[argc];

    PyObject* o;
    int i;
    for (i=0; i<argc; i++) {
      o = PyList_GET_ITEM(pyargv, i);
      if (!PyString_Check(o)) {
	PyErr_SetString(PyExc_TypeError,
			"argument 2: parameter must be a list of strings.");
	delete[] argv;
	return 0;
      }
      argv[i] = PyString_AS_STRING(o);
    }

    int orig_argc = argc;

    CORBA::ORB_ptr orb;
    try {
      orb = CORBA::ORB_init(argc, argv, orbid);
    }
    OMNIPY_CATCH_AND_HANDLE_SYSTEM_EXCEPTIONS

    if (omniORB::trace(2)) {
      omniORB::logger l;
      l << "omniORBpy distribution date: " OMNIORBPY_DIST_DATE "\n";
    }

    omniPy::orb = orb;

    // Remove eaten arguments from Python argv list
    if (argc < orig_argc) {
      int r;
      char *s, *t;
      for (i=0; i<argc; ++i) {
	s = argv[i];

	while (1) {
	  o = PyList_GetItem(pyargv, i); OMNIORB_ASSERT(o != 0);
	  t = PyString_AS_STRING(o);
	  if (s == t) break;
	  r = PySequence_DelItem(pyargv, i);
	  OMNIORB_ASSERT(r != -1);
	}
      }
      while (PyList_Size(pyargv) > argc) {
	// Delete -ORB arguments at end
	r = PySequence_DelItem(pyargv, i);
	OMNIORB_ASSERT(r != -1);
      }
    }
    delete [] argv;

    omniPy::setTwin(pyorb, orb, ORB_TWIN);

    // Initialise the thread state cache
    omnipyThreadCache::init();

    Py_INCREF(Py_None);
    return Py_None;
  }

  ////////////////////////////////////////////////////////////////////////////
  // CDR stream marshalling/unmarshalling                                   //
  ////////////////////////////////////////////////////////////////////////////

  static PyObject*
  omnipy_cdrMarshal(PyObject* self, PyObject* args)
  {
    PyObject *desc, *data;
    int endian = -1;

    if (!PyArg_ParseTuple(args, (char*)"OO|i", &desc, &data, &endian))
      return 0;

    if (endian > 1 || endian < -1) {
      PyErr_SetString(PyExc_ValueError,
		      "argument 3: endian must be 0 or 1");
      return 0;
    }

    try {
      omniPy::validateType(desc, data, CORBA::COMPLETED_NO);

      if (endian == -1) {
	// Marshal into an encapsulation
	cdrEncapsulationStream stream;
        omniPy::ValueTrackerClearer vtc(stream);

	omniPy::marshalPyObject(stream, desc, data);

	return PyString_FromStringAndSize((char*)stream.bufPtr(),
					  stream.bufSize());
      }
      else {
	// Marshal into a raw buffer
	cdrMemoryStream stream;
        omniPy::ValueTrackerClearer vtc(stream);

	if (endian != omni::myByteOrder)
	  stream.setByteSwapFlag(endian);

	omniPy::marshalPyObject(stream, desc, data);

	return PyString_FromStringAndSize((char*)stream.bufPtr(),
					  stream.bufSize());
      }
    }
    OMNIPY_CATCH_AND_HANDLE_SYSTEM_EXCEPTIONS
  }

  static inline PyObject* do_cdrUnmarshal(cdrStream& stream, PyObject* desc)
  {
    PyObject* r = omniPy::unmarshalPyObject(stream, desc);
    if (r && stream.checkInputOverrun(1, 1)) {
      // More data in stream -- must have used the wrong TypeCode
      Py_DECREF(r);
      OMNIORB_THROW(MARSHAL, MARSHAL_MessageTooLong, CORBA::COMPLETED_NO);
    }
    return r;
  }

  static PyObject*
  omnipy_cdrUnmarshal(PyObject* self, PyObject* args)
  {
    PyObject* desc;
    char*     encap;
    size_t    size;
    int       endian = -1;
    
    if (!PyArg_ParseTuple(args, (char*)"Os#|i",
			  &desc, &encap, &size, &endian))
      return 0;

    if (endian > 1 || endian < -1) {
      PyErr_SetString(PyExc_ValueError,
		      "argument 3: endian must be 0 or 1");
      return 0;
    }

    try {
      if (endian == -1) {
	// Encapsulation
	cdrEncapsulationStream stream((CORBA::Octet*)encap, size);
        omniPy::ValueTrackerClearer vtc(stream);
	return do_cdrUnmarshal(stream, desc);
      }
      else {
	// Simple buffer. Is it aligned ok?
	if ((omni::ptr_arith_t)encap ==
	    omni::align_to((omni::ptr_arith_t)encap, omni::ALIGN_8)) {

	  cdrMemoryStream stream((CORBA::Octet*)encap, size);
          omniPy::ValueTrackerClearer vtc(stream);

	  if (endian != omni::myByteOrder)
	    stream.setByteSwapFlag(endian);

	  return do_cdrUnmarshal(stream, desc);
	}
	else {
	  // Unfortunately, this is a common case, due to the way
	  // Python string objects are laid out.
	  cdrMemoryStream stream;
          omniPy::ValueTrackerClearer vtc(stream);

	  if (endian != omni::myByteOrder)
	    stream.setByteSwapFlag(endian);

	  stream.put_octet_array((CORBA::Octet*)encap, size);
	  return do_cdrUnmarshal(stream, desc);
	}
      }
    }
    OMNIPY_CATCH_AND_HANDLE_SYSTEM_EXCEPTIONS
  }


  ////////////////////////////////////////////////////////////////////////////
  // Functions operating on object references                               //
  ////////////////////////////////////////////////////////////////////////////

  static PyObject*
  omnipy_invoke(PyObject* self, PyObject* args)
  {
    // Arg format
    //  (objref, op_name, (in_desc,out_desc,exc_desc [, ctxt [,values]]), args)
    //
    //  exc_desc is a dictionary containing a mapping from repoIds to
    //  tuples of the form (exception class, marshal desc., param count)

    PyObject *pyobjref, *in_d, *out_d, *exc_d, *ctxt_d, *op_args, *result;
    char*  op;
    size_t op_len;

    PyObject* o;
    PyObject* desc;

    pyobjref = PyTuple_GET_ITEM(args,0);

    o        = PyTuple_GET_ITEM(args,1);
    op       = PyString_AS_STRING(o);
    op_len   = PyString_GET_SIZE(o);

    desc     = PyTuple_GET_ITEM(args,2);

    in_d     = PyTuple_GET_ITEM(desc,0);
    out_d    = PyTuple_GET_ITEM(desc,1);
    exc_d    = PyTuple_GET_ITEM(desc,2);

    int desclen = PyTuple_GET_SIZE(desc);

    if (desclen >= 4) {
      ctxt_d = PyTuple_GET_ITEM(desc,3);
      if (ctxt_d == Py_None)
	ctxt_d = 0;
    }
    else
      ctxt_d = 0;

    CORBA::Boolean contains_values = 0;

    if (desclen == 5) {
      PyObject* v = PyTuple_GET_ITEM(desc,4);
      if (v != Py_None)
	contains_values = 1;
    }

    op_args  = PyTuple_GET_ITEM(args,3);

    int arg_len = PyTuple_GET_SIZE(in_d) + (ctxt_d ? 1:0);

    if (PyTuple_GET_SIZE(op_args) != arg_len) {
      char* err = new char[80];
      sprintf(err, "Operation requires %d argument%s; %d given",
	      arg_len, (arg_len == 1) ? "" : "s",
	      PyTuple_GET_SIZE(op_args));

      PyErr_SetString(PyExc_TypeError, err);
      delete [] err;
      return 0;
    }

    CORBA::Object_ptr cxxobjref =
      (CORBA::Object_ptr)omniPy::getTwin(pyobjref, OBJREF_TWIN);

    omniObjRef*    oobjref   = cxxobjref->_PR_getobj();
    CORBA::Boolean is_oneway = (out_d == Py_None);

    omniPy::Py_omniCallDescriptor call_desc(op, op_len + 1, is_oneway,
					    in_d, out_d, exc_d, ctxt_d,
					    op_args, 0);

    if (contains_values)
      call_desc.containsValues(1);

    try {
      call_desc.releaseInterpreterLock();
      oobjref->_invoke(call_desc);
      call_desc.reacquireInterpreterLock();
      if (!is_oneway) {
	return call_desc.result();
      }
      else {
	Py_INCREF(Py_None);
	return Py_None;
      }
    }
#ifdef HAS_Cplusplus_catch_exception_by_base
    catch (const CORBA::SystemException& ex) {
      // systemException() reacquires the interpreter lock if necessary
      call_desc.systemException(ex);
    }
#else
#define DO_CALL_DESC_SYSTEM_EXCEPTON(exc) \
    catch (const CORBA::exc& ex) { \
      call_desc.systemException(ex); \
    }
OMNIORB_FOR_EACH_SYS_EXCEPTION(DO_CALL_DESC_SYSTEM_EXCEPTON)
#undef DO_CALL_DESC_SYSTEM_EXCEPTON
#endif
    catch (omniPy::PyUserException& ex) {
      call_desc.reacquireInterpreterLock();
      ex.setPyExceptionState();
    }
    catch (...) {
      // This should not happen, but in case it does we reacquire the
      // interpreter lock to avoid an assertion failure from the call
      // descriptor's destructor.
      omniORB::logs(1, "Unexpected C++ exception during Python invocation.");
      call_desc.ensureInterpreterLock();
      throw;
    }
    return 0;
  }

  static PyObject*
  omnipy_releaseObjref(PyObject* self, PyObject* args)
  {
    PyObject* pyobjref;

    if (!PyArg_ParseTuple(args, (char*)"O", &pyobjref))
      return 0;

    CORBA::Object_ptr cxxobjref =
      (CORBA::Object_ptr)omniPy::getTwin(pyobjref, OBJREF_TWIN);

    if (cxxobjref) {
      {
	omniPy::InterpreterUnlocker _u;
	CORBA::release(cxxobjref);
      }
      omniPy::remTwin(pyobjref, OBJREF_TWIN);
    }
    Py_INCREF(Py_None);
    return Py_None;
  }

  static PyObject*
  omnipy_isA(PyObject* self, PyObject* args)
  {
    PyObject* pyobjref;
    char*     repoId;

    if (!PyArg_ParseTuple(args, (char*)"Os", &pyobjref, &repoId))
      return 0;

    CORBA::Object_ptr cxxobjref =
      (CORBA::Object_ptr)omniPy::getTwin(pyobjref, OBJREF_TWIN);

    RAISE_PY_BAD_PARAM_IF(!cxxobjref, BAD_PARAM_WrongPythonType);

    try {
      omniPy::InterpreterUnlocker ul;
      CORBA::Boolean isa = cxxobjref->_is_a(repoId);
      return PyInt_FromLong(isa);
    }
    OMNIPY_CATCH_AND_HANDLE_SYSTEM_EXCEPTIONS
  }

  static PyObject*
  omnipy_nonExistent(PyObject* self, PyObject* args)
  {
    PyObject* pyobjref;

    if (!PyArg_ParseTuple(args, (char*)"O", &pyobjref))
      return 0;

    CORBA::Object_ptr cxxobjref =
      (CORBA::Object_ptr)omniPy::getTwin(pyobjref, OBJREF_TWIN);

    RAISE_PY_BAD_PARAM_IF(!cxxobjref, BAD_PARAM_WrongPythonType);

    try {
      omniPy::InterpreterUnlocker ul;
      CORBA::Boolean nex = cxxobjref->_non_existent();
      return PyInt_FromLong(nex);
    }
    OMNIPY_CATCH_AND_HANDLE_SYSTEM_EXCEPTIONS
  }

  static PyObject*
  omnipy_isEquivalent(PyObject* self, PyObject* args)
  {
    PyObject* pyobjref1;
    PyObject* pyobjref2;

    if (!PyArg_ParseTuple(args, (char*)"OO", &pyobjref1, &pyobjref2))
      return 0;

    CORBA::Object_ptr cxxobjref1, cxxobjref2;
    cxxobjref1 = (CORBA::Object_ptr)omniPy::getTwin(pyobjref1, OBJREF_TWIN);
    cxxobjref2 = (CORBA::Object_ptr)omniPy::getTwin(pyobjref2, OBJREF_TWIN);

    RAISE_PY_BAD_PARAM_IF(!cxxobjref1 || !cxxobjref2,
			  BAD_PARAM_WrongPythonType);

    try {
      omniPy::InterpreterUnlocker ul;
      CORBA::Boolean ise = cxxobjref1->_is_equivalent(cxxobjref2);
      return PyInt_FromLong(ise);
    }
    OMNIPY_CATCH_AND_HANDLE_SYSTEM_EXCEPTIONS
  }

  static PyObject*
  omnipy_hash(PyObject* self, PyObject* args)
  {
    PyObject*    pyobjref;
    CORBA::ULong max;

    if (!PyArg_ParseTuple(args, (char*)"Oi", &pyobjref, &max))
      return 0;

    CORBA::Object_ptr cxxobjref =
      (CORBA::Object_ptr)omniPy::getTwin(pyobjref, OBJREF_TWIN);

    RAISE_PY_BAD_PARAM_IF(!cxxobjref, BAD_PARAM_WrongPythonType);

    CORBA::ULong h = cxxobjref->_hash(max);
    return PyInt_FromLong(h);
  }


  static PyObject*
  omnipy_narrow(PyObject* self, PyObject* args)
  {
    PyObject* pysource;
    char*     repoId;
    int       checked;

    if (!PyArg_ParseTuple(args, (char*)"Osi", &pysource, &repoId, &checked))
      return 0;

    CORBA::Object_ptr cxxsource =
      (CORBA::Object_ptr)omniPy::getTwin(pysource, OBJREF_TWIN);

    RAISE_PY_BAD_PARAM_IF(!cxxsource, BAD_PARAM_WrongPythonType);

    CORBA::Boolean    isa;
    CORBA::Object_ptr cxxdest = 0;

    try {
      omniPy::InterpreterUnlocker ul;

      if (checked || cxxsource->_NP_is_pseudo())
	isa = cxxsource->_is_a(repoId);
      else
	isa = 1;

      if (isa) {
	if (!cxxsource->_NP_is_pseudo()) {
	  omniObjRef* oosource = cxxsource->_PR_getobj();
	  omniObjRef* oodest;
	  {
	    omni_tracedmutex_lock sync(*omni::internalLock);
	    oodest = omniPy::createObjRef(repoId, oosource->_getIOR(), 1,
					  oosource->_identity(), 1,
					  oosource->_isForwardLocation());
	  }
	  cxxdest = (CORBA::Object_ptr)
	                   (oodest->_ptrToObjRef(CORBA::Object::_PD_repoId));
	}
	else
	  cxxdest = CORBA::Object::_duplicate(cxxsource);
      }
    }
    OMNIPY_CATCH_AND_HANDLE_SYSTEM_EXCEPTIONS

    if (isa) {
      return omniPy::createPyCorbaObjRef(repoId, cxxdest);
    }
    else {
      Py_INCREF(Py_None);
      return Py_None;
    }
  }

  static PyObject*
  omnipy_ensureInit(PyObject* self, PyObject* args)
  {
    PyObject* m = PyImport_ImportModule((char*)"_omnipy");
    PyObject* o = PyObject_GetAttrString(m, (char*)"orb_func");
    PyObject* f = 0;
    
    if (o && PyModule_Check(o))
      f = PyObject_GetAttrString(o, (char*)"destroy");

    if (!o || !PyModule_Check(o) || !f || f == Py_None) {
      omniORB::logs(5, "Reinitialise omniORBpy sub-modules.");
      PyObject* d = PyModule_GetDict(m);
      omniPy::initORBFunc(d);
      omniPy::initPOAFunc(d);
      omniPy::initPOAManagerFunc(d);
      omniPy::initPOACurrentFunc(d);
      omniPy::initInterceptorFunc(d);
      omniPy::initomniFunc(d);
    }
    Py_XDECREF(o);
    Py_XDECREF(f);

    Py_INCREF(Py_None);
    return Py_None;
  }


  ////////////////////////////////////////////////////////////////////////////
  // Python method table                                                    //
  ////////////////////////////////////////////////////////////////////////////

  static PyMethodDef omnipy_methods[] = {

    // omnipy specific things:
    {(char*)"checkVersion",      omnipy_checkVersion,            METH_VARARGS},
    {(char*)"coreVersion",       omnipy_coreVersion,             METH_VARARGS},
    {(char*)"registerPyObjects", omnipy_registerPyObjects,       METH_VARARGS},
    {(char*)"cdrMarshal",        omnipy_cdrMarshal,              METH_VARARGS},
    {(char*)"cdrUnmarshal",      omnipy_cdrUnmarshal,            METH_VARARGS},
    {(char*)"need_ORB_init",     omnipy_need_ORB_init,           METH_VARARGS},
    {(char*)"ensureInit",        omnipy_ensureInit,              METH_VARARGS},

    // Wrappers for functions in CORBA::
    {(char*)"ORB_init",          omnipy_ORB_init,                METH_VARARGS},

    // Functions for CORBA objects:
    {(char*)"invoke",            omnipy_invoke,                  METH_VARARGS},
    {(char*)"releaseObjref",     omnipy_releaseObjref,           METH_VARARGS},
    {(char*)"isA",               omnipy_isA,                     METH_VARARGS},
    {(char*)"nonExistent",       omnipy_nonExistent,             METH_VARARGS},
    {(char*)"isEquivalent",      omnipy_isEquivalent,            METH_VARARGS},
    {(char*)"hash",              omnipy_hash,                    METH_VARARGS},
    {(char*)"narrow",            omnipy_narrow,                  METH_VARARGS},
    {0,0}
  };

  void DLL_EXPORT init_omnipy()
  {
    // Make sure Python is running multi-threaded
    PyEval_InitThreads();

    PyObject* m = Py_InitModule((char*)"_omnipy", omnipy_methods);
    PyObject* d = PyModule_GetDict(m);
    PyDict_SetItemString(d, (char*)"omnipyTwinType",
			 (PyObject*)&omnipyTwinType);

    PyObject* excs = generateExceptionList();
    PyDict_SetItemString(d, (char*)"system_exceptions", excs);
    Py_DECREF(excs);

    omniPy::py_omnipymodule = m;
    omniPy::initORBFunc(d);
    omniPy::initPOAFunc(d);
    omniPy::initPOAManagerFunc(d);
    omniPy::initPOACurrentFunc(d);
    omniPy::initInterceptorFunc(d);
    omniPy::initomniFunc(d);

    // Set up the C++ API singleton
    PyObject* api = PyCObject_FromVoidPtr((void*)&omniPy::cxxAPI, 0);
    PyDict_SetItemString(d, (char*)"API", api);
    Py_DECREF(api);

    // Create an empty list for external modules to register
    // additional pseudo object creation functions.
    PyObject* pseudolist = PyList_New(0);
    PyDict_SetItemString(d, (char*)"pseudoFns", pseudolist);
    Py_DECREF(pseudolist);

    omniInitialiser::install(&the_omni_python_initialiser);
  }
}


syntax highlighted by Code2HTML, v. 0.9.1