Animation Editors: 'Only Selected' filtering option now works on Pose Channels too
[blender.git] / source / blender / blenlib / intern / string.c
1 /* util.c
2  *
3  * various string, file, list operations.
4  *
5  *
6  * $Id$
7  *
8  * ***** BEGIN GPL LICENSE BLOCK *****
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software Foundation,
22  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
23  *
24  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
25  * All rights reserved.
26  *
27  * The Original Code is: all of this file.
28  *
29  * Contributor(s): none yet.
30  *
31  * ***** END GPL LICENSE BLOCK *****
32  * 
33  */
34
35 #include <stdio.h>
36 #include <string.h>
37 #include <stdlib.h>
38 #include <stdarg.h>
39 #include <ctype.h>
40
41 #include "MEM_guardedalloc.h"
42
43 #include "BLI_dynstr.h"
44 #include "BLI_string.h"
45
46 char *BLI_strdupn(const char *str, int len) {
47         char *n= MEM_mallocN(len+1, "strdup");
48         memcpy(n, str, len);
49         n[len]= '\0';
50         
51         return n;
52 }
53 char *BLI_strdup(const char *str) {
54         return BLI_strdupn(str, strlen(str));
55 }
56
57 char *BLI_strncpy(char *dst, const char *src, int maxncpy) {
58         int srclen= strlen(src);
59         int cpylen= (srclen>(maxncpy-1))?(maxncpy-1):srclen;
60         
61         memcpy(dst, src, cpylen);
62         dst[cpylen]= '\0';
63         
64         return dst;
65 }
66
67 int BLI_snprintf(char *buffer, size_t count, const char *format, ...)
68 {
69         int n;
70         va_list arg;
71
72         va_start(arg, format);
73         n = vsnprintf(buffer, count, format, arg);
74         
75         if (n != -1 && n < count) {
76                 buffer[n] = '\0';
77         } else {
78                 buffer[count-1] = '\0';
79         }
80         
81         va_end(arg);
82         return n;
83 }
84
85 char *BLI_sprintfN(const char *format, ...)
86 {
87         DynStr *ds;
88         va_list arg;
89         char *n;
90
91         va_start(arg, format);
92
93         ds= BLI_dynstr_new();
94         BLI_dynstr_vappendf(ds, format, arg);
95         n= BLI_dynstr_get_cstring(ds);
96         BLI_dynstr_free(ds);
97
98         va_end(arg);
99
100         return n;
101 }
102
103 /* Makes a copy of the text within the "" that appear after some text 'blahblah'
104  * i.e. for string 'pose["apples"]' with prefix 'pose[', it should grab "apples"
105  * 
106  *      - str: is the entire string to chop
107  *      - prefix: is the part of the string to leave out 
108  *
109  * Assume that the strings returned must be freed afterwards, and that the inputs will contain 
110  * data we want...
111  */
112 char *BLI_getQuotedStr (const char *str, const char *prefix)
113 {
114         int prefixLen = strlen(prefix);
115         char *startMatch, *endMatch;
116         
117         /* get the starting point (i.e. where prefix starts, and add prefixLen+1 to it to get be after the first " */
118         startMatch= strstr(str, prefix) + prefixLen + 1;
119         
120         /* get the end point (i.e. where the next occurance of " is after the starting point) */
121         endMatch= strchr(startMatch, '"'); // "  NOTE: this comment here is just so that my text editor still shows the functions ok...
122         
123         /* return the slice indicated */
124         return BLI_strdupn(startMatch, (int)(endMatch-startMatch));
125 }
126
127 /* Replaces all occurances of oldText with newText in str, returning a new string that doesn't 
128  * contain the 'replaced' occurances.
129  */
130 // A rather wasteful string-replacement utility, though this shall do for now...
131 // Feel free to replace this with an even safe + nicer alternative 
132 char *BLI_replacestr(char *str, const char *oldText, const char *newText)
133 {
134         DynStr *ds= NULL;
135         int lenOld= strlen(oldText);
136         char *match;
137         
138         /* sanity checks */
139         if ((str == NULL) || (str[0]==0))
140                 return NULL;
141         else if ((oldText == NULL) || (newText == NULL) || (oldText[0]==0))
142                 return BLI_strdup(str);
143         
144         /* while we can still find a match for the old substring that we're searching for, 
145          * keep dicing and replacing
146          */
147         while ( (match = strstr(str, oldText)) ) {
148                 /* the assembly buffer only gets created when we actually need to rebuild the string */
149                 if (ds == NULL)
150                         ds= BLI_dynstr_new();
151                         
152                 /* if the match position does not match the current position in the string, 
153                  * copy the text up to this position and advance the current position in the string
154                  */
155                 if (str != match) {
156                         /* replace the token at the 'match' position with \0 so that the copied string will be ok,
157                          * add the segment of the string from str to match to the buffer, then restore the value at match
158                          */
159                         match[0]= 0;
160                         BLI_dynstr_append(ds, str);
161                         match[0]= oldText[0];
162                         
163                         /* now our current position should be set on the start of the match */
164                         str= match;
165                 }
166                 
167                 /* add the replacement text to the accumulation buffer */
168                 BLI_dynstr_append(ds, newText);
169                 
170                 /* advance the current position of the string up to the end of the replaced segment */
171                 str += lenOld;
172         }
173         
174         /* finish off and return a new string that has had all occurances of */
175         if (ds) {
176                 char *newStr;
177                 
178                 /* add what's left of the string to the assembly buffer 
179                  *      - we've been adjusting str to point at the end of the replaced segments
180                  */
181                 if (str != NULL)
182                         BLI_dynstr_append(ds, str);
183                 
184                 /* convert to new c-string (MEM_malloc'd), and free the buffer */
185                 newStr= BLI_dynstr_get_cstring(ds);
186                 BLI_dynstr_free(ds);
187                 
188                 return newStr;
189         }
190         else {
191                 /* just create a new copy of the entire string - we avoid going through the assembly buffer 
192                  * for what should be a bit more efficiency...
193                  */
194                 return BLI_strdup(str);
195         }
196
197
198 int BLI_streq(const char *a, const char *b) 
199 {
200         return (strcmp(a, b)==0);
201 }
202
203 int BLI_strcaseeq(const char *a, const char *b) 
204 {
205         return (BLI_strcasecmp(a, b)==0);
206 }
207
208 /* strcasestr not available in MSVC */
209 char *BLI_strcasestr(const char *s, const char *find)
210 {
211     register char c, sc;
212     register size_t len;
213         
214     if ((c = *find++) != 0) {
215                 c= tolower(c);
216                 len = strlen(find);
217                 do {
218                         do {
219                                 if ((sc = *s++) == 0)
220                                         return (NULL);
221                                 sc= tolower(sc);
222                         } while (sc != c);
223                 } while (BLI_strncasecmp(s, find, len) != 0);
224                 s--;
225     }
226     return ((char *) s);
227 }
228
229
230 int BLI_strcasecmp(const char *s1, const char *s2) {
231         int i;
232
233         for (i=0; ; i++) {
234                 char c1 = tolower(s1[i]);
235                 char c2 = tolower(s2[i]);
236
237                 if (c1<c2) {
238                         return -1;
239                 } else if (c1>c2) {
240                         return 1;
241                 } else if (c1==0) {
242                         break;
243                 }
244         }
245
246         return 0;
247 }
248
249 int BLI_strncasecmp(const char *s1, const char *s2, int n) {
250         int i;
251
252         for (i=0; i<n; i++) {
253                 char c1 = tolower(s1[i]);
254                 char c2 = tolower(s2[i]);
255
256                 if (c1<c2) {
257                         return -1;
258                 } else if (c1>c2) {
259                         return 1;
260                 } else if (c1==0) {
261                         break;
262                 }
263         }
264
265         return 0;
266 }
267
268 /* natural string compare, keeping numbers in order */
269 int BLI_natstrcmp(const char *s1, const char *s2)
270 {
271         int d1= 0, d2= 0;
272         
273         /* if both chars are numeric, to a strtol().
274            then increase string deltas as long they are 
275            numeric, else do a tolower and char compare */
276         
277         while(1) {
278                 char c1 = tolower(s1[d1]);
279                 char c2 = tolower(s2[d2]);
280                 
281                 if( isdigit(c1) && isdigit(c2) ) {
282                         int val1, val2;
283                         
284                         val1= (int)strtol(s1+d1, (char **)NULL, 10);
285                         val2= (int)strtol(s2+d2, (char **)NULL, 10);
286                         
287                         if (val1<val2) {
288                                 return -1;
289                         } else if (val1>val2) {
290                                 return 1;
291                         }
292                         d1++;
293                         while( isdigit(s1[d1]) )
294                                 d1++;
295                         d2++;
296                         while( isdigit(s2[d2]) )
297                                 d2++;
298                         
299                         c1 = tolower(s1[d1]);
300                         c2 = tolower(s2[d2]);
301                 }
302                 
303                 if (c1<c2) {
304                         return -1;
305                 } else if (c1>c2) {
306                         return 1;
307                 } else if (c1==0) {
308                         break;
309                 }
310                 d1++;
311                 d2++;
312         }
313         return 0;
314 }
315
316 void BLI_timestr(double _time, char *str)
317 {
318         /* format 00:00:00.00 (hr:min:sec) string has to be 12 long */
319         int  hr= ( (int)  _time) / (60*60);
320         int min= (((int)  _time) / 60 ) % 60;
321         int sec= ( (int) (_time)) % 60;
322         int hun= ( (int) (_time   * 100.0)) % 100;
323         
324         if (hr) {
325                 sprintf(str, "%.2d:%.2d:%.2d.%.2d",hr,min,sec,hun);
326         } else {
327                 sprintf(str, "%.2d:%.2d.%.2d",min,sec,hun);
328         }
329         
330         str[11]=0;
331 }