use BLI_strncpy and BLI_snprintf when the size of the string is known.
[blender.git] / source / blender / blenkernel / intern / property.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): ton roosendaal
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/blenkernel/intern/property.c
29  *  \ingroup bke
30  */
31
32
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <stddef.h>
36 #include <string.h>
37 #include <ctype.h>
38
39 #include "MEM_guardedalloc.h"
40
41 #include "DNA_property_types.h"
42 #include "DNA_object_types.h"
43
44 #include "BLI_blenlib.h"
45
46 #include "BKE_property.h"
47
48 void free_property(bProperty *prop)
49 {
50         
51         if(prop->poin && prop->poin != &prop->data) MEM_freeN(prop->poin);
52         MEM_freeN(prop);
53         
54 }
55
56 void free_properties(ListBase *lb)
57 {
58         bProperty *prop;
59         
60         while( (prop= lb->first) ) {
61                 BLI_remlink(lb, prop);
62                 free_property(prop);
63         }
64 }
65
66 bProperty *copy_property(bProperty *prop)
67 {
68         bProperty *propn;
69         
70         propn= MEM_dupallocN(prop);
71         if(prop->poin && prop->poin != &prop->data) {
72                 propn->poin= MEM_dupallocN(prop->poin);
73         }
74         else propn->poin= &propn->data;
75         
76         return propn;
77 }
78
79 void copy_properties(ListBase *lbn, ListBase *lbo)
80 {
81         bProperty *prop, *propn;
82         free_properties( lbn ); /* incase we are copying to an object with props */
83         prop= lbo->first;
84         while(prop) {
85                 propn= copy_property(prop);
86                 BLI_addtail(lbn, propn);
87                 prop= prop->next;
88         }
89         
90         
91 }
92
93 void init_property(bProperty *prop)
94 {
95         /* also use when property changes type */
96         
97         if(prop->poin && prop->poin != &prop->data) MEM_freeN(prop->poin);
98         prop->poin= NULL;
99         
100         prop->data= 0;
101         
102         switch(prop->type) {
103         case GPROP_BOOL:
104         case GPROP_INT:
105         case GPROP_FLOAT:
106         case GPROP_TIME:
107                 prop->poin= &prop->data;
108                 break;
109         case GPROP_STRING:
110                 prop->poin= MEM_callocN(MAX_PROPSTRING, "property string");
111                 break;
112         }
113 }
114
115
116 bProperty *new_property(int type)
117 {
118         bProperty *prop;
119
120         prop= MEM_callocN(sizeof(bProperty), "property");
121         prop->type= type;
122
123         init_property(prop);
124         
125         strcpy(prop->name, "prop");
126
127         return prop;
128 }
129
130 /* used by unique_property() only */
131 static bProperty *get_property__internal(bProperty *first, bProperty *self, const char *name)
132 {
133         bProperty *p;
134         for(p= first; p; p= p->next) {
135                 if (p!=self && (strcmp(p->name, name)==0))
136                         return p;
137         }
138         return NULL;
139 }
140 void unique_property(bProperty *first, bProperty *prop, int force)
141 {
142         bProperty *p;
143
144         /* set the first if its not set */
145         if(first==NULL) {
146                 first= prop;
147                 while(first->prev) {
148                         first= first->prev;
149                 }
150         }
151
152         if(force) {
153                 /* change other names to make them unique */
154                 while((p = get_property__internal(first, prop, prop->name))) {
155                         unique_property(first, p, 0);
156                 }
157         }else {
158                 /* change our own name until its unique */
159                 if(get_property__internal(first, prop, prop->name)) {
160                         /* there is a collision */
161                         char new_name[sizeof(prop->name)];
162                         char base_name[sizeof(prop->name)];
163                         char num[sizeof(prop->name)];
164                         int i= 0;
165
166                         /* strip numbers */
167                         BLI_strncpy(base_name, prop->name, sizeof(base_name));
168                         for(i= strlen(base_name)-1; (i>=0 && isdigit(base_name[i])); i--) {
169                                 base_name[i]= '\0';
170                         }
171                         i= 0;
172
173                         do { /* ensure we have enough chars for the new number in the name */
174                                 BLI_snprintf(num, sizeof(num), "%d", i++);
175                                 BLI_strncpy(new_name, base_name, sizeof(prop->name) - strlen(num));
176                                 strcat(new_name, num);
177                         } while(get_property__internal(first, prop, new_name));
178
179                         BLI_strncpy(prop->name, new_name, sizeof(prop->name));
180                 }
181         }
182 }
183
184 bProperty *get_ob_property(Object *ob, const char *name)
185 {
186         return BLI_findstring(&ob->prop, name, offsetof(bProperty, name));
187 }
188
189 void set_ob_property(Object *ob, bProperty *propc)
190 {
191         bProperty *prop;
192         prop= get_ob_property(ob, propc->name);
193         if(prop) {
194                 free_property(prop);
195                 BLI_remlink(&ob->prop, prop);
196         }
197         BLI_addtail(&ob->prop, copy_property(propc));
198 }
199
200 /* negative: prop is smaller
201  * positive: prop is larger
202  */
203 int compare_property(bProperty *prop, const char *str)
204 {
205 //      extern int Gdfra;               /* sector.c */
206         float fvalue, ftest;
207         
208         switch(prop->type) {
209         case GPROP_BOOL:
210                 if(BLI_strcasecmp(str, "true")==0) {
211                         if(prop->data==1) return 0;
212                         else return 1;
213                 }
214                 else if(BLI_strcasecmp(str, "false")==0) {
215                         if(prop->data==0) return 0;
216                         else return 1;
217                 }
218                 /* no break, do GPROP_int too! */
219                 
220         case GPROP_INT:
221                 return prop->data - atoi(str);
222
223         case GPROP_FLOAT:
224         case GPROP_TIME:
225                 // WARNING: untested for GPROP_TIME
226                 // function isn't used currently
227                 fvalue= *((float *)&prop->data);
228                 ftest= (float)atof(str);
229                 if( fvalue > ftest) return 1;
230                 else if( fvalue < ftest) return -1;
231                 return 0;
232
233         case GPROP_STRING:
234                 return strcmp(prop->poin, str);
235         }
236         
237         return 0;
238 }
239
240 void set_property(bProperty *prop, const char *str)
241 {
242 //      extern int Gdfra;               /* sector.c */
243
244         switch(prop->type) {
245         case GPROP_BOOL:
246                 if(BLI_strcasecmp(str, "true")==0) prop->data= 1;
247                 else if(BLI_strcasecmp(str, "false")==0) prop->data= 0;
248                 else prop->data= (atoi(str)!=0);
249                 break;
250         case GPROP_INT:
251                 prop->data= atoi(str);
252                 break;
253         case GPROP_FLOAT:
254         case GPROP_TIME:
255                 *((float *)&prop->data)= (float)atof(str);
256                 break;
257         case GPROP_STRING:
258                 strcpy(prop->poin, str); /* TODO - check size? */
259                 break;
260         }
261         
262 }
263
264 void add_property(bProperty *prop, const char *str)
265 {
266 //      extern int Gdfra;               /* sector.c */
267
268         switch(prop->type) {
269         case GPROP_BOOL:
270         case GPROP_INT:
271                 prop->data+= atoi(str);
272                 break;
273         case GPROP_FLOAT:
274         case GPROP_TIME:
275                 *((float *)&prop->data)+= (float)atof(str);
276                 break;
277         case GPROP_STRING:
278                 /* strcpy(prop->poin, str); */
279                 break;
280         }
281 }
282
283 /* reads value of property, sets it in chars in str */
284 void set_property_valstr(bProperty *prop, char *str)
285 {
286 //      extern int Gdfra;               /* sector.c */
287
288         if(str == NULL) return;
289
290         switch(prop->type) {
291         case GPROP_BOOL:
292         case GPROP_INT:
293                 sprintf(str, "%d", prop->data);
294                 break;
295         case GPROP_FLOAT:
296         case GPROP_TIME:
297                 sprintf(str, "%f", *((float *)&prop->data));
298                 break;
299         case GPROP_STRING:
300                 BLI_strncpy(str, prop->poin, MAX_PROPSTRING);
301                 break;
302         }
303 }
304
305 void cp_property(bProperty *prop1, bProperty *prop2)
306 {
307         char str[128];
308
309         set_property_valstr(prop2, str);
310
311         set_property(prop1, str);
312 }