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