8eeca6900a1ac827d83c10b024a29b72542519d6
[blender.git] / source / blender / blenlib / intern / util.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 <fcntl.h>
37 #include <ctype.h>
38 #include <string.h>
39 #include <stdlib.h>
40 #include <stdarg.h>
41 #include <math.h> /* for log10 */
42
43 #include "MEM_guardedalloc.h"
44
45 #include "DNA_listBase.h"
46 #include "DNA_userdef_types.h"
47
48 #include "BLI_blenlib.h"
49 #include "BLI_storage.h"
50 #include "BLI_storage_types.h"
51 #include "BLI_dynamiclist.h"
52
53 #include "BLI_util.h"
54 #include "BKE_utildefines.h"
55
56
57 #ifdef HAVE_CONFIG_H
58 #include <config.h>
59 #endif
60
61 #ifndef WIN32 
62 #include <unistd.h>
63 #else
64 #include <io.h>
65 #endif
66
67 #ifdef WIN32
68
69 #ifdef _WIN32_IE
70 #undef _WIN32_IE
71 #endif
72 #define _WIN32_IE 0x0501
73 #include <windows.h>
74 #include <shlobj.h>
75
76 #include "BLI_winstuff.h"
77
78 /* for duplicate_defgroup */
79 #if !(defined vsnprintf)
80 #define vsnprintf _vsnprintf
81 #endif
82
83 #endif
84
85
86 #ifndef WIN32
87 #include <sys/time.h>
88 #endif
89
90 #ifdef __APPLE__
91 #include <sys/param.h>
92 #include <CoreFoundation/CoreFoundation.h>
93 #endif
94
95 #ifdef __linux__
96 #include "binreloc.h"
97 #endif
98
99 /* local */
100
101 static int add_win32_extension(char *name);
102
103 /* implementation */
104
105 int BLI_stringdec(char *string, char *kop, char *start, unsigned short *numlen)
106 {
107         unsigned short len, len2, nums = 0, nume = 0;
108         short i, found = 0;
109
110         len2 = len = strlen(string);
111         
112         if (len > 6) {
113                 if (BLI_strncasecmp(string + len - 6, ".blend", 6) == 0) len -= 6;
114                 else if (BLI_strncasecmp(string + len - 6, ".trace", 6) == 0) len -= 6;
115         }
116         
117         if (len > 9) {
118                 if (BLI_strncasecmp(string + len - 9, ".blend.gz", 9) == 0) len -= 9;
119         }
120                 
121         if (len == len2) {
122                 if (len > 4) {
123                         /* handle .jf0 en .jf1 for jstreams */
124                         if (BLI_strncasecmp(string + len - 4, ".jf", 3) == 0) len -= 4;
125                         else if (BLI_strncasecmp(string + len - 4, ".tga", 4) == 0) len -= 4;
126                         else if (BLI_strncasecmp(string + len - 4, ".jpg", 4) == 0) len -= 4;
127                         else if (BLI_strncasecmp(string + len - 4, ".png", 4) == 0) len -= 4;
128                         else if (BLI_strncasecmp(string + len - 4, ".txt", 4) == 0) len -= 4;
129                         else if (BLI_strncasecmp(string + len - 4, ".cyc", 4) == 0) len -= 4;
130                         else if (BLI_strncasecmp(string + len - 4, ".enh", 4) == 0) len -= 4;
131                         else if (BLI_strncasecmp(string + len - 4, ".rgb", 4) == 0) len -= 4;
132                         else if (BLI_strncasecmp(string + len - 4, ".psx", 4) == 0) len -= 4;
133                         else if (BLI_strncasecmp(string + len - 4, ".ble", 4) == 0) len -= 4;
134                         else if (BLI_strncasecmp(string + len - 4, ".exr", 4) == 0) len -= 4;
135                 }
136         }
137         
138         for (i = len - 1; i >= 0; i--) {
139                 if (string[i] == '/') break;
140                 if (isdigit(string[i])) {
141                         if (found){
142                                 nums = i;
143                         }
144                         else{
145                                 nume = i;
146                                 nums = i;
147                                 found = 1;
148                         }
149                 }
150                 else {
151                         if (found) break;
152                 }
153         }
154         if (found){
155                 if (start) strcpy(start,&string[nume+1]);
156                 if (kop) {
157                         strcpy(kop,string);
158                         kop[nums]=0;
159                 }
160                 if (numlen) *numlen = nume-nums+1;
161                 return ((int)atoi(&(string[nums])));
162         }
163         if (start) strcpy(start, string + len);
164         if (kop) {
165                 strncpy(kop, string, len);
166                 kop[len] = 0;
167         }
168         if (numlen) *numlen=0;
169         return 0;
170 }
171
172
173 void BLI_stringenc(char *string, char *kop, char *start, unsigned short numlen, int pic)
174 {
175         char numstr[10]="";
176         unsigned short len,i;
177
178         strcpy(string,kop);
179         
180         if (pic>0 || numlen==4) {
181                 len= sprintf(numstr,"%d",pic);
182                 
183                 for(i=len;i<numlen;i++){
184                         strcat(string,"0");
185                 }
186                 strcat(string,numstr);
187         }
188         strcat(string, start);
189 }
190
191
192 void BLI_newname(char *name, int add)
193 {
194         char head[128], tail[128];
195         int pic;
196         unsigned short digits;
197         
198         pic = BLI_stringdec(name, head, tail, &digits);
199         
200         /* are we going from 100 -> 99 or from 10 -> 9 */
201         if (add < 0 && digits < 4 && digits > 0) {
202                 int i, exp;
203                 exp = 1;
204                 for (i = digits; i > 1; i--) exp *= 10;
205                 if (pic >= exp && (pic + add) < exp) digits--;
206         }
207         
208         pic += add;
209         
210         if (digits==4 && pic<0) pic= 0;
211         BLI_stringenc(name, head, tail, digits, pic);
212 }
213
214 /* little helper macro for BLI_uniquename */
215 #ifndef GIVE_STRADDR
216         #define GIVE_STRADDR(data, offset) ( ((char *)data) + offset )
217 #endif
218
219 /* Generic function to set a unique name. It is only designed to be used in situations
220  * where the name is part of the struct, and also that the name is at most 128 chars long.
221  * 
222  * For places where this is used, see constraint.c for example...
223  *
224  *      name_offs: should be calculated using offsetof(structname, membername) macro from stddef.h
225  *      len: maximum length of string (to prevent overflows, etc.)
226  *      defname: the name that should be used by default if none is specified already
227  *      delim: the character which acts as a delimeter between parts of the name
228  */
229 void BLI_uniquename(ListBase *list, void *vlink, char defname[], char delim, short name_offs, short len)
230 {
231         Link *link;
232         char tempname[128];
233         int     number = 1, exists = 0;
234         char *dot;
235         
236         /* Make sure length can be handled */
237         if ((len < 0) || (len > 128))
238                 return;
239         
240         /* See if we are given an empty string */
241         if (ELEM(NULL, vlink, defname))
242                 return;
243         
244         if (GIVE_STRADDR(vlink, name_offs) == '\0') {
245                 /* give it default name first */
246                 BLI_strncpy(GIVE_STRADDR(vlink, name_offs), defname, len);
247         }
248         
249         /* See if we even need to do this */
250         if (list == NULL)
251                 return;
252         
253         for (link = list->first; link; link= link->next) {
254                 if (link != vlink) {
255                         if (!strcmp(GIVE_STRADDR(link, name_offs), GIVE_STRADDR(vlink, name_offs))) {
256                                 exists = 1;
257                                 break;
258                         }
259                 }
260         }
261         if (exists == 0)
262                 return;
263
264         /* Strip off the suffix */
265         dot = strchr(GIVE_STRADDR(vlink, name_offs), delim);
266         if (dot)
267                 *dot=0;
268         
269         for (number = 1; number <= 999; number++) {
270                 BLI_snprintf(tempname, 128, "%s%c%03d", GIVE_STRADDR(vlink, name_offs), delim, number);
271                 
272                 exists = 0;
273                 for (link= list->first; link; link= link->next) {
274                         if (vlink != link) {
275                                 if (!strcmp(GIVE_STRADDR(link, name_offs), tempname)) {
276                                         exists = 1;
277                                         break;
278                                 }
279                         }
280                 }
281                 if (exists == 0) {
282                         BLI_strncpy(GIVE_STRADDR(vlink, name_offs), tempname, len);
283                         return;
284                 }
285         }
286 }
287
288 /* ******************** string encoding ***************** */
289
290 /* This is quite an ugly function... its purpose is to
291  * take the dir name, make it absolute, and clean it up, replacing
292  * excess file entry stuff (like /tmp/../tmp/../)
293  * note that dir isn't protected for max string names... 
294  * 
295  * If relbase is NULL then its ignored
296  */
297
298 void BLI_cleanup_dir(const char *relabase, char *dir)
299 {
300         BLI_cleanup_file(relabase, dir);
301         BLI_add_slash(dir);
302
303 }
304
305 void BLI_cleanup_file(const char *relabase, char *dir)
306 {
307         short a;
308         char *start, *eind;
309         if (relabase) {
310                 BLI_convertstringcode(dir, relabase);
311         } else {
312                 if (dir[0]=='/' && dir[1]=='/') {
313                         if (dir[2]== '\0') {
314                                 return; /* path is "//" - cant clean it */
315                         }
316                         dir = dir+2; /* skip the first // */
317                 }
318         }
319         
320         /* Note
321          *   memmove( start, eind, strlen(eind)+1 );
322          * is the same as
323          *   strcpy( start, eind ); 
324          * except strcpy should not be used because there is overlap,
325           * so use memmove's slightly more obscure syntax - Campbell
326          */
327         
328 #ifdef WIN32
329         
330         /* Note, this should really be moved to the file selector,
331          * since this function is used in many areas */
332         if(strcmp(dir, ".")==0) {       /* happens for example in FILE_MAIN */
333            get_default_root(dir);
334            return;
335         }       
336
337         while ( (start = strstr(dir, "\\..\\")) ) {
338                 eind = start + strlen("\\..\\") - 1;
339                 a = start-dir-1;
340                 while (a>0) {
341                         if (dir[a] == '\\') break;
342                         a--;
343                 }
344                 if (a<0) {
345                         break;
346                 } else {
347                         memmove( dir+a, eind, strlen(eind)+1 );
348                 }
349         }
350
351         while ( (start = strstr(dir,"\\.\\")) ){
352                 eind = start + strlen("\\.\\") - 1;
353                 memmove( start, eind, strlen(eind)+1 );
354         }
355
356         while ( (start = strstr(dir,"\\\\" )) ){
357                 eind = start + strlen("\\\\") - 1;
358                 memmove( start, eind, strlen(eind)+1 );
359         }
360
361         if((a = strlen(dir))){                          /* remove the '\\' at the end */
362                 while(a>0 && dir[a-1] == '\\'){
363                         a--;
364                         dir[a] = 0;
365                 }
366         }
367 #else
368         if(dir[0]=='.') {       /* happens, for example in FILE_MAIN */
369            dir[0]= '/';
370            dir[1]= 0;
371            return;
372         }       
373
374         while ( (start = strstr(dir, "/../")) ) {
375                 eind = start + strlen("/../") - 1;
376                 a = start-dir-1;
377                 while (a>0) {
378                         if (dir[a] == '/') break;
379                         a--;
380                 }
381                 if (a<0) {
382                         break;
383                 } else {
384                         memmove( dir+a, eind, strlen(eind)+1 );
385                 }
386         }
387
388         while ( (start = strstr(dir,"/./")) ){
389                 eind = start + strlen("/./") - 1;
390                 memmove( start, eind, strlen(eind)+1 );
391         }
392
393         while ( (start = strstr(dir,"//" )) ){
394                 eind = start + strlen("//") - 1;
395                 memmove( start, eind, strlen(eind)+1 );
396         }
397
398         if( (a = strlen(dir)) ){                                /* remove all '/' at the end */
399                 while(dir[a-1] == '/'){
400                         a--;
401                         dir[a] = 0;
402                         if (a<=0) break;
403                 }
404         }
405 #endif
406 }
407
408
409 void BLI_makestringcode(const char *relfile, char *file)
410 {
411         char * p;
412         char * q;
413         char * lslash;
414         char temp[FILE_MAXDIR+FILE_MAXFILE];
415         char res[FILE_MAXDIR+FILE_MAXFILE];
416         
417         /* if file is already relative, bail out */
418         if(file[0]=='/' && file[1]=='/') return;
419         
420         /* also bail out if relative path is not set */
421         if (relfile[0] == 0) return;
422
423 #ifdef WIN32 
424         if (strlen(relfile) > 2 && relfile[1] != ':') {
425                 char* ptemp;
426                 /* fix missing volume name in relative base,
427                    can happen with old .Blog files */
428                 get_default_root(temp);
429                 ptemp = &temp[2];
430                 if (relfile[0] != '\\' && relfile[0] != '/') {
431                         ptemp++;
432                 }
433                 BLI_strncpy(ptemp, relfile, FILE_MAXDIR + FILE_MAXFILE-3);
434         } else {
435                 BLI_strncpy(temp, relfile, FILE_MAXDIR + FILE_MAXFILE);
436         }
437
438         if (strlen(file) > 2) {
439                 if ( temp[1] == ':' && file[1] == ':' && temp[0] != file[0] )
440                         return;
441         }
442 #else
443         BLI_strncpy(temp, relfile, FILE_MAX);
444 #endif
445
446         BLI_char_switch(temp, '\\', '/');
447         BLI_char_switch(file, '\\', '/');
448         
449         /* remove /./ which confuse the following slash counting... */
450         BLI_cleanup_file(NULL, file);
451         BLI_cleanup_file(NULL, temp);
452         
453         /* the last slash in the file indicates where the path part ends */
454         lslash = BLI_last_slash(temp);
455
456         if (lslash) 
457         {       
458                 /* find the prefix of the filename that is equal for both filenames.
459                    This is replaced by the two slashes at the beginning */
460                 p = temp;
461                 q = file;
462                 while (*p == *q) {
463                         ++p; ++q;
464                 }
465                 /* we might have passed the slash when the beginning of a dir matches 
466                    so we rewind. Only check on the actual filename
467                 */
468                 if (*q != '/') {
469                         while ( (q >= file) && (*q != '/') ) { --q; --p; }
470                 } 
471                 else if (*p != '/') {
472                         while ( (p >= temp) && (*p != '/') ) { --p; --q; }
473                 }
474                 
475                 strcpy(res,     "//");
476
477                 /* p now points to the slash that is at the beginning of the part
478                    where the path is different from the relative path. 
479                    We count the number of directories we need to go up in the
480                    hierarchy to arrive at the common 'prefix' of the path
481                 */                      
482                 while (p && p < lslash) {
483                         if (*p == '/') 
484                                 strcat(res,     "../");
485                         ++p;
486                 }
487
488                 strcat(res, q+1); /* don't copy the slash at the beginning */
489                 
490 #ifdef  WIN32
491                 BLI_char_switch(res+2, '/', '\\');
492 #endif
493                 strcpy(file, res);
494         }
495 }
496
497 int BLI_has_parent(char *path)
498 {
499         int len;
500         int slashes = 0;
501         BLI_clean(path);
502         len = BLI_add_slash(path) - 1;
503
504         while (len>=0) {
505                 if ((path[len] == '\\') || (path[len] == '/'))
506                         slashes++;
507                 len--;
508         }
509         return slashes > 1;
510 }
511
512 int BLI_parent_dir(char *path)
513 {
514 #ifdef WIN32
515         static char *parent_dir="..\\";
516 #else
517         static char *parent_dir="../";
518 #endif
519         char tmp[FILE_MAXDIR+FILE_MAXFILE+4];
520         BLI_strncpy(tmp, path, sizeof(tmp));
521         BLI_add_slash(tmp);
522         strcat(tmp, parent_dir);
523         BLI_cleanup_dir(NULL, tmp);
524         
525         if (!BLI_testextensie(tmp, parent_dir)) {
526                 BLI_strncpy(path, tmp, sizeof(tmp));    
527                 return 1;
528         } else {
529                 return 0;
530         }
531 }
532
533 int BLI_convertstringframe(char *path, int frame)
534 {
535         int ch_sta, ch_end, i;
536         /* Insert current frame: file### -> file001 */
537         ch_sta = ch_end = 0;
538         for (i = 0; path[i] != '\0'; i++) {
539                 if (path[i] == '\\' || path[i] == '/') {
540                         ch_end = 0; /* this is a directory name, dont use any hashes we found */
541                 } else if (path[i] == '#') {
542                         ch_sta = i;
543                         ch_end = ch_sta+1;
544                         while (path[ch_end] == '#') {
545                                 ch_end++;
546                         }
547                         i = ch_end-1; /* keep searching */
548                         
549                         /* dont break, there may be a slash after this that invalidates the previous #'s */
550                 }
551         }
552         if (ch_end) { /* warning, ch_end is the last # +1 */
553                 /* Add the frame number? */
554                 short numlen, hashlen;
555                 char tmp[FILE_MAX];
556                 
557                 char format[16]; /* 6 is realistically the maxframe (300000), so 8 should be enough, but 16 to be safe. */
558                 if (((ch_end-1)-ch_sta) >= 16) {
559                         ch_end = ch_sta+15; /* disallow values longer then 'format' can hold */
560                 }
561                 
562                 strcpy(tmp, path);
563                 
564                 numlen = 1 + (int)log10((double)frame); /* this is the number of chars in the number */
565                 hashlen = ch_end - ch_sta;
566                 
567                 sprintf(format, "%d", frame);
568                 
569                 if (numlen==hashlen) { /* simple case */
570                         memcpy(tmp+ch_sta, format, numlen);
571                 } else if (numlen < hashlen) {
572                         memcpy(tmp+ch_sta + (hashlen-numlen), format, numlen); /*dont copy the string terminator */
573                         memset(tmp+ch_sta, '0', hashlen-numlen);
574                 } else {
575                         /* number is longer then number of #'s */
576                         if (tmp[ch_end] == '\0') { /* hashes are last, no need to move any string*/
577                                 /* bad juju - not testing string length here :/ */
578                                 memcpy(tmp+ch_sta, format, numlen+1); /* add 1 to get the string terminator \0 */
579                         } else {
580                                 /* we need to move the end characters, reuse i */
581                                 int j;
582                                 
583                                 i = strlen(tmp); /* +1 to copy the string terminator */
584                                 j = i + (numlen-hashlen); /* from/to */
585                                 
586                                 while (i >= ch_end) {
587                                         tmp[j] = tmp[i]; 
588                                         i--;
589                                         j--;
590                                 }
591                                 memcpy(tmp + ch_sta, format, numlen);
592                         }
593                 }       
594                 strcpy(path, tmp);
595                 return 1;
596         }
597         return 0;
598 }
599
600
601 int BLI_convertstringcode(char *path, const char *basepath)
602 {
603         int wasrelative = (strncmp(path, "//", 2)==0);
604         char tmp[FILE_MAX];
605         char base[FILE_MAX];
606 #ifdef WIN32
607         char vol[3] = {'\0', '\0', '\0'};
608
609         BLI_strncpy(vol, path, 3);
610         /* we are checking here if we have an absolute path that is not in the current
611            blend file as a lib main - we are basically checking for the case that a 
612            UNIX root '/' is passed.
613         */
614         if (!wasrelative && (vol[1] != ':' && (vol[0] == '\0' || vol[0] == '/' || vol[0] == '\\'))) {
615                 char *p = path;
616                 get_default_root(tmp);
617                 // get rid of the slashes at the beginning of the path
618                 while (*p == '\\' || *p == '/') {
619                         p++;
620                 }
621                 strcat(tmp, p);
622         }
623         else {
624                 BLI_strncpy(tmp, path, FILE_MAX);
625         }
626 #else
627         BLI_strncpy(tmp, path, FILE_MAX);
628         
629         /* Check for loading a windows path on a posix system
630          * in this case, there is no use in trying C:/ since it 
631          * will never exist on a unix os.
632          * 
633          * Add a / prefix and lowercase the driveletter, remove the :
634          * C:\foo.JPG -> /c/foo.JPG */
635         
636         if (isalpha(tmp[0]) && tmp[1] == ':' && (tmp[2]=='\\' || tmp[2]=='/') ) {
637                 tmp[1] = tolower(tmp[0]); /* replace ':' with driveletter */
638                 tmp[0] = '/'; 
639                 /* '\' the slash will be converted later */
640         }
641         
642 #endif
643
644         BLI_strncpy(base, basepath, FILE_MAX);
645         
646         BLI_cleanup_file(NULL, base);
647         
648         /* push slashes into unix mode - strings entering this part are
649            potentially messed up: having both back- and forward slashes.
650            Here we push into one conform direction, and at the end we
651            push them into the system specific dir. This ensures uniformity
652            of paths and solving some problems (and prevent potential future
653            ones) -jesterKing. */
654         BLI_char_switch(tmp, '\\', '/');
655         BLI_char_switch(base, '\\', '/');       
656
657         /* Paths starting with // will get the blend file as their base,
658          * this isnt standard in any os but is uesed in blender all over the place */
659         if (wasrelative) {
660                 char *lslash= BLI_last_slash(base);
661                 if (lslash) {
662                         int baselen= (int) (lslash-base) + 1;
663                         /* use path for for temp storage here, we copy back over it right away */
664                         BLI_strncpy(path, tmp+2, FILE_MAX);
665                         
666                         memcpy(tmp, base, baselen);
667                         strcpy(tmp+baselen, path);
668                         strcpy(path, tmp);
669                 } else {
670                         strcpy(path, tmp+2);
671                 }
672         } else {
673                 strcpy(path, tmp);
674         }
675         
676         if (path[0]!='\0') {
677                 if ( path[strlen(path)-1]=='/') {
678                         BLI_cleanup_dir(NULL, path);
679                 } else {
680                         BLI_cleanup_file(NULL, path);
681                 }
682         }
683         
684 #ifdef WIN32
685         /* skip first two chars, which in case of
686            absolute path will be drive:/blabla and
687            in case of relpath //blabla/. So relpath
688            // will be retained, rest will be nice and
689            shiny win32 backward slashes :) -jesterKing
690         */
691         BLI_char_switch(path+2, '/', '\\');
692 #endif
693         
694         return wasrelative;
695 }
696
697
698 /*
699  * Should only be done with command line paths.
700  * this is NOT somthing blenders internal paths support like the // prefix
701  */
702 int BLI_convertstringcwd(char *path)
703 {
704         int wasrelative = 1;
705         int filelen = strlen(path);
706         
707 #ifdef WIN32
708         if (filelen >= 3 && path[1] == ':' && (path[2] == '\\' || path[2] == '/'))
709                 wasrelative = 0;
710 #else
711         if (filelen >= 2 && path[0] == '/')
712                 wasrelative = 0;
713 #endif
714         
715         if (wasrelative==1) {
716                 char cwd[FILE_MAXDIR + FILE_MAXFILE];
717                 BLI_getwdN(cwd); /* incase the full path to the blend isnt used */
718                 
719                 if (cwd[0] == '\0') {
720                         printf( "Could not get the current working directory - $PWD for an unknown reason.");
721                 } else {
722                         /* uses the blend path relative to cwd important for loading relative linked files.
723                         *
724                         * cwd should contain c:\ etc on win32 so the relbase can be NULL
725                         * relbase being NULL also prevents // being misunderstood as relative to the current
726                         * blend file which isnt a feature we want to use in this case since were dealing
727                         * with a path from the command line, rather then from inside Blender */
728                         
729                         char origpath[FILE_MAXDIR + FILE_MAXFILE];
730                         BLI_strncpy(origpath, path, FILE_MAXDIR + FILE_MAXFILE);
731                         
732                         BLI_make_file_string(NULL, path, cwd, origpath); 
733                 }
734         }
735         
736         return wasrelative;
737 }
738
739
740 /* copy di to fi, filename only */
741 void BLI_splitdirstring(char *di, char *fi)
742 {
743         char *lslash= BLI_last_slash(di);
744
745         if (lslash) {
746                 BLI_strncpy(fi, lslash+1, FILE_MAXFILE);
747                 *(lslash+1)=0;
748         } else {
749                 BLI_strncpy(fi, di, FILE_MAXFILE);
750                 di[0]= 0;
751         }
752 }
753
754 void BLI_getlastdir(const char* dir, char *last, int maxlen)
755 {
756         const char *s = dir;
757         const char *lslash = NULL;
758         const char *prevslash = NULL;
759         while (*s) {
760                 if ((*s == '\\') || (*s == '/')) {
761                         prevslash = lslash;
762                         lslash = s;
763                 }
764                 s++;
765         }
766         if (prevslash) {
767                 BLI_strncpy(last, prevslash+1, maxlen);
768         } else {
769                 BLI_strncpy(last, dir, maxlen);
770         }
771 }
772
773 char *BLI_gethome(void) {
774         #if !defined(WIN32)
775                 return getenv("HOME");
776
777         #else /* Windows */
778                 char * ret;
779                 static char dir[512];
780                 static char appdatapath[MAXPATHLEN];
781                 HRESULT hResult;
782
783                 /* Check for %HOME% env var */
784
785                 ret = getenv("HOME");
786                 if(ret) {
787                         sprintf(dir, "%s\\.blender", ret);
788                         if (BLI_exists(dir)) return dir;
789                 }
790
791                 /* else, check install dir (path containing blender.exe) */
792
793                 BLI_getInstallationDir(dir);
794
795                 if (BLI_exists(dir))
796                 {
797                         strcat(dir,"\\.blender");
798                         if (BLI_exists(dir)) return(dir);
799                 }
800
801                                 
802                 /* add user profile support for WIN 2K / NT */
803                 hResult = SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT, appdatapath);
804                 
805                 if (hResult == S_OK)
806                 {
807                         if (BLI_exists(appdatapath)) { /* from fop, also below... */
808                                 sprintf(dir, "%s\\Blender Foundation\\Blender", appdatapath);
809                                 BLI_recurdir_fileops(dir);
810                                 if (BLI_exists(dir)) {
811                                         strcat(dir,"\\.blender");
812                                         if(BLI_exists(dir)) return(dir);
813                                 }
814                         }
815                         hResult = SHGetFolderPath(NULL, CSIDL_COMMON_APPDATA, NULL, SHGFP_TYPE_CURRENT, appdatapath);
816                         if (hResult == S_OK)
817                         {
818                                 if (BLI_exists(appdatapath)) 
819                                 { /* from fop, also below... */
820                                         sprintf(dir, "%s\\Blender Foundation\\Blender", appdatapath);
821                                         BLI_recurdir_fileops(dir);
822                                         if (BLI_exists(dir)) {
823                                                 strcat(dir,"\\.blender");
824                                                 if(BLI_exists(dir)) return(dir);
825                                         }
826                                 }
827                         }
828                 }
829 #if 0
830                 ret = getenv("USERPROFILE");
831                 if (ret) {
832                         if (BLI_exists(ret)) { /* from fop, also below...  */
833                                 sprintf(dir, "%s\\Application Data\\Blender Foundation\\Blender", ret);
834                                 BLI_recurdir_fileops(dir);
835                                 if (BLI_exists(dir)) {
836                                         strcat(dir,"\\.blender");
837                                         if(BLI_exists(dir)) return(dir);
838                                 }
839                         }
840                 }
841 #endif
842
843                 /* 
844                    Saving in the Windows dir is less than desirable. 
845                    Use as a last resort ONLY! (aphex)
846                 */
847                 
848                 ret = getenv("WINDOWS");                
849                 if (ret) {
850                         if(BLI_exists(ret)) return ret;
851                 }
852
853                 ret = getenv("WINDIR"); 
854                 if (ret) {
855                         if(BLI_exists(ret)) return ret;
856                 }
857                 
858                 return "C:\\Temp";      /* sheesh! bad, bad, bad! (aphex) */
859         #endif
860 }
861
862 /* this function returns the path to a blender folder, if it exists,
863  * trying in this order:
864  *
865  * path_to_executable/release/folder_name (in svn)
866  * ./release/folder_name (in svn)
867  * $HOME/.blender/folder_name
868  * path_to_executable/.blender/folder_name
869  *
870  * returns NULL if none is found. */
871
872 char *BLI_gethome_folder(char *folder_name)
873 {
874         extern char bprogname[]; /* argv[0] from creator.c */
875         static char homedir[FILE_MAXDIR] = "";
876         static char fulldir[FILE_MAXDIR] = "";
877         char tmpdir[FILE_MAXDIR];
878         char bprogdir[FILE_MAXDIR];
879         char *s;
880         int i;
881
882         /* use argv[0] (bprogname) to get the path to the executable */
883         s = BLI_last_slash(bprogname);
884
885         i = s - bprogname + 1;
886         BLI_strncpy(bprogdir, bprogname, i);
887
888         /* try path_to_executable/release/folder_name (in svn) */
889         if (folder_name) {
890                 BLI_snprintf(tmpdir, sizeof(tmpdir), "release/%s", folder_name);
891                 BLI_make_file_string("/", fulldir, bprogdir, tmpdir);
892                 if (BLI_exists(fulldir)) return fulldir;
893                 else fulldir[0] = '\0';
894         }
895
896         /* try ./release/folder_name (in svn) */
897         if(folder_name) {
898                 BLI_snprintf(fulldir, sizeof(fulldir), "./release/%s", folder_name);
899                 if (BLI_exists(fulldir)) return fulldir;
900                 else fulldir[0] = '\0';
901         }
902
903         /* BLI_gethome() can return NULL if env vars are not set */
904         s = BLI_gethome();
905
906         if(!s) { /* bail if no $HOME */
907                 printf("$HOME is NOT set\n");
908                 return NULL;
909         }
910
911         if(strstr(s, ".blender"))
912                 BLI_strncpy(homedir, s, FILE_MAXDIR);
913         else
914                 BLI_make_file_string("/", homedir, s, ".blender");
915
916         /* if $HOME/.blender/folder_name exists, return it */
917         if(BLI_exists(homedir)) {
918                 if (folder_name) {
919                         BLI_make_file_string("/", fulldir, homedir, folder_name);
920                         if(BLI_exists(fulldir))
921                                 return fulldir;
922                 }
923                 else
924                         return homedir;
925         }
926         else
927                 homedir[0] = '\0';
928
929         /* using tmpdir to preserve homedir (if) found above:
930          * the ideal is to have a home dir with folder_name dir inside
931          * it, but if that isn't available, it's possible to
932          * have a 'broken' home dir somewhere and a folder_name dir in the
933          * svn sources */
934         BLI_make_file_string("/", tmpdir, bprogdir, ".blender");
935
936         if(BLI_exists(tmpdir)) {
937                 if(folder_name) {
938                         BLI_make_file_string("/", fulldir, tmpdir, folder_name);
939                         if(BLI_exists(fulldir)) {
940                                 BLI_strncpy(homedir, tmpdir, FILE_MAXDIR);
941                                 return fulldir;
942                         }
943                         else {
944                                 homedir[0] = '\0';
945                                 fulldir[0] = '\0';
946                         }
947                 }
948                 else return homedir;
949         }
950
951         return NULL;
952 }
953
954
955 void BLI_clean(char *path)
956 {
957         if(path==0) return;
958 #ifdef WIN32
959         if(path && strlen(path)>2) {
960                 BLI_char_switch(path+2, '/', '\\');
961         }
962 #else
963         BLI_char_switch(path, '\\', '/');
964 #endif
965 }
966
967 void BLI_char_switch(char *string, char from, char to) 
968 {
969         if(string==0) return;
970         while (*string != 0) {
971                 if (*string == from) *string = to;
972                 string++;
973         }
974 }
975
976 void BLI_make_exist(char *dir) {
977         int a;
978
979         #ifdef WIN32
980                 BLI_char_switch(dir, '/', '\\');
981         #else
982                 BLI_char_switch(dir, '\\', '/');
983         #endif  
984         
985         a = strlen(dir);
986         
987 #ifdef WIN32    
988         while(BLI_exists(dir) == 0){
989                 a --;
990                 while(dir[a] != '\\'){
991                         a--;
992                         if (a <= 0) break;
993                 }
994                 if (a >= 0) dir[a+1] = 0;
995                 else {
996                         /* defaulting to drive (usually 'C:') of Windows installation */
997                         get_default_root(dir);
998                         break;
999                 }
1000         }
1001 #else
1002         while(BLI_exist(dir) == 0){
1003                 a --;
1004                 while(dir[a] != '/'){
1005                         a--;
1006                         if (a <= 0) break;
1007                 }
1008                 if (a >= 0) dir[a+1] = 0;
1009                 else {
1010                         strcpy(dir,"/");
1011                         break;
1012                 }
1013         }
1014 #endif
1015 }
1016
1017 void BLI_make_existing_file(char *name)
1018 {
1019         char di[FILE_MAXDIR], fi[FILE_MAXFILE];
1020         
1021         strcpy(di, name);
1022         BLI_splitdirstring(di, fi);
1023         
1024         /* test exist */
1025         if (BLI_exists(di) == 0) {
1026                 BLI_recurdir_fileops(di);
1027         }
1028 }
1029
1030
1031 void BLI_make_file_string(const char *relabase, char *string,  const char *dir, const char *file)
1032 {
1033         int sl;
1034
1035         if (!string || !dir || !file) return; /* We don't want any NULLs */
1036         
1037         string[0]= 0; /* ton */
1038
1039         /* we first push all slashes into unix mode, just to make sure we don't get
1040            any mess with slashes later on. -jesterKing */
1041         /* constant strings can be passed for those parameters - don't change them - elubie */
1042         /*
1043         BLI_char_switch(relabase, '\\', '/');
1044         BLI_char_switch(dir, '\\', '/');
1045         BLI_char_switch(file, '\\', '/');
1046         */
1047
1048         /* Resolve relative references */       
1049         if (relabase && dir[0] == '/' && dir[1] == '/') {
1050                 char *lslash;
1051                 
1052                 /* Get the file name, chop everything past the last slash (ie. the filename) */
1053                 strcpy(string, relabase);
1054                 
1055                 lslash= (strrchr(string, '/')>strrchr(string, '\\'))?strrchr(string, '/'):strrchr(string, '\\');
1056                 
1057                 if(lslash) *(lslash+1)= 0;
1058
1059                 dir+=2; /* Skip over the relative reference */
1060         }
1061 #ifdef WIN32
1062         else {
1063                 if (strlen(dir) >= 2 && dir[1] == ':' ) {
1064                         BLI_strncpy(string, dir, 3);
1065                         dir += 2;
1066                 }
1067                 else { /* no drive specified */
1068                         /* first option: get the drive from the relabase if it has one */
1069                         if (relabase && strlen(relabase) >= 2 && relabase[1] == ':' ) {
1070                                 BLI_strncpy(string, relabase, 3);       
1071                                 string[2] = '\\';
1072                                 string[3] = '\0';
1073                         }
1074                         else { /* we're out of luck here, guessing the first valid drive, usually c:\ */
1075                                 get_default_root(string);
1076                         }
1077                         
1078                         /* ignore leading slashes */
1079                         while (*dir == '/' || *dir == '\\') dir++;
1080                 }
1081         }
1082 #endif
1083
1084         strcat(string, dir);
1085
1086         /* Make sure string ends in one (and only one) slash */ 
1087         /* first trim all slashes from the end of the string */
1088         sl = strlen(string);
1089         while (sl>0 && ( string[sl-1] == '/' || string[sl-1] == '\\') ) {
1090                 string[sl-1] = '\0';
1091                 sl--;
1092         }
1093         /* since we've now removed all slashes, put back one slash at the end. */
1094         strcat(string, "/");
1095         
1096         while (*file && (*file == '/' || *file == '\\')) /* Trim slashes from the front of file */
1097                 file++;
1098                 
1099         strcat (string, file);
1100         
1101         /* Push all slashes to the system preferred direction */
1102         BLI_clean(string);
1103 }
1104
1105 int BLI_testextensie(const char *str, const char *ext)
1106 {
1107         short a, b;
1108         int retval;
1109
1110         a= strlen(str);
1111         b= strlen(ext);
1112
1113         if(a==0 || b==0 || b>=a) {
1114                 retval = 0;
1115         } else if (BLI_strcasecmp(ext, str + a - b)) {
1116                 retval = 0;     
1117         } else {
1118                 retval = 1;
1119         }
1120
1121         return (retval);
1122 }
1123
1124 /*
1125  * This is a simple version of BLI_split_dirfile that has the following advantages...
1126  * 
1127  * Converts "/foo/bar.txt" to "/foo/" and "bar.txt"
1128  * - wont change 'string'
1129  * - wont create any directories
1130  * - dosnt use CWD, or deal with relative paths.
1131  * - Only fill's in *dir and *file when they are non NULL
1132  * */
1133 void BLI_split_dirfile_basic(const char *string, char *dir, char *file)
1134 {
1135         int lslash=0, i = 0;
1136         for (i=0; string[i]!='\0'; i++) {
1137                 if (string[i]=='\\' || string[i]=='/')
1138                         lslash = i+1;
1139         }
1140         if (dir) {
1141                 if (lslash) {
1142                         BLI_strncpy( dir, string, lslash+1); /* +1 to include the slash and the last char */
1143                 } else {
1144                         dir[0] = '\0';
1145                 }
1146         }
1147         
1148         if (file) {
1149                 strcpy( file, string+lslash);
1150         }
1151 }
1152
1153
1154 /* Warning,
1155  * - May modify 'string' variable
1156  * - May create the directory if it dosnt exist
1157  * if this is not needed use BLI_split_dirfile_basic(...)
1158  */
1159 void BLI_split_dirfile(char *string, char *dir, char *file)
1160 {
1161         int a;
1162 #ifdef WIN32
1163         int sl;
1164         short is_relative = 0;
1165         char path[FILE_MAX];
1166 #endif
1167
1168         dir[0]= 0;
1169         file[0]= 0;
1170
1171 #ifdef WIN32
1172         BLI_strncpy(path, string, FILE_MAX);
1173         BLI_char_switch(path, '/', '\\'); /* make sure we have a valid path format */
1174         sl = strlen(path);
1175         if (sl) {
1176                 int len;
1177                 if (path[0] == '/' || path[0] == '\\') { 
1178                         BLI_strncpy(dir, path, FILE_MAXDIR);
1179                         if (sl > 1 && path[0] == '\\' && path[1] == '\\') is_relative = 1;
1180                 } else if (sl > 2 && path[1] == ':' && path[2] == '\\') {
1181                         BLI_strncpy(dir, path, FILE_MAXDIR);
1182                 } else {
1183                         BLI_getwdN(dir);
1184                         strcat(dir,"\\");
1185                         strcat(dir,path);
1186                         BLI_strncpy(path,dir,FILE_MAXDIR+FILE_MAXFILE);
1187                 }
1188                 
1189                 // BLI_exist doesn't recognize a slashed dirname as a dir
1190                 //  check if a trailing slash exists, and remove it. Do not do this
1191                 //  when we are already at root. -jesterKing
1192                 a = strlen(dir);
1193                 if(a>=4 && dir[a-1]=='\\') dir[a-1] = 0;
1194
1195                 if (is_relative) {
1196                         printf("WARNING: BLI_split_dirfile needs absolute dir\n");
1197                 }
1198                 else {
1199                         BLI_make_exist(dir);
1200                 }
1201
1202                 if (S_ISDIR(BLI_exist(dir))) {
1203
1204                         /* copy from end of string into file, to ensure filename itself isn't truncated 
1205                         if string is too long. (aphex) */
1206
1207                         len = FILE_MAXFILE - strlen(path);
1208
1209                         if (len < 0)
1210                                 BLI_strncpy(file,path + abs(len),FILE_MAXFILE);
1211                         else
1212                                 BLI_strncpy(file,path,FILE_MAXFILE);
1213                     
1214                         if (strrchr(path,'\\')) {
1215                                 BLI_strncpy(file,strrchr(path,'\\')+1,FILE_MAXFILE);
1216                         }
1217                         
1218                         if ( (a = strlen(dir)) ) {
1219                                 if (dir[a-1] != '\\') strcat(dir,"\\");
1220                         }
1221                 }
1222                 else {
1223                         a = strlen(dir) - 1;
1224                         while(a>0 && dir[a] != '\\') a--;
1225                         dir[a + 1] = 0;
1226                         BLI_strncpy(file, path + strlen(dir),FILE_MAXFILE);
1227                 }
1228
1229         }
1230         else {
1231                 /* defaulting to first valid drive hoping it's not empty CD and DVD drives */
1232                 get_default_root(dir);
1233                 file[0]=0;
1234         }
1235 #else
1236         if (strlen(string)) {
1237                 if (string[0] == '/') { 
1238                         strcpy(dir, string);
1239                 } else if (string[1] == ':' && string[2] == '\\') {
1240                         string+=2;
1241                         strcpy(dir, string);
1242                 } else {
1243                         BLI_getwdN(dir);
1244                         strcat(dir,"/");
1245                         strcat(dir,string);
1246                         strcpy((char *)string,dir);
1247                 }
1248
1249                 BLI_make_exist(dir);
1250                         
1251                 if (S_ISDIR(BLI_exist(dir))) {
1252                         strcpy(file,string + strlen(dir));
1253
1254                         if (strrchr(file,'/')) strcpy(file,strrchr(file,'/')+1);
1255                 
1256                         if ( (a = strlen(dir)) ) {
1257                                 if (dir[a-1] != '/') strcat(dir,"/");
1258                         }
1259                 }
1260                 else {
1261                         a = strlen(dir) - 1;
1262                         while(dir[a] != '/') a--;
1263                         dir[a + 1] = 0;
1264                         strcpy(file, string + strlen(dir));
1265                 }
1266         }
1267         else {
1268                 BLI_getwdN(dir);
1269                 strcat(dir, "/");
1270                 file[0] = 0;
1271         }
1272 #endif
1273 }
1274
1275 /* simple appending of filename to dir, does not check for valid path! */
1276 void BLI_join_dirfile(char *string, const char *dir, const char *file)
1277 {
1278         int sl_dir;
1279         
1280         if(string != dir) /* compare pointers */
1281                 BLI_strncpy(string, dir, FILE_MAX);
1282         
1283         sl_dir= BLI_add_slash(string);
1284         
1285         if (sl_dir <FILE_MAX) {
1286                 BLI_strncpy(string + sl_dir, file, FILE_MAX-sl_dir);
1287         }
1288 }
1289
1290 static int add_win32_extension(char *name)
1291 {
1292         int retval = 0;
1293         int type;
1294
1295         type = BLI_exist(name);
1296         if ((type == 0) || S_ISDIR(type)) {
1297 #ifdef _WIN32
1298                 char filename[FILE_MAXDIR+FILE_MAXFILE];
1299                 char ext[FILE_MAXDIR+FILE_MAXFILE];
1300                 char *extensions = getenv("PATHEXT");
1301                 if (extensions) {
1302                         char *temp;
1303                         do {
1304                                 strcpy(filename, name);
1305                                 temp = strstr(extensions, ";");
1306                                 if (temp) {
1307                                         strncpy(ext, extensions, temp - extensions);
1308                                         ext[temp - extensions] = 0;
1309                                         extensions = temp + 1;
1310                                         strcat(filename, ext);
1311                                 } else {
1312                                         strcat(filename, extensions);
1313                                 }
1314
1315                                 type = BLI_exist(filename);
1316                                 if (type && (! S_ISDIR(type))) {
1317                                         retval = 1;
1318                                         strcpy(name, filename);
1319                                         break;
1320                                 }
1321                         } while (temp);
1322                 }
1323 #endif
1324         } else {
1325                 retval = 1;
1326         }
1327
1328         return (retval);
1329 }
1330
1331 void BLI_where_am_i(char *fullname, const char *name)
1332 {
1333         char filename[FILE_MAXDIR+FILE_MAXFILE];
1334         char *path = NULL, *temp;
1335         
1336 #ifdef _WIN32
1337         char *seperator = ";";
1338         char slash = '\\';
1339 #else
1340         char *seperator = ":";
1341         char slash = '/';
1342 #endif
1343
1344         
1345 #ifdef __linux__
1346         /* linux uses binreloc since argv[0] is not relyable, call br_init( NULL ) first */
1347         path = br_find_exe( NULL );
1348         if (path) {
1349                 strcpy(fullname, path);
1350                 free(path);
1351                 return;
1352         }
1353 #endif
1354         
1355         /* unix and non linux */
1356         if (name && fullname && strlen(name)) {
1357                 strcpy(fullname, name);
1358                 if (name[0] == '.') {
1359                         // relative path, prepend cwd
1360                         BLI_getwdN(fullname);
1361                         
1362                         // not needed but avoids annoying /./ in name
1363                         if(name && name[0]=='.' && name[1]==slash)
1364                                 BLI_join_dirfile(fullname, fullname, name+2);
1365                         else
1366                                 BLI_join_dirfile(fullname, fullname, name);
1367                         
1368                         add_win32_extension(fullname);
1369                 } else if (BLI_last_slash(name)) {
1370                         // full path
1371                         strcpy(fullname, name);
1372                         add_win32_extension(fullname);
1373                 } else {
1374                         // search for binary in $PATH
1375                         path = getenv("PATH");
1376                         if (path) {
1377                                 do {
1378                                         temp = strstr(path, seperator);
1379                                         if (temp) {
1380                                                 strncpy(filename, path, temp - path);
1381                                                 filename[temp - path] = 0;
1382                                                 path = temp + 1;
1383                                         } else {
1384                                                 strncpy(filename, path, sizeof(filename));
1385                                         }
1386                                         BLI_join_dirfile(fullname, fullname, name);
1387                                         if (add_win32_extension(filename)) {
1388                                                 strcpy(fullname, filename);
1389                                                 break;
1390                                         }
1391                                 } while (temp);
1392                         }
1393                 }
1394 #ifndef NDEBUG
1395                 if (strcmp(name, fullname)) {
1396                         printf("guessing '%s' == '%s'\n", name, fullname);
1397                 }
1398 #endif
1399
1400 #ifdef _WIN32
1401                 // in windows change long filename to short filename because
1402                 // win2k doesn't know how to parse a commandline with lots of
1403                 // spaces and double-quotes. There's another solution to this
1404                 // with spawnv(P_WAIT, bprogname, argv) instead of system() but
1405                 // that's even uglier
1406                 GetShortPathName(fullname, fullname, FILE_MAXDIR+FILE_MAXFILE);
1407 #ifndef NDEBUG
1408                 printf("Shortname = '%s'\n", fullname);
1409 #endif
1410 #endif
1411         }
1412 }
1413
1414 void BLI_where_is_temp(char *fullname, int usertemp)
1415 {
1416         fullname[0] = '\0';
1417         
1418         if (usertemp && BLI_exists(U.tempdir)) {
1419                 strcpy(fullname, U.tempdir);
1420         }
1421         
1422         
1423 #ifdef WIN32
1424         if (fullname[0] == '\0') {
1425                 char *tmp = getenv("TEMP"); /* Windows */
1426                 if (tmp && BLI_exists(tmp)) {
1427                         strcpy(fullname, tmp);
1428                 }
1429         }
1430 #else
1431         /* Other OS's - Try TMP and TMPDIR */
1432         if (fullname[0] == '\0') {
1433                 char *tmp = getenv("TMP");
1434                 if (tmp && BLI_exists(tmp)) {
1435                         strcpy(fullname, tmp);
1436                 }
1437         }
1438         
1439         if (fullname[0] == '\0') {
1440                 char *tmp = getenv("TMPDIR");
1441                 if (tmp && BLI_exists(tmp)) {
1442                         strcpy(fullname, tmp);
1443                 }
1444         }
1445 #endif  
1446         
1447         if (fullname[0] == '\0') {
1448                 strcpy(fullname, "/tmp/");
1449         } else {
1450                 /* add a trailing slash if needed */
1451                 BLI_add_slash(fullname);
1452         }
1453 }
1454
1455 char *get_install_dir(void) {
1456         extern char bprogname[];
1457         char *tmpname = BLI_strdup(bprogname);
1458         char *cut;
1459
1460 #ifdef __APPLE__
1461         cut = strstr(tmpname, ".app");
1462         if (cut) cut[0] = 0;
1463 #endif
1464
1465         cut = BLI_last_slash(tmpname);
1466
1467         if (cut) {
1468                 cut[0] = 0;
1469                 return tmpname;
1470         } else {
1471                 MEM_freeN(tmpname);
1472                 return NULL;
1473         }
1474 }
1475
1476 /* 
1477  * returns absolute path to the app bundle
1478  * only useful on OS X 
1479  */
1480 #ifdef __APPLE__
1481 char* BLI_getbundle(void) {
1482         CFURLRef bundleURL;
1483         CFStringRef pathStr;
1484         static char path[MAXPATHLEN];
1485         CFBundleRef mainBundle = CFBundleGetMainBundle();
1486
1487         bundleURL = CFBundleCopyBundleURL(mainBundle);
1488         pathStr = CFURLCopyFileSystemPath(bundleURL, kCFURLPOSIXPathStyle);
1489         CFStringGetCString(pathStr, path, MAXPATHLEN, kCFStringEncodingASCII);
1490         return path;
1491 }
1492 #endif
1493
1494 #ifdef WITH_ICONV
1495 #include "iconv.h"
1496 #include "localcharset.h"
1497
1498 void BLI_string_to_utf8(char *original, char *utf_8, const char *code)
1499 {
1500         size_t inbytesleft=strlen(original);
1501         size_t outbytesleft=512;
1502         size_t rv=0;
1503         iconv_t cd;
1504         
1505         if (NULL == code) {
1506                 code = locale_charset();
1507         }
1508         cd=iconv_open("UTF-8", code);
1509
1510         if (cd == (iconv_t)(-1)) {
1511                 printf("iconv_open Error");
1512                 *utf_8='\0';
1513                 return ;
1514         }
1515         rv=iconv(cd, &original, &inbytesleft, &utf_8, &outbytesleft);
1516         if (rv == (size_t) -1) {
1517                 printf("iconv Error\n");
1518                 return ;
1519         }
1520         *utf_8 = '\0';
1521         iconv_close(cd);
1522 }
1523 #endif // WITH_ICONV
1524
1525