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