== SCons ==
[blender.git] / source / blender / blenlib / intern / util.c
1 /* util.c
2  *
3  * various string, file, list operations.
4  *
5  *
6  * $Id$
7  *
8  * ***** BEGIN GPL LICENSE BLOCK *****
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software Foundation,
22  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
23  *
24  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
25  * All rights reserved.
26  *
27  * The Original Code is: all of this file.
28  *
29  * Contributor(s): none yet.
30  *
31  * ***** END GPL LICENSE BLOCK *****
32  * 
33  */
34
35 #include <stdio.h>
36 #include <fcntl.h>
37 #include <ctype.h>
38 #include <string.h>
39 #include <stdlib.h>
40 #include <stdarg.h>
41 #include <math.h> /* for log10 */
42
43 #include "MEM_guardedalloc.h"
44
45 #include "DNA_listBase.h"
46 #include "DNA_userdef_types.h"
47
48 #include "BLI_blenlib.h"
49 #include "BLI_storage.h"
50 #include "BLI_storage_types.h"
51 #include "BLI_dynamiclist.h"
52
53 #include "BLI_util.h"
54 #include "BKE_utildefines.h"
55
56
57
58
59 #ifdef HAVE_CONFIG_H
60 #include <config.h>
61 #endif
62
63 #ifndef WIN32 
64 #include <unistd.h>
65 #else
66 #include <io.h>
67 #endif
68
69 #ifdef WIN32
70
71 #ifdef _WIN32_IE
72 #undef _WIN32_IE
73 #endif
74 #define _WIN32_IE 0x0501
75 #include <windows.h>
76 #include <shlobj.h>
77
78 #include "BLI_winstuff.h"
79
80 /* for duplicate_defgroup */
81 #if !(defined vsnprintf)
82 #define vsnprintf _vsnprintf
83 #endif
84
85 #endif
86
87
88 #ifndef WIN32
89 #include <sys/time.h>
90 #endif
91
92 #ifdef __APPLE__
93 #include <sys/param.h>
94 #include <CoreFoundation/CoreFoundation.h>
95 #endif
96
97 #ifdef __linux__
98 #include "binreloc.h"
99 #endif
100
101 /* local */
102
103 static int add_win32_extension(char *name);
104
105 /* implementation */
106
107 int BLI_stringdec(char *string, char *kop, char *start, unsigned short *numlen)
108 {
109         unsigned short len, len2, nums = 0, nume = 0;
110         short i, found = 0;
111
112         len2 = len = strlen(string);
113         
114         if (len > 6) {
115                 if (BLI_strncasecmp(string + len - 6, ".blend", 6) == 0) len -= 6;
116                 else if (BLI_strncasecmp(string + len - 6, ".trace", 6) == 0) len -= 6;
117         }
118         
119         if (len > 9) {
120                 if (BLI_strncasecmp(string + len - 9, ".blend.gz", 9) == 0) len -= 9;
121         }
122                 
123         if (len == len2) {
124                 if (len > 4) {
125                         /* handle .jf0 en .jf1 for jstreams */
126                         if (BLI_strncasecmp(string + len - 4, ".jf", 3) == 0) len -= 4;
127                         else if (BLI_strncasecmp(string + len - 4, ".tga", 4) == 0) len -= 4;
128                         else if (BLI_strncasecmp(string + len - 4, ".jpg", 4) == 0) len -= 4;
129                         else if (BLI_strncasecmp(string + len - 4, ".png", 4) == 0) len -= 4;
130                         else if (BLI_strncasecmp(string + len - 4, ".txt", 4) == 0) len -= 4;
131                         else if (BLI_strncasecmp(string + len - 4, ".cyc", 4) == 0) len -= 4;
132                         else if (BLI_strncasecmp(string + len - 4, ".enh", 4) == 0) len -= 4;
133                         else if (BLI_strncasecmp(string + len - 4, ".rgb", 4) == 0) len -= 4;
134                         else if (BLI_strncasecmp(string + len - 4, ".psx", 4) == 0) len -= 4;
135                         else if (BLI_strncasecmp(string + len - 4, ".ble", 4) == 0) len -= 4;
136                         else if (BLI_strncasecmp(string + len - 4, ".exr", 4) == 0) len -= 4;
137                 }
138         }
139         
140         for (i = len - 1; i >= 0; i--) {
141                 if (string[i] == '/') break;
142                 if (isdigit(string[i])) {
143                         if (found){
144                                 nums = i;
145                         }
146                         else{
147                                 nume = i;
148                                 nums = i;
149                                 found = 1;
150                         }
151                 }
152                 else {
153                         if (found) break;
154                 }
155         }
156         if (found){
157                 if (start) strcpy(start,&string[nume+1]);
158                 if (kop) {
159                         strcpy(kop,string);
160                         kop[nums]=0;
161                 }
162                 if (numlen) *numlen = nume-nums+1;
163                 return ((int)atoi(&(string[nums])));
164         }
165         if (start) strcpy(start, string + len);
166         if (kop) {
167                 strncpy(kop, string, len);
168                 kop[len] = 0;
169         }
170         if (numlen) *numlen=0;
171         return 0;
172 }
173
174
175 void BLI_stringenc(char *string, char *kop, char *start, unsigned short numlen, int pic)
176 {
177         char numstr[10]="";
178         unsigned short len,i;
179
180         strcpy(string,kop);
181         
182         if (pic>0 || numlen==4) {
183                 len= sprintf(numstr,"%d",pic);
184                 
185                 for(i=len;i<numlen;i++){
186                         strcat(string,"0");
187                 }
188                 strcat(string,numstr);
189         }
190         strcat(string, start);
191 }
192
193
194 void BLI_newname(char *name, int add)
195 {
196         char head[128], tail[128];
197         int pic;
198         unsigned short digits;
199         
200         pic = BLI_stringdec(name, head, tail, &digits);
201         
202         /* are we going from 100 -> 99 or from 10 -> 9 */
203         if (add < 0 && digits < 4 && digits > 0) {
204                 int i, exp;
205                 exp = 1;
206                 for (i = digits; i > 1; i--) exp *= 10;
207                 if (pic >= exp && (pic + add) < exp) digits--;
208         }
209         
210         pic += add;
211         
212         if (digits==4 && pic<0) pic= 0;
213         BLI_stringenc(name, head, tail, digits, pic);
214 }
215
216 /* little helper macro for BLI_uniquename */
217 #ifndef GIVE_STRADDR
218         #define GIVE_STRADDR(data, offset) ( ((char *)data) + offset )
219 #endif
220
221 /* Generic function to set a unique name. It is only designed to be used in situations
222  * where the name is part of the struct, and also that the name is at most 128 chars long.
223  * 
224  * For places where this is used, see constraint.c for example...
225  *
226  *      name_offs: should be calculated using offsetof(structname, membername) macro from stddef.h
227  *      len: maximum length of string (to prevent overflows, etc.)
228  *      defname: the name that should be used by default if none is specified already
229  *      delim: the character which acts as a delimeter between parts of the name
230  */
231 void BLI_uniquename(ListBase *list, void *vlink, char defname[], char delim, short name_offs, short len)
232 {
233         Link *link;
234         char tempname[128];
235         int     number = 1, exists = 0;
236         char *dot;
237         
238         /* Make sure length can be handled */
239         if ((len < 0) || (len > 128))
240                 return;
241         
242         /* See if we are given an empty string */
243         if (ELEM(NULL, vlink, defname))
244                 return;
245         
246         if (GIVE_STRADDR(vlink, name_offs) == '\0') {
247                 /* give it default name first */
248                 BLI_strncpy(GIVE_STRADDR(vlink, name_offs), defname, len);
249         }
250         
251         /* See if we even need to do this */
252         if (list == NULL)
253                 return;
254         
255         for (link = list->first; link; link= link->next) {
256                 if (link != vlink) {
257                         if (!strcmp(GIVE_STRADDR(link, name_offs), GIVE_STRADDR(vlink, name_offs))) {
258                                 exists = 1;
259                                 break;
260                         }
261                 }
262         }
263         if (exists == 0)
264                 return;
265
266         /* Strip off the suffix */
267         dot = strchr(GIVE_STRADDR(vlink, name_offs), delim);
268         if (dot)
269                 *dot=0;
270         
271         for (number = 1; number <= 999; number++) {
272                 BLI_snprintf(tempname, 128, "%s%c%03d", GIVE_STRADDR(vlink, name_offs), delim, number);
273                 
274                 exists = 0;
275                 for (link= list->first; link; link= link->next) {
276                         if (vlink != link) {
277                                 if (!strcmp(GIVE_STRADDR(link, name_offs), tempname)) {
278                                         exists = 1;
279                                         break;
280                                 }
281                         }
282                 }
283                 if (exists == 0) {
284                         BLI_strncpy(GIVE_STRADDR(vlink, name_offs), tempname, len);
285                         return;
286                 }
287         }
288 }
289
290 /* ******************** string encoding ***************** */
291
292 /* This is quite an ugly function... its purpose is to
293  * take the dir name, make it absolute, and clean it up, replacing
294  * excess file entry stuff (like /tmp/../tmp/../)
295  * note that dir isn't protected for max string names... 
296  * 
297  * If relbase is NULL then its ignored
298  */
299
300 void BLI_cleanup_dir(const char *relabase, char *dir)
301 {
302         BLI_cleanup_file(relabase, dir);
303         BLI_add_slash(dir);
304
305 }
306
307 void BLI_cleanup_file(const char *relabase, char *dir)
308 {
309         short a;
310         char *start, *eind;
311         if (relabase) {
312                 BLI_convertstringcode(dir, relabase);
313         } else {
314                 if (dir[0]=='/' && dir[1]=='/') {
315                         if (dir[2]== '\0') {
316                                 return; /* path is "//" - cant clean it */
317                         }
318                         dir = dir+2; /* skip the first // */
319                 }
320         }
321         
322         /* Note
323          *   memmove( start, eind, strlen(eind)+1 );
324          * is the same as
325          *   strcpy( start, eind ); 
326          * except strcpy should not be used because there is overlap,
327           * so use memmove's slightly more obscure syntax - Campbell
328          */
329         
330 #ifdef WIN32
331         
332         /* Note, this should really be moved to the file selector,
333          * since this function is used in many areas */
334         if(strcmp(dir, ".")==0) {       /* happens for example in FILE_MAIN */
335            get_default_root(dir);
336            return;
337         }       
338
339         while ( (start = strstr(dir, "\\..\\")) ) {
340                 eind = start + strlen("\\..\\") - 1;
341                 a = start-dir-1;
342                 while (a>0) {
343                         if (dir[a] == '\\') break;
344                         a--;
345                 }
346                 if (a<0) {
347                         break;
348                 } else {
349                         memmove( dir+a, eind, strlen(eind)+1 );
350                 }
351         }
352
353         while ( (start = strstr(dir,"\\.\\")) ){
354                 eind = start + strlen("\\.\\") - 1;
355                 memmove( start, eind, strlen(eind)+1 );
356         }
357
358         while ( (start = strstr(dir,"\\\\" )) ){
359                 eind = start + strlen("\\\\") - 1;
360                 memmove( start, eind, strlen(eind)+1 );
361         }
362
363         if((a = strlen(dir))){                          /* remove the '\\' at the end */
364                 while(a>0 && dir[a-1] == '\\'){
365                         a--;
366                         dir[a] = 0;
367                 }
368         }
369 #else
370         if(dir[0]=='.') {       /* happens, for example in FILE_MAIN */
371            dir[0]= '/';
372            dir[1]= 0;
373            return;
374         }       
375
376         while ( (start = strstr(dir, "/../")) ) {
377                 eind = start + strlen("/../") - 1;
378                 a = start-dir-1;
379                 while (a>0) {
380                         if (dir[a] == '/') break;
381                         a--;
382                 }
383                 if (a<0) {
384                         break;
385                 } else {
386                         memmove( dir+a, eind, strlen(eind)+1 );
387                 }
388         }
389
390         while ( (start = strstr(dir,"/./")) ){
391                 eind = start + strlen("/./") - 1;
392                 memmove( start, eind, strlen(eind)+1 );
393         }
394
395         while ( (start = strstr(dir,"//" )) ){
396                 eind = start + strlen("//") - 1;
397                 memmove( start, eind, strlen(eind)+1 );
398         }
399
400         if( (a = strlen(dir)) ){                                /* remove all '/' at the end */
401                 while(dir[a-1] == '/'){
402                         a--;
403                         dir[a] = 0;
404                         if (a<=0) break;
405                 }
406         }
407 #endif
408 }
409
410
411 void BLI_makestringcode(const char *relfile, char *file)
412 {
413         char * p;
414         char * q;
415         char * lslash;
416         char temp[FILE_MAXDIR+FILE_MAXFILE];
417         char res[FILE_MAXDIR+FILE_MAXFILE];
418         
419         /* if file is already relative, bail out */
420         if(file[0]=='/' && file[1]=='/') return;
421         
422         /* also bail out if relative path is not set */
423         if (relfile[0] == 0) return;
424
425 #ifdef WIN32 
426         if (strlen(relfile) > 2 && relfile[1] != ':') {
427                 char* ptemp;
428                 /* fix missing volume name in relative base,
429                    can happen with old .Blog files */
430                 get_default_root(temp);
431                 ptemp = &temp[2];
432                 if (relfile[0] != '\\' && relfile[0] != '/') {
433                         ptemp++;
434                 }
435                 BLI_strncpy(ptemp, relfile, FILE_MAXDIR + FILE_MAXFILE-3);
436         } else {
437                 BLI_strncpy(temp, relfile, FILE_MAXDIR + FILE_MAXFILE);
438         }
439
440         if (strlen(file) > 2) {
441                 if ( temp[1] == ':' && file[1] == ':' && temp[0] != file[0] )
442                         return;
443         }
444 #else
445         BLI_strncpy(temp, relfile, FILE_MAX);
446 #endif
447
448         BLI_char_switch(temp, '\\', '/');
449         BLI_char_switch(file, '\\', '/');
450         
451         /* remove /./ which confuse the following slash counting... */
452         BLI_cleanup_file(NULL, file);
453         BLI_cleanup_file(NULL, temp);
454         
455         /* the last slash in the file indicates where the path part ends */
456         lslash = BLI_last_slash(temp);
457
458         if (lslash) 
459         {       
460                 /* find the prefix of the filename that is equal for both filenames.
461                    This is replaced by the two slashes at the beginning */
462                 p = temp;
463                 q = file;
464                 while (*p == *q) {
465                         ++p; ++q;
466                 }
467                 /* we might have passed the slash when the beginning of a dir matches 
468                    so we rewind. Only check on the actual filename
469                 */
470                 if (*q != '/') {
471                         while ( (q >= file) && (*q != '/') ) { --q; --p; }
472                 } 
473                 else if (*p != '/') {
474                         while ( (p >= temp) && (*p != '/') ) { --p; --q; }
475                 }
476                 
477                 strcpy(res,     "//");
478
479                 /* p now points to the slash that is at the beginning of the part
480                    where the path is different from the relative path. 
481                    We count the number of directories we need to go up in the
482                    hierarchy to arrive at the common 'prefix' of the path
483                 */                      
484                 while (p && p < lslash) {
485                         if (*p == '/') 
486                                 strcat(res,     "../");
487                         ++p;
488                 }
489
490                 strcat(res, q+1); /* don't copy the slash at the beginning */
491                 
492 #ifdef  WIN32
493                 BLI_char_switch(res+2, '/', '\\');
494 #endif
495                 strcpy(file, res);
496         }
497 }
498
499 int BLI_has_parent(char *path)
500 {
501         int len;
502         int slashes = 0;
503         BLI_clean(path);
504         len = BLI_add_slash(path) - 1;
505
506         while (len>=0) {
507                 if ((path[len] == '\\') || (path[len] == '/'))
508                         slashes++;
509                 len--;
510         }
511         return slashes > 1;
512 }
513
514 int BLI_parent_dir(char *path)
515 {
516 #ifdef WIN32
517         static char *parent_dir="..\\";
518 #else
519         static char *parent_dir="../";
520 #endif
521         char tmp[FILE_MAXDIR+FILE_MAXFILE+4];
522         BLI_strncpy(tmp, path, sizeof(tmp));
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 int BLI_convertstringframe(char *path, int frame)
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         if (ch_end) { /* warning, ch_end is the last # +1 */
555                 /* Add the frame number? */
556                 short numlen, hashlen;
557                 char tmp[FILE_MAX];
558                 
559                 char format[16]; /* 6 is realistically the maxframe (300000), so 8 should be enough, but 16 to be safe. */
560                 if (((ch_end-1)-ch_sta) >= 16) {
561                         ch_end = ch_sta+15; /* disallow values longer then 'format' can hold */
562                 }
563                 
564                 strcpy(tmp, path);
565                 
566                 numlen = 1 + (int)log10((double)frame); /* this is the number of chars in the number */
567                 hashlen = ch_end - ch_sta;
568                 
569                 sprintf(format, "%d", frame);
570                 
571                 if (numlen==hashlen) { /* simple case */
572                         memcpy(tmp+ch_sta, format, numlen);
573                 } else if (numlen < hashlen) {
574                         memcpy(tmp+ch_sta + (hashlen-numlen), format, numlen); /*dont copy the string terminator */
575                         memset(tmp+ch_sta, '0', hashlen-numlen);
576                 } else {
577                         /* number is longer then number of #'s */
578                         if (tmp[ch_end] == '\0') { /* hashes are last, no need to move any string*/
579                                 /* bad juju - not testing string length here :/ */
580                                 memcpy(tmp+ch_sta, format, numlen+1); /* add 1 to get the string terminator \0 */
581                         } else {
582                                 /* we need to move the end characters, reuse i */
583                                 int j;
584                                 
585                                 i = strlen(tmp); /* +1 to copy the string terminator */
586                                 j = i + (numlen-hashlen); /* from/to */
587                                 
588                                 while (i >= ch_end) {
589                                         tmp[j] = tmp[i]; 
590                                         i--;
591                                         j--;
592                                 }
593                                 memcpy(tmp + ch_sta, format, numlen);
594                         }
595                 }       
596                 strcpy(path, tmp);
597                 return 1;
598         }
599         return 0;
600 }
601
602
603 int BLI_convertstringcode(char *path, const char *basepath)
604 {
605         int wasrelative = (strncmp(path, "//", 2)==0);
606         char tmp[FILE_MAX];
607         char base[FILE_MAX];
608 #ifdef WIN32
609         char vol[3] = {'\0', '\0', '\0'};
610
611         BLI_strncpy(vol, path, 3);
612         /* we are checking here if we have an absolute path that is not in the current
613            blend file as a lib main - we are basically checking for the case that a 
614            UNIX root '/' is passed.
615         */
616         if (!wasrelative && (vol[1] != ':' && (vol[0] == '\0' || vol[0] == '/' || vol[0] == '\\'))) {
617                 char *p = path;
618                 get_default_root(tmp);
619                 // get rid of the slashes at the beginning of the path
620                 while (*p == '\\' || *p == '/') {
621                         p++;
622                 }
623                 strcat(tmp, p);
624         }
625         else {
626                 BLI_strncpy(tmp, path, FILE_MAX);
627         }
628 #else
629         BLI_strncpy(tmp, path, FILE_MAX);
630         
631         /* Check for loading a windows path on a posix system
632          * in this case, there is no use in trying C:/ since it 
633          * will never exist on a unix os.
634          * 
635          * Add a / prefix and lowercase the driveletter, remove the :
636          * C:\foo.JPG -> /c/foo.JPG */
637         
638         if (isalpha(tmp[0]) && tmp[1] == ':' && (tmp[2]=='\\' || tmp[2]=='/') ) {
639                 tmp[1] = tolower(tmp[0]); /* replace ':' with driveletter */
640                 tmp[0] = '/'; 
641                 /* '\' the slash will be converted later */
642         }
643         
644 #endif
645
646         BLI_strncpy(base, basepath, FILE_MAX);
647         
648         BLI_cleanup_file(NULL, base);
649         
650         /* push slashes into unix mode - strings entering this part are
651            potentially messed up: having both back- and forward slashes.
652            Here we push into one conform direction, and at the end we
653            push them into the system specific dir. This ensures uniformity
654            of paths and solving some problems (and prevent potential future
655            ones) -jesterKing. */
656         BLI_char_switch(tmp, '\\', '/');
657         BLI_char_switch(base, '\\', '/');       
658
659         /* Paths starting with // will get the blend file as their base,
660          * this isnt standard in any os but is uesed in blender all over the place */
661         if (wasrelative) {
662                 char *lslash= BLI_last_slash(base);
663                 if (lslash) {
664                         int baselen= (int) (lslash-base) + 1;
665                         /* use path for for temp storage here, we copy back over it right away */
666                         BLI_strncpy(path, tmp+2, FILE_MAX);
667                         
668                         memcpy(tmp, base, baselen);
669                         strcpy(tmp+baselen, path);
670                         strcpy(path, tmp);
671                 } else {
672                         strcpy(path, tmp+2);
673                 }
674         } else {
675                 strcpy(path, tmp);
676         }
677         
678         if (path[0]!='\0') {
679                 if ( path[strlen(path)-1]=='/') {
680                         BLI_cleanup_dir(NULL, path);
681                 } else {
682                         BLI_cleanup_file(NULL, path);
683                 }
684         }
685         
686 #ifdef WIN32
687         /* skip first two chars, which in case of
688            absolute path will be drive:/blabla and
689            in case of relpath //blabla/. So relpath
690            // will be retained, rest will be nice and
691            shiny win32 backward slashes :) -jesterKing
692         */
693         BLI_char_switch(path+2, '/', '\\');
694 #endif
695         
696         return wasrelative;
697 }
698
699
700 /*
701  * Should only be done with command line paths.
702  * this is NOT somthing blenders internal paths support like the // prefix
703  */
704 int BLI_convertstringcwd(char *path)
705 {
706         int wasrelative = 1;
707         int filelen = strlen(path);
708         
709 #ifdef WIN32
710         if (filelen >= 3 && path[1] == ':' && (path[2] == '\\' || path[2] == '/'))
711                 wasrelative = 0;
712 #else
713         if (filelen >= 2 && path[0] == '/')
714                 wasrelative = 0;
715 #endif
716         
717         if (wasrelative==1) {
718                 char cwd[FILE_MAXDIR + FILE_MAXFILE];
719                 BLI_getwdN(cwd); /* incase the full path to the blend isnt used */
720                 
721                 if (cwd[0] == '\0') {
722                         printf( "Could not get the current working directory - $PWD for an unknown reason.");
723                 } else {
724                         /* uses the blend path relative to cwd important for loading relative linked files.
725                         *
726                         * cwd should contain c:\ etc on win32 so the relbase can be NULL
727                         * relbase being NULL also prevents // being misunderstood as relative to the current
728                         * blend file which isnt a feature we want to use in this case since were dealing
729                         * with a path from the command line, rather then from inside Blender */
730                         
731                         char origpath[FILE_MAXDIR + FILE_MAXFILE];
732                         BLI_strncpy(origpath, path, FILE_MAXDIR + FILE_MAXFILE);
733                         
734                         BLI_make_file_string(NULL, path, cwd, origpath); 
735                 }
736         }
737         
738         return wasrelative;
739 }
740
741
742 /* copy di to fi, filename only */
743 void BLI_splitdirstring(char *di, char *fi)
744 {
745         char *lslash= BLI_last_slash(di);
746
747         if (lslash) {
748                 BLI_strncpy(fi, lslash+1, FILE_MAXFILE);
749                 *(lslash+1)=0;
750         } else {
751                 BLI_strncpy(fi, di, FILE_MAXFILE);
752                 di[0]= 0;
753         }
754 }
755
756 void BLI_getlastdir(const char* dir, char *last, int maxlen)
757 {
758         const char *s = dir;
759         const char *lslash = NULL;
760         const char *prevslash = NULL;
761         while (*s) {
762                 if ((*s == '\\') || (*s == '/')) {
763                         prevslash = lslash;
764                         lslash = s;
765                 }
766                 s++;
767         }
768         if (prevslash) {
769                 BLI_strncpy(last, prevslash+1, maxlen);
770         } else {
771                 BLI_strncpy(last, dir, maxlen);
772         }
773 }
774
775 char *BLI_gethome(void) {
776         #if !defined(WIN32)
777                 return getenv("HOME");
778
779         #else /* Windows */
780                 char * ret;
781                 static char dir[512];
782                 static char appdatapath[MAXPATHLEN];
783                 HRESULT hResult;
784
785                 /* Check for %HOME% env var */
786
787                 ret = getenv("HOME");
788                 if(ret) {
789                         sprintf(dir, "%s\\.blender", ret);
790                         if (BLI_exists(dir)) return dir;
791                 }
792
793                 /* else, check install dir (path containing blender.exe) */
794
795                 BLI_getInstallationDir(dir);
796
797                 if (BLI_exists(dir))
798                 {
799                         strcat(dir,"\\.blender");
800                         if (BLI_exists(dir)) return(dir);
801                 }
802
803                                 
804                 /* add user profile support for WIN 2K / NT */
805                 hResult = SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT, appdatapath);
806                 
807                 if (hResult == S_OK)
808                 {
809                         if (BLI_exists(appdatapath)) { /* from fop, also below... */
810                                 sprintf(dir, "%s\\Blender Foundation\\Blender", appdatapath);
811                                 BLI_recurdir_fileops(dir);
812                                 if (BLI_exists(dir)) {
813                                         strcat(dir,"\\.blender");
814                                         if(BLI_exists(dir)) return(dir);
815                                 }
816                         }
817                         hResult = SHGetFolderPath(NULL, CSIDL_COMMON_APPDATA, NULL, SHGFP_TYPE_CURRENT, appdatapath);
818                         if (hResult == S_OK)
819                         {
820                                 if (BLI_exists(appdatapath)) 
821                                 { /* from fop, also below... */
822                                         sprintf(dir, "%s\\Blender Foundation\\Blender", appdatapath);
823                                         BLI_recurdir_fileops(dir);
824                                         if (BLI_exists(dir)) {
825                                                 strcat(dir,"\\.blender");
826                                                 if(BLI_exists(dir)) return(dir);
827                                         }
828                                 }
829                         }
830                 }
831 #if 0
832                 ret = getenv("USERPROFILE");
833                 if (ret) {
834                         if (BLI_exists(ret)) { /* from fop, also below...  */
835                                 sprintf(dir, "%s\\Application Data\\Blender Foundation\\Blender", ret);
836                                 BLI_recurdir_fileops(dir);
837                                 if (BLI_exists(dir)) {
838                                         strcat(dir,"\\.blender");
839                                         if(BLI_exists(dir)) return(dir);
840                                 }
841                         }
842                 }
843 #endif
844
845                 /* 
846                    Saving in the Windows dir is less than desirable. 
847                    Use as a last resort ONLY! (aphex)
848                 */
849                 
850                 ret = getenv("WINDOWS");                
851                 if (ret) {
852                         if(BLI_exists(ret)) return ret;
853                 }
854
855                 ret = getenv("WINDIR"); 
856                 if (ret) {
857                         if(BLI_exists(ret)) return ret;
858                 }
859                 
860                 return "C:\\Temp";      /* sheesh! bad, bad, bad! (aphex) */
861         #endif
862 }
863
864 /* this function returns the path to a blender folder, if it exists,
865  * trying in this order:
866  *
867  * path_to_executable/release/folder_name (in svn)
868  * ./release/folder_name (in svn)
869  * $HOME/.blender/folder_name
870  * path_to_executable/.blender/folder_name
871  *
872  * returns NULL if none is found. */
873
874 char *BLI_gethome_folder(char *folder_name)
875 {
876         extern char bprogname[]; /* argv[0] from creator.c */
877         static char homedir[FILE_MAXDIR] = "";
878         static char fulldir[FILE_MAXDIR] = "";
879         char tmpdir[FILE_MAXDIR];
880         char bprogdir[FILE_MAXDIR];
881         char *s;
882         int i;
883
884         /* use argv[0] (bprogname) to get the path to the executable */
885         s = BLI_last_slash(bprogname);
886
887         i = s - bprogname + 1;
888         BLI_strncpy(bprogdir, bprogname, i);
889
890         /* try path_to_executable/release/folder_name (in svn) */
891         if (folder_name) {
892                 BLI_snprintf(tmpdir, sizeof(tmpdir), "release/%s", folder_name);
893                 BLI_make_file_string("/", fulldir, bprogdir, tmpdir);
894                 if (BLI_exists(fulldir)) return fulldir;
895                 else fulldir[0] = '\0';
896         }
897
898         /* try ./release/folder_name (in svn) */
899         if(folder_name) {
900                 BLI_snprintf(fulldir, sizeof(fulldir), "./release/%s", folder_name);
901                 if (BLI_exists(fulldir)) return fulldir;
902                 else fulldir[0] = '\0';
903         }
904
905         /* BLI_gethome() can return NULL if env vars are not set */
906         s = BLI_gethome();
907
908         if(!s) { /* bail if no $HOME */
909                 printf("$HOME is NOT set\n");
910                 return NULL;
911         }
912
913         if(strstr(s, ".blender"))
914                 BLI_strncpy(homedir, s, FILE_MAXDIR);
915         else
916                 BLI_make_file_string("/", homedir, s, ".blender");
917
918         /* if $HOME/.blender/folder_name exists, return it */
919         if(BLI_exists(homedir)) {
920                 if (folder_name) {
921                         BLI_make_file_string("/", fulldir, homedir, folder_name);
922                         if(BLI_exists(fulldir))
923                                 return fulldir;
924                 }
925                 else
926                         return homedir;
927         }
928         else
929                 homedir[0] = '\0';
930
931         /* using tmpdir to preserve homedir (if) found above:
932          * the ideal is to have a home dir with folder_name dir inside
933          * it, but if that isn't available, it's possible to
934          * have a 'broken' home dir somewhere and a folder_name dir in the
935          * svn sources */
936         BLI_make_file_string("/", tmpdir, bprogdir, ".blender");
937
938         if(BLI_exists(tmpdir)) {
939                 if(folder_name) {
940                         BLI_make_file_string("/", fulldir, tmpdir, folder_name);
941                         if(BLI_exists(fulldir)) {
942                                 BLI_strncpy(homedir, tmpdir, FILE_MAXDIR);
943                                 return fulldir;
944                         }
945                         else {
946                                 homedir[0] = '\0';
947                                 fulldir[0] = '\0';
948                         }
949                 }
950                 else return homedir;
951         }
952
953         return NULL;
954 }
955
956 void BLI_setenv(const char *env, const char*val)
957 {
958         /* SGI or free windows */
959 #if (defined(__sgi) || ((defined(WIN32) || defined(WIN64)) && defined(FREE_WINDOWS)))
960         char *envstr= malloc(sizeof(char) * (strlen(env) + strlen(val) + 2)); /* one for = another for \0 */
961
962         sprintf(envstr, "%s=%s", env, val);
963         putenv(envstr);
964         free(envstr);
965
966         /* non-free windows */
967 #elif (defined(WIN32) || defined(WIN64)) /* not free windows */
968         _putenv_s(env, val);
969 #else
970         /* linux/osx/bsd */
971         setenv(env, val, 1);
972 #endif
973 }
974
975 void BLI_clean(char *path)
976 {
977         if(path==0) return;
978 #ifdef WIN32
979         if(path && strlen(path)>2) {
980                 BLI_char_switch(path+2, '/', '\\');
981         }
982 #else
983         BLI_char_switch(path, '\\', '/');
984 #endif
985 }
986
987 void BLI_char_switch(char *string, char from, char to) 
988 {
989         if(string==0) return;
990         while (*string != 0) {
991                 if (*string == from) *string = to;
992                 string++;
993         }
994 }
995
996 void BLI_make_exist(char *dir) {
997         int a;
998
999         #ifdef WIN32
1000                 BLI_char_switch(dir, '/', '\\');
1001         #else
1002                 BLI_char_switch(dir, '\\', '/');
1003         #endif  
1004         
1005         a = strlen(dir);
1006         
1007 #ifdef WIN32    
1008         while(BLI_exists(dir) == 0){
1009                 a --;
1010                 while(dir[a] != '\\'){
1011                         a--;
1012                         if (a <= 0) break;
1013                 }
1014                 if (a >= 0) dir[a+1] = 0;
1015                 else {
1016                         /* defaulting to drive (usually 'C:') of Windows installation */
1017                         get_default_root(dir);
1018                         break;
1019                 }
1020         }
1021 #else
1022         while(BLI_exist(dir) == 0){
1023                 a --;
1024                 while(dir[a] != '/'){
1025                         a--;
1026                         if (a <= 0) break;
1027                 }
1028                 if (a >= 0) dir[a+1] = 0;
1029                 else {
1030                         strcpy(dir,"/");
1031                         break;
1032                 }
1033         }
1034 #endif
1035 }
1036
1037 void BLI_make_existing_file(char *name)
1038 {
1039         char di[FILE_MAXDIR], fi[FILE_MAXFILE];
1040         
1041         strcpy(di, name);
1042         BLI_splitdirstring(di, fi);
1043         
1044         /* test exist */
1045         if (BLI_exists(di) == 0) {
1046                 BLI_recurdir_fileops(di);
1047         }
1048 }
1049
1050
1051 void BLI_make_file_string(const char *relabase, char *string,  const char *dir, const char *file)
1052 {
1053         int sl;
1054
1055         if (!string || !dir || !file) return; /* We don't want any NULLs */
1056         
1057         string[0]= 0; /* ton */
1058
1059         /* we first push all slashes into unix mode, just to make sure we don't get
1060            any mess with slashes later on. -jesterKing */
1061         /* constant strings can be passed for those parameters - don't change them - elubie */
1062         /*
1063         BLI_char_switch(relabase, '\\', '/');
1064         BLI_char_switch(dir, '\\', '/');
1065         BLI_char_switch(file, '\\', '/');
1066         */
1067
1068         /* Resolve relative references */       
1069         if (relabase && dir[0] == '/' && dir[1] == '/') {
1070                 char *lslash;
1071                 
1072                 /* Get the file name, chop everything past the last slash (ie. the filename) */
1073                 strcpy(string, relabase);
1074                 
1075                 lslash= (strrchr(string, '/')>strrchr(string, '\\'))?strrchr(string, '/'):strrchr(string, '\\');
1076                 
1077                 if(lslash) *(lslash+1)= 0;
1078
1079                 dir+=2; /* Skip over the relative reference */
1080         }
1081 #ifdef WIN32
1082         else {
1083                 if (strlen(dir) >= 2 && dir[1] == ':' ) {
1084                         BLI_strncpy(string, dir, 3);
1085                         dir += 2;
1086                 }
1087                 else { /* no drive specified */
1088                         /* first option: get the drive from the relabase if it has one */
1089                         if (relabase && strlen(relabase) >= 2 && relabase[1] == ':' ) {
1090                                 BLI_strncpy(string, relabase, 3);       
1091                                 string[2] = '\\';
1092                                 string[3] = '\0';
1093                         }
1094                         else { /* we're out of luck here, guessing the first valid drive, usually c:\ */
1095                                 get_default_root(string);
1096                         }
1097                         
1098                         /* ignore leading slashes */
1099                         while (*dir == '/' || *dir == '\\') dir++;
1100                 }
1101         }
1102 #endif
1103
1104         strcat(string, dir);
1105
1106         /* Make sure string ends in one (and only one) slash */ 
1107         /* first trim all slashes from the end of the string */
1108         sl = strlen(string);
1109         while (sl>0 && ( string[sl-1] == '/' || string[sl-1] == '\\') ) {
1110                 string[sl-1] = '\0';
1111                 sl--;
1112         }
1113         /* since we've now removed all slashes, put back one slash at the end. */
1114         strcat(string, "/");
1115         
1116         while (*file && (*file == '/' || *file == '\\')) /* Trim slashes from the front of file */
1117                 file++;
1118                 
1119         strcat (string, file);
1120         
1121         /* Push all slashes to the system preferred direction */
1122         BLI_clean(string);
1123 }
1124
1125 int BLI_testextensie(const char *str, const char *ext)
1126 {
1127         short a, b;
1128         int retval;
1129
1130         a= strlen(str);
1131         b= strlen(ext);
1132
1133         if(a==0 || b==0 || b>=a) {
1134                 retval = 0;
1135         } else if (BLI_strcasecmp(ext, str + a - b)) {
1136                 retval = 0;     
1137         } else {
1138                 retval = 1;
1139         }
1140
1141         return (retval);
1142 }
1143
1144 /*
1145  * This is a simple version of BLI_split_dirfile that has the following advantages...
1146  * 
1147  * Converts "/foo/bar.txt" to "/foo/" and "bar.txt"
1148  * - wont change 'string'
1149  * - wont create any directories
1150  * - dosnt use CWD, or deal with relative paths.
1151  * - Only fill's in *dir and *file when they are non NULL
1152  * */
1153 void BLI_split_dirfile_basic(const char *string, char *dir, char *file)
1154 {
1155         int lslash=0, i = 0;
1156         for (i=0; string[i]!='\0'; i++) {
1157                 if (string[i]=='\\' || string[i]=='/')
1158                         lslash = i+1;
1159         }
1160         if (dir) {
1161                 if (lslash) {
1162                         BLI_strncpy( dir, string, lslash+1); /* +1 to include the slash and the last char */
1163                 } else {
1164                         dir[0] = '\0';
1165                 }
1166         }
1167         
1168         if (file) {
1169                 strcpy( file, string+lslash);
1170         }
1171 }
1172
1173
1174 /* Warning,
1175  * - May modify 'string' variable
1176  * - May create the directory if it dosnt exist
1177  * if this is not needed use BLI_split_dirfile_basic(...)
1178  */
1179 void BLI_split_dirfile(char *string, char *dir, char *file)
1180 {
1181         int a;
1182 #ifdef WIN32
1183         int sl;
1184         short is_relative = 0;
1185         char path[FILE_MAX];
1186 #endif
1187
1188         dir[0]= 0;
1189         file[0]= 0;
1190
1191 #ifdef WIN32
1192         BLI_strncpy(path, string, FILE_MAX);
1193         BLI_char_switch(path, '/', '\\'); /* make sure we have a valid path format */
1194         sl = strlen(path);
1195         if (sl) {
1196                 int len;
1197                 if (path[0] == '/' || path[0] == '\\') { 
1198                         BLI_strncpy(dir, path, FILE_MAXDIR);
1199                         if (sl > 1 && path[0] == '\\' && path[1] == '\\') is_relative = 1;
1200                 } else if (sl > 2 && path[1] == ':' && path[2] == '\\') {
1201                         BLI_strncpy(dir, path, FILE_MAXDIR);
1202                 } else {
1203                         BLI_getwdN(dir);
1204                         strcat(dir,"\\");
1205                         strcat(dir,path);
1206                         BLI_strncpy(path,dir,FILE_MAXDIR+FILE_MAXFILE);
1207                 }
1208                 
1209                 // BLI_exist doesn't recognize a slashed dirname as a dir
1210                 //  check if a trailing slash exists, and remove it. Do not do this
1211                 //  when we are already at root. -jesterKing
1212                 a = strlen(dir);
1213                 if(a>=4 && dir[a-1]=='\\') dir[a-1] = 0;
1214
1215                 if (is_relative) {
1216                         printf("WARNING: BLI_split_dirfile needs absolute dir\n");
1217                 }
1218                 else {
1219                         BLI_make_exist(dir);
1220                 }
1221
1222                 if (S_ISDIR(BLI_exist(dir))) {
1223
1224                         /* copy from end of string into file, to ensure filename itself isn't truncated 
1225                         if string is too long. (aphex) */
1226
1227                         len = FILE_MAXFILE - strlen(path);
1228
1229                         if (len < 0)
1230                                 BLI_strncpy(file,path + abs(len),FILE_MAXFILE);
1231                         else
1232                                 BLI_strncpy(file,path,FILE_MAXFILE);
1233                     
1234                         if (strrchr(path,'\\')) {
1235                                 BLI_strncpy(file,strrchr(path,'\\')+1,FILE_MAXFILE);
1236                         }
1237                         
1238                         if ( (a = strlen(dir)) ) {
1239                                 if (dir[a-1] != '\\') strcat(dir,"\\");
1240                         }
1241                 }
1242                 else {
1243                         a = strlen(dir) - 1;
1244                         while(a>0 && dir[a] != '\\') a--;
1245                         dir[a + 1] = 0;
1246                         BLI_strncpy(file, path + strlen(dir),FILE_MAXFILE);
1247                 }
1248
1249         }
1250         else {
1251                 /* defaulting to first valid drive hoping it's not empty CD and DVD drives */
1252                 get_default_root(dir);
1253                 file[0]=0;
1254         }
1255 #else
1256         if (strlen(string)) {
1257                 if (string[0] == '/') { 
1258                         strcpy(dir, string);
1259                 } else if (string[1] == ':' && string[2] == '\\') {
1260                         string+=2;
1261                         strcpy(dir, string);
1262                 } else {
1263                         BLI_getwdN(dir);
1264                         strcat(dir,"/");
1265                         strcat(dir,string);
1266                         strcpy((char *)string,dir);
1267                 }
1268
1269                 BLI_make_exist(dir);
1270                         
1271                 if (S_ISDIR(BLI_exist(dir))) {
1272                         strcpy(file,string + strlen(dir));
1273
1274                         if (strrchr(file,'/')) strcpy(file,strrchr(file,'/')+1);
1275                 
1276                         if ( (a = strlen(dir)) ) {
1277                                 if (dir[a-1] != '/') strcat(dir,"/");
1278                         }
1279                 }
1280                 else {
1281                         a = strlen(dir) - 1;
1282                         while(dir[a] != '/') a--;
1283                         dir[a + 1] = 0;
1284                         strcpy(file, string + strlen(dir));
1285                 }
1286         }
1287         else {
1288                 BLI_getwdN(dir);
1289                 strcat(dir, "/");
1290                 file[0] = 0;
1291         }
1292 #endif
1293 }
1294
1295 /* simple appending of filename to dir, does not check for valid path! */
1296 void BLI_join_dirfile(char *string, const char *dir, const char *file)
1297 {
1298         int sl_dir;
1299         
1300         if(string != dir) /* compare pointers */
1301                 BLI_strncpy(string, dir, FILE_MAX);
1302         
1303         sl_dir= BLI_add_slash(string);
1304         
1305         if (sl_dir <FILE_MAX) {
1306                 BLI_strncpy(string + sl_dir, file, FILE_MAX-sl_dir);
1307         }
1308 }
1309
1310 static int add_win32_extension(char *name)
1311 {
1312         int retval = 0;
1313         int type;
1314
1315         type = BLI_exist(name);
1316         if ((type == 0) || S_ISDIR(type)) {
1317 #ifdef _WIN32
1318                 char filename[FILE_MAXDIR+FILE_MAXFILE];
1319                 char ext[FILE_MAXDIR+FILE_MAXFILE];
1320                 char *extensions = getenv("PATHEXT");
1321                 if (extensions) {
1322                         char *temp;
1323                         do {
1324                                 strcpy(filename, name);
1325                                 temp = strstr(extensions, ";");
1326                                 if (temp) {
1327                                         strncpy(ext, extensions, temp - extensions);
1328                                         ext[temp - extensions] = 0;
1329                                         extensions = temp + 1;
1330                                         strcat(filename, ext);
1331                                 } else {
1332                                         strcat(filename, extensions);
1333                                 }
1334
1335                                 type = BLI_exist(filename);
1336                                 if (type && (! S_ISDIR(type))) {
1337                                         retval = 1;
1338                                         strcpy(name, filename);
1339                                         break;
1340                                 }
1341                         } while (temp);
1342                 }
1343 #endif
1344         } else {
1345                 retval = 1;
1346         }
1347
1348         return (retval);
1349 }
1350
1351 void BLI_where_am_i(char *fullname, const char *name)
1352 {
1353         char filename[FILE_MAXDIR+FILE_MAXFILE];
1354         char *path = NULL, *temp;
1355         
1356 #ifdef _WIN32
1357         char *seperator = ";";
1358         char slash = '\\';
1359 #else
1360         char *seperator = ":";
1361         char slash = '/';
1362 #endif
1363
1364         
1365 #ifdef __linux__
1366         /* linux uses binreloc since argv[0] is not relyable, call br_init( NULL ) first */
1367         path = br_find_exe( NULL );
1368         if (path) {
1369                 strcpy(fullname, path);
1370                 free(path);
1371                 return;
1372         }
1373 #endif
1374         
1375         /* unix and non linux */
1376         if (name && fullname && strlen(name)) {
1377                 strcpy(fullname, name);
1378                 if (name[0] == '.') {
1379                         // relative path, prepend cwd
1380                         BLI_getwdN(fullname);
1381                         
1382                         // not needed but avoids annoying /./ in name
1383                         if(name && name[0]=='.' && name[1]==slash)
1384                                 BLI_join_dirfile(fullname, fullname, name+2);
1385                         else
1386                                 BLI_join_dirfile(fullname, fullname, name);
1387                         
1388                         add_win32_extension(fullname);
1389                 } else if (BLI_last_slash(name)) {
1390                         // full path
1391                         strcpy(fullname, name);
1392                         add_win32_extension(fullname);
1393                 } else {
1394                         // search for binary in $PATH
1395                         path = getenv("PATH");
1396                         if (path) {
1397                                 do {
1398                                         temp = strstr(path, seperator);
1399                                         if (temp) {
1400                                                 strncpy(filename, path, temp - path);
1401                                                 filename[temp - path] = 0;
1402                                                 path = temp + 1;
1403                                         } else {
1404                                                 strncpy(filename, path, sizeof(filename));
1405                                         }
1406                                         BLI_join_dirfile(fullname, fullname, name);
1407                                         if (add_win32_extension(filename)) {
1408                                                 strcpy(fullname, filename);
1409                                                 break;
1410                                         }
1411                                 } while (temp);
1412                         }
1413                 }
1414 #ifndef NDEBUG
1415                 if (strcmp(name, fullname)) {
1416                         printf("guessing '%s' == '%s'\n", name, fullname);
1417                 }
1418 #endif
1419
1420 #ifdef _WIN32
1421                 // in windows change long filename to short filename because
1422                 // win2k doesn't know how to parse a commandline with lots of
1423                 // spaces and double-quotes. There's another solution to this
1424                 // with spawnv(P_WAIT, bprogname, argv) instead of system() but
1425                 // that's even uglier
1426                 GetShortPathName(fullname, fullname, FILE_MAXDIR+FILE_MAXFILE);
1427 #ifndef NDEBUG
1428                 printf("Shortname = '%s'\n", fullname);
1429 #endif
1430 #endif
1431         }
1432 }
1433
1434 void BLI_where_is_temp(char *fullname, int usertemp)
1435 {
1436         fullname[0] = '\0';
1437         
1438         if (usertemp && BLI_exists(U.tempdir)) {
1439                 strcpy(fullname, U.tempdir);
1440         }
1441         
1442         
1443 #ifdef WIN32
1444         if (fullname[0] == '\0') {
1445                 char *tmp = getenv("TEMP"); /* Windows */
1446                 if (tmp && BLI_exists(tmp)) {
1447                         strcpy(fullname, tmp);
1448                 }
1449         }
1450 #else
1451         /* Other OS's - Try TMP and TMPDIR */
1452         if (fullname[0] == '\0') {
1453                 char *tmp = getenv("TMP");
1454                 if (tmp && BLI_exists(tmp)) {
1455                         strcpy(fullname, tmp);
1456                 }
1457         }
1458         
1459         if (fullname[0] == '\0') {
1460                 char *tmp = getenv("TMPDIR");
1461                 if (tmp && BLI_exists(tmp)) {
1462                         strcpy(fullname, tmp);
1463                 }
1464         }
1465 #endif  
1466         
1467         if (fullname[0] == '\0') {
1468                 strcpy(fullname, "/tmp/");
1469         } else {
1470                 /* add a trailing slash if needed */
1471                 BLI_add_slash(fullname);
1472         }
1473 }
1474
1475 char *get_install_dir(void) {
1476         extern char bprogname[];
1477         char *tmpname = BLI_strdup(bprogname);
1478         char *cut;
1479
1480 #ifdef __APPLE__
1481         cut = strstr(tmpname, ".app");
1482         if (cut) cut[0] = 0;
1483 #endif
1484
1485         cut = BLI_last_slash(tmpname);
1486
1487         if (cut) {
1488                 cut[0] = 0;
1489                 return tmpname;
1490         } else {
1491                 MEM_freeN(tmpname);
1492                 return NULL;
1493         }
1494 }
1495
1496 /* 
1497  * returns absolute path to the app bundle
1498  * only useful on OS X 
1499  */
1500 #ifdef __APPLE__
1501 char* BLI_getbundle(void) {
1502         CFURLRef bundleURL;
1503         CFStringRef pathStr;
1504         static char path[MAXPATHLEN];
1505         CFBundleRef mainBundle = CFBundleGetMainBundle();
1506
1507         bundleURL = CFBundleCopyBundleURL(mainBundle);
1508         pathStr = CFURLCopyFileSystemPath(bundleURL, kCFURLPOSIXPathStyle);
1509         CFStringGetCString(pathStr, path, MAXPATHLEN, kCFStringEncodingASCII);
1510         return path;
1511 }
1512 #endif
1513
1514 #ifdef WITH_ICONV
1515 #include "iconv.h"
1516 #include "localcharset.h"
1517
1518 void BLI_string_to_utf8(char *original, char *utf_8, const char *code)
1519 {
1520         size_t inbytesleft=strlen(original);
1521         size_t outbytesleft=512;
1522         size_t rv=0;
1523         iconv_t cd;
1524         
1525         if (NULL == code) {
1526                 code = locale_charset();
1527         }
1528         cd=iconv_open("UTF-8", code);
1529
1530         if (cd == (iconv_t)(-1)) {
1531                 printf("iconv_open Error");
1532                 *utf_8='\0';
1533                 return ;
1534         }
1535         rv=iconv(cd, &original, &inbytesleft, &utf_8, &outbytesleft);
1536         if (rv == (size_t) -1) {
1537                 printf("iconv Error\n");
1538                 return ;
1539         }
1540         *utf_8 = '\0';
1541         iconv_close(cd);
1542 }
1543 #endif // WITH_ICONV
1544
1545