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