RNA
[blender.git] / source / blender / makesrna / intern / rna_access.c
1 /**
2  * $Id$
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  * Contributor(s): Blender Foundation (2008).
21  *
22  * ***** END GPL LICENSE BLOCK *****
23  */
24
25 #include <stdlib.h>
26 #include <string.h>
27
28 #include "MEM_guardedalloc.h"
29
30 #include "BLI_blenlib.h"
31 #include "BLI_dynstr.h"
32
33 #include "RNA_access.h"
34 #include "RNA_types.h"
35
36 #include "rna_internal.h"
37
38 /* Pointer */
39
40 void RNA_pointer_main_get(struct Main *main, struct PointerRNA *r_ptr)
41 {
42         r_ptr->data= main;
43         r_ptr->type= &RNA_Main;
44         r_ptr->id.data= NULL;
45         r_ptr->id.type= NULL;
46 }
47
48 static void rna_pointer_inherit_id(PointerRNA *parent, PointerRNA *ptr)
49 {
50         if(ptr->type && ptr->type->flag & STRUCT_ID) {
51                 ptr->id.data= ptr->data;
52                 ptr->id.type= ptr->type;
53         }
54         else {
55                 ptr->id.data= parent->id.data;
56                 ptr->id.type= parent->id.type;
57         }
58 }
59
60 /* Structs */
61
62 const char *RNA_struct_cname(PointerRNA *ptr)
63 {
64         return ptr->type->cname;
65 }
66
67 const char *RNA_struct_ui_name(PointerRNA *ptr)
68 {
69         return ptr->type->name;
70 }
71
72 PropertyRNA *RNA_struct_name_property(PointerRNA *ptr)
73 {
74         return ptr->type->nameproperty;
75 }
76
77 PropertyRNA *RNA_struct_iterator_property(PointerRNA *ptr)
78 {
79         return ptr->type->iteratorproperty;
80 }
81
82 /* Property Information */
83
84 const char *RNA_property_cname(PropertyRNA *prop, PointerRNA *ptr)
85 {
86         return prop->cname;
87 }
88
89 PropertyType RNA_property_type(PropertyRNA *prop, PointerRNA *ptr)
90 {
91         return prop->type;
92 }
93
94 PropertySubType RNA_property_subtype(PropertyRNA *prop, PointerRNA *ptr)
95 {
96         return prop->subtype;
97 }
98
99 int RNA_property_array_length(PropertyRNA *prop, PointerRNA *ptr)
100 {
101         return prop->arraylength;
102 }
103
104 void RNA_property_int_range(PropertyRNA *prop, PointerRNA *ptr, int *hardmin, int *hardmax)
105 {
106         IntPropertyRNA *iprop= (IntPropertyRNA*)prop;
107
108         *hardmin= iprop->hardmin;
109         *hardmax= iprop->hardmax;
110 }
111
112 void RNA_property_int_ui_range(PropertyRNA *prop, PointerRNA *ptr, int *softmin, int *softmax, int *step)
113 {
114         IntPropertyRNA *iprop= (IntPropertyRNA*)prop;
115
116         *softmin= iprop->softmin;
117         *softmax= iprop->softmax;
118         *step= iprop->step;
119 }
120
121 void RNA_property_float_range(PropertyRNA *prop, PointerRNA *ptr, float *hardmin, float *hardmax)
122 {
123         FloatPropertyRNA *fprop= (FloatPropertyRNA*)prop;
124
125         *hardmin= fprop->hardmin;
126         *hardmax= fprop->hardmax;
127 }
128
129 void RNA_property_float_ui_range(PropertyRNA *prop, PointerRNA *ptr, float *softmin, float *softmax, float *step, float *precision)
130 {
131         FloatPropertyRNA *fprop= (FloatPropertyRNA*)prop;
132
133         *softmin= fprop->softmin;
134         *softmax= fprop->softmax;
135         *step= fprop->step;
136         *precision= fprop->precision;
137 }
138
139 int RNA_property_string_maxlength(PropertyRNA *prop, PointerRNA *ptr)
140 {
141         StringPropertyRNA *sprop= (StringPropertyRNA*)prop;
142         
143         return sprop->maxlength;
144 }
145
146 void RNA_property_enum_items(PropertyRNA *prop, PointerRNA *ptr, const PropertyEnumItem **item, int *totitem)
147 {
148         EnumPropertyRNA *eprop= (EnumPropertyRNA*)prop;
149
150         *item= eprop->item;
151         *totitem= eprop->totitem;
152 }
153
154 const char *RNA_property_ui_name(PropertyRNA *prop, PointerRNA *ptr)
155 {
156         return prop->name;
157 }
158
159 const char *RNA_property_ui_description(PropertyRNA *prop, PointerRNA *ptr)
160 {
161         return prop->description;
162 }
163
164 /* Property Data */
165
166 int RNA_property_editable(PropertyRNA *prop, PointerRNA *ptr)
167 {
168         return !(prop->flag & PROP_NOT_EDITABLE);
169 }
170
171 int RNA_property_evaluated(PropertyRNA *prop, PointerRNA *ptr)
172 {
173         return (prop->flag & PROP_EVALUATED);
174 }
175
176 void RNA_property_notify(PropertyRNA *prop, struct bContext *C, PointerRNA *ptr)
177 {
178         if(prop->notify)
179                 prop->notify(C, ptr);
180 }
181
182 int RNA_property_boolean_get(PropertyRNA *prop, PointerRNA *ptr)
183 {
184         BooleanPropertyRNA *bprop= (BooleanPropertyRNA*)prop;
185
186         return bprop->get(ptr);
187 }
188
189 void RNA_property_boolean_set(PropertyRNA *prop, PointerRNA *ptr, int value)
190 {
191         BooleanPropertyRNA *bprop= (BooleanPropertyRNA*)prop;
192
193         if(bprop->set)
194                 bprop->set(ptr, value);
195 }
196
197 int RNA_property_boolean_get_array(PropertyRNA *prop, PointerRNA *ptr, int index)
198 {
199         BooleanPropertyRNA *bprop= (BooleanPropertyRNA*)prop;
200
201         return bprop->getarray(ptr, index);
202 }
203
204 void RNA_property_boolean_set_array(PropertyRNA *prop, PointerRNA *ptr, int index, int value)
205 {
206         BooleanPropertyRNA *bprop= (BooleanPropertyRNA*)prop;
207
208         if(bprop->setarray)
209                 bprop->setarray(ptr, index, value);
210 }
211
212 int RNA_property_int_get(PropertyRNA *prop, PointerRNA *ptr)
213 {
214         IntPropertyRNA *iprop= (IntPropertyRNA*)prop;
215
216         return iprop->get(ptr);
217 }
218
219 void RNA_property_int_set(PropertyRNA *prop, PointerRNA *ptr, int value)
220 {
221         IntPropertyRNA *iprop= (IntPropertyRNA*)prop;
222
223         if(iprop->set)
224                 iprop->set(ptr, value);
225 }
226
227 int RNA_property_int_get_array(PropertyRNA *prop, PointerRNA *ptr, int index)
228 {
229         IntPropertyRNA *iprop= (IntPropertyRNA*)prop;
230
231         return iprop->getarray(ptr, index);
232 }
233
234 void RNA_property_int_set_array(PropertyRNA *prop, PointerRNA *ptr, int index, int value)
235 {
236         IntPropertyRNA *iprop= (IntPropertyRNA*)prop;
237
238         if(iprop->setarray)
239                 iprop->setarray(ptr, index, value);
240 }
241
242 float RNA_property_float_get(PropertyRNA *prop, PointerRNA *ptr)
243 {
244         FloatPropertyRNA *fprop= (FloatPropertyRNA*)prop;
245
246         return fprop->get(ptr);
247 }
248
249 void RNA_property_float_set(PropertyRNA *prop, PointerRNA *ptr, float value)
250 {
251         FloatPropertyRNA *fprop= (FloatPropertyRNA*)prop;
252
253         if(fprop->set)
254                 fprop->set(ptr, value);
255 }
256
257 float RNA_property_float_get_array(PropertyRNA *prop, PointerRNA *ptr, int index)
258 {
259         FloatPropertyRNA *fprop= (FloatPropertyRNA*)prop;
260
261         return fprop->getarray(ptr, index);
262 }
263
264 void RNA_property_float_set_array(PropertyRNA *prop, PointerRNA *ptr, int index, float value)
265 {
266         FloatPropertyRNA *fprop= (FloatPropertyRNA*)prop;
267
268         if(fprop->setarray)
269                 fprop->setarray(ptr, index, value);
270 }
271
272 void RNA_property_string_get(PropertyRNA *prop, PointerRNA *ptr, char *value)
273 {
274         StringPropertyRNA *sprop= (StringPropertyRNA*)prop;
275
276         sprop->get(ptr, value);
277 }
278
279 char *RNA_property_string_get_alloc(PropertyRNA *prop, PointerRNA *ptr, char *fixedbuf, int fixedlen)
280 {
281         char *buf;
282         int length;
283
284         length= RNA_property_string_length(prop, ptr);
285
286         if(length+1 < fixedlen)
287                 buf= fixedbuf;
288         else
289                 buf= MEM_callocN(sizeof(char)*(length+1), "RNA_string_get_alloc");
290
291         RNA_property_string_get(prop, ptr, buf);
292
293         return buf;
294 }
295
296 int RNA_property_string_length(PropertyRNA *prop, PointerRNA *ptr)
297 {
298         StringPropertyRNA *sprop= (StringPropertyRNA*)prop;
299
300         return sprop->length(ptr);
301 }
302
303 void RNA_property_string_set(PropertyRNA *prop, PointerRNA *ptr, const char *value)
304 {
305         StringPropertyRNA *sprop= (StringPropertyRNA*)prop;
306
307         if(sprop->set)
308                 sprop->set(ptr, value);
309 }
310
311 int RNA_property_enum_get(PropertyRNA *prop, PointerRNA *ptr)
312 {
313         EnumPropertyRNA *eprop= (EnumPropertyRNA*)prop;
314
315         return eprop->get(ptr);
316 }
317
318 void RNA_property_enum_set(PropertyRNA *prop, PointerRNA *ptr, int value)
319 {
320         EnumPropertyRNA *eprop= (EnumPropertyRNA*)prop;
321
322         if(eprop->set)
323                 eprop->set(ptr, value);
324 }
325
326 void RNA_property_pointer_get(PropertyRNA *prop, PointerRNA *ptr, PointerRNA *r_ptr)
327 {
328         PointerPropertyRNA *pprop= (PointerPropertyRNA*)prop;
329
330         r_ptr->data= pprop->get(ptr);
331
332         if(r_ptr->data) {
333                 r_ptr->type= RNA_property_pointer_type(prop, ptr);
334                 rna_pointer_inherit_id(ptr, r_ptr);
335         }
336         else
337                 memset(r_ptr, 0, sizeof(*r_ptr));
338 }
339
340 void RNA_property_pointer_set(PropertyRNA *prop, PointerRNA *ptr, PointerRNA *ptr_value)
341 {
342         PointerPropertyRNA *pprop= (PointerPropertyRNA*)prop;
343
344         if(pprop->set)
345                 pprop->set(ptr, ptr_value->data);
346 }
347
348 StructRNA *RNA_property_pointer_type(PropertyRNA *prop, PointerRNA *ptr)
349 {
350         PointerPropertyRNA *pprop= (PointerPropertyRNA*)prop;
351
352         if(pprop->type)
353                 return pprop->type(ptr);
354         
355         return pprop->structtype;
356 }
357
358 static StructRNA *rna_property_collection_type(PropertyRNA *prop, CollectionPropertyIterator *iter)
359 {
360         CollectionPropertyRNA *cprop= (CollectionPropertyRNA*)prop;
361
362         if(cprop->type)
363                 return cprop->type(iter);
364         
365         return cprop->structtype;
366 }
367
368 static void rna_property_collection_get(PropertyRNA *prop, CollectionPropertyIterator *iter, PointerRNA *r_ptr)
369 {
370         CollectionPropertyRNA *cprop= (CollectionPropertyRNA*)prop;
371
372         r_ptr->data= cprop->get(iter);
373
374         if(r_ptr->data) {
375                 r_ptr->type= rna_property_collection_type(prop, iter);
376                 rna_pointer_inherit_id(&iter->parent, r_ptr);
377         }
378         else
379                 memset(r_ptr, 0, sizeof(*r_ptr));
380 }
381
382 void RNA_property_collection_begin(PropertyRNA *prop, CollectionPropertyIterator *iter, PointerRNA *ptr)
383 {
384         CollectionPropertyRNA *cprop= (CollectionPropertyRNA*)prop;
385
386         iter->parent= *ptr;
387         cprop->begin(iter, ptr);
388
389         if(iter->valid)
390                 rna_property_collection_get(prop, iter, &iter->ptr);
391         else
392                 memset(&iter->ptr, 0, sizeof(iter->ptr));
393 }
394
395 void RNA_property_collection_next(PropertyRNA *prop, CollectionPropertyIterator *iter)
396 {
397         CollectionPropertyRNA *cprop= (CollectionPropertyRNA*)prop;
398
399         cprop->next(iter);
400
401         if(iter->valid)
402                 rna_property_collection_get(prop, iter, &iter->ptr);
403         else
404                 memset(&iter->ptr, 0, sizeof(iter->ptr));
405 }
406
407 void RNA_property_collection_end(PropertyRNA *prop, CollectionPropertyIterator *iter)
408 {
409         CollectionPropertyRNA *cprop= (CollectionPropertyRNA*)prop;
410
411         if(cprop->end)
412                 cprop->end(iter);
413 }
414
415 int RNA_property_collection_length(PropertyRNA *prop, PointerRNA *ptr)
416 {
417         CollectionPropertyRNA *cprop= (CollectionPropertyRNA*)prop;
418
419         if(cprop->length) {
420                 return cprop->length(ptr);
421         }
422         else {
423                 CollectionPropertyIterator iter;
424                 int length= 0;
425
426                 for(cprop->begin(&iter, ptr); iter.valid; cprop->next(&iter))
427                         length++;
428
429                 if(cprop->end)
430                         cprop->end(&iter);
431
432                 return length;
433         }
434 }
435
436 int RNA_property_collection_lookup_int(PropertyRNA *prop, PointerRNA *ptr, int key, PointerRNA *r_ptr)
437 {
438         CollectionPropertyRNA *cprop= (CollectionPropertyRNA*)prop;
439
440         if(cprop->lookupint) {
441                 /* we have a callback defined, use it */
442                 r_ptr->data= cprop->lookupint(ptr, key, &r_ptr->type);
443
444                 if(r_ptr->data) {
445                         if(!r_ptr->type)
446                                 r_ptr->type= cprop->structtype;
447                         rna_pointer_inherit_id(ptr, r_ptr);
448
449                         return 1;
450                 }
451                 else {
452                         memset(r_ptr, 0, sizeof(*r_ptr));
453                         return 0;
454                 }
455         }
456         else {
457                 /* no callback defined, just iterate and find the nth item */
458                 CollectionPropertyIterator iter;
459                 int i;
460
461                 RNA_property_collection_begin(prop, &iter, ptr);
462                 for(i=0; iter.valid; RNA_property_collection_next(prop, &iter), i++) {
463                         if(i == key) {
464                                 *r_ptr= iter.ptr;
465                                 break;
466                         }
467                 }
468                 RNA_property_collection_end(prop, &iter);
469
470                 if(!iter.valid)
471                         memset(r_ptr, 0, sizeof(*r_ptr));
472
473                 return iter.valid;
474         }
475 }
476
477 int RNA_property_collection_lookup_string(PropertyRNA *prop, PointerRNA *ptr, const char *key, PointerRNA *r_ptr)
478 {
479         CollectionPropertyRNA *cprop= (CollectionPropertyRNA*)prop;
480
481         if(cprop->lookupstring) {
482                 /* we have a callback defined, use it */
483                 r_ptr->data= cprop->lookupstring(ptr, key, &r_ptr->type);
484
485                 if(r_ptr->data) {
486                         if(!r_ptr->type)
487                                 r_ptr->type= cprop->structtype;
488                         rna_pointer_inherit_id(ptr, r_ptr);
489
490                         return 1;
491                 }
492                 else {
493                         memset(r_ptr, 0, sizeof(*r_ptr));
494                         return 0;
495                 }
496         }
497         else {
498                 /* no callback defined, compare with name properties if they exist */
499                 CollectionPropertyIterator iter;
500                 PropertyRNA *nameprop;
501                 char name[256], *nameptr;
502                 int length, alloc, found= 0;
503
504                 RNA_property_collection_begin(prop, &iter, ptr);
505                 for(; iter.valid; RNA_property_collection_next(prop, &iter)) {
506                         if(iter.ptr.data && iter.ptr.type->nameproperty) {
507                                 nameprop= iter.ptr.type->nameproperty;
508
509                                 length= RNA_property_string_length(nameprop, &iter.ptr);
510
511                                 if(sizeof(name)-1 < length) {
512                                         nameptr= name;
513                                         alloc= 0;
514                                 }
515                                 else {
516                                         nameptr= MEM_mallocN(sizeof(char)*length+1, "RNA_lookup_string");
517                                         alloc= 1;
518                                 }
519
520                                 RNA_property_string_get(nameprop, &iter.ptr, nameptr);
521
522                                 if(strcmp(nameptr, key) == 0) {
523                                         *r_ptr= iter.ptr;
524                                         found= 1;
525                                 }
526
527                                 if(alloc)
528                                         MEM_freeN(nameptr);
529
530                                 if(found)
531                                         break;
532                         }
533                 }
534                 RNA_property_collection_end(prop, &iter);
535
536                 if(!iter.valid)
537                         memset(r_ptr, 0, sizeof(*r_ptr));
538
539                 return iter.valid;
540         }
541 }
542
543 /* Standard iterator functions */
544
545 void rna_iterator_listbase_begin(CollectionPropertyIterator *iter, ListBase *lb)
546 {
547         iter->internal= lb->first;
548         iter->valid= (iter->internal != NULL);
549 }
550
551 void rna_iterator_listbase_next(CollectionPropertyIterator *iter)
552 {
553         iter->internal= ((Link*)iter->internal)->next;
554         iter->valid= (iter->internal != NULL);
555 }
556
557 void *rna_iterator_listbase_get(CollectionPropertyIterator *iter)
558 {
559         return iter->internal;
560 }
561
562 void rna_iterator_array_begin(CollectionPropertyIterator *iter, void *ptr, int itemsize, int length)
563 {
564         ArrayIterator *internal;
565
566         internal= MEM_callocN(sizeof(ArrayIterator), "ArrayIterator");
567         internal->ptr= ptr;
568         internal->endptr= ((char*)ptr)+length*itemsize;
569         internal->itemsize= itemsize;
570
571         iter->internal= internal;
572         iter->valid= (internal->ptr != internal->endptr);
573 }
574
575 void rna_iterator_array_next(CollectionPropertyIterator *iter)
576 {
577         ArrayIterator *internal= iter->internal;
578
579         internal->ptr += internal->itemsize;
580         iter->valid= (internal->ptr != internal->endptr);
581 }
582
583 void *rna_iterator_array_get(CollectionPropertyIterator *iter)
584 {
585         ArrayIterator *internal= iter->internal;
586
587         return internal->ptr;
588 }
589
590 void rna_iterator_array_end(CollectionPropertyIterator *iter)
591 {
592         MEM_freeN(iter->internal);
593 }
594
595 /* RNA Path - Experiment */
596
597 static char *rna_path_token(const char **path, char *fixedbuf, int fixedlen, int bracket)
598 {
599         const char *p;
600         char *buf;
601         int i, j, len, escape;
602
603         len= 0;
604
605         if(bracket) {
606                 /* get data between [], check escaping ] with \] */
607                 if(**path == '[') (*path)++;
608                 else return NULL;
609
610                 p= *path;
611
612                 escape= 0;
613                 while(*p && (*p != ']' || escape)) {
614                         escape= (*p == '\\');
615                         len++;
616                         p++;
617                 }
618
619                 if(*p != ']') return NULL;
620         }
621         else {
622                 /* get data until . or [ */
623                 p= *path;
624
625                 while(*p && *p != '.' && *p != '[') {
626                         len++;
627                         p++;
628                 }
629         }
630         
631         /* empty, return */
632         if(len == 0)
633                 return NULL;
634         
635         /* try to use fixed buffer if possible */
636         if(len+1 < fixedlen)
637                 buf= fixedbuf;
638         else
639                 buf= MEM_callocN(sizeof(char)*(len+1), "rna_path_token");
640
641         /* copy string, taking into account escaped ] */
642         for(p=*path, i=0, j=0; i<len; i++, p++) {
643                 if(*p == '\\' && *(p+1) == ']');
644                 else buf[j++]= *p;
645         }
646
647         buf[j]= 0;
648
649         /* set path to start of next token */
650         if(*p == ']') p++;
651         if(*p == '.') p++;
652         *path= p;
653
654         return buf;
655 }
656
657 int RNA_path_resolve(PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop)
658 {
659         CollectionPropertyIterator iter;
660         PropertyRNA *prop, *iterprop;
661         PointerRNA curptr, nextptr;
662         char fixedbuf[256], *token;
663         int len, intkey;
664
665         prop= NULL;
666         curptr= *ptr;
667
668         while(*path) {
669                 /* look up property name in current struct */
670                 token= rna_path_token(&path, fixedbuf, sizeof(fixedbuf), 0);
671
672                 if(!token)
673                         return 0;
674
675                 iterprop= RNA_struct_iterator_property(&curptr);
676                 RNA_property_collection_begin(iterprop, &iter, &curptr);
677                 prop= NULL;
678
679                 for(; iter.valid; RNA_property_collection_next(iterprop, &iter)) {
680                         if(strcmp(token, RNA_property_cname(iter.ptr.data, &iter.ptr)) == 0) {
681                                 prop= iter.ptr.data;
682                                 break;
683                         }
684                 }
685
686                 RNA_property_collection_end(iterprop, &iter);
687
688                 if(token != fixedbuf)
689                         MEM_freeN(token);
690
691                 if(!prop)
692                         return 0;
693
694                 /* now look up the value of this property if it is a pointer or
695                  * collection, otherwise return the property rna so that the
696                  * caller can read the value of the property itself */
697                 if(prop->type == PROP_POINTER) {
698                         RNA_property_pointer_get(prop, &curptr, &nextptr);
699
700                         if(nextptr.data)
701                                 curptr= nextptr;
702                         else
703                                 return 0;
704                 }
705                 else if(prop->type == PROP_COLLECTION && *path) {
706                         /* resolve the lookup with [] brackets */
707                         token= rna_path_token(&path, fixedbuf, sizeof(fixedbuf), 1);
708
709                         if(!token)
710                                 return 0;
711
712                         len= strlen(token);
713
714                         /* check for "" to see if it is a string */
715                         if(len >= 2 && *token == '"' && token[len-2] == '"') {
716                                 /* strip away "" */
717                                 token[len-2]= 0;
718                                 RNA_property_collection_lookup_string(prop, &curptr, token+1, &nextptr);
719                         }
720                         else {
721                                 /* otherwise do int lookup */
722                                 intkey= atoi(token);
723                                 RNA_property_collection_lookup_int(prop, &curptr, intkey, &nextptr);
724                         }
725
726                         if(token != fixedbuf)
727                                 MEM_freeN(token);
728
729                         if(nextptr.data)
730                                 curptr= nextptr;
731                         else
732                                 return 0;
733                 }
734         }
735
736         *r_ptr= curptr;
737         *r_prop= prop;
738
739         return 1;
740 }
741
742 char *RNA_path_append(const char *path, PropertyRNA *prop, int intkey, const char *strkey)
743 {
744         DynStr *dynstr;
745         const char *s;
746         char appendstr[128], *result;
747         
748         dynstr= BLI_dynstr_new();
749
750         /* add .cname */
751         if(path) {
752                 BLI_dynstr_append(dynstr, (char*)path);
753                 if(*path)
754                         BLI_dynstr_append(dynstr, ".");
755         }
756
757         BLI_dynstr_append(dynstr, (char*)prop->cname);
758
759         if(prop->type == PROP_COLLECTION) {
760                 /* add ["strkey"] or [intkey] */
761                 BLI_dynstr_append(dynstr, "[");
762
763                 if(strkey) {
764                         BLI_dynstr_append(dynstr, "\"");
765                         for(s=strkey; *s; s++) {
766                                 if(*s == '[') {
767                                         appendstr[0]= '\\';
768                                         appendstr[1]= *s;
769                                         appendstr[2]= 0;
770                                 }
771                                 else {
772                                         appendstr[0]= *s;
773                                         appendstr[1]= 0;
774                                 }
775                                 BLI_dynstr_append(dynstr, appendstr);
776                         }
777                         BLI_dynstr_append(dynstr, "\"");
778                 }
779                 else {
780                         sprintf(appendstr, "%d", intkey);
781                         BLI_dynstr_append(dynstr, appendstr);
782                 }
783
784                 BLI_dynstr_append(dynstr, "]");
785         }
786
787         result= BLI_dynstr_get_cstring(dynstr);
788         BLI_dynstr_free(dynstr);
789
790         return result;
791 }
792
793 char *RNA_path_back(const char *path)
794 {
795         char fixedbuf[256];
796         const char *previous, *current;
797         char *result, *token;
798         int i;
799
800         if(!path)
801                 return NULL;
802
803         previous= NULL;
804         current= path;
805
806         /* parse token by token until the end, then we back up to the previous
807          * position and strip of the next token to get the path one step back */
808         while(*current) {
809                 token= rna_path_token(&current, fixedbuf, sizeof(fixedbuf), 0);
810
811                 if(!token)
812                         return NULL;
813                 if(token != fixedbuf)
814                         MEM_freeN(token);
815
816                 /* in case of collection we also need to strip off [] */
817                 token= rna_path_token(&current, fixedbuf, sizeof(fixedbuf), 1);
818                 if(token && token != fixedbuf)
819                         MEM_freeN(token);
820                 
821                 if(!*current)
822                         break;
823
824                 previous= current;
825         }
826
827         if(!previous)
828                 return NULL;
829
830         /* copy and strip off last token */
831         i= previous - path;
832         result= BLI_strdup(path);
833
834         if(i > 0 && result[i-1] == '.') i--;
835         result[i]= 0;
836
837         return result;
838 }
839