Panda3D
|
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