Fix for paths commit from Andrea:
[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 #if defined(__APPLE__)
1019 #ifndef WITH_COCOA
1020 const char* BLI_osx_getBasePath(basePathesTypes pathType)
1021 {
1022         return "/tmp/";
1023 }
1024 #endif
1025 #endif
1026
1027 static int get_path_user(char *targetpath, char *folder_name, char *envvar)
1028 {
1029         char user_path[FILE_MAX];
1030 #if defined(WIN32)
1031         char appdata[FILE_MAX];
1032 #endif
1033
1034         user_path[0] = '\0';
1035
1036         if (test_env_path(targetpath, envvar))
1037                 return 1;
1038
1039 #if defined(__APPLE__)
1040         BLI_snprintf(user_path, FILE_MAX, "%s/%s", BLI_osx_getBasePath(BasePath_BlenderUser), blender_version_decimal());
1041 #elif defined(WIN32)
1042         if (get_knownfolder_path(appdata, CSIDL_APPDATA)) {     
1043                 BLI_snprintf(user_path, FILE_MAX, "%s\\Blender Foundation\\Blender\\%s", appdata, blender_version_decimal());
1044         }
1045 #else /* UNIX */
1046         /* XXX example below - replace with OS API */
1047         BLI_snprintf(user_path, FILE_MAX, "%s/.blender/%s", BLI_gethome(), blender_version_decimal());
1048 #endif
1049
1050         if(!user_path[0])
1051                 return 0;
1052         
1053 #ifdef PATH_DEBUG2
1054         printf("get_path_user: %s\n", user_path);
1055 #endif
1056         
1057         /* try $HOME/folder_name */
1058         return test_path(targetpath, user_path, NULL, folder_name);
1059 }
1060
1061 static int get_path_system(char *targetpath, char *folder_name, char *envvar)
1062 {
1063         char system_path[FILE_MAX];
1064 #if defined(WIN32)
1065         char appdata[FILE_MAX];
1066 #endif
1067
1068         if (test_env_path(targetpath, envvar))
1069                 return 1;
1070         
1071 #if defined(__APPLE__)
1072         BLI_snprintf(system_path, FILE_MAX, "%s/%s", BLI_osx_getBasePath(BasePath_ApplicationBundle), blender_version_decimal());
1073 #elif defined(WIN32)
1074         if (get_knownfolder_path(appdata, CSIDL_COMMON_APPDATA)) {      
1075                 BLI_snprintf(system_path, FILE_MAX, "%s\\Blender Foundation\\Blender\\%s", appdata, blender_version_decimal());
1076         }
1077 #else /* UNIX */
1078         /* XXX example below - replace with OS API */
1079         BLI_snprintf(system_path, FILE_MAX, "/usr/share/blender/%s", blender_version_decimal());
1080 #endif
1081         
1082         if(!system_path[0])
1083                 return 0;
1084         
1085 #ifdef PATH_DEBUG2
1086         printf("get_path_system: %s\n", system_path);
1087 #endif
1088         
1089         /* try $BLENDERPATH/folder_name */
1090         return test_path(targetpath, system_path, NULL, folder_name);
1091 }
1092
1093 /* get a folder out of the 'folder_id' presets for paths */
1094 /* returns the path if found, NULL string if not */
1095 char *BLI_get_folder(int folder_id, char *subfolder)
1096 {
1097         static char path[FILE_MAX] = "";
1098         char search_path[FILE_MAX];
1099         
1100         switch (folder_id) {
1101                 case BLENDER_DATAFILES:         /* general case */
1102                         BLI_join_dirfile(search_path, "datafiles", subfolder);
1103                         if (get_path_user(path, search_path, "BLENDER_USER_DATAFILES")) break;
1104                         if (get_path_local(path, search_path)) break;
1105                         if (get_path_system(path, search_path, "BLENDER_SYSTEM_DATAFILES")) break;
1106                         return NULL;
1107                         
1108                 case BLENDER_USER_DATAFILES:            
1109                         BLI_join_dirfile(search_path, "datafiles", subfolder);
1110                         if (get_path_user(path, search_path, "BLENDER_USER_DATAFILES")) break;
1111                         return NULL;
1112                         
1113                 case BLENDER_SYSTEM_DATAFILES:
1114                         BLI_join_dirfile(search_path, "datafiles", subfolder);
1115                         if (get_path_system(path, search_path, "BLENDER_SYSTEM_DATAFILES"))     break;
1116                         return NULL;
1117                         
1118                 case BLENDER_CONFIG:            /* general case */
1119                         BLI_join_dirfile(search_path, "config", subfolder);
1120                         if (get_path_user(path, search_path, "BLENDER_USER_CONFIG")) break;
1121                         if (get_path_local(path, search_path)) break;
1122                         if (get_path_system(path, search_path, "BLENDER_SYSTEM_CONFIG")) break;
1123                         return NULL;
1124                         
1125                 case BLENDER_USER_CONFIG:
1126                         BLI_join_dirfile(search_path, "config", subfolder);
1127                         if (get_path_user(path, search_path, "BLENDER_USER_CONFIG")) break;
1128                         return NULL;
1129                         
1130                 case BLENDER_SYSTEM_CONFIG:
1131                         BLI_join_dirfile(search_path, "config", subfolder);
1132                         if (get_path_system(path, search_path, "BLENDER_SYSTEM_CONFIG")) break;
1133                         return NULL;
1134                         
1135                 case BLENDER_SCRIPTS:           /* general case */
1136                         BLI_join_dirfile(search_path, "scripts", subfolder);
1137                         if (get_path_user(path, search_path, "BLENDER_USER_SCRIPTS")) break;            
1138                         if (get_path_local(path, search_path)) break;
1139                         if (get_path_system(path, search_path, "BLENDER_SYSTEM_SCRIPTS")) break;
1140                         return NULL;
1141                         
1142                 case BLENDER_USER_SCRIPTS:
1143                         BLI_join_dirfile(search_path, "scripts", subfolder);
1144                         if (get_path_user(path, search_path, "BLENDER_USER_SCRIPTS")) break;
1145                         return NULL;
1146                         
1147                 case BLENDER_SYSTEM_SCRIPTS:
1148                         BLI_join_dirfile(search_path, "scripts", subfolder);
1149                         if (get_path_system(path, search_path, "BLENDER_SYSTEM_SCRIPTS")) break;
1150                         return NULL;
1151                         
1152                 case BLENDER_PYTHON:            /* general case */
1153                         BLI_join_dirfile(search_path, "python", subfolder);
1154                         if (get_path_local(path, search_path)) break;
1155                         if (get_path_system(path, search_path, "BLENDER_SYSTEM_PYTHON")) break;
1156                         return NULL;
1157                         
1158                 case BLENDER_SYSTEM_PYTHON:
1159                         BLI_join_dirfile(search_path, "scripts", subfolder);
1160                         
1161                         if (get_path_system(path, search_path, "BLENDER_SYSTEM_PYTHON")) break;
1162                         return NULL;
1163         }
1164         
1165         return path;
1166 }
1167
1168 static char *BLI_get_user_folder_notest(int folder_id, char *subfolder)
1169 {
1170         static char path[FILE_MAX] = "";
1171         char search_path[FILE_MAX];
1172
1173         switch (folder_id) {
1174                 case BLENDER_USER_DATAFILES:
1175                         BLI_join_dirfile(search_path, "datafiles", subfolder);
1176                         get_path_user(path, search_path, "BLENDER_USER_DATAFILES");
1177                         break;
1178                 case BLENDER_USER_CONFIG:
1179                         BLI_join_dirfile(search_path, "config", subfolder);
1180                         get_path_user(path, search_path, "BLENDER_USER_CONFIG");
1181                         break;
1182         }
1183         if ('\0' == path[0]) {
1184                 return NULL;
1185         }
1186         return path;
1187 }
1188
1189 char *BLI_get_folder_create(int folder_id, char *subfolder)
1190 {
1191         char *path;
1192
1193         /* only for user folders */
1194         if (!ELEM(folder_id, BLENDER_USER_DATAFILES, BLENDER_USER_CONFIG))
1195                 return NULL;
1196         
1197         path = BLI_get_folder(folder_id, subfolder);
1198         
1199         if (!path) {
1200                 path = BLI_get_user_folder_notest(folder_id, subfolder);
1201                 if (path) BLI_recurdir_fileops(path);
1202         }
1203         
1204         return path;
1205 }
1206
1207
1208 /* End new stuff */
1209 /* ************************************************************* */
1210 /* ************************************************************* */
1211
1212
1213
1214 #ifdef PATH_DEBUG
1215 #undef PATH_DEBUG
1216 #endif
1217
1218 void BLI_setenv(const char *env, const char*val)
1219 {
1220         /* SGI or free windows */
1221 #if (defined(__sgi) || ((defined(WIN32) || defined(WIN64)) && defined(FREE_WINDOWS)))
1222         char *envstr= MEM_mallocN(sizeof(char) * (strlen(env) + strlen(val) + 2), "envstr"); /* one for = another for \0 */
1223
1224         sprintf(envstr, "%s=%s", env, val);
1225         putenv(envstr);
1226         MEM_freeN(envstr);
1227
1228         /* non-free windows */
1229 #elif (defined(WIN32) || defined(WIN64)) /* not free windows */
1230         _putenv_s(env, val);
1231 #else
1232         /* linux/osx/bsd */
1233         setenv(env, val, 1);
1234 #endif
1235 }
1236
1237
1238 /**
1239  Only set an env var if already not there.
1240  Like Unix setenv(env, val, 0);
1241  */
1242 void BLI_setenv_if_new(const char *env, const char* val)
1243 {
1244         if(getenv(env) == NULL)
1245                 BLI_setenv(env, val);
1246 }
1247
1248
1249 void BLI_clean(char *path)
1250 {
1251         if(path==0) return;
1252 #ifdef WIN32
1253         if(path && strlen(path)>2) {
1254                 BLI_char_switch(path+2, '/', '\\');
1255         }
1256 #else
1257         BLI_char_switch(path, '\\', '/');
1258 #endif
1259 }
1260
1261 void BLI_char_switch(char *string, char from, char to) 
1262 {
1263         if(string==0) return;
1264         while (*string != 0) {
1265                 if (*string == from) *string = to;
1266                 string++;
1267         }
1268 }
1269
1270 void BLI_make_exist(char *dir) {
1271         int a;
1272
1273         #ifdef WIN32
1274                 BLI_char_switch(dir, '/', '\\');
1275         #else
1276                 BLI_char_switch(dir, '\\', '/');
1277         #endif  
1278         
1279         a = strlen(dir);
1280         
1281 #ifdef WIN32    
1282         while(BLI_exists(dir) == 0){
1283                 a --;
1284                 while(dir[a] != '\\'){
1285                         a--;
1286                         if (a <= 0) break;
1287                 }
1288                 if (a >= 0) dir[a+1] = 0;
1289                 else {
1290                         /* defaulting to drive (usually 'C:') of Windows installation */
1291                         get_default_root(dir);
1292                         break;
1293                 }
1294         }
1295 #else
1296         while(BLI_exist(dir) == 0){
1297                 a --;
1298                 while(dir[a] != '/'){
1299                         a--;
1300                         if (a <= 0) break;
1301                 }
1302                 if (a >= 0) dir[a+1] = 0;
1303                 else {
1304                         strcpy(dir,"/");
1305                         break;
1306                 }
1307         }
1308 #endif
1309 }
1310
1311 void BLI_make_existing_file(char *name)
1312 {
1313         char di[FILE_MAXDIR+FILE_MAXFILE], fi[FILE_MAXFILE];
1314
1315         strcpy(di, name);
1316         BLI_splitdirstring(di, fi);
1317         
1318         /* test exist */
1319         if (BLI_exists(di) == 0) {
1320                 BLI_recurdir_fileops(di);
1321         }
1322 }
1323
1324
1325 void BLI_make_file_string(const char *relabase, char *string,  const char *dir, const char *file)
1326 {
1327         int sl;
1328
1329         if (!string || !dir || !file) return; /* We don't want any NULLs */
1330         
1331         string[0]= 0; /* ton */
1332
1333         /* we first push all slashes into unix mode, just to make sure we don't get
1334            any mess with slashes later on. -jesterKing */
1335         /* constant strings can be passed for those parameters - don't change them - elubie */
1336         /*
1337         BLI_char_switch(relabase, '\\', '/');
1338         BLI_char_switch(dir, '\\', '/');
1339         BLI_char_switch(file, '\\', '/');
1340         */
1341
1342         /* Resolve relative references */       
1343         if (relabase && dir[0] == '/' && dir[1] == '/') {
1344                 char *lslash;
1345                 
1346                 /* Get the file name, chop everything past the last slash (ie. the filename) */
1347                 strcpy(string, relabase);
1348                 
1349                 lslash= (strrchr(string, '/')>strrchr(string, '\\'))?strrchr(string, '/'):strrchr(string, '\\');
1350                 
1351                 if(lslash) *(lslash+1)= 0;
1352
1353                 dir+=2; /* Skip over the relative reference */
1354         }
1355 #ifdef WIN32
1356         else {
1357                 if (strlen(dir) >= 2 && dir[1] == ':' ) {
1358                         BLI_strncpy(string, dir, 3);
1359                         dir += 2;
1360                 }
1361                 else { /* no drive specified */
1362                         /* first option: get the drive from the relabase if it has one */
1363                         if (relabase && strlen(relabase) >= 2 && relabase[1] == ':' ) {
1364                                 BLI_strncpy(string, relabase, 3);       
1365                                 string[2] = '\\';
1366                                 string[3] = '\0';
1367                         }
1368                         else { /* we're out of luck here, guessing the first valid drive, usually c:\ */
1369                                 get_default_root(string);
1370                         }
1371                         
1372                         /* ignore leading slashes */
1373                         while (*dir == '/' || *dir == '\\') dir++;
1374                 }
1375         }
1376 #endif
1377
1378         strcat(string, dir);
1379
1380         /* Make sure string ends in one (and only one) slash */ 
1381         /* first trim all slashes from the end of the string */
1382         sl = strlen(string);
1383         while (sl>0 && ( string[sl-1] == '/' || string[sl-1] == '\\') ) {
1384                 string[sl-1] = '\0';
1385                 sl--;
1386         }
1387         /* since we've now removed all slashes, put back one slash at the end. */
1388         strcat(string, "/");
1389         
1390         while (*file && (*file == '/' || *file == '\\')) /* Trim slashes from the front of file */
1391                 file++;
1392                 
1393         strcat (string, file);
1394         
1395         /* Push all slashes to the system preferred direction */
1396         BLI_clean(string);
1397 }
1398
1399 int BLI_testextensie(const char *str, const char *ext)
1400 {
1401         short a, b;
1402         int retval;
1403
1404         a= strlen(str);
1405         b= strlen(ext);
1406
1407         if(a==0 || b==0 || b>=a) {
1408                 retval = 0;
1409         } else if (BLI_strcasecmp(ext, str + a - b)) {
1410                 retval = 0;     
1411         } else {
1412                 retval = 1;
1413         }
1414
1415         return (retval);
1416 }
1417
1418 int BLI_replace_extension(char *path, int maxlen, const char *ext)
1419 {
1420         int a;
1421
1422         for(a=strlen(path)-1; a>=0; a--)
1423                 if(path[a] == '.' || path[a] == '/' || path[a] == '\\')
1424                         break;
1425         
1426         if(path[a] != '.')
1427                 a= strlen(path);
1428
1429         if(a + strlen(ext) >= maxlen)
1430                 return 0;
1431
1432         strcpy(path+a, ext);
1433         return 1;
1434 }
1435
1436 /* Converts "/foo/bar.txt" to "/foo/" and "bar.txt"
1437  * - wont change 'string'
1438  * - wont create any directories
1439  * - dosnt use CWD, or deal with relative paths.
1440  * - Only fill's in *dir and *file when they are non NULL
1441  * */
1442 void BLI_split_dirfile(const char *string, char *dir, char *file)
1443 {
1444         char *lslash_str = BLI_last_slash(string);
1445         int lslash= lslash_str ? (int)(lslash_str - string) + 1 : 0;
1446
1447         if (dir) {
1448                 if (lslash) {
1449                         BLI_strncpy( dir, string, lslash + 1); /* +1 to include the slash and the last char */
1450                 } else {
1451                         dir[0] = '\0';
1452                 }
1453         }
1454         
1455         if (file) {
1456                 strcpy( file, string+lslash);
1457         }
1458 }
1459
1460 /* simple appending of filename to dir, does not check for valid path! */
1461 void BLI_join_dirfile(char *string, const char *dir, const char *file)
1462 {
1463         int sl_dir;
1464         
1465         if(string != dir) /* compare pointers */
1466                 BLI_strncpy(string, dir, FILE_MAX);
1467
1468         if (!file)
1469                 return;
1470         
1471         sl_dir= BLI_add_slash(string);
1472         
1473         if (sl_dir <FILE_MAX) {
1474                 BLI_strncpy(string + sl_dir, file, FILE_MAX-sl_dir);
1475         }
1476 }
1477
1478 /* like pythons os.path.basename( ) */
1479 char *BLI_path_basename(char *path)
1480 {
1481         char *filename= BLI_last_slash(path);
1482         return filename ? filename + 1 : path;
1483 }
1484
1485 /*
1486   Produce image export path.
1487
1488   Fails returning 0 if image filename is empty or if destination path
1489   matches image path (i.e. both are the same file).
1490
1491   Trailing slash in dest_dir is optional.
1492
1493   Logic:
1494
1495   - if an image is "below" current .blend file directory, rebuild the
1496         same dir structure in dest_dir
1497
1498   For example //textures/foo/bar.png becomes
1499   [dest_dir]/textures/foo/bar.png.
1500
1501   - if an image is not "below" current .blend file directory,
1502   disregard it's path and copy it in the same directory where 3D file
1503   goes.
1504
1505   For example //../foo/bar.png becomes [dest_dir]/bar.png.
1506
1507   This logic will help ensure that all image paths are relative and
1508   that a user gets his images in one place. It'll also provide
1509   consistent behaviour across exporters.
1510  */
1511 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)
1512 {
1513         char path[FILE_MAX];
1514         char dir[FILE_MAX];
1515         char base[FILE_MAX];
1516         char blend_dir[FILE_MAX];       /* directory, where current .blend file resides */
1517         char dest_path[FILE_MAX];
1518         char rel_dir[FILE_MAX];
1519         int len;
1520
1521         if (abs)
1522                 abs[0]= 0;
1523
1524         if (rel)
1525                 rel[0]= 0;
1526
1527         BLI_split_dirfile(base_dir, blend_dir, NULL);
1528
1529         if (src_dir[0]=='\0')
1530                 return 0;
1531
1532         BLI_strncpy(path, src_dir, sizeof(path));
1533
1534         /* expand "//" in filename and get absolute path */
1535         BLI_path_abs(path, base_dir);
1536
1537         /* get the directory part */
1538         BLI_split_dirfile(path, dir, base);
1539
1540         len= strlen(blend_dir);
1541
1542         rel_dir[0] = 0;
1543
1544         /* if image is "below" current .blend file directory */
1545         if (!strncmp(path, blend_dir, len)) {
1546
1547                 /* if image is _in_ current .blend file directory */
1548                 if (!strcmp(dir, blend_dir)) {
1549                         BLI_join_dirfile(dest_path, dest_dir, base);
1550                 }
1551                 /* "below" */
1552                 else {
1553                         /* rel = image_path_dir - blend_dir */
1554                         BLI_strncpy(rel_dir, dir + len, sizeof(rel_dir));
1555
1556                         BLI_join_dirfile(dest_path, dest_dir, rel_dir);
1557                         BLI_join_dirfile(dest_path, dest_path, base);
1558                 }
1559
1560         }
1561         /* image is out of current directory */
1562         else {
1563                 BLI_join_dirfile(dest_path, dest_dir, base);
1564         }
1565
1566         if (abs)
1567                 BLI_strncpy(abs, dest_path, abs_size);
1568
1569         if (rel) {
1570                 strncat(rel, rel_dir, rel_size);
1571                 strncat(rel, base, rel_size);
1572         }
1573
1574         /* return 2 if src=dest */
1575         if (!strcmp(path, dest_path)) {
1576                 // if (G.f & G_DEBUG) printf("%s and %s are the same file\n", path, dest_path);
1577                 return 2;
1578         }
1579
1580         return 1;
1581 }
1582
1583
1584 static int add_win32_extension(char *name)
1585 {
1586         int retval = 0;
1587         int type;
1588
1589         type = BLI_exist(name);
1590         if ((type == 0) || S_ISDIR(type)) {
1591 #ifdef _WIN32
1592                 char filename[FILE_MAXDIR+FILE_MAXFILE];
1593                 char ext[FILE_MAXDIR+FILE_MAXFILE];
1594                 char *extensions = getenv("PATHEXT");
1595                 if (extensions) {
1596                         char *temp;
1597                         do {
1598                                 strcpy(filename, name);
1599                                 temp = strstr(extensions, ";");
1600                                 if (temp) {
1601                                         strncpy(ext, extensions, temp - extensions);
1602                                         ext[temp - extensions] = 0;
1603                                         extensions = temp + 1;
1604                                         strcat(filename, ext);
1605                                 } else {
1606                                         strcat(filename, extensions);
1607                                 }
1608
1609                                 type = BLI_exist(filename);
1610                                 if (type && (! S_ISDIR(type))) {
1611                                         retval = 1;
1612                                         strcpy(name, filename);
1613                                         break;
1614                                 }
1615                         } while (temp);
1616                 }
1617 #endif
1618         } else {
1619                 retval = 1;
1620         }
1621
1622         return (retval);
1623 }
1624
1625 void BLI_where_am_i(char *fullname, const char *name)
1626 {
1627         char filename[FILE_MAXDIR+FILE_MAXFILE];
1628         char *path = NULL, *temp;
1629         
1630 #ifdef _WIN32
1631         char *separator = ";";
1632         char slash = '\\';
1633 #else
1634         char *separator = ":";
1635         char slash = '/';
1636 #endif
1637
1638         
1639 #ifdef __linux__
1640         /* linux uses binreloc since argv[0] is not relyable, call br_init( NULL ) first */
1641         path = br_find_exe( NULL );
1642         if (path) {
1643                 BLI_strncpy(fullname, path, FILE_MAXDIR+FILE_MAXFILE);
1644                 free(path);
1645                 return;
1646         }
1647 #endif
1648
1649 #ifdef _WIN32
1650         if(GetModuleFileName(0, fullname, FILE_MAXDIR+FILE_MAXFILE)) {
1651                 GetShortPathName(fullname, fullname, FILE_MAXDIR+FILE_MAXFILE);
1652                 return;
1653         }
1654 #endif
1655
1656         /* unix and non linux */
1657         if (name && fullname && strlen(name)) {
1658                 strcpy(fullname, name);
1659                 if (name[0] == '.') {
1660                         // relative path, prepend cwd
1661                         BLI_getwdN(fullname);
1662                         
1663                         // not needed but avoids annoying /./ in name
1664                         if(name && name[0]=='.' && name[1]==slash)
1665                                 BLI_join_dirfile(fullname, fullname, name+2);
1666                         else
1667                                 BLI_join_dirfile(fullname, fullname, name);
1668                         
1669                         add_win32_extension(fullname);
1670                 } else if (BLI_last_slash(name)) {
1671                         // full path
1672                         strcpy(fullname, name);
1673                         add_win32_extension(fullname);
1674                 } else {
1675                         // search for binary in $PATH
1676                         path = getenv("PATH");
1677                         if (path) {
1678                                 do {
1679                                         temp = strstr(path, separator);
1680                                         if (temp) {
1681                                                 strncpy(filename, path, temp - path);
1682                                                 filename[temp - path] = 0;
1683                                                 path = temp + 1;
1684                                         } else {
1685                                                 strncpy(filename, path, sizeof(filename));
1686                                         }
1687                                         BLI_join_dirfile(fullname, fullname, name);
1688                                         if (add_win32_extension(filename)) {
1689                                                 strcpy(fullname, filename);
1690                                                 break;
1691                                         }
1692                                 } while (temp);
1693                         }
1694                 }
1695 #ifndef NDEBUG
1696                 if (strcmp(name, fullname)) {
1697                         printf("guessing '%s' == '%s'\n", name, fullname);
1698                 }
1699 #endif
1700
1701 #ifdef _WIN32
1702                 // in windows change long filename to short filename because
1703                 // win2k doesn't know how to parse a commandline with lots of
1704                 // spaces and double-quotes. There's another solution to this
1705                 // with spawnv(P_WAIT, bprogname, argv) instead of system() but
1706                 // that's even uglier
1707                 GetShortPathName(fullname, fullname, FILE_MAXDIR+FILE_MAXFILE);
1708 #ifndef NDEBUG
1709                 printf("Shortname = '%s'\n", fullname);
1710 #endif
1711 #endif
1712         }
1713 }
1714
1715 void BLI_where_is_temp(char *fullname, int usertemp)
1716 {
1717         fullname[0] = '\0';
1718         
1719         if (usertemp && BLI_exists(U.tempdir)) {
1720                 strcpy(fullname, U.tempdir);
1721         }
1722         
1723         
1724 #ifdef WIN32
1725         if (fullname[0] == '\0') {
1726                 char *tmp = getenv("TEMP"); /* Windows */
1727                 if (tmp && BLI_exists(tmp)) {
1728                         strcpy(fullname, tmp);
1729                 }
1730         }
1731 #else
1732         /* Other OS's - Try TMP and TMPDIR */
1733         if (fullname[0] == '\0') {
1734                 char *tmp = getenv("TMP");
1735                 if (tmp && BLI_exists(tmp)) {
1736                         strcpy(fullname, tmp);
1737                 }
1738         }
1739         
1740         if (fullname[0] == '\0') {
1741                 char *tmp = getenv("TMPDIR");
1742                 if (tmp && BLI_exists(tmp)) {
1743                         strcpy(fullname, tmp);
1744                 }
1745         }
1746 #endif  
1747         
1748         if (fullname[0] == '\0') {
1749                 strcpy(fullname, "/tmp/");
1750         } else {
1751                 /* add a trailing slash if needed */
1752                 BLI_add_slash(fullname);
1753         }
1754 }
1755
1756 char *get_install_dir(void) {
1757         extern char bprogname[];
1758         char *tmpname = BLI_strdup(bprogname);
1759         char *cut;
1760
1761 #ifdef __APPLE__
1762         cut = strstr(tmpname, ".app");
1763         if (cut) cut[0] = 0;
1764 #endif
1765
1766         cut = BLI_last_slash(tmpname);
1767
1768         if (cut) {
1769                 cut[0] = 0;
1770                 return tmpname;
1771         } else {
1772                 MEM_freeN(tmpname);
1773                 return NULL;
1774         }
1775 }
1776
1777 #ifdef WITH_ICONV
1778
1779 void BLI_string_to_utf8(char *original, char *utf_8, const char *code)
1780 {
1781         size_t inbytesleft=strlen(original);
1782         size_t outbytesleft=512;
1783         size_t rv=0;
1784         iconv_t cd;
1785         
1786         if (NULL == code) {
1787                 code = locale_charset();
1788         }
1789         cd=iconv_open("UTF-8", code);
1790
1791         if (cd == (iconv_t)(-1)) {
1792                 printf("iconv_open Error");
1793                 *utf_8='\0';
1794                 return ;
1795         }
1796         rv=iconv(cd, &original, &inbytesleft, &utf_8, &outbytesleft);
1797         if (rv == (size_t) -1) {
1798                 printf("iconv Error\n");
1799                 return ;
1800         }
1801         *utf_8 = '\0';
1802         iconv_close(cd);
1803 }
1804 #endif // WITH_ICONV
1805
1806