fix for 2 bugs in own recent commits,
[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) {
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\\.blender", ret);
750                         if (BLI_exists(dir)) return dir;
751                 }
752
753                 /* else, check install dir (path containing blender.exe) */
754
755                 BLI_getInstallationDir(dir);
756
757                 if (BLI_exists(dir))
758                 {
759                         strcat(dir,"\\.blender");
760                         if (BLI_exists(dir)) return(dir);
761                 }
762
763                                 
764                 /* add user profile support for WIN 2K / NT.
765                  * This is %APPDATA%, which translates to either
766                  * %USERPROFILE%\Application Data or since Vista
767                  * to %USERPROFILE%\AppData\Roaming
768                  */
769                 hResult = SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT, appdatapath);
770                 
771                 if (hResult == S_OK)
772                 {
773                         if (BLI_exists(appdatapath)) { /* from fop, also below... */
774                                 sprintf(dir, "%s\\Blender Foundation\\Blender", appdatapath);
775                                 BLI_recurdir_fileops(dir);
776                                 if (BLI_exists(dir)) {
777                                         strcat(dir,"\\.blender");
778                                         if(BLI_exists(dir)) return(dir);
779                                 }
780                         }
781                         hResult = SHGetFolderPath(NULL, CSIDL_COMMON_APPDATA, NULL, SHGFP_TYPE_CURRENT, appdatapath);
782                         if (hResult == S_OK)
783                         {
784                                 if (BLI_exists(appdatapath)) 
785                                 { /* from fop, also below... */
786                                         sprintf(dir, "%s\\Blender Foundation\\Blender", appdatapath);
787                                         BLI_recurdir_fileops(dir);
788                                         if (BLI_exists(dir)) {
789                                                 strcat(dir,"\\.blender");
790                                                 if(BLI_exists(dir)) return(dir);
791                                         }
792                                 }
793                         }
794                 }
795                 
796                 return "C:\\Temp";      /* sheesh! bad, bad, bad! (aphex) */
797         #endif
798 }
799
800 /* this function returns the path to a blender folder, if it exists
801  * utility functions for BLI_gethome_folder */
802
803 // #define PATH_DEBUG /* for testing paths that are checked */
804
805 static int test_data_path(char *targetpath, char *path_base, char *path_sep, char *folder_name)
806 {
807         char tmppath[FILE_MAXDIR];
808         
809         if(path_sep)    BLI_join_dirfile(tmppath, path_base, path_sep);
810         else                    BLI_strncpy(tmppath, path_base, sizeof(tmppath));
811         
812         BLI_make_file_string("/", targetpath, tmppath, folder_name);
813         
814         if (BLI_exists(targetpath)) {
815 #ifdef PATH_DEBUG
816                 printf("\tpath found: %s\n", targetpath);
817 #endif
818                 return 1;
819         }
820         else {
821 #ifdef PATH_DEBUG
822                 printf("\tpath missing: %s\n", targetpath);
823 #endif
824                 targetpath[0] = '\0';
825                 return 0;
826         }
827 }
828
829 static int gethome_path_local(char *targetpath, char *folder_name)
830 {
831         extern char bprogname[]; /* argv[0] from creator.c */
832         char bprogdir[FILE_MAXDIR];
833         char cwd[FILE_MAXDIR];
834         char *s;
835         int i;
836         
837 #ifdef PATH_DEBUG
838         printf("gethome_path_local...\n");
839 #endif
840         
841         /* try release/folder_name (binary relative) */
842         /* use argv[0] (bprogname) to get the path to the executable */
843         s = BLI_last_slash(bprogname);
844         i = s - bprogname + 1;
845         BLI_strncpy(bprogdir, bprogname, i);
846
847         /* try release/folder_name (BIN relative) */
848         if(test_data_path(targetpath, bprogdir, "release", folder_name))
849                 return 1;
850
851         /* try release/folder_name (CWD relative) */
852         if(test_data_path(targetpath, BLI_getwdN(cwd), "release", folder_name))
853                 return 1;
854
855         /* try ./.blender/folder_name */
856         if(test_data_path(targetpath, bprogdir, ".blender", folder_name))
857                 return 1;
858         
859         return 0;
860 }
861
862 static int gethome_path_user(char *targetpath, char *folder_name)
863 {
864         char *home_path= BLI_gethome();
865
866 #ifdef PATH_DEBUG
867         printf("gethome_path_user...\n");
868 #endif
869         
870         /* try $HOME/folder_name */
871         return test_data_path(targetpath, home_path, ".blender", folder_name);
872 }
873
874 static int gethome_path_system(char *targetpath, char *folder_name)
875 {
876         extern char blender_path[]; /* unix prefix eg. /usr/share/blender/2.5 creator.c */
877         
878         if(!blender_path[0])
879                 return 0;
880         
881 #ifdef PATH_DEBUG
882         printf("gethome_path_system...\n");
883 #endif
884         
885         /* try $BLENDERPATH/folder_name */
886         return test_data_path(targetpath, blender_path, NULL, folder_name);
887 }
888
889 char *BLI_gethome_folder(char *folder_name, int flag)
890 {
891         static char fulldir[FILE_MAXDIR] = "";
892         
893         /* first check if this is a redistributable bundle */
894         if(flag & BLI_GETHOME_LOCAL) {
895                 if (gethome_path_local(fulldir, folder_name))
896                         return fulldir;
897         }
898
899         /* then check if the OS has blender data files installed in a global location */
900         if(flag & BLI_GETHOME_SYSTEM) {
901                 if (gethome_path_system(fulldir, folder_name))
902                         return fulldir;
903         }
904         
905         /* now check the users home dir for data files */
906         if(flag & BLI_GETHOME_USER) {
907                 if (gethome_path_user(fulldir, folder_name))
908                         return fulldir;
909         }
910         
911         return NULL;
912 }
913
914
915 /* NEW stuff, to be cleaned up when fully migrated */
916 /* ************************************************************* */
917 /* ************************************************************* */
918
919 #define PATH_DEBUG2
920
921 static char *blender_version_decimal(void)
922 {
923         static char version_str[5];
924         sprintf(version_str, "%d.%02d", BLENDER_VERSION/100, BLENDER_VERSION%100);
925         return version_str;
926 }
927
928 static int test_path(char *targetpath, char *path_base, char *path_sep, char *folder_name)
929 {
930         char tmppath[FILE_MAX];
931         
932         if(path_sep)    BLI_join_dirfile(tmppath, path_base, path_sep);
933         else                    BLI_strncpy(tmppath, path_base, sizeof(tmppath));
934         
935         BLI_make_file_string("/", targetpath, tmppath, folder_name);
936         
937         if (BLI_exists(targetpath)) {
938 #ifdef PATH_DEBUG2
939                 printf("\tpath found: %s\n", targetpath);
940 #endif
941                 return 1;
942         }
943         else {
944 #ifdef PATH_DEBUG2
945                 printf("\tpath missing: %s\n", targetpath);
946 #endif
947                 //targetpath[0] = '\0';
948                 return 0;
949         }
950 }
951
952 static int test_env_path(char *path, char *envvar)
953 {
954         char *env = envvar?getenv(envvar):NULL;
955         if (!env) return 0;
956         
957         if (BLI_exists(env)) {
958                 BLI_strncpy(path, env, FILE_MAX);
959                 return 1;
960         } else {
961                 path[0] = '\0';
962                 return 0;
963         }
964 }
965
966 static int get_path_local(char *targetpath, char *folder_name)
967 {
968         extern char bprogname[]; /* argv[0] from creator.c */
969         char bprogdir[FILE_MAX];
970         char cwd[FILE_MAX];
971         char *s;
972         int i;
973         
974 #ifdef PATH_DEBUG2
975         printf("get_path_local...\n");
976 #endif
977         
978         
979         /* use argv[0] (bprogname) to get the path to the executable */
980         s = BLI_last_slash(bprogname);
981         i = s - bprogname + 1;
982         BLI_strncpy(bprogdir, bprogname, i);
983         
984         /* try EXECUTABLE_DIR/folder_name */
985         if(test_path(targetpath, bprogdir, "", folder_name))
986                 return 1;
987         
988         /* try CWD/release/folder_name */
989         if(test_path(targetpath, BLI_getwdN(cwd), "release", folder_name))
990                 return 1;
991         
992         /* try EXECUTABLE_DIR/release/folder_name */
993         if(test_path(targetpath, bprogdir, "release", folder_name))
994                 return 1;
995         
996         /* try EXECUTABLE_DIR/2.5/folder_name - new default directory for local blender installed files */
997         if(test_path(targetpath, bprogdir, blender_version_decimal(), folder_name))
998                 return 1;
999
1000         /* try ./.blender/folder_name -- DEPRECATED, need to update build systems */
1001         if(test_path(targetpath, bprogdir, ".blender", folder_name))
1002                 return 1;
1003
1004         return 0;
1005 }
1006
1007 #ifdef WIN32
1008 static int get_knownfolder_path(char *path, int folder) 
1009 {
1010         static char knownpath[MAXPATHLEN];
1011         HRESULT hResult = SHGetFolderPath(NULL, folder, NULL, SHGFP_TYPE_CURRENT, knownpath);
1012         
1013         if (hResult == S_OK)
1014         {
1015                 if (BLI_exists(knownpath)) { /* from fop, also below... */
1016                         BLI_strncpy(path, knownpath, FILE_MAX);
1017                         return 1;
1018                 }
1019         }
1020         return 0;
1021 }
1022 #endif
1023
1024 #if defined(__APPLE__)
1025 #ifndef WITH_COCOA
1026 const char* BLI_osx_getBasePath(basePathesTypes pathType)
1027 {
1028         return "/tmp/";
1029 }
1030 #endif
1031 #endif
1032
1033 static int get_path_user(char *targetpath, char *folder_name, char *envvar)
1034 {
1035         char user_path[FILE_MAX];
1036 #if defined(WIN32)
1037         char appdata[FILE_MAX];
1038 #endif
1039
1040         user_path[0] = '\0';
1041
1042         if (test_env_path(targetpath, envvar))
1043                 return 1;
1044
1045 #if defined(__APPLE__)
1046         BLI_snprintf(user_path, FILE_MAX, "%s/%s", BLI_osx_getBasePath(BasePath_BlenderUser), blender_version_decimal());
1047 #elif defined(WIN32)
1048         if (get_knownfolder_path(appdata, CSIDL_APPDATA)) {     
1049                 BLI_snprintf(user_path, FILE_MAX, "%s\\Blender Foundation\\Blender\\%s", appdata, blender_version_decimal());
1050         }
1051 #else /* UNIX */
1052         /* XXX example below - replace with OS API */
1053         BLI_snprintf(user_path, FILE_MAX, "%s/.blender/%s", BLI_gethome(), blender_version_decimal());
1054 #endif
1055
1056         if(!user_path[0])
1057                 return 0;
1058         
1059 #ifdef PATH_DEBUG2
1060         printf("get_path_user: %s\n", user_path);
1061 #endif
1062         
1063         /* try $HOME/folder_name */
1064         return test_path(targetpath, user_path, NULL, folder_name);
1065 }
1066
1067 static int get_path_system(char *targetpath, char *folder_name, char *envvar)
1068 {
1069         char system_path[FILE_MAX];
1070 #if defined(WIN32)
1071         char appdata[FILE_MAX];
1072 #endif
1073
1074         if (test_env_path(targetpath, envvar))
1075                 return 1;
1076         
1077 #if defined(__APPLE__)
1078         BLI_snprintf(system_path, FILE_MAX, "%s/%s", BLI_osx_getBasePath(BasePath_ApplicationBundle), blender_version_decimal());
1079 #elif defined(WIN32)
1080         if (get_knownfolder_path(appdata, CSIDL_COMMON_APPDATA)) {      
1081                 BLI_snprintf(system_path, FILE_MAX, "%s\\Blender Foundation\\Blender\\%s", appdata, blender_version_decimal());
1082         }
1083 #else /* UNIX */
1084         /* XXX example below - replace with OS API */
1085         BLI_snprintf(system_path, FILE_MAX, "/usr/share/blender/%s", blender_version_decimal());
1086 #endif
1087         
1088         if(!system_path[0])
1089                 return 0;
1090         
1091 #ifdef PATH_DEBUG2
1092         printf("get_path_system: %s\n", system_path);
1093 #endif
1094         
1095         /* try $BLENDERPATH/folder_name */
1096         return test_path(targetpath, system_path, NULL, folder_name);
1097 }
1098
1099 /* get a folder out of the 'folder_id' presets for paths */
1100 /* returns the path if found, NULL string if not */
1101 char *BLI_get_folder(int folder_id, char *subfolder)
1102 {
1103         static char path[FILE_MAX] = "";
1104         char search_path[FILE_MAX];
1105         
1106         switch (folder_id) {
1107                 case BLENDER_DATAFILES:         /* general case */
1108                         BLI_join_dirfile(search_path, "datafiles", subfolder);
1109                         if (get_path_user(path, search_path, "BLENDER_USER_DATAFILES")) break;
1110                         if (get_path_local(path, search_path)) break;
1111                         if (get_path_system(path, search_path, "BLENDER_SYSTEM_DATAFILES")) break;
1112                         return NULL;
1113                         
1114                 case BLENDER_USER_DATAFILES:            
1115                         BLI_join_dirfile(search_path, "datafiles", subfolder);
1116                         if (get_path_user(path, search_path, "BLENDER_USER_DATAFILES")) break;
1117                         return NULL;
1118                         
1119                 case BLENDER_SYSTEM_DATAFILES:
1120                         BLI_join_dirfile(search_path, "datafiles", subfolder);
1121                         if (get_path_system(path, search_path, "BLENDER_SYSTEM_DATAFILES"))     break;
1122                         return NULL;
1123                         
1124                 case BLENDER_CONFIG:            /* general case */
1125                         BLI_join_dirfile(search_path, "config", subfolder);
1126                         if (get_path_user(path, search_path, "BLENDER_USER_CONFIG")) break;
1127                         if (get_path_local(path, search_path)) break;
1128                         if (get_path_system(path, search_path, "BLENDER_SYSTEM_CONFIG")) break;
1129                         return NULL;
1130                         
1131                 case BLENDER_USER_CONFIG:
1132                         BLI_join_dirfile(search_path, "config", subfolder);
1133                         if (get_path_user(path, search_path, "BLENDER_USER_CONFIG")) break;
1134                         return NULL;
1135                         
1136                 case BLENDER_SYSTEM_CONFIG:
1137                         BLI_join_dirfile(search_path, "config", subfolder);
1138                         if (get_path_system(path, search_path, "BLENDER_SYSTEM_CONFIG")) break;
1139                         return NULL;
1140                         
1141                 case BLENDER_SCRIPTS:           /* general case */
1142                         BLI_join_dirfile(search_path, "scripts", subfolder);
1143                         if (get_path_user(path, search_path, "BLENDER_USER_SCRIPTS")) break;            
1144                         if (get_path_local(path, search_path)) break;
1145                         if (get_path_system(path, search_path, "BLENDER_SYSTEM_SCRIPTS")) break;
1146                         return NULL;
1147                         
1148                 case BLENDER_USER_SCRIPTS:
1149                         BLI_join_dirfile(search_path, "scripts", subfolder);
1150                         if (get_path_user(path, search_path, "BLENDER_USER_SCRIPTS")) break;
1151                         return NULL;
1152                         
1153                 case BLENDER_SYSTEM_SCRIPTS:
1154                         BLI_join_dirfile(search_path, "scripts", subfolder);
1155                         if (get_path_system(path, search_path, "BLENDER_SYSTEM_SCRIPTS")) break;
1156                         return NULL;
1157                         
1158                 case BLENDER_PYTHON:            /* general case */
1159                         BLI_join_dirfile(search_path, "python", subfolder);
1160                         if (get_path_local(path, search_path)) break;
1161                         if (get_path_system(path, search_path, "BLENDER_SYSTEM_PYTHON")) break;
1162                         return NULL;
1163                         
1164                 case BLENDER_SYSTEM_PYTHON:
1165                         BLI_join_dirfile(search_path, "python", subfolder);
1166                         
1167                         if (get_path_system(path, search_path, "BLENDER_SYSTEM_PYTHON")) break;
1168                         return NULL;
1169         }
1170         
1171         return path;
1172 }
1173
1174 static char *BLI_get_user_folder_notest(int folder_id, char *subfolder)
1175 {
1176         static char path[FILE_MAX] = "";
1177         char search_path[FILE_MAX];
1178
1179         switch (folder_id) {
1180                 case BLENDER_USER_DATAFILES:
1181                         BLI_join_dirfile(search_path, "datafiles", subfolder);
1182                         get_path_user(path, search_path, "BLENDER_USER_DATAFILES");
1183                         break;
1184                 case BLENDER_USER_CONFIG:
1185                         BLI_join_dirfile(search_path, "config", subfolder);
1186                         get_path_user(path, search_path, "BLENDER_USER_CONFIG");
1187                         break;
1188         }
1189         if ('\0' == path[0]) {
1190                 return NULL;
1191         }
1192         return path;
1193 }
1194
1195 char *BLI_get_folder_create(int folder_id, char *subfolder)
1196 {
1197         char *path;
1198
1199         /* only for user folders */
1200         if (!ELEM(folder_id, BLENDER_USER_DATAFILES, BLENDER_USER_CONFIG))
1201                 return NULL;
1202         
1203         path = BLI_get_folder(folder_id, subfolder);
1204         
1205         if (!path) {
1206                 path = BLI_get_user_folder_notest(folder_id, subfolder);
1207                 if (path) BLI_recurdir_fileops(path);
1208         }
1209         
1210         return path;
1211 }
1212
1213
1214 /* End new stuff */
1215 /* ************************************************************* */
1216 /* ************************************************************* */
1217
1218
1219
1220 #ifdef PATH_DEBUG
1221 #undef PATH_DEBUG
1222 #endif
1223
1224 void BLI_setenv(const char *env, const char*val)
1225 {
1226         /* SGI or free windows */
1227 #if (defined(__sgi) || ((defined(WIN32) || defined(WIN64)) && defined(FREE_WINDOWS)))
1228         char *envstr= MEM_mallocN(sizeof(char) * (strlen(env) + strlen(val) + 2), "envstr"); /* one for = another for \0 */
1229
1230         sprintf(envstr, "%s=%s", env, val);
1231         putenv(envstr);
1232         MEM_freeN(envstr);
1233
1234         /* non-free windows */
1235 #elif (defined(WIN32) || defined(WIN64)) /* not free windows */
1236         _putenv_s(env, val);
1237 #else
1238         /* linux/osx/bsd */
1239         setenv(env, val, 1);
1240 #endif
1241 }
1242
1243
1244 /**
1245  Only set an env var if already not there.
1246  Like Unix setenv(env, val, 0);
1247  */
1248 void BLI_setenv_if_new(const char *env, const char* val)
1249 {
1250         if(getenv(env) == NULL)
1251                 BLI_setenv(env, val);
1252 }
1253
1254
1255 void BLI_clean(char *path)
1256 {
1257         if(path==0) return;
1258 #ifdef WIN32
1259         if(path && strlen(path)>2) {
1260                 BLI_char_switch(path+2, '/', '\\');
1261         }
1262 #else
1263         BLI_char_switch(path, '\\', '/');
1264 #endif
1265 }
1266
1267 void BLI_char_switch(char *string, char from, char to) 
1268 {
1269         if(string==0) return;
1270         while (*string != 0) {
1271                 if (*string == from) *string = to;
1272                 string++;
1273         }
1274 }
1275
1276 void BLI_make_exist(char *dir) {
1277         int a;
1278
1279         #ifdef WIN32
1280                 BLI_char_switch(dir, '/', '\\');
1281         #else
1282                 BLI_char_switch(dir, '\\', '/');
1283         #endif  
1284         
1285         a = strlen(dir);
1286         
1287 #ifdef WIN32    
1288         while(BLI_exists(dir) == 0){
1289                 a --;
1290                 while(dir[a] != '\\'){
1291                         a--;
1292                         if (a <= 0) break;
1293                 }
1294                 if (a >= 0) dir[a+1] = 0;
1295                 else {
1296                         /* defaulting to drive (usually 'C:') of Windows installation */
1297                         get_default_root(dir);
1298                         break;
1299                 }
1300         }
1301 #else
1302         while(BLI_exist(dir) == 0){
1303                 a --;
1304                 while(dir[a] != '/'){
1305                         a--;
1306                         if (a <= 0) break;
1307                 }
1308                 if (a >= 0) dir[a+1] = 0;
1309                 else {
1310                         strcpy(dir,"/");
1311                         break;
1312                 }
1313         }
1314 #endif
1315 }
1316
1317 void BLI_make_existing_file(char *name)
1318 {
1319         char di[FILE_MAXDIR+FILE_MAXFILE], fi[FILE_MAXFILE];
1320
1321         strcpy(di, name);
1322         BLI_splitdirstring(di, fi);
1323         
1324         /* test exist */
1325         if (BLI_exists(di) == 0) {
1326                 BLI_recurdir_fileops(di);
1327         }
1328 }
1329
1330
1331 void BLI_make_file_string(const char *relabase, char *string,  const char *dir, const char *file)
1332 {
1333         int sl;
1334
1335         if (!string || !dir || !file) return; /* We don't want any NULLs */
1336         
1337         string[0]= 0; /* ton */
1338
1339         /* we first push all slashes into unix mode, just to make sure we don't get
1340            any mess with slashes later on. -jesterKing */
1341         /* constant strings can be passed for those parameters - don't change them - elubie */
1342         /*
1343         BLI_char_switch(relabase, '\\', '/');
1344         BLI_char_switch(dir, '\\', '/');
1345         BLI_char_switch(file, '\\', '/');
1346         */
1347
1348         /* Resolve relative references */       
1349         if (relabase && dir[0] == '/' && dir[1] == '/') {
1350                 char *lslash;
1351                 
1352                 /* Get the file name, chop everything past the last slash (ie. the filename) */
1353                 strcpy(string, relabase);
1354                 
1355                 lslash= (strrchr(string, '/')>strrchr(string, '\\'))?strrchr(string, '/'):strrchr(string, '\\');
1356                 
1357                 if(lslash) *(lslash+1)= 0;
1358
1359                 dir+=2; /* Skip over the relative reference */
1360         }
1361 #ifdef WIN32
1362         else {
1363                 if (strlen(dir) >= 2 && dir[1] == ':' ) {
1364                         BLI_strncpy(string, dir, 3);
1365                         dir += 2;
1366                 }
1367                 else { /* no drive specified */
1368                         /* first option: get the drive from the relabase if it has one */
1369                         if (relabase && strlen(relabase) >= 2 && relabase[1] == ':' ) {
1370                                 BLI_strncpy(string, relabase, 3);       
1371                                 string[2] = '\\';
1372                                 string[3] = '\0';
1373                         }
1374                         else { /* we're out of luck here, guessing the first valid drive, usually c:\ */
1375                                 get_default_root(string);
1376                         }
1377                         
1378                         /* ignore leading slashes */
1379                         while (*dir == '/' || *dir == '\\') dir++;
1380                 }
1381         }
1382 #endif
1383
1384         strcat(string, dir);
1385
1386         /* Make sure string ends in one (and only one) slash */ 
1387         /* first trim all slashes from the end of the string */
1388         sl = strlen(string);
1389         while (sl>0 && ( string[sl-1] == '/' || string[sl-1] == '\\') ) {
1390                 string[sl-1] = '\0';
1391                 sl--;
1392         }
1393         /* since we've now removed all slashes, put back one slash at the end. */
1394         strcat(string, "/");
1395         
1396         while (*file && (*file == '/' || *file == '\\')) /* Trim slashes from the front of file */
1397                 file++;
1398                 
1399         strcat (string, file);
1400         
1401         /* Push all slashes to the system preferred direction */
1402         BLI_clean(string);
1403 }
1404
1405 int BLI_testextensie(const char *str, const char *ext)
1406 {
1407         short a, b;
1408         int retval;
1409
1410         a= strlen(str);
1411         b= strlen(ext);
1412
1413         if(a==0 || b==0 || b>=a) {
1414                 retval = 0;
1415         } else if (BLI_strcasecmp(ext, str + a - b)) {
1416                 retval = 0;     
1417         } else {
1418                 retval = 1;
1419         }
1420
1421         return (retval);
1422 }
1423
1424 int BLI_replace_extension(char *path, int maxlen, const char *ext)
1425 {
1426         int a;
1427
1428         for(a=strlen(path)-1; a>=0; a--)
1429                 if(path[a] == '.' || path[a] == '/' || path[a] == '\\')
1430                         break;
1431         
1432         if(path[a] != '.')
1433                 a= strlen(path);
1434
1435         if(a + strlen(ext) >= maxlen)
1436                 return 0;
1437
1438         strcpy(path+a, ext);
1439         return 1;
1440 }
1441
1442 /* Converts "/foo/bar.txt" to "/foo/" and "bar.txt"
1443  * - wont change 'string'
1444  * - wont create any directories
1445  * - dosnt use CWD, or deal with relative paths.
1446  * - Only fill's in *dir and *file when they are non NULL
1447  * */
1448 void BLI_split_dirfile(const char *string, char *dir, char *file)
1449 {
1450         char *lslash_str = BLI_last_slash(string);
1451         int lslash= lslash_str ? (int)(lslash_str - string) + 1 : 0;
1452
1453         if (dir) {
1454                 if (lslash) {
1455                         BLI_strncpy( dir, string, lslash + 1); /* +1 to include the slash and the last char */
1456                 } else {
1457                         dir[0] = '\0';
1458                 }
1459         }
1460         
1461         if (file) {
1462                 strcpy( file, string+lslash);
1463         }
1464 }
1465
1466 /* simple appending of filename to dir, does not check for valid path! */
1467 void BLI_join_dirfile(char *string, const char *dir, const char *file)
1468 {
1469         int sl_dir;
1470         
1471         if(string != dir) /* compare pointers */
1472                 BLI_strncpy(string, dir, FILE_MAX);
1473
1474         if (!file)
1475                 return;
1476         
1477         sl_dir= BLI_add_slash(string);
1478         
1479         if (sl_dir <FILE_MAX) {
1480                 BLI_strncpy(string + sl_dir, file, FILE_MAX-sl_dir);
1481         }
1482 }
1483
1484 /* like pythons os.path.basename( ) */
1485 char *BLI_path_basename(char *path)
1486 {
1487         char *filename= BLI_last_slash(path);
1488         return filename ? filename + 1 : path;
1489 }
1490
1491 /*
1492   Produce image export path.
1493
1494   Fails returning 0 if image filename is empty or if destination path
1495   matches image path (i.e. both are the same file).
1496
1497   Trailing slash in dest_dir is optional.
1498
1499   Logic:
1500
1501   - if an image is "below" current .blend file directory, rebuild the
1502         same dir structure in dest_dir
1503
1504   For example //textures/foo/bar.png becomes
1505   [dest_dir]/textures/foo/bar.png.
1506
1507   - if an image is not "below" current .blend file directory,
1508   disregard it's path and copy it in the same directory where 3D file
1509   goes.
1510
1511   For example //../foo/bar.png becomes [dest_dir]/bar.png.
1512
1513   This logic will help ensure that all image paths are relative and
1514   that a user gets his images in one place. It'll also provide
1515   consistent behaviour across exporters.
1516  */
1517 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)
1518 {
1519         char path[FILE_MAX];
1520         char dir[FILE_MAX];
1521         char base[FILE_MAX];
1522         char blend_dir[FILE_MAX];       /* directory, where current .blend file resides */
1523         char dest_path[FILE_MAX];
1524         char rel_dir[FILE_MAX];
1525         int len;
1526
1527         if (abs)
1528                 abs[0]= 0;
1529
1530         if (rel)
1531                 rel[0]= 0;
1532
1533         BLI_split_dirfile(base_dir, blend_dir, NULL);
1534
1535         if (src_dir[0]=='\0')
1536                 return 0;
1537
1538         BLI_strncpy(path, src_dir, sizeof(path));
1539
1540         /* expand "//" in filename and get absolute path */
1541         BLI_path_abs(path, base_dir);
1542
1543         /* get the directory part */
1544         BLI_split_dirfile(path, dir, base);
1545
1546         len= strlen(blend_dir);
1547
1548         rel_dir[0] = 0;
1549
1550         /* if image is "below" current .blend file directory */
1551         if (!strncmp(path, blend_dir, len)) {
1552
1553                 /* if image is _in_ current .blend file directory */
1554                 if (!strcmp(dir, blend_dir)) {
1555                         BLI_join_dirfile(dest_path, dest_dir, base);
1556                 }
1557                 /* "below" */
1558                 else {
1559                         /* rel = image_path_dir - blend_dir */
1560                         BLI_strncpy(rel_dir, dir + len, sizeof(rel_dir));
1561
1562                         BLI_join_dirfile(dest_path, dest_dir, rel_dir);
1563                         BLI_join_dirfile(dest_path, dest_path, base);
1564                 }
1565
1566         }
1567         /* image is out of current directory */
1568         else {
1569                 BLI_join_dirfile(dest_path, dest_dir, base);
1570         }
1571
1572         if (abs)
1573                 BLI_strncpy(abs, dest_path, abs_size);
1574
1575         if (rel) {
1576                 strncat(rel, rel_dir, rel_size);
1577                 strncat(rel, base, rel_size);
1578         }
1579
1580         /* return 2 if src=dest */
1581         if (!strcmp(path, dest_path)) {
1582                 // if (G.f & G_DEBUG) printf("%s and %s are the same file\n", path, dest_path);
1583                 return 2;
1584         }
1585
1586         return 1;
1587 }
1588
1589
1590 static int add_win32_extension(char *name)
1591 {
1592         int retval = 0;
1593         int type;
1594
1595         type = BLI_exist(name);
1596         if ((type == 0) || S_ISDIR(type)) {
1597 #ifdef _WIN32
1598                 char filename[FILE_MAXDIR+FILE_MAXFILE];
1599                 char ext[FILE_MAXDIR+FILE_MAXFILE];
1600                 char *extensions = getenv("PATHEXT");
1601                 if (extensions) {
1602                         char *temp;
1603                         do {
1604                                 strcpy(filename, name);
1605                                 temp = strstr(extensions, ";");
1606                                 if (temp) {
1607                                         strncpy(ext, extensions, temp - extensions);
1608                                         ext[temp - extensions] = 0;
1609                                         extensions = temp + 1;
1610                                         strcat(filename, ext);
1611                                 } else {
1612                                         strcat(filename, extensions);
1613                                 }
1614
1615                                 type = BLI_exist(filename);
1616                                 if (type && (! S_ISDIR(type))) {
1617                                         retval = 1;
1618                                         strcpy(name, filename);
1619                                         break;
1620                                 }
1621                         } while (temp);
1622                 }
1623 #endif
1624         } else {
1625                 retval = 1;
1626         }
1627
1628         return (retval);
1629 }
1630
1631 void BLI_where_am_i(char *fullname, const char *name)
1632 {
1633         char filename[FILE_MAXDIR+FILE_MAXFILE];
1634         char *path = NULL, *temp;
1635         
1636 #ifdef _WIN32
1637         char *separator = ";";
1638         char slash = '\\';
1639 #else
1640         char *separator = ":";
1641         char slash = '/';
1642 #endif
1643
1644         
1645 #ifdef __linux__
1646         /* linux uses binreloc since argv[0] is not relyable, call br_init( NULL ) first */
1647         path = br_find_exe( NULL );
1648         if (path) {
1649                 BLI_strncpy(fullname, path, FILE_MAXDIR+FILE_MAXFILE);
1650                 free(path);
1651                 return;
1652         }
1653 #endif
1654
1655 #ifdef _WIN32
1656         if(GetModuleFileName(0, fullname, FILE_MAXDIR+FILE_MAXFILE)) {
1657                 GetShortPathName(fullname, fullname, FILE_MAXDIR+FILE_MAXFILE);
1658                 return;
1659         }
1660 #endif
1661
1662         /* unix and non linux */
1663         if (name && fullname && strlen(name)) {
1664                 strcpy(fullname, name);
1665                 if (name[0] == '.') {
1666                         // relative path, prepend cwd
1667                         BLI_getwdN(fullname);
1668                         
1669                         // not needed but avoids annoying /./ in name
1670                         if(name && name[0]=='.' && name[1]==slash)
1671                                 BLI_join_dirfile(fullname, fullname, name+2);
1672                         else
1673                                 BLI_join_dirfile(fullname, fullname, name);
1674                         
1675                         add_win32_extension(fullname);
1676                 } else if (BLI_last_slash(name)) {
1677                         // full path
1678                         strcpy(fullname, name);
1679                         add_win32_extension(fullname);
1680                 } else {
1681                         // search for binary in $PATH
1682                         path = getenv("PATH");
1683                         if (path) {
1684                                 do {
1685                                         temp = strstr(path, separator);
1686                                         if (temp) {
1687                                                 strncpy(filename, path, temp - path);
1688                                                 filename[temp - path] = 0;
1689                                                 path = temp + 1;
1690                                         } else {
1691                                                 strncpy(filename, path, sizeof(filename));
1692                                         }
1693                                         BLI_join_dirfile(fullname, fullname, name);
1694                                         if (add_win32_extension(filename)) {
1695                                                 strcpy(fullname, filename);
1696                                                 break;
1697                                         }
1698                                 } while (temp);
1699                         }
1700                 }
1701 #ifndef NDEBUG
1702                 if (strcmp(name, fullname)) {
1703                         printf("guessing '%s' == '%s'\n", name, fullname);
1704                 }
1705 #endif
1706
1707 #ifdef _WIN32
1708                 // in windows change long filename to short filename because
1709                 // win2k doesn't know how to parse a commandline with lots of
1710                 // spaces and double-quotes. There's another solution to this
1711                 // with spawnv(P_WAIT, bprogname, argv) instead of system() but
1712                 // that's even uglier
1713                 GetShortPathName(fullname, fullname, FILE_MAXDIR+FILE_MAXFILE);
1714 #ifndef NDEBUG
1715                 printf("Shortname = '%s'\n", fullname);
1716 #endif
1717 #endif
1718         }
1719 }
1720
1721 void BLI_where_is_temp(char *fullname, int usertemp)
1722 {
1723         fullname[0] = '\0';
1724         
1725         if (usertemp && BLI_exists(U.tempdir)) {
1726                 strcpy(fullname, U.tempdir);
1727         }
1728         
1729         
1730 #ifdef WIN32
1731         if (fullname[0] == '\0') {
1732                 char *tmp = getenv("TEMP"); /* Windows */
1733                 if (tmp && BLI_exists(tmp)) {
1734                         strcpy(fullname, tmp);
1735                 }
1736         }
1737 #else
1738         /* Other OS's - Try TMP and TMPDIR */
1739         if (fullname[0] == '\0') {
1740                 char *tmp = getenv("TMP");
1741                 if (tmp && BLI_exists(tmp)) {
1742                         strcpy(fullname, tmp);
1743                 }
1744         }
1745         
1746         if (fullname[0] == '\0') {
1747                 char *tmp = getenv("TMPDIR");
1748                 if (tmp && BLI_exists(tmp)) {
1749                         strcpy(fullname, tmp);
1750                 }
1751         }
1752 #endif  
1753         
1754         if (fullname[0] == '\0') {
1755                 strcpy(fullname, "/tmp/");
1756         } else {
1757                 /* add a trailing slash if needed */
1758                 BLI_add_slash(fullname);
1759         }
1760 }
1761
1762 char *get_install_dir(void) {
1763         extern char bprogname[];
1764         char *tmpname = BLI_strdup(bprogname);
1765         char *cut;
1766
1767 #ifdef __APPLE__
1768         cut = strstr(tmpname, ".app");
1769         if (cut) cut[0] = 0;
1770 #endif
1771
1772         cut = BLI_last_slash(tmpname);
1773
1774         if (cut) {
1775                 cut[0] = 0;
1776                 return tmpname;
1777         } else {
1778                 MEM_freeN(tmpname);
1779                 return NULL;
1780         }
1781 }
1782
1783 #ifdef WITH_ICONV
1784
1785 void BLI_string_to_utf8(char *original, char *utf_8, const char *code)
1786 {
1787         size_t inbytesleft=strlen(original);
1788         size_t outbytesleft=512;
1789         size_t rv=0;
1790         iconv_t cd;
1791         
1792         if (NULL == code) {
1793                 code = locale_charset();
1794         }
1795         cd=iconv_open("UTF-8", code);
1796
1797         if (cd == (iconv_t)(-1)) {
1798                 printf("iconv_open Error");
1799                 *utf_8='\0';
1800                 return ;
1801         }
1802         rv=iconv(cd, &original, &inbytesleft, &utf_8, &outbytesleft);
1803         if (rv == (size_t) -1) {
1804                 printf("iconv Error\n");
1805                 return ;
1806         }
1807         *utf_8 = '\0';
1808         iconv_close(cd);
1809 }
1810 #endif // WITH_ICONV
1811
1812