merge with/from trunk at r35190
[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, const 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                 /* first check for '.' so "foo.bar" comes before "foo 1.bar" */ 
316                 if(c1=='.' && c2!='.')
317                         return -1;
318                 if(c1!='.' && c2=='.')
319                         return 1;
320                 else if (c1<c2) {
321                         return -1;
322                 } else if (c1>c2) {
323                         return 1;
324                 } else if (c1==0) {
325                         break;
326                 }
327                 d1++;
328                 d2++;
329         }
330         return 0;
331 }
332
333 void BLI_timestr(double _time, char *str)
334 {
335         /* format 00:00:00.00 (hr:min:sec) string has to be 12 long */
336         int  hr= ( (int)  _time) / (60*60);
337         int min= (((int)  _time) / 60 ) % 60;
338         int sec= ( (int) (_time)) % 60;
339         int hun= ( (int) (_time   * 100.0)) % 100;
340         
341         if (hr) {
342                 sprintf(str, "%.2d:%.2d:%.2d.%.2d",hr,min,sec,hun);
343         } else {
344                 sprintf(str, "%.2d:%.2d.%.2d",min,sec,hun);
345         }
346         
347         str[11]=0;
348 }
349
350 /* determine the length of a fixed-size string */
351 size_t BLI_strnlen(const char *str, size_t maxlen)
352 {
353         const char *end = memchr(str, '\0', maxlen);
354         return end ? (size_t) (end - str) : maxlen;
355 }
356
357 /* from libswish3, originally called u8_isvalid(),
358  * modified to return the index of the bad character (byte index not utf).
359  * http://svn.swish-e.org/libswish3/trunk/src/libswish3/utf8.c r3044 - campbell */
360
361 /* based on the valid_utf8 routine from the PCRE library by Philip Hazel
362
363    length is in bytes, since without knowing whether the string is valid
364    it's hard to know how many characters there are! */
365
366 static const char trailingBytesForUTF8[256] = {
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         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,
369         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,
370         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,
371         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,
372         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,
373         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,
374         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
375 };
376
377 int BLI_utf8_invalid_byte(const char *str, int length)
378 {
379     const unsigned char *p, *pend = (unsigned char*)str + length;
380     unsigned char c;
381     int ab;
382
383     for (p = (unsigned char*)str; p < pend; p++) {
384         c = *p;
385         if (c < 128)
386             continue;
387         if ((c & 0xc0) != 0xc0)
388             goto utf8_error;
389         ab = trailingBytesForUTF8[c];
390         if (length < ab)
391             goto utf8_error;
392         length -= ab;
393
394         p++;
395         /* Check top bits in the second byte */
396         if ((*p & 0xc0) != 0x80)
397             goto utf8_error;
398
399         /* Check for overlong sequences for each different length */
400         switch (ab) {
401             /* Check for xx00 000x */
402         case 1:
403             if ((c & 0x3e) == 0) goto utf8_error;
404             continue;   /* We know there aren't any more bytes to check */
405
406             /* Check for 1110 0000, xx0x xxxx */
407         case 2:
408             if (c == 0xe0 && (*p & 0x20) == 0) goto utf8_error;
409             break;
410
411             /* Check for 1111 0000, xx00 xxxx */
412         case 3:
413             if (c == 0xf0 && (*p & 0x30) == 0) goto utf8_error;
414             break;
415
416             /* Check for 1111 1000, xx00 0xxx */
417         case 4:
418             if (c == 0xf8 && (*p & 0x38) == 0) goto utf8_error;
419             break;
420
421             /* Check for leading 0xfe or 0xff,
422                and then for 1111 1100, xx00 00xx */
423         case 5:
424             if (c == 0xfe || c == 0xff ||
425                 (c == 0xfc && (*p & 0x3c) == 0)) goto utf8_error;
426             break;
427         }
428
429         /* Check for valid bytes after the 2nd, if any; all must start 10 */
430         while (--ab > 0) {
431             if ((*(p+1) & 0xc0) != 0x80) goto utf8_error;
432                         p++; /* do this after so we get usable offset - campbell */
433         }
434     }
435
436     return -1;
437
438 utf8_error:
439
440         return (int)((char *)p - (char *)str) - 1;
441 }
442
443 int BLI_utf8_invalid_strip(char *str, int length)
444 {
445         int bad_char, tot= 0;
446
447         while((bad_char= BLI_utf8_invalid_byte(str, length)) != -1) {
448                 str += bad_char;
449                 length -= bad_char;
450
451                 if(length == 0) {
452                         /* last character bad, strip it */
453                         *str= '\0';
454                         tot++;
455                         break;
456                 }
457                 else {
458                         /* strip, keep looking */
459                         memmove(str, str + 1, length);
460                         tot++;
461                 }
462         }
463
464         return tot;
465 }
466