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