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