MSVC 9 compile fixes and cleanups
[blender-staging.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 int BLI_convertstringframe(char *path, int frame)
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         if (ch_end) { /* warning, ch_end is the last # +1 */
548                 /* Add the frame number? */
549                 short numlen, hashlen;
550                 char tmp[FILE_MAX];
551                 
552                 char format[16]; /* 6 is realistically the maxframe (300000), so 8 should be enough, but 16 to be safe. */
553                 if (((ch_end-1)-ch_sta) >= 16) {
554                         ch_end = ch_sta+15; /* disallow values longer then 'format' can hold */
555                 }
556                 
557                 strcpy(tmp, path);
558                 
559                 numlen = 1 + (int)log10((double)frame); /* this is the number of chars in the number */
560                 hashlen = ch_end - ch_sta;
561                 
562                 sprintf(format, "%d", frame);
563                 
564                 if (numlen==hashlen) { /* simple case */
565                         memcpy(tmp+ch_sta, format, numlen);
566                 } else if (numlen < hashlen) {
567                         memcpy(tmp+ch_sta + (hashlen-numlen), format, numlen); /*dont copy the string terminator */
568                         memset(tmp+ch_sta, '0', hashlen-numlen);
569                 } else {
570                         /* number is longer then number of #'s */
571                         if (tmp[ch_end] == '\0') { /* hashes are last, no need to move any string*/
572                                 /* bad juju - not testing string length here :/ */
573                                 memcpy(tmp+ch_sta, format, numlen+1); /* add 1 to get the string terminator \0 */
574                         } else {
575                                 /* we need to move the end characters, reuse i */
576                                 int j;
577                                 
578                                 i = strlen(tmp); /* +1 to copy the string terminator */
579                                 j = i + (numlen-hashlen); /* from/to */
580                                 
581                                 while (i >= ch_end) {
582                                         tmp[j] = tmp[i]; 
583                                         i--;
584                                         j--;
585                                 }
586                                 memcpy(tmp + ch_sta, format, numlen);
587                         }
588                 }       
589                 strcpy(path, tmp);
590                 return 1;
591         }
592         return 0;
593 }
594
595
596 int BLI_convertstringcode(char *path, const char *basepath)
597 {
598         int wasrelative = (strncmp(path, "//", 2)==0);
599         char tmp[FILE_MAX];
600         char base[FILE_MAX];
601 #ifdef WIN32
602         char vol[3] = {'\0', '\0', '\0'};
603
604         BLI_strncpy(vol, path, 3);
605         /* we are checking here if we have an absolute path that is not in the current
606            blend file as a lib main - we are basically checking for the case that a 
607            UNIX root '/' is passed.
608         */
609         if (!wasrelative && (vol[1] != ':' && (vol[0] == '\0' || vol[0] == '/' || vol[0] == '\\'))) {
610                 char *p = path;
611                 get_default_root(tmp);
612                 // get rid of the slashes at the beginning of the path
613                 while (*p == '\\' || *p == '/') {
614                         p++;
615                 }
616                 strcat(tmp, p);
617         }
618         else {
619                 BLI_strncpy(tmp, path, FILE_MAX);
620         }
621 #else
622         BLI_strncpy(tmp, path, FILE_MAX);
623         
624         /* Check for loading a windows path on a posix system
625          * in this case, there is no use in trying C:/ since it 
626          * will never exist on a unix os.
627          * 
628          * Add a / prefix and lowercase the driveletter, remove the :
629          * C:\foo.JPG -> /c/foo.JPG */
630         
631         if (isalpha(tmp[0]) && tmp[1] == ':' && (tmp[2]=='\\' || tmp[2]=='/') ) {
632                 tmp[1] = tolower(tmp[0]); /* replace ':' with driveletter */
633                 tmp[0] = '/'; 
634                 /* '\' the slash will be converted later */
635         }
636         
637 #endif
638
639         BLI_strncpy(base, basepath, FILE_MAX);
640         
641         BLI_cleanup_file(NULL, base);
642         
643         /* push slashes into unix mode - strings entering this part are
644            potentially messed up: having both back- and forward slashes.
645            Here we push into one conform direction, and at the end we
646            push them into the system specific dir. This ensures uniformity
647            of paths and solving some problems (and prevent potential future
648            ones) -jesterKing. */
649         BLI_char_switch(tmp, '\\', '/');
650         BLI_char_switch(base, '\\', '/');       
651
652         /* Paths starting with // will get the blend file as their base,
653          * this isnt standard in any os but is uesed in blender all over the place */
654         if (wasrelative) {
655                 char *lslash= BLI_last_slash(base);
656                 if (lslash) {
657                         int baselen= (int) (lslash-base) + 1;
658                         /* use path for for temp storage here, we copy back over it right away */
659                         BLI_strncpy(path, tmp+2, FILE_MAX);
660                         
661                         memcpy(tmp, base, baselen);
662                         strcpy(tmp+baselen, path);
663                         strcpy(path, tmp);
664                 } else {
665                         strcpy(path, tmp+2);
666                 }
667         } else {
668                 strcpy(path, tmp);
669         }
670         
671         if (path[0]!='\0') {
672                 if ( path[strlen(path)-1]=='/') {
673                         BLI_cleanup_dir(NULL, path);
674                 } else {
675                         BLI_cleanup_file(NULL, path);
676                 }
677         }
678         
679 #ifdef WIN32
680         /* skip first two chars, which in case of
681            absolute path will be drive:/blabla and
682            in case of relpath //blabla/. So relpath
683            // will be retained, rest will be nice and
684            shiny win32 backward slashes :) -jesterKing
685         */
686         BLI_char_switch(path+2, '/', '\\');
687 #endif
688         
689         return wasrelative;
690 }
691
692
693 /*
694  * Should only be done with command line paths.
695  * this is NOT somthing blenders internal paths support like the // prefix
696  */
697 int BLI_convertstringcwd(char *path)
698 {
699         int wasrelative = 1;
700         int filelen = strlen(path);
701         
702 #ifdef WIN32
703         if (filelen >= 3 && path[1] == ':' && (path[2] == '\\' || path[2] == '/'))
704                 wasrelative = 0;
705 #else
706         if (filelen >= 2 && path[0] == '/')
707                 wasrelative = 0;
708 #endif
709         
710         if (wasrelative==1) {
711                 char cwd[FILE_MAXDIR + FILE_MAXFILE];
712                 BLI_getwdN(cwd); /* incase the full path to the blend isnt used */
713                 
714                 if (cwd[0] == '\0') {
715                         printf( "Could not get the current working directory - $PWD for an unknown reason.");
716                 } else {
717                         /* uses the blend path relative to cwd important for loading relative linked files.
718                         *
719                         * cwd should contain c:\ etc on win32 so the relbase can be NULL
720                         * relbase being NULL also prevents // being misunderstood as relative to the current
721                         * blend file which isnt a feature we want to use in this case since were dealing
722                         * with a path from the command line, rather then from inside Blender */
723                         
724                         char origpath[FILE_MAXDIR + FILE_MAXFILE];
725                         BLI_strncpy(origpath, path, FILE_MAXDIR + FILE_MAXFILE);
726                         
727                         BLI_make_file_string(NULL, path, cwd, origpath); 
728                 }
729         }
730         
731         return wasrelative;
732 }
733
734
735 /* copy di to fi, filename only */
736 void BLI_splitdirstring(char *di, char *fi)
737 {
738         char *lslash= BLI_last_slash(di);
739
740         if (lslash) {
741                 BLI_strncpy(fi, lslash+1, FILE_MAXFILE);
742                 *(lslash+1)=0;
743         } else {
744                 BLI_strncpy(fi, di, FILE_MAXFILE);
745                 di[0]= 0;
746         }
747 }
748
749 void BLI_getlastdir(const char* dir, char *last, int maxlen)
750 {
751         const char *s = dir;
752         const char *lslash = NULL;
753         const char *prevslash = NULL;
754         while (*s) {
755                 if ((*s == '\\') || (*s == '/')) {
756                         prevslash = lslash;
757                         lslash = s;
758                 }
759                 s++;
760         }
761         if (prevslash) {
762                 BLI_strncpy(last, prevslash+1, maxlen);
763         } else {
764                 BLI_strncpy(last, dir, maxlen);
765         }
766 }
767
768 char *BLI_gethome(void) {
769         #if !defined(WIN32)
770                 return getenv("HOME");
771
772         #else /* Windows */
773                 char * ret;
774                 static char dir[512];
775                 static char appdatapath[MAXPATHLEN];
776                 HRESULT hResult;
777
778                 /* Check for %HOME% env var */
779
780                 ret = getenv("HOME");
781                 if(ret) {
782                         sprintf(dir, "%s\\.blender", ret);
783                         if (BLI_exists(dir)) return dir;
784                 }
785
786                 /* else, check install dir (path containing blender.exe) */
787
788                 BLI_getInstallationDir(dir);
789
790                 if (BLI_exists(dir))
791                 {
792                         strcat(dir,"\\.blender");
793                         if (BLI_exists(dir)) return(dir);
794                 }
795
796                                 
797                 /* add user profile support for WIN 2K / NT */
798                 hResult = SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT, appdatapath);
799                 
800                 if (hResult == S_OK)
801                 {
802                         if (BLI_exists(appdatapath)) { /* from fop, also below... */
803                                 sprintf(dir, "%s\\Blender Foundation\\Blender", appdatapath);
804                                 BLI_recurdir_fileops(dir);
805                                 if (BLI_exists(dir)) {
806                                         strcat(dir,"\\.blender");
807                                         if(BLI_exists(dir)) return(dir);
808                                 }
809                         }
810                         hResult = SHGetFolderPath(NULL, CSIDL_COMMON_APPDATA, NULL, SHGFP_TYPE_CURRENT, appdatapath);
811                         if (hResult == S_OK)
812                         {
813                                 if (BLI_exists(appdatapath)) 
814                                 { /* from fop, also below... */
815                                         sprintf(dir, "%s\\Blender Foundation\\Blender", appdatapath);
816                                         BLI_recurdir_fileops(dir);
817                                         if (BLI_exists(dir)) {
818                                                 strcat(dir,"\\.blender");
819                                                 if(BLI_exists(dir)) return(dir);
820                                         }
821                                 }
822                         }
823                 }
824 #if 0
825                 ret = getenv("USERPROFILE");
826                 if (ret) {
827                         if (BLI_exists(ret)) { /* from fop, also below...  */
828                                 sprintf(dir, "%s\\Application Data\\Blender Foundation\\Blender", ret);
829                                 BLI_recurdir_fileops(dir);
830                                 if (BLI_exists(dir)) {
831                                         strcat(dir,"\\.blender");
832                                         if(BLI_exists(dir)) return(dir);
833                                 }
834                         }
835                 }
836 #endif
837
838                 /* 
839                    Saving in the Windows dir is less than desirable. 
840                    Use as a last resort ONLY! (aphex)
841                 */
842                 
843                 ret = getenv("WINDOWS");                
844                 if (ret) {
845                         if(BLI_exists(ret)) return ret;
846                 }
847
848                 ret = getenv("WINDIR"); 
849                 if (ret) {
850                         if(BLI_exists(ret)) return ret;
851                 }
852                 
853                 return "C:\\Temp";      /* sheesh! bad, bad, bad! (aphex) */
854         #endif
855 }
856
857 /* this function returns the path to a blender folder, if it exists
858  * utility functions for BLI_gethome_folder */
859
860 /* #define PATH_DEBUG */ /* for testing paths that are checked */
861
862 static int test_data_path(char *targetpath, char *path_base, char *path_sep, char *folder_name)
863 {
864         char tmppath[FILE_MAXDIR];
865         
866         if(path_sep)    BLI_join_dirfile(tmppath, path_base, path_sep);
867         else                    BLI_strncpy(tmppath, path_base, sizeof(tmppath));
868         
869         BLI_make_file_string("/", targetpath, tmppath, folder_name);
870         
871         if (BLI_exists(targetpath)) {
872 #ifdef PATH_DEBUG
873                 printf("\tpath found: %s\n", targetpath);
874 #endif
875                 return 1;
876         }
877         else {
878 #ifdef PATH_DEBUG
879                 printf("\tpath missing: %s\n", targetpath);
880 #endif
881                 targetpath[0] = '\0';
882                 return 0;
883         }
884 }
885
886 static int gethome_path_local(char *targetpath, char *folder_name)
887 {
888         extern char bprogname[]; /* argv[0] from creator.c */
889         char bprogdir[FILE_MAXDIR];
890         char cwd[FILE_MAXDIR];
891         char *s;
892         int i;
893         
894 #ifdef PATH_DEBUG
895         printf("gethome_path_local...\n");
896 #endif
897         
898         /* try release/folder_name (binary relative) */
899         /* use argv[0] (bprogname) to get the path to the executable */
900         s = BLI_last_slash(bprogname);
901         i = s - bprogname + 1;
902         BLI_strncpy(bprogdir, bprogname, i);
903
904         /* try release/folder_name (CWD relative) */
905         if(test_data_path(targetpath, BLI_getwdN(cwd), "release", folder_name))
906                 return 1;
907
908         if(test_data_path(targetpath, bprogdir, "release", folder_name))
909                 return 1;
910
911         /* try ./.blender/folder_name */
912         if(test_data_path(targetpath, bprogdir, ".blender", folder_name))
913                 return 1;
914         
915         return 0;
916 }
917
918 static int gethome_path_user(char *targetpath, char *folder_name)
919 {
920         char *home_path= BLI_gethome();
921
922 #ifdef PATH_DEBUG
923         printf("gethome_path_user...\n");
924 #endif
925         
926         /* try $HOME/folder_name */
927         return test_data_path(targetpath, home_path, ".blender", folder_name);
928 }
929
930 static int gethome_path_system(char *targetpath, char *folder_name)
931 {
932         extern char blender_path[]; /* unix prefix eg. /usr/share/blender/2.5 creator.c */
933         
934         if(!blender_path[0])
935                 return 0;
936         
937 #ifdef PATH_DEBUG
938         printf("gethome_path_system...\n");
939 #endif
940         
941         /* try $BLENDERPATH/folder_name */
942         return test_data_path(targetpath, blender_path, NULL, folder_name);
943 }
944
945 char *BLI_gethome_folder(char *folder_name, int flag)
946 {
947         static char fulldir[FILE_MAXDIR] = "";
948         
949         /* first check if this is a redistributable bundle */
950         if(flag & BLI_GETHOME_LOCAL) {
951                 if (gethome_path_local(fulldir, folder_name))
952                         return fulldir;
953         }
954
955         /* then check if the OS has blender data files installed in a global location */
956         if(flag & BLI_GETHOME_SYSTEM) {
957                 if (gethome_path_system(fulldir, folder_name))
958                         return fulldir;
959         }
960         
961         /* now check the users home dir for data files */
962         if(flag & BLI_GETHOME_USER) {
963                 if (gethome_path_user(fulldir, folder_name))
964                         return fulldir;
965         }
966         
967         return NULL;
968 }
969
970 #ifdef PATH_DEBUG
971 #undef PATH_DEBUG
972 #endif
973
974 void BLI_setenv(const char *env, const char*val)
975 {
976         /* SGI or free windows */
977 #if (defined(__sgi) || ((defined(WIN32) || defined(WIN64)) && defined(FREE_WINDOWS)))
978         char *envstr= malloc(sizeof(char) * (strlen(env) + strlen(val) + 2)); /* one for = another for \0 */
979
980         sprintf(envstr, "%s=%s", env, val);
981         putenv(envstr);
982         free(envstr);
983
984         /* non-free windows */
985 #elif (defined(WIN32) || defined(WIN64)) /* not free windows */
986         _putenv_s(env, val);
987 #else
988         /* linux/osx/bsd */
989         setenv(env, val, 1);
990 #endif
991 }
992
993
994 /**
995  Only set an env var if already not there.
996  Like Unix setenv(env, val, 0);
997  */
998 void BLI_setenv_if_new(const char *env, const char* val)
999 {
1000         if(getenv(env) == NULL)
1001                 BLI_setenv(env, val);
1002 }
1003
1004
1005 void BLI_clean(char *path)
1006 {
1007         if(path==0) return;
1008 #ifdef WIN32
1009         if(path && strlen(path)>2) {
1010                 BLI_char_switch(path+2, '/', '\\');
1011         }
1012 #else
1013         BLI_char_switch(path, '\\', '/');
1014 #endif
1015 }
1016
1017 void BLI_char_switch(char *string, char from, char to) 
1018 {
1019         if(string==0) return;
1020         while (*string != 0) {
1021                 if (*string == from) *string = to;
1022                 string++;
1023         }
1024 }
1025
1026 void BLI_make_exist(char *dir) {
1027         int a;
1028
1029         #ifdef WIN32
1030                 BLI_char_switch(dir, '/', '\\');
1031         #else
1032                 BLI_char_switch(dir, '\\', '/');
1033         #endif  
1034         
1035         a = strlen(dir);
1036         
1037 #ifdef WIN32    
1038         while(BLI_exists(dir) == 0){
1039                 a --;
1040                 while(dir[a] != '\\'){
1041                         a--;
1042                         if (a <= 0) break;
1043                 }
1044                 if (a >= 0) dir[a+1] = 0;
1045                 else {
1046                         /* defaulting to drive (usually 'C:') of Windows installation */
1047                         get_default_root(dir);
1048                         break;
1049                 }
1050         }
1051 #else
1052         while(BLI_exist(dir) == 0){
1053                 a --;
1054                 while(dir[a] != '/'){
1055                         a--;
1056                         if (a <= 0) break;
1057                 }
1058                 if (a >= 0) dir[a+1] = 0;
1059                 else {
1060                         strcpy(dir,"/");
1061                         break;
1062                 }
1063         }
1064 #endif
1065 }
1066
1067 void BLI_make_existing_file(char *name)
1068 {
1069         char di[FILE_MAXDIR], fi[FILE_MAXFILE];
1070         
1071         strcpy(di, name);
1072         BLI_splitdirstring(di, fi);
1073         
1074         /* test exist */
1075         if (BLI_exists(di) == 0) {
1076                 BLI_recurdir_fileops(di);
1077         }
1078 }
1079
1080
1081 void BLI_make_file_string(const char *relabase, char *string,  const char *dir, const char *file)
1082 {
1083         int sl;
1084
1085         if (!string || !dir || !file) return; /* We don't want any NULLs */
1086         
1087         string[0]= 0; /* ton */
1088
1089         /* we first push all slashes into unix mode, just to make sure we don't get
1090            any mess with slashes later on. -jesterKing */
1091         /* constant strings can be passed for those parameters - don't change them - elubie */
1092         /*
1093         BLI_char_switch(relabase, '\\', '/');
1094         BLI_char_switch(dir, '\\', '/');
1095         BLI_char_switch(file, '\\', '/');
1096         */
1097
1098         /* Resolve relative references */       
1099         if (relabase && dir[0] == '/' && dir[1] == '/') {
1100                 char *lslash;
1101                 
1102                 /* Get the file name, chop everything past the last slash (ie. the filename) */
1103                 strcpy(string, relabase);
1104                 
1105                 lslash= (strrchr(string, '/')>strrchr(string, '\\'))?strrchr(string, '/'):strrchr(string, '\\');
1106                 
1107                 if(lslash) *(lslash+1)= 0;
1108
1109                 dir+=2; /* Skip over the relative reference */
1110         }
1111 #ifdef WIN32
1112         else {
1113                 if (strlen(dir) >= 2 && dir[1] == ':' ) {
1114                         BLI_strncpy(string, dir, 3);
1115                         dir += 2;
1116                 }
1117                 else { /* no drive specified */
1118                         /* first option: get the drive from the relabase if it has one */
1119                         if (relabase && strlen(relabase) >= 2 && relabase[1] == ':' ) {
1120                                 BLI_strncpy(string, relabase, 3);       
1121                                 string[2] = '\\';
1122                                 string[3] = '\0';
1123                         }
1124                         else { /* we're out of luck here, guessing the first valid drive, usually c:\ */
1125                                 get_default_root(string);
1126                         }
1127                         
1128                         /* ignore leading slashes */
1129                         while (*dir == '/' || *dir == '\\') dir++;
1130                 }
1131         }
1132 #endif
1133
1134         strcat(string, dir);
1135
1136         /* Make sure string ends in one (and only one) slash */ 
1137         /* first trim all slashes from the end of the string */
1138         sl = strlen(string);
1139         while (sl>0 && ( string[sl-1] == '/' || string[sl-1] == '\\') ) {
1140                 string[sl-1] = '\0';
1141                 sl--;
1142         }
1143         /* since we've now removed all slashes, put back one slash at the end. */
1144         strcat(string, "/");
1145         
1146         while (*file && (*file == '/' || *file == '\\')) /* Trim slashes from the front of file */
1147                 file++;
1148                 
1149         strcat (string, file);
1150         
1151         /* Push all slashes to the system preferred direction */
1152         BLI_clean(string);
1153 }
1154
1155 int BLI_testextensie(const char *str, const char *ext)
1156 {
1157         short a, b;
1158         int retval;
1159
1160         a= strlen(str);
1161         b= strlen(ext);
1162
1163         if(a==0 || b==0 || b>=a) {
1164                 retval = 0;
1165         } else if (BLI_strcasecmp(ext, str + a - b)) {
1166                 retval = 0;     
1167         } else {
1168                 retval = 1;
1169         }
1170
1171         return (retval);
1172 }
1173
1174 /*
1175  * This is a simple version of BLI_split_dirfile that has the following advantages...
1176  * 
1177  * Converts "/foo/bar.txt" to "/foo/" and "bar.txt"
1178  * - wont change 'string'
1179  * - wont create any directories
1180  * - dosnt use CWD, or deal with relative paths.
1181  * - Only fill's in *dir and *file when they are non NULL
1182  * */
1183 void BLI_split_dirfile_basic(const char *string, char *dir, char *file)
1184 {
1185         int lslash=0, i = 0;
1186         for (i=0; string[i]!='\0'; i++) {
1187                 if (string[i]=='\\' || string[i]=='/')
1188                         lslash = i+1;
1189         }
1190         if (dir) {
1191                 if (lslash) {
1192                         BLI_strncpy( dir, string, lslash+1); /* +1 to include the slash and the last char */
1193                 } else {
1194                         dir[0] = '\0';
1195                 }
1196         }
1197         
1198         if (file) {
1199                 strcpy( file, string+lslash);
1200         }
1201 }
1202
1203
1204 /* Warning,
1205  * - May modify 'string' variable
1206  * - May create the directory if it dosnt exist
1207  * if this is not needed use BLI_split_dirfile_basic(...)
1208  */
1209 void BLI_split_dirfile(char *string, char *dir, char *file)
1210 {
1211         int a;
1212 #ifdef WIN32
1213         int sl;
1214         short is_relative = 0;
1215         char path[FILE_MAX];
1216 #endif
1217
1218         dir[0]= 0;
1219         file[0]= 0;
1220
1221 #ifdef WIN32
1222         BLI_strncpy(path, string, FILE_MAX);
1223         BLI_char_switch(path, '/', '\\'); /* make sure we have a valid path format */
1224         sl = strlen(path);
1225         if (sl) {
1226                 int len;
1227                 if (path[0] == '/' || path[0] == '\\') { 
1228                         BLI_strncpy(dir, path, FILE_MAXDIR);
1229                         if (sl > 1 && path[0] == '\\' && path[1] == '\\') is_relative = 1;
1230                 } else if (sl > 2 && path[1] == ':' && path[2] == '\\') {
1231                         BLI_strncpy(dir, path, FILE_MAXDIR);
1232                 } else {
1233                         BLI_getwdN(dir);
1234                         strcat(dir,"\\");
1235                         strcat(dir,path);
1236                         BLI_strncpy(path,dir,FILE_MAXDIR+FILE_MAXFILE);
1237                 }
1238                 
1239                 // BLI_exist doesn't recognize a slashed dirname as a dir
1240                 //  check if a trailing slash exists, and remove it. Do not do this
1241                 //  when we are already at root. -jesterKing
1242                 a = strlen(dir);
1243                 if(a>=4 && dir[a-1]=='\\') dir[a-1] = 0;
1244
1245                 if (is_relative) {
1246                         printf("WARNING: BLI_split_dirfile needs absolute dir\n");
1247                 }
1248                 else {
1249                         BLI_make_exist(dir);
1250                 }
1251
1252                 if (S_ISDIR(BLI_exist(dir))) {
1253
1254                         /* copy from end of string into file, to ensure filename itself isn't truncated 
1255                         if string is too long. (aphex) */
1256
1257                         len = FILE_MAXFILE - strlen(path);
1258
1259                         if (len < 0)
1260                                 BLI_strncpy(file,path + abs(len),FILE_MAXFILE);
1261                         else
1262                                 BLI_strncpy(file,path,FILE_MAXFILE);
1263                     
1264                         if (strrchr(path,'\\')) {
1265                                 BLI_strncpy(file,strrchr(path,'\\')+1,FILE_MAXFILE);
1266                         }
1267                         
1268                         if ( (a = strlen(dir)) ) {
1269                                 if (dir[a-1] != '\\') strcat(dir,"\\");
1270                         }
1271                 }
1272                 else {
1273                         a = strlen(dir) - 1;
1274                         while(a>0 && dir[a] != '\\') a--;
1275                         dir[a + 1] = 0;
1276                         BLI_strncpy(file, path + strlen(dir),FILE_MAXFILE);
1277                 }
1278
1279         }
1280         else {
1281                 /* defaulting to first valid drive hoping it's not empty CD and DVD drives */
1282                 get_default_root(dir);
1283                 file[0]=0;
1284         }
1285 #else
1286         if (strlen(string)) {
1287                 if (string[0] == '/') { 
1288                         strcpy(dir, string);
1289                 } else if (string[1] == ':' && string[2] == '\\') {
1290                         string+=2;
1291                         strcpy(dir, string);
1292                 } else {
1293                         BLI_getwdN(dir);
1294                         strcat(dir,"/");
1295                         strcat(dir,string);
1296                         strcpy((char *)string,dir);
1297                 }
1298
1299                 BLI_make_exist(dir);
1300                         
1301                 if (S_ISDIR(BLI_exist(dir))) {
1302                         strcpy(file,string + strlen(dir));
1303
1304                         if (strrchr(file,'/')) strcpy(file,strrchr(file,'/')+1);
1305                 
1306                         if ( (a = strlen(dir)) ) {
1307                                 if (dir[a-1] != '/') strcat(dir,"/");
1308                         }
1309                 }
1310                 else {
1311                         a = strlen(dir) - 1;
1312                         while(dir[a] != '/') a--;
1313                         dir[a + 1] = 0;
1314                         strcpy(file, string + strlen(dir));
1315                 }
1316         }
1317         else {
1318                 BLI_getwdN(dir);
1319                 strcat(dir, "/");
1320                 file[0] = 0;
1321         }
1322 #endif
1323 }
1324
1325 /* simple appending of filename to dir, does not check for valid path! */
1326 void BLI_join_dirfile(char *string, const char *dir, const char *file)
1327 {
1328         int sl_dir;
1329         
1330         if(string != dir) /* compare pointers */
1331                 BLI_strncpy(string, dir, FILE_MAX);
1332         
1333         sl_dir= BLI_add_slash(string);
1334         
1335         if (sl_dir <FILE_MAX) {
1336                 BLI_strncpy(string + sl_dir, file, FILE_MAX-sl_dir);
1337         }
1338 }
1339
1340 static int add_win32_extension(char *name)
1341 {
1342         int retval = 0;
1343         int type;
1344
1345         type = BLI_exist(name);
1346         if ((type == 0) || S_ISDIR(type)) {
1347 #ifdef _WIN32
1348                 char filename[FILE_MAXDIR+FILE_MAXFILE];
1349                 char ext[FILE_MAXDIR+FILE_MAXFILE];
1350                 char *extensions = getenv("PATHEXT");
1351                 if (extensions) {
1352                         char *temp;
1353                         do {
1354                                 strcpy(filename, name);
1355                                 temp = strstr(extensions, ";");
1356                                 if (temp) {
1357                                         strncpy(ext, extensions, temp - extensions);
1358                                         ext[temp - extensions] = 0;
1359                                         extensions = temp + 1;
1360                                         strcat(filename, ext);
1361                                 } else {
1362                                         strcat(filename, extensions);
1363                                 }
1364
1365                                 type = BLI_exist(filename);
1366                                 if (type && (! S_ISDIR(type))) {
1367                                         retval = 1;
1368                                         strcpy(name, filename);
1369                                         break;
1370                                 }
1371                         } while (temp);
1372                 }
1373 #endif
1374         } else {
1375                 retval = 1;
1376         }
1377
1378         return (retval);
1379 }
1380
1381 void BLI_where_am_i(char *fullname, const char *name)
1382 {
1383         char filename[FILE_MAXDIR+FILE_MAXFILE];
1384         char *path = NULL, *temp;
1385         
1386 #ifdef _WIN32
1387         char *separator = ";";
1388         char slash = '\\';
1389 #else
1390         char *separator = ":";
1391         char slash = '/';
1392 #endif
1393
1394         
1395 #ifdef __linux__
1396         /* linux uses binreloc since argv[0] is not relyable, call br_init( NULL ) first */
1397         path = br_find_exe( NULL );
1398         if (path) {
1399                 strcpy(fullname, path);
1400                 free(path);
1401                 return;
1402         }
1403 #endif
1404
1405 #ifdef _WIN32
1406         if(GetModuleFileName(0, fullname, FILE_MAXDIR+FILE_MAXFILE)) {
1407                 GetShortPathName(fullname, fullname, FILE_MAXDIR+FILE_MAXFILE);
1408                 return;
1409         }
1410 #endif
1411
1412         /* unix and non linux */
1413         if (name && fullname && strlen(name)) {
1414                 strcpy(fullname, name);
1415                 if (name[0] == '.') {
1416                         // relative path, prepend cwd
1417                         BLI_getwdN(fullname);
1418                         
1419                         // not needed but avoids annoying /./ in name
1420                         if(name && name[0]=='.' && name[1]==slash)
1421                                 BLI_join_dirfile(fullname, fullname, name+2);
1422                         else
1423                                 BLI_join_dirfile(fullname, fullname, name);
1424                         
1425                         add_win32_extension(fullname);
1426                 } else if (BLI_last_slash(name)) {
1427                         // full path
1428                         strcpy(fullname, name);
1429                         add_win32_extension(fullname);
1430                 } else {
1431                         // search for binary in $PATH
1432                         path = getenv("PATH");
1433                         if (path) {
1434                                 do {
1435                                         temp = strstr(path, separator);
1436                                         if (temp) {
1437                                                 strncpy(filename, path, temp - path);
1438                                                 filename[temp - path] = 0;
1439                                                 path = temp + 1;
1440                                         } else {
1441                                                 strncpy(filename, path, sizeof(filename));
1442                                         }
1443                                         BLI_join_dirfile(fullname, fullname, name);
1444                                         if (add_win32_extension(filename)) {
1445                                                 strcpy(fullname, filename);
1446                                                 break;
1447                                         }
1448                                 } while (temp);
1449                         }
1450                 }
1451 #ifndef NDEBUG
1452                 if (strcmp(name, fullname)) {
1453                         printf("guessing '%s' == '%s'\n", name, fullname);
1454                 }
1455 #endif
1456
1457 #ifdef _WIN32
1458                 // in windows change long filename to short filename because
1459                 // win2k doesn't know how to parse a commandline with lots of
1460                 // spaces and double-quotes. There's another solution to this
1461                 // with spawnv(P_WAIT, bprogname, argv) instead of system() but
1462                 // that's even uglier
1463                 GetShortPathName(fullname, fullname, FILE_MAXDIR+FILE_MAXFILE);
1464 #ifndef NDEBUG
1465                 printf("Shortname = '%s'\n", fullname);
1466 #endif
1467 #endif
1468         }
1469 }
1470
1471 void BLI_where_is_temp(char *fullname, int usertemp)
1472 {
1473         fullname[0] = '\0';
1474         
1475         if (usertemp && BLI_exists(U.tempdir)) {
1476                 strcpy(fullname, U.tempdir);
1477         }
1478         
1479         
1480 #ifdef WIN32
1481         if (fullname[0] == '\0') {
1482                 char *tmp = getenv("TEMP"); /* Windows */
1483                 if (tmp && BLI_exists(tmp)) {
1484                         strcpy(fullname, tmp);
1485                 }
1486         }
1487 #else
1488         /* Other OS's - Try TMP and TMPDIR */
1489         if (fullname[0] == '\0') {
1490                 char *tmp = getenv("TMP");
1491                 if (tmp && BLI_exists(tmp)) {
1492                         strcpy(fullname, tmp);
1493                 }
1494         }
1495         
1496         if (fullname[0] == '\0') {
1497                 char *tmp = getenv("TMPDIR");
1498                 if (tmp && BLI_exists(tmp)) {
1499                         strcpy(fullname, tmp);
1500                 }
1501         }
1502 #endif  
1503         
1504         if (fullname[0] == '\0') {
1505                 strcpy(fullname, "/tmp/");
1506         } else {
1507                 /* add a trailing slash if needed */
1508                 BLI_add_slash(fullname);
1509         }
1510 }
1511
1512 char *get_install_dir(void) {
1513         extern char bprogname[];
1514         char *tmpname = BLI_strdup(bprogname);
1515         char *cut;
1516
1517 #ifdef __APPLE__
1518         cut = strstr(tmpname, ".app");
1519         if (cut) cut[0] = 0;
1520 #endif
1521
1522         cut = BLI_last_slash(tmpname);
1523
1524         if (cut) {
1525                 cut[0] = 0;
1526                 return tmpname;
1527         } else {
1528                 MEM_freeN(tmpname);
1529                 return NULL;
1530         }
1531 }
1532
1533 /* 
1534  * returns absolute path to the app bundle
1535  * only useful on OS X 
1536  */
1537 #ifdef __APPLE__
1538 char* BLI_getbundle(void) {
1539         CFURLRef bundleURL;
1540         CFStringRef pathStr;
1541         static char path[MAXPATHLEN];
1542         CFBundleRef mainBundle = CFBundleGetMainBundle();
1543
1544         bundleURL = CFBundleCopyBundleURL(mainBundle);
1545         pathStr = CFURLCopyFileSystemPath(bundleURL, kCFURLPOSIXPathStyle);
1546         CFStringGetCString(pathStr, path, MAXPATHLEN, kCFStringEncodingASCII);
1547         CFRelease(pathStr);
1548         CFRelease(bundleURL);
1549         return path;
1550 }
1551 #endif
1552
1553 #ifdef WITH_ICONV
1554 #include "iconv.h"
1555 #include "localcharset.h"
1556
1557 void BLI_string_to_utf8(char *original, char *utf_8, const char *code)
1558 {
1559         size_t inbytesleft=strlen(original);
1560         size_t outbytesleft=512;
1561         size_t rv=0;
1562         iconv_t cd;
1563         
1564         if (NULL == code) {
1565                 code = locale_charset();
1566         }
1567         cd=iconv_open("UTF-8", code);
1568
1569         if (cd == (iconv_t)(-1)) {
1570                 printf("iconv_open Error");
1571                 *utf_8='\0';
1572                 return ;
1573         }
1574         rv=iconv(cd, &original, &inbytesleft, &utf_8, &outbytesleft);
1575         if (rv == (size_t) -1) {
1576                 printf("iconv Error\n");
1577                 return ;
1578         }
1579         *utf_8 = '\0';
1580         iconv_close(cd);
1581 }
1582 #endif // WITH_ICONV
1583
1584