Blender  V2.59
IDProp.c
Go to the documentation of this file.
00001 /*
00002  * $Id: IDProp.c 37581 2011-06-17 05:56:17Z campbellbarton $
00003  *
00004  * ***** BEGIN GPL LICENSE BLOCK *****
00005  *
00006  * This program is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU General Public License
00008  * as published by the Free Software Foundation; either version 2
00009  * of the License, or (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software Foundation,
00018  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00019  *
00020  *
00021  * Contributor(s): Joseph Eagar, Campbell Barton
00022  *
00023  * ***** END GPL LICENSE BLOCK *****
00024  */
00025 
00031 #include <Python.h>
00032 
00033 #include "IDProp.h"
00034 #include "MEM_guardedalloc.h"
00035 
00036 #include "BLI_string.h"
00037 #include "BLI_utildefines.h"
00038 
00039 #include "BKE_idprop.h"
00040 
00041 
00042 #define USE_STRING_COERCE
00043 
00044 #ifdef USE_STRING_COERCE
00045 #include "py_capi_utils.h"
00046 #endif
00047 
00048 extern PyTypeObject BPy_IDArray_Type;
00049 extern PyTypeObject BPy_IDGroup_Iter_Type;
00050 extern PyTypeObject BPy_IDGroup_Type;
00051 
00052 /*********************** ID Property Main Wrapper Stuff ***************/
00053 
00054 /* use for both array and group */
00055 static long BPy_IDGroup_hash(BPy_IDProperty *self)
00056 {
00057         return _Py_HashPointer(self->prop);
00058 }
00059 
00060 static PyObject *BPy_IDGroup_repr(BPy_IDProperty *self)
00061 {
00062         return PyUnicode_FromFormat( "<bpy id property from \"%s\">", self->id->name);
00063 }
00064 
00065 PyObject *BPy_IDGroup_WrapData( ID *id, IDProperty *prop )
00066 {
00067         switch ( prop->type ) {
00068                 case IDP_STRING:
00069 #ifdef USE_STRING_COERCE
00070                         return PyC_UnicodeFromByte(IDP_Array(prop));
00071 #else
00072                         return PyUnicode_FromString(IDP_Array(prop));
00073 #endif
00074                 case IDP_INT:
00075                         return PyLong_FromLong( (long)prop->data.val );
00076                 case IDP_FLOAT:
00077                         return PyFloat_FromDouble( (double)(*(float*)(&prop->data.val)) );
00078                 case IDP_DOUBLE:
00079                         return PyFloat_FromDouble( (*(double*)(&prop->data.val)) );
00080                 case IDP_GROUP:
00081                         /*blegh*/
00082                         {
00083                                 BPy_IDProperty *group = PyObject_New(BPy_IDProperty, &BPy_IDGroup_Type);
00084                                 group->id = id;
00085                                 group->prop = prop;
00086                                 return (PyObject*) group;
00087                         }
00088                 case IDP_ARRAY:
00089                         {
00090                                 BPy_IDProperty *array = PyObject_New(BPy_IDProperty, &BPy_IDArray_Type);
00091                                 array->id = id;
00092                                 array->prop = prop;
00093                                 return (PyObject*) array;
00094                         }
00095                 case IDP_IDPARRAY: /* this could be better a internal type */
00096                         {
00097                                 PyObject *seq = PyList_New(prop->len), *wrap;
00098                                 IDProperty *array= IDP_IDPArray(prop);
00099                                 int i;
00100 
00101                                 if (!seq) {
00102                                         PyErr_Format(PyExc_RuntimeError, "BPy_IDGroup_MapDataToPy, IDP_IDPARRAY: PyList_New(%d) failed", prop->len);
00103                                         return NULL;
00104                                 }
00105 
00106                                 for (i=0; i<prop->len; i++) {
00107                                         wrap= BPy_IDGroup_WrapData(id, array++);
00108 
00109                                         if (!wrap) /* BPy_IDGroup_MapDataToPy sets the error */
00110                                                 return NULL;
00111 
00112                                         PyList_SET_ITEM(seq, i, wrap);
00113                                 }
00114 
00115                                 return seq;
00116                         }
00117                 /* case IDP_IDPARRAY: TODO */
00118         }
00119         Py_RETURN_NONE;
00120 }
00121 
00122 #if 0 /* UNUSED, currenly assignment overwrites into new properties, rather than setting in-place */
00123 static int BPy_IDGroup_SetData(BPy_IDProperty *self, IDProperty *prop, PyObject *value)
00124 {
00125         switch (prop->type) {
00126                 case IDP_STRING:
00127                 {
00128                         char *st;
00129                         if (!PyUnicode_Check(value)) {
00130                                 PyErr_SetString(PyExc_TypeError, "expected a string!");
00131                                 return -1;
00132                         }
00133 #ifdef USE_STRING_COERCE
00134                         {
00135                                 int alloc_len;
00136                                 PyObject *value_coerce= NULL;
00137 
00138                                 st= (char *)PyC_UnicodeAsByte(value, &value_coerce);
00139                                 alloc_len= strlen(st) + 1;
00140 
00141                                 st = _PyUnicode_AsString(value);
00142                                 IDP_ResizeArray(prop, alloc_len);
00143                                 memcpy(IDP_Array(prop), st, alloc_len);
00144                                 Py_XDECREF(value_coerce);
00145                         }
00146 #else
00147                         st = _PyUnicode_AsString(value);
00148                         IDP_ResizeArray(prop, strlen(st)+1);
00149                         strcpy(IDP_Array(prop), st);
00150 #endif
00151 
00152                         return 0;
00153                 }
00154 
00155                 case IDP_INT:
00156                 {
00157                         int ivalue= PyLong_AsSsize_t(value);
00158                         if (ivalue==-1 && PyErr_Occurred()) {
00159                                 PyErr_SetString(PyExc_TypeError, "expected an int type");
00160                                 return -1;
00161                         }
00162                         prop->data.val = ivalue;
00163                         break;
00164                 }
00165                 case IDP_FLOAT:
00166                 {
00167                         float fvalue= (float)PyFloat_AsDouble(value);
00168                         if (fvalue==-1 && PyErr_Occurred()) {
00169                                 PyErr_SetString(PyExc_TypeError, "expected a float");
00170                                 return -1;
00171                         }
00172                         *(float*)&self->prop->data.val = fvalue;
00173                         break;
00174                 }
00175                 case IDP_DOUBLE:
00176                 {
00177                         double dvalue= PyFloat_AsDouble(value);
00178                         if (dvalue==-1 && PyErr_Occurred()) {
00179                                 PyErr_SetString(PyExc_TypeError, "expected a float");
00180                                 return -1;
00181                         }
00182                         *(double*)&self->prop->data.val = dvalue;
00183                         break;
00184                 }
00185                 default:
00186                         PyErr_SetString(PyExc_AttributeError, "attempt to set read-only attribute!");
00187                         return -1;
00188         }
00189         return 0;
00190 }
00191 #endif
00192 
00193 static PyObject *BPy_IDGroup_GetName(BPy_IDProperty *self, void *UNUSED(closure))
00194 {
00195         return PyUnicode_FromString(self->prop->name);
00196 }
00197 
00198 static int BPy_IDGroup_SetName(BPy_IDProperty *self, PyObject *value, void *UNUSED(closure))
00199 {
00200         char *st;
00201         if (!PyUnicode_Check(value)) {
00202                 PyErr_SetString(PyExc_TypeError, "expected a string!");
00203                 return -1;
00204         }
00205 
00206         st = _PyUnicode_AsString(value);
00207         if (BLI_strnlen(st, MAX_IDPROP_NAME) == MAX_IDPROP_NAME) {
00208                 PyErr_SetString(PyExc_TypeError, "string length cannot exceed 31 characters!");
00209                 return -1;
00210         }
00211 
00212         BLI_strncpy(self->prop->name, st, sizeof(self->prop->name));
00213         return 0;
00214 }
00215 
00216 #if 0
00217 static PyObject *BPy_IDGroup_GetType(BPy_IDProperty *self)
00218 {
00219         return PyLong_FromSsize_t(self->prop->type);
00220 }
00221 #endif
00222 
00223 static PyGetSetDef BPy_IDGroup_getseters[] = {
00224         {(char *)"name", (getter)BPy_IDGroup_GetName, (setter)BPy_IDGroup_SetName, (char *)"The name of this Group.", NULL},
00225          {NULL, NULL, NULL, NULL, NULL}
00226 };
00227 
00228 static Py_ssize_t BPy_IDGroup_Map_Len(BPy_IDProperty *self)
00229 {
00230         if (self->prop->type != IDP_GROUP) {
00231                 PyErr_SetString(PyExc_TypeError, "len() of unsized object");
00232                 return -1;
00233         }
00234 
00235         return self->prop->len;
00236 }
00237 
00238 static PyObject *BPy_IDGroup_Map_GetItem(BPy_IDProperty *self, PyObject *item)
00239 {
00240         IDProperty *idprop;
00241         char *name;
00242 
00243         if (self->prop->type  != IDP_GROUP) {
00244                 PyErr_SetString(PyExc_TypeError, "unsubscriptable object");
00245                 return NULL;
00246         }
00247 
00248         name= _PyUnicode_AsString(item);
00249 
00250         if (name == NULL) {
00251                 PyErr_SetString(PyExc_TypeError, "only strings are allowed as keys of ID properties");
00252                 return NULL;
00253         }
00254 
00255         idprop= IDP_GetPropertyFromGroup(self->prop, name);
00256 
00257         if(idprop==NULL) {
00258                 PyErr_SetString(PyExc_KeyError, "key not in subgroup dict");
00259                 return NULL;
00260         }
00261 
00262         return BPy_IDGroup_WrapData(self->id, idprop);
00263 
00264 }
00265 
00266 /*returns NULL on success, error string on failure*/
00267 static int idp_sequence_type(PyObject *seq)
00268 {
00269         PyObject *item;
00270         int type= IDP_INT;
00271 
00272         int i, len = PySequence_Size(seq);
00273         for (i=0; i < len; i++) {
00274                 item = PySequence_GetItem(seq, i);
00275                 if (PyFloat_Check(item)) {
00276                         if(type == IDP_IDPARRAY) { /* mixed dict/int */
00277                                 Py_DECREF(item);
00278                                 return -1;
00279                         }
00280                         type= IDP_DOUBLE;
00281                 }
00282                 else if (PyLong_Check(item)) {
00283                         if(type == IDP_IDPARRAY) { /* mixed dict/int */
00284                                 Py_DECREF(item);
00285                                 return -1;
00286                         }
00287                 }
00288                 else if (PyMapping_Check(item)) {
00289                         if(i != 0 && (type != IDP_IDPARRAY)) { /* mixed dict/int */
00290                                 Py_DECREF(item);
00291                                 return -1;
00292                         }
00293                         type= IDP_IDPARRAY;
00294                 }
00295                 else {
00296                         Py_XDECREF(item);
00297                         return -1;
00298                 }
00299 
00300                 Py_DECREF(item);
00301         }
00302 
00303         return type;
00304 }
00305 
00306 /* note: group can be a pointer array or a group */
00307 const char *BPy_IDProperty_Map_ValidateAndCreate(const char *name, IDProperty *group, PyObject *ob)
00308 {
00309         IDProperty *prop = NULL;
00310         IDPropertyTemplate val = {0};
00311 
00312         if(strlen(name) >= sizeof(group->name))
00313                 return "the length of IDProperty names is limited to 31 characters";
00314 
00315         if (PyFloat_Check(ob)) {
00316                 val.d = PyFloat_AsDouble(ob);
00317                 prop = IDP_New(IDP_DOUBLE, val, name);
00318         }
00319         else if (PyLong_Check(ob)) {
00320                 val.i = (int) PyLong_AsSsize_t(ob);
00321                 prop = IDP_New(IDP_INT, val, name);
00322         }
00323         else if (PyUnicode_Check(ob)) {
00324 #ifdef USE_STRING_COERCE
00325                 PyObject *value_coerce= NULL;
00326                 val.str = (char *)PyC_UnicodeAsByte(ob, &value_coerce);
00327                 prop = IDP_New(IDP_STRING, val, name);
00328                 Py_XDECREF(value_coerce);
00329 #else
00330                 val.str = _PyUnicode_AsString(ob);
00331                 prop = IDP_New(IDP_STRING, val, name);
00332 #endif
00333         }
00334         else if (PySequence_Check(ob)) {
00335                 PyObject *item;
00336                 int i;
00337 
00338                 if((val.array.type= idp_sequence_type(ob)) == -1)
00339                         return "only floats, ints and dicts are allowed in ID property arrays";
00340 
00341                 /*validate sequence and derive type.
00342                 we assume IDP_INT unless we hit a float
00343                 number; then we assume it's */
00344 
00345                 val.array.len = PySequence_Size(ob);
00346 
00347                 switch(val.array.type) {
00348                 case IDP_DOUBLE:
00349                         prop = IDP_New(IDP_ARRAY, val, name);
00350                         for (i=0; i<val.array.len; i++) {
00351                                 item = PySequence_GetItem(ob, i);
00352                                 ((double*)IDP_Array(prop))[i] = (float)PyFloat_AsDouble(item);
00353                                 Py_DECREF(item);
00354                         }
00355                         break;
00356                 case IDP_INT:
00357                         prop = IDP_New(IDP_ARRAY, val, name);
00358                         for (i=0; i<val.array.len; i++) {
00359                                 item = PySequence_GetItem(ob, i);
00360                                 ((int*)IDP_Array(prop))[i] = (int)PyLong_AsSsize_t(item);
00361                                 Py_DECREF(item);
00362                         }
00363                         break;
00364                 case IDP_IDPARRAY:
00365                         prop= IDP_NewIDPArray(name);
00366                         for (i=0; i<val.array.len; i++) {
00367                                 const char *error;
00368                                 item = PySequence_GetItem(ob, i);
00369                                 error= BPy_IDProperty_Map_ValidateAndCreate("", prop, item);
00370                                 Py_DECREF(item);
00371 
00372                                 if(error)
00373                                         return error;
00374                         }
00375                         break;
00376                 }
00377         }
00378         else if (PyMapping_Check(ob)) {
00379                 PyObject *keys, *vals, *key, *pval;
00380                 int i, len;
00381                 /*yay! we get into recursive stuff now!*/
00382                 keys = PyMapping_Keys(ob);
00383                 vals = PyMapping_Values(ob);
00384 
00385                 /*we allocate the group first; if we hit any invalid data,
00386                   we can delete it easily enough.*/
00387                 prop = IDP_New(IDP_GROUP, val, name);
00388                 len = PyMapping_Length(ob);
00389                 for (i=0; i<len; i++) {
00390                         key = PySequence_GetItem(keys, i);
00391                         pval = PySequence_GetItem(vals, i);
00392                         if (!PyUnicode_Check(key)) {
00393                                 IDP_FreeProperty(prop);
00394                                 MEM_freeN(prop);
00395                                 Py_XDECREF(keys);
00396                                 Py_XDECREF(vals);
00397                                 Py_XDECREF(key);
00398                                 Py_XDECREF(pval);
00399                                 return "invalid element in subgroup dict template!";
00400                         }
00401                         if (BPy_IDProperty_Map_ValidateAndCreate(_PyUnicode_AsString(key), prop, pval)) {
00402                                 IDP_FreeProperty(prop);
00403                                 MEM_freeN(prop);
00404                                 Py_XDECREF(keys);
00405                                 Py_XDECREF(vals);
00406                                 Py_XDECREF(key);
00407                                 Py_XDECREF(pval);
00408                                 return "invalid element in subgroup dict template!";
00409                         }
00410                         Py_XDECREF(key);
00411                         Py_XDECREF(pval);
00412                 }
00413                 Py_XDECREF(keys);
00414                 Py_XDECREF(vals);
00415         }
00416         else return "invalid property value";
00417 
00418         if(group->type==IDP_IDPARRAY) {
00419                 IDP_AppendArray(group, prop);
00420                 // IDP_FreeProperty(item); // IDP_AppendArray does a shallow copy (memcpy), only free memory
00421                 MEM_freeN(prop);
00422         }
00423         else {
00424                 IDP_ReplaceInGroup(group, prop);
00425         }
00426 
00427         return NULL;
00428 }
00429 
00430 int BPy_Wrap_SetMapItem(IDProperty *prop, PyObject *key, PyObject *val)
00431 {
00432         if (prop->type  != IDP_GROUP) {
00433                 PyErr_SetString(PyExc_TypeError, "unsubscriptable object");
00434                 return -1;
00435         }
00436 
00437         if (val == NULL) { /* del idprop[key] */
00438                 IDProperty *pkey = IDP_GetPropertyFromGroup(prop, _PyUnicode_AsString(key));
00439                 if (pkey) {
00440                         IDP_RemFromGroup(prop, pkey);
00441                         IDP_FreeProperty(pkey);
00442                         MEM_freeN(pkey);
00443                         return 0;
00444                 }
00445                 else {
00446                         PyErr_SetString(PyExc_KeyError, "property not found in group");
00447                         return -1;
00448                 }
00449         }
00450         else {
00451                 const char *err;
00452 
00453                 if (!PyUnicode_Check(key)) {
00454                         PyErr_SetString(PyExc_TypeError, "only strings are allowed as subgroup keys");
00455                         return -1;
00456                 }
00457 
00458                 err = BPy_IDProperty_Map_ValidateAndCreate(_PyUnicode_AsString(key), prop, val);
00459                 if (err) {
00460                         PyErr_SetString(PyExc_KeyError, err );
00461                         return -1;
00462                 }
00463 
00464                 return 0;
00465         }
00466 }
00467 
00468 static int BPy_IDGroup_Map_SetItem(BPy_IDProperty *self, PyObject *key, PyObject *val)
00469 {
00470         return BPy_Wrap_SetMapItem(self->prop, key, val);
00471 }
00472 
00473 static PyObject *BPy_IDGroup_iter(BPy_IDProperty *self)
00474 {
00475         BPy_IDGroup_Iter *iter = PyObject_New(BPy_IDGroup_Iter, &BPy_IDGroup_Iter_Type);
00476         iter->group = self;
00477         iter->mode = IDPROP_ITER_KEYS;
00478         iter->cur = self->prop->data.group.first;
00479         Py_XINCREF(iter);
00480         return (PyObject*) iter;
00481 }
00482 
00483 static PyObject *BPy_IDGroup_MapDataToPy(IDProperty *prop)
00484 {
00485         switch (prop->type) {
00486                 case IDP_STRING:
00487 #ifdef USE_STRING_COERCE
00488                         return PyC_UnicodeFromByte(IDP_Array(prop));
00489 #else
00490                         return PyUnicode_FromString(IDP_Array(prop));
00491 #endif
00492                         break;
00493                 case IDP_FLOAT:
00494                         return PyFloat_FromDouble(*((float*)&prop->data.val));
00495                         break;
00496                 case IDP_DOUBLE:
00497                         return PyFloat_FromDouble(*((double*)&prop->data.val));
00498                         break;
00499                 case IDP_INT:
00500                         return PyLong_FromSsize_t( prop->data.val );
00501                         break;
00502                 case IDP_ARRAY:
00503                 {
00504                         PyObject *seq = PyList_New(prop->len);
00505                         int i;
00506 
00507                         if (!seq) {
00508                                 PyErr_Format(PyExc_RuntimeError, "BPy_IDGroup_MapDataToPy, IDP_ARRAY: PyList_New(%d) failed", prop->len);
00509                                 return NULL;
00510                         }
00511 
00512                         switch(prop->subtype) {
00513                                 case IDP_FLOAT:
00514                                 {
00515                                         float *array= (float*)IDP_Array(prop);
00516                                         for (i=0; i<prop->len; i++) {
00517                                                 PyList_SET_ITEM(seq, i, PyFloat_FromDouble(array[i]));
00518                                         }
00519                                         break;
00520                                 }
00521                                 case IDP_DOUBLE:
00522                                 {
00523                                         double *array= (double*)IDP_Array(prop);
00524                                         for (i=0; i<prop->len; i++) {
00525                                                 PyList_SET_ITEM(seq, i, PyFloat_FromDouble(array[i]));
00526                                         }
00527                                         break;
00528                                 }
00529                                 case IDP_INT:
00530                                 {
00531                                         int *array= (int*)IDP_Array(prop);
00532                                         for (i=0; i<prop->len; i++) {
00533                                                 PyList_SET_ITEM(seq, i, PyLong_FromLong(array[i]));
00534                                         }
00535                                         break;
00536                                 }
00537                                 default:
00538                                         PyErr_SetString(PyExc_RuntimeError, "invalid/corrupt array type!");
00539                                         Py_DECREF(seq);
00540                                         return NULL;
00541                         }
00542 
00543                         return seq;
00544                 }
00545                 case IDP_IDPARRAY:
00546                 {
00547                         PyObject *seq = PyList_New(prop->len), *wrap;
00548                         IDProperty *array= IDP_IDPArray(prop);
00549                         int i;
00550 
00551                         if (!seq) {
00552                                 PyErr_Format(PyExc_RuntimeError, "BPy_IDGroup_MapDataToPy, IDP_IDPARRAY: PyList_New(%d) failed", prop->len);
00553                                 return NULL;
00554                         }
00555 
00556                         for (i=0; i<prop->len; i++) {
00557                                 wrap= BPy_IDGroup_MapDataToPy(array++);
00558 
00559                                 if (!wrap) /* BPy_IDGroup_MapDataToPy sets the error */
00560                                         return NULL;
00561 
00562                                 PyList_SET_ITEM(seq, i, wrap);
00563                         }
00564                         return seq;
00565                 }
00566                 case IDP_GROUP:
00567                 {
00568                         PyObject *dict = PyDict_New(), *wrap;
00569                         IDProperty *loop;
00570 
00571                         for (loop=prop->data.group.first; loop; loop=loop->next) {
00572                                 wrap = BPy_IDGroup_MapDataToPy(loop);
00573 
00574                                 if (!wrap) /* BPy_IDGroup_MapDataToPy sets the error */
00575                                         return NULL;
00576 
00577                                 PyDict_SetItemString(dict, loop->name, wrap);
00578                                 Py_DECREF(wrap);
00579                         }
00580                         return dict;
00581                 }
00582         }
00583 
00584         PyErr_Format(PyExc_RuntimeError, "eek!! '%s' property exists with a bad type code '%d' !!!", prop->name, prop->type);
00585         return NULL;
00586 }
00587 
00588 static PyObject *BPy_IDGroup_Pop(BPy_IDProperty *self, PyObject *value)
00589 {
00590         IDProperty *idprop;
00591         PyObject *pyform;
00592         char *name = _PyUnicode_AsString(value);
00593 
00594         if (!name) {
00595                 PyErr_SetString(PyExc_TypeError, "pop expected at least 1 argument, got 0");
00596                 return NULL;
00597         }
00598 
00599         idprop= IDP_GetPropertyFromGroup(self->prop, name);
00600 
00601         if(idprop) {
00602                 pyform = BPy_IDGroup_MapDataToPy(idprop);
00603 
00604                 if (!pyform) {
00605                         /*ok something bad happened with the pyobject,
00606                           so don't remove the prop from the group.  if pyform is
00607                           NULL, then it already should have raised an exception.*/
00608                         return NULL;
00609                 }
00610 
00611                 IDP_RemFromGroup(self->prop, idprop);
00612                 return pyform;
00613         }
00614 
00615         PyErr_SetString(PyExc_KeyError, "item not in group");
00616         return NULL;
00617 }
00618 
00619 static PyObject *BPy_IDGroup_IterItems(BPy_IDProperty *self)
00620 {
00621         BPy_IDGroup_Iter *iter = PyObject_New(BPy_IDGroup_Iter, &BPy_IDGroup_Iter_Type);
00622         iter->group = self;
00623         iter->mode = IDPROP_ITER_ITEMS;
00624         iter->cur = self->prop->data.group.first;
00625         Py_XINCREF(iter);
00626         return (PyObject*) iter;
00627 }
00628 
00629 /* utility function */
00630 static void BPy_IDGroup_CorrectListLen(IDProperty *prop, PyObject *seq, int len)
00631 {
00632         int j;
00633 
00634         printf("ID Property Error found and corrected in BPy_IDGroup_GetKeys/Values/Items!\n");
00635 
00636         /*fill rest of list with valid references to None*/
00637         for (j=len; j<prop->len; j++) {
00638                 Py_INCREF(Py_None);
00639                 PyList_SET_ITEM(seq, j, Py_None);
00640         }
00641 
00642         /*set correct group length*/
00643         prop->len = len;
00644 }
00645 
00646 PyObject *BPy_Wrap_GetKeys(IDProperty *prop)
00647 {
00648         PyObject *seq = PyList_New(prop->len);
00649         IDProperty *loop;
00650         int i;
00651 
00652         for (i=0, loop=prop->data.group.first; loop && (i < prop->len); loop=loop->next, i++)
00653                 PyList_SET_ITEM(seq, i, PyUnicode_FromString(loop->name));
00654 
00655         /* if the id prop is corrupt, count the remaining */
00656         for (; loop; loop=loop->next, i++) {}
00657 
00658         if (i != prop->len) { /* if the loop didnt finish, we know the length is wrong */
00659                 BPy_IDGroup_CorrectListLen(prop, seq, i);
00660                 Py_DECREF(seq); /*free the list*/
00661                 /*call self again*/
00662                 return BPy_Wrap_GetKeys(prop);
00663         }
00664 
00665         return seq;
00666 }
00667 
00668 PyObject *BPy_Wrap_GetValues(ID *id, IDProperty *prop)
00669 {
00670         PyObject *seq = PyList_New(prop->len);
00671         IDProperty *loop;
00672         int i;
00673 
00674         for (i=0, loop=prop->data.group.first; loop; loop=loop->next, i++) {
00675                 PyList_SET_ITEM(seq, i, BPy_IDGroup_WrapData(id, loop));
00676         }
00677 
00678         if (i != prop->len) {
00679                 BPy_IDGroup_CorrectListLen(prop, seq, i);
00680                 Py_DECREF(seq); /*free the list*/
00681                 /*call self again*/
00682                 return BPy_Wrap_GetValues(id, prop);
00683         }
00684 
00685         return seq;
00686 }
00687 
00688 PyObject *BPy_Wrap_GetItems(ID *id, IDProperty *prop)
00689 {
00690         PyObject *seq = PyList_New(prop->len);
00691         IDProperty *loop;
00692         int i;
00693 
00694         for (i=0, loop=prop->data.group.first; loop; loop=loop->next, i++) {
00695                 PyObject *item= PyTuple_New(2);
00696                 PyTuple_SET_ITEM(item, 0, PyUnicode_FromString(loop->name));
00697                 PyTuple_SET_ITEM(item, 1, BPy_IDGroup_WrapData(id, loop));
00698                 PyList_SET_ITEM(seq, i, item);
00699         }
00700 
00701         if (i != prop->len) {
00702                 BPy_IDGroup_CorrectListLen(prop, seq, i);
00703                 Py_DECREF(seq); /*free the list*/
00704                 /*call self again*/
00705                 return BPy_Wrap_GetItems(id, prop);
00706         }
00707 
00708         return seq;
00709 }
00710 
00711 
00712 static PyObject *BPy_IDGroup_GetKeys(BPy_IDProperty *self)
00713 {
00714         return BPy_Wrap_GetKeys(self->prop);
00715 }
00716 
00717 static PyObject *BPy_IDGroup_GetValues(BPy_IDProperty *self)
00718 {
00719         return BPy_Wrap_GetValues(self->id, self->prop);
00720 }
00721 
00722 static PyObject *BPy_IDGroup_GetItems(BPy_IDProperty *self)
00723 {
00724         return BPy_Wrap_GetItems(self->id, self->prop);
00725 }
00726 
00727 static int BPy_IDGroup_Contains(BPy_IDProperty *self, PyObject *value)
00728 {
00729         char *name = _PyUnicode_AsString(value);
00730 
00731         if (!name) {
00732                 PyErr_SetString(PyExc_TypeError, "expected a string");
00733                 return -1;
00734         }
00735 
00736         return IDP_GetPropertyFromGroup(self->prop, name) ? 1:0;
00737 }
00738 
00739 static PyObject *BPy_IDGroup_Update(BPy_IDProperty *self, PyObject *value)
00740 {
00741         PyObject *pkey, *pval;
00742         Py_ssize_t i=0;
00743 
00744         if (!PyDict_Check(value)) {
00745                 PyErr_SetString(PyExc_TypeError, "expected an object derived from dict");
00746                 return NULL;
00747         }
00748 
00749         while (PyDict_Next(value, &i, &pkey, &pval)) {
00750                 BPy_IDGroup_Map_SetItem(self, pkey, pval);
00751                 if (PyErr_Occurred()) return NULL;
00752         }
00753 
00754         Py_RETURN_NONE;
00755 }
00756 
00757 static PyObject *BPy_IDGroup_to_dict(BPy_IDProperty *self)
00758 {
00759         return BPy_IDGroup_MapDataToPy(self->prop);
00760 }
00761 
00762 
00763 /* Matches python dict.get(key, [default]) */
00764 static PyObject* BPy_IDGroup_Get(BPy_IDProperty *self, PyObject *args)
00765 {
00766         IDProperty *idprop;
00767         char *key;
00768         PyObject* def = Py_None;
00769 
00770         if (!PyArg_ParseTuple(args, "s|O:get", &key, &def))
00771                 return NULL;
00772 
00773         idprop= IDP_GetPropertyFromGroup(self->prop, key);
00774         if (idprop) {
00775                 PyObject* pyobj = BPy_IDGroup_WrapData(self->id, idprop);
00776                 if (pyobj)
00777                         return pyobj;
00778         }
00779 
00780         Py_INCREF(def);
00781         return def;
00782 }
00783 
00784 static struct PyMethodDef BPy_IDGroup_methods[] = {
00785         {"pop", (PyCFunction)BPy_IDGroup_Pop, METH_O,
00786                 "pop an item from the group; raises KeyError if the item doesn't exist"},
00787         {"iteritems", (PyCFunction)BPy_IDGroup_IterItems, METH_NOARGS,
00788                 "iterate through the items in the dict; behaves like dictionary method iteritems"},
00789         {"keys", (PyCFunction)BPy_IDGroup_GetKeys, METH_NOARGS,
00790                 "get the keys associated with this group as a list of strings"},
00791         {"values", (PyCFunction)BPy_IDGroup_GetValues, METH_NOARGS,
00792                 "get the values associated with this group"},
00793         {"items", (PyCFunction)BPy_IDGroup_GetItems, METH_NOARGS,
00794                 "get the items associated with this group"},
00795         {"update", (PyCFunction)BPy_IDGroup_Update, METH_O,
00796                 "updates the values in the group with the values of another or a dict"},
00797         {"get", (PyCFunction)BPy_IDGroup_Get, METH_VARARGS,
00798                 "idprop.get(k[,d]) -> idprop[k] if k in idprop, else d.  d defaults to None"},
00799         {"to_dict", (PyCFunction)BPy_IDGroup_to_dict, METH_NOARGS,
00800                 "return a purely python version of the group"},
00801         {NULL, NULL, 0, NULL}
00802 };
00803 
00804 static PySequenceMethods BPy_IDGroup_Seq = {
00805         (lenfunc) BPy_IDGroup_Map_Len,          /* lenfunc sq_length */
00806         NULL,                                                           /* binaryfunc sq_concat */
00807         NULL,                                                           /* ssizeargfunc sq_repeat */
00808         NULL,                                                           /* ssizeargfunc sq_item */ /* TODO - setting this will allow PySequence_Check to return True */
00809         NULL,                                                           /* intintargfunc ***was_sq_slice*** */
00810         NULL,                                                           /* intobjargproc sq_ass_item */
00811         NULL,                                                           /* ssizeobjargproc ***was_sq_ass_slice*** */
00812         (objobjproc) BPy_IDGroup_Contains,      /* objobjproc sq_contains */
00813         NULL,                                                           /* binaryfunc sq_inplace_concat */
00814         NULL,                                                           /* ssizeargfunc sq_inplace_repeat */
00815 };
00816 
00817 static PyMappingMethods BPy_IDGroup_Mapping = {
00818         (lenfunc)BPy_IDGroup_Map_Len,           /*inquiry mp_length */
00819         (binaryfunc)BPy_IDGroup_Map_GetItem,/*binaryfunc mp_subscript */
00820         (objobjargproc)BPy_IDGroup_Map_SetItem, /*objobjargproc mp_ass_subscript */
00821 };
00822 
00823 PyTypeObject BPy_IDGroup_Type = {
00824         PyVarObject_HEAD_INIT(NULL, 0)
00825         /*  For printing, in format "<module>.<name>" */
00826         "Blender IDProperty",           /* char *tp_name; */
00827         sizeof(BPy_IDProperty),         /* int tp_basicsize; */
00828         0,                          /* tp_itemsize;  For allocation */
00829 
00830         /* Methods to implement standard operations */
00831 
00832         NULL,                                           /* destructor tp_dealloc; */
00833         NULL,                       /* printfunc tp_print; */
00834         NULL,     /* getattrfunc tp_getattr; */
00835         NULL,     /* setattrfunc tp_setattr; */
00836         NULL,                       /* cmpfunc tp_compare; */
00837         (reprfunc)BPy_IDGroup_repr,     /* reprfunc tp_repr; */
00838 
00839         /* Method suites for standard classes */
00840 
00841         NULL,                       /* PyNumberMethods *tp_as_number; */
00842         &BPy_IDGroup_Seq,                       /* PySequenceMethods *tp_as_sequence; */
00843         &BPy_IDGroup_Mapping,           /* PyMappingMethods *tp_as_mapping; */
00844 
00845         /* More standard operations (here for binary compatibility) */
00846 
00847         (hashfunc)BPy_IDGroup_hash, /* hashfunc tp_hash; */
00848         NULL,                       /* ternaryfunc tp_call; */
00849         NULL,                       /* reprfunc tp_str; */
00850         NULL,                       /* getattrofunc tp_getattro; */
00851         NULL,                       /* setattrofunc tp_setattro; */
00852 
00853         /* Functions to access object as input/output buffer */
00854         NULL,                       /* PyBufferProcs *tp_as_buffer; */
00855 
00856   /*** Flags to define presence of optional/expanded features ***/
00857         Py_TPFLAGS_DEFAULT,         /* long tp_flags; */
00858 
00859         NULL,                       /*  char *tp_doc;  Documentation string */
00860   /*** Assigned meaning in release 2.0 ***/
00861         /* call function for all accessible objects */
00862         NULL,                       /* traverseproc tp_traverse; */
00863 
00864         /* delete references to contained objects */
00865         NULL,                       /* inquiry tp_clear; */
00866 
00867   /***  Assigned meaning in release 2.1 ***/
00868   /*** rich comparisons ***/
00869         NULL,                       /* richcmpfunc tp_richcompare; */
00870 
00871   /***  weak reference enabler ***/
00872         0,                          /* long tp_weaklistoffset; */
00873 
00874   /*** Added in release 2.2 ***/
00875         /*   Iterators */
00876         (getiterfunc)BPy_IDGroup_iter, /* getiterfunc tp_iter; */
00877         NULL,                       /* iternextfunc tp_iternext; */
00878   /*** Attribute descriptor and subclassing stuff ***/
00879         BPy_IDGroup_methods,        /* struct PyMethodDef *tp_methods; */
00880         NULL,                       /* struct PyMemberDef *tp_members; */
00881         BPy_IDGroup_getseters,       /* struct PyGetSetDef *tp_getset; */
00882 };
00883 
00884 /*********** Main external wrapping function *******/
00885 PyObject *BPy_Wrap_IDProperty(ID *id, IDProperty *prop, IDProperty *parent)
00886 {
00887         BPy_IDProperty *wrap = PyObject_New(BPy_IDProperty, &BPy_IDGroup_Type);
00888         wrap->prop = prop;
00889         wrap->parent = parent;
00890         wrap->id = id;
00891         //wrap->destroy = 0;
00892         return (PyObject*) wrap;
00893 }
00894 
00895 
00896 /********Array Wrapper********/
00897 
00898 static PyTypeObject *idp_array_py_type(BPy_IDArray *self, short *is_double)
00899 {
00900         switch (self->prop->subtype) {
00901                 case IDP_FLOAT:
00902                         *is_double= 0;
00903                         return &PyFloat_Type;
00904                 case IDP_DOUBLE:
00905                         *is_double= 1;
00906                         return &PyFloat_Type;
00907                 case IDP_INT:
00908                         *is_double= 0;
00909                         return &PyLong_Type;
00910         }
00911 
00912         *is_double= 0;
00913         return NULL;
00914 }
00915 
00916 static PyObject *BPy_IDArray_repr(BPy_IDArray *self)
00917 {
00918         return PyUnicode_FromFormat("<bpy id property array [%d]>", self->prop->len);
00919 }
00920 
00921 static PyObject *BPy_IDArray_GetType(BPy_IDArray *self)
00922 {
00923         switch(self->prop->subtype) {
00924         case IDP_FLOAT:
00925                 return PyUnicode_FromString("f");
00926         case IDP_DOUBLE:
00927                 return PyUnicode_FromString("d");
00928         case IDP_INT:
00929                 return PyUnicode_FromString("i");
00930         }
00931 
00932         PyErr_SetString(PyExc_RuntimeError, "invalid/corrupt array type!");
00933         return NULL;
00934 }
00935 
00936 static PyGetSetDef BPy_IDArray_getseters[] = {
00937     /* matches pythons array.typecode */
00938         {(char *)"typecode", (getter)BPy_IDArray_GetType, (setter)NULL, (char *)"The type of the data in the array, is an int.", NULL},
00939         {NULL, NULL, NULL, NULL, NULL},
00940 };
00941 
00942 static PyObject *BPy_IDArray_to_list(BPy_IDArray *self)
00943 {
00944         return BPy_IDGroup_MapDataToPy(self->prop);
00945 }
00946 
00947 static PyMethodDef BPy_IDArray_methods[] = {
00948         {"to_list", (PyCFunction)BPy_IDArray_to_list, METH_NOARGS,
00949                 "return the array as a list"},
00950         {NULL, NULL, 0, NULL}
00951 };
00952 
00953 static int BPy_IDArray_Len(BPy_IDArray *self)
00954 {
00955         return self->prop->len;
00956 }
00957 
00958 static PyObject *BPy_IDArray_GetItem(BPy_IDArray *self, int index)
00959 {
00960         if (index < 0 || index >= self->prop->len) {
00961                 PyErr_SetString(PyExc_IndexError, "index out of range!");
00962                 return NULL;
00963         }
00964 
00965         switch (self->prop->subtype) {
00966                 case IDP_FLOAT:
00967                         return PyFloat_FromDouble(((float*)IDP_Array(self->prop))[index]);
00968                 case IDP_DOUBLE:
00969                         return PyFloat_FromDouble(((double*)IDP_Array(self->prop))[index]);
00970                 case IDP_INT:
00971                         return PyLong_FromLong((long)((int*)IDP_Array(self->prop))[index]);
00972         }
00973 
00974         PyErr_SetString(PyExc_RuntimeError, "invalid/corrupt array type!");
00975         return NULL;
00976 }
00977 
00978 static int BPy_IDArray_SetItem(BPy_IDArray *self, int index, PyObject *value)
00979 {
00980         int i;
00981         float f;
00982         double d;
00983 
00984         if (index < 0 || index >= self->prop->len) {
00985                 PyErr_SetString(PyExc_RuntimeError, "index out of range!");
00986                 return -1;
00987         }
00988 
00989         switch (self->prop->subtype) {
00990                 case IDP_FLOAT:
00991                         f= (float)PyFloat_AsDouble(value);
00992                         if (f==-1 && PyErr_Occurred()) {
00993                                 PyErr_SetString(PyExc_TypeError, "expected a float");
00994                                 return -1;
00995                         }
00996                         ((float*)IDP_Array(self->prop))[index] = f;
00997                         break;
00998                 case IDP_DOUBLE:
00999                         d= PyFloat_AsDouble(value);
01000                         if (d==-1 && PyErr_Occurred()) {
01001                                 PyErr_SetString(PyExc_TypeError, "expected a float");
01002                                 return -1;
01003                         }
01004                         ((double*)IDP_Array(self->prop))[index] = d;
01005                         break;
01006                 case IDP_INT:
01007                         i= PyLong_AsSsize_t(value);
01008                         if (i==-1 && PyErr_Occurred()) {
01009                                 PyErr_SetString(PyExc_TypeError, "expected an int type");
01010                                 return -1;
01011                         }
01012 
01013                         ((int*)IDP_Array(self->prop))[index] = i;
01014                         break;
01015         }
01016         return 0;
01017 }
01018 
01019 static PySequenceMethods BPy_IDArray_Seq = {
01020         (lenfunc) BPy_IDArray_Len,                      /* inquiry sq_length */
01021         NULL,                                                           /* binaryfunc sq_concat */
01022         NULL,                                                           /* intargfunc sq_repeat */
01023         (ssizeargfunc)BPy_IDArray_GetItem,      /* intargfunc sq_item */
01024         NULL,                                                           /* intintargfunc sq_slice */
01025         (ssizeobjargproc)BPy_IDArray_SetItem,/* intobjargproc sq_ass_item */
01026         NULL,                                                           /* intintobjargproc sq_ass_slice */
01027         NULL,                                                           /* objobjproc sq_contains */
01028                                 /* Added in release 2.0 */
01029         NULL,                                                           /* binaryfunc sq_inplace_concat */
01030         NULL,                                                           /* intargfunc sq_inplace_repeat */
01031 };
01032 
01033 
01034 
01035 /* sequence slice (get): idparr[a:b] */
01036 static PyObject *BPy_IDArray_slice(BPy_IDArray *self, int begin, int end)
01037 {
01038         IDProperty *prop= self->prop;
01039         PyObject *tuple;
01040         int count;
01041 
01042         CLAMP(begin, 0, prop->len);
01043         if (end<0) end= prop->len+end+1;
01044         CLAMP(end, 0, prop->len);
01045         begin= MIN2(begin, end);
01046 
01047         tuple= PyTuple_New(end - begin);
01048 
01049         switch (prop->subtype) {
01050                 case IDP_FLOAT:
01051                 {
01052                         float *array= (float*)IDP_Array(prop);
01053                         for(count = begin; count < end; count++) {
01054                                 PyTuple_SET_ITEM(tuple, count - begin, PyFloat_FromDouble(array[count]));
01055                         }
01056                         break;
01057                 }
01058                 case IDP_DOUBLE:
01059                 {
01060                         double *array= (double*)IDP_Array(prop);
01061                         for(count = begin; count < end; count++) {
01062                                 PyTuple_SET_ITEM(tuple, count - begin, PyFloat_FromDouble(array[count]));
01063                         }
01064                         break;
01065                 }
01066                 case IDP_INT:
01067                 {
01068                         int *array= (int*)IDP_Array(prop);
01069                         for(count = begin; count < end; count++) {
01070                                 PyTuple_SET_ITEM(tuple, count - begin, PyLong_FromLong(array[count]));
01071                         }
01072                         break;
01073                 }
01074         }
01075 
01076         return tuple;
01077 }
01078 /* sequence slice (set): idparr[a:b] = value */
01079 static int BPy_IDArray_ass_slice(BPy_IDArray *self, int begin, int end, PyObject *seq)
01080 {
01081         IDProperty *prop= self->prop;
01082         short is_double= 0;
01083         const PyTypeObject *py_type= idp_array_py_type(self, &is_double);
01084         const size_t elem_size= is_double ? sizeof(double) : sizeof(float);
01085         size_t alloc_len;
01086         size_t size;
01087         void *vec;
01088 
01089         CLAMP(begin, 0, prop->len);
01090         CLAMP(end, 0, prop->len);
01091         begin = MIN2(begin, end);
01092 
01093         size = (end - begin);
01094         alloc_len= size * elem_size;
01095 
01096         vec= MEM_mallocN(alloc_len, "array assignment"); /* NOTE: we count on int/float being the same size here */
01097         if(PyC_AsArray(vec, seq, size, py_type, is_double, "slice assignment: ") == -1) {
01098                 MEM_freeN(vec);
01099                 return -1;
01100         }
01101 
01102         memcpy((void *)(((char *)IDP_Array(prop)) + (begin * elem_size)), vec, alloc_len);
01103 
01104         MEM_freeN(vec);
01105         return 0;
01106 }
01107 
01108 static PyObject *BPy_IDArray_subscript(BPy_IDArray* self, PyObject* item)
01109 {
01110         if (PyIndex_Check(item)) {
01111                 Py_ssize_t i;
01112                 i = PyNumber_AsSsize_t(item, PyExc_IndexError);
01113                 if (i == -1 && PyErr_Occurred())
01114                         return NULL;
01115                 if (i < 0)
01116                         i += self->prop->len;
01117                 return BPy_IDArray_GetItem(self, i);
01118         }
01119         else if (PySlice_Check(item)) {
01120                 Py_ssize_t start, stop, step, slicelength;
01121 
01122                 if (PySlice_GetIndicesEx((void *)item, self->prop->len, &start, &stop, &step, &slicelength) < 0)
01123                         return NULL;
01124 
01125                 if (slicelength <= 0) {
01126                         return PyTuple_New(0);
01127                 }
01128                 else if (step == 1) {
01129                         return BPy_IDArray_slice(self, start, stop);
01130                 }
01131                 else {
01132                         PyErr_SetString(PyExc_TypeError, "slice steps not supported with vectors");
01133                         return NULL;
01134                 }
01135         }
01136         else {
01137                 PyErr_Format(PyExc_TypeError, "vector indices must be integers, not %.200s", Py_TYPE(item)->tp_name);
01138                 return NULL;
01139         }
01140 }
01141 
01142 static int BPy_IDArray_ass_subscript(BPy_IDArray* self, PyObject* item, PyObject* value)
01143 {
01144         if (PyIndex_Check(item)) {
01145                 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
01146                 if (i == -1 && PyErr_Occurred())
01147                         return -1;
01148                 if (i < 0)
01149                         i += self->prop->len;
01150                 return BPy_IDArray_SetItem(self, i, value);
01151         }
01152         else if (PySlice_Check(item)) {
01153                 Py_ssize_t start, stop, step, slicelength;
01154 
01155                 if (PySlice_GetIndicesEx((void *)item, self->prop->len, &start, &stop, &step, &slicelength) < 0)
01156                         return -1;
01157 
01158                 if (step == 1)
01159                         return BPy_IDArray_ass_slice(self, start, stop, value);
01160                 else {
01161                         PyErr_SetString(PyExc_TypeError, "slice steps not supported with vectors");
01162                         return -1;
01163                 }
01164         }
01165         else {
01166                 PyErr_Format(PyExc_TypeError, "vector indices must be integers, not %.200s", Py_TYPE(item)->tp_name);
01167                 return -1;
01168         }
01169 }
01170 
01171 static PyMappingMethods BPy_IDArray_AsMapping = {
01172         (lenfunc)BPy_IDArray_Len,
01173         (binaryfunc)BPy_IDArray_subscript,
01174         (objobjargproc)BPy_IDArray_ass_subscript
01175 };
01176 
01177 
01178 PyTypeObject BPy_IDArray_Type = {
01179         PyVarObject_HEAD_INIT(NULL, 0)
01180         /*  For printing, in format "<module>.<name>" */
01181         "Blender IDArray",           /* char *tp_name; */
01182         sizeof(BPy_IDArray),       /* int tp_basicsize; */
01183         0,                          /* tp_itemsize;  For allocation */
01184 
01185         /* Methods to implement standard operations */
01186 
01187         NULL,                                           /* destructor tp_dealloc; */
01188         NULL,                       /* printfunc tp_print; */
01189         NULL,     /* getattrfunc tp_getattr; */
01190         NULL,     /* setattrfunc tp_setattr; */
01191         NULL,                       /* cmpfunc tp_compare; */
01192         (reprfunc)BPy_IDArray_repr,     /* reprfunc tp_repr; */
01193 
01194         /* Method suites for standard classes */
01195 
01196         NULL,                       /* PyNumberMethods *tp_as_number; */
01197         &BPy_IDArray_Seq,               /* PySequenceMethods *tp_as_sequence; */
01198         &BPy_IDArray_AsMapping,     /* PyMappingMethods *tp_as_mapping; */
01199 
01200         /* More standard operations (here for binary compatibility) */
01201 
01202         NULL,                                           /* hashfunc tp_hash; */
01203         NULL,                       /* ternaryfunc tp_call; */
01204         NULL,                       /* reprfunc tp_str; */
01205         NULL,                       /* getattrofunc tp_getattro; */
01206         NULL,                       /* setattrofunc tp_setattro; */
01207 
01208         /* Functions to access object as input/output buffer */
01209         NULL,                       /* PyBufferProcs *tp_as_buffer; */
01210 
01211   /*** Flags to define presence of optional/expanded features ***/
01212         Py_TPFLAGS_DEFAULT,         /* long tp_flags; */
01213 
01214         NULL,                       /*  char *tp_doc;  Documentation string */
01215   /*** Assigned meaning in release 2.0 ***/
01216         /* call function for all accessible objects */
01217         NULL,                       /* traverseproc tp_traverse; */
01218 
01219         /* delete references to contained objects */
01220         NULL,                       /* inquiry tp_clear; */
01221 
01222   /***  Assigned meaning in release 2.1 ***/
01223   /*** rich comparisons ***/
01224         NULL,                       /* richcmpfunc tp_richcompare; */
01225 
01226   /***  weak reference enabler ***/
01227         0,                          /* long tp_weaklistoffset; */
01228 
01229   /*** Added in release 2.2 ***/
01230         /*   Iterators */
01231         NULL,                       /* getiterfunc tp_iter; */
01232         NULL,                       /* iternextfunc tp_iternext; */
01233 
01234   /*** Attribute descriptor and subclassing stuff ***/
01235         BPy_IDArray_methods,            /* struct PyMethodDef *tp_methods; */
01236         NULL,                       /* struct PyMemberDef *tp_members; */
01237         BPy_IDArray_getseters,       /* struct PyGetSetDef *tp_getset; */
01238         NULL,                       /* struct _typeobject *tp_base; */
01239         NULL,                       /* PyObject *tp_dict; */
01240         NULL,                       /* descrgetfunc tp_descr_get; */
01241         NULL,                       /* descrsetfunc tp_descr_set; */
01242         0,                          /* long tp_dictoffset; */
01243         NULL,                       /* initproc tp_init; */
01244         NULL,                       /* allocfunc tp_alloc; */
01245         NULL,                       /* newfunc tp_new; */
01246         /*  Low-level free-memory routine */
01247         NULL,                       /* freefunc tp_free;  */
01248         /* For PyObject_IS_GC */
01249         NULL,                       /* inquiry tp_is_gc;  */
01250         NULL,                       /* PyObject *tp_bases; */
01251         /* method resolution order */
01252         NULL,                       /* PyObject *tp_mro;  */
01253         NULL,                       /* PyObject *tp_cache; */
01254         NULL,                       /* PyObject *tp_subclasses; */
01255         NULL,                       /* PyObject *tp_weaklist; */
01256         NULL
01257 };
01258 
01259 /*********** ID Property Group iterator ********/
01260 
01261 static PyObject *IDGroup_Iter_iterself(PyObject *self)
01262 {
01263         Py_XINCREF(self);
01264         return self;
01265 }
01266 
01267 static PyObject *IDGroup_Iter_repr(BPy_IDGroup_Iter *self)
01268 {
01269         return PyUnicode_FromFormat("(ID Property Group Iter \"%s\")", self->group->prop->name);
01270 }
01271 
01272 static PyObject *BPy_Group_Iter_Next(BPy_IDGroup_Iter *self)
01273 {
01274         IDProperty *cur=NULL;
01275         PyObject *ret;
01276 
01277         if (self->cur) {
01278                 cur = self->cur;
01279                 self->cur = self->cur->next;
01280                 if (self->mode == IDPROP_ITER_ITEMS) {
01281                         ret = PyTuple_New(2);
01282                         PyTuple_SET_ITEM(ret, 0, PyUnicode_FromString(cur->name));
01283                         PyTuple_SET_ITEM(ret, 1, BPy_IDGroup_WrapData(self->group->id, cur));
01284                         return ret;
01285                 }
01286                 else {
01287                         return PyUnicode_FromString(cur->name);
01288                 }
01289         }
01290         else {
01291                 PyErr_SetString(PyExc_StopIteration, "iterator at end");
01292                 return NULL;
01293         }
01294 }
01295 
01296 PyTypeObject BPy_IDGroup_Iter_Type = {
01297         PyVarObject_HEAD_INIT(NULL, 0)
01298         /*  For printing, in format "<module>.<name>" */
01299         "Blender IDGroup_Iter",           /* char *tp_name; */
01300         sizeof( BPy_IDGroup_Iter ),       /* int tp_basicsize; */
01301         0,                          /* tp_itemsize;  For allocation */
01302 
01303         /* Methods to implement standard operations */
01304 
01305         NULL,                                           /* destructor tp_dealloc; */
01306         NULL,                       /* printfunc tp_print; */
01307         NULL,     /* getattrfunc tp_getattr; */
01308         NULL,     /* setattrfunc tp_setattr; */
01309         NULL,                       /* cmpfunc tp_compare; */
01310         ( reprfunc ) IDGroup_Iter_repr,     /* reprfunc tp_repr; */
01311 
01312         /* Method suites for standard classes */
01313 
01314         NULL,                       /* PyNumberMethods *tp_as_number; */
01315         NULL,                                           /* PySequenceMethods *tp_as_sequence; */
01316         NULL,                       /* PyMappingMethods *tp_as_mapping; */
01317 
01318         /* More standard operations (here for binary compatibility) */
01319 
01320         NULL,                       /* hashfunc tp_hash; */
01321         NULL,                       /* ternaryfunc tp_call; */
01322         NULL,                       /* reprfunc tp_str; */
01323         NULL,                       /* getattrofunc tp_getattro; */
01324         NULL,                       /* setattrofunc tp_setattro; */
01325 
01326         /* Functions to access object as input/output buffer */
01327         NULL,                       /* PyBufferProcs *tp_as_buffer; */
01328 
01329   /*** Flags to define presence of optional/expanded features ***/
01330         Py_TPFLAGS_DEFAULT,         /* long tp_flags; */
01331 
01332         NULL,                       /*  char *tp_doc;  Documentation string */
01333   /*** Assigned meaning in release 2.0 ***/
01334         /* call function for all accessible objects */
01335         NULL,                       /* traverseproc tp_traverse; */
01336 
01337         /* delete references to contained objects */
01338         NULL,                       /* inquiry tp_clear; */
01339 
01340   /***  Assigned meaning in release 2.1 ***/
01341   /*** rich comparisons ***/
01342         NULL,                       /* richcmpfunc tp_richcompare; */
01343 
01344   /***  weak reference enabler ***/
01345         0,                          /* long tp_weaklistoffset; */
01346 
01347   /*** Added in release 2.2 ***/
01348         /*   Iterators */
01349         IDGroup_Iter_iterself,              /* getiterfunc tp_iter; */
01350         (iternextfunc) BPy_Group_Iter_Next, /* iternextfunc tp_iternext; */
01351 };
01352 
01353 void IDProp_Init_Types(void)
01354 {
01355         PyType_Ready(&BPy_IDGroup_Type);
01356         PyType_Ready(&BPy_IDGroup_Iter_Type);
01357         PyType_Ready(&BPy_IDArray_Type);
01358 }