9304618f596586e8a1f81d40b70a65358b3a418c
[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 void RNA_property_collection_begin(PropertyRNA *prop, CollectionPropertyIterator *iter, PointerRNA *ptr)
359 {
360         CollectionPropertyRNA *cprop= (CollectionPropertyRNA*)prop;
361
362         iter->pointer= *ptr;
363         cprop->begin(iter, ptr);
364 }
365
366 void RNA_property_collection_next(PropertyRNA *prop, CollectionPropertyIterator *iter)
367 {
368         CollectionPropertyRNA *cprop= (CollectionPropertyRNA*)prop;
369
370         cprop->next(iter);
371 }
372
373 void RNA_property_collection_end(PropertyRNA *prop, CollectionPropertyIterator *iter)
374 {
375         CollectionPropertyRNA *cprop= (CollectionPropertyRNA*)prop;
376
377         if(cprop->end)
378                 cprop->end(iter);
379 }
380
381 void RNA_property_collection_get(PropertyRNA *prop, CollectionPropertyIterator *iter, PointerRNA *r_ptr)
382 {
383         CollectionPropertyRNA *cprop= (CollectionPropertyRNA*)prop;
384
385         r_ptr->data= cprop->get(iter);
386
387         if(r_ptr->data) {
388                 r_ptr->type= RNA_property_collection_type(prop, iter);
389                 rna_pointer_inherit_id(&iter->pointer, r_ptr);
390         }
391         else
392                 memset(r_ptr, 0, sizeof(*r_ptr));
393 }
394
395 StructRNA *RNA_property_collection_type(PropertyRNA *prop, CollectionPropertyIterator *iter)
396 {
397         CollectionPropertyRNA *cprop= (CollectionPropertyRNA*)prop;
398
399         if(cprop->type)
400                 return cprop->type(iter);
401         
402         return cprop->structtype;
403 }
404
405 int RNA_property_collection_length(PropertyRNA *prop, PointerRNA *ptr)
406 {
407         CollectionPropertyRNA *cprop= (CollectionPropertyRNA*)prop;
408
409         if(cprop->length) {
410                 return cprop->length(ptr);
411         }
412         else {
413                 CollectionPropertyIterator iter;
414                 int length= 0;
415
416                 for(cprop->begin(&iter, ptr); iter.valid; cprop->next(&iter))
417                         length++;
418
419                 if(cprop->end)
420                         cprop->end(&iter);
421
422                 return length;
423         }
424 }
425
426 int RNA_property_collection_lookup_int(PropertyRNA *prop, PointerRNA *ptr, int key, PointerRNA *r_ptr)
427 {
428         CollectionPropertyRNA *cprop= (CollectionPropertyRNA*)prop;
429
430         if(cprop->lookupint) {
431                 /* we have a callback defined, use it */
432                 r_ptr->data= cprop->lookupint(ptr, key, &r_ptr->type);
433
434                 if(r_ptr->data) {
435                         if(!r_ptr->type)
436                                 r_ptr->type= cprop->structtype;
437                         rna_pointer_inherit_id(ptr, r_ptr);
438
439                         return 1;
440                 }
441                 else {
442                         memset(r_ptr, 0, sizeof(*r_ptr));
443                         return 0;
444                 }
445         }
446         else {
447                 /* no callback defined, just iterate and find the nth item */
448                 CollectionPropertyIterator iter;
449                 int i;
450
451                 RNA_property_collection_begin(prop, &iter, ptr);
452                 for(i=0; iter.valid; RNA_property_collection_next(prop, &iter), i++) {
453                         if(i == key) {
454                                 RNA_property_collection_get(prop, &iter, r_ptr);
455                                 break;
456                         }
457                 }
458                 RNA_property_collection_end(prop, &iter);
459
460                 if(!iter.valid)
461                         memset(r_ptr, 0, sizeof(*r_ptr));
462
463                 return iter.valid;
464         }
465 }
466
467 int RNA_property_collection_lookup_string(PropertyRNA *prop, PointerRNA *ptr, const char *key, PointerRNA *r_ptr)
468 {
469         CollectionPropertyRNA *cprop= (CollectionPropertyRNA*)prop;
470
471         if(cprop->lookupstring) {
472                 /* we have a callback defined, use it */
473                 r_ptr->data= cprop->lookupstring(ptr, key, &r_ptr->type);
474
475                 if(r_ptr->data) {
476                         if(!r_ptr->type)
477                                 r_ptr->type= cprop->structtype;
478                         rna_pointer_inherit_id(ptr, r_ptr);
479
480                         return 1;
481                 }
482                 else {
483                         memset(r_ptr, 0, sizeof(*r_ptr));
484                         return 0;
485                 }
486         }
487         else {
488                 /* no callback defined, compare with name properties if they exist */
489                 CollectionPropertyIterator iter;
490                 PropertyRNA *nameprop;
491                 PointerRNA iterptr;
492                 char name[256], *nameptr;
493                 int length, alloc, found= 0;
494
495                 RNA_property_collection_begin(prop, &iter, ptr);
496                 for(; iter.valid; RNA_property_collection_next(prop, &iter)) {
497                         RNA_property_collection_get(prop, &iter, &iterptr);
498
499                         if(iterptr.data && iterptr.type->nameproperty) {
500                                 nameprop= iterptr.type->nameproperty;
501
502                                 length= RNA_property_string_length(nameprop, &iterptr);
503
504                                 if(sizeof(name)-1 < length) {
505                                         nameptr= name;
506                                         alloc= 0;
507                                 }
508                                 else {
509                                         nameptr= MEM_mallocN(sizeof(char)*length+1, "RNA_lookup_string");
510                                         alloc= 1;
511                                 }
512
513                                 RNA_property_string_get(nameprop, &iterptr, nameptr);
514
515                                 if(strcmp(nameptr, key) == 0) {
516                                         *r_ptr= iterptr;
517                                         found= 1;
518                                 }
519
520                                 if(alloc)
521                                         MEM_freeN(nameptr);
522
523                                 if(found)
524                                         break;
525                         }
526                 }
527                 RNA_property_collection_end(prop, &iter);
528
529                 if(!iter.valid)
530                         memset(r_ptr, 0, sizeof(*r_ptr));
531
532                 return iter.valid;
533         }
534 }
535
536 /* Standard iterator functions */
537
538 void rna_iterator_listbase_begin(CollectionPropertyIterator *iter, ListBase *lb)
539 {
540         iter->internal= lb->first;
541         iter->valid= (iter->internal != NULL);
542 }
543
544 void rna_iterator_listbase_next(CollectionPropertyIterator *iter)
545 {
546         iter->internal= ((Link*)iter->internal)->next;
547         iter->valid= (iter->internal != NULL);
548 }
549
550 void *rna_iterator_listbase_get(CollectionPropertyIterator *iter)
551 {
552         return iter->internal;
553 }
554
555 void rna_iterator_array_begin(CollectionPropertyIterator *iter, void *ptr, int itemsize, int length)
556 {
557         ArrayIterator *internal;
558
559         internal= MEM_callocN(sizeof(ArrayIterator), "ArrayIterator");
560         internal->ptr= ptr;
561         internal->endptr= ((char*)ptr)+length*itemsize;
562         internal->itemsize= itemsize;
563
564         iter->internal= internal;
565         iter->valid= (internal->ptr != internal->endptr);
566 }
567
568 void rna_iterator_array_next(CollectionPropertyIterator *iter)
569 {
570         ArrayIterator *internal= iter->internal;
571
572         internal->ptr += internal->itemsize;
573         iter->valid= (internal->ptr != internal->endptr);
574 }
575
576 void *rna_iterator_array_get(CollectionPropertyIterator *iter)
577 {
578         ArrayIterator *internal= iter->internal;
579
580         return internal->ptr;
581 }
582
583 void rna_iterator_array_end(CollectionPropertyIterator *iter)
584 {
585         MEM_freeN(iter->internal);
586 }
587
588 /* RNA Path - Experiment */
589
590 static char *rna_path_token(const char **path, char *fixedbuf, int fixedlen, int bracket)
591 {
592         const char *p;
593         char *buf;
594         int i, j, len, escape;
595
596         len= 0;
597
598         if(bracket) {
599                 /* get data between [], check escaping ] with \] */
600                 if(**path == '[') (*path)++;
601                 else return NULL;
602
603                 p= *path;
604
605                 escape= 0;
606                 while(*p && (*p != ']' || escape)) {
607                         escape= (*p == '\\');
608                         len++;
609                         p++;
610                 }
611
612                 if(*p != ']') return NULL;
613         }
614         else {
615                 /* get data until . or [ */
616                 p= *path;
617
618                 while(*p && *p != '.' && *p != '[') {
619                         len++;
620                         p++;
621                 }
622         }
623         
624         /* empty, return */
625         if(len == 0)
626                 return NULL;
627         
628         /* try to use fixed buffer if possible */
629         if(len+1 < fixedlen)
630                 buf= fixedbuf;
631         else
632                 buf= MEM_callocN(sizeof(char)*(len+1), "rna_path_token");
633
634         /* copy string, taking into account escaped ] */
635         for(p=*path, i=0, j=0; i<len; i++, p++) {
636                 if(*p == '\\' && *(p+1) == ']');
637                 else buf[j++]= *p;
638         }
639
640         buf[j]= 0;
641
642         /* set path to start of next token */
643         if(*p == ']') p++;
644         if(*p == '.') p++;
645         *path= p;
646
647         return buf;
648 }
649
650 int RNA_path_resolve(PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop)
651 {
652         CollectionPropertyIterator iter;
653         PropertyRNA *prop, *iterprop;
654         PointerRNA curptr, nextptr;
655         char fixedbuf[256], *token;
656         int len, intkey;
657
658         prop= NULL;
659         curptr= *ptr;
660
661         while(*path) {
662                 /* look up property name in current struct */
663                 token= rna_path_token(&path, fixedbuf, sizeof(fixedbuf), 0);
664
665                 if(!token)
666                         return 0;
667
668                 iterprop= RNA_struct_iterator_property(&curptr);
669                 RNA_property_collection_begin(iterprop, &iter, &curptr);
670                 prop= NULL;
671
672                 for(; iter.valid; RNA_property_collection_next(iterprop, &iter)) {
673                         PointerRNA cptr;
674                         PropertyRNA *cprop;
675
676                         RNA_property_collection_get(iterprop, &iter, &cptr);
677                         cprop= cptr.data;
678
679                         if(strcmp(token, cprop->cname) == 0) {
680                                 prop= cprop;
681                                 break;
682                         }
683                 }
684
685                 RNA_property_collection_end(iterprop, &iter);
686
687                 if(token != fixedbuf)
688                         MEM_freeN(token);
689
690                 if(!prop)
691                         return 0;
692
693                 /* now look up the value of this property if it is a pointer or
694                  * collection, otherwise return the property rna so that the
695                  * caller can read the value of the property itself */
696                 if(prop->type == PROP_POINTER) {
697                         RNA_property_pointer_get(prop, &curptr, &nextptr);
698
699                         if(nextptr.data)
700                                 curptr= nextptr;
701                         else
702                                 return 0;
703                 }
704                 else if(prop->type == PROP_COLLECTION && *path) {
705                         /* resolve the lookup with [] brackets */
706                         token= rna_path_token(&path, fixedbuf, sizeof(fixedbuf), 1);
707
708                         if(!token)
709                                 return 0;
710
711                         len= strlen(token);
712
713                         /* check for "" to see if it is a string */
714                         if(len >= 2 && *token == '"' && token[len-2] == '"') {
715                                 /* strip away "" */
716                                 token[len-2]= 0;
717                                 RNA_property_collection_lookup_string(prop, &curptr, token+1, &nextptr);
718                         }
719                         else {
720                                 /* otherwise do int lookup */
721                                 intkey= atoi(token);
722                                 RNA_property_collection_lookup_int(prop, &curptr, intkey, &nextptr);
723                         }
724
725                         if(token != fixedbuf)
726                                 MEM_freeN(token);
727
728                         if(nextptr.data)
729                                 curptr= nextptr;
730                         else
731                                 return 0;
732                 }
733         }
734
735         *r_ptr= curptr;
736         *r_prop= prop;
737
738         return 1;
739 }
740
741 char *RNA_path_append(const char *path, PropertyRNA *prop, int intkey, const char *strkey)
742 {
743         DynStr *dynstr;
744         const char *s;
745         char appendstr[128], *result;
746         
747         dynstr= BLI_dynstr_new();
748
749         /* add .cname */
750         if(path) {
751                 BLI_dynstr_append(dynstr, (char*)path);
752                 if(*path)
753                         BLI_dynstr_append(dynstr, ".");
754         }
755
756         BLI_dynstr_append(dynstr, (char*)prop->cname);
757
758         if(prop->type == PROP_COLLECTION) {
759                 /* add ["strkey"] or [intkey] */
760                 BLI_dynstr_append(dynstr, "[");
761
762                 if(strkey) {
763                         BLI_dynstr_append(dynstr, "\"");
764                         for(s=strkey; *s; s++) {
765                                 if(*s == '[') {
766                                         appendstr[0]= '\\';
767                                         appendstr[1]= *s;
768                                         appendstr[2]= 0;
769                                 }
770                                 else {
771                                         appendstr[0]= *s;
772                                         appendstr[1]= 0;
773                                 }
774                                 BLI_dynstr_append(dynstr, appendstr);
775                         }
776                         BLI_dynstr_append(dynstr, "\"");
777                 }
778                 else {
779                         sprintf(appendstr, "%d", intkey);
780                         BLI_dynstr_append(dynstr, appendstr);
781                 }
782
783                 BLI_dynstr_append(dynstr, "]");
784         }
785
786         result= BLI_dynstr_get_cstring(dynstr);
787         BLI_dynstr_free(dynstr);
788
789         return result;
790 }
791
792 char *RNA_path_back(const char *path)
793 {
794         char fixedbuf[256];
795         const char *previous, *current;
796         char *result, *token;
797         int i;
798
799         if(!path)
800                 return NULL;
801
802         previous= NULL;
803         current= path;
804
805         /* parse token by token until the end, then we back up to the previous
806          * position and strip of the next token to get the path one step back */
807         while(*current) {
808                 token= rna_path_token(&current, fixedbuf, sizeof(fixedbuf), 0);
809
810                 if(!token)
811                         return NULL;
812                 if(token != fixedbuf)
813                         MEM_freeN(token);
814
815                 /* in case of collection we also need to strip off [] */
816                 token= rna_path_token(&current, fixedbuf, sizeof(fixedbuf), 1);
817                 if(token && token != fixedbuf)
818                         MEM_freeN(token);
819                 
820                 if(!*current)
821                         break;
822
823                 previous= current;
824         }
825
826         if(!previous)
827                 return NULL;
828
829         /* copy and strip off last token */
830         i= previous - path;
831         result= BLI_strdup(path);
832
833         if(i > 0 && result[i-1] == '.') i--;
834         result[i]= 0;
835
836         return result;
837 }
838