Drag and drop 2.5 integration! Finally, slashdot regulars can use
[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_strdupcat(const char *str1, const char *str2)
58 {
59         int len;
60         char *n;
61         
62         len= strlen(str1)+strlen(str2);
63         n= MEM_mallocN(len+1, "strdupcat");
64         strcpy(n, str1);
65         strcat(n, str2);
66         
67         return n;
68 }
69
70 char *BLI_strncpy(char *dst, const char *src, int maxncpy) {
71         int srclen= strlen(src);
72         int cpylen= (srclen>(maxncpy-1))?(maxncpy-1):srclen;
73         
74         memcpy(dst, src, cpylen);
75         dst[cpylen]= '\0';
76         
77         return dst;
78 }
79
80 int BLI_snprintf(char *buffer, size_t count, const char *format, ...)
81 {
82         int n;
83         va_list arg;
84
85         va_start(arg, format);
86         n = vsnprintf(buffer, count, format, arg);
87         
88         if (n != -1 && n < count) {
89                 buffer[n] = '\0';
90         } else {
91                 buffer[count-1] = '\0';
92         }
93         
94         va_end(arg);
95         return n;
96 }
97
98 char *BLI_sprintfN(const char *format, ...)
99 {
100         DynStr *ds;
101         va_list arg;
102         char *n;
103
104         va_start(arg, format);
105
106         ds= BLI_dynstr_new();
107         BLI_dynstr_vappendf(ds, format, arg);
108         n= BLI_dynstr_get_cstring(ds);
109         BLI_dynstr_free(ds);
110
111         va_end(arg);
112
113         return n;
114 }
115
116 /* Makes a copy of the text within the "" that appear after some text 'blahblah'
117  * i.e. for string 'pose["apples"]' with prefix 'pose[', it should grab "apples"
118  * 
119  *      - str: is the entire string to chop
120  *      - prefix: is the part of the string to leave out 
121  *
122  * Assume that the strings returned must be freed afterwards, and that the inputs will contain 
123  * data we want...
124  */
125 char *BLI_getQuotedStr (const char *str, const char *prefix)
126 {
127         int prefixLen = strlen(prefix);
128         char *startMatch, *endMatch;
129         
130         /* get the starting point (i.e. where prefix starts, and add prefixLen+1 to it to get be after the first " */
131         startMatch= strstr(str, prefix) + prefixLen + 1;
132         
133         /* get the end point (i.e. where the next occurance of " is after the starting point) */
134         endMatch= strchr(startMatch, '"'); // "  NOTE: this comment here is just so that my text editor still shows the functions ok...
135         
136         /* return the slice indicated */
137         return BLI_strdupn(startMatch, (int)(endMatch-startMatch));
138 }
139
140 /* Replaces all occurances of oldText with newText in str, returning a new string that doesn't 
141  * contain the 'replaced' occurances.
142  */
143 // A rather wasteful string-replacement utility, though this shall do for now...
144 // Feel free to replace this with an even safe + nicer alternative 
145 char *BLI_replacestr(char *str, const char *oldText, const char *newText)
146 {
147         DynStr *ds= NULL;
148         int lenOld= strlen(oldText);
149         char *match;
150         
151         /* sanity checks */
152         if ((str == NULL) || (str[0]==0))
153                 return NULL;
154         else if ((oldText == NULL) || (newText == NULL) || (oldText[0]==0))
155                 return BLI_strdup(str);
156         
157         /* while we can still find a match for the old substring that we're searching for, 
158          * keep dicing and replacing
159          */
160         while ( (match = strstr(str, oldText)) ) {
161                 /* the assembly buffer only gets created when we actually need to rebuild the string */
162                 if (ds == NULL)
163                         ds= BLI_dynstr_new();
164                         
165                 /* if the match position does not match the current position in the string, 
166                  * copy the text up to this position and advance the current position in the string
167                  */
168                 if (str != match) {
169                         /* replace the token at the 'match' position with \0 so that the copied string will be ok,
170                          * add the segment of the string from str to match to the buffer, then restore the value at match
171                          */
172                         match[0]= 0;
173                         BLI_dynstr_append(ds, str);
174                         match[0]= oldText[0];
175                         
176                         /* now our current position should be set on the start of the match */
177                         str= match;
178                 }
179                 
180                 /* add the replacement text to the accumulation buffer */
181                 BLI_dynstr_append(ds, newText);
182                 
183                 /* advance the current position of the string up to the end of the replaced segment */
184                 str += lenOld;
185         }
186         
187         /* finish off and return a new string that has had all occurances of */
188         if (ds) {
189                 char *newStr;
190                 
191                 /* add what's left of the string to the assembly buffer 
192                  *      - we've been adjusting str to point at the end of the replaced segments
193                  */
194                 if (str != NULL)
195                         BLI_dynstr_append(ds, str);
196                 
197                 /* convert to new c-string (MEM_malloc'd), and free the buffer */
198                 newStr= BLI_dynstr_get_cstring(ds);
199                 BLI_dynstr_free(ds);
200                 
201                 return newStr;
202         }
203         else {
204                 /* just create a new copy of the entire string - we avoid going through the assembly buffer 
205                  * for what should be a bit more efficiency...
206                  */
207                 return BLI_strdup(str);
208         }
209
210
211 int BLI_streq(const char *a, const char *b) 
212 {
213         return (strcmp(a, b)==0);
214 }
215
216 int BLI_strcaseeq(const char *a, const char *b) 
217 {
218         return (BLI_strcasecmp(a, b)==0);
219 }
220
221 /* strcasestr not available in MSVC */
222 char *BLI_strcasestr(const char *s, const char *find)
223 {
224     register char c, sc;
225     register size_t len;
226         
227     if ((c = *find++) != 0) {
228                 c= tolower(c);
229                 len = strlen(find);
230                 do {
231                         do {
232                                 if ((sc = *s++) == 0)
233                                         return (NULL);
234                                 sc= tolower(sc);
235                         } while (sc != c);
236                 } while (BLI_strncasecmp(s, find, len) != 0);
237                 s--;
238     }
239     return ((char *) s);
240 }
241
242
243 int BLI_strcasecmp(const char *s1, const char *s2) {
244         int i;
245
246         for (i=0; ; i++) {
247                 char c1 = tolower(s1[i]);
248                 char c2 = tolower(s2[i]);
249
250                 if (c1<c2) {
251                         return -1;
252                 } else if (c1>c2) {
253                         return 1;
254                 } else if (c1==0) {
255                         break;
256                 }
257         }
258
259         return 0;
260 }
261
262 int BLI_strncasecmp(const char *s1, const char *s2, int n) {
263         int i;
264
265         for (i=0; i<n; i++) {
266                 char c1 = tolower(s1[i]);
267                 char c2 = tolower(s2[i]);
268
269                 if (c1<c2) {
270                         return -1;
271                 } else if (c1>c2) {
272                         return 1;
273                 } else if (c1==0) {
274                         break;
275                 }
276         }
277
278         return 0;
279 }
280
281 /* natural string compare, keeping numbers in order */
282 int BLI_natstrcmp(const char *s1, const char *s2)
283 {
284         int d1= 0, d2= 0;
285         
286         /* if both chars are numeric, to a strtol().
287            then increase string deltas as long they are 
288            numeric, else do a tolower and char compare */
289         
290         while(1) {
291                 char c1 = tolower(s1[d1]);
292                 char c2 = tolower(s2[d2]);
293                 
294                 if( isdigit(c1) && isdigit(c2) ) {
295                         int val1, val2;
296                         
297                         val1= (int)strtol(s1+d1, (char **)NULL, 10);
298                         val2= (int)strtol(s2+d2, (char **)NULL, 10);
299                         
300                         if (val1<val2) {
301                                 return -1;
302                         } else if (val1>val2) {
303                                 return 1;
304                         }
305                         d1++;
306                         while( isdigit(s1[d1]) )
307                                 d1++;
308                         d2++;
309                         while( isdigit(s2[d2]) )
310                                 d2++;
311                         
312                         c1 = tolower(s1[d1]);
313                         c2 = tolower(s2[d2]);
314                 }
315                 
316                 if (c1<c2) {
317                         return -1;
318                 } else if (c1>c2) {
319                         return 1;
320                 } else if (c1==0) {
321                         break;
322                 }
323                 d1++;
324                 d2++;
325         }
326         return 0;
327 }
328
329 void BLI_timestr(double _time, char *str)
330 {
331         /* format 00:00:00.00 (hr:min:sec) string has to be 12 long */
332         int  hr= ( (int)  _time) / (60*60);
333         int min= (((int)  _time) / 60 ) % 60;
334         int sec= ( (int) (_time)) % 60;
335         int hun= ( (int) (_time   * 100.0)) % 100;
336         
337         if (hr) {
338                 sprintf(str, "%.2d:%.2d:%.2d.%.2d",hr,min,sec,hun);
339         } else {
340                 sprintf(str, "%.2d:%.2d.%.2d",min,sec,hun);
341         }
342         
343         str[11]=0;
344 }