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