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