correct typo's
[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 /* Converts "/foo/bar.txt" to "/foo/" and "bar.txt"
1113  * - wont change 'string'
1114  * - wont create any directories
1115  * - dosnt use CWD, or deal with relative paths.
1116  * - Only fill's in *dir and *file when they are non NULL
1117  * */
1118 void BLI_split_dirfile(const char *string, char *dir, char *file)
1119 {
1120         char *lslash_str = BLI_last_slash(string);
1121         int lslash= lslash_str ? (int)(lslash_str - string) + 1 : 0;
1122
1123         if (dir) {
1124                 if (lslash) {
1125                         BLI_strncpy( dir, string, lslash + 1); /* +1 to include the slash and the last char */
1126                 } else {
1127                         dir[0] = '\0';
1128                 }
1129         }
1130         
1131         if (file) {
1132                 strcpy( file, string+lslash);
1133         }
1134 }
1135
1136 /* simple appending of filename to dir, does not check for valid path! */
1137 void BLI_join_dirfile(char *string, const char *dir, const char *file)
1138 {
1139         int sl_dir;
1140         
1141         if(string != dir) /* compare pointers */
1142                 BLI_strncpy(string, dir, FILE_MAX);
1143         
1144         sl_dir= BLI_add_slash(string);
1145         
1146         if (sl_dir <FILE_MAX) {
1147                 BLI_strncpy(string + sl_dir, file, FILE_MAX-sl_dir);
1148         }
1149 }
1150
1151
1152 /*
1153   Produce image export path.
1154
1155   Fails returning 0 if image filename is empty or if destination path
1156   matches image path (i.e. both are the same file).
1157
1158   Trailing slash in dest_dir is optional.
1159
1160   Logic:
1161
1162   - if an image is "below" current .blend file directory, rebuild the
1163         same dir structure in dest_dir
1164
1165   For example //textures/foo/bar.png becomes
1166   [dest_dir]/textures/foo/bar.png.
1167
1168   - if an image is not "below" current .blend file directory,
1169   disregard it's path and copy it in the same directory where 3D file
1170   goes.
1171
1172   For example //../foo/bar.png becomes [dest_dir]/bar.png.
1173
1174   This logic will help ensure that all image paths are relative and
1175   that a user gets his images in one place. It'll also provide
1176   consistent behaviour across exporters.
1177  */
1178 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)
1179 {
1180         char path[FILE_MAX];
1181         char dir[FILE_MAX];
1182         char base[FILE_MAX];
1183         char blend_dir[FILE_MAX];       /* directory, where current .blend file resides */
1184         char dest_path[FILE_MAX];
1185         char rel_dir[FILE_MAX];
1186         int len;
1187
1188         if (abs)
1189                 abs[0]= 0;
1190
1191         if (rel)
1192                 rel[0]= 0;
1193
1194         BLI_split_dirfile(base_dir, blend_dir, NULL);
1195
1196         if (src_dir[0]=='\0')
1197                 return 0;
1198
1199         BLI_strncpy(path, src_dir, sizeof(path));
1200
1201         /* expand "//" in filename and get absolute path */
1202         BLI_path_abs(path, base_dir);
1203
1204         /* get the directory part */
1205         BLI_split_dirfile(path, dir, base);
1206
1207         len= strlen(blend_dir);
1208
1209         rel_dir[0] = 0;
1210
1211         /* if image is "below" current .blend file directory */
1212         if (!strncmp(path, blend_dir, len)) {
1213
1214                 /* if image is _in_ current .blend file directory */
1215                 if (!strcmp(dir, blend_dir)) {
1216                         BLI_join_dirfile(dest_path, dest_dir, base);
1217                 }
1218                 /* "below" */
1219                 else {
1220                         /* rel = image_path_dir - blend_dir */
1221                         BLI_strncpy(rel_dir, dir + len, sizeof(rel_dir));
1222
1223                         BLI_join_dirfile(dest_path, dest_dir, rel_dir);
1224                         BLI_join_dirfile(dest_path, dest_path, base);
1225                 }
1226
1227         }
1228         /* image is out of current directory */
1229         else {
1230                 BLI_join_dirfile(dest_path, dest_dir, base);
1231         }
1232
1233         if (abs)
1234                 BLI_strncpy(abs, dest_path, abs_size);
1235
1236         if (rel) {
1237                 strncat(rel, rel_dir, rel_size);
1238                 strncat(rel, base, rel_size);
1239         }
1240
1241         /* return 2 if src=dest */
1242         if (!strcmp(path, dest_path)) {
1243                 // if (G.f & G_DEBUG) printf("%s and %s are the same file\n", path, dest_path);
1244                 return 2;
1245         }
1246
1247         return 1;
1248 }
1249
1250
1251 static int add_win32_extension(char *name)
1252 {
1253         int retval = 0;
1254         int type;
1255
1256         type = BLI_exist(name);
1257         if ((type == 0) || S_ISDIR(type)) {
1258 #ifdef _WIN32
1259                 char filename[FILE_MAXDIR+FILE_MAXFILE];
1260                 char ext[FILE_MAXDIR+FILE_MAXFILE];
1261                 char *extensions = getenv("PATHEXT");
1262                 if (extensions) {
1263                         char *temp;
1264                         do {
1265                                 strcpy(filename, name);
1266                                 temp = strstr(extensions, ";");
1267                                 if (temp) {
1268                                         strncpy(ext, extensions, temp - extensions);
1269                                         ext[temp - extensions] = 0;
1270                                         extensions = temp + 1;
1271                                         strcat(filename, ext);
1272                                 } else {
1273                                         strcat(filename, extensions);
1274                                 }
1275
1276                                 type = BLI_exist(filename);
1277                                 if (type && (! S_ISDIR(type))) {
1278                                         retval = 1;
1279                                         strcpy(name, filename);
1280                                         break;
1281                                 }
1282                         } while (temp);
1283                 }
1284 #endif
1285         } else {
1286                 retval = 1;
1287         }
1288
1289         return (retval);
1290 }
1291
1292 void BLI_where_am_i(char *fullname, const char *name)
1293 {
1294         char filename[FILE_MAXDIR+FILE_MAXFILE];
1295         char *path = NULL, *temp;
1296         
1297 #ifdef _WIN32
1298         char *separator = ";";
1299         char slash = '\\';
1300 #else
1301         char *separator = ":";
1302         char slash = '/';
1303 #endif
1304
1305         
1306 #ifdef __linux__
1307         /* linux uses binreloc since argv[0] is not relyable, call br_init( NULL ) first */
1308         path = br_find_exe( NULL );
1309         if (path) {
1310                 BLI_strncpy(fullname, path, FILE_MAXDIR+FILE_MAXFILE);
1311                 free(path);
1312                 return;
1313         }
1314 #endif
1315
1316 #ifdef _WIN32
1317         if(GetModuleFileName(0, fullname, FILE_MAXDIR+FILE_MAXFILE)) {
1318                 GetShortPathName(fullname, fullname, FILE_MAXDIR+FILE_MAXFILE);
1319                 return;
1320         }
1321 #endif
1322
1323         /* unix and non linux */
1324         if (name && fullname && strlen(name)) {
1325                 strcpy(fullname, name);
1326                 if (name[0] == '.') {
1327                         // relative path, prepend cwd
1328                         BLI_getwdN(fullname);
1329                         
1330                         // not needed but avoids annoying /./ in name
1331                         if(name && name[0]=='.' && name[1]==slash)
1332                                 BLI_join_dirfile(fullname, fullname, name+2);
1333                         else
1334                                 BLI_join_dirfile(fullname, fullname, name);
1335                         
1336                         add_win32_extension(fullname);
1337                 } else if (BLI_last_slash(name)) {
1338                         // full path
1339                         strcpy(fullname, name);
1340                         add_win32_extension(fullname);
1341                 } else {
1342                         // search for binary in $PATH
1343                         path = getenv("PATH");
1344                         if (path) {
1345                                 do {
1346                                         temp = strstr(path, separator);
1347                                         if (temp) {
1348                                                 strncpy(filename, path, temp - path);
1349                                                 filename[temp - path] = 0;
1350                                                 path = temp + 1;
1351                                         } else {
1352                                                 strncpy(filename, path, sizeof(filename));
1353                                         }
1354                                         BLI_join_dirfile(fullname, fullname, name);
1355                                         if (add_win32_extension(filename)) {
1356                                                 strcpy(fullname, filename);
1357                                                 break;
1358                                         }
1359                                 } while (temp);
1360                         }
1361                 }
1362 #ifndef NDEBUG
1363                 if (strcmp(name, fullname)) {
1364                         printf("guessing '%s' == '%s'\n", name, fullname);
1365                 }
1366 #endif
1367
1368 #ifdef _WIN32
1369                 // in windows change long filename to short filename because
1370                 // win2k doesn't know how to parse a commandline with lots of
1371                 // spaces and double-quotes. There's another solution to this
1372                 // with spawnv(P_WAIT, bprogname, argv) instead of system() but
1373                 // that's even uglier
1374                 GetShortPathName(fullname, fullname, FILE_MAXDIR+FILE_MAXFILE);
1375 #ifndef NDEBUG
1376                 printf("Shortname = '%s'\n", fullname);
1377 #endif
1378 #endif
1379         }
1380 }
1381
1382 void BLI_where_is_temp(char *fullname, int usertemp)
1383 {
1384         fullname[0] = '\0';
1385         
1386         if (usertemp && BLI_exists(U.tempdir)) {
1387                 strcpy(fullname, U.tempdir);
1388         }
1389         
1390         
1391 #ifdef WIN32
1392         if (fullname[0] == '\0') {
1393                 char *tmp = getenv("TEMP"); /* Windows */
1394                 if (tmp && BLI_exists(tmp)) {
1395                         strcpy(fullname, tmp);
1396                 }
1397         }
1398 #else
1399         /* Other OS's - Try TMP and TMPDIR */
1400         if (fullname[0] == '\0') {
1401                 char *tmp = getenv("TMP");
1402                 if (tmp && BLI_exists(tmp)) {
1403                         strcpy(fullname, tmp);
1404                 }
1405         }
1406         
1407         if (fullname[0] == '\0') {
1408                 char *tmp = getenv("TMPDIR");
1409                 if (tmp && BLI_exists(tmp)) {
1410                         strcpy(fullname, tmp);
1411                 }
1412         }
1413 #endif  
1414         
1415         if (fullname[0] == '\0') {
1416                 strcpy(fullname, "/tmp/");
1417         } else {
1418                 /* add a trailing slash if needed */
1419                 BLI_add_slash(fullname);
1420         }
1421 }
1422
1423 char *get_install_dir(void) {
1424         extern char bprogname[];
1425         char *tmpname = BLI_strdup(bprogname);
1426         char *cut;
1427
1428 #ifdef __APPLE__
1429         cut = strstr(tmpname, ".app");
1430         if (cut) cut[0] = 0;
1431 #endif
1432
1433         cut = BLI_last_slash(tmpname);
1434
1435         if (cut) {
1436                 cut[0] = 0;
1437                 return tmpname;
1438         } else {
1439                 MEM_freeN(tmpname);
1440                 return NULL;
1441         }
1442 }
1443
1444 /* 
1445  * returns absolute path to the app bundle
1446  * only useful on OS X 
1447  */
1448 #ifdef __APPLE__
1449 char* BLI_getbundle(void) {
1450         CFURLRef bundleURL;
1451         CFStringRef pathStr;
1452         static char path[MAXPATHLEN];
1453         CFBundleRef mainBundle = CFBundleGetMainBundle();
1454
1455         bundleURL = CFBundleCopyBundleURL(mainBundle);
1456         pathStr = CFURLCopyFileSystemPath(bundleURL, kCFURLPOSIXPathStyle);
1457         CFStringGetCString(pathStr, path, MAXPATHLEN, kCFStringEncodingASCII);
1458         CFRelease(pathStr);
1459         CFRelease(bundleURL);
1460         return path;
1461 }
1462 #endif
1463
1464 #ifdef WITH_ICONV
1465
1466 void BLI_string_to_utf8(char *original, char *utf_8, const char *code)
1467 {
1468         size_t inbytesleft=strlen(original);
1469         size_t outbytesleft=512;
1470         size_t rv=0;
1471         iconv_t cd;
1472         
1473         if (NULL == code) {
1474                 code = locale_charset();
1475         }
1476         cd=iconv_open("UTF-8", code);
1477
1478         if (cd == (iconv_t)(-1)) {
1479                 printf("iconv_open Error");
1480                 *utf_8='\0';
1481                 return ;
1482         }
1483         rv=iconv(cd, &original, &inbytesleft, &utf_8, &outbytesleft);
1484         if (rv == (size_t) -1) {
1485                 printf("iconv Error\n");
1486                 return ;
1487         }
1488         *utf_8 = '\0';
1489         iconv_close(cd);
1490 }
1491 #endif // WITH_ICONV
1492
1493