fix for own error, BLI_replace_extension would strip the filename if there wasn't...
[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 (path[a] != '.') {
1418                 a= path_len;
1419         }
1420
1421         if(a + ext_len >= maxlen)
1422                 return 0;
1423
1424         memcpy(path+a, ext, ext_len + 1);
1425         return 1;
1426 }
1427
1428 /* strip's trailing '.'s and adds the extension only when needed */
1429 int BLI_ensure_extension(char *path, size_t maxlen, const char *ext)
1430 {
1431         size_t path_len= strlen(path);
1432         size_t ext_len= strlen(ext);
1433         size_t a;
1434
1435         /* first check the extension is alread there */
1436         if (    (ext_len <= path_len) &&
1437                 (strcmp(path + (path_len - ext_len), ext) == 0))
1438         {
1439                 return 1;
1440         }
1441
1442         for(a= path_len - 1; a >= 0; a--) {
1443                 if (path[a] == '.') {
1444                         path[a]= '\0';
1445                 }
1446                 else {
1447                         break;
1448                 }
1449         }
1450         a++;
1451
1452         if(a + ext_len >= maxlen)
1453                 return 0;
1454
1455         memcpy(path+a, ext, ext_len + 1);
1456         return 1;
1457 }
1458
1459 /* Converts "/foo/bar.txt" to "/foo/" and "bar.txt"
1460  * - wont change 'string'
1461  * - wont create any directories
1462  * - dosnt use CWD, or deal with relative paths.
1463  * - Only fill's in *dir and *file when they are non NULL
1464  * */
1465 void BLI_split_dirfile(const char *string, char *dir, char *file, const size_t dirlen, const size_t filelen)
1466 {
1467         char *lslash_str = BLI_last_slash(string);
1468         size_t lslash= lslash_str ? (size_t)(lslash_str - string) + 1 : 0;
1469
1470         if (dir) {
1471                 if (lslash) {
1472                         BLI_strncpy( dir, string, MIN2(dirlen, lslash + 1)); /* +1 to include the slash and the last char */
1473                 }
1474                 else {
1475                         dir[0] = '\0';
1476                 }
1477         }
1478         
1479         if (file) {
1480                 BLI_strncpy(file, string+lslash, filelen);
1481         }
1482 }
1483
1484 void BLI_split_dir_part(const char *string, char *dir, const size_t dirlen)
1485 {
1486         BLI_split_dirfile(string, dir, NULL, dirlen, 0);
1487 }
1488
1489 void BLI_split_file_part(const char *string, char *file, const size_t filelen)
1490 {
1491         BLI_split_dirfile(string, NULL, file, 0, filelen);
1492 }
1493
1494 /* simple appending of filename to dir, does not check for valid path! */
1495 void BLI_join_dirfile(char *dst, const size_t maxlen, const char *dir, const char *file)
1496 {
1497         size_t dirlen= BLI_strnlen(dir, maxlen);
1498
1499         if (dst != dir) {
1500                 if(dirlen  == maxlen) {
1501                         memcpy(dst, dir, dirlen);
1502                         dst[dirlen - 1]= '\0';
1503                         return; /* dir fills the path */
1504                 }
1505                 else {
1506                         memcpy(dst, dir, dirlen + 1);
1507                 }
1508         }
1509
1510         if (dirlen + 1 >= maxlen) {
1511                 return; /* fills the path */
1512         }
1513
1514         /* inline BLI_add_slash */
1515         if (dst[dirlen - 1] != SEP) {
1516                 dst[dirlen++]= SEP;
1517                 dst[dirlen  ]= '\0';
1518         }
1519
1520         if (dirlen >= maxlen) {
1521                 return; /* fills the path */
1522         }
1523
1524         if (file == NULL) {
1525                 return;
1526         }
1527
1528         BLI_strncpy(dst + dirlen, file, maxlen - dirlen);
1529 }
1530
1531 /* like pythons os.path.basename( ) */
1532 char *BLI_path_basename(char *path)
1533 {
1534         char *filename= BLI_last_slash(path);
1535         return filename ? filename + 1 : path;
1536 }
1537
1538 /*
1539   Produce image export path.
1540
1541   Fails returning 0 if image filename is empty or if destination path
1542   matches image path (i.e. both are the same file).
1543
1544   Trailing slash in dest_dir is optional.
1545
1546   Logic:
1547
1548   - if an image is "below" current .blend file directory, rebuild the
1549         same dir structure in dest_dir
1550
1551   For example //textures/foo/bar.png becomes
1552   [dest_dir]/textures/foo/bar.png.
1553
1554   - if an image is not "below" current .blend file directory,
1555   disregard it's path and copy it in the same directory where 3D file
1556   goes.
1557
1558   For example //../foo/bar.png becomes [dest_dir]/bar.png.
1559
1560   This logic will help ensure that all image paths are relative and
1561   that a user gets his images in one place. It'll also provide
1562   consistent behaviour across exporters.
1563  */
1564 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)
1565 {
1566         char path[FILE_MAX];
1567         char dir[FILE_MAX];
1568         char base[FILE_MAX];
1569         char blend_dir[FILE_MAX];       /* directory, where current .blend file resides */
1570         char dest_path[FILE_MAX];
1571         char rel_dir[FILE_MAX];
1572         int len;
1573
1574         if (abs)
1575                 abs[0]= 0;
1576
1577         if (rel)
1578                 rel[0]= 0;
1579
1580         BLI_split_dir_part(base_dir, blend_dir, sizeof(blend_dir));
1581
1582         if (src_dir[0]=='\0')
1583                 return 0;
1584
1585         BLI_strncpy(path, src_dir, sizeof(path));
1586
1587         /* expand "//" in filename and get absolute path */
1588         BLI_path_abs(path, base_dir);
1589
1590         /* get the directory part */
1591         BLI_split_dirfile(path, dir, base, sizeof(dir), sizeof(base));
1592
1593         len= strlen(blend_dir);
1594
1595         rel_dir[0] = 0;
1596
1597         /* if image is "below" current .blend file directory */
1598         if (!strncmp(path, blend_dir, len)) {
1599
1600                 /* if image is _in_ current .blend file directory */
1601                 if (BLI_path_cmp(dir, blend_dir) == 0) {
1602                         BLI_join_dirfile(dest_path, sizeof(dest_path), dest_dir, base);
1603                 }
1604                 /* "below" */
1605                 else {
1606                         /* rel = image_path_dir - blend_dir */
1607                         BLI_strncpy(rel_dir, dir + len, sizeof(rel_dir));
1608
1609                         BLI_join_dirfile(dest_path, sizeof(dest_path), dest_dir, rel_dir);
1610                         BLI_join_dirfile(dest_path, sizeof(dest_path), dest_path, base);
1611                 }
1612
1613         }
1614         /* image is out of current directory */
1615         else {
1616                 BLI_join_dirfile(dest_path, sizeof(dest_path), dest_dir, base);
1617         }
1618
1619         if (abs)
1620                 BLI_strncpy(abs, dest_path, abs_len);
1621
1622         if (rel) {
1623                 strncat(rel, rel_dir, rel_len);
1624                 strncat(rel, base, rel_len);
1625         }
1626
1627         /* return 2 if src=dest */
1628         if (BLI_path_cmp(path, dest_path) == 0) {
1629                 // if (G.f & G_DEBUG) printf("%s and %s are the same file\n", path, dest_path);
1630                 return 2;
1631         }
1632
1633         return 1;
1634 }
1635
1636 char *BLI_first_slash(char *string)
1637 {
1638         char *ffslash, *fbslash;
1639         
1640         ffslash= strchr(string, '/');   
1641         fbslash= strchr(string, '\\');
1642         
1643         if (!ffslash) return fbslash;
1644         else if (!fbslash) return ffslash;
1645         
1646         if ((intptr_t)ffslash < (intptr_t)fbslash) return ffslash;
1647         else return fbslash;
1648 }
1649
1650 char *BLI_last_slash(const char *string)
1651 {
1652         char *lfslash, *lbslash;
1653         
1654         lfslash= strrchr(string, '/');  
1655         lbslash= strrchr(string, '\\');
1656
1657         if (!lfslash) return lbslash; 
1658         else if (!lbslash) return lfslash;
1659         
1660         if ((intptr_t)lfslash < (intptr_t)lbslash) return lbslash;
1661         else return lfslash;
1662 }
1663
1664 /* adds a slash if there isnt one there already */
1665 int BLI_add_slash(char *string)
1666 {
1667         int len = strlen(string);
1668         if (len==0 || string[len-1] != SEP) {
1669                 string[len] = SEP;
1670                 string[len+1] = '\0';
1671                 return len+1;
1672         }
1673         return len;
1674 }
1675
1676 /* removes a slash if there is one */
1677 void BLI_del_slash(char *string)
1678 {
1679         int len = strlen(string);
1680         while (len) {
1681                 if (string[len-1] == SEP) {
1682                         string[len-1] = '\0';
1683                         len--;
1684                 } else {
1685                         break;
1686                 }
1687         }
1688 }
1689
1690 static int add_win32_extension(char *name)
1691 {
1692         int retval = 0;
1693         int type;
1694
1695         type = BLI_exists(name);
1696         if ((type == 0) || S_ISDIR(type)) {
1697 #ifdef _WIN32
1698                 char filename[FILE_MAXDIR+FILE_MAXFILE];
1699                 char ext[FILE_MAXDIR+FILE_MAXFILE];
1700                 const char *extensions = getenv("PATHEXT");
1701                 if (extensions) {
1702                         char *temp;
1703                         do {
1704                                 strcpy(filename, name);
1705                                 temp = strstr(extensions, ";");
1706                                 if (temp) {
1707                                         strncpy(ext, extensions, temp - extensions);
1708                                         ext[temp - extensions] = 0;
1709                                         extensions = temp + 1;
1710                                         strcat(filename, ext);
1711                                 } else {
1712                                         strcat(filename, extensions);
1713                                 }
1714
1715                                 type = BLI_exists(filename);
1716                                 if (type && (! S_ISDIR(type))) {
1717                                         retval = 1;
1718                                         strcpy(name, filename);
1719                                         break;
1720                                 }
1721                         } while (temp);
1722                 }
1723 #endif
1724         } else {
1725                 retval = 1;
1726         }
1727
1728         return (retval);
1729 }
1730
1731 /*
1732 * Checks if name is a fully qualified filename to an executable.
1733 * If not it searches $PATH for the file. On Windows it also
1734 * adds the correct extension (.com .exe etc) from
1735 * $PATHEXT if necessary. Also on Windows it translates
1736 * the name to its 8.3 version to prevent problems with
1737 * spaces and stuff. Final result is returned in fullname.
1738 *
1739 * @param fullname The full path and full name of the executable
1740 * (must be FILE_MAX minimum)
1741 * @param name The name of the executable (usually argv[0]) to be checked
1742 */
1743 static void bli_where_am_i(char *fullname, const size_t maxlen, const char *name)
1744 {
1745         char filename[FILE_MAXDIR+FILE_MAXFILE];
1746         const char *path = NULL, *temp;
1747
1748 #ifdef _WIN32
1749         const char *separator = ";";
1750 #else
1751         const char *separator = ":";
1752 #endif
1753
1754         
1755 #ifdef WITH_BINRELOC
1756         /* linux uses binreloc since argv[0] is not reliable, call br_init( NULL ) first */
1757         path = br_find_exe( NULL );
1758         if (path) {
1759                 BLI_strncpy(fullname, path, maxlen);
1760                 free((void *)path);
1761                 return;
1762         }
1763 #endif
1764
1765 #ifdef _WIN32
1766         if(GetModuleFileName(0, fullname, maxlen)) {
1767                 if(!BLI_exists(fullname)) {
1768                         printf("path can't be found: \"%.*s\"\n", maxlen, fullname);
1769                         MessageBox(NULL, "path contains invalid characters or is too long (see console)", "Error", MB_OK);
1770                 }
1771                 return;
1772         }
1773 #endif
1774
1775         /* unix and non linux */
1776         if (name && name[0]) {
1777                 BLI_strncpy(fullname, name, maxlen);
1778                 if (name[0] == '.') {
1779                         char wdir[FILE_MAX]= "";
1780                         BLI_current_working_dir(wdir, sizeof(wdir));     /* backup cwd to restore after */
1781
1782                         // not needed but avoids annoying /./ in name
1783                         if(name[1]==SEP)
1784                                 BLI_join_dirfile(fullname, maxlen, wdir, name+2);
1785                         else
1786                                 BLI_join_dirfile(fullname, maxlen, wdir, name);
1787
1788                         add_win32_extension(fullname); /* XXX, doesnt respect length */
1789                 }
1790                 else if (BLI_last_slash(name)) {
1791                         // full path
1792                         BLI_strncpy(fullname, name, maxlen);
1793                         add_win32_extension(fullname);
1794                 } else {
1795                         // search for binary in $PATH
1796                         path = getenv("PATH");
1797                         if (path) {
1798                                 do {
1799                                         temp = strstr(path, separator);
1800                                         if (temp) {
1801                                                 strncpy(filename, path, temp - path);
1802                                                 filename[temp - path] = 0;
1803                                                 path = temp + 1;
1804                                         } else {
1805                                                 strncpy(filename, path, sizeof(filename));
1806                                         }
1807                                         BLI_join_dirfile(fullname, maxlen, fullname, name);
1808                                         if (add_win32_extension(filename)) {
1809                                                 BLI_strncpy(fullname, filename, maxlen);
1810                                                 break;
1811                                         }
1812                                 } while (temp);
1813                         }
1814                 }
1815 #if defined(DEBUG)
1816                 if (strcmp(name, fullname)) {
1817                         printf("guessing '%s' == '%s'\n", name, fullname);
1818                 }
1819 #endif
1820         }
1821 }
1822
1823 void BLI_init_program_path(const char *argv0)
1824 {
1825         bli_where_am_i(bprogname, sizeof(bprogname), argv0);
1826         BLI_split_dir_part(bprogname, bprogdir, sizeof(bprogdir));
1827 }
1828
1829 const char *BLI_program_path(void)
1830 {
1831         return bprogname;
1832 }
1833
1834 const char *BLI_program_dir(void)
1835 {
1836         return bprogdir;
1837 }
1838
1839 /**
1840 * Gets the temp directory when blender first runs.
1841 * If the default path is not found, use try $TEMP
1842
1843 * Also make sure the temp dir has a trailing slash
1844 *
1845 * @param fullname The full path to the temp directory
1846 * @param userdir Directory specified in user preferences 
1847 */
1848 static void BLI_where_is_temp(char *fullname, const size_t maxlen, char *userdir)
1849 {
1850         fullname[0] = '\0';
1851         
1852         if (userdir && BLI_is_dir(userdir)) {
1853                 BLI_strncpy(fullname, userdir, maxlen);
1854         }
1855         
1856         
1857 #ifdef WIN32
1858         if (fullname[0] == '\0') {
1859                 const char *tmp = getenv("TEMP"); /* Windows */
1860                 if (tmp && BLI_is_dir(tmp)) {
1861                         BLI_strncpy(fullname, tmp, maxlen);
1862                 }
1863         }
1864 #else
1865         /* Other OS's - Try TMP and TMPDIR */
1866         if (fullname[0] == '\0') {
1867                 const char *tmp = getenv("TMP");
1868                 if (tmp && BLI_is_dir(tmp)) {
1869                         BLI_strncpy(fullname, tmp, maxlen);
1870                 }
1871         }
1872         
1873         if (fullname[0] == '\0') {
1874                 const char *tmp = getenv("TMPDIR");
1875                 if (tmp && BLI_is_dir(tmp)) {
1876                         BLI_strncpy(fullname, tmp, maxlen);
1877                 }
1878         }
1879 #endif  
1880         
1881         if (fullname[0] == '\0') {
1882                 BLI_strncpy(fullname, "/tmp/", maxlen);
1883         } else {
1884                 /* add a trailing slash if needed */
1885                 BLI_add_slash(fullname);
1886 #ifdef WIN32
1887                 if(userdir && userdir != fullname) {
1888                         BLI_strncpy(userdir, fullname, maxlen); /* also set user pref to show %TEMP%. /tmp/ is just plain confusing for Windows users. */
1889                 }
1890 #endif
1891         }
1892 }
1893
1894 void BLI_init_temporary_dir(char *userdir)
1895 {
1896         BLI_where_is_temp(btempdir, FILE_MAX, userdir);
1897 }
1898
1899 const char *BLI_temporary_dir(void)
1900 {
1901         return btempdir;
1902 }
1903
1904 void BLI_system_temporary_dir(char *dir)
1905 {
1906         BLI_where_is_temp(dir, FILE_MAX, NULL);
1907 }
1908
1909 #ifdef WITH_ICONV
1910
1911 void BLI_string_to_utf8(char *original, char *utf_8, const char *code)
1912 {
1913         size_t inbytesleft=strlen(original);
1914         size_t outbytesleft=512;
1915         size_t rv=0;
1916         iconv_t cd;
1917         
1918         if (NULL == code) {
1919                 code = locale_charset();
1920         }
1921         cd=iconv_open("UTF-8", code);
1922
1923         if (cd == (iconv_t)(-1)) {
1924                 printf("iconv_open Error");
1925                 *utf_8='\0';
1926                 return ;
1927         }
1928         rv=iconv(cd, &original, &inbytesleft, &utf_8, &outbytesleft);
1929         if (rv == (size_t) -1) {
1930                 printf("iconv Error\n");
1931                 return ;
1932         }
1933         *utf_8 = '\0';
1934         iconv_close(cd);
1935 }
1936 #endif // WITH_ICONV
1937
1938