merged to r37017 from trunk
[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 /** \file blender/blenlib/intern/string.c
36  *  \ingroup bli
37  */
38
39
40 #include <string.h>
41 #include <stdlib.h>
42 #include <stdarg.h>
43 #include <ctype.h>
44
45 #include "MEM_guardedalloc.h"
46
47 #include "BLI_dynstr.h"
48 #include "BLI_string.h"
49
50 char *BLI_strdupn(const char *str, const size_t len) {
51         char *n= MEM_mallocN(len+1, "strdup");
52         memcpy(n, str, len);
53         n[len]= '\0';
54         
55         return n;
56 }
57 char *BLI_strdup(const char *str) {
58         return BLI_strdupn(str, strlen(str));
59 }
60
61 char *BLI_strdupcat(const char *str1, const char *str2)
62 {
63         size_t len;
64         char *n;
65         
66         len= strlen(str1)+strlen(str2);
67         n= MEM_mallocN(len+1, "strdupcat");
68         strcpy(n, str1);
69         strcat(n, str2);
70         
71         return n;
72 }
73
74 char *BLI_strncpy(char *dst, const char *src, const size_t maxncpy) {
75         size_t srclen= strlen(src);
76         size_t cpylen= (srclen>(maxncpy-1))?(maxncpy-1):srclen;
77         
78         memcpy(dst, src, cpylen);
79         dst[cpylen]= '\0';
80         
81         return dst;
82 }
83
84 size_t BLI_snprintf(char *buffer, size_t count, const char *format, ...)
85 {
86         size_t n;
87         va_list arg;
88
89         va_start(arg, format);
90         n = vsnprintf(buffer, count, format, arg);
91         
92         if (n != -1 && n < count) {
93                 buffer[n] = '\0';
94         } else {
95                 buffer[count-1] = '\0';
96         }
97         
98         va_end(arg);
99         return n;
100 }
101
102 char *BLI_sprintfN(const char *format, ...)
103 {
104         DynStr *ds;
105         va_list arg;
106         char *n;
107
108         va_start(arg, format);
109
110         ds= BLI_dynstr_new();
111         BLI_dynstr_vappendf(ds, format, arg);
112         n= BLI_dynstr_get_cstring(ds);
113         BLI_dynstr_free(ds);
114
115         va_end(arg);
116
117         return n;
118 }
119
120 /* Makes a copy of the text within the "" that appear after some text 'blahblah'
121  * i.e. for string 'pose["apples"]' with prefix 'pose[', it should grab "apples"
122  * 
123  *      - str: is the entire string to chop
124  *      - prefix: is the part of the string to leave out 
125  *
126  * Assume that the strings returned must be freed afterwards, and that the inputs will contain 
127  * data we want...
128  */
129 char *BLI_getQuotedStr (const char *str, const char *prefix)
130 {
131         size_t prefixLen = strlen(prefix);
132         char *startMatch, *endMatch;
133         
134         /* get the starting point (i.e. where prefix starts, and add prefixLen+1 to it to get be after the first " */
135         startMatch= strstr(str, prefix) + prefixLen + 1;
136         
137         /* get the end point (i.e. where the next occurance of " is after the starting point) */
138         endMatch= strchr(startMatch, '"'); // "  NOTE: this comment here is just so that my text editor still shows the functions ok...
139         
140         /* return the slice indicated */
141         return BLI_strdupn(startMatch, (size_t)(endMatch-startMatch));
142 }
143
144 /* Replaces all occurances of oldText with newText in str, returning a new string that doesn't 
145  * contain the 'replaced' occurances.
146  */
147 // A rather wasteful string-replacement utility, though this shall do for now...
148 // Feel free to replace this with an even safe + nicer alternative 
149 char *BLI_replacestr(char *str, const char *oldText, const char *newText)
150 {
151         DynStr *ds= NULL;
152         size_t lenOld= strlen(oldText);
153         char *match;
154         
155         /* sanity checks */
156         if ((str == NULL) || (str[0]==0))
157                 return NULL;
158         else if ((oldText == NULL) || (newText == NULL) || (oldText[0]==0))
159                 return BLI_strdup(str);
160         
161         /* while we can still find a match for the old substring that we're searching for, 
162          * keep dicing and replacing
163          */
164         while ( (match = strstr(str, oldText)) ) {
165                 /* the assembly buffer only gets created when we actually need to rebuild the string */
166                 if (ds == NULL)
167                         ds= BLI_dynstr_new();
168                         
169                 /* if the match position does not match the current position in the string, 
170                  * copy the text up to this position and advance the current position in the string
171                  */
172                 if (str != match) {
173                         /* replace the token at the 'match' position with \0 so that the copied string will be ok,
174                          * add the segment of the string from str to match to the buffer, then restore the value at match
175                          */
176                         match[0]= 0;
177                         BLI_dynstr_append(ds, str);
178                         match[0]= oldText[0];
179                         
180                         /* now our current position should be set on the start of the match */
181                         str= match;
182                 }
183                 
184                 /* add the replacement text to the accumulation buffer */
185                 BLI_dynstr_append(ds, newText);
186                 
187                 /* advance the current position of the string up to the end of the replaced segment */
188                 str += lenOld;
189         }
190         
191         /* finish off and return a new string that has had all occurances of */
192         if (ds) {
193                 char *newStr;
194                 
195                 /* add what's left of the string to the assembly buffer 
196                  *      - we've been adjusting str to point at the end of the replaced segments
197                  */
198                 if (str != NULL)
199                         BLI_dynstr_append(ds, str);
200                 
201                 /* convert to new c-string (MEM_malloc'd), and free the buffer */
202                 newStr= BLI_dynstr_get_cstring(ds);
203                 BLI_dynstr_free(ds);
204                 
205                 return newStr;
206         }
207         else {
208                 /* just create a new copy of the entire string - we avoid going through the assembly buffer 
209                  * for what should be a bit more efficiency...
210                  */
211                 return BLI_strdup(str);
212         }
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, size_t len) {
262         int i;
263
264         for (i=0; i<len; 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
467 void BLI_ascii_strtolower(char *str, int len)
468 {
469         int i;
470
471         for(i=0; i<len; i++)
472                 if(str[i] >= 'A' && str[i] <= 'Z')
473                         str[i] += 'a' - 'A';
474 }
475
476 void BLI_ascii_strtoupper(char *str, int len)
477 {
478         int i;
479
480         for(i=0; i<len; i++)
481                 if(str[i] >= 'a' && str[i] <= 'z')
482                         str[i] -= 'a' - 'A';
483 }
484