de4b53cbd93f236e5166143059f03ef3055168fa
[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 /* Replaces all occurances of oldText with newText in str, returning a new string that doesn't 
104  * contain the 'replaced' occurances.
105  */
106 // A rather wasteful string-replacement utility, though this shall do for now...
107 // Feel free to replace this with an even safe + nicer alternative 
108 char *BLI_replacestr(char *str, const char *oldText, const char *newText)
109 {
110         DynStr *ds= NULL;
111         int lenOld= strlen(oldText);
112         char *match;
113         
114         /* sanity checks */
115         if ((str == NULL) || (str[0]==0))
116                 return NULL;
117         else if ((oldText == NULL) || (newText == NULL) || (oldText[0]==0))
118                 return BLI_strdup(str);
119         
120         /* while we can still find a match for the old substring that we're searching for, 
121          * keep dicing and replacing
122          */
123         while ( (match = strstr(str, oldText)) ) {
124                 /* the assembly buffer only gets created when we actually need to rebuild the string */
125                 if (ds == NULL)
126                         ds= BLI_dynstr_new();
127                         
128                 /* if the match position does not match the current position in the string, 
129                  * copy the text up to this position and advance the current position in the string
130                  */
131                 if (str != match) {
132                         /* replace the token at the 'match' position with \0 so that the copied string will be ok,
133                          * add the segment of the string from str to match to the buffer, then restore the value at match
134                          */
135                         match[0]= 0;
136                         BLI_dynstr_append(ds, str);
137                         match[0]= oldText[0];
138                         
139                         /* now our current position should be set on the start of the match */
140                         str= match;
141                 }
142                 
143                 /* add the replacement text to the accumulation buffer */
144                 BLI_dynstr_append(ds, newText);
145                 
146                 /* advance the current position of the string up to the end of the replaced segment */
147                 str += lenOld;
148         }
149         
150         /* finish off and return a new string that has had all occurances of */
151         if (ds) {
152                 char *newStr;
153                 
154                 /* add what's left of the string to the assembly buffer 
155                  *      - we've been adjusting str to point at the end of the replaced segments
156                  */
157                 if (str != NULL)
158                         BLI_dynstr_append(ds, str);
159                 
160                 /* convert to new c-string (MEM_malloc'd), and free the buffer */
161                 newStr= BLI_dynstr_get_cstring(ds);
162                 BLI_dynstr_free(ds);
163                 
164                 return newStr;
165         }
166         else {
167                 /* just create a new copy of the entire string - we avoid going through the assembly buffer 
168                  * for what should be a bit more efficiency...
169                  */
170                 return BLI_strdup(str);
171         }
172
173
174 int BLI_streq(const char *a, const char *b) 
175 {
176         return (strcmp(a, b)==0);
177 }
178
179 int BLI_strcaseeq(const char *a, const char *b) 
180 {
181         return (BLI_strcasecmp(a, b)==0);
182 }
183
184 /* strcasestr not available in MSVC */
185 char *BLI_strcasestr(const char *s, const char *find)
186 {
187     register char c, sc;
188     register size_t len;
189         
190     if ((c = *find++) != 0) {
191                 c= tolower(c);
192                 len = strlen(find);
193                 do {
194                         do {
195                                 if ((sc = *s++) == 0)
196                                         return (NULL);
197                                 sc= tolower(sc);
198                         } while (sc != c);
199                 } while (BLI_strncasecmp(s, find, len) != 0);
200                 s--;
201     }
202     return ((char *) s);
203 }
204
205
206 int BLI_strcasecmp(const char *s1, const char *s2) {
207         int i;
208
209         for (i=0; ; i++) {
210                 char c1 = tolower(s1[i]);
211                 char c2 = tolower(s2[i]);
212
213                 if (c1<c2) {
214                         return -1;
215                 } else if (c1>c2) {
216                         return 1;
217                 } else if (c1==0) {
218                         break;
219                 }
220         }
221
222         return 0;
223 }
224
225 int BLI_strncasecmp(const char *s1, const char *s2, int n) {
226         int i;
227
228         for (i=0; i<n; i++) {
229                 char c1 = tolower(s1[i]);
230                 char c2 = tolower(s2[i]);
231
232                 if (c1<c2) {
233                         return -1;
234                 } else if (c1>c2) {
235                         return 1;
236                 } else if (c1==0) {
237                         break;
238                 }
239         }
240
241         return 0;
242 }
243
244 /* natural string compare, keeping numbers in order */
245 int BLI_natstrcmp(const char *s1, const char *s2)
246 {
247         int d1= 0, d2= 0;
248         
249         /* if both chars are numeric, to a strtol().
250            then increase string deltas as long they are 
251            numeric, else do a tolower and char compare */
252         
253         while(1) {
254                 char c1 = tolower(s1[d1]);
255                 char c2 = tolower(s2[d2]);
256                 
257                 if( isdigit(c1) && isdigit(c2) ) {
258                         int val1, val2;
259                         
260                         val1= (int)strtol(s1+d1, (char **)NULL, 10);
261                         val2= (int)strtol(s2+d2, (char **)NULL, 10);
262                         
263                         if (val1<val2) {
264                                 return -1;
265                         } else if (val1>val2) {
266                                 return 1;
267                         }
268                         d1++;
269                         while( isdigit(s1[d1]) )
270                                 d1++;
271                         d2++;
272                         while( isdigit(s2[d2]) )
273                                 d2++;
274                         
275                         c1 = tolower(s1[d1]);
276                         c2 = tolower(s2[d2]);
277                 }
278                 
279                 if (c1<c2) {
280                         return -1;
281                 } else if (c1>c2) {
282                         return 1;
283                 } else if (c1==0) {
284                         break;
285                 }
286                 d1++;
287                 d2++;
288         }
289         return 0;
290 }
291
292 void BLI_timestr(double _time, char *str)
293 {
294         /* format 00:00:00.00 (hr:min:sec) string has to be 12 long */
295         int  hr= ( (int)  _time) / (60*60);
296         int min= (((int)  _time) / 60 ) % 60;
297         int sec= ( (int) (_time)) % 60;
298         int hun= ( (int) (_time   * 100.0)) % 100;
299         
300         if (hr) {
301                 sprintf(str, "%.2d:%.2d:%.2d.%.2d",hr,min,sec,hun);
302         } else {
303                 sprintf(str, "%.2d:%.2d.%.2d",min,sec,hun);
304         }
305         
306         str[11]=0;
307 }