mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-04 02:42:49 -04:00
718 lines
25 KiB
C++
718 lines
25 KiB
C++
// Filename: py_panda.cxx
|
|
// Created by: drose (04Jul05)
|
|
//
|
|
////////////////////////////////////////////////////////////////////
|
|
//
|
|
// PANDA 3D SOFTWARE
|
|
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
|
//
|
|
// All use of this software is subject to the terms of the revised BSD
|
|
// license. You should have received a copy of this license along
|
|
// with this source code in a file named "LICENSE."
|
|
//
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
#include "py_panda.h"
|
|
#include "config_interrogatedb.h"
|
|
|
|
#ifdef HAVE_PYTHON
|
|
|
|
PyMemberDef standard_type_members[] = {
|
|
{(char *)"this", T_INT, offsetof(Dtool_PyInstDef,_ptr_to_object),READONLY, (char *)"C++ This if any"},
|
|
// {(char *)"this_ownership", T_INT, offsetof(Dtool_PyInstDef, _memory_rules), READONLY, (char *)"C++ 'this' ownership rules"},
|
|
// {(char *)"this_const", T_INT, offsetof(Dtool_PyInstDef, _is_const), READONLY, (char *)"C++ 'this' const flag"},
|
|
// {(char *)"this_signature", T_INT, offsetof(Dtool_PyInstDef, _signature), READONLY, (char *)"A type check signature"},
|
|
{(char *)"this_metatype", T_OBJECT, offsetof(Dtool_PyInstDef, _My_Type), READONLY, (char *)"The dtool meta object"},
|
|
{NULL} /* Sentinel */
|
|
};
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
/// Simple Recognition Functions..
|
|
////////////////////////////////////////////////////////////////////////
|
|
bool DtoolCanThisBeAPandaInstance(PyObject *self)
|
|
{
|
|
// simple sanity check for the class type..size.. will stop basic foobars..
|
|
if(self->ob_type->tp_basicsize >= (int)sizeof(Dtool_PyInstDef))
|
|
{
|
|
Dtool_PyInstDef * pyself = (Dtool_PyInstDef *) self;
|
|
if(pyself->_signature == PY_PANDA_SIGNATURE)
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
////////////////////////////////////////////////////////////////////////
|
|
// Function : DTOOL_Call_ExtractThisPointerForType
|
|
//
|
|
// These are the wrappers that allow for down and upcast from type ..
|
|
// needed by the Dtool py interface.. Be very careful if you muck with these
|
|
// as the generated code depends on how this is set up..
|
|
////////////////////////////////////////////////////////////////////////
|
|
void DTOOL_Call_ExtractThisPointerForType(PyObject *self, Dtool_PyTypedObject * classdef, void ** answer)
|
|
{
|
|
if(DtoolCanThisBeAPandaInstance(self))
|
|
*answer = ((Dtool_PyInstDef *)self)->_My_Type->_Dtool_UpcastInterface(self,classdef);
|
|
else
|
|
answer = NULL;
|
|
};
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: attempt_coercion
|
|
// Description: A helper function for DTOOL_Call_GetPointerThisClass,
|
|
// below. This attempts to coerce the given object to
|
|
// the indicated Panda object, by creating a temporary
|
|
// instance of the required Panda object. If
|
|
// successful, returns the "this" pointer of the
|
|
// temporary object; otherwise, returns NULL.
|
|
////////////////////////////////////////////////////////////////////
|
|
static void *
|
|
attempt_coercion(PyObject *self, Dtool_PyTypedObject *classdef,
|
|
PyObject **coerced) {
|
|
// The supplied parameter is not the required type.
|
|
if (coerced != NULL) {
|
|
// Attempt coercion: try to create a temporary instance of the
|
|
// required class using the supplied parameter.
|
|
PyObject *obj = PyObject_Call((PyObject *)classdef, self, NULL);
|
|
if (obj != NULL) {
|
|
// Well, whaddaya know? The supplied parameter(s) suited
|
|
// the object's constructor. Now we have a temporary object
|
|
// that we can pass to the function.
|
|
Dtool_PyTypedObject *my_type = ((Dtool_PyInstDef *)obj)->_My_Type;
|
|
void *result = my_type->_Dtool_UpcastInterface(obj, classdef);
|
|
if (result != NULL) {
|
|
// Successfully coerced. Store the newly-allocated
|
|
// pointer, so the caller can release the coerced object
|
|
// at his leisure. We store it in a list, so that other
|
|
// parameters can accumulate there too.
|
|
if ((*coerced) == NULL) {
|
|
(*coerced) = PyList_New(0);
|
|
}
|
|
PyList_Append(*coerced, obj);
|
|
return result;
|
|
}
|
|
// Some problem getting the C++ pointer from our created
|
|
// temporary object. Weird.
|
|
Py_DECREF(obj);
|
|
}
|
|
|
|
// Clear the error returned by the coercion constructor. It's not
|
|
// the error message we want to report.
|
|
PyErr_Clear();
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
// Temporary function to preserve backward compatibility.
|
|
void *
|
|
DTOOL_Call_GetPointerThisClass(PyObject *self, Dtool_PyTypedObject *classdef,
|
|
int param, const string &function_name, bool const_ok,
|
|
PyObject **coerced) {
|
|
return DTOOL_Call_GetPointerThisClass(self, classdef,
|
|
param, function_name, const_ok,
|
|
coerced, true);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DTOOL_Call_GetPointerThisClass
|
|
// Description: Extracts the C++ pointer for an object, given its
|
|
// Python wrapper object, for passing as the parameter
|
|
// to a C++ function.
|
|
//
|
|
// self is the Python wrapper object in question.
|
|
//
|
|
// classdef is the Python class wrapper for the C++
|
|
// class in which the this pointer should be returned.
|
|
// (This may require an upcast operation, if self is not
|
|
// already an instance of classdef.)
|
|
//
|
|
// param and function_name are used for error reporting
|
|
// only, and describe the particular function and
|
|
// parameter index for this parameter.
|
|
//
|
|
// const_ok is true if the function is declared const
|
|
// and can therefore be called with either a const or
|
|
// non-const "this" pointer, or false if the function is
|
|
// declared non-const, and can therefore be called with
|
|
// only a non-const "this" pointer.
|
|
//
|
|
// If coerced is non-NULL, parameter coercion will be
|
|
// attempted. This means the supplied parameter may not
|
|
// exactly match the required type, but will satisfy the
|
|
// require type's constructor; and we will create
|
|
// temporary object(s) of the required type instead. In
|
|
// this case, coerced is a pointer to a PyList that will
|
|
// be filled with these temporary objects. If coerced
|
|
// is a pointer to a NULL PyObject, a new PyList will be
|
|
// created on the first successful coercion. If coerced
|
|
// itself is NULL, parameter coercion will not be
|
|
// attempted.
|
|
//
|
|
// The return value is the C++ pointer that was
|
|
// extracted, or NULL if there was a problem (in which
|
|
// case the Python exception state will have been set).
|
|
////////////////////////////////////////////////////////////////////
|
|
void *
|
|
DTOOL_Call_GetPointerThisClass(PyObject *self, Dtool_PyTypedObject *classdef,
|
|
int param, const string &function_name, bool const_ok,
|
|
PyObject **coerced, bool report_errors) {
|
|
if (PyErr_Occurred()) {
|
|
return NULL;
|
|
}
|
|
if (self != NULL) {
|
|
if (DtoolCanThisBeAPandaInstance(self)) {
|
|
Dtool_PyTypedObject *my_type = ((Dtool_PyInstDef *)self)->_My_Type;
|
|
void *result = my_type->_Dtool_UpcastInterface(self, classdef);
|
|
if (result != NULL) {
|
|
if (const_ok || !((Dtool_PyInstDef *)self)->_is_const) {
|
|
return result;
|
|
}
|
|
|
|
if (report_errors) {
|
|
ostringstream str;
|
|
str << function_name << "() argument " << param << " may not be const";
|
|
string msg = str.str();
|
|
PyErr_SetString(PyExc_TypeError, msg.c_str());
|
|
}
|
|
|
|
} else {
|
|
if (report_errors) {
|
|
ostringstream str;
|
|
str << function_name << "() argument " << param << " must be ";
|
|
|
|
|
|
PyObject *fname = PyObject_GetAttrString((PyObject *)classdef, "__name__");
|
|
if (fname != (PyObject *)NULL) {
|
|
str << PyString_AsString(fname);
|
|
Py_DECREF(fname);
|
|
} else {
|
|
str << classdef->_name;
|
|
}
|
|
|
|
PyObject *tname = PyObject_GetAttrString((PyObject *)self->ob_type, "__name__");
|
|
if (tname != (PyObject *)NULL) {
|
|
str << ", not " << PyString_AsString(tname);
|
|
Py_DECREF(tname);
|
|
} else {
|
|
str << ", not " << my_type->_name;
|
|
}
|
|
|
|
string msg = str.str();
|
|
PyErr_SetString(PyExc_TypeError, msg.c_str());
|
|
}
|
|
}
|
|
|
|
} else {
|
|
// The parameter was not a Panda type. Can we coerce it to the
|
|
// appropriate type, by creating a temporary object?
|
|
void *result = attempt_coercion(self, classdef, coerced);
|
|
if (result != NULL) {
|
|
return result;
|
|
}
|
|
|
|
// Coercion failed.
|
|
if (report_errors) {
|
|
ostringstream str;
|
|
str << function_name << "() argument " << param << " must be ";
|
|
|
|
PyObject *fname = PyObject_GetAttrString((PyObject *)classdef, "__name__");
|
|
if (fname != (PyObject *)NULL) {
|
|
str << PyString_AsString(fname);
|
|
Py_DECREF(fname);
|
|
} else {
|
|
str << classdef->_name;
|
|
}
|
|
|
|
PyObject *tname = PyObject_GetAttrString((PyObject *)self->ob_type, "__name__");
|
|
if (tname != (PyObject *)NULL) {
|
|
str << ", not " << PyString_AsString(tname);
|
|
Py_DECREF(tname);
|
|
}
|
|
|
|
string msg = str.str();
|
|
PyErr_SetString(PyExc_TypeError, msg.c_str());
|
|
}
|
|
}
|
|
} else {
|
|
if (report_errors) {
|
|
PyErr_SetString(PyExc_TypeError, "Self Is Null");
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void * DTOOL_Call_GetPointerThis(PyObject *self)
|
|
{
|
|
if(self != NULL)
|
|
{
|
|
if(DtoolCanThisBeAPandaInstance(self))
|
|
{
|
|
Dtool_PyInstDef * pyself = (Dtool_PyInstDef *) self;
|
|
return pyself->_ptr_to_object;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
};
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// Function : DTool_CreatePyInstanceTyped
|
|
//
|
|
// this function relies on the behavior of typed objects in the panda system.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////
|
|
PyObject * DTool_CreatePyInstanceTyped(void * local_this_in, Dtool_PyTypedObject & known_class_type, bool memory_rules, bool is_const, int RunTimeType)
|
|
{
|
|
if(local_this_in == NULL )
|
|
{
|
|
// Lets don't be stupid..
|
|
PyErr_SetString(PyExc_TypeError, "C Function Return Null 'this'");
|
|
return NULL;
|
|
}
|
|
/////////////////////////////////////////////////////
|
|
// IF the calss is posibly a run time typed object
|
|
/////////////////////////////////////////////////////
|
|
if(RunTimeType > 0)
|
|
{
|
|
/////////////////////////////////////////////////////
|
|
// get best fit class...
|
|
/////////////////////////////////////////////////////
|
|
Dtool_PyTypedObject * target_class = Dtool_RuntimeTypeDtoolType(RunTimeType);
|
|
if(target_class != NULL)
|
|
{
|
|
/////////////////////////////////////////////////////
|
|
// cast to the type...
|
|
//////////////////////////////////////////////////////
|
|
void * new_local_this = target_class->_Dtool_DowncastInterface(local_this_in,&known_class_type);
|
|
if(new_local_this != NULL)
|
|
{
|
|
/////////////////////////////////////////////
|
|
// ask class to allocate a instance..
|
|
/////////////////////////////////////////////
|
|
Dtool_PyInstDef * self = (Dtool_PyInstDef *) target_class->As_PyTypeObject().tp_new(&target_class->As_PyTypeObject(), NULL,NULL);
|
|
if(self != NULL)
|
|
{
|
|
self->_ptr_to_object = new_local_this;
|
|
self->_memory_rules = memory_rules;
|
|
self->_is_const = is_const;
|
|
self->_signature = PY_PANDA_SIGNATURE;
|
|
self->_My_Type = target_class;
|
|
return (PyObject *)self;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////
|
|
// if we get this far .. just wrap the thing in the known type ??
|
|
// better than aborting...I guess....
|
|
/////////////////////////////////////////////////////
|
|
Dtool_PyInstDef * self = (Dtool_PyInstDef *) known_class_type.As_PyTypeObject().tp_new(&known_class_type.As_PyTypeObject(), NULL,NULL);
|
|
if(self != NULL)
|
|
{
|
|
self->_ptr_to_object = local_this_in;
|
|
self->_memory_rules = memory_rules;
|
|
self->_is_const = is_const;
|
|
self->_signature = PY_PANDA_SIGNATURE;
|
|
self->_My_Type = &known_class_type;
|
|
}
|
|
return (PyObject *)self;
|
|
};
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// DTool_CreatePyInstance .. wrapper function to finalize the existance of a general
|
|
// dtool py instance..
|
|
////////////////////////////////////////////////////////////////////////
|
|
PyObject * DTool_CreatePyInstance(void * local_this, Dtool_PyTypedObject & in_classdef, bool memory_rules, bool is_const)
|
|
{
|
|
if(local_this == NULL)
|
|
{
|
|
PyErr_SetString(PyExc_TypeError, "C Function Return Null 'this' ");
|
|
return NULL;
|
|
}
|
|
|
|
Dtool_PyTypedObject * classdef = &in_classdef;
|
|
Dtool_PyInstDef * self = (Dtool_PyInstDef *) classdef->As_PyTypeObject().tp_new(&classdef->As_PyTypeObject(), NULL,NULL);
|
|
if(self != NULL)
|
|
{
|
|
self->_ptr_to_object = local_this;
|
|
self->_memory_rules = memory_rules;
|
|
self->_is_const = is_const;
|
|
self->_My_Type = classdef;
|
|
}
|
|
return (PyObject *)self;
|
|
};
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/// Th Finalizer for simple instances..
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
int DTool_PyInit_Finalize(PyObject * self, void * This, Dtool_PyTypedObject *type, bool memory_rules, bool is_const)
|
|
{
|
|
// lets put some code in here that checks to see the memory is properly configured..
|
|
// prior to my call ..
|
|
|
|
((Dtool_PyInstDef *)self)->_My_Type = type;
|
|
((Dtool_PyInstDef *)self)->_ptr_to_object = This;
|
|
((Dtool_PyInstDef *)self)->_memory_rules = memory_rules;
|
|
((Dtool_PyInstDef *)self)->_is_const = is_const;
|
|
return 0;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/// A heler function to glu methed definition together .. that can not be done at
|
|
// code generation time becouse of multiple generation passes in interigate..
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
void Dtool_Accum_MethDefs(PyMethodDef in[], MethodDefmap &themap)
|
|
{
|
|
for(; in->ml_name != NULL; in++)
|
|
{
|
|
if(themap.find(in->ml_name) == themap.end())
|
|
{
|
|
themap[in->ml_name] = in;
|
|
}
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// ** HACK ** allert..
|
|
//
|
|
// Need to keep a runtime type dictionary ... that is forward declared of typed object.
|
|
// We rely on the fact that typed objects are uniquly defined by an integer.
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
void
|
|
RegisterRuntimeClass(Dtool_PyTypedObject * otype, int class_id) {
|
|
if (class_id == 0) {
|
|
interrogatedb_cat.warning()
|
|
<< "Class " << otype->_name
|
|
<< " has a zero TypeHandle value; check that init_type() is called.\n";
|
|
|
|
} else if (class_id > 0) {
|
|
RunTimeTypeDictionary &dict = GetRunTimeDictionary();
|
|
pair<RunTimeTypeDictionary::iterator, bool> result =
|
|
dict.insert(RunTimeTypeDictionary::value_type(class_id, otype));
|
|
if (!result.second) {
|
|
// There was already an entry in the dictionary for class_id.
|
|
Dtool_PyTypedObject *other_type = (*result.first).second;
|
|
interrogatedb_cat.warning()
|
|
<< "Classes " << otype->_name << " and " << other_type->_name
|
|
<< " share the same TypeHandle value (" << class_id
|
|
<< "); check class definitions.\n";
|
|
|
|
} else {
|
|
GetRunTimeTypeList().insert(class_id);
|
|
otype->_Dtool_IsRunTimeCapable = true;
|
|
}
|
|
}
|
|
};
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
Dtool_PyTypedObject * Dtool_RuntimeTypeDtoolType(int type)
|
|
{
|
|
RunTimeTypeDictionary::iterator di = GetRunTimeDictionary().find(type);
|
|
if(di != GetRunTimeDictionary().end())
|
|
return di->second;
|
|
else
|
|
{
|
|
int type2 = get_best_parent_from_Set(type,GetRunTimeTypeList());
|
|
di = GetRunTimeDictionary().find(type2);
|
|
if(di != GetRunTimeDictionary().end())
|
|
return di->second;
|
|
}
|
|
return NULL;
|
|
};
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
void Dtool_PyModuleInitHelper( LibrayDef *defs[], const char * modulename)
|
|
{
|
|
// the module level function inits....
|
|
MethodDefmap functions;
|
|
for(int xx = 0; defs[xx] != NULL; xx++)
|
|
Dtool_Accum_MethDefs(defs[xx]->_methods,functions);
|
|
|
|
PyMethodDef *newdef = new PyMethodDef[functions.size()+1];
|
|
MethodDefmap::iterator mi;
|
|
int offset = 0;
|
|
for(mi = functions.begin(); mi != functions.end(); mi++, offset++)
|
|
newdef[offset] = *mi->second;
|
|
newdef[offset].ml_doc = NULL;
|
|
newdef[offset].ml_name = NULL;
|
|
newdef[offset].ml_meth = NULL;
|
|
newdef[offset].ml_flags = 0;
|
|
|
|
PyObject * module = Py_InitModule(modulename,newdef);
|
|
|
|
if(module == NULL)
|
|
{
|
|
PyErr_SetString(PyExc_TypeError, "Py_InitModule Returned NULL ???");
|
|
return;
|
|
}
|
|
|
|
|
|
// the constant inits... enums, classes ...
|
|
for(int y = 0; defs[y] != NULL; y++)
|
|
defs[y]->_constants(module);
|
|
|
|
PyModule_AddIntConstant(module,"Dtool_PyNavtiveInterface",1);
|
|
}
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/// HACK.... Be carefull
|
|
//
|
|
// Dtool_BorrowThisReference
|
|
// This function can be used to grab the "THIS" pointer from an object and use it
|
|
// Required to support historical inheritance in the form of "is this instance of"..
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
PyObject * Dtool_BorrowThisReference(PyObject * self, PyObject * args )
|
|
{
|
|
PyObject *from_in = NULL;
|
|
PyObject *to_in = NULL;
|
|
if(PyArg_ParseTuple(args, "OO", &to_in, &from_in))
|
|
{
|
|
|
|
if(DtoolCanThisBeAPandaInstance(from_in) && DtoolCanThisBeAPandaInstance(to_in))
|
|
{
|
|
Dtool_PyInstDef * from = (Dtool_PyInstDef *) from_in;
|
|
Dtool_PyInstDef * to = (Dtool_PyInstDef *) to_in;
|
|
if(from->_My_Type == to->_My_Type)
|
|
{
|
|
to->_memory_rules = false;
|
|
to->_is_const = from->_is_const;
|
|
to->_ptr_to_object = from->_ptr_to_object;
|
|
return Py_BuildValue("");
|
|
}
|
|
PyErr_SetString(PyExc_TypeError, "Must Be Same Type??");
|
|
}
|
|
else
|
|
PyErr_SetString(PyExc_TypeError, "One of these does not appear to be DTOOL Instance ??");
|
|
}
|
|
return (PyObject *) NULL;
|
|
}
|
|
//////////////////////////////////////////////////////////////////////////////////////////////
|
|
// We do expose a dictionay for dtool classes .. this should be removed at some point..
|
|
//////////////////////////////////////////////////////////////////////////////////////////////
|
|
PyObject * Dtool_AddToDictionary(PyObject * self1, PyObject * args )
|
|
{
|
|
|
|
PyObject * self;
|
|
PyObject * subject;
|
|
PyObject * key;
|
|
if(PyArg_ParseTuple(args, "OSO", &self, &key, &subject))
|
|
{
|
|
PyObject * dict = ((PyTypeObject *)self)->tp_dict;
|
|
if(dict == NULL && !PyDict_Check(dict))
|
|
PyErr_SetString(PyExc_TypeError, "No dictionary On Object");
|
|
else
|
|
PyDict_SetItem(dict,key,subject);
|
|
|
|
}
|
|
if(PyErr_Occurred())
|
|
return (PyObject *)NULL;
|
|
return Py_BuildValue("");
|
|
|
|
}
|
|
///////////////////////////////////////////////////////////////////////////////////
|
|
/*
|
|
inline long DTool_HashKey(PyObject * inst)
|
|
{
|
|
long outcome = (long)inst;
|
|
PyObject * func = PyObject_GetAttrString(inst, "__hash__");
|
|
if (func == NULL)
|
|
{
|
|
if(DtoolCanThisBeAPandaInstance(inst))
|
|
if(((Dtool_PyInstDef *)inst)->_ptr_to_object != NULL)
|
|
outcome = (long)((Dtool_PyInstDef *)inst)->_ptr_to_object;
|
|
}
|
|
else
|
|
{
|
|
PyObject *res = PyEval_CallObject(func, (PyObject *)NULL);
|
|
Py_DECREF(func);
|
|
if (res == NULL)
|
|
return -1;
|
|
if (PyInt_Check(res))
|
|
{
|
|
outcome = PyInt_AsLong(res);
|
|
if (outcome == -1)
|
|
outcome = -2;
|
|
}
|
|
else
|
|
{
|
|
PyErr_SetString(PyExc_TypeError,
|
|
"__hash__() should return an int");
|
|
outcome = -1;
|
|
}
|
|
Py_DECREF(res);
|
|
}
|
|
return outcome;
|
|
}
|
|
*/
|
|
|
|
/* Compare v to w. Return
|
|
-1 if v < w or exception (PyErr_Occurred() true in latter case).
|
|
0 if v == w.
|
|
1 if v > w.
|
|
XXX The docs (C API manual) say the return value is undefined in case
|
|
XXX of error.
|
|
*/
|
|
|
|
int DTOOL_PyObject_Compare_old(PyObject *v1, PyObject *v2)
|
|
{
|
|
// if we are related..
|
|
if(PyType_IsSubtype(v1->ob_type, v2->ob_type))
|
|
{
|
|
void * v1_this = DTOOL_Call_GetPointerThis(v1);
|
|
void * v2_this = DTOOL_Call_GetPointerThis(v2);
|
|
if(v1_this != NULL && v2_this != NULL) // both are our types...
|
|
{
|
|
PyObject * func = PyObject_GetAttrString(v1, "compareTo");
|
|
if (func == NULL)
|
|
{
|
|
PyErr_Clear();
|
|
}
|
|
else
|
|
{
|
|
PyObject * res = NULL;
|
|
PyObject * args = Py_BuildValue("(O)", v2);
|
|
if (args != NULL)
|
|
{
|
|
res = PyObject_Call(func, args, NULL);
|
|
Py_DECREF(args);
|
|
}
|
|
Py_DECREF(func);
|
|
PyErr_Clear(); // just in case the function threw an error
|
|
// only use if the cuntion return an INT... hmm
|
|
if(res != NULL && PyInt_Check(res))
|
|
{
|
|
int answer = PyInt_AsLong(res);
|
|
Py_DECREF(res);
|
|
return answer;
|
|
}
|
|
if(res != NULL)
|
|
Py_DECREF(res);
|
|
|
|
};
|
|
// CompareTo Failed some how :(
|
|
// do a this compare .. if Possible...
|
|
if(v1_this < v2_this)
|
|
return -1;
|
|
|
|
if(v1_this > v2_this)
|
|
return 1;
|
|
return 0;
|
|
}
|
|
// ok drop to a basic object compare hmmmmmm
|
|
}
|
|
if(v1 < v2)
|
|
return -1;
|
|
if(v1 > v2)
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
int DTOOL_PyObject_Compare(PyObject *v1, PyObject *v2)
|
|
{
|
|
// First try compare to function..
|
|
PyObject * func = PyObject_GetAttrString(v1, "compareTo");
|
|
if (func == NULL)
|
|
{
|
|
PyErr_Clear();
|
|
}
|
|
else
|
|
{
|
|
PyObject * res = NULL;
|
|
PyObject * args = Py_BuildValue("(O)", v2);
|
|
if (args != NULL)
|
|
{
|
|
res = PyObject_Call(func, args, NULL);
|
|
Py_DECREF(args);
|
|
}
|
|
Py_DECREF(func);
|
|
PyErr_Clear(); // just in case the function threw an error
|
|
// only use if the cuntion return an INT... hmm
|
|
if(res != NULL && PyInt_Check(res))
|
|
{
|
|
int answer = PyInt_AsLong(res);
|
|
Py_DECREF(res);
|
|
|
|
// Python really wants us to return strictly -1, 0, or 1.
|
|
if (answer < 0) {
|
|
return -1;
|
|
} else if (answer > 0) {
|
|
return 1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
if(res != NULL)
|
|
Py_DECREF(res);
|
|
|
|
};
|
|
|
|
// try this compare
|
|
void * v1_this = DTOOL_Call_GetPointerThis(v1);
|
|
void * v2_this = DTOOL_Call_GetPointerThis(v2);
|
|
if(v1_this != NULL && v2_this != NULL) // both are our types...
|
|
{
|
|
if(v1_this < v2_this)
|
|
return -1;
|
|
|
|
if(v1_this > v2_this)
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
// ok self compare...
|
|
if(v1 < v2)
|
|
return -1;
|
|
if(v1 > v2)
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
|
|
PyObject *make_list_for_item(PyObject *self, const char *num_name,
|
|
const char *element_name) {
|
|
PyObject *num_result = PyObject_CallMethod(self, (char *)num_name, (char *)"()");
|
|
if (num_result == NULL) {
|
|
return NULL;
|
|
}
|
|
Py_ssize_t num_elements = PyInt_AsSsize_t(num_result);
|
|
Py_DECREF(num_result);
|
|
|
|
PyObject *list = PyList_New(num_elements);
|
|
for (int i = 0; i < num_elements; ++i) {
|
|
PyObject *element = PyObject_CallMethod(self, (char *)element_name, (char *)"(i)", i);
|
|
if (element == NULL) {
|
|
Py_DECREF(list);
|
|
return NULL;
|
|
}
|
|
PyList_SetItem(list, i, element);
|
|
}
|
|
return list;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: PyLongOrInt_FromUnsignedLong
|
|
// Description: Similar to PyLong_FromUnsignedLong(), but returns
|
|
// either a regular integer or a long integer, according
|
|
// to whether the indicated value will fit.
|
|
////////////////////////////////////////////////////////////////////
|
|
EXPCL_DTOOLCONFIG PyObject *
|
|
PyLongOrInt_FromUnsignedLong(unsigned long value) {
|
|
if ((long)value < 0) {
|
|
return PyLong_FromUnsignedLong(value);
|
|
} else {
|
|
return PyInt_FromLong((long)value);
|
|
}
|
|
}
|
|
|
|
|
|
#endif // HAVE_PYTHON
|