synched with trunk at revision 34793
[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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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 <string.h>
36 #include <stdlib.h>
37 #include <stdarg.h>
38 #include <ctype.h>
39
40 #include "MEM_guardedalloc.h"
41
42 #include "BLI_dynstr.h"
43 #include "BLI_string.h"
44
45 char *BLI_strdupn(const char *str, int len) {
46         char *n= MEM_mallocN(len+1, "strdup");
47         memcpy(n, str, len);
48         n[len]= '\0';
49         
50         return n;
51 }
52 char *BLI_strdup(const char *str) {
53         return BLI_strdupn(str, strlen(str));
54 }
55
56 char *BLI_strdupcat(const char *str1, const char *str2)
57 {
58         int len;
59         char *n;
60         
61         len= strlen(str1)+strlen(str2);
62         n= MEM_mallocN(len+1, "strdupcat");
63         strcpy(n, str1);
64         strcat(n, str2);
65         
66         return n;
67 }
68
69 char *BLI_strncpy(char *dst, const char *src, int maxncpy) {
70         int srclen= strlen(src);
71         int cpylen= (srclen>(maxncpy-1))?(maxncpy-1):srclen;
72         
73         memcpy(dst, src, cpylen);
74         dst[cpylen]= '\0';
75         
76         return dst;
77 }
78
79 int BLI_snprintf(char *buffer, size_t count, const char *format, ...)
80 {
81         int n;
82         va_list arg;
83
84         va_start(arg, format);
85         n = vsnprintf(buffer, count, format, arg);
86         
87         if (n != -1 && n < count) {
88                 buffer[n] = '\0';
89         } else {
90                 buffer[count-1] = '\0';
91         }
92         
93         va_end(arg);
94         return n;
95 }
96
97 char *BLI_sprintfN(const char *format, ...)
98 {
99         DynStr *ds;
100         va_list arg;
101         char *n;
102
103         va_start(arg, format);
104
105         ds= BLI_dynstr_new();
106         BLI_dynstr_vappendf(ds, format, arg);
107         n= BLI_dynstr_get_cstring(ds);
108         BLI_dynstr_free(ds);
109
110         va_end(arg);
111
112         return n;
113 }
114
115 /* Makes a copy of the text within the "" that appear after some text 'blahblah'
116  * i.e. for string 'pose["apples"]' with prefix 'pose[', it should grab "apples"
117  * 
118  *      - str: is the entire string to chop
119  *      - prefix: is the part of the string to leave out 
120  *
121  * Assume that the strings returned must be freed afterwards, and that the inputs will contain 
122  * data we want...
123  */
124 char *BLI_getQuotedStr (const char *str, const char *prefix)
125 {
126         int prefixLen = strlen(prefix);
127         char *startMatch, *endMatch;
128         
129         /* get the starting point (i.e. where prefix starts, and add prefixLen+1 to it to get be after the first " */
130         startMatch= strstr(str, prefix) + prefixLen + 1;
131         
132         /* get the end point (i.e. where the next occurance of " is after the starting point) */
133         endMatch= strchr(startMatch, '"'); // "  NOTE: this comment here is just so that my text editor still shows the functions ok...
134         
135         /* return the slice indicated */
136         return BLI_strdupn(startMatch, (int)(endMatch-startMatch));
137 }
138
139 /* Replaces all occurances of oldText with newText in str, returning a new string that doesn't 
140  * contain the 'replaced' occurances.
141  */
142 // A rather wasteful string-replacement utility, though this shall do for now...
143 // Feel free to replace this with an even safe + nicer alternative 
144 char *BLI_replacestr(char *str, const char *oldText, const char *newText)
145 {
146         DynStr *ds= NULL;
147         int lenOld= strlen(oldText);
148         char *match;
149         
150         /* sanity checks */
151         if ((str == NULL) || (str[0]==0))
152                 return NULL;
153         else if ((oldText == NULL) || (newText == NULL) || (oldText[0]==0))
154                 return BLI_strdup(str);
155         
156         /* while we can still find a match for the old substring that we're searching for, 
157          * keep dicing and replacing
158          */
159         while ( (match = strstr(str, oldText)) ) {
160                 /* the assembly buffer only gets created when we actually need to rebuild the string */
161                 if (ds == NULL)
162                         ds= BLI_dynstr_new();
163                         
164                 /* if the match position does not match the current position in the string, 
165                  * copy the text up to this position and advance the current position in the string
166                  */
167                 if (str != match) {
168                         /* replace the token at the 'match' position with \0 so that the copied string will be ok,
169                          * add the segment of the string from str to match to the buffer, then restore the value at match
170                          */
171                         match[0]= 0;
172                         BLI_dynstr_append(ds, str);
173                         match[0]= oldText[0];
174                         
175                         /* now our current position should be set on the start of the match */
176                         str= match;
177                 }
178                 
179                 /* add the replacement text to the accumulation buffer */
180                 BLI_dynstr_append(ds, newText);
181                 
182                 /* advance the current position of the string up to the end of the replaced segment */
183                 str += lenOld;
184         }
185         
186         /* finish off and return a new string that has had all occurances of */
187         if (ds) {
188                 char *newStr;
189                 
190                 /* add what's left of the string to the assembly buffer 
191                  *      - we've been adjusting str to point at the end of the replaced segments
192                  */
193                 if (str != NULL)
194                         BLI_dynstr_append(ds, str);
195                 
196                 /* convert to new c-string (MEM_malloc'd), and free the buffer */
197                 newStr= BLI_dynstr_get_cstring(ds);
198                 BLI_dynstr_free(ds);
199                 
200                 return newStr;
201         }
202         else {
203                 /* just create a new copy of the entire string - we avoid going through the assembly buffer 
204                  * for what should be a bit more efficiency...
205                  */
206                 return BLI_strdup(str);
207         }
208
209
210 int BLI_streq(const char *a, const char *b) 
211 {
212         return (strcmp(a, b)==0);
213 }
214
215 int BLI_strcaseeq(const char *a, const char *b) 
216 {
217         return (BLI_strcasecmp(a, b)==0);
218 }
219
220 /* strcasestr not available in MSVC */
221 char *BLI_strcasestr(const char *s, const char *find)
222 {
223         register char c, sc;
224         register size_t len;
225         
226         if ((c = *find++) != 0) {
227                 c= tolower(c);
228                 len = strlen(find);
229                 do {
230                         do {
231                                 if ((sc = *s++) == 0)
232                                         return (NULL);
233                                 sc= tolower(sc);
234                         } while (sc != c);
235                 } while (BLI_strncasecmp(s, find, len) != 0);
236                 s--;
237         }
238         return ((char *) s);
239 }
240
241
242 int BLI_strcasecmp(const char *s1, const char *s2) {
243         int i;
244
245         for (i=0; ; i++) {
246                 char c1 = tolower(s1[i]);
247                 char c2 = tolower(s2[i]);
248
249                 if (c1<c2) {
250                         return -1;
251                 } else if (c1>c2) {
252                         return 1;
253                 } else if (c1==0) {
254                         break;
255                 }
256         }
257
258         return 0;
259 }
260
261 int BLI_strncasecmp(const char *s1, const char *s2, int n) {
262         int i;
263
264         for (i=0; i<n; i++) {
265                 char c1 = tolower(s1[i]);
266                 char c2 = tolower(s2[i]);
267
268                 if (c1<c2) {
269                         return -1;
270                 } else if (c1>c2) {
271                         return 1;
272                 } else if (c1==0) {
273                         break;
274                 }
275         }
276
277         return 0;
278 }
279
280 /* natural string compare, keeping numbers in order */
281 int BLI_natstrcmp(const char *s1, const char *s2)
282 {
283         int d1= 0, d2= 0;
284         
285         /* if both chars are numeric, to a strtol().
286            then increase string deltas as long they are 
287            numeric, else do a tolower and char compare */
288         
289         while(1) {
290                 char c1 = tolower(s1[d1]);
291                 char c2 = tolower(s2[d2]);
292                 
293                 if( isdigit(c1) && isdigit(c2) ) {
294                         int val1, val2;
295                         
296                         val1= (int)strtol(s1+d1, (char **)NULL, 10);
297                         val2= (int)strtol(s2+d2, (char **)NULL, 10);
298                         
299                         if (val1<val2) {
300                                 return -1;
301                         } else if (val1>val2) {
302                                 return 1;
303                         }
304                         d1++;
305                         while( isdigit(s1[d1]) )
306                                 d1++;
307                         d2++;
308                         while( isdigit(s2[d2]) )
309                                 d2++;
310                         
311                         c1 = tolower(s1[d1]);
312                         c2 = tolower(s2[d2]);
313                 }
314                 
315                 if (c1<c2) {
316                         return -1;
317                 } else if (c1>c2) {
318                         return 1;
319                 } else if (c1==0) {
320                         break;
321                 }
322                 d1++;
323                 d2++;
324         }
325         return 0;
326 }
327
328 void BLI_timestr(double _time, char *str)
329 {
330         /* format 00:00:00.00 (hr:min:sec) string has to be 12 long */
331         int  hr= ( (int)  _time) / (60*60);
332         int min= (((int)  _time) / 60 ) % 60;
333         int sec= ( (int) (_time)) % 60;
334         int hun= ( (int) (_time   * 100.0)) % 100;
335         
336         if (hr) {
337                 sprintf(str, "%.2d:%.2d:%.2d.%.2d",hr,min,sec,hun);
338         } else {
339                 sprintf(str, "%.2d:%.2d.%.2d",min,sec,hun);
340         }
341         
342         str[11]=0;
343 }
344
345 /* determine the length of a fixed-size string */
346 size_t BLI_strnlen(const char *str, size_t maxlen)
347 {
348         const char *end = memchr(str, '\0', maxlen);
349         return end ? (size_t) (end - str) : maxlen;
350 }
351
352 /* from libswish3, originally called u8_isvalid(),
353  * modified to return the index of the bad character (byte index not utf).
354  * http://svn.swish-e.org/libswish3/trunk/src/libswish3/utf8.c r3044 - campbell */
355
356 /* based on the valid_utf8 routine from the PCRE library by Philip Hazel
357
358    length is in bytes, since without knowing whether the string is valid
359    it's hard to know how many characters there are! */
360
361 static const char trailingBytesForUTF8[256] = {
362         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
363         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
364         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
365         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
366         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
367         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
368         1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
369         2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5
370 };
371
372 int BLI_utf8_invalid_byte(const char *str, int length)
373 {
374     const unsigned char *p, *pend = (unsigned char*)str + length;
375     unsigned char c;
376     int ab;
377
378     for (p = (unsigned char*)str; p < pend; p++) {
379         c = *p;
380         if (c < 128)
381             continue;
382         if ((c & 0xc0) != 0xc0)
383             goto utf8_error;
384         ab = trailingBytesForUTF8[c];
385         if (length < ab)
386             goto utf8_error;
387         length -= ab;
388
389         p++;
390         /* Check top bits in the second byte */
391         if ((*p & 0xc0) != 0x80)
392             goto utf8_error;
393
394         /* Check for overlong sequences for each different length */
395         switch (ab) {
396             /* Check for xx00 000x */
397         case 1:
398             if ((c & 0x3e) == 0) goto utf8_error;
399             continue;   /* We know there aren't any more bytes to check */
400
401             /* Check for 1110 0000, xx0x xxxx */
402         case 2:
403             if (c == 0xe0 && (*p & 0x20) == 0) goto utf8_error;
404             break;
405
406             /* Check for 1111 0000, xx00 xxxx */
407         case 3:
408             if (c == 0xf0 && (*p & 0x30) == 0) goto utf8_error;
409             break;
410
411             /* Check for 1111 1000, xx00 0xxx */
412         case 4:
413             if (c == 0xf8 && (*p & 0x38) == 0) goto utf8_error;
414             break;
415
416             /* Check for leading 0xfe or 0xff,
417                and then for 1111 1100, xx00 00xx */
418         case 5:
419             if (c == 0xfe || c == 0xff ||
420                 (c == 0xfc && (*p & 0x3c) == 0)) goto utf8_error;
421             break;
422         }
423
424         /* Check for valid bytes after the 2nd, if any; all must start 10 */
425         while (--ab > 0) {
426             if ((*(p+1) & 0xc0) != 0x80) goto utf8_error;
427                         p++; /* do this after so we get usable offset - campbell */
428         }
429     }
430
431     return -1;
432
433 utf8_error:
434
435         return (int)((char *)p - (char *)str) - 1;
436 }
437
438 int BLI_utf8_invalid_strip(char *str, int length)
439 {
440         int bad_char, tot= 0;
441
442         while((bad_char= BLI_utf8_invalid_byte(str, length)) != -1) {
443                 str += bad_char;
444                 length -= bad_char;
445
446                 if(length == 0) {
447                         /* last character bad, strip it */
448                         *str= '\0';
449                         tot++;
450                         break;
451                 }
452                 else {
453                         /* strip, keep looking */
454                         memmove(str, str + 1, length);
455                         tot++;
456                 }
457         }
458
459         return tot;
460 }
461