svn merge -r 37306:39975 https://svn.blender.org/svnroot/bf-blender/trunk/blender
[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
121 /* match pythons string escaping, assume double quotes - (")
122  * TODO: should be used to create RNA animation paths.
123  * TODO: support more fancy string escaping. current code is primitive
124  *    this basically is an ascii version of PyUnicode_EncodeUnicodeEscape()
125  *    which is a useful reference. */
126 size_t BLI_strescape(char *dst, const char *src, const size_t maxlen)
127 {
128         size_t len= 0;
129         while(len < maxlen) {
130                 switch(*src) {
131                         case '\0':
132                                 goto escape_finish;
133                         case '\\':
134                         case '"':
135
136                                 /* less common but should also be support */
137                         case '\t':
138                         case '\n':
139                         case '\r':
140                                 if(len + 1 <  maxlen) {
141                                         *dst++ = '\\';
142                                         len++;
143                                 }
144                                 else {
145                                         /* not enough space to escape */
146                                         break;
147                                 }
148                                 /* intentionally pass through */
149                         default:
150                                 *dst = *src;
151                 }
152                 dst++;
153                 src++;
154                 len++;
155         }
156
157 escape_finish:
158
159         *dst= '\0';
160
161         return len;
162 }
163
164
165 /* Makes a copy of the text within the "" that appear after some text 'blahblah'
166  * i.e. for string 'pose["apples"]' with prefix 'pose[', it should grab "apples"
167  * 
168  *      - str: is the entire string to chop
169  *      - prefix: is the part of the string to leave out 
170  *
171  * Assume that the strings returned must be freed afterwards, and that the inputs will contain 
172  * data we want...
173  */
174 char *BLI_getQuotedStr (const char *str, const char *prefix)
175 {
176         size_t prefixLen = strlen(prefix);
177         char *startMatch, *endMatch;
178         
179         /* get the starting point (i.e. where prefix starts, and add prefixLen+1 to it to get be after the first " */
180         startMatch= strstr(str, prefix) + prefixLen + 1;
181         
182         /* get the end point (i.e. where the next occurance of " is after the starting point) */
183         endMatch= strchr(startMatch, '"'); // "  NOTE: this comment here is just so that my text editor still shows the functions ok...
184         
185         /* return the slice indicated */
186         return BLI_strdupn(startMatch, (size_t)(endMatch-startMatch));
187 }
188
189 /* Replaces all occurances of oldText with newText in str, returning a new string that doesn't 
190  * contain the 'replaced' occurances.
191  */
192 // A rather wasteful string-replacement utility, though this shall do for now...
193 // Feel free to replace this with an even safe + nicer alternative 
194 char *BLI_replacestr(char *str, const char *oldText, const char *newText)
195 {
196         DynStr *ds= NULL;
197         size_t lenOld= strlen(oldText);
198         char *match;
199         
200         /* sanity checks */
201         if ((str == NULL) || (str[0]==0))
202                 return NULL;
203         else if ((oldText == NULL) || (newText == NULL) || (oldText[0]==0))
204                 return BLI_strdup(str);
205         
206         /* while we can still find a match for the old substring that we're searching for, 
207          * keep dicing and replacing
208          */
209         while ( (match = strstr(str, oldText)) ) {
210                 /* the assembly buffer only gets created when we actually need to rebuild the string */
211                 if (ds == NULL)
212                         ds= BLI_dynstr_new();
213                         
214                 /* if the match position does not match the current position in the string, 
215                  * copy the text up to this position and advance the current position in the string
216                  */
217                 if (str != match) {
218                         /* replace the token at the 'match' position with \0 so that the copied string will be ok,
219                          * add the segment of the string from str to match to the buffer, then restore the value at match
220                          */
221                         match[0]= 0;
222                         BLI_dynstr_append(ds, str);
223                         match[0]= oldText[0];
224                         
225                         /* now our current position should be set on the start of the match */
226                         str= match;
227                 }
228                 
229                 /* add the replacement text to the accumulation buffer */
230                 BLI_dynstr_append(ds, newText);
231                 
232                 /* advance the current position of the string up to the end of the replaced segment */
233                 str += lenOld;
234         }
235         
236         /* finish off and return a new string that has had all occurances of */
237         if (ds) {
238                 char *newStr;
239                 
240                 /* add what's left of the string to the assembly buffer 
241                  *      - we've been adjusting str to point at the end of the replaced segments
242                  */
243                 if (str != NULL)
244                         BLI_dynstr_append(ds, str);
245                 
246                 /* convert to new c-string (MEM_malloc'd), and free the buffer */
247                 newStr= BLI_dynstr_get_cstring(ds);
248                 BLI_dynstr_free(ds);
249                 
250                 return newStr;
251         }
252         else {
253                 /* just create a new copy of the entire string - we avoid going through the assembly buffer 
254                  * for what should be a bit more efficiency...
255                  */
256                 return BLI_strdup(str);
257         }
258
259
260 int BLI_strcaseeq(const char *a, const char *b) 
261 {
262         return (BLI_strcasecmp(a, b)==0);
263 }
264
265 /* strcasestr not available in MSVC */
266 char *BLI_strcasestr(const char *s, const char *find)
267 {
268         register char c, sc;
269         register size_t len;
270         
271         if ((c = *find++) != 0) {
272                 c= tolower(c);
273                 len = strlen(find);
274                 do {
275                         do {
276                                 if ((sc = *s++) == 0)
277                                         return (NULL);
278                                 sc= tolower(sc);
279                         } while (sc != c);
280                 } while (BLI_strncasecmp(s, find, len) != 0);
281                 s--;
282         }
283         return ((char *) s);
284 }
285
286
287 int BLI_strcasecmp(const char *s1, const char *s2) {
288         int i;
289
290         for (i=0; ; i++) {
291                 char c1 = tolower(s1[i]);
292                 char c2 = tolower(s2[i]);
293
294                 if (c1<c2) {
295                         return -1;
296                 } else if (c1>c2) {
297                         return 1;
298                 } else if (c1==0) {
299                         break;
300                 }
301         }
302
303         return 0;
304 }
305
306 int BLI_strncasecmp(const char *s1, const char *s2, size_t len) {
307         int i;
308
309         for (i=0; i<len; i++) {
310                 char c1 = tolower(s1[i]);
311                 char c2 = tolower(s2[i]);
312
313                 if (c1<c2) {
314                         return -1;
315                 } else if (c1>c2) {
316                         return 1;
317                 } else if (c1==0) {
318                         break;
319                 }
320         }
321
322         return 0;
323 }
324
325 /* natural string compare, keeping numbers in order */
326 int BLI_natstrcmp(const char *s1, const char *s2)
327 {
328         int d1= 0, d2= 0;
329         
330         /* if both chars are numeric, to a strtol().
331            then increase string deltas as long they are 
332            numeric, else do a tolower and char compare */
333         
334         while(1) {
335                 char c1 = tolower(s1[d1]);
336                 char c2 = tolower(s2[d2]);
337                 
338                 if( isdigit(c1) && isdigit(c2) ) {
339                         int val1, val2;
340                         
341                         val1= (int)strtol(s1+d1, (char **)NULL, 10);
342                         val2= (int)strtol(s2+d2, (char **)NULL, 10);
343                         
344                         if (val1<val2) {
345                                 return -1;
346                         } else if (val1>val2) {
347                                 return 1;
348                         }
349                         d1++;
350                         while( isdigit(s1[d1]) )
351                                 d1++;
352                         d2++;
353                         while( isdigit(s2[d2]) )
354                                 d2++;
355                         
356                         c1 = tolower(s1[d1]);
357                         c2 = tolower(s2[d2]);
358                 }
359         
360                 /* first check for '.' so "foo.bar" comes before "foo 1.bar" */ 
361                 if(c1=='.' && c2!='.')
362                         return -1;
363                 if(c1!='.' && c2=='.')
364                         return 1;
365                 else if (c1<c2) {
366                         return -1;
367                 } else if (c1>c2) {
368                         return 1;
369                 } else if (c1==0) {
370                         break;
371                 }
372                 d1++;
373                 d2++;
374         }
375         return 0;
376 }
377
378 void BLI_timestr(double _time, char *str)
379 {
380         /* format 00:00:00.00 (hr:min:sec) string has to be 12 long */
381         int  hr= ( (int)  _time) / (60*60);
382         int min= (((int)  _time) / 60 ) % 60;
383         int sec= ( (int) (_time)) % 60;
384         int hun= ( (int) (_time   * 100.0)) % 100;
385         
386         if (hr) {
387                 sprintf(str, "%.2d:%.2d:%.2d.%.2d",hr,min,sec,hun);
388         } else {
389                 sprintf(str, "%.2d:%.2d.%.2d",min,sec,hun);
390         }
391         
392         str[11]=0;
393 }
394
395 /* determine the length of a fixed-size string */
396 size_t BLI_strnlen(const char *str, size_t maxlen)
397 {
398         const char *end = memchr(str, '\0', maxlen);
399         return end ? (size_t) (end - str) : maxlen;
400 }
401
402 /* from libswish3, originally called u8_isvalid(),
403  * modified to return the index of the bad character (byte index not utf).
404  * http://svn.swish-e.org/libswish3/trunk/src/libswish3/utf8.c r3044 - campbell */
405
406 /* based on the valid_utf8 routine from the PCRE library by Philip Hazel
407
408    length is in bytes, since without knowing whether the string is valid
409    it's hard to know how many characters there are! */
410
411 static const char trailingBytesForUTF8[256] = {
412         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,
413         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,
414         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,
415         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,
416         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,
417         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,
418         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,
419         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
420 };
421
422 int BLI_utf8_invalid_byte(const char *str, int length)
423 {
424         const unsigned char *p, *pend = (unsigned char*)str + length;
425         unsigned char c;
426         int ab;
427
428         for (p = (unsigned char*)str; p < pend; p++) {
429                 c = *p;
430                 if (c < 128)
431                         continue;
432                 if ((c & 0xc0) != 0xc0)
433                         goto utf8_error;
434                 ab = trailingBytesForUTF8[c];
435                 if (length < ab)
436                         goto utf8_error;
437                 length -= ab;
438
439                 p++;
440                 /* Check top bits in the second byte */
441                 if ((*p & 0xc0) != 0x80)
442                         goto utf8_error;
443
444                 /* Check for overlong sequences for each different length */
445                 switch (ab) {
446                         /* Check for xx00 000x */
447                 case 1:
448                         if ((c & 0x3e) == 0) goto utf8_error;
449                         continue;   /* We know there aren't any more bytes to check */
450
451                         /* Check for 1110 0000, xx0x xxxx */
452                 case 2:
453                         if (c == 0xe0 && (*p & 0x20) == 0) goto utf8_error;
454                         break;
455
456                         /* Check for 1111 0000, xx00 xxxx */
457                 case 3:
458                         if (c == 0xf0 && (*p & 0x30) == 0) goto utf8_error;
459                         break;
460
461                         /* Check for 1111 1000, xx00 0xxx */
462                 case 4:
463                         if (c == 0xf8 && (*p & 0x38) == 0) goto utf8_error;
464                         break;
465
466                         /* Check for leading 0xfe or 0xff,
467                            and then for 1111 1100, xx00 00xx */
468                 case 5:
469                         if (c == 0xfe || c == 0xff ||
470                                 (c == 0xfc && (*p & 0x3c) == 0)) goto utf8_error;
471                         break;
472                 }
473
474                 /* Check for valid bytes after the 2nd, if any; all must start 10 */
475                 while (--ab > 0) {
476                         if ((*(p+1) & 0xc0) != 0x80) goto utf8_error;
477                         p++; /* do this after so we get usable offset - campbell */
478                 }
479         }
480
481         return -1;
482
483 utf8_error:
484
485         return (int)((char *)p - (char *)str) - 1;
486 }
487
488 int BLI_utf8_invalid_strip(char *str, int length)
489 {
490         int bad_char, tot= 0;
491
492         while((bad_char= BLI_utf8_invalid_byte(str, length)) != -1) {
493                 str += bad_char;
494                 length -= bad_char;
495
496                 if(length == 0) {
497                         /* last character bad, strip it */
498                         *str= '\0';
499                         tot++;
500                         break;
501                 }
502                 else {
503                         /* strip, keep looking */
504                         memmove(str, str + 1, length);
505                         tot++;
506                 }
507         }
508
509         return tot;
510 }
511
512 void BLI_ascii_strtolower(char *str, int len)
513 {
514         int i;
515
516         for(i=0; i<len; i++)
517                 if(str[i] >= 'A' && str[i] <= 'Z')
518                         str[i] += 'a' - 'A';
519 }
520
521 void BLI_ascii_strtoupper(char *str, int len)
522 {
523         int i;
524
525         for(i=0; i<len; i++)
526                 if(str[i] >= 'a' && str[i] <= 'z')
527                         str[i] -= 'a' - 'A';
528 }
529