Panda3D

py_panda.cxx

00001 // Filename: py_panda.cxx
00002 // Created by:  drose (04Jul05)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 #include "py_panda.h"
00016 #include "config_interrogatedb.h"
00017 
00018 #ifdef HAVE_PYTHON
00019 
00020 PyMemberDef standard_type_members[] = {
00021   {(char *)"this", T_INT, offsetof(Dtool_PyInstDef,_ptr_to_object),READONLY, (char *)"C++ This if any"},
00022 //  {(char *)"this_ownership", T_INT, offsetof(Dtool_PyInstDef, _memory_rules), READONLY, (char *)"C++ 'this' ownership rules"},
00023 //  {(char *)"this_const", T_INT, offsetof(Dtool_PyInstDef, _is_const), READONLY, (char *)"C++ 'this' const flag"},
00024 //  {(char *)"this_signature", T_INT, offsetof(Dtool_PyInstDef, _signature), READONLY, (char *)"A type check signature"},
00025   {(char *)"this_metatype", T_OBJECT, offsetof(Dtool_PyInstDef, _My_Type), READONLY, (char *)"The dtool meta object"},
00026   {NULL}  /* Sentinel */
00027 };
00028 
00029 
00030 ////////////////////////////////////////////////////////////////////////
00031 /// Simple Recognition Functions..
00032 ////////////////////////////////////////////////////////////////////////
00033 bool DtoolCanThisBeAPandaInstance(PyObject *self)
00034 {
00035     // simple sanity check for the class type..size.. will stop basic foobars..
00036     if(self->ob_type->tp_basicsize >= (int)sizeof(Dtool_PyInstDef))
00037     {
00038         Dtool_PyInstDef * pyself = (Dtool_PyInstDef *) self;
00039         if(pyself->_signature == PY_PANDA_SIGNATURE)
00040             return true;
00041     }
00042     return false;
00043 }
00044 ////////////////////////////////////////////////////////////////////////
00045 //  Function : DTOOL_Call_ExtractThisPointerForType
00046 //
00047 //  These are the wrappers that allow for down and upcast from type .. 
00048 //      needed by the Dtool py interface.. Be very careful if you muck with these
00049 //      as the generated code depends on how this is set up..
00050 ////////////////////////////////////////////////////////////////////////
00051 void DTOOL_Call_ExtractThisPointerForType(PyObject *self, Dtool_PyTypedObject * classdef, void ** answer)
00052 {
00053     if(DtoolCanThisBeAPandaInstance(self))
00054         *answer = ((Dtool_PyInstDef *)self)->_My_Type->_Dtool_UpcastInterface(self,classdef);
00055     else
00056         answer = NULL;
00057 };
00058 
00059 ////////////////////////////////////////////////////////////////////
00060 //     Function: attempt_coercion
00061 //  Description: A helper function for DTOOL_Call_GetPointerThisClass,
00062 //               below.  This attempts to coerce the given object to
00063 //               the indicated Panda object, by creating a temporary
00064 //               instance of the required Panda object.  If
00065 //               successful, returns the "this" pointer of the
00066 //               temporary object; otherwise, returns NULL.
00067 ////////////////////////////////////////////////////////////////////
00068 static void *
00069 attempt_coercion(PyObject *self, Dtool_PyTypedObject *classdef,
00070                  PyObject **coerced) {
00071   // The supplied parameter is not the required type.
00072   if (coerced != NULL) {
00073     // Attempt coercion: try to create a temporary instance of the
00074     // required class using the supplied parameter.
00075     PyObject *obj = PyObject_Call((PyObject *)classdef, self, NULL);
00076     if (obj == NULL) {
00077       // That didn't work; try to call a static "make" method instead.
00078       PyObject *make = PyObject_GetAttrString((PyObject *)classdef, "make");
00079       if (make != NULL) {
00080         PyErr_Clear();
00081         obj = PyObject_Call(make, self, NULL);
00082         Py_DECREF(make);
00083       }
00084     }
00085     if (obj != NULL) {
00086       // Well, whaddaya know?  The supplied parameter(s) suited
00087       // the object's constructor.  Now we have a temporary object
00088       // that we can pass to the function.
00089       Dtool_PyTypedObject *my_type = ((Dtool_PyInstDef *)obj)->_My_Type;
00090       void *result = my_type->_Dtool_UpcastInterface(obj, classdef);
00091       if (result != NULL) {
00092         // Successfully coerced.  Store the newly-allocated
00093         // pointer, so the caller can release the coerced object
00094         // at his leisure.  We store it in a list, so that other
00095         // parameters can accumulate there too.
00096         if ((*coerced) == NULL) {
00097           (*coerced) = PyList_New(0);
00098         }
00099         PyList_Append(*coerced, obj);
00100         Py_DECREF(obj);
00101         return result;
00102       }
00103       // Some problem getting the C++ pointer from our created
00104       // temporary object.  Weird.
00105       Py_DECREF(obj);
00106     }
00107     
00108     // Clear the error returned by the coercion constructor.  It's not
00109     // the error message we want to report.
00110     PyErr_Clear();
00111   }
00112   return NULL;
00113 }
00114 
00115 // Temporary function to preserve backward compatibility.
00116 void *
00117 DTOOL_Call_GetPointerThisClass(PyObject *self, Dtool_PyTypedObject *classdef,
00118                                int param, const string &function_name, bool const_ok,
00119                                PyObject **coerced) {
00120   return DTOOL_Call_GetPointerThisClass(self, classdef,
00121                                         param, function_name, const_ok,
00122                                         coerced, true);
00123 }
00124 
00125 ////////////////////////////////////////////////////////////////////
00126 //     Function: DTOOL_Call_GetPointerThisClass
00127 //  Description: Extracts the C++ pointer for an object, given its
00128 //               Python wrapper object, for passing as the parameter
00129 //               to a C++ function.
00130 //
00131 //               self is the Python wrapper object in question.
00132 //
00133 //               classdef is the Python class wrapper for the C++
00134 //               class in which the this pointer should be returned.
00135 //               (This may require an upcast operation, if self is not
00136 //               already an instance of classdef.)
00137 //
00138 //               param and function_name are used for error reporting
00139 //               only, and describe the particular function and
00140 //               parameter index for this parameter.
00141 //
00142 //               const_ok is true if the function is declared const
00143 //               and can therefore be called with either a const or
00144 //               non-const "this" pointer, or false if the function is
00145 //               declared non-const, and can therefore be called with
00146 //               only a non-const "this" pointer.
00147 //
00148 //               If coerced is non-NULL, parameter coercion will be
00149 //               attempted.  This means the supplied parameter may not
00150 //               exactly match the required type, but will satisfy the
00151 //               require type's constructor; and we will create
00152 //               temporary object(s) of the required type instead.  In
00153 //               this case, coerced is a pointer to a PyList that will
00154 //               be filled with these temporary objects.  If coerced
00155 //               is a pointer to a NULL PyObject, a new PyList will be
00156 //               created on the first successful coercion.  If coerced
00157 //               itself is NULL, parameter coercion will not be
00158 //               attempted.
00159 //
00160 //               The return value is the C++ pointer that was
00161 //               extracted, or NULL if there was a problem (in which
00162 //               case the Python exception state will have been set).
00163 ////////////////////////////////////////////////////////////////////
00164 void *
00165 DTOOL_Call_GetPointerThisClass(PyObject *self, Dtool_PyTypedObject *classdef,
00166                                int param, const string &function_name, bool const_ok,
00167                                PyObject **coerced, bool report_errors) {
00168   if (PyErr_Occurred()) {
00169     return NULL;
00170   }
00171   if (self != NULL) {
00172     if (DtoolCanThisBeAPandaInstance(self)) {
00173       Dtool_PyTypedObject *my_type = ((Dtool_PyInstDef *)self)->_My_Type;
00174       void *result = my_type->_Dtool_UpcastInterface(self, classdef);
00175       if (result != NULL) {
00176         if (const_ok || !((Dtool_PyInstDef *)self)->_is_const) {
00177           return result;
00178         }
00179 
00180         if (report_errors) {
00181           ostringstream str;
00182           str << function_name << "() argument " << param << " may not be const";
00183           string msg = str.str();
00184           PyErr_SetString(PyExc_TypeError, msg.c_str());
00185         }
00186 
00187       } else {
00188         if (report_errors) {
00189           ostringstream str;
00190           str << function_name << "() argument " << param << " must be ";
00191           
00192           
00193           PyObject *fname = PyObject_GetAttrString((PyObject *)classdef, "__name__");
00194           if (fname != (PyObject *)NULL) {
00195             str << PyString_AsString(fname);
00196             Py_DECREF(fname);
00197           } else {
00198             str << classdef->_name;
00199           }
00200           
00201           PyObject *tname = PyObject_GetAttrString((PyObject *)self->ob_type, "__name__");
00202           if (tname != (PyObject *)NULL) {
00203             str << ", not " << PyString_AsString(tname);
00204             Py_DECREF(tname);
00205           } else {
00206             str << ", not " << my_type->_name;
00207           }
00208           
00209           string msg = str.str();
00210           PyErr_SetString(PyExc_TypeError, msg.c_str());
00211         }
00212       }
00213 
00214     } else {
00215       // The parameter was not a Panda type.  Can we coerce it to the
00216       // appropriate type, by creating a temporary object?
00217       void *result = attempt_coercion(self, classdef, coerced);
00218       if (result != NULL) {
00219         return result;
00220       }
00221 
00222       // Coercion failed.
00223       if (report_errors) {
00224         ostringstream str;
00225         str << function_name << "() argument " << param << " must be ";
00226         
00227         PyObject *fname = PyObject_GetAttrString((PyObject *)classdef, "__name__");
00228         if (fname != (PyObject *)NULL) {
00229           str << PyString_AsString(fname);
00230           Py_DECREF(fname);
00231         } else {
00232           str << classdef->_name;
00233         }
00234         
00235         PyObject *tname = PyObject_GetAttrString((PyObject *)self->ob_type, "__name__");
00236         if (tname != (PyObject *)NULL) {
00237           str << ", not " << PyString_AsString(tname);
00238           Py_DECREF(tname);
00239         }
00240         
00241         string msg = str.str();
00242         PyErr_SetString(PyExc_TypeError, msg.c_str());
00243       }
00244     }
00245   } else {
00246     if (report_errors) {
00247       PyErr_SetString(PyExc_TypeError, "Self Is Null"); 
00248     }
00249   }
00250 
00251   return NULL;
00252 }
00253 
00254 void * DTOOL_Call_GetPointerThis(PyObject *self)
00255 {
00256   if(self != NULL)
00257   {
00258       if(DtoolCanThisBeAPandaInstance(self))
00259       {
00260         Dtool_PyInstDef * pyself = (Dtool_PyInstDef *) self;
00261         return pyself->_ptr_to_object;
00262       }
00263   }
00264 
00265   return NULL;
00266 };
00267 
00268 ////////////////////////////////////////////////////////////////////////
00269 //  Function : DTool_CreatePyInstanceTyped
00270 //
00271 // this function relies on the behavior of typed objects in the panda system. 
00272 //
00273 ////////////////////////////////////////////////////////////////////////
00274 PyObject * DTool_CreatePyInstanceTyped(void * local_this_in, Dtool_PyTypedObject & known_class_type, bool memory_rules, bool is_const, int RunTimeType)
00275 {     
00276     if(local_this_in == NULL )
00277     {
00278         // Lets don't be stupid..
00279         PyErr_SetString(PyExc_TypeError, "C Function Return Null 'this'");
00280         return NULL;
00281     }
00282    /////////////////////////////////////////////////////
00283    // IF the calss is posibly a run time typed object
00284    /////////////////////////////////////////////////////
00285     if(RunTimeType > 0)
00286     {
00287        /////////////////////////////////////////////////////
00288        // get best fit class...
00289        /////////////////////////////////////////////////////
00290         Dtool_PyTypedObject * target_class = Dtool_RuntimeTypeDtoolType(RunTimeType);
00291         if(target_class != NULL)
00292         {
00293            /////////////////////////////////////////////////////
00294            // cast to the type...
00295            //////////////////////////////////////////////////////
00296             void * new_local_this = target_class->_Dtool_DowncastInterface(local_this_in,&known_class_type);
00297             if(new_local_this != NULL)
00298             {
00299                 /////////////////////////////////////////////
00300                 // ask class to allocate a instance..
00301                 /////////////////////////////////////////////
00302                 Dtool_PyInstDef * self = (Dtool_PyInstDef *) target_class->As_PyTypeObject().tp_new(&target_class->As_PyTypeObject(), NULL,NULL);
00303                 if(self != NULL)
00304                 {
00305                     self->_ptr_to_object = new_local_this;
00306                     self->_memory_rules = memory_rules;
00307                     self->_is_const = is_const;
00308                     self->_signature = PY_PANDA_SIGNATURE;
00309                     self->_My_Type = target_class;    
00310                     return (PyObject *)self;
00311                 }             
00312             }
00313         }
00314     }
00315 
00316     /////////////////////////////////////////////////////
00317     // if we get this far .. just wrap the thing in the known type ??
00318     //    better than aborting...I guess....
00319     /////////////////////////////////////////////////////
00320     Dtool_PyInstDef * self = (Dtool_PyInstDef *) known_class_type.As_PyTypeObject().tp_new(&known_class_type.As_PyTypeObject(), NULL,NULL);
00321     if(self != NULL)
00322     {
00323         self->_ptr_to_object = local_this_in;
00324         self->_memory_rules = memory_rules;
00325         self->_is_const = is_const;
00326         self->_signature = PY_PANDA_SIGNATURE;
00327         self->_My_Type = &known_class_type;    
00328     }
00329     return (PyObject *)self;
00330 };
00331 
00332 ////////////////////////////////////////////////////////////////////////
00333 // DTool_CreatePyInstance .. wrapper function to finalize the existance of a general 
00334 //    dtool py instance..
00335 ////////////////////////////////////////////////////////////////////////
00336 PyObject * DTool_CreatePyInstance(void * local_this, Dtool_PyTypedObject & in_classdef, bool memory_rules, bool is_const)
00337 {    
00338     if(local_this == NULL)
00339     {
00340         PyErr_SetString(PyExc_TypeError, "C Function Return Null 'this' ");
00341         return NULL;
00342     }
00343 
00344     Dtool_PyTypedObject * classdef = &in_classdef;
00345     Dtool_PyInstDef * self = (Dtool_PyInstDef *) classdef->As_PyTypeObject().tp_new(&classdef->As_PyTypeObject(), NULL,NULL);
00346     if(self != NULL)
00347     {
00348         self->_ptr_to_object = local_this;
00349         self->_memory_rules = memory_rules;
00350         self->_is_const = is_const;
00351         self->_My_Type = classdef;    
00352     } 
00353     return (PyObject *)self;
00354 };
00355 
00356 ///////////////////////////////////////////////////////////////////////////////
00357 /// Th Finalizer for simple instances..
00358 ///////////////////////////////////////////////////////////////////////////////
00359 int  DTool_PyInit_Finalize(PyObject * self, void * This, Dtool_PyTypedObject *type, bool memory_rules, bool is_const)
00360 {
00361     // lets put some code in here that checks to see the memory is properly configured..
00362     // prior to my call ..
00363 
00364     ((Dtool_PyInstDef *)self)->_My_Type = type;
00365     ((Dtool_PyInstDef *)self)->_ptr_to_object = This;
00366     ((Dtool_PyInstDef *)self)->_memory_rules = memory_rules;
00367     ((Dtool_PyInstDef *)self)->_is_const = is_const;
00368     return 0;
00369 }
00370 
00371 ///////////////////////////////////////////////////////////////////////////////
00372 /// A heler function to glu methed definition together .. that can not be done at 
00373 // code generation time becouse of multiple generation passes in interigate..
00374 //
00375 ///////////////////////////////////////////////////////////////////////////////
00376 
00377 void Dtool_Accum_MethDefs(PyMethodDef  in[], MethodDefmap &themap)
00378 {
00379     for(; in->ml_name != NULL; in++)
00380     {
00381         if(themap.find(in->ml_name) == themap.end())
00382         {
00383             themap[in->ml_name] = in;
00384         }
00385     }
00386 }   
00387 
00388 ///////////////////////////////////////////////////////////////////////////////
00389 //  ** HACK ** allert..
00390 //
00391 //      Need to keep a runtime type dictionary ... that is forward declared of typed object.
00392 //        We rely on the fact that typed objects are uniquly defined by an integer.
00393 //
00394 ///////////////////////////////////////////////////////////////////////////////
00395 
00396 void
00397 RegisterRuntimeClass(Dtool_PyTypedObject * otype, int class_id) {
00398   if (class_id == 0) {
00399     interrogatedb_cat.warning()
00400       << "Class " << otype->_name 
00401       << " has a zero TypeHandle value; check that init_type() is called.\n";
00402 
00403   } else if (class_id > 0) {
00404     RunTimeTypeDictionary &dict = GetRunTimeDictionary();
00405     pair<RunTimeTypeDictionary::iterator, bool> result =
00406       dict.insert(RunTimeTypeDictionary::value_type(class_id, otype));
00407     if (!result.second) {
00408       // There was already an entry in the dictionary for class_id.
00409       Dtool_PyTypedObject *other_type = (*result.first).second;
00410       interrogatedb_cat.warning()
00411         << "Classes " << otype->_name << " and " << other_type->_name
00412         << " share the same TypeHandle value (" << class_id 
00413         << "); check class definitions.\n";
00414 
00415     } else {
00416       GetRunTimeTypeList().insert(class_id);
00417       otype->_Dtool_IsRunTimeCapable = true;
00418     }
00419   }
00420 };
00421 
00422 ///////////////////////////////////////////////////////////////////////////////
00423 ///////////////////////////////////////////////////////////////////////////////
00424 Dtool_PyTypedObject *  Dtool_RuntimeTypeDtoolType(int type)
00425 {
00426     RunTimeTypeDictionary::iterator di = GetRunTimeDictionary().find(type);
00427     if(di != GetRunTimeDictionary().end())
00428         return di->second;
00429     else
00430     {
00431         int  type2 = get_best_parent_from_Set(type,GetRunTimeTypeList());
00432         di = GetRunTimeDictionary().find(type2);
00433         if(di != GetRunTimeDictionary().end())
00434             return di->second;
00435     }
00436     return NULL;    
00437 };
00438 
00439 ///////////////////////////////////////////////////////////////////////////////
00440 void Dtool_PyModuleInitHelper( LibrayDef   *defs[], const char *  modulename)
00441 {
00442     // the module level function inits....
00443     MethodDefmap  functions;
00444     for(int xx = 0; defs[xx] != NULL; xx++)
00445         Dtool_Accum_MethDefs(defs[xx]->_methods,functions);
00446 
00447     PyMethodDef  *newdef = new PyMethodDef[functions.size()+1];
00448     MethodDefmap::iterator mi;
00449     int     offset = 0;
00450     for(mi = functions.begin(); mi != functions.end(); mi++, offset++)
00451         newdef[offset] = *mi->second;
00452     newdef[offset].ml_doc = NULL;
00453     newdef[offset].ml_name = NULL;
00454     newdef[offset].ml_meth = NULL;
00455     newdef[offset].ml_flags = 0;
00456 
00457     PyObject * module = Py_InitModule((char *)modulename,newdef);   
00458 
00459     if(module == NULL)
00460     {
00461          PyErr_SetString(PyExc_TypeError, "Py_InitModule Returned NULL ???"); 
00462          return;
00463     }
00464 
00465 
00466     // the constant inits... enums, classes ...
00467     for(int y = 0; defs[y] != NULL; y++)
00468         defs[y]->_constants(module);
00469 
00470     PyModule_AddIntConstant(module,"Dtool_PyNativeInterface",1);
00471 }
00472 ///////////////////////////////////////////////////////////////////////////////
00473 ///  HACK.... Be carefull 
00474 //
00475 //  Dtool_BorrowThisReference
00476 //      This function can be used to grab the "THIS" pointer from an object and use it
00477 //      Required to support historical inheritance in the form of "is this instance of"..
00478 //
00479 ///////////////////////////////////////////////////////////////////////////////
00480 PyObject * Dtool_BorrowThisReference(PyObject * self, PyObject * args )
00481 {
00482     PyObject *from_in = NULL;
00483     PyObject *to_in = NULL;
00484     if(PyArg_ParseTuple(args, "OO", &to_in, &from_in)) 
00485     {
00486 
00487         if(DtoolCanThisBeAPandaInstance(from_in) && DtoolCanThisBeAPandaInstance(to_in))
00488         {
00489             Dtool_PyInstDef * from = (Dtool_PyInstDef *) from_in;
00490             Dtool_PyInstDef * to = (Dtool_PyInstDef *) to_in;
00491             if(from->_My_Type == to->_My_Type)
00492             {
00493                 to->_memory_rules = false;
00494                 to->_is_const = from->_is_const;
00495                 to->_ptr_to_object = from->_ptr_to_object;
00496                 return Py_BuildValue("");
00497             }
00498             PyErr_SetString(PyExc_TypeError, "Must Be Same Type??"); 
00499         }
00500         else
00501             PyErr_SetString(PyExc_TypeError, "One of these does not appear to be DTOOL Instance ??"); 
00502     }
00503     return (PyObject *) NULL;
00504 }
00505 //////////////////////////////////////////////////////////////////////////////////////////////
00506 // We do expose a dictionay for dtool classes .. this should be removed at some point..
00507 //////////////////////////////////////////////////////////////////////////////////////////////
00508 PyObject * Dtool_AddToDictionary(PyObject * self1, PyObject * args )
00509 {
00510 
00511     PyObject  *     self;
00512     PyObject  *     subject;
00513     PyObject  *     key;
00514     if(PyArg_ParseTuple(args, "OSO", &self, &key, &subject))
00515     {
00516         PyObject * dict = ((PyTypeObject *)self)->tp_dict;
00517         if(dict == NULL && !PyDict_Check(dict))
00518             PyErr_SetString(PyExc_TypeError, "No dictionary On Object");
00519         else
00520             PyDict_SetItem(dict,key,subject);
00521 
00522     }   
00523     if(PyErr_Occurred())
00524         return (PyObject *)NULL;
00525     return Py_BuildValue("");
00526 
00527 }
00528 ///////////////////////////////////////////////////////////////////////////////////
00529 /*
00530 inline long  DTool_HashKey(PyObject * inst)
00531 {
00532     long   outcome = (long)inst;
00533     PyObject * func = PyObject_GetAttrString(inst, "__hash__");
00534     if (func == NULL) 
00535     {
00536         if(DtoolCanThisBeAPandaInstance(inst))
00537             if(((Dtool_PyInstDef *)inst)->_ptr_to_object != NULL)
00538                 outcome =  (long)((Dtool_PyInstDef *)inst)->_ptr_to_object;
00539     }
00540     else
00541     {
00542         PyObject *res = PyEval_CallObject(func, (PyObject *)NULL);
00543         Py_DECREF(func);
00544         if (res == NULL)
00545             return -1;
00546         if (PyInt_Check(res)) 
00547         {
00548             outcome = PyInt_AsLong(res);
00549             if (outcome == -1)
00550                 outcome = -2;
00551         }
00552         else 
00553         {
00554             PyErr_SetString(PyExc_TypeError,
00555                 "__hash__() should return an int");
00556             outcome = -1;
00557         }
00558         Py_DECREF(res);
00559     }
00560     return outcome;
00561 }
00562 */
00563 
00564 /* Compare v to w.  Return
00565    -1 if v <  w or exception (PyErr_Occurred() true in latter case).
00566     0 if v == w.
00567     1 if v > w.
00568    XXX The docs (C API manual) say the return value is undefined in case
00569    XXX of error.
00570 */
00571 
00572 int DTOOL_PyObject_Compare_old(PyObject *v1, PyObject *v2)
00573 {
00574     // if we are related..
00575     if(PyType_IsSubtype(v1->ob_type, v2->ob_type)) 
00576     {
00577         void * v1_this = DTOOL_Call_GetPointerThis(v1);
00578         void * v2_this = DTOOL_Call_GetPointerThis(v2);
00579         if(v1_this != NULL && v2_this != NULL) // both are our types...
00580         {
00581             PyObject * func = PyObject_GetAttrString(v1, "compareTo");
00582             if (func == NULL)
00583             {
00584                 PyErr_Clear();
00585             }
00586             else
00587             {
00588                 PyObject * res = NULL;
00589                 PyObject * args = Py_BuildValue("(O)", v2);
00590                 if (args != NULL)
00591                 {
00592                     res = PyObject_Call(func, args, NULL);
00593                     Py_DECREF(args);
00594                 }
00595                 Py_DECREF(func);
00596                 PyErr_Clear(); // just in case the function threw an error
00597                 // only use if the function  return an INT... hmm
00598                 if(res != NULL && PyInt_Check(res))
00599                 {
00600                     int answer = PyInt_AsLong(res);
00601                     Py_DECREF(res);
00602                     return  answer;
00603                 }
00604                 if(res != NULL)
00605                     Py_DECREF(res);
00606 
00607             };
00608             // CompareTo Failed some how :(
00609             // do a this compare  .. if Possible...
00610             if(v1_this < v2_this)
00611                 return -1;
00612 
00613             if(v1_this > v2_this)
00614                 return 1;
00615             return 0;
00616         }
00617         // ok drop to a basic object compare hmmmmmm
00618     }
00619     if(v1 < v2)
00620         return  -1;
00621     if(v1 > v2)
00622         return  1;
00623     return 0;   
00624 }
00625 
00626 
00627 
00628 
00629 int DTOOL_PyObject_Compare(PyObject *v1, PyObject *v2)
00630 {
00631     //  First try compare to function..
00632     PyObject * func = PyObject_GetAttrString(v1, "compareTo");
00633     if (func == NULL)
00634     {
00635         PyErr_Clear();
00636     }
00637     else
00638     {
00639         PyObject * res = NULL;
00640         PyObject * args = Py_BuildValue("(O)", v2);
00641         if (args != NULL)
00642         {
00643             res = PyObject_Call(func, args, NULL);
00644             Py_DECREF(args);
00645         }
00646         Py_DECREF(func);
00647         PyErr_Clear(); // just in case the function threw an error
00648         // only use if the function  return an INT... hmm
00649         if(res != NULL && PyInt_Check(res))
00650         {
00651             int answer = PyInt_AsLong(res);
00652             Py_DECREF(res);
00653 
00654             // Python really wants us to return strictly -1, 0, or 1.
00655             if (answer < 0) {
00656               return -1;
00657             } else if (answer > 0) {
00658               return 1;
00659             } else {
00660               return 0;
00661             }
00662         }
00663         if(res != NULL)
00664             Py_DECREF(res);
00665 
00666     };
00667 
00668     // try this compare
00669     void * v1_this = DTOOL_Call_GetPointerThis(v1);
00670     void * v2_this = DTOOL_Call_GetPointerThis(v2);
00671     if(v1_this != NULL && v2_this != NULL) // both are our types...
00672     {
00673         if(v1_this < v2_this)
00674             return -1;
00675 
00676         if(v1_this > v2_this)
00677             return 1;
00678         return 0;
00679     }
00680 
00681     // ok self compare...
00682     if(v1 < v2)
00683         return  -1;
00684     if(v1 > v2)
00685         return  1;
00686     return 0;   
00687 }
00688 
00689 
00690 PyObject *make_list_for_item(PyObject *self, const char *num_name,
00691                              const char *element_name) {
00692   PyObject *num_result = PyObject_CallMethod(self, (char *)num_name, (char *)"()");
00693   if (num_result == NULL) {
00694     return NULL;
00695   }
00696   Py_ssize_t num_elements = PyInt_AsSsize_t(num_result);
00697   Py_DECREF(num_result);
00698   
00699   PyObject *list = PyList_New(num_elements);
00700   for (int i = 0; i < num_elements; ++i) {
00701     PyObject *element = PyObject_CallMethod(self, (char *)element_name, (char *)"(i)", i);
00702     if (element == NULL) {
00703       Py_DECREF(list);
00704       return NULL;
00705     }
00706     PyList_SetItem(list, i, element);
00707   }
00708   return list;
00709 }
00710 
00711 ////////////////////////////////////////////////////////////////////
00712 //     Function: copy_from_make_copy
00713 //  Description: This is a support function for a synthesized
00714 //               __copy__() method from a C++ make_copy() method.
00715 ////////////////////////////////////////////////////////////////////
00716 PyObject *copy_from_make_copy(PyObject *self) {
00717   return PyObject_CallMethod(self, (char *)"makeCopy", (char *)"()");
00718 }
00719 
00720 ////////////////////////////////////////////////////////////////////
00721 //     Function: copy_from_copy_constructor
00722 //  Description: This is a support function for a synthesized
00723 //               __copy__() method from a C++ copy constructor.
00724 ////////////////////////////////////////////////////////////////////
00725 PyObject *copy_from_copy_constructor(PyObject *self) {
00726   PyObject *this_class = PyObject_Type(self);
00727   if (this_class == NULL) {
00728     return NULL;
00729   }
00730 
00731   PyObject *result = PyObject_CallFunction(this_class, (char *)"(O)", self);
00732   Py_DECREF(this_class);
00733   return result;
00734 }
00735 
00736 ////////////////////////////////////////////////////////////////////
00737 //     Function: map_deepcopy_to_copy
00738 //  Description: This is a support function for a synthesized
00739 //               __deepcopy__() method for any class that has a
00740 //               __copy__() method.  The sythethic method simply
00741 //               invokes __copy__().
00742 ////////////////////////////////////////////////////////////////////
00743 PyObject *map_deepcopy_to_copy(PyObject *self, PyObject *args) {
00744   return PyObject_CallMethod(self, (char *)"__copy__", (char *)"()");
00745 }
00746 
00747 ////////////////////////////////////////////////////////////////////
00748 //     Function: PyLongOrInt_FromUnsignedLong
00749 //  Description: Similar to PyLong_FromUnsignedLong(), but returns
00750 //               either a regular integer or a long integer, according
00751 //               to whether the indicated value will fit.
00752 ////////////////////////////////////////////////////////////////////
00753 EXPCL_DTOOLCONFIG PyObject *
00754 PyLongOrInt_FromUnsignedLong(unsigned long value) {
00755   if ((long)value < 0) {
00756     return PyLong_FromUnsignedLong(value);
00757   } else {
00758     return PyInt_FromLong((long)value);
00759   }
00760 }
00761 
00762 
00763 #endif  // HAVE_PYTHON
 All Classes Functions Variables Enumerations