Merge with 2.5 -r 21619:21756.
[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 void BLI_setenv(const char *env, const char*val)
955 {
956         /* SGI or free windows */
957 #if (defined(__sgi) || ((defined(WIN32) || defined(WIN64)) && defined(FREE_WINDOWS)))
958         char *envstr= malloc(sizeof(char) * (strlen(env) + strlen(val) + 2)); /* one for = another for \0 */
959
960         sprintf(envstr, "%s=%s", env, val);
961         putenv(envstr);
962         free(envstr);
963
964         /* non-free windows */
965 #elif (defined(WIN32) || defined(WIN64)) /* not free windows */
966         _putenv_s(env, val);
967 #else
968         /* linux/osx/bsd */
969         setenv(env, val, 1);
970 #endif
971 }
972
973 void BLI_clean(char *path)
974 {
975         if(path==0) return;
976 #ifdef WIN32
977         if(path && strlen(path)>2) {
978                 BLI_char_switch(path+2, '/', '\\');
979         }
980 #else
981         BLI_char_switch(path, '\\', '/');
982 #endif
983 }
984
985 void BLI_char_switch(char *string, char from, char to) 
986 {
987         if(string==0) return;
988         while (*string != 0) {
989                 if (*string == from) *string = to;
990                 string++;
991         }
992 }
993
994 void BLI_make_exist(char *dir) {
995         int a;
996
997         #ifdef WIN32
998                 BLI_char_switch(dir, '/', '\\');
999         #else
1000                 BLI_char_switch(dir, '\\', '/');
1001         #endif  
1002         
1003         a = strlen(dir);
1004         
1005 #ifdef WIN32    
1006         while(BLI_exists(dir) == 0){
1007                 a --;
1008                 while(dir[a] != '\\'){
1009                         a--;
1010                         if (a <= 0) break;
1011                 }
1012                 if (a >= 0) dir[a+1] = 0;
1013                 else {
1014                         /* defaulting to drive (usually 'C:') of Windows installation */
1015                         get_default_root(dir);
1016                         break;
1017                 }
1018         }
1019 #else
1020         while(BLI_exist(dir) == 0){
1021                 a --;
1022                 while(dir[a] != '/'){
1023                         a--;
1024                         if (a <= 0) break;
1025                 }
1026                 if (a >= 0) dir[a+1] = 0;
1027                 else {
1028                         strcpy(dir,"/");
1029                         break;
1030                 }
1031         }
1032 #endif
1033 }
1034
1035 void BLI_make_existing_file(char *name)
1036 {
1037         char di[FILE_MAXDIR], fi[FILE_MAXFILE];
1038         
1039         strcpy(di, name);
1040         BLI_splitdirstring(di, fi);
1041         
1042         /* test exist */
1043         if (BLI_exists(di) == 0) {
1044                 BLI_recurdir_fileops(di);
1045         }
1046 }
1047
1048
1049 void BLI_make_file_string(const char *relabase, char *string,  const char *dir, const char *file)
1050 {
1051         int sl;
1052
1053         if (!string || !dir || !file) return; /* We don't want any NULLs */
1054         
1055         string[0]= 0; /* ton */
1056
1057         /* we first push all slashes into unix mode, just to make sure we don't get
1058            any mess with slashes later on. -jesterKing */
1059         /* constant strings can be passed for those parameters - don't change them - elubie */
1060         /*
1061         BLI_char_switch(relabase, '\\', '/');
1062         BLI_char_switch(dir, '\\', '/');
1063         BLI_char_switch(file, '\\', '/');
1064         */
1065
1066         /* Resolve relative references */       
1067         if (relabase && dir[0] == '/' && dir[1] == '/') {
1068                 char *lslash;
1069                 
1070                 /* Get the file name, chop everything past the last slash (ie. the filename) */
1071                 strcpy(string, relabase);
1072                 
1073                 lslash= (strrchr(string, '/')>strrchr(string, '\\'))?strrchr(string, '/'):strrchr(string, '\\');
1074                 
1075                 if(lslash) *(lslash+1)= 0;
1076
1077                 dir+=2; /* Skip over the relative reference */
1078         }
1079 #ifdef WIN32
1080         else {
1081                 if (strlen(dir) >= 2 && dir[1] == ':' ) {
1082                         BLI_strncpy(string, dir, 3);
1083                         dir += 2;
1084                 }
1085                 else { /* no drive specified */
1086                         /* first option: get the drive from the relabase if it has one */
1087                         if (relabase && strlen(relabase) >= 2 && relabase[1] == ':' ) {
1088                                 BLI_strncpy(string, relabase, 3);       
1089                                 string[2] = '\\';
1090                                 string[3] = '\0';
1091                         }
1092                         else { /* we're out of luck here, guessing the first valid drive, usually c:\ */
1093                                 get_default_root(string);
1094                         }
1095                         
1096                         /* ignore leading slashes */
1097                         while (*dir == '/' || *dir == '\\') dir++;
1098                 }
1099         }
1100 #endif
1101
1102         strcat(string, dir);
1103
1104         /* Make sure string ends in one (and only one) slash */ 
1105         /* first trim all slashes from the end of the string */
1106         sl = strlen(string);
1107         while (sl>0 && ( string[sl-1] == '/' || string[sl-1] == '\\') ) {
1108                 string[sl-1] = '\0';
1109                 sl--;
1110         }
1111         /* since we've now removed all slashes, put back one slash at the end. */
1112         strcat(string, "/");
1113         
1114         while (*file && (*file == '/' || *file == '\\')) /* Trim slashes from the front of file */
1115                 file++;
1116                 
1117         strcat (string, file);
1118         
1119         /* Push all slashes to the system preferred direction */
1120         BLI_clean(string);
1121 }
1122
1123 int BLI_testextensie(const char *str, const char *ext)
1124 {
1125         short a, b;
1126         int retval;
1127
1128         a= strlen(str);
1129         b= strlen(ext);
1130
1131         if(a==0 || b==0 || b>=a) {
1132                 retval = 0;
1133         } else if (BLI_strcasecmp(ext, str + a - b)) {
1134                 retval = 0;     
1135         } else {
1136                 retval = 1;
1137         }
1138
1139         return (retval);
1140 }
1141
1142 /*
1143  * This is a simple version of BLI_split_dirfile that has the following advantages...
1144  * 
1145  * Converts "/foo/bar.txt" to "/foo/" and "bar.txt"
1146  * - wont change 'string'
1147  * - wont create any directories
1148  * - dosnt use CWD, or deal with relative paths.
1149  * - Only fill's in *dir and *file when they are non NULL
1150  * */
1151 void BLI_split_dirfile_basic(const char *string, char *dir, char *file)
1152 {
1153         int lslash=0, i = 0;
1154         for (i=0; string[i]!='\0'; i++) {
1155                 if (string[i]=='\\' || string[i]=='/')
1156                         lslash = i+1;
1157         }
1158         if (dir) {
1159                 if (lslash) {
1160                         BLI_strncpy( dir, string, lslash+1); /* +1 to include the slash and the last char */
1161                 } else {
1162                         dir[0] = '\0';
1163                 }
1164         }
1165         
1166         if (file) {
1167                 strcpy( file, string+lslash);
1168         }
1169 }
1170
1171
1172 /* Warning,
1173  * - May modify 'string' variable
1174  * - May create the directory if it dosnt exist
1175  * if this is not needed use BLI_split_dirfile_basic(...)
1176  */
1177 void BLI_split_dirfile(char *string, char *dir, char *file)
1178 {
1179         int a;
1180 #ifdef WIN32
1181         int sl;
1182         short is_relative = 0;
1183         char path[FILE_MAX];
1184 #endif
1185
1186         dir[0]= 0;
1187         file[0]= 0;
1188
1189 #ifdef WIN32
1190         BLI_strncpy(path, string, FILE_MAX);
1191         BLI_char_switch(path, '/', '\\'); /* make sure we have a valid path format */
1192         sl = strlen(path);
1193         if (sl) {
1194                 int len;
1195                 if (path[0] == '/' || path[0] == '\\') { 
1196                         BLI_strncpy(dir, path, FILE_MAXDIR);
1197                         if (sl > 1 && path[0] == '\\' && path[1] == '\\') is_relative = 1;
1198                 } else if (sl > 2 && path[1] == ':' && path[2] == '\\') {
1199                         BLI_strncpy(dir, path, FILE_MAXDIR);
1200                 } else {
1201                         BLI_getwdN(dir);
1202                         strcat(dir,"\\");
1203                         strcat(dir,path);
1204                         BLI_strncpy(path,dir,FILE_MAXDIR+FILE_MAXFILE);
1205                 }
1206                 
1207                 // BLI_exist doesn't recognize a slashed dirname as a dir
1208                 //  check if a trailing slash exists, and remove it. Do not do this
1209                 //  when we are already at root. -jesterKing
1210                 a = strlen(dir);
1211                 if(a>=4 && dir[a-1]=='\\') dir[a-1] = 0;
1212
1213                 if (is_relative) {
1214                         printf("WARNING: BLI_split_dirfile needs absolute dir\n");
1215                 }
1216                 else {
1217                         BLI_make_exist(dir);
1218                 }
1219
1220                 if (S_ISDIR(BLI_exist(dir))) {
1221
1222                         /* copy from end of string into file, to ensure filename itself isn't truncated 
1223                         if string is too long. (aphex) */
1224
1225                         len = FILE_MAXFILE - strlen(path);
1226
1227                         if (len < 0)
1228                                 BLI_strncpy(file,path + abs(len),FILE_MAXFILE);
1229                         else
1230                                 BLI_strncpy(file,path,FILE_MAXFILE);
1231                     
1232                         if (strrchr(path,'\\')) {
1233                                 BLI_strncpy(file,strrchr(path,'\\')+1,FILE_MAXFILE);
1234                         }
1235                         
1236                         if ( (a = strlen(dir)) ) {
1237                                 if (dir[a-1] != '\\') strcat(dir,"\\");
1238                         }
1239                 }
1240                 else {
1241                         a = strlen(dir) - 1;
1242                         while(a>0 && dir[a] != '\\') a--;
1243                         dir[a + 1] = 0;
1244                         BLI_strncpy(file, path + strlen(dir),FILE_MAXFILE);
1245                 }
1246
1247         }
1248         else {
1249                 /* defaulting to first valid drive hoping it's not empty CD and DVD drives */
1250                 get_default_root(dir);
1251                 file[0]=0;
1252         }
1253 #else
1254         if (strlen(string)) {
1255                 if (string[0] == '/') { 
1256                         strcpy(dir, string);
1257                 } else if (string[1] == ':' && string[2] == '\\') {
1258                         string+=2;
1259                         strcpy(dir, string);
1260                 } else {
1261                         BLI_getwdN(dir);
1262                         strcat(dir,"/");
1263                         strcat(dir,string);
1264                         strcpy((char *)string,dir);
1265                 }
1266
1267                 BLI_make_exist(dir);
1268                         
1269                 if (S_ISDIR(BLI_exist(dir))) {
1270                         strcpy(file,string + strlen(dir));
1271
1272                         if (strrchr(file,'/')) strcpy(file,strrchr(file,'/')+1);
1273                 
1274                         if ( (a = strlen(dir)) ) {
1275                                 if (dir[a-1] != '/') strcat(dir,"/");
1276                         }
1277                 }
1278                 else {
1279                         a = strlen(dir) - 1;
1280                         while(dir[a] != '/') a--;
1281                         dir[a + 1] = 0;
1282                         strcpy(file, string + strlen(dir));
1283                 }
1284         }
1285         else {
1286                 BLI_getwdN(dir);
1287                 strcat(dir, "/");
1288                 file[0] = 0;
1289         }
1290 #endif
1291 }
1292
1293 /* simple appending of filename to dir, does not check for valid path! */
1294 void BLI_join_dirfile(char *string, const char *dir, const char *file)
1295 {
1296         int sl_dir;
1297         
1298         if(string != dir) /* compare pointers */
1299                 BLI_strncpy(string, dir, FILE_MAX);
1300         
1301         sl_dir= BLI_add_slash(string);
1302         
1303         if (sl_dir <FILE_MAX) {
1304                 BLI_strncpy(string + sl_dir, file, FILE_MAX-sl_dir);
1305         }
1306 }
1307
1308 static int add_win32_extension(char *name)
1309 {
1310         int retval = 0;
1311         int type;
1312
1313         type = BLI_exist(name);
1314         if ((type == 0) || S_ISDIR(type)) {
1315 #ifdef _WIN32
1316                 char filename[FILE_MAXDIR+FILE_MAXFILE];
1317                 char ext[FILE_MAXDIR+FILE_MAXFILE];
1318                 char *extensions = getenv("PATHEXT");
1319                 if (extensions) {
1320                         char *temp;
1321                         do {
1322                                 strcpy(filename, name);
1323                                 temp = strstr(extensions, ";");
1324                                 if (temp) {
1325                                         strncpy(ext, extensions, temp - extensions);
1326                                         ext[temp - extensions] = 0;
1327                                         extensions = temp + 1;
1328                                         strcat(filename, ext);
1329                                 } else {
1330                                         strcat(filename, extensions);
1331                                 }
1332
1333                                 type = BLI_exist(filename);
1334                                 if (type && (! S_ISDIR(type))) {
1335                                         retval = 1;
1336                                         strcpy(name, filename);
1337                                         break;
1338                                 }
1339                         } while (temp);
1340                 }
1341 #endif
1342         } else {
1343                 retval = 1;
1344         }
1345
1346         return (retval);
1347 }
1348
1349 void BLI_where_am_i(char *fullname, const char *name)
1350 {
1351         char filename[FILE_MAXDIR+FILE_MAXFILE];
1352         char *path = NULL, *temp;
1353         
1354 #ifdef _WIN32
1355         char *seperator = ";";
1356         char slash = '\\';
1357 #else
1358         char *seperator = ":";
1359         char slash = '/';
1360 #endif
1361
1362         
1363 #ifdef __linux__
1364         /* linux uses binreloc since argv[0] is not relyable, call br_init( NULL ) first */
1365         path = br_find_exe( NULL );
1366         if (path) {
1367                 strcpy(fullname, path);
1368                 free(path);
1369                 return;
1370         }
1371 #endif
1372         
1373         /* unix and non linux */
1374         if (name && fullname && strlen(name)) {
1375                 strcpy(fullname, name);
1376                 if (name[0] == '.') {
1377                         // relative path, prepend cwd
1378                         BLI_getwdN(fullname);
1379                         
1380                         // not needed but avoids annoying /./ in name
1381                         if(name && name[0]=='.' && name[1]==slash)
1382                                 BLI_join_dirfile(fullname, fullname, name+2);
1383                         else
1384                                 BLI_join_dirfile(fullname, fullname, name);
1385                         
1386                         add_win32_extension(fullname);
1387                 } else if (BLI_last_slash(name)) {
1388                         // full path
1389                         strcpy(fullname, name);
1390                         add_win32_extension(fullname);
1391                 } else {
1392                         // search for binary in $PATH
1393                         path = getenv("PATH");
1394                         if (path) {
1395                                 do {
1396                                         temp = strstr(path, seperator);
1397                                         if (temp) {
1398                                                 strncpy(filename, path, temp - path);
1399                                                 filename[temp - path] = 0;
1400                                                 path = temp + 1;
1401                                         } else {
1402                                                 strncpy(filename, path, sizeof(filename));
1403                                         }
1404                                         BLI_join_dirfile(fullname, fullname, name);
1405                                         if (add_win32_extension(filename)) {
1406                                                 strcpy(fullname, filename);
1407                                                 break;
1408                                         }
1409                                 } while (temp);
1410                         }
1411                 }
1412 #ifndef NDEBUG
1413                 if (strcmp(name, fullname)) {
1414                         printf("guessing '%s' == '%s'\n", name, fullname);
1415                 }
1416 #endif
1417
1418 #ifdef _WIN32
1419                 // in windows change long filename to short filename because
1420                 // win2k doesn't know how to parse a commandline with lots of
1421                 // spaces and double-quotes. There's another solution to this
1422                 // with spawnv(P_WAIT, bprogname, argv) instead of system() but
1423                 // that's even uglier
1424                 GetShortPathName(fullname, fullname, FILE_MAXDIR+FILE_MAXFILE);
1425 #ifndef NDEBUG
1426                 printf("Shortname = '%s'\n", fullname);
1427 #endif
1428 #endif
1429         }
1430 }
1431
1432 void BLI_where_is_temp(char *fullname, int usertemp)
1433 {
1434         fullname[0] = '\0';
1435         
1436         if (usertemp && BLI_exists(U.tempdir)) {
1437                 strcpy(fullname, U.tempdir);
1438         }
1439         
1440         
1441 #ifdef WIN32
1442         if (fullname[0] == '\0') {
1443                 char *tmp = getenv("TEMP"); /* Windows */
1444                 if (tmp && BLI_exists(tmp)) {
1445                         strcpy(fullname, tmp);
1446                 }
1447         }
1448 #else
1449         /* Other OS's - Try TMP and TMPDIR */
1450         if (fullname[0] == '\0') {
1451                 char *tmp = getenv("TMP");
1452                 if (tmp && BLI_exists(tmp)) {
1453                         strcpy(fullname, tmp);
1454                 }
1455         }
1456         
1457         if (fullname[0] == '\0') {
1458                 char *tmp = getenv("TMPDIR");
1459                 if (tmp && BLI_exists(tmp)) {
1460                         strcpy(fullname, tmp);
1461                 }
1462         }
1463 #endif  
1464         
1465         if (fullname[0] == '\0') {
1466                 strcpy(fullname, "/tmp/");
1467         } else {
1468                 /* add a trailing slash if needed */
1469                 BLI_add_slash(fullname);
1470         }
1471 }
1472
1473 char *get_install_dir(void) {
1474         extern char bprogname[];
1475         char *tmpname = BLI_strdup(bprogname);
1476         char *cut;
1477
1478 #ifdef __APPLE__
1479         cut = strstr(tmpname, ".app");
1480         if (cut) cut[0] = 0;
1481 #endif
1482
1483         cut = BLI_last_slash(tmpname);
1484
1485         if (cut) {
1486                 cut[0] = 0;
1487                 return tmpname;
1488         } else {
1489                 MEM_freeN(tmpname);
1490                 return NULL;
1491         }
1492 }
1493
1494 /* 
1495  * returns absolute path to the app bundle
1496  * only useful on OS X 
1497  */
1498 #ifdef __APPLE__
1499 char* BLI_getbundle(void) {
1500         CFURLRef bundleURL;
1501         CFStringRef pathStr;
1502         static char path[MAXPATHLEN];
1503         CFBundleRef mainBundle = CFBundleGetMainBundle();
1504
1505         bundleURL = CFBundleCopyBundleURL(mainBundle);
1506         pathStr = CFURLCopyFileSystemPath(bundleURL, kCFURLPOSIXPathStyle);
1507         CFStringGetCString(pathStr, path, MAXPATHLEN, kCFStringEncodingASCII);
1508         return path;
1509 }
1510 #endif
1511
1512 #ifdef WITH_ICONV
1513 #include "iconv.h"
1514 #include "localcharset.h"
1515
1516 void BLI_string_to_utf8(char *original, char *utf_8, const char *code)
1517 {
1518         size_t inbytesleft=strlen(original);
1519         size_t outbytesleft=512;
1520         size_t rv=0;
1521         iconv_t cd;
1522         
1523         if (NULL == code) {
1524                 code = locale_charset();
1525         }
1526         cd=iconv_open("UTF-8", code);
1527
1528         if (cd == (iconv_t)(-1)) {
1529                 printf("iconv_open Error");
1530                 *utf_8='\0';
1531                 return ;
1532         }
1533         rv=iconv(cd, &original, &inbytesleft, &utf_8, &outbytesleft);
1534         if (rv == (size_t) -1) {
1535                 printf("iconv Error\n");
1536                 return ;
1537         }
1538         *utf_8 = '\0';
1539         iconv_close(cd);
1540 }
1541 #endif // WITH_ICONV
1542
1543