merge with 2.5 at r18679
[blender.git] / source / gameengine / Expressions / PyObjectPlus.cpp
1 /**
2  * $Id$
3  * ***** BEGIN GPL LICENSE BLOCK *****
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software Foundation,
17  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18  *
19  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
20  * All rights reserved.
21  *
22  * The Original Code is: all of this file.
23  *
24  * Contributor(s): none yet.
25  *
26  * ***** END GPL LICENSE BLOCK *****
27  */
28
29 #ifdef HAVE_CONFIG_H
30 #include <config.h>
31 #endif
32
33 #ifndef NO_EXP_PYTHON_EMBEDDING
34
35 /*------------------------------
36  * PyObjectPlus cpp
37  *
38  * C++ library routines for Crawl 3.2
39  *
40  * Derived from work by
41  * David Redish
42  * graduate student
43  * Computer Science Department 
44  * Carnegie Mellon University (CMU)
45  * Center for the Neural Basis of Cognition (CNBC) 
46  * http://www.python.org/doc/PyCPP.html
47  *
48 ------------------------------*/
49 #include <MT_assert.h>
50 #include "stdlib.h"
51 #include "PyObjectPlus.h"
52 #include "STR_String.h"
53 /*------------------------------
54  * PyObjectPlus Type            -- Every class, even the abstract one should have a Type
55 ------------------------------*/
56
57 PyTypeObject PyObjectPlus::Type = {
58         PyObject_HEAD_INIT(&PyType_Type)
59         0,                              /*ob_size*/
60         "PyObjectPlus",                 /*tp_name*/
61         sizeof(PyObjectPlus),           /*tp_basicsize*/
62         0,                              /*tp_itemsize*/
63         /* methods */
64         PyDestructor,                   /*tp_dealloc*/
65         0,                              /*tp_print*/
66         __getattr,                      /*tp_getattr*/
67         __setattr,                      /*tp_setattr*/
68         0,                              /*tp_compare*/
69         __repr,                         /*tp_repr*/
70         0,                              /*tp_as_number*/
71         0,                              /*tp_as_sequence*/
72         0,                              /*tp_as_mapping*/
73         0,                              /*tp_hash*/
74         0,                              /*tp_call */
75 };
76
77 PyObjectPlus::~PyObjectPlus()
78 {
79         if (ob_refcnt)
80         {
81                 _Py_ForgetReference(this);
82         }
83 //      assert(ob_refcnt==0);
84 }
85
86 PyObjectPlus::PyObjectPlus(PyTypeObject *T)                             // constructor
87 {
88         MT_assert(T != NULL);
89         this->ob_type = T; 
90         _Py_NewReference(this);
91 };
92   
93 /*------------------------------
94  * PyObjectPlus Methods         -- Every class, even the abstract one should have a Methods
95 ------------------------------*/
96 PyMethodDef PyObjectPlus::Methods[] = {
97   {"isA",                (PyCFunction) sPy_isA,                 METH_VARARGS},
98   {NULL, NULL}          /* Sentinel */
99 };
100
101 /*------------------------------
102  * PyObjectPlus Parents         -- Every class, even the abstract one should have parents
103 ------------------------------*/
104 PyParentObject PyObjectPlus::Parents[] = {&PyObjectPlus::Type, NULL};
105
106 /*------------------------------
107  * PyObjectPlus attributes      -- attributes
108 ------------------------------*/
109 PyObject *PyObjectPlus::_getattr(const STR_String& attr)
110 {
111         if (attr == "__doc__" && GetType()->tp_doc)
112                 return PyString_FromString(GetType()->tp_doc);
113
114   //if (streq(attr, "type"))
115   //  return Py_BuildValue("s", (*(GetParents()))->tp_name);
116
117   return Py_FindMethod(Methods, this, const_cast<char *>(attr.ReadPtr()));
118 }
119
120 int PyObjectPlus::_delattr(const STR_String& attr)
121 {
122         PyErr_SetString(PyExc_AttributeError, "attribute cant be deleted");
123         return 1;
124 }
125
126 int PyObjectPlus::_setattr(const STR_String& attr, PyObject *value)
127 {
128         //return PyObject::_setattr(attr,value);
129         //cerr << "Unknown attribute" << endl;
130         PyErr_SetString(PyExc_AttributeError, "attribute cant be set");
131         return 1;
132 }
133
134 PyObject *PyObjectPlus::_getattr_self(const PyAttributeDef attrlist[], void *self, const STR_String &attr)
135 {
136         const PyAttributeDef *attrdef;
137         for (attrdef=attrlist; attrdef->m_name != NULL; attrdef++)
138         {
139                 if (attr == attrdef->m_name) 
140                 {
141                         if (attrdef->m_type == KX_PYATTRIBUTE_TYPE_DUMMY)
142                         {
143                                 // fake attribute, ignore
144                                 return NULL;
145                         }
146                         char *ptr = reinterpret_cast<char*>(self)+attrdef->m_offset;
147                         if (attrdef->m_length > 1)
148                         {
149                                 PyObject* resultlist = PyList_New(attrdef->m_length);
150                                 for (int i=0; i<attrdef->m_length; i++)
151                                 {
152                                         switch (attrdef->m_type) {
153                                         case KX_PYATTRIBUTE_TYPE_BOOL:
154                                                 {
155                                                         bool *val = reinterpret_cast<bool*>(ptr);
156                                                         ptr += sizeof(bool);
157                                                         PyList_SetItem(resultlist,i,PyInt_FromLong(*val));
158                                                         break;
159                                                 }
160                                         case KX_PYATTRIBUTE_TYPE_SHORT:
161                                                 {
162                                                         short int *val = reinterpret_cast<short int*>(ptr);
163                                                         ptr += sizeof(short int);
164                                                         PyList_SetItem(resultlist,i,PyInt_FromLong(*val));
165                                                         break;
166                                                 }
167                                         case KX_PYATTRIBUTE_TYPE_ENUM:
168                                                 // enum are like int, just make sure the field size is the same
169                                                 if (sizeof(int) != attrdef->m_size)
170                                                 {
171                                                         Py_DECREF(resultlist);
172                                                         return NULL;
173                                                 }
174                                                 // walkthrough
175                                         case KX_PYATTRIBUTE_TYPE_INT:
176                                                 {
177                                                         int *val = reinterpret_cast<int*>(ptr);
178                                                         ptr += sizeof(int);
179                                                         PyList_SetItem(resultlist,i,PyInt_FromLong(*val));
180                                                         break;
181                                                 }
182                                         case KX_PYATTRIBUTE_TYPE_FLOAT:
183                                                 {
184                                                         float *val = reinterpret_cast<float*>(ptr);
185                                                         ptr += sizeof(float);
186                                                         PyList_SetItem(resultlist,i,PyFloat_FromDouble(*val));
187                                                         break;
188                                                 }
189                                         default:
190                                                 // no support for array of complex data
191                                                 Py_DECREF(resultlist);
192                                                 return NULL;
193                                         }
194                                 }
195                                 return resultlist;
196                         }
197                         else
198                         {
199                                 switch (attrdef->m_type) {
200                                 case KX_PYATTRIBUTE_TYPE_BOOL:
201                                         {
202                                                 bool *val = reinterpret_cast<bool*>(ptr);
203                                                 return PyInt_FromLong(*val);
204                                         }
205                                 case KX_PYATTRIBUTE_TYPE_SHORT:
206                                         {
207                                                 short int *val = reinterpret_cast<short int*>(ptr);
208                                                 return PyInt_FromLong(*val);
209                                         }
210                                 case KX_PYATTRIBUTE_TYPE_ENUM:
211                                         // enum are like int, just make sure the field size is the same
212                                         if (sizeof(int) != attrdef->m_size)
213                                         {
214                                                 return NULL;
215                                         }
216                                         // walkthrough
217                                 case KX_PYATTRIBUTE_TYPE_INT:
218                                         {
219                                                 int *val = reinterpret_cast<int*>(ptr);
220                                                 return PyInt_FromLong(*val);
221                                         }
222                                 case KX_PYATTRIBUTE_TYPE_FLOAT:
223                                         {
224                                                 float *val = reinterpret_cast<float*>(ptr);
225                                                 return PyFloat_FromDouble(*val);
226                                         }
227                                 case KX_PYATTRIBUTE_TYPE_STRING:
228                                         {
229                                                 STR_String *val = reinterpret_cast<STR_String*>(ptr);
230                                                 return PyString_FromString(*val);
231                                         }
232                                 default:
233                                         return NULL;
234                                 }
235                         }
236                 }
237         }
238         return NULL;
239 }
240
241 int PyObjectPlus::_setattr_self(const PyAttributeDef attrlist[], void *self, const STR_String &attr, PyObject *value)
242 {
243         const PyAttributeDef *attrdef;
244         void *undoBuffer = NULL;
245         void *sourceBuffer = NULL;
246         size_t bufferSize = 0;
247
248         for (attrdef=attrlist; attrdef->m_name != NULL; attrdef++)
249         {
250                 if (attr == attrdef->m_name) 
251                 {
252                         if (attrdef->m_access == KX_PYATTRIBUTE_RO ||
253                                 attrdef->m_type == KX_PYATTRIBUTE_TYPE_DUMMY)
254                         {
255                                 PyErr_SetString(PyExc_AttributeError, "property is read-only");
256                                 return 1;
257                         }
258                         char *ptr = reinterpret_cast<char*>(self)+attrdef->m_offset;
259                         if (attrdef->m_length > 1)
260                         {
261                                 if (!PySequence_Check(value)) 
262                                 {
263                                         PyErr_SetString(PyExc_TypeError, "expected a sequence");
264                                         return 1;
265                                 }
266                                 if (PySequence_Size(value) != attrdef->m_length)
267                                 {
268                                         PyErr_SetString(PyExc_TypeError, "incorrect number of elements in sequence");
269                                         return 1;
270                                 }
271                                 switch (attrdef->m_type) 
272                                 {
273                                 case KX_PYATTRIBUTE_TYPE_BOOL:
274                                         bufferSize = sizeof(bool);
275                                         break;
276                                 case KX_PYATTRIBUTE_TYPE_SHORT:
277                                         bufferSize = sizeof(short int);
278                                         break;
279                                 case KX_PYATTRIBUTE_TYPE_ENUM:
280                                 case KX_PYATTRIBUTE_TYPE_INT:
281                                         bufferSize = sizeof(int);
282                                         break;
283                                 case KX_PYATTRIBUTE_TYPE_FLOAT:
284                                         bufferSize = sizeof(float);
285                                         break;
286                                 default:
287                                         // should not happen
288                                         PyErr_SetString(PyExc_AttributeError, "Unsupported attribute type, report to blender.org");
289                                         return 1;
290                                 }
291                                 // let's implement a smart undo method
292                                 bufferSize *= attrdef->m_length;
293                                 undoBuffer = malloc(bufferSize);
294                                 sourceBuffer = ptr;
295                                 if (undoBuffer)
296                                 {
297                                         memcpy(undoBuffer, sourceBuffer, bufferSize);
298                                 }
299                                 for (int i=0; i<attrdef->m_length; i++)
300                                 {
301                                         PyObject *item = PySequence_GetItem(value, i); /* new ref */
302                                         // we can decrement the reference immediately, the reference count
303                                         // is at least 1 because the item is part of an array
304                                         Py_DECREF(item);
305                                         switch (attrdef->m_type) 
306                                         {
307                                         case KX_PYATTRIBUTE_TYPE_BOOL:
308                                                 {
309                                                         bool *var = reinterpret_cast<bool*>(ptr);
310                                                         ptr += sizeof(bool);
311                                                         if (PyInt_Check(item)) 
312                                                         {
313                                                                 *var = (PyInt_AsLong(item) != 0);
314                                                         } 
315                                                         else if (PyBool_Check(item))
316                                                         {
317                                                                 *var = (item == Py_True);
318                                                         }
319                                                         else
320                                                         {
321                                                                 PyErr_SetString(PyExc_TypeError, "expected an integer or a bool");
322                                                                 goto UNDO_AND_ERROR;
323                                                         }
324                                                         break;
325                                                 }
326                                         case KX_PYATTRIBUTE_TYPE_SHORT:
327                                                 {
328                                                         short int *var = reinterpret_cast<short int*>(ptr);
329                                                         ptr += sizeof(short int);
330                                                         if (PyInt_Check(item)) 
331                                                         {
332                                                                 long val = PyInt_AsLong(item);
333                                                                 if (attrdef->m_clamp)
334                                                                 {
335                                                                         if (val < attrdef->m_imin)
336                                                                                 val = attrdef->m_imin;
337                                                                         else if (val > attrdef->m_imax)
338                                                                                 val = attrdef->m_imax;
339                                                                 }
340                                                                 else if (val < attrdef->m_imin || val > attrdef->m_imax)
341                                                                 {
342                                                                         PyErr_SetString(PyExc_ValueError, "item value out of range");
343                                                                         goto UNDO_AND_ERROR;
344                                                                 }
345                                                                 *var = (short int)val;
346                                                         }
347                                                         else
348                                                         {
349                                                                 PyErr_SetString(PyExc_TypeError, "expected an integer");
350                                                                 goto UNDO_AND_ERROR;
351                                                         }
352                                                         break;
353                                                 }
354                                         case KX_PYATTRIBUTE_TYPE_ENUM:
355                                                 // enum are equivalent to int, just make sure that the field size matches:
356                                                 if (sizeof(int) != attrdef->m_size)
357                                                 {
358                                                         PyErr_SetString(PyExc_AttributeError, "attribute size check error, report to blender.org");
359                                                         goto UNDO_AND_ERROR;
360                                                 }
361                                                 // walkthrough
362                                         case KX_PYATTRIBUTE_TYPE_INT:
363                                                 {
364                                                         int *var = reinterpret_cast<int*>(ptr);
365                                                         ptr += sizeof(int);
366                                                         if (PyInt_Check(item)) 
367                                                         {
368                                                                 long val = PyInt_AsLong(item);
369                                                                 if (attrdef->m_clamp)
370                                                                 {
371                                                                         if (val < attrdef->m_imin)
372                                                                                 val = attrdef->m_imin;
373                                                                         else if (val > attrdef->m_imax)
374                                                                                 val = attrdef->m_imax;
375                                                                 }
376                                                                 else if (val < attrdef->m_imin || val > attrdef->m_imax)
377                                                                 {
378                                                                         PyErr_SetString(PyExc_ValueError, "item value out of range");
379                                                                         goto UNDO_AND_ERROR;
380                                                                 }
381                                                                 *var = (int)val;
382                                                         }
383                                                         else
384                                                         {
385                                                                 PyErr_SetString(PyExc_TypeError, "expected an integer");
386                                                                 goto UNDO_AND_ERROR;
387                                                         }
388                                                         break;
389                                                 }
390                                         case KX_PYATTRIBUTE_TYPE_FLOAT:
391                                                 {
392                                                         float *var = reinterpret_cast<float*>(ptr);
393                                                         ptr += sizeof(float);
394                                                         double val = PyFloat_AsDouble(item);
395                                                         if (val == -1.0 && PyErr_Occurred())
396                                                         {
397                                                                 PyErr_SetString(PyExc_TypeError, "expected a float");
398                                                                 goto UNDO_AND_ERROR;
399                                                         }
400                                                         else if (attrdef->m_clamp) 
401                                                         {
402                                                                 if (val < attrdef->m_fmin)
403                                                                         val = attrdef->m_fmin;
404                                                                 else if (val > attrdef->m_fmax)
405                                                                         val = attrdef->m_fmax;
406                                                         }
407                                                         else if (val < attrdef->m_fmin || val > attrdef->m_fmax)
408                                                         {
409                                                                 PyErr_SetString(PyExc_ValueError, "item value out of range");
410                                                                 goto UNDO_AND_ERROR;
411                                                         }
412                                                         *var = (float)val;
413                                                         break;
414                                                 }
415                                         default:
416                                                 // should not happen
417                                                 PyErr_SetString(PyExc_AttributeError, "attribute type check error, report to blender.org");
418                                                 goto UNDO_AND_ERROR;
419                                         }
420                                 }
421                                 // no error, call check function if any
422                                 if (attrdef->m_function != NULL)
423                                 {
424                                         if ((*attrdef->m_function)(self, attrdef) != 0)
425                                         {
426                                                 // post check returned an error, restore values
427                                         UNDO_AND_ERROR:
428                                                 if (undoBuffer)
429                                                 {
430                                                         memcpy(sourceBuffer, undoBuffer, bufferSize);
431                                                         free(undoBuffer);
432                                                 }
433                                                 return 1;
434                                         }
435                                 }
436                                 if (undoBuffer)
437                                         free(undoBuffer);
438                                 return 0;
439                         }
440                         else    // simple attribute value
441                         {
442
443                                 if (attrdef->m_function != NULL)
444                                 {
445                                         // post check function is provided, prepare undo buffer
446                                         sourceBuffer = ptr;
447                                         switch (attrdef->m_type) 
448                                         {
449                                         case KX_PYATTRIBUTE_TYPE_BOOL:
450                                                 bufferSize = sizeof(bool);
451                                                 break;
452                                         case KX_PYATTRIBUTE_TYPE_SHORT:
453                                                 bufferSize = sizeof(short);
454                                                 break;
455                                         case KX_PYATTRIBUTE_TYPE_ENUM:
456                                         case KX_PYATTRIBUTE_TYPE_INT:
457                                                 bufferSize = sizeof(int);
458                                                 break;
459                                         case KX_PYATTRIBUTE_TYPE_FLOAT:
460                                                 bufferSize = sizeof(float);
461                                                 break;
462                                         case KX_PYATTRIBUTE_TYPE_STRING:
463                                                 sourceBuffer = reinterpret_cast<STR_String*>(ptr)->Ptr();
464                                                 if (sourceBuffer)
465                                                         bufferSize = strlen(reinterpret_cast<char*>(sourceBuffer))+1;
466                                                 break;
467                                         default:
468                                                 PyErr_SetString(PyExc_AttributeError, "unknown attribute type, report to blender.org");
469                                                 return 1;
470                                         }
471                                         if (bufferSize)
472                                         {
473                                                 undoBuffer = malloc(bufferSize);
474                                                 if (undoBuffer)
475                                                 {
476                                                         memcpy(undoBuffer, sourceBuffer, bufferSize);
477                                                 }
478                                         }
479                                 }
480                                         
481                                 switch (attrdef->m_type) 
482                                 {
483                                 case KX_PYATTRIBUTE_TYPE_BOOL:
484                                         {
485                                                 bool *var = reinterpret_cast<bool*>(ptr);
486                                                 if (PyInt_Check(value)) 
487                                                 {
488                                                         *var = (PyInt_AsLong(value) != 0);
489                                                 } 
490                                                 else if (PyBool_Check(value))
491                                                 {
492                                                         *var = (value == Py_True);
493                                                 }
494                                                 else
495                                                 {
496                                                         PyErr_SetString(PyExc_TypeError, "expected an integer or a bool");
497                                                         goto FREE_AND_ERROR;
498                                                 }
499                                                 break;
500                                         }
501                                 case KX_PYATTRIBUTE_TYPE_SHORT:
502                                         {
503                                                 short int *var = reinterpret_cast<short int*>(ptr);
504                                                 if (PyInt_Check(value)) 
505                                                 {
506                                                         long val = PyInt_AsLong(value);
507                                                         if (attrdef->m_clamp)
508                                                         {
509                                                                 if (val < attrdef->m_imin)
510                                                                         val = attrdef->m_imin;
511                                                                 else if (val > attrdef->m_imax)
512                                                                         val = attrdef->m_imax;
513                                                         }
514                                                         else if (val < attrdef->m_imin || val > attrdef->m_imax)
515                                                         {
516                                                                 PyErr_SetString(PyExc_ValueError, "value out of range");
517                                                                 goto FREE_AND_ERROR;
518                                                         }
519                                                         *var = (short int)val;
520                                                 }
521                                                 else
522                                                 {
523                                                         PyErr_SetString(PyExc_TypeError, "expected an integer");
524                                                         goto FREE_AND_ERROR;
525                                                 }
526                                                 break;
527                                         }
528                                 case KX_PYATTRIBUTE_TYPE_ENUM:
529                                         // enum are equivalent to int, just make sure that the field size matches:
530                                         if (sizeof(int) != attrdef->m_size)
531                                         {
532                                                 PyErr_SetString(PyExc_AttributeError, "attribute size check error, report to blender.org");
533                                                 goto FREE_AND_ERROR;
534                                         }
535                                         // walkthrough
536                                 case KX_PYATTRIBUTE_TYPE_INT:
537                                         {
538                                                 int *var = reinterpret_cast<int*>(ptr);
539                                                 if (PyInt_Check(value)) 
540                                                 {
541                                                         long val = PyInt_AsLong(value);
542                                                         if (attrdef->m_clamp)
543                                                         {
544                                                                 if (val < attrdef->m_imin)
545                                                                         val = attrdef->m_imin;
546                                                                 else if (val > attrdef->m_imax)
547                                                                         val = attrdef->m_imax;
548                                                         }
549                                                         else if (val < attrdef->m_imin || val > attrdef->m_imax)
550                                                         {
551                                                                 PyErr_SetString(PyExc_ValueError, "value out of range");
552                                                                 goto FREE_AND_ERROR;
553                                                         }
554                                                         *var = (int)val;
555                                                 }
556                                                 else
557                                                 {
558                                                         PyErr_SetString(PyExc_TypeError, "expected an integer");
559                                                         goto FREE_AND_ERROR;
560                                                 }
561                                                 break;
562                                         }
563                                 case KX_PYATTRIBUTE_TYPE_FLOAT:
564                                         {
565                                                 float *var = reinterpret_cast<float*>(ptr);
566                                                 double val = PyFloat_AsDouble(value);
567                                                 if (val == -1.0 && PyErr_Occurred())
568                                                 {
569                                                         PyErr_SetString(PyExc_TypeError, "expected a float");
570                                                         goto FREE_AND_ERROR;
571                                                 }
572                                                 else if (attrdef->m_clamp)
573                                                 {
574                                                         if (val < attrdef->m_fmin)
575                                                                 val = attrdef->m_fmin;
576                                                         else if (val > attrdef->m_fmax)
577                                                                 val = attrdef->m_fmax;
578                                                 }
579                                                 else if (val < attrdef->m_fmin || val > attrdef->m_fmax)
580                                                 {
581                                                         PyErr_SetString(PyExc_ValueError, "value out of range");
582                                                         goto FREE_AND_ERROR;
583                                                 }
584                                                 *var = (float)val;
585                                                 break;
586                                         }
587                                 case KX_PYATTRIBUTE_TYPE_STRING:
588                                         {
589                                                 STR_String *var = reinterpret_cast<STR_String*>(ptr);
590                                                 if (PyString_Check(value)) 
591                                                 {
592                                                         char *val = PyString_AsString(value);
593                                                         if (attrdef->m_clamp)
594                                                         {
595                                                                 if (strlen(val) < attrdef->m_imin)
596                                                                 {
597                                                                         // can't increase the length of the string
598                                                                         PyErr_SetString(PyExc_ValueError, "string length too short");
599                                                                         goto FREE_AND_ERROR;
600                                                                 }
601                                                                 else if (strlen(val) > attrdef->m_imax)
602                                                                 {
603                                                                         // trim the string
604                                                                         char c = val[attrdef->m_imax];
605                                                                         val[attrdef->m_imax] = 0;
606                                                                         *var = val;
607                                                                         val[attrdef->m_imax] = c;
608                                                                         break;
609                                                                 }
610                                                         } else if (strlen(val) < attrdef->m_imin || strlen(val) > attrdef->m_imax)
611                                                         {
612                                                                 PyErr_SetString(PyExc_ValueError, "string length out of range");
613                                                                 goto FREE_AND_ERROR;
614                                                         }
615                                                         *var = val;
616                                                 }
617                                                 else
618                                                 {
619                                                         PyErr_SetString(PyExc_TypeError, "expected a string");
620                                                         goto FREE_AND_ERROR;
621                                                 }
622                                                 break;
623                                         }
624                                 default:
625                                         // should not happen
626                                         PyErr_SetString(PyExc_AttributeError, "unknown attribute type, report to blender.org");
627                                         goto FREE_AND_ERROR;
628                                 }
629                         }
630                         // check if post processing is needed
631                         if (attrdef->m_function != NULL)
632                         {
633                                 if ((*attrdef->m_function)(self, attrdef) != 0)
634                                 {
635                                         // restore value
636                                 RESTORE_AND_ERROR:
637                                         if (undoBuffer)
638                                         {
639                                                 if (attrdef->m_type == KX_PYATTRIBUTE_TYPE_STRING)
640                                                 {
641                                                         // special case for STR_String: restore the string
642                                                         STR_String *var = reinterpret_cast<STR_String*>(ptr);
643                                                         *var = reinterpret_cast<char*>(undoBuffer);
644                                                 }
645                                                 else
646                                                 {
647                                                         // other field type have direct values
648                                                         memcpy(ptr, undoBuffer, bufferSize);
649                                                 }
650                                         }
651                                 FREE_AND_ERROR:
652                                         if (undoBuffer)
653                                                 free(undoBuffer);
654                                         return 1;
655                                 }
656                         }
657                         if (undoBuffer)
658                                 free(undoBuffer);
659                         return 0;
660                 }
661         }
662         return -1;                      
663 }
664
665 /*------------------------------
666  * PyObjectPlus repr            -- representations
667 ------------------------------*/
668 PyObject *PyObjectPlus::_repr(void)
669 {
670         PyErr_SetString(PyExc_SystemError, "Representation not overridden by object.");  
671         return NULL;
672 }
673
674 /*------------------------------
675  * PyObjectPlus isA             -- the isA functions
676 ------------------------------*/
677 bool PyObjectPlus::isA(PyTypeObject *T)         // if called with a Type, use "typename"
678 {
679   return isA(T->tp_name);
680 }
681
682
683 bool PyObjectPlus::isA(const char *mytypename)          // check typename of each parent
684 {
685   int i;
686   PyParentObject  P;
687   PyParentObject *Ps = GetParents();
688   
689   for (P = Ps[i=0]; P != NULL; P = Ps[i++])
690   {
691       if (STR_String(P->tp_name) == STR_String(mytypename)      )
692                   return true;
693   }
694         
695   return false;
696 }
697
698 PyObject *PyObjectPlus::Py_isA(PyObject *args)          // Python wrapper for isA
699 {
700   char *mytypename;
701   if (!PyArg_ParseTuple(args, "s", &mytypename))
702     return NULL;
703   if(isA(mytypename))
704     Py_RETURN_TRUE;
705   else
706     Py_RETURN_FALSE;
707 }
708
709 #endif //NO_EXP_PYTHON_EMBEDDING
710