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