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