Blender V2.61 - r43446

PyObjectPlus.cpp

Go to the documentation of this file.
00001 /*
00002  * ***** BEGIN GPL LICENSE BLOCK *****
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  *
00018  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
00019  * All rights reserved.
00020  *
00021  * The Original Code is: all of this file.
00022  *
00023  * Contributor(s): none yet.
00024  *
00025  * ***** END GPL LICENSE BLOCK *****
00026  */
00027 
00033 /*------------------------------
00034  * PyObjectPlus cpp
00035  *
00036  * C++ library routines for Crawl 3.2
00037  *
00038  * Derived from work by
00039  * David Redish
00040  * graduate student
00041  * Computer Science Department 
00042  * Carnegie Mellon University (CMU)
00043  * Center for the Neural Basis of Cognition (CNBC) 
00044  * http://www.python.org/doc/PyCPP.html
00045  *
00046 ------------------------------*/
00047 #include <stdlib.h>
00048 #include <stddef.h>
00049 
00050 #include "PyObjectPlus.h"
00051 #include "STR_String.h"
00052 #include "MT_Vector3.h"
00053 #include "MEM_guardedalloc.h"
00054 
00055 PyObjectPlus::~PyObjectPlus()
00056 {
00057 #ifdef WITH_PYTHON
00058     if(m_proxy) {
00059         BGE_PROXY_REF(m_proxy)= NULL;
00060         Py_DECREF(m_proxy);         /* Remove own reference, python may still have 1 */
00061     }
00062 //  assert(ob_refcnt==0);
00063 #endif
00064 }
00065 
00066 PyObjectPlus::PyObjectPlus() : SG_QList()               // constructor
00067 {
00068 #ifdef WITH_PYTHON
00069     m_proxy= NULL;
00070 #endif
00071 };
00072 
00073 void PyObjectPlus::ProcessReplica()
00074 {
00075 #ifdef WITH_PYTHON
00076     /* Clear the proxy, will be created again if needed with GetProxy()
00077      * otherwise the PyObject will point to the wrong reference */
00078     m_proxy= NULL;
00079 #endif
00080 }
00081 
00082 /* Sometimes we might want to manually invalidate a BGE type even if
00083  * it hasnt been released by the BGE, say for example when an object
00084  * is removed from a scene, accessing it may cause problems.
00085  *
00086  * In this case the current proxy is made invalid, disowned,
00087  * and will raise an error on access. However if python can get access
00088  * to this class again it will make a new proxy and work as expected.
00089  */
00090 void PyObjectPlus::InvalidateProxy()        // check typename of each parent
00091 {
00092 #ifdef WITH_PYTHON
00093     if(m_proxy) {
00094         BGE_PROXY_REF(m_proxy)=NULL;
00095         Py_DECREF(m_proxy);
00096         m_proxy= NULL;
00097     }
00098 #endif
00099 }
00100 
00101 
00102 #ifdef WITH_PYTHON
00103 
00104 /*------------------------------
00105  * PyObjectPlus Type        -- Every class, even the abstract one should have a Type
00106 ------------------------------*/
00107 
00108 
00109 PyTypeObject PyObjectPlus::Type = {
00110     PyVarObject_HEAD_INIT(NULL, 0)
00111     "PyObjectPlus",                 /*tp_name*/
00112     sizeof(PyObjectPlus_Proxy),     /*tp_basicsize*/
00113     0,                              /*tp_itemsize*/
00114     /* methods */
00115     py_base_dealloc,                /* tp_dealloc */
00116     0,                              /* printfunc tp_print; */
00117     0,                              /* getattrfunc tp_getattr; */
00118     0,                              /* setattrfunc tp_setattr; */
00119     0,                              /* tp_compare */ /* DEPRECATED in python 3.0! */
00120     py_base_repr,                   /* tp_repr */
00121     0,0,0,0,0,0,0,0,0,              /* Method suites for standard classes */
00122     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,/* long tp_flags; */
00123     0,0,0,0,
00124     /* weak reference enabler */
00125 #ifdef USE_WEAKREFS
00126     offsetof(PyObjectPlus_Proxy, in_weakreflist),   /* long tp_weaklistoffset; */
00127 #else
00128     0,
00129 #endif
00130     0,0,
00131     Methods,
00132     0,
00133     0,
00134     NULL // no subtype
00135 };
00136 
00137 PyObject *PyObjectPlus::py_base_repr(PyObject *self)            // This should be the entry in Type.
00138 {
00139     PyObjectPlus *self_plus= BGE_PROXY_REF(self);
00140     if(self_plus==NULL) {
00141         PyErr_SetString(PyExc_SystemError, BGE_PROXY_ERROR_MSG);
00142         return NULL;
00143     }
00144     return self_plus->py_repr();  
00145 }
00146 
00147 
00148 PyObject * PyObjectPlus::py_base_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
00149 {
00150     PyTypeObject *base_type;
00151     PyObjectPlus_Proxy *base = NULL;
00152 
00153     if (!PyArg_ParseTuple(args, "O:Base PyObjectPlus", &base))
00154         return NULL;
00155 
00156     /* the 'base' PyObject may be subclassed (multiple times even)
00157      * we need to find the first C++ defined class to check 'type'
00158      * is a subclass of the base arguments type.
00159      *
00160      * This way we can share one tp_new function for every PyObjectPlus
00161      *
00162      * eg.
00163      *
00164      * # CustomOb is called 'type' in this C code
00165      * class CustomOb(GameTypes.KX_GameObject):
00166      *     pass
00167      *
00168      * # this calls py_base_new(...), the type of 'CustomOb' is checked to be a subclass of the 'cont.owner' type
00169      * ob = CustomOb(cont.owner)
00170      *
00171      * */
00172     base_type= Py_TYPE(base);
00173     while(base_type && !BGE_PROXY_CHECK_TYPE(base_type))
00174         base_type= base_type->tp_base;
00175 
00176     if(base_type==NULL || !BGE_PROXY_CHECK_TYPE(base_type)) {
00177         PyErr_SetString(PyExc_TypeError, "can't subclass from a blender game type because the argument given is not a game class or subclass");
00178         return NULL;
00179     }
00180 
00181     /* use base_type rather than Py_TYPE(base) because we could already be subtyped */
00182     if(!PyType_IsSubtype(type, base_type)) {
00183         PyErr_Format(PyExc_TypeError, "can't subclass blender game type <%s> from <%s> because it is not a subclass", base_type->tp_name, type->tp_name);
00184         return NULL;
00185     }
00186 
00187     /* invalidate the existing base and return a new subclassed one,
00188      * this is a bit dodgy in that it also attaches its self to the existing object
00189      * which is not really 'correct' python OO but for our use its OK. */
00190 
00191     PyObjectPlus_Proxy *ret = (PyObjectPlus_Proxy *) type->tp_alloc(type, 0); /* starts with 1 ref, used for the return ref' */
00192     ret->ref= base->ref;
00193     ret->ptr= base->ptr;
00194     ret->py_owns= base->py_owns;
00195     ret->py_ref = base->py_ref;
00196 
00197     if (ret->py_ref) {
00198         base->ref= NULL;        /* invalidate! disallow further access */
00199         base->ptr = NULL;
00200         if (ret->ref)
00201             ret->ref->m_proxy= NULL;
00202         /* 'base' may be free'd after this func finished but not necessarily
00203          * there is no reference to the BGE data now so it will throw an error on access */
00204         Py_DECREF(base);
00205         if (ret->ref) {
00206             ret->ref->m_proxy= (PyObject *)ret; /* no need to add a ref because one is added when creating. */
00207             Py_INCREF(ret); /* we return a new ref but m_proxy holds a ref so we need to add one */
00208         }
00209     } else {
00210         // generic structures don't hold a reference to this proxy, so don't increment ref count
00211         if (ret->py_owns)
00212             // but if the proxy owns the structure, there can be only one owner
00213             base->ptr= NULL;
00214     }
00215 
00216     return (PyObject *)ret;
00217 }
00218 
00222 void PyObjectPlus::py_base_dealloc(PyObject *self)              // python wrapper
00223 {
00224 #ifdef USE_WEAKREFS
00225     if (BGE_PROXY_WKREF(self) != NULL)
00226         PyObject_ClearWeakRefs((PyObject *) self);
00227 #endif
00228 
00229     if (BGE_PROXY_PYREF(self)) {
00230         PyObjectPlus *self_plus= BGE_PROXY_REF(self);
00231         if(self_plus) {
00232             if(BGE_PROXY_PYOWNS(self)) { /* Does python own this?, then delete it  */
00233                 self_plus->m_proxy = NULL; /* Need this to stop ~PyObjectPlus from decrefing m_proxy otherwise its decref'd twice and py-debug crashes */
00234                 delete self_plus;
00235             }
00236             BGE_PROXY_REF(self)= NULL; // not really needed
00237         }
00238         // the generic pointer is not deleted directly, only through self_plus
00239         BGE_PROXY_PTR(self)= NULL; // not really needed
00240     } else {
00241         void *ptr= BGE_PROXY_PTR(self);
00242         if(ptr) {
00243             if(BGE_PROXY_PYOWNS(self)) { /* Does python own this?, then delete it  */
00244                 // generic structure owned by python MUST be created though MEM_alloc
00245                 MEM_freeN(ptr);
00246             }
00247             BGE_PROXY_PTR(self)= NULL; // not really needed
00248         }
00249     }
00250 #if 0
00251     /* is ok normally but not for subtyping, use tp_free instead. */
00252     PyObject_DEL( self );
00253 #else
00254     Py_TYPE(self)->tp_free(self);
00255 #endif
00256 };
00257 
00258 /*------------------------------
00259  * PyObjectPlus Methods     -- Every class, even the abstract one should have a Methods
00260 ------------------------------*/
00261 PyMethodDef PyObjectPlus::Methods[] = {
00262   {NULL, NULL}      /* Sentinel */
00263 };
00264 
00265 #define attr_invalid (&(PyObjectPlus::Attributes[0]))
00266 PyAttributeDef PyObjectPlus::Attributes[] = {
00267     KX_PYATTRIBUTE_RO_FUNCTION("invalid",       PyObjectPlus, pyattr_get_invalid),
00268     {NULL} //Sentinel
00269 };
00270 
00271 
00272 
00273 PyObject* PyObjectPlus::pyattr_get_invalid(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
00274 {
00275     return PyBool_FromLong(self_v ? 0:1);
00276 }
00277 
00278 /* note, this is called as a python 'getset, where the PyAttributeDef is the closure */
00279 PyObject *PyObjectPlus::py_get_attrdef(PyObject *self_py, const PyAttributeDef *attrdef)
00280 {
00281     PyObjectPlus *ref= (BGE_PROXY_REF(self_py));
00282     char* ptr = (attrdef->m_usePtr) ? (char*)BGE_PROXY_PTR(self_py) : (char*)ref;
00283     if(ptr == NULL || (BGE_PROXY_PYREF(self_py) && (ref==NULL || !ref->py_is_valid()))) {
00284         if(attrdef == attr_invalid)
00285             Py_RETURN_TRUE; // dont bother running the function
00286 
00287         PyErr_SetString(PyExc_SystemError, BGE_PROXY_ERROR_MSG);
00288         return NULL;
00289     }
00290 
00291     if (attrdef->m_type == KX_PYATTRIBUTE_TYPE_DUMMY)
00292     {
00293         // fake attribute, ignore
00294         return NULL;
00295     }
00296     if (attrdef->m_type == KX_PYATTRIBUTE_TYPE_FUNCTION)
00297     {
00298         // the attribute has no field correspondance, handover processing to function.
00299         if (attrdef->m_getFunction == NULL)
00300             return NULL;
00301         return (*attrdef->m_getFunction)(ptr, attrdef);
00302     }
00303     ptr += attrdef->m_offset;
00304     if (attrdef->m_length > 1)
00305     {
00306         PyObject* resultlist = PyList_New(attrdef->m_length);
00307         for (unsigned int i=0; i<attrdef->m_length; i++)
00308         {
00309             switch (attrdef->m_type) {
00310             case KX_PYATTRIBUTE_TYPE_BOOL:
00311                 {
00312                     bool *val = reinterpret_cast<bool*>(ptr);
00313                     ptr += sizeof(bool);
00314                     PyList_SET_ITEM(resultlist,i,PyLong_FromSsize_t(*val));
00315                     break;
00316                 }
00317             case KX_PYATTRIBUTE_TYPE_SHORT:
00318                 {
00319                     short int *val = reinterpret_cast<short int*>(ptr);
00320                     ptr += sizeof(short int);
00321                     PyList_SET_ITEM(resultlist,i,PyLong_FromSsize_t(*val));
00322                     break;
00323                 }
00324             case KX_PYATTRIBUTE_TYPE_ENUM:
00325                 // enum are like int, just make sure the field size is the same
00326                 if (sizeof(int) != attrdef->m_size)
00327                 {
00328                     Py_DECREF(resultlist);
00329                     return NULL;
00330                 }
00331                 // walkthrough
00332             case KX_PYATTRIBUTE_TYPE_INT:
00333                 {
00334                     int *val = reinterpret_cast<int*>(ptr);
00335                     ptr += sizeof(int);
00336                     PyList_SET_ITEM(resultlist,i,PyLong_FromSsize_t(*val));
00337                     break;
00338                 }
00339             case KX_PYATTRIBUTE_TYPE_FLOAT:
00340                 {
00341                     float *val = reinterpret_cast<float*>(ptr);
00342                     ptr += sizeof(float);
00343                     PyList_SET_ITEM(resultlist,i,PyFloat_FromDouble(*val));
00344                     break;
00345                 }
00346             default:
00347                 // no support for array of complex data
00348                 Py_DECREF(resultlist);
00349                 return NULL;
00350             }
00351         }
00352         return resultlist;
00353     }
00354     else
00355     {
00356         switch (attrdef->m_type) {
00357         case KX_PYATTRIBUTE_TYPE_FLAG:
00358             {
00359                 bool bval;
00360                 switch (attrdef->m_size) {
00361                 case 1:
00362                     {
00363                         unsigned char *val = reinterpret_cast<unsigned char*>(ptr);
00364                         bval = (*val & attrdef->m_imin);
00365                         break;
00366                     }
00367                 case 2:
00368                     {
00369                         unsigned short *val = reinterpret_cast<unsigned short*>(ptr);
00370                         bval = (*val & attrdef->m_imin);
00371                         break;
00372                     }
00373                 case 4:
00374                     {
00375                         unsigned int *val = reinterpret_cast<unsigned int*>(ptr);
00376                         bval = (*val & attrdef->m_imin);
00377                         break;
00378                     }
00379                 default:
00380                     return NULL;
00381                 }
00382                 if (attrdef->m_imax)
00383                     bval = !bval;
00384                 return PyLong_FromSsize_t(bval);
00385             }
00386         case KX_PYATTRIBUTE_TYPE_BOOL:
00387             {
00388                 bool *val = reinterpret_cast<bool*>(ptr);
00389                 return PyLong_FromSsize_t(*val);
00390             }
00391         case KX_PYATTRIBUTE_TYPE_SHORT:
00392             {
00393                 short int *val = reinterpret_cast<short int*>(ptr);
00394                 return PyLong_FromSsize_t(*val);
00395             }
00396         case KX_PYATTRIBUTE_TYPE_ENUM:
00397             // enum are like int, just make sure the field size is the same
00398             if (sizeof(int) != attrdef->m_size)
00399             {
00400                 return NULL;
00401             }
00402             // walkthrough
00403         case KX_PYATTRIBUTE_TYPE_INT:
00404             {
00405                 int *val = reinterpret_cast<int*>(ptr);
00406                 return PyLong_FromSsize_t(*val);
00407             }
00408         case KX_PYATTRIBUTE_TYPE_FLOAT:
00409             {
00410                 float *val = reinterpret_cast<float*>(ptr);
00411                 if (attrdef->m_imin == 0) {
00412                     if (attrdef->m_imax == 0) {
00413                         return PyFloat_FromDouble(*val);
00414                     } else {
00415                         // vector, verify size
00416                         if (attrdef->m_size != attrdef->m_imax*sizeof(float)) 
00417                         {
00418                             return NULL;
00419                         }
00420 #ifdef USE_MATHUTILS
00421                         return Vector_CreatePyObject(val, attrdef->m_imax, Py_NEW, NULL);
00422 #else
00423                         PyObject* resultlist = PyList_New(attrdef->m_imax);
00424                         for (unsigned int i=0; i<attrdef->m_imax; i++)
00425                         {
00426                             PyList_SET_ITEM(resultlist,i,PyFloat_FromDouble(val[i]));
00427                         }
00428                         return resultlist;
00429 #endif
00430                     }
00431                 } else {
00432                     // matrix case
00433                     if (attrdef->m_size != attrdef->m_imax*attrdef->m_imin*sizeof(float)) 
00434                     {
00435                         return NULL;
00436                     }
00437 #ifdef USE_MATHUTILS
00438                     return Matrix_CreatePyObject(val, attrdef->m_imin, attrdef->m_imax, Py_WRAP, NULL);
00439 #else
00440                     PyObject* collist = PyList_New(attrdef->m_imin);
00441                     for (unsigned int i=0; i<attrdef->m_imin; i++)
00442                     {
00443                         PyObject* col = PyList_New(attrdef->m_imax);
00444                         for (unsigned int j=0; j<attrdef->m_imax; j++)
00445                         {
00446                             PyList_SET_ITEM(col,j,PyFloat_FromDouble(val[j]));
00447                         }
00448                         PyList_SET_ITEM(collist,i,col);
00449                         val += attrdef->m_imax;
00450                     }
00451                     return collist;
00452 #endif
00453                 }
00454             }
00455         case KX_PYATTRIBUTE_TYPE_VECTOR:
00456             {
00457                 MT_Vector3 *val = reinterpret_cast<MT_Vector3*>(ptr);
00458 #ifdef USE_MATHUTILS
00459                 float fval[3]= {(*val)[0], (*val)[1], (*val)[2]};
00460                 return Vector_CreatePyObject(fval, 3, Py_NEW, NULL);
00461 #else
00462                 PyObject* resultlist = PyList_New(3);
00463                 for (unsigned int i=0; i<3; i++)
00464                 {
00465                     PyList_SET_ITEM(resultlist,i,PyFloat_FromDouble((*val)[i]));
00466                 }
00467                 return resultlist;
00468 #endif
00469             }
00470         case KX_PYATTRIBUTE_TYPE_STRING:
00471             {
00472                 STR_String *val = reinterpret_cast<STR_String*>(ptr);
00473                 return PyUnicode_From_STR_String(*val);
00474             }
00475         case KX_PYATTRIBUTE_TYPE_CHAR:
00476             {
00477                 return PyUnicode_FromString(ptr);
00478             }
00479         default:
00480             return NULL;
00481         }
00482     }
00483 }
00484 
00485 
00486 static bool py_check_attr_float(float *var, PyObject *value, const PyAttributeDef *attrdef)
00487 {
00488     double val = PyFloat_AsDouble(value);
00489     if (val == -1.0 && PyErr_Occurred())
00490     {
00491         PyErr_Format(PyExc_TypeError, "expected float value for attribute \"%s\"", attrdef->m_name);
00492         return false;
00493     }
00494     if (attrdef->m_clamp)
00495     {
00496         if (val < attrdef->m_fmin)
00497             val = attrdef->m_fmin;
00498         else if (val > attrdef->m_fmax)
00499             val = attrdef->m_fmax;
00500     }
00501     else if (val < attrdef->m_fmin || val > attrdef->m_fmax)
00502     {
00503         PyErr_Format(PyExc_ValueError, "value out of range for attribute \"%s\"", attrdef->m_name);
00504         return false;
00505     }
00506     *var = (float)val;
00507     return true;
00508 }
00509 
00510 /* note, this is called as a python getset */
00511 int PyObjectPlus::py_set_attrdef(PyObject *self_py, PyObject *value, const PyAttributeDef *attrdef)
00512 {
00513     PyObjectPlus *ref= (BGE_PROXY_REF(self_py));
00514     char* ptr = (attrdef->m_usePtr) ? (char*)BGE_PROXY_PTR(self_py) : (char*)ref;
00515     if(ref==NULL || !ref->py_is_valid() || ptr==NULL) {
00516         PyErr_SetString(PyExc_SystemError, BGE_PROXY_ERROR_MSG);
00517         return PY_SET_ATTR_FAIL;
00518     }
00519 
00520     void *undoBuffer = NULL;
00521     void *sourceBuffer = NULL;
00522     size_t bufferSize = 0;
00523     PyObject *item = NULL;  // to store object that must be dereferenced in case of error
00524     PyObject *list = NULL;  // to store object that must be dereferenced in case of error
00525     
00526     ptr += attrdef->m_offset;
00527     if (attrdef->m_length > 1)
00528     {
00529         if (!PySequence_Check(value)) 
00530         {
00531             PyErr_Format(PyExc_TypeError, "expected a sequence for attribute \"%s\"", attrdef->m_name);
00532             return PY_SET_ATTR_FAIL;
00533         }
00534         if (PySequence_Size(value) != attrdef->m_length)
00535         {
00536             PyErr_Format(PyExc_TypeError, "incorrect number of elements in sequence for attribute \"%s\"", attrdef->m_name);
00537             return PY_SET_ATTR_FAIL;
00538         }
00539         switch (attrdef->m_type) 
00540         {
00541         case KX_PYATTRIBUTE_TYPE_FUNCTION:
00542             if (attrdef->m_setFunction == NULL) 
00543             {
00544                 PyErr_Format(PyExc_AttributeError, "function attribute without function for attribute \"%s\", report to blender.org", attrdef->m_name);
00545                 return PY_SET_ATTR_FAIL;
00546             }
00547             return (*attrdef->m_setFunction)(ref, attrdef, value);
00548         case KX_PYATTRIBUTE_TYPE_BOOL:
00549             bufferSize = sizeof(bool);
00550             break;
00551         case KX_PYATTRIBUTE_TYPE_SHORT:
00552             bufferSize = sizeof(short int);
00553             break;
00554         case KX_PYATTRIBUTE_TYPE_ENUM:
00555         case KX_PYATTRIBUTE_TYPE_INT:
00556             bufferSize = sizeof(int);
00557             break;
00558         case KX_PYATTRIBUTE_TYPE_FLOAT:
00559             bufferSize = sizeof(float);
00560             break;
00561         default:
00562             // should not happen
00563             PyErr_Format(PyExc_AttributeError, "Unsupported attribute type for attribute \"%s\", report to blender.org", attrdef->m_name);
00564             return PY_SET_ATTR_FAIL;
00565         }
00566         // let's implement a smart undo method
00567         bufferSize *= attrdef->m_length;
00568         undoBuffer = malloc(bufferSize);
00569         sourceBuffer = ptr;
00570         if (undoBuffer)
00571         {
00572             memcpy(undoBuffer, sourceBuffer, bufferSize);
00573         }
00574         for (int i=0; i<attrdef->m_length; i++)
00575         {
00576             item = PySequence_GetItem(value, i); /* new ref */
00577             switch (attrdef->m_type) 
00578             {
00579             case KX_PYATTRIBUTE_TYPE_BOOL:
00580                 {
00581                     bool *var = reinterpret_cast<bool*>(ptr);
00582                     ptr += sizeof(bool);
00583                     if (PyLong_Check(item)) 
00584                     {
00585                         *var = (PyLong_AsSsize_t(item) != 0);
00586                     } 
00587                     else if (PyBool_Check(item))
00588                     {
00589                         *var = (item == Py_True);
00590                     }
00591                     else
00592                     {
00593                         PyErr_Format(PyExc_TypeError, "expected an integer or a bool for attribute \"%s\"", attrdef->m_name);
00594                         goto UNDO_AND_ERROR;
00595                     }
00596                     break;
00597                 }
00598             case KX_PYATTRIBUTE_TYPE_SHORT:
00599                 {
00600                     short int *var = reinterpret_cast<short int*>(ptr);
00601                     ptr += sizeof(short int);
00602                     if (PyLong_Check(item)) 
00603                     {
00604                         long val = PyLong_AsSsize_t(item);
00605                         if (attrdef->m_clamp)
00606                         {
00607                             if (val < attrdef->m_imin)
00608                                 val = attrdef->m_imin;
00609                             else if (val > attrdef->m_imax)
00610                                 val = attrdef->m_imax;
00611                         }
00612                         else if (val < attrdef->m_imin || val > attrdef->m_imax)
00613                         {
00614                             PyErr_Format(PyExc_ValueError, "item value out of range for attribute \"%s\"", attrdef->m_name);
00615                             goto UNDO_AND_ERROR;
00616                         }
00617                         *var = (short int)val;
00618                     }
00619                     else
00620                     {
00621                         PyErr_Format(PyExc_TypeError, "expected an integer for attribute \"%s\"", attrdef->m_name);
00622                         goto UNDO_AND_ERROR;
00623                     }
00624                     break;
00625                 }
00626             case KX_PYATTRIBUTE_TYPE_ENUM:
00627                 // enum are equivalent to int, just make sure that the field size matches:
00628                 if (sizeof(int) != attrdef->m_size)
00629                 {
00630                     PyErr_Format(PyExc_AttributeError, "Size check error for attribute, \"%s\", report to blender.org", attrdef->m_name);
00631                     goto UNDO_AND_ERROR;
00632                 }
00633                 // walkthrough
00634             case KX_PYATTRIBUTE_TYPE_INT:
00635                 {
00636                     int *var = reinterpret_cast<int*>(ptr);
00637                     ptr += sizeof(int);
00638                     if (PyLong_Check(item)) 
00639                     {
00640                         long val = PyLong_AsSsize_t(item);
00641                         if (attrdef->m_clamp)
00642                         {
00643                             if (val < attrdef->m_imin)
00644                                 val = attrdef->m_imin;
00645                             else if (val > attrdef->m_imax)
00646                                 val = attrdef->m_imax;
00647                         }
00648                         else if (val < attrdef->m_imin || val > attrdef->m_imax)
00649                         {
00650                             PyErr_Format(PyExc_ValueError, "item value out of range for attribute \"%s\"", attrdef->m_name);
00651                             goto UNDO_AND_ERROR;
00652                         }
00653                         *var = (int)val;
00654                     }
00655                     else
00656                     {
00657                         PyErr_Format(PyExc_TypeError, "expected an integer for attribute \"%s\"", attrdef->m_name);
00658                         goto UNDO_AND_ERROR;
00659                     }
00660                     break;
00661                 }
00662             case KX_PYATTRIBUTE_TYPE_FLOAT:
00663                 {
00664                     float *var = reinterpret_cast<float*>(ptr);
00665                     ptr += sizeof(float);
00666                     double val = PyFloat_AsDouble(item);
00667                     if (val == -1.0 && PyErr_Occurred())
00668                     {
00669                         PyErr_Format(PyExc_TypeError, "expected a float for attribute \"%s\"", attrdef->m_name);
00670                         goto UNDO_AND_ERROR;
00671                     }
00672                     else if (attrdef->m_clamp) 
00673                     {
00674                         if (val < attrdef->m_fmin)
00675                             val = attrdef->m_fmin;
00676                         else if (val > attrdef->m_fmax)
00677                             val = attrdef->m_fmax;
00678                     }
00679                     else if (val < attrdef->m_fmin || val > attrdef->m_fmax)
00680                     {
00681                         PyErr_Format(PyExc_ValueError, "item value out of range for attribute \"%s\"", attrdef->m_name);
00682                         goto UNDO_AND_ERROR;
00683                     }
00684                     *var = (float)val;
00685                     break;
00686                 }
00687             default:
00688                 // should not happen
00689                 PyErr_Format(PyExc_AttributeError, "type check error for attribute \"%s\", report to blender.org", attrdef->m_name);
00690                 goto UNDO_AND_ERROR;
00691             }
00692             // finished using item, release
00693             Py_DECREF(item);
00694             item = NULL;
00695         }
00696         // no error, call check function if any
00697         if (attrdef->m_checkFunction != NULL)
00698         {
00699             if ((*attrdef->m_checkFunction)(ref, attrdef) != 0)
00700             {
00701                 // if the checing function didnt set an error then set a generic one here so we dont set an error with no exception
00702                 if (PyErr_Occurred()==0)
00703                     PyErr_Format(PyExc_AttributeError, "type check error for attribute \"%s\", reasion unknown", attrdef->m_name);
00704                 
00705                 // post check returned an error, restore values
00706             UNDO_AND_ERROR:
00707                 if (undoBuffer)
00708                 {
00709                     memcpy(sourceBuffer, undoBuffer, bufferSize);
00710                     free(undoBuffer);
00711                 }
00712                 if (item)
00713                     Py_DECREF(item);
00714                 return PY_SET_ATTR_FAIL;
00715             }
00716         }
00717         if (undoBuffer)
00718             free(undoBuffer);
00719         return PY_SET_ATTR_SUCCESS;
00720     }
00721     else    // simple attribute value
00722     {
00723         if (attrdef->m_type == KX_PYATTRIBUTE_TYPE_FUNCTION)
00724         {
00725             if (attrdef->m_setFunction == NULL)
00726             {
00727                 PyErr_Format(PyExc_AttributeError, "function attribute without function \"%s\", report to blender.org", attrdef->m_name);
00728                 return PY_SET_ATTR_FAIL;
00729             }
00730             return (*attrdef->m_setFunction)(ref, attrdef, value);
00731         }
00732         if (attrdef->m_checkFunction != NULL || attrdef->m_type == KX_PYATTRIBUTE_TYPE_VECTOR)
00733         {
00734             // post check function is provided, prepare undo buffer
00735             sourceBuffer = ptr;
00736             switch (attrdef->m_type) 
00737             {
00738             case KX_PYATTRIBUTE_TYPE_BOOL:
00739                 bufferSize = sizeof(bool);
00740                 break;
00741             case KX_PYATTRIBUTE_TYPE_SHORT:
00742                 bufferSize = sizeof(short);
00743                 break;
00744             case KX_PYATTRIBUTE_TYPE_ENUM:
00745             case KX_PYATTRIBUTE_TYPE_FLAG:
00746             case KX_PYATTRIBUTE_TYPE_CHAR:
00747                 bufferSize = attrdef->m_size;
00748                 break;
00749             case KX_PYATTRIBUTE_TYPE_INT:
00750                 bufferSize = sizeof(int);
00751                 break;
00752             case KX_PYATTRIBUTE_TYPE_FLOAT:
00753                 bufferSize = sizeof(float);
00754                 if (attrdef->m_imax)
00755                     bufferSize *= attrdef->m_imax;
00756                 if (attrdef->m_imin)
00757                     bufferSize *= attrdef->m_imin;
00758                 break;
00759             case KX_PYATTRIBUTE_TYPE_STRING:
00760                 sourceBuffer = reinterpret_cast<STR_String*>(ptr)->Ptr();
00761                 if (sourceBuffer)
00762                     bufferSize = strlen(reinterpret_cast<char*>(sourceBuffer))+1;
00763                 break;
00764             case KX_PYATTRIBUTE_TYPE_VECTOR:
00765                 bufferSize = sizeof(MT_Vector3);
00766                 break;
00767             default:
00768                 PyErr_Format(PyExc_AttributeError, "unknown type for attribute \"%s\", report to blender.org", attrdef->m_name);
00769                 return PY_SET_ATTR_FAIL;
00770             }
00771             if (bufferSize)
00772             {
00773                 undoBuffer = malloc(bufferSize);
00774                 if (undoBuffer)
00775                 {
00776                     memcpy(undoBuffer, sourceBuffer, bufferSize);
00777                 }
00778             }
00779         }
00780             
00781         switch (attrdef->m_type) 
00782         {
00783         case KX_PYATTRIBUTE_TYPE_BOOL:
00784             {
00785                 bool *var = reinterpret_cast<bool*>(ptr);
00786                 if (PyLong_Check(value)) 
00787                 {
00788                     *var = (PyLong_AsSsize_t(value) != 0);
00789                 } 
00790                 else if (PyBool_Check(value))
00791                 {
00792                     *var = (value == Py_True);
00793                 }
00794                 else
00795                 {
00796                     PyErr_Format(PyExc_TypeError, "expected an integer or a bool for attribute \"%s\"", attrdef->m_name);
00797                     goto FREE_AND_ERROR;
00798                 }
00799                 break;
00800             }
00801         case KX_PYATTRIBUTE_TYPE_FLAG:
00802             {
00803                 bool bval;
00804                 if (PyLong_Check(value)) 
00805                 {
00806                     bval = (PyLong_AsSsize_t(value) != 0);
00807                 } 
00808                 else if (PyBool_Check(value))
00809                 {
00810                     bval = (value == Py_True);
00811                 }
00812                 else
00813                 {
00814                     PyErr_Format(PyExc_TypeError, "expected an integer or a bool for attribute \"%s\"", attrdef->m_name);
00815                     goto FREE_AND_ERROR;
00816                 }
00817                 if (attrdef->m_imax)
00818                     bval = !bval;
00819                 switch (attrdef->m_size) {
00820                 case 1:
00821                     {
00822                         unsigned char *val = reinterpret_cast<unsigned char*>(ptr);
00823                         *val = (*val & ~attrdef->m_imin) | ((bval)?attrdef->m_imin:0);
00824                         break;
00825                     }
00826                 case 2:
00827                     {
00828                         unsigned short *val = reinterpret_cast<unsigned short*>(ptr);
00829                         *val = (*val & ~attrdef->m_imin) | ((bval)?attrdef->m_imin:0);
00830                         break;
00831                     }
00832                 case 4:
00833                     {
00834                         unsigned int *val = reinterpret_cast<unsigned int*>(ptr);
00835                         *val = (*val & ~attrdef->m_imin) | ((bval)?attrdef->m_imin:0);
00836                         break;
00837                     }
00838                 default:
00839                     PyErr_Format(PyExc_TypeError, "internal error: unsupported flag field \"%s\"", attrdef->m_name);
00840                     goto FREE_AND_ERROR;
00841                 }
00842                 break;
00843             }
00844         case KX_PYATTRIBUTE_TYPE_SHORT:
00845             {
00846                 short int *var = reinterpret_cast<short int*>(ptr);
00847                 if (PyLong_Check(value)) 
00848                 {
00849                     long val = PyLong_AsSsize_t(value);
00850                     if (attrdef->m_clamp)
00851                     {
00852                         if (val < attrdef->m_imin)
00853                             val = attrdef->m_imin;
00854                         else if (val > attrdef->m_imax)
00855                             val = attrdef->m_imax;
00856                     }
00857                     else if (val < attrdef->m_imin || val > attrdef->m_imax)
00858                     {
00859                         PyErr_Format(PyExc_ValueError, "value out of range for attribute \"%s\"", attrdef->m_name);
00860                         goto FREE_AND_ERROR;
00861                     }
00862                     *var = (short int)val;
00863                 }
00864                 else
00865                 {
00866                     PyErr_Format(PyExc_TypeError, "expected an integer for attribute \"%s\"", attrdef->m_name);
00867                     goto FREE_AND_ERROR;
00868                 }
00869                 break;
00870             }
00871         case KX_PYATTRIBUTE_TYPE_ENUM:
00872             // enum are equivalent to int, just make sure that the field size matches:
00873             if (sizeof(int) != attrdef->m_size)
00874             {
00875                 PyErr_Format(PyExc_AttributeError, "attribute size check error for attribute \"%s\", report to blender.org", attrdef->m_name);
00876                 goto FREE_AND_ERROR;
00877             }
00878             // walkthrough
00879         case KX_PYATTRIBUTE_TYPE_INT:
00880             {
00881                 int *var = reinterpret_cast<int*>(ptr);
00882                 if (PyLong_Check(value)) 
00883                 {
00884                     long val = PyLong_AsSsize_t(value);
00885                     if (attrdef->m_clamp)
00886                     {
00887                         if (val < attrdef->m_imin)
00888                             val = attrdef->m_imin;
00889                         else if (val > attrdef->m_imax)
00890                             val = attrdef->m_imax;
00891                     }
00892                     else if (val < attrdef->m_imin || val > attrdef->m_imax)
00893                     {
00894                         PyErr_Format(PyExc_ValueError, "value out of range for attribute \"%s\"", attrdef->m_name);
00895                         goto FREE_AND_ERROR;
00896                     }
00897                     *var = (int)val;
00898                 }
00899                 else
00900                 {
00901                     PyErr_Format(PyExc_TypeError, "expected an integer for attribute \"%s\"", attrdef->m_name);
00902                     goto FREE_AND_ERROR;
00903                 }
00904                 break;
00905             }
00906         case KX_PYATTRIBUTE_TYPE_FLOAT:
00907             {
00908                 float *var = reinterpret_cast<float*>(ptr);
00909                 if (attrdef->m_imin != 0) 
00910                 {
00911                     if (attrdef->m_size != attrdef->m_imin*attrdef->m_imax*sizeof(float)) 
00912                     {
00913                         PyErr_Format(PyExc_TypeError, "internal error: incorrect field size for attribute \"%s\"", attrdef->m_name);
00914                         goto FREE_AND_ERROR;
00915                     }
00916                     if (!PySequence_Check(value) || PySequence_Size(value) != attrdef->m_imin) 
00917                     {
00918                         PyErr_Format(PyExc_TypeError, "expected a sequence of [%d][%d] floats for attribute \"%s\"", attrdef->m_imin, attrdef->m_imax, attrdef->m_name);
00919                         goto FREE_AND_ERROR;
00920                     }
00921                     for (int i=0; i<attrdef->m_imin; i++)
00922                     {
00923                         PyObject *list = PySequence_GetItem(value, i); /* new ref */
00924                         if (!PySequence_Check(list) || PySequence_Size(list) != attrdef->m_imax) 
00925                         {
00926                             PyErr_Format(PyExc_TypeError, "expected a sequence of [%d][%d] floats for attribute \"%s\"", attrdef->m_imin, attrdef->m_imax, attrdef->m_name);
00927                             goto RESTORE_AND_ERROR;
00928                         }
00929                         for (int j=0; j<attrdef->m_imax; j++)
00930                         {
00931                             item = PySequence_GetItem(list, j); /* new ref */
00932                             if (!py_check_attr_float(var, item, attrdef))
00933                             {
00934                                 PyErr_Format(PyExc_TypeError, "expected a sequence of [%d][%d] floats for attribute \"%s\"", attrdef->m_imin, attrdef->m_imax, attrdef->m_name);
00935                                 goto RESTORE_AND_ERROR;
00936                             }
00937                             Py_DECREF(item);
00938                             item = NULL;
00939                             ++var;
00940                         }
00941                         Py_DECREF(list);
00942                         list = NULL;
00943                     }
00944                 } 
00945                 else if (attrdef->m_imax != 0) 
00946                 {
00947                     if (attrdef->m_size != attrdef->m_imax*sizeof(float)) 
00948                     {
00949                         PyErr_Format(PyExc_TypeError, "internal error: incorrect field size for attribute \"%s\"", attrdef->m_name);
00950                         goto FREE_AND_ERROR;
00951                     }
00952                     if (!PySequence_Check(value) || PySequence_Size(value) != attrdef->m_imax) 
00953                     {
00954                         PyErr_Format(PyExc_TypeError, "expected a sequence of [%d] floats for attribute \"%s\"", attrdef->m_imax, attrdef->m_name);
00955                         goto FREE_AND_ERROR;
00956                     }
00957                     for (int i=0; i<attrdef->m_imax; i++)
00958                     {
00959                         item = PySequence_GetItem(value, i); /* new ref */
00960                         if (!py_check_attr_float(var, item, attrdef))
00961                         {
00962                             goto RESTORE_AND_ERROR;
00963                         }
00964                         Py_DECREF(item);
00965                         item = NULL;
00966                         ++var;
00967                     }
00968                 } 
00969                 else
00970                 {
00971                     if (!py_check_attr_float(var, value, attrdef))
00972                         goto FREE_AND_ERROR;
00973                 }
00974                 break;
00975             }
00976         case KX_PYATTRIBUTE_TYPE_VECTOR:
00977             {
00978                 if (!PySequence_Check(value) || PySequence_Size(value) != 3) 
00979                 {
00980                     PyErr_Format(PyExc_TypeError, "expected a sequence of 3 floats for attribute \"%s\"", attrdef->m_name);
00981                     goto FREE_AND_ERROR;
00982                 }
00983                 MT_Vector3 *var = reinterpret_cast<MT_Vector3*>(ptr);
00984                 for (int i=0; i<3; i++)
00985                 {
00986                     item = PySequence_GetItem(value, i); /* new ref */
00987                     double val = PyFloat_AsDouble(item);
00988                     Py_DECREF(item);
00989                     item = NULL;
00990                     if (val == -1.0 && PyErr_Occurred())
00991                     {
00992                         PyErr_Format(PyExc_TypeError, "expected a sequence of 3 floats for attribute \"%s\"", attrdef->m_name);
00993                         goto RESTORE_AND_ERROR;
00994                     }
00995                     else if (attrdef->m_clamp)
00996                     {
00997                         if (val < attrdef->m_fmin)
00998                             val = attrdef->m_fmin;
00999                         else if (val > attrdef->m_fmax)
01000                             val = attrdef->m_fmax;
01001                     }
01002                     else if (val < attrdef->m_fmin || val > attrdef->m_fmax)
01003                     {
01004                         PyErr_Format(PyExc_ValueError, "value out of range for attribute \"%s\"", attrdef->m_name);
01005                         goto RESTORE_AND_ERROR;
01006                     }
01007                     (*var)[i] = (MT_Scalar)val;
01008                 }
01009                 break;
01010             }
01011         case KX_PYATTRIBUTE_TYPE_CHAR:
01012             {
01013                 if (PyUnicode_Check(value)) 
01014                 {
01015                     Py_ssize_t val_size;
01016                     const char *val = _PyUnicode_AsStringAndSize(value, &val_size);
01017                     strncpy(ptr, val, attrdef->m_size);
01018                     ptr[attrdef->m_size-1] = 0;
01019                 }
01020                 else
01021                 {
01022                     PyErr_Format(PyExc_TypeError, "expected a string for attribute \"%s\"", attrdef->m_name);
01023                     goto FREE_AND_ERROR;
01024                 }
01025                 break;
01026             }
01027         case KX_PYATTRIBUTE_TYPE_STRING:
01028             {
01029                 STR_String *var = reinterpret_cast<STR_String*>(ptr);
01030                 if (PyUnicode_Check(value)) 
01031                 {
01032                     Py_ssize_t val_len;
01033                     const char *val = _PyUnicode_AsStringAndSize(value, &val_len); /* XXX, should be 'const' but we do a silly trick to have a shorter string */
01034                     if (attrdef->m_clamp)
01035                     {
01036                         if (val_len < attrdef->m_imin)
01037                         {
01038                             // can't increase the length of the string
01039                             PyErr_Format(PyExc_ValueError, "string length too short for attribute \"%s\"", attrdef->m_name);
01040                             goto FREE_AND_ERROR;
01041                         }
01042                         else if (val_len > attrdef->m_imax)
01043                         {
01044                             // trim the string
01045                             var->SetLength(attrdef->m_imax);
01046                             memcpy(var->Ptr(), val, attrdef->m_imax - 1);
01047                             break;
01048                         }
01049                     } else if (val_len < attrdef->m_imin || val_len > attrdef->m_imax)
01050                     {
01051                         PyErr_Format(PyExc_ValueError, "string length out of range for attribute \"%s\"", attrdef->m_name);
01052                         goto FREE_AND_ERROR;
01053                     }
01054                     *var = val;
01055                 }
01056                 else
01057                 {
01058                     PyErr_Format(PyExc_TypeError, "expected a string for attribute \"%s\"", attrdef->m_name);
01059                     goto FREE_AND_ERROR;
01060                 }
01061                 break;
01062             }
01063         default:
01064             // should not happen
01065             PyErr_Format(PyExc_AttributeError, "unknown type for attribute \"%s\", report to blender.org", attrdef->m_name);
01066             goto FREE_AND_ERROR;
01067         }
01068     }
01069     // check if post processing is needed
01070     if (attrdef->m_checkFunction != NULL)
01071     {
01072         if ((*attrdef->m_checkFunction)(ref, attrdef) != 0)
01073         {
01074             // restore value
01075         RESTORE_AND_ERROR:
01076             if (undoBuffer)
01077             {
01078                 if (attrdef->m_type == KX_PYATTRIBUTE_TYPE_STRING)
01079                 {
01080                     // special case for STR_String: restore the string
01081                     STR_String *var = reinterpret_cast<STR_String*>(ptr);
01082                     *var = reinterpret_cast<char*>(undoBuffer);
01083                 }
01084                 else
01085                 {
01086                     // other field type have direct values
01087                     memcpy(ptr, undoBuffer, bufferSize);
01088                 }
01089             }
01090         FREE_AND_ERROR:
01091             if (undoBuffer)
01092                 free(undoBuffer);
01093             if (list)
01094                 Py_DECREF(list);
01095             if (item)
01096                 Py_DECREF(item);
01097             return 1;
01098         }
01099     }
01100     if (undoBuffer)
01101         free(undoBuffer);
01102     return 0;   
01103 }
01104 
01105 
01106 
01107 /*------------------------------
01108  * PyObjectPlus repr        -- representations
01109 ------------------------------*/
01110 PyObject *PyObjectPlus::py_repr(void)
01111 {
01112     PyErr_SetString(PyExc_SystemError, "Representation not overridden by object.");  
01113     return NULL;
01114 }
01115 
01116 PyObject *PyObjectPlus::GetProxyPlus_Ext(PyObjectPlus *self, PyTypeObject *tp, void *ptr)
01117 {
01118     if (self->m_proxy==NULL)
01119     {
01120         self->m_proxy = reinterpret_cast<PyObject *>PyObject_NEW( PyObjectPlus_Proxy, tp);
01121         BGE_PROXY_PYOWNS(self->m_proxy) = false;
01122         BGE_PROXY_PYREF(self->m_proxy) = true;
01123 #ifdef USE_WEAKREFS
01124         BGE_PROXY_WKREF(self->m_proxy) = NULL;
01125 #endif
01126     }
01127     //PyObject_Print(self->m_proxy, stdout, 0);
01128     //printf("ref %d\n", self->m_proxy->ob_refcnt);
01129     
01130     BGE_PROXY_REF(self->m_proxy) = self; /* Its possible this was set to NULL, so set it back here */
01131     BGE_PROXY_PTR(self->m_proxy) = ptr;
01132     Py_INCREF(self->m_proxy); /* we own one, thos ones fore the return */
01133     return self->m_proxy;
01134 }
01135 
01136 PyObject *PyObjectPlus::NewProxyPlus_Ext(PyObjectPlus *self, PyTypeObject *tp, void *ptr, bool py_owns)
01137 {
01138     if (!self) 
01139     {
01140         // in case of proxy without reference to game object
01141         PyObject* proxy = reinterpret_cast<PyObject *>PyObject_NEW( PyObjectPlus_Proxy, tp);
01142         BGE_PROXY_PYREF(proxy) = false;
01143         BGE_PROXY_PYOWNS(proxy) = py_owns;
01144         BGE_PROXY_REF(proxy) = NULL; 
01145         BGE_PROXY_PTR(proxy) = ptr;
01146 #ifdef USE_WEAKREFS
01147         BGE_PROXY_WKREF(proxy) = NULL;
01148 #endif
01149         return proxy;
01150     }
01151     if (self->m_proxy)
01152     {
01153         if(py_owns)
01154         {   /* Free */
01155             BGE_PROXY_REF(self->m_proxy) = NULL;
01156             Py_DECREF(self->m_proxy);
01157             self->m_proxy= NULL;
01158         }
01159         else {
01160             Py_INCREF(self->m_proxy);
01161             return self->m_proxy;
01162         }
01163         
01164     }
01165     
01166     GetProxyPlus_Ext(self, tp, ptr);
01167     if(py_owns) {
01168         BGE_PROXY_PYOWNS(self->m_proxy) = py_owns;
01169         Py_DECREF(self->m_proxy); /* could avoid thrashing here but for now its ok */
01170     }
01171     return self->m_proxy;
01172 }
01173 
01174 PyObject *PyUnicode_From_STR_String(const STR_String& str)
01175 {
01176     return PyUnicode_FromStringAndSize(str.ReadPtr(), str.Length());
01177 }
01178 
01181 /* deprecation warning management */
01182 
01183 bool PyObjectPlus::m_ignore_deprecation_warnings(false);
01184 void PyObjectPlus::SetDeprecationWarnings(bool ignoreDeprecationWarnings)
01185 {
01186     m_ignore_deprecation_warnings = ignoreDeprecationWarnings;
01187 }
01188 
01189 void PyObjectPlus::ShowDeprecationWarning_func(const char* old_way,const char* new_way)
01190 {
01191     printf("Method %s is deprecated, please use %s instead.\n", old_way, new_way);
01192     PyC_LineSpit();
01193 }
01194 
01195 void PyObjectPlus::ClearDeprecationWarning()
01196 {
01197     WarnLink *wlink_next;
01198     WarnLink *wlink = GetDeprecationWarningLinkFirst();
01199     
01200     while(wlink)
01201     {
01202         wlink->warn_done= false; /* no need to NULL the link, its cleared before adding to the list next time round */
01203         wlink_next= reinterpret_cast<WarnLink *>(wlink->link);
01204         wlink->link= NULL;
01205         wlink= wlink_next;
01206     }
01207     NullDeprecationWarning();
01208 }
01209 
01210 WarnLink*       m_base_wlink_first= NULL;
01211 WarnLink*       m_base_wlink_last= NULL;
01212 
01213 WarnLink*       PyObjectPlus::GetDeprecationWarningLinkFirst(void) {return m_base_wlink_first;}
01214 WarnLink*       PyObjectPlus::GetDeprecationWarningLinkLast(void) {return m_base_wlink_last;}
01215 void            PyObjectPlus::SetDeprecationWarningFirst(WarnLink* wlink) {m_base_wlink_first= wlink;}
01216 void            PyObjectPlus::SetDeprecationWarningLinkLast(WarnLink* wlink) {m_base_wlink_last= wlink;}
01217 void            PyObjectPlus::NullDeprecationWarning() {m_base_wlink_first= m_base_wlink_last= NULL;}
01218 
01219 #endif // WITH_PYTHON