resolve some compiler warnings with intel c/c++ compiler
[blender-staging.git] / source / blender / python / api2_2x / IDProp.c
1 /**
2  * $Id: IDProp.c
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21  * All rights reserved.
22  *
23  * Contributor(s): Joseph Eagar
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27  
28 #include "DNA_ID.h"
29
30 #include "BKE_idprop.h"
31
32 #include "IDProp.h"
33 #include "gen_utils.h"
34
35 #include "MEM_guardedalloc.h"
36
37 #define BSTR_EQ(a, b)   (*(a) == *(b) && !strcmp(a, b))
38
39 /*** Function to wrap ID properties ***/
40 PyObject *BPy_Wrap_IDProperty(ID *id, IDProperty *prop, IDProperty *parent);
41
42 extern PyTypeObject IDArray_Type;
43 extern PyTypeObject IDGroup_Iter_Type;
44
45 /*********************** ID Property Main Wrapper Stuff ***************/
46
47 PyObject *IDGroup_repr( BPy_IDProperty *self )
48 {
49         return PyString_FromString( "(ID Property)" );
50 }
51
52 extern PyTypeObject IDGroup_Type;
53
54 PyObject *BPy_IDGroup_WrapData( ID *id, IDProperty *prop )
55 {
56         switch ( prop->type ) {
57                 case IDP_STRING:
58                         return PyString_FromString( prop->data.pointer );
59                 case IDP_INT:
60                         return PyInt_FromLong( (long)prop->data.val );
61                 case IDP_FLOAT:
62                         return PyFloat_FromDouble( (double)(*(float*)(&prop->data.val)) );
63                 case IDP_DOUBLE:
64                         return PyFloat_FromDouble( (*(double*)(&prop->data.val)) );
65                 case IDP_GROUP:
66                         /*blegh*/
67                         {
68                                 BPy_IDProperty *group = PyObject_New(BPy_IDProperty, &IDGroup_Type);
69                                 if (!group)
70                                         return EXPP_ReturnPyObjError( PyExc_RuntimeError,
71                                            "PyObject_New() failed" );
72                         
73                                 group->id = id;
74                                 group->prop = prop;
75                                 return (PyObject*) group;
76                         }
77                 case IDP_ARRAY:
78                         {
79                                 BPy_IDProperty *array = PyObject_New(BPy_IDProperty, &IDArray_Type);
80                                 if (!array)
81                                         return EXPP_ReturnPyObjError( PyExc_RuntimeError,
82                                            "PyObject_New() failed" );
83                                            
84                                 array->id = id;
85                                 array->prop = prop;
86                                 return (PyObject*) array;
87                         }
88         }
89         Py_RETURN_NONE;
90 }
91
92 int BPy_IDGroup_SetData(BPy_IDProperty *self, IDProperty *prop, PyObject *value)
93 {
94         switch (prop->type) {
95                 case IDP_STRING:
96                 {
97                         char *st;
98                         if (!PyString_Check(value))
99                                 return EXPP_ReturnIntError(PyExc_TypeError, "expected a string!");
100
101                         st = PyString_AsString(value);
102                         IDP_ResizeArray(prop, strlen(st)+1);
103                         strcpy(prop->data.pointer, st);
104                         return 0;
105                 }
106
107                 case IDP_INT:
108                 {
109                         int ivalue;
110                         if (!PyNumber_Check(value))
111                                 return EXPP_ReturnIntError(PyExc_TypeError, "expected an int!");
112                         value = PyNumber_Int(value);
113                         if (!value)
114                                 return EXPP_ReturnIntError(PyExc_TypeError, "expected an int!");
115                         ivalue = (int) PyInt_AsLong(value);
116                         prop->data.val = ivalue;
117                         Py_XDECREF(value);
118                         break;
119                 }
120                 case IDP_FLOAT:
121                 {
122                         float fvalue;
123                         if (!PyNumber_Check(value))
124                                 return EXPP_ReturnIntError(PyExc_TypeError, "expected a float!");
125                         value = PyNumber_Float(value);
126                         if (!value)
127                                 return EXPP_ReturnIntError(PyExc_TypeError, "expected a float!");
128                         fvalue = (float) PyFloat_AsDouble(value);
129                         *(float*)&self->prop->data.val = fvalue;
130                         Py_XDECREF(value);
131                         break;
132                 }
133                 case IDP_DOUBLE:
134                 {
135                         double dvalue;
136                         if (!PyNumber_Check(value))
137                                 return EXPP_ReturnIntError(PyExc_TypeError, "expected a float!");
138                         value = PyNumber_Float(value);
139                         if (!value)
140                                 return EXPP_ReturnIntError(PyExc_TypeError, "expected a float!");
141                         dvalue = (float) PyFloat_AsDouble(value);
142                         *(double*)&self->prop->data.val = dvalue;
143                         Py_XDECREF(value);
144                         break;
145                 }
146                 default:
147                         return EXPP_ReturnIntError(PyExc_AttributeError, "attempt to set read-only attribute!");
148         }
149         return 0;
150 }
151
152 PyObject *BPy_IDGroup_GetName(BPy_IDProperty *self, void *bleh)
153 {
154         return PyString_FromString(self->prop->name);
155 }
156
157 static int BPy_IDGroup_SetName(BPy_IDProperty *self, PyObject *value, void *bleh)
158 {
159         char *st;
160         if (!PyString_Check(value))
161                 return EXPP_ReturnIntError(PyExc_TypeError, "expected a string!");
162
163         st = PyString_AsString(value);
164         if (strlen(st) >= MAX_IDPROP_NAME)
165                 return EXPP_ReturnIntError(PyExc_TypeError, "string length cannot exceed 31 characters!");
166
167         strcpy(self->prop->name, st);
168         return 0;
169 }
170
171 static PyObject *BPy_IDGroup_GetType(BPy_IDProperty *self)
172 {
173         return PyInt_FromLong((long)self->prop->type);
174 }
175
176 static PyGetSetDef BPy_IDGroup_getseters[] = {
177         {"name",
178          (getter)BPy_IDGroup_GetName, (setter)BPy_IDGroup_SetName,
179          "The name of this Group.",
180          NULL},
181          {NULL, NULL, NULL, NULL, NULL}
182 };
183          
184 static int BPy_IDGroup_Map_Len(BPy_IDProperty *self)
185 {
186         if (self->prop->type != IDP_GROUP)
187                 return EXPP_ReturnIntError( PyExc_TypeError,
188                         "len() of unsized object");
189                         
190         return self->prop->len;
191 }
192
193 static PyObject *BPy_IDGroup_Map_GetItem(BPy_IDProperty *self, PyObject *item)
194 {
195         IDProperty *loop;
196         char *st;
197         
198         if (self->prop->type  != IDP_GROUP)
199                 return EXPP_ReturnPyObjError( PyExc_TypeError,
200                         "unsubscriptable object");
201                         
202         if (!PyString_Check(item)) 
203                 return EXPP_ReturnPyObjError( PyExc_TypeError,
204                         "only strings are allowed as keys of ID properties");
205         
206         st = PyString_AsString(item);
207         for (loop=self->prop->data.group.first; loop; loop=loop->next) {
208                 if (BSTR_EQ(loop->name, st)) return BPy_IDGroup_WrapData(self->id, loop);
209         }
210         return EXPP_ReturnPyObjError( PyExc_KeyError,
211                 "key not in subgroup dict");
212 }
213
214 /*returns NULL on success, error string on failure*/
215 static char *BPy_IDProperty_Map_ValidateAndCreate(char *name, IDProperty *group, PyObject *ob)
216 {
217         IDProperty *prop = NULL;
218         IDPropertyTemplate val = {0};
219         
220         if (PyFloat_Check(ob)) {
221                 val.d = PyFloat_AsDouble(ob);
222                 prop = IDP_New(IDP_DOUBLE, val, name);
223         } else if (PyInt_Check(ob)) {
224                 val.i = (int) PyInt_AsLong(ob);
225                 prop = IDP_New(IDP_INT, val, name);
226         } else if (PyString_Check(ob)) {
227                 val.str = PyString_AsString(ob);
228                 prop = IDP_New(IDP_STRING, val, name);
229         } else if (PySequence_Check(ob)) {
230                 PyObject *item;
231                 int i;
232                 
233                 /*validate sequence and derive type.
234                 we assume IDP_INT unless we hit a float
235                 number; then we assume it's */
236                 val.array.type = IDP_INT;
237                 val.array.len = PySequence_Length(ob);
238                 for (i=0; i<val.array.len; i++) {
239                         item = PySequence_GetItem(ob, i);
240                         if (PyFloat_Check(item)) val.array.type = IDP_DOUBLE;
241                         else if (!PyInt_Check(item)) return "only floats and ints are allowed in ID property arrays";
242                         Py_XDECREF(item);
243                 }
244                 
245                 prop = IDP_New(IDP_ARRAY, val, name);
246                 for (i=0; i<val.array.len; i++) {
247                         item = PySequence_GetItem(ob, i);
248                         if (val.array.type == IDP_INT) {
249                                 item = PyNumber_Int(item);
250                                 ((int*)prop->data.pointer)[i] = (int)PyInt_AsLong(item);
251                         } else {
252                                 item = PyNumber_Float(item);
253                                 ((double*)prop->data.pointer)[i] = (float)PyFloat_AsDouble(item);
254                         }
255                         Py_XDECREF(item);
256                 }
257         } else if (PyMapping_Check(ob)) {
258                 PyObject *keys, *vals, *key, *pval;
259                 int i, len;
260                 /*yay! we get into recursive stuff now!*/
261                 keys = PyMapping_Keys(ob);
262                 vals = PyMapping_Values(ob);
263                 
264                 /*we allocate the group first; if we hit any invalid data,
265                   we can delete it easily enough.*/
266                 prop = IDP_New(IDP_GROUP, val, name);
267                 len = PyMapping_Length(ob);
268                 for (i=0; i<len; i++) {
269                         key = PySequence_GetItem(keys, i);
270                         pval = PySequence_GetItem(vals, i);
271                         if (!PyString_Check(key)) {
272                                 IDP_FreeProperty(prop);
273                                 MEM_freeN(prop);
274                                 Py_XDECREF(keys);
275                                 Py_XDECREF(vals);
276                                 Py_XDECREF(key);
277                                 Py_XDECREF(pval);
278                                 return "invalid element in subgroup dict template!";
279                         }
280                         if (BPy_IDProperty_Map_ValidateAndCreate(PyString_AsString(key), prop, pval)) {
281                                 IDP_FreeProperty(prop);
282                                 MEM_freeN(prop);
283                                 Py_XDECREF(keys);
284                                 Py_XDECREF(vals);
285                                 Py_XDECREF(key);
286                                 Py_XDECREF(pval);
287                                 return "invalid element in subgroup dict template!";
288                         }
289                         Py_XDECREF(key);
290                         Py_XDECREF(pval);
291                 }
292                 Py_XDECREF(keys);
293                 Py_XDECREF(vals);
294         } else return "invalid property value";
295         
296         IDP_ReplaceInGroup(group, prop);
297         return NULL;
298 }
299
300 static int BPy_IDGroup_Map_SetItem(BPy_IDProperty *self, PyObject *key, PyObject *val)
301 {
302         char *err;
303         
304         if (self->prop->type  != IDP_GROUP)
305                 return EXPP_ReturnIntError( PyExc_TypeError,
306                         "unsubscriptable object");
307                         
308         if (!PyString_Check(key))
309                 return EXPP_ReturnIntError( PyExc_TypeError,
310                    "only strings are allowed as subgroup keys" );
311
312         if (val == NULL) {
313                 IDProperty *pkey = IDP_GetPropertyFromGroup(self->prop, PyString_AsString(key));
314                 if (pkey) {
315                         IDP_RemFromGroup(self->prop, pkey);
316                         IDP_FreeProperty(pkey);
317                         MEM_freeN(pkey);
318                         return 0;
319                 } else return EXPP_ReturnIntError( PyExc_RuntimeError, "property not found in group" );
320         }
321         
322         err = BPy_IDProperty_Map_ValidateAndCreate(PyString_AsString(key), self->prop, val);
323         if (err) return EXPP_ReturnIntError( PyExc_RuntimeError, err );
324         
325         return 0;
326 }
327
328 static PyObject *BPy_IDGroup_SpawnIterator(BPy_IDProperty *self)
329 {
330         BPy_IDGroup_Iter *iter = PyObject_New(BPy_IDGroup_Iter, &IDGroup_Iter_Type);
331         
332         if (!iter)
333                 return EXPP_ReturnPyObjError( PyExc_RuntimeError,
334                    "PyObject_New() failed" );
335         iter->group = self;
336         iter->mode = IDPROP_ITER_KEYS;
337         iter->cur = self->prop->data.group.first;
338         Py_XINCREF(iter);
339         return (PyObject*) iter;
340 }
341
342 static PyObject *BPy_IDGroup_MapDataToPy(IDProperty *prop)
343 {
344         switch (prop->type) {
345                 case IDP_STRING:
346                         return PyString_FromString(prop->data.pointer);
347                         break;
348                 case IDP_FLOAT:
349                         return PyFloat_FromDouble(*((float*)&prop->data.val));
350                         break;
351                 case IDP_DOUBLE:
352                         return PyFloat_FromDouble(*((double*)&prop->data.val));
353                         break;
354                 case IDP_INT:
355                         return PyInt_FromLong( (long)prop->data.val );
356                         break;
357                 case IDP_ARRAY:
358                 {
359                         PyObject *seq = PyList_New(prop->len);
360                         int i;
361                         
362                         if (!seq) 
363                                 return EXPP_ReturnPyObjError( PyExc_RuntimeError,
364                                            "PyList_New() failed" );
365                         
366                         for (i=0; i<prop->len; i++) {
367                                 if (prop->subtype == IDP_FLOAT) {
368                                                 PyList_SetItem(seq, i,
369                                                 PyFloat_FromDouble(((float*)prop->data.pointer)[i]));
370                                 } else if (prop->subtype == IDP_DOUBLE) {
371                                                 PyList_SetItem(seq, i,
372                                                 PyFloat_FromDouble(((double*)prop->data.pointer)[i]));                          
373                                 } else  { PyList_SetItem(seq, i,
374                                                   PyInt_FromLong(((int*)prop->data.pointer)[i]));
375                                 }
376                         }
377                         return seq;
378                 }
379                 case IDP_GROUP:
380                 {
381                         PyObject *dict = PyDict_New(), *wrap;
382                         IDProperty *loop;
383                         
384                         if (!dict)
385                                 return EXPP_ReturnPyObjError( PyExc_RuntimeError,
386                                            "PyDict_New() failed" );
387                                            
388                         for (loop=prop->data.group.first; loop; loop=loop->next) {
389                                 wrap = BPy_IDGroup_MapDataToPy(loop);
390                                 if (!wrap) 
391                                         return EXPP_ReturnPyObjError( PyExc_RuntimeError,
392                                            "BPy_IDGroup_MapDataToPy() failed" );
393                                            
394                                 PyDict_SetItemString(dict, loop->name, wrap);
395                         }
396                         return dict;
397                 }
398         }
399         
400         return EXPP_ReturnPyObjError( PyExc_RuntimeError,
401                                            "eek!! a property exists with a bad type code!!!" );
402 }
403
404 static PyObject *BPy_IDGroup_Pop(BPy_IDProperty *self, PyObject *value)
405 {
406         IDProperty *loop;
407         PyObject *pyform;
408         char *name = PyString_AsString(value);
409         
410         if (!name) {
411                 return EXPP_ReturnPyObjError( PyExc_TypeError,
412                    "pop expected at least 1 argument, got 0" );
413         }
414         
415         for (loop=self->prop->data.group.first; loop; loop=loop->next) {
416                 if (BSTR_EQ(loop->name, name)) {
417                         pyform = BPy_IDGroup_MapDataToPy(loop);
418                         
419                         if (!pyform)
420                                 /*ok something bad happened with the pyobject,
421                                   so don't remove the prop from the group.  if pyform is
422                                   NULL, then it already should have raised an exception.*/
423                                   return NULL;
424
425                         IDP_RemFromGroup(self->prop, loop);
426                         return pyform;
427                 }
428         }
429         
430         return EXPP_ReturnPyObjError( PyExc_KeyError,
431                    "item not in group" );
432 }
433
434 static PyObject *BPy_IDGroup_IterItems(BPy_IDProperty *self)
435 {
436         BPy_IDGroup_Iter *iter = PyObject_New(BPy_IDGroup_Iter, &IDGroup_Iter_Type);
437         
438         if (!iter)
439                 return EXPP_ReturnPyObjError( PyExc_RuntimeError,
440                    "PyObject_New() failed" );
441         
442         iter->group = self;
443         iter->mode = IDPROP_ITER_ITEMS;
444         iter->cur = self->prop->data.group.first;
445         Py_XINCREF(iter);
446         return (PyObject*) iter;
447 }
448
449 static PyObject *BPy_IDGroup_GetKeys(BPy_IDProperty *self)
450 {
451         PyObject *seq = PyList_New(self->prop->len);
452         IDProperty *loop;
453         int i, j;
454
455         if (!seq) 
456                 return EXPP_ReturnPyObjError( PyExc_RuntimeError,
457                    "PyList_New() failed" );
458                    
459         for (i=0, loop=self->prop->data.group.first; loop; loop=loop->next, i++)
460                 PyList_SetItem(seq, i, PyString_FromString(loop->name));
461         
462         if (i != self->prop->len) {
463                 printf("ID Property Error found and corrected in BPy_IDGroup_GetKeys!\n");
464                 
465                 /*fill rest of list with valid references to None*/
466                 for (j=i; j<self->prop->len; j++) {
467                         Py_INCREF(Py_None);
468                         PyList_SetItem(seq, j, Py_None);
469                 }
470                 
471                 /*set correct group length*/
472                 self->prop->len = i;
473                 
474                 /*free the list*/
475                 Py_DECREF(seq);
476                 
477                 /*call self again*/
478                 return BPy_IDGroup_GetKeys(self);               
479         }
480         
481         return seq;
482 }
483
484 static PyObject *BPy_IDGroup_GetValues(BPy_IDProperty *self)
485 {
486         PyObject *seq = PyList_New(self->prop->len);
487         IDProperty *loop;
488         int i, j;
489
490         if (!seq) 
491                 return EXPP_ReturnPyObjError( PyExc_RuntimeError,
492                    "PyList_New() failed" );
493         
494         for (i=0, loop=self->prop->data.group.first; loop; loop=loop->next, i++) {
495                 PyList_SetItem(seq, i, BPy_IDGroup_WrapData(self->id, loop));
496         }
497
498         if (i != self->prop->len) {
499                 printf("ID Property Error found and corrected in BPy_IDGroup_GetValues!\n");
500                 
501                 /*fill rest of list with valid references to None*/
502                 for (j=i; j<self->prop->len; j++) {
503                         Py_INCREF(Py_None);
504                         PyList_SetItem(seq, j, Py_None);
505                 }
506                 
507                 /*set correct group length*/
508                 self->prop->len = i;
509                 
510                 /*free the old list*/
511                 Py_DECREF(seq);
512                 
513                 /*call self again*/
514                 return BPy_IDGroup_GetValues(self);             
515         }
516                 
517         return seq;
518 }
519
520 static PyObject *BPy_IDGroup_HasKey(BPy_IDProperty *self, PyObject *value)
521 {
522         IDProperty *loop;
523         char *name = PyString_AsString(value);
524         
525         if (!name)
526                 return EXPP_ReturnPyObjError( PyExc_TypeError,
527                    "expected a string");
528                    
529         for (loop=self->prop->data.group.first; loop; loop=loop->next) {
530                 if (BSTR_EQ(loop->name, name)) Py_RETURN_TRUE;
531         }
532         
533         Py_RETURN_FALSE;
534 }
535
536 static PyObject *BPy_IDGroup_Update(BPy_IDProperty *self, PyObject *vars)
537 {
538         PyObject *pyob, *pkey, *pval;
539         Py_ssize_t i=0;
540         
541         if (PySequence_Size(vars) != 1)
542                 return EXPP_ReturnPyObjError( PyExc_TypeError,
543                    "expected an object derived from dict.");
544           
545         pyob = PyTuple_GET_ITEM(vars, 0);
546         if (!PyDict_Check(pyob))
547                 return EXPP_ReturnPyObjError( PyExc_TypeError,
548                    "expected an object derived from dict.");
549                    
550         while (PyDict_Next(pyob, &i, &pkey, &pval)) {
551                 BPy_IDGroup_Map_SetItem(self, pkey, pval);
552                 if (PyErr_Occurred()) return NULL;
553         }
554         
555         Py_RETURN_NONE;
556 }
557
558 static PyObject *BPy_IDGroup_ConvertToPy(BPy_IDProperty *self)
559 {
560         return BPy_IDGroup_MapDataToPy(self->prop);
561 }
562
563 static struct PyMethodDef BPy_IDGroup_methods[] = {
564         {"pop", (PyCFunction)BPy_IDGroup_Pop, METH_O,
565                 "pop an item from the group; raises KeyError if the item doesn't exist."},
566         {"iteritems", (PyCFunction)BPy_IDGroup_IterItems, METH_NOARGS,
567                 "iterate through the items in the dict; behaves like dictionary method iteritems."},
568         {"keys", (PyCFunction)BPy_IDGroup_GetKeys, METH_NOARGS,
569                 "get the keys associated with this group as a list of strings."},
570         {"values", (PyCFunction)BPy_IDGroup_GetValues, METH_NOARGS,
571                 "get the values associated with this group."},
572         {"has_key", (PyCFunction)BPy_IDGroup_HasKey, METH_O,
573                 "returns true if the group contains a key, false if not."},
574         {"update", (PyCFunction)BPy_IDGroup_Update, METH_VARARGS,
575                 "updates the values in the group with the values of another or a dict."},
576         {"convert_to_pyobject", (PyCFunction)BPy_IDGroup_ConvertToPy, METH_NOARGS,
577                 "return a purely python version of the group."},
578         {0, NULL, 0, NULL}
579 };
580                 
581 PyMappingMethods BPy_IDGroup_Mapping = {
582         (inquiry)BPy_IDGroup_Map_Len,                   /*inquiry mp_length */
583         (binaryfunc)BPy_IDGroup_Map_GetItem,            /*binaryfunc mp_subscript */
584         (objobjargproc)BPy_IDGroup_Map_SetItem, /*objobjargproc mp_ass_subscript */
585 };
586
587 PyTypeObject IDGroup_Type = {
588         PyObject_HEAD_INIT( NULL )  /* required py macro */
589         0,                          /* ob_size */
590         /*  For printing, in format "<module>.<name>" */
591         "Blender IDProperty",           /* char *tp_name; */
592         sizeof( BPy_IDProperty ),       /* int tp_basicsize; */
593         0,                          /* tp_itemsize;  For allocation */
594
595         /* Methods to implement standard operations */
596
597         NULL,                                           /* destructor tp_dealloc; */
598         NULL,                       /* printfunc tp_print; */
599         NULL,     /* getattrfunc tp_getattr; */
600         NULL,     /* setattrfunc tp_setattr; */
601         NULL,                       /* cmpfunc tp_compare; */
602         ( reprfunc ) IDGroup_repr,     /* reprfunc tp_repr; */
603
604         /* Method suites for standard classes */
605
606         NULL,                       /* PyNumberMethods *tp_as_number; */
607         NULL,                                   /* PySequenceMethods *tp_as_sequence; */
608         &BPy_IDGroup_Mapping,     /* PyMappingMethods *tp_as_mapping; */
609
610         /* More standard operations (here for binary compatibility) */
611
612         NULL,                       /* hashfunc tp_hash; */
613         NULL,                       /* ternaryfunc tp_call; */
614         NULL,                       /* reprfunc tp_str; */
615         NULL,                       /* getattrofunc tp_getattro; */
616         NULL,                       /* setattrofunc tp_setattro; */
617
618         /* Functions to access object as input/output buffer */
619         NULL,                       /* PyBufferProcs *tp_as_buffer; */
620
621   /*** Flags to define presence of optional/expanded features ***/
622         Py_TPFLAGS_DEFAULT,         /* long tp_flags; */
623
624         NULL,                       /*  char *tp_doc;  Documentation string */
625   /*** Assigned meaning in release 2.0 ***/
626         /* call function for all accessible objects */
627         NULL,                       /* traverseproc tp_traverse; */
628
629         /* delete references to contained objects */
630         NULL,                       /* inquiry tp_clear; */
631
632   /***  Assigned meaning in release 2.1 ***/
633   /*** rich comparisons ***/
634         NULL,                       /* richcmpfunc tp_richcompare; */
635
636   /***  weak reference enabler ***/
637         0,                          /* long tp_weaklistoffset; */
638
639   /*** Added in release 2.2 ***/
640         /*   Iterators */
641         (getiterfunc)BPy_IDGroup_SpawnIterator, /* getiterfunc tp_iter; */
642         NULL,                       /* iternextfunc tp_iternext; */
643   /*** Attribute descriptor and subclassing stuff ***/
644         BPy_IDGroup_methods,        /* struct PyMethodDef *tp_methods; */
645         NULL,                       /* struct PyMemberDef *tp_members; */
646         BPy_IDGroup_getseters,       /* struct PyGetSetDef *tp_getset; */
647 };
648
649 /*********** Main external wrapping function *******/
650 PyObject *BPy_Wrap_IDProperty(ID *id, IDProperty *prop, IDProperty *parent)
651 {
652         BPy_IDProperty *wrap = PyObject_New(BPy_IDProperty, &IDGroup_Type);
653         
654         if (!wrap)
655                 return EXPP_ReturnPyObjError( PyExc_RuntimeError,
656                    "PyObject_New() failed" );
657                                                    
658         wrap->prop = prop;
659         wrap->parent = parent;
660         wrap->id = id;
661         //wrap->destroy = 0;
662         return (PyObject*) wrap;
663 }
664
665
666 /********Array Wrapper********/
667
668 static PyObject *IDArray_repr(BPy_IDArray *self)
669 {
670         return PyString_FromString("(ID Array)");
671 }
672
673
674 static PyObject *BPy_IDArray_GetType(BPy_IDArray *self)
675 {
676         return PyInt_FromLong( (long)self->prop->subtype );
677 }
678
679 static PyObject *BPy_IDArray_GetLen(BPy_IDArray *self)
680 {
681         return PyInt_FromLong( (long)self->prop->len );
682 }
683
684 static PyGetSetDef BPy_IDArray_getseters[] = {
685         {"len",
686          (getter)BPy_IDArray_GetLen, (setter)NULL,
687          "The length of the array, can also be gotten with len(array).",
688          NULL},
689         {"type",
690          (getter)BPy_IDArray_GetType, (setter)NULL,
691          "The type of the data in the array, is an ant.",
692          NULL}, 
693         {NULL, NULL, NULL, NULL, NULL},
694 };
695
696 static int BPy_IDArray_Len(BPy_IDArray *self)
697 {
698         return self->prop->len;
699 }
700
701 static PyObject *BPy_IDArray_GetItem(BPy_IDArray *self, int index)
702 {
703         if (index < 0 || index >= self->prop->len)
704                 return EXPP_ReturnPyObjError( PyExc_IndexError,
705                                 "index out of range!");
706
707         switch (self->prop->subtype) {
708                 case IDP_FLOAT:
709                         return PyFloat_FromDouble( (double)(((float*)self->prop->data.pointer)[index]));
710                         break;
711                 case IDP_DOUBLE:
712                         return PyFloat_FromDouble( (((double*)self->prop->data.pointer)[index]));
713                         break;          
714                 case IDP_INT:
715                         return PyInt_FromLong( (long)((int*)self->prop->data.pointer)[index] );
716                         break;
717         }
718                 return EXPP_ReturnPyObjError( PyExc_RuntimeError,
719                                 "invalid/corrupt array type!");
720 }
721
722 static int BPy_IDArray_SetItem(BPy_IDArray *self, int index, PyObject *val)
723 {
724         int i;
725         float f;
726         double d;
727         
728         if (index < 0 || index >= self->prop->len)
729                 return EXPP_ReturnIntError( PyExc_RuntimeError,
730                                 "index out of range!");
731
732         switch (self->prop->subtype) {
733                 case IDP_FLOAT:
734                         if (!PyNumber_Check(val)) return EXPP_ReturnIntError( PyExc_TypeError,
735                                 "expected a float");
736                         val = PyNumber_Float(val);
737                         if (!val) return EXPP_ReturnIntError( PyExc_TypeError,
738                                 "expected a float");
739
740                         f = (float) PyFloat_AsDouble(val);
741                         ((float*)self->prop->data.pointer)[index] = f;
742                         Py_XDECREF(val);
743                         break;
744                 case IDP_DOUBLE:
745                         if (!PyNumber_Check(val)) return EXPP_ReturnIntError( PyExc_TypeError,
746                                 "expected a float");
747                         val = PyNumber_Float(val);
748                         if (!val) return EXPP_ReturnIntError( PyExc_TypeError,
749                                 "expected a float");
750
751                         d = (double) PyFloat_AsDouble(val);
752                         ((double*)self->prop->data.pointer)[index] = d;
753                         Py_XDECREF(val);
754                         break;
755                 case IDP_INT:
756                         if (!PyNumber_Check(val)) return EXPP_ReturnIntError( PyExc_TypeError,
757                                 "expected an int");
758                         val = PyNumber_Int(val);
759                         if (!val) return EXPP_ReturnIntError( PyExc_TypeError,
760                                 "expected an int");
761
762                         i = (int) PyInt_AsLong(val);
763                         ((int*)self->prop->data.pointer)[index] = i;
764                         Py_XDECREF(val);
765                         break;
766         }
767         return 0;
768 }
769
770 static PySequenceMethods BPy_IDArray_Seq = {
771         (inquiry) BPy_IDArray_Len,                      /* inquiry sq_length */
772         0,                                                                      /* binaryfunc sq_concat */
773         0,                                                                      /* intargfunc sq_repeat */
774         (intargfunc)BPy_IDArray_GetItem,        /* intargfunc sq_item */
775         0,                                                                      /* intintargfunc sq_slice */
776         (intobjargproc)BPy_IDArray_SetItem,     /* intobjargproc sq_ass_item */
777         0,                                                                      /* intintobjargproc sq_ass_slice */
778         0,                                                                      /* objobjproc sq_contains */
779                                 /* Added in release 2.0 */
780         0,                                                                      /* binaryfunc sq_inplace_concat */
781         0,                                                                      /* intargfunc sq_inplace_repeat */
782 };
783
784 PyTypeObject IDArray_Type = {
785         PyObject_HEAD_INIT( NULL )  /* required py macro */
786         0,                          /* ob_size */
787         /*  For printing, in format "<module>.<name>" */
788         "Blender IDArray",           /* char *tp_name; */
789         sizeof( BPy_IDArray ),       /* int tp_basicsize; */
790         0,                          /* tp_itemsize;  For allocation */
791
792         /* Methods to implement standard operations */
793
794         NULL,                                           /* destructor tp_dealloc; */
795         NULL,                       /* printfunc tp_print; */
796         NULL,     /* getattrfunc tp_getattr; */
797         NULL,     /* setattrfunc tp_setattr; */
798         NULL,                       /* cmpfunc tp_compare; */
799         ( reprfunc ) IDArray_repr,     /* reprfunc tp_repr; */
800
801         /* Method suites for standard classes */
802
803         NULL,                       /* PyNumberMethods *tp_as_number; */
804         &BPy_IDArray_Seq,                       /* PySequenceMethods *tp_as_sequence; */
805         NULL,                       /* PyMappingMethods *tp_as_mapping; */
806
807         /* More standard operations (here for binary compatibility) */
808
809         NULL,                       /* hashfunc tp_hash; */
810         NULL,                       /* ternaryfunc tp_call; */
811         NULL,                       /* reprfunc tp_str; */
812         NULL,                       /* getattrofunc tp_getattro; */
813         NULL,                       /* setattrofunc tp_setattro; */
814
815         /* Functions to access object as input/output buffer */
816         NULL,                       /* PyBufferProcs *tp_as_buffer; */
817
818   /*** Flags to define presence of optional/expanded features ***/
819         Py_TPFLAGS_DEFAULT,         /* long tp_flags; */
820
821         NULL,                       /*  char *tp_doc;  Documentation string */
822   /*** Assigned meaning in release 2.0 ***/
823         /* call function for all accessible objects */
824         NULL,                       /* traverseproc tp_traverse; */
825
826         /* delete references to contained objects */
827         NULL,                       /* inquiry tp_clear; */
828
829   /***  Assigned meaning in release 2.1 ***/
830   /*** rich comparisons ***/
831         NULL,                       /* richcmpfunc tp_richcompare; */
832
833   /***  weak reference enabler ***/
834         0,                          /* long tp_weaklistoffset; */
835
836   /*** Added in release 2.2 ***/
837         /*   Iterators */
838         NULL,                       /* getiterfunc tp_iter; */
839         NULL,                       /* iternextfunc tp_iternext; */
840
841   /*** Attribute descriptor and subclassing stuff ***/
842         NULL,                       /* struct PyMethodDef *tp_methods; */
843         NULL,                       /* struct PyMemberDef *tp_members; */
844         BPy_IDArray_getseters,       /* struct PyGetSetDef *tp_getset; */
845         NULL,                       /* struct _typeobject *tp_base; */
846         NULL,                       /* PyObject *tp_dict; */
847         NULL,                       /* descrgetfunc tp_descr_get; */
848         NULL,                       /* descrsetfunc tp_descr_set; */
849         0,                          /* long tp_dictoffset; */
850         NULL,                       /* initproc tp_init; */
851         NULL,                       /* allocfunc tp_alloc; */
852         NULL,                       /* newfunc tp_new; */
853         /*  Low-level free-memory routine */
854         NULL,                       /* freefunc tp_free;  */
855         /* For PyObject_IS_GC */
856         NULL,                       /* inquiry tp_is_gc;  */
857         NULL,                       /* PyObject *tp_bases; */
858         /* method resolution order */
859         NULL,                       /* PyObject *tp_mro;  */
860         NULL,                       /* PyObject *tp_cache; */
861         NULL,                       /* PyObject *tp_subclasses; */
862         NULL,                       /* PyObject *tp_weaklist; */
863         NULL
864 };
865
866 /*********** ID Property Group iterator ********/
867
868 static PyObject *IDGroup_Iter_iterself(PyObject *self)
869 {
870         Py_XINCREF(self);
871         return self;
872 }
873
874 static PyObject *IDGroup_Iter_repr(BPy_IDGroup_Iter *self)
875 {
876         return PyString_FromString("(ID Property Group)");
877 }
878
879 static PyObject *BPy_Group_Iter_Next(BPy_IDGroup_Iter *self)
880 {
881         IDProperty *cur=NULL;
882         PyObject *tmpval;
883         PyObject *ret;
884
885         if (self->cur) {
886                 cur = self->cur;
887                 self->cur = self->cur->next;
888                 if (self->mode == IDPROP_ITER_ITEMS) {
889                         tmpval = BPy_IDGroup_WrapData(self->group->id, cur);
890                         ret = Py_BuildValue("[s, O]", cur->name, tmpval);
891                         Py_DECREF(tmpval);
892                         return ret;
893                 } else {
894                         return PyString_FromString(cur->name);
895                 }
896         } else {
897                 return EXPP_ReturnPyObjError( PyExc_StopIteration,
898                                 "iterator at end" );
899         }
900 }
901
902 PyTypeObject IDGroup_Iter_Type = {
903         PyObject_HEAD_INIT( NULL )  /* required py macro */
904         0,                          /* ob_size */
905         /*  For printing, in format "<module>.<name>" */
906         "Blender IDGroup_Iter",           /* char *tp_name; */
907         sizeof( BPy_IDGroup_Iter ),       /* int tp_basicsize; */
908         0,                          /* tp_itemsize;  For allocation */
909
910         /* Methods to implement standard operations */
911
912         NULL,                                           /* destructor tp_dealloc; */
913         NULL,                       /* printfunc tp_print; */
914         NULL,     /* getattrfunc tp_getattr; */
915         NULL,     /* setattrfunc tp_setattr; */
916         NULL,                       /* cmpfunc tp_compare; */
917         ( reprfunc ) IDGroup_Iter_repr,     /* reprfunc tp_repr; */
918
919         /* Method suites for standard classes */
920
921         NULL,                       /* PyNumberMethods *tp_as_number; */
922         NULL,                                   /* PySequenceMethods *tp_as_sequence; */
923         NULL,                       /* PyMappingMethods *tp_as_mapping; */
924
925         /* More standard operations (here for binary compatibility) */
926
927         NULL,                       /* hashfunc tp_hash; */
928         NULL,                       /* ternaryfunc tp_call; */
929         NULL,                       /* reprfunc tp_str; */
930         NULL,                       /* getattrofunc tp_getattro; */
931         NULL,                       /* setattrofunc tp_setattro; */
932
933         /* Functions to access object as input/output buffer */
934         NULL,                       /* PyBufferProcs *tp_as_buffer; */
935
936   /*** Flags to define presence of optional/expanded features ***/
937         Py_TPFLAGS_DEFAULT,         /* long tp_flags; */
938
939         NULL,                       /*  char *tp_doc;  Documentation string */
940   /*** Assigned meaning in release 2.0 ***/
941         /* call function for all accessible objects */
942         NULL,                       /* traverseproc tp_traverse; */
943
944         /* delete references to contained objects */
945         NULL,                       /* inquiry tp_clear; */
946
947   /***  Assigned meaning in release 2.1 ***/
948   /*** rich comparisons ***/
949         NULL,                       /* richcmpfunc tp_richcompare; */
950
951   /***  weak reference enabler ***/
952         0,                          /* long tp_weaklistoffset; */
953
954   /*** Added in release 2.2 ***/
955         /*   Iterators */
956         IDGroup_Iter_iterself,              /* getiterfunc tp_iter; */
957         (iternextfunc) BPy_Group_Iter_Next, /* iternextfunc tp_iternext; */
958 };
959
960 void IDProp_Init_Types(void)
961 {
962         PyType_Ready( &IDGroup_Type );
963         PyType_Ready( &IDGroup_Iter_Type );
964         PyType_Ready( &IDArray_Type );
965 }