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