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