3 * various string, file, list operations.
8 * ***** BEGIN GPL LICENSE BLOCK *****
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.
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.
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.
24 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
25 * All rights reserved.
27 * The Original Code is: all of this file.
29 * Contributor(s): none yet.
31 * ***** END GPL LICENSE BLOCK *****
41 #include <math.h> /* for log10 */
43 #include "MEM_guardedalloc.h"
45 #include "DNA_listBase.h"
46 #include "DNA_userdef_types.h"
48 #include "BLI_blenlib.h"
49 #include "BLI_storage.h"
50 #include "BLI_storage_types.h"
51 #include "BLI_dynamiclist.h"
54 #include "BKE_utildefines.h"
72 #define _WIN32_IE 0x0501
76 #include "BLI_winstuff.h"
78 /* for duplicate_defgroup */
79 #if !(defined vsnprintf)
80 #define vsnprintf _vsnprintf
91 #include <sys/param.h>
92 #include <CoreFoundation/CoreFoundation.h>
101 static int add_win32_extension(char *name);
105 int BLI_stringdec(char *string, char *kop, char *start, unsigned short *numlen)
107 unsigned short len, len2, nums = 0, nume = 0;
110 len2 = len = strlen(string);
113 if (BLI_strncasecmp(string + len - 6, ".blend", 6) == 0) len -= 6;
114 else if (BLI_strncasecmp(string + len - 6, ".trace", 6) == 0) len -= 6;
118 if (BLI_strncasecmp(string + len - 9, ".blend.gz", 9) == 0) len -= 9;
123 /* handle .jf0 en .jf1 for jstreams */
124 if (BLI_strncasecmp(string + len - 4, ".jf", 3) == 0) len -= 4;
125 else if (BLI_strncasecmp(string + len - 4, ".tga", 4) == 0) len -= 4;
126 else if (BLI_strncasecmp(string + len - 4, ".jpg", 4) == 0) len -= 4;
127 else if (BLI_strncasecmp(string + len - 4, ".png", 4) == 0) len -= 4;
128 else if (BLI_strncasecmp(string + len - 4, ".txt", 4) == 0) len -= 4;
129 else if (BLI_strncasecmp(string + len - 4, ".cyc", 4) == 0) len -= 4;
130 else if (BLI_strncasecmp(string + len - 4, ".enh", 4) == 0) len -= 4;
131 else if (BLI_strncasecmp(string + len - 4, ".rgb", 4) == 0) len -= 4;
132 else if (BLI_strncasecmp(string + len - 4, ".psx", 4) == 0) len -= 4;
133 else if (BLI_strncasecmp(string + len - 4, ".ble", 4) == 0) len -= 4;
134 else if (BLI_strncasecmp(string + len - 4, ".exr", 4) == 0) len -= 4;
138 for (i = len - 1; i >= 0; i--) {
139 if (string[i] == '/') break;
140 if (isdigit(string[i])) {
155 if (start) strcpy(start,&string[nume+1]);
160 if (numlen) *numlen = nume-nums+1;
161 return ((int)atoi(&(string[nums])));
163 if (start) strcpy(start, string + len);
165 strncpy(kop, string, len);
168 if (numlen) *numlen=0;
173 void BLI_stringenc(char *string, char *kop, char *start, unsigned short numlen, int pic)
176 unsigned short len,i;
180 if (pic>0 || numlen==4) {
181 len= sprintf(numstr,"%d",pic);
183 for(i=len;i<numlen;i++){
186 strcat(string,numstr);
188 strcat(string, start);
192 void BLI_newname(char *name, int add)
194 char head[128], tail[128];
196 unsigned short digits;
198 pic = BLI_stringdec(name, head, tail, &digits);
200 /* are we going from 100 -> 99 or from 10 -> 9 */
201 if (add < 0 && digits < 4 && digits > 0) {
204 for (i = digits; i > 1; i--) exp *= 10;
205 if (pic >= exp && (pic + add) < exp) digits--;
210 if (digits==4 && pic<0) pic= 0;
211 BLI_stringenc(name, head, tail, digits, pic);
214 /* little helper macro for BLI_uniquename */
216 #define GIVE_STRADDR(data, offset) ( ((char *)data) + offset )
219 /* Generic function to set a unique name. It is only designed to be used in situations
220 * where the name is part of the struct, and also that the name is at most 128 chars long.
222 * For places where this is used, see constraint.c for example...
224 * name_offs: should be calculated using offsetof(structname, membername) macro from stddef.h
225 * len: maximum length of string (to prevent overflows, etc.)
226 * defname: the name that should be used by default if none is specified already
227 * delim: the character which acts as a delimeter between parts of the name
229 void BLI_uniquename(ListBase *list, void *vlink, char defname[], char delim, short name_offs, short len)
233 int number = 1, exists = 0;
236 /* Make sure length can be handled */
237 if ((len < 0) || (len > 128))
240 /* See if we are given an empty string */
241 if (ELEM(NULL, vlink, defname))
244 if (GIVE_STRADDR(vlink, name_offs) == '\0') {
245 /* give it default name first */
246 BLI_strncpy(GIVE_STRADDR(vlink, name_offs), defname, len);
249 /* See if we even need to do this */
253 for (link = list->first; link; link= link->next) {
255 if (!strcmp(GIVE_STRADDR(link, name_offs), GIVE_STRADDR(vlink, name_offs))) {
264 /* Strip off the suffix */
265 dot = strchr(GIVE_STRADDR(vlink, name_offs), delim);
269 for (number = 1; number <= 999; number++) {
270 BLI_snprintf(tempname, 128, "%s%c%03d", GIVE_STRADDR(vlink, name_offs), delim, number);
273 for (link= list->first; link; link= link->next) {
275 if (!strcmp(GIVE_STRADDR(link, name_offs), tempname)) {
282 BLI_strncpy(GIVE_STRADDR(vlink, name_offs), tempname, len);
288 /* ******************** string encoding ***************** */
290 /* This is quite an ugly function... its purpose is to
291 * take the dir name, make it absolute, and clean it up, replacing
292 * excess file entry stuff (like /tmp/../tmp/../)
293 * note that dir isn't protected for max string names...
295 * If relbase is NULL then its ignored
298 void BLI_cleanup_dir(const char *relabase, char *dir)
300 BLI_cleanup_file(relabase, dir);
305 void BLI_cleanup_file(const char *relabase, char *dir)
310 BLI_convertstringcode(dir, relabase);
312 if (dir[0]=='/' && dir[1]=='/') {
314 return; /* path is "//" - cant clean it */
316 dir = dir+2; /* skip the first // */
321 * memmove( start, eind, strlen(eind)+1 );
323 * strcpy( start, eind );
324 * except strcpy should not be used because there is overlap,
325 * so use memmove's slightly more obscure syntax - Campbell
330 /* Note, this should really be moved to the file selector,
331 * since this function is used in many areas */
332 if(strcmp(dir, ".")==0) { /* happens for example in FILE_MAIN */
333 get_default_root(dir);
337 while ( (start = strstr(dir, "\\..\\")) ) {
338 eind = start + strlen("\\..\\") - 1;
341 if (dir[a] == '\\') break;
347 memmove( dir+a, eind, strlen(eind)+1 );
351 while ( (start = strstr(dir,"\\.\\")) ){
352 eind = start + strlen("\\.\\") - 1;
353 memmove( start, eind, strlen(eind)+1 );
356 while ( (start = strstr(dir,"\\\\" )) ){
357 eind = start + strlen("\\\\") - 1;
358 memmove( start, eind, strlen(eind)+1 );
361 if((a = strlen(dir))){ /* remove the '\\' at the end */
362 while(a>0 && dir[a-1] == '\\'){
368 if(dir[0]=='.') { /* happens, for example in FILE_MAIN */
374 while ( (start = strstr(dir, "/../")) ) {
375 eind = start + strlen("/../") - 1;
378 if (dir[a] == '/') break;
384 memmove( dir+a, eind, strlen(eind)+1 );
388 while ( (start = strstr(dir,"/./")) ){
389 eind = start + strlen("/./") - 1;
390 memmove( start, eind, strlen(eind)+1 );
393 while ( (start = strstr(dir,"//" )) ){
394 eind = start + strlen("//") - 1;
395 memmove( start, eind, strlen(eind)+1 );
398 if( (a = strlen(dir)) ){ /* remove all '/' at the end */
399 while(dir[a-1] == '/'){
409 void BLI_makestringcode(const char *relfile, char *file)
414 char temp[FILE_MAXDIR+FILE_MAXFILE];
415 char res[FILE_MAXDIR+FILE_MAXFILE];
417 /* if file is already relative, bail out */
418 if(file[0]=='/' && file[1]=='/') return;
420 /* also bail out if relative path is not set */
421 if (relfile[0] == 0) return;
424 if (strlen(relfile) > 2 && relfile[1] != ':') {
426 /* fix missing volume name in relative base,
427 can happen with old .Blog files */
428 get_default_root(temp);
430 if (relfile[0] != '\\' && relfile[0] != '/') {
433 BLI_strncpy(ptemp, relfile, FILE_MAXDIR + FILE_MAXFILE-3);
435 BLI_strncpy(temp, relfile, FILE_MAXDIR + FILE_MAXFILE);
438 if (strlen(file) > 2) {
439 if ( temp[1] == ':' && file[1] == ':' && temp[0] != file[0] )
443 BLI_strncpy(temp, relfile, FILE_MAX);
446 BLI_char_switch(temp, '\\', '/');
447 BLI_char_switch(file, '\\', '/');
449 /* remove /./ which confuse the following slash counting... */
450 BLI_cleanup_file(NULL, file);
451 BLI_cleanup_file(NULL, temp);
453 /* the last slash in the file indicates where the path part ends */
454 lslash = BLI_last_slash(temp);
458 /* find the prefix of the filename that is equal for both filenames.
459 This is replaced by the two slashes at the beginning */
465 /* we might have passed the slash when the beginning of a dir matches
466 so we rewind. Only check on the actual filename
469 while ( (q >= file) && (*q != '/') ) { --q; --p; }
471 else if (*p != '/') {
472 while ( (p >= temp) && (*p != '/') ) { --p; --q; }
477 /* p now points to the slash that is at the beginning of the part
478 where the path is different from the relative path.
479 We count the number of directories we need to go up in the
480 hierarchy to arrive at the common 'prefix' of the path
482 while (p && p < lslash) {
488 strcat(res, q+1); /* don't copy the slash at the beginning */
491 BLI_char_switch(res+2, '/', '\\');
497 int BLI_parent_dir(char *path)
500 static char *parent_dir="..\\";
502 static char *parent_dir="../";
504 char tmp[FILE_MAXDIR+FILE_MAXFILE+4];
505 BLI_strncpy(tmp, path, sizeof(tmp));
507 strcat(tmp, parent_dir);
508 BLI_cleanup_dir(NULL, tmp);
510 if (!BLI_testextensie(tmp, parent_dir)) {
511 BLI_strncpy(path, tmp, sizeof(tmp));
518 int BLI_convertstringframe(char *path, int frame)
520 int ch_sta, ch_end, i;
521 /* Insert current frame: file### -> file001 */
523 for (i = 0; path[i] != '\0'; i++) {
524 if (path[i] == '\\' || path[i] == '/') {
525 ch_end = 0; /* this is a directory name, dont use any hashes we found */
526 } else if (path[i] == '#') {
529 while (path[ch_end] == '#') {
532 i = ch_end-1; /* keep searching */
534 /* dont break, there may be a slash after this that invalidates the previous #'s */
537 if (ch_end) { /* warning, ch_end is the last # +1 */
538 /* Add the frame number? */
539 short numlen, hashlen;
542 char format[16]; /* 6 is realistically the maxframe (300000), so 8 should be enough, but 16 to be safe. */
543 if (((ch_end-1)-ch_sta) >= 16) {
544 ch_end = ch_sta+15; /* disallow values longer then 'format' can hold */
549 numlen = 1 + (int)log10((double)frame); /* this is the number of chars in the number */
550 hashlen = ch_end - ch_sta;
552 sprintf(format, "%d", frame);
554 if (numlen==hashlen) { /* simple case */
555 memcpy(tmp+ch_sta, format, numlen);
556 } else if (numlen < hashlen) {
557 memcpy(tmp+ch_sta + (hashlen-numlen), format, numlen); /*dont copy the string terminator */
558 memset(tmp+ch_sta, '0', hashlen-numlen);
560 /* number is longer then number of #'s */
561 if (tmp[ch_end] == '\0') { /* hashes are last, no need to move any string*/
562 /* bad juju - not testing string length here :/ */
563 memcpy(tmp+ch_sta, format, numlen+1); /* add 1 to get the string terminator \0 */
565 /* we need to move the end characters, reuse i */
568 i = strlen(tmp); /* +1 to copy the string terminator */
569 j = i + (numlen-hashlen); /* from/to */
571 while (i >= ch_end) {
576 memcpy(tmp + ch_sta, format, numlen);
586 int BLI_convertstringcode(char *path, const char *basepath)
588 int wasrelative = (strncmp(path, "//", 2)==0);
592 char vol[3] = {'\0', '\0', '\0'};
594 BLI_strncpy(vol, path, 3);
595 /* we are checking here if we have an absolute path that is not in the current
596 blend file as a lib main - we are basically checking for the case that a
597 UNIX root '/' is passed.
599 if (!wasrelative && (vol[1] != ':' && (vol[0] == '\0' || vol[0] == '/' || vol[0] == '\\'))) {
601 get_default_root(tmp);
602 // get rid of the slashes at the beginning of the path
603 while (*p == '\\' || *p == '/') {
609 BLI_strncpy(tmp, path, FILE_MAX);
612 BLI_strncpy(tmp, path, FILE_MAX);
614 /* Check for loading a windows path on a posix system
615 * in this case, there is no use in trying C:/ since it
616 * will never exist on a unix os.
618 * Add a / prefix and lowercase the driveletter, remove the :
619 * C:\foo.JPG -> /c/foo.JPG */
621 if (isalpha(tmp[0]) && tmp[1] == ':' && (tmp[2]=='\\' || tmp[2]=='/') ) {
622 tmp[1] = tolower(tmp[0]); /* replace ':' with driveletter */
624 /* '\' the slash will be converted later */
629 BLI_strncpy(base, basepath, FILE_MAX);
631 BLI_cleanup_file(NULL, base);
633 /* push slashes into unix mode - strings entering this part are
634 potentially messed up: having both back- and forward slashes.
635 Here we push into one conform direction, and at the end we
636 push them into the system specific dir. This ensures uniformity
637 of paths and solving some problems (and prevent potential future
638 ones) -jesterKing. */
639 BLI_char_switch(tmp, '\\', '/');
640 BLI_char_switch(base, '\\', '/');
642 /* Paths starting with // will get the blend file as their base,
643 * this isnt standard in any os but is uesed in blender all over the place */
645 char *lslash= BLI_last_slash(base);
647 int baselen= (int) (lslash-base) + 1;
648 /* use path for for temp storage here, we copy back over it right away */
649 BLI_strncpy(path, tmp+2, FILE_MAX);
651 memcpy(tmp, base, baselen);
652 strcpy(tmp+baselen, path);
662 if ( path[strlen(path)-1]=='/') {
663 BLI_cleanup_dir(NULL, path);
665 BLI_cleanup_file(NULL, path);
670 /* skip first two chars, which in case of
671 absolute path will be drive:/blabla and
672 in case of relpath //blabla/. So relpath
673 // will be retained, rest will be nice and
674 shiny win32 backward slashes :) -jesterKing
676 BLI_char_switch(path+2, '/', '\\');
684 * Should only be done with command line paths.
685 * this is NOT somthing blenders internal paths support like the // prefix
687 int BLI_convertstringcwd(char *path)
690 int filelen = strlen(path);
693 if (filelen >= 3 && path[1] == ':' && (path[2] == '\\' || path[2] == '/'))
696 if (filelen >= 2 && path[0] == '/')
700 if (wasrelative==1) {
701 char cwd[FILE_MAXDIR + FILE_MAXFILE];
702 BLI_getwdN(cwd); /* incase the full path to the blend isnt used */
704 if (cwd[0] == '\0') {
705 printf( "Could not get the current working directory - $PWD for an unknown reason.");
707 /* uses the blend path relative to cwd important for loading relative linked files.
709 * cwd should contain c:\ etc on win32 so the relbase can be NULL
710 * relbase being NULL also prevents // being misunderstood as relative to the current
711 * blend file which isnt a feature we want to use in this case since were dealing
712 * with a path from the command line, rather then from inside Blender */
714 char origpath[FILE_MAXDIR + FILE_MAXFILE];
715 BLI_strncpy(origpath, path, FILE_MAXDIR + FILE_MAXFILE);
717 BLI_make_file_string(NULL, path, cwd, origpath);
725 /* copy di to fi, filename only */
726 void BLI_splitdirstring(char *di, char *fi)
728 char *lslash= BLI_last_slash(di);
731 BLI_strncpy(fi, lslash+1, FILE_MAXFILE);
734 BLI_strncpy(fi, di, FILE_MAXFILE);
739 char *BLI_gethome(void) {
741 return getenv("HOME");
745 static char dir[512];
746 static char appdatapath[MAXPATHLEN];
749 /* Check for %HOME% env var */
751 ret = getenv("HOME");
753 sprintf(dir, "%s\\.blender", ret);
754 if (BLI_exists(dir)) return dir;
757 /* else, check install dir (path containing blender.exe) */
759 BLI_getInstallationDir(dir);
763 strcat(dir,"\\.blender");
764 if (BLI_exists(dir)) return(dir);
768 /* add user profile support for WIN 2K / NT */
769 hResult = SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT, appdatapath);
773 if (BLI_exists(appdatapath)) { /* from fop, also below... */
774 sprintf(dir, "%s\\Blender Foundation\\Blender", appdatapath);
775 BLI_recurdir_fileops(dir);
776 if (BLI_exists(dir)) {
777 strcat(dir,"\\.blender");
778 if(BLI_exists(dir)) return(dir);
781 hResult = SHGetFolderPath(NULL, CSIDL_COMMON_APPDATA, NULL, SHGFP_TYPE_CURRENT, appdatapath);
784 if (BLI_exists(appdatapath))
785 { /* from fop, also below... */
786 sprintf(dir, "%s\\Blender Foundation\\Blender", appdatapath);
787 BLI_recurdir_fileops(dir);
788 if (BLI_exists(dir)) {
789 strcat(dir,"\\.blender");
790 if(BLI_exists(dir)) return(dir);
796 ret = getenv("USERPROFILE");
798 if (BLI_exists(ret)) { /* from fop, also below... */
799 sprintf(dir, "%s\\Application Data\\Blender Foundation\\Blender", ret);
800 BLI_recurdir_fileops(dir);
801 if (BLI_exists(dir)) {
802 strcat(dir,"\\.blender");
803 if(BLI_exists(dir)) return(dir);
810 Saving in the Windows dir is less than desirable.
811 Use as a last resort ONLY! (aphex)
814 ret = getenv("WINDOWS");
816 if(BLI_exists(ret)) return ret;
819 ret = getenv("WINDIR");
821 if(BLI_exists(ret)) return ret;
824 return "C:\\Temp"; /* sheesh! bad, bad, bad! (aphex) */
828 /* this function returns the path to a blender folder, if it exists,
829 * trying in this order:
831 * path_to_executable/release/folder_name (in svn)
832 * ./release/folder_name (in svn)
833 * $HOME/.blender/folder_name
834 * path_to_executable/.blender/folder_name
836 * returns NULL if none is found. */
838 char *BLI_gethome_folder(char *folder_name)
840 extern char bprogname[]; /* argv[0] from creator.c */
841 static char homedir[FILE_MAXDIR] = "";
842 static char fulldir[FILE_MAXDIR] = "";
843 char tmpdir[FILE_MAXDIR];
844 char bprogdir[FILE_MAXDIR];
848 /* use argv[0] (bprogname) to get the path to the executable */
849 s = BLI_last_slash(bprogname);
851 i = s - bprogname + 1;
852 BLI_strncpy(bprogdir, bprogname, i);
854 /* try path_to_executable/release/folder_name (in svn) */
856 BLI_snprintf(tmpdir, sizeof(tmpdir), "release/%s", folder_name);
857 BLI_make_file_string("/", fulldir, bprogdir, tmpdir);
858 if (BLI_exists(fulldir)) return fulldir;
859 else fulldir[0] = '\0';
862 /* try ./release/folder_name (in svn) */
864 BLI_snprintf(fulldir, sizeof(fulldir), "./release/%s", folder_name);
865 if (BLI_exists(fulldir)) return fulldir;
866 else fulldir[0] = '\0';
869 /* BLI_gethome() can return NULL if env vars are not set */
872 if(!s) { /* bail if no $HOME */
873 printf("$HOME is NOT set\n");
877 if(strstr(s, ".blender"))
878 BLI_strncpy(homedir, s, FILE_MAXDIR);
880 BLI_make_file_string("/", homedir, s, ".blender");
882 /* if $HOME/.blender/folder_name exists, return it */
883 if(BLI_exists(homedir)) {
885 BLI_make_file_string("/", fulldir, homedir, folder_name);
886 if(BLI_exists(fulldir))
895 /* using tmpdir to preserve homedir (if) found above:
896 * the ideal is to have a home dir with folder_name dir inside
897 * it, but if that isn't available, it's possible to
898 * have a 'broken' home dir somewhere and a folder_name dir in the
900 BLI_make_file_string("/", tmpdir, bprogdir, ".blender");
902 if(BLI_exists(tmpdir)) {
904 BLI_make_file_string("/", fulldir, tmpdir, folder_name);
905 if(BLI_exists(fulldir)) {
906 BLI_strncpy(homedir, tmpdir, FILE_MAXDIR);
921 void BLI_clean(char *path)
925 if(path && strlen(path)>2) {
926 BLI_char_switch(path+2, '/', '\\');
929 BLI_char_switch(path, '\\', '/');
933 void BLI_char_switch(char *string, char from, char to)
935 if(string==0) return;
936 while (*string != 0) {
937 if (*string == from) *string = to;
942 void BLI_make_exist(char *dir) {
946 BLI_char_switch(dir, '/', '\\');
948 BLI_char_switch(dir, '\\', '/');
954 while(BLI_exists(dir) == 0){
956 while(dir[a] != '\\'){
960 if (a >= 0) dir[a+1] = 0;
962 /* defaulting to drive (usually 'C:') of Windows installation */
963 get_default_root(dir);
968 while(BLI_exist(dir) == 0){
970 while(dir[a] != '/'){
974 if (a >= 0) dir[a+1] = 0;
983 void BLI_make_existing_file(char *name)
985 char di[FILE_MAXDIR], fi[FILE_MAXFILE];
988 BLI_splitdirstring(di, fi);
991 if (BLI_exists(di) == 0) {
992 BLI_recurdir_fileops(di);
997 void BLI_make_file_string(const char *relabase, char *string, const char *dir, const char *file)
1001 if (!string || !dir || !file) return; /* We don't want any NULLs */
1003 string[0]= 0; /* ton */
1005 /* we first push all slashes into unix mode, just to make sure we don't get
1006 any mess with slashes later on. -jesterKing */
1007 /* constant strings can be passed for those parameters - don't change them - elubie */
1009 BLI_char_switch(relabase, '\\', '/');
1010 BLI_char_switch(dir, '\\', '/');
1011 BLI_char_switch(file, '\\', '/');
1014 /* Resolve relative references */
1015 if (relabase && dir[0] == '/' && dir[1] == '/') {
1018 /* Get the file name, chop everything past the last slash (ie. the filename) */
1019 strcpy(string, relabase);
1021 lslash= (strrchr(string, '/')>strrchr(string, '\\'))?strrchr(string, '/'):strrchr(string, '\\');
1023 if(lslash) *(lslash+1)= 0;
1025 dir+=2; /* Skip over the relative reference */
1029 if (strlen(dir) >= 2 && dir[1] == ':' ) {
1030 BLI_strncpy(string, dir, 3);
1033 else { /* no drive specified */
1034 /* first option: get the drive from the relabase if it has one */
1035 if (relabase && strlen(relabase) >= 2 && relabase[1] == ':' ) {
1036 BLI_strncpy(string, relabase, 3);
1040 else { /* we're out of luck here, guessing the first valid drive, usually c:\ */
1041 get_default_root(string);
1044 /* ignore leading slashes */
1045 while (*dir == '/' || *dir == '\\') dir++;
1050 strcat(string, dir);
1052 /* Make sure string ends in one (and only one) slash */
1053 /* first trim all slashes from the end of the string */
1054 sl = strlen(string);
1055 while (sl>0 && ( string[sl-1] == '/' || string[sl-1] == '\\') ) {
1056 string[sl-1] = '\0';
1059 /* since we've now removed all slashes, put back one slash at the end. */
1060 strcat(string, "/");
1062 while (*file && (*file == '/' || *file == '\\')) /* Trim slashes from the front of file */
1065 strcat (string, file);
1067 /* Push all slashes to the system preferred direction */
1071 int BLI_testextensie(const char *str, const char *ext)
1079 if(a==0 || b==0 || b>=a) {
1081 } else if (BLI_strcasecmp(ext, str + a - b)) {
1091 * This is a simple version of BLI_split_dirfile that has the following advantages...
1093 * Converts "/foo/bar.txt" to "/foo/" and "bar.txt"
1094 * - wont change 'string'
1095 * - wont create any directories
1096 * - dosnt use CWD, or deal with relative paths.
1097 * - Only fill's in *dir and *file when they are non NULL
1099 void BLI_split_dirfile_basic(const char *string, char *dir, char *file)
1101 int lslash=0, i = 0;
1102 for (i=0; string[i]!='\0'; i++) {
1103 if (string[i]=='\\' || string[i]=='/')
1108 BLI_strncpy( dir, string, lslash+1); /* +1 to include the slash and the last char */
1115 strcpy( file, string+lslash);
1121 * - May modify 'string' variable
1122 * - May create the directory if it dosnt exist
1123 * if this is not needed use BLI_split_dirfile_basic(...)
1125 void BLI_split_dirfile(char *string, char *dir, char *file)
1130 short is_relative = 0;
1131 char path[FILE_MAX];
1138 BLI_strncpy(path, string, FILE_MAX);
1139 BLI_char_switch(path, '/', '\\'); /* make sure we have a valid path format */
1143 if (path[0] == '/' || path[0] == '\\') {
1144 BLI_strncpy(dir, path, FILE_MAXDIR);
1145 if (sl > 1 && path[0] == '\\' && path[1] == '\\') is_relative = 1;
1146 } else if (sl > 2 && path[1] == ':' && path[2] == '\\') {
1147 BLI_strncpy(dir, path, FILE_MAXDIR);
1152 BLI_strncpy(path,dir,FILE_MAXDIR+FILE_MAXFILE);
1155 // BLI_exist doesn't recognize a slashed dirname as a dir
1156 // check if a trailing slash exists, and remove it. Do not do this
1157 // when we are already at root. -jesterKing
1159 if(a>=4 && dir[a-1]=='\\') dir[a-1] = 0;
1162 printf("WARNING: BLI_split_dirfile needs absolute dir\n");
1165 BLI_make_exist(dir);
1168 if (S_ISDIR(BLI_exist(dir))) {
1170 /* copy from end of string into file, to ensure filename itself isn't truncated
1171 if string is too long. (aphex) */
1173 len = FILE_MAXFILE - strlen(path);
1176 BLI_strncpy(file,path + abs(len),FILE_MAXFILE);
1178 BLI_strncpy(file,path,FILE_MAXFILE);
1180 if (strrchr(path,'\\')) {
1181 BLI_strncpy(file,strrchr(path,'\\')+1,FILE_MAXFILE);
1184 if ( (a = strlen(dir)) ) {
1185 if (dir[a-1] != '\\') strcat(dir,"\\");
1189 a = strlen(dir) - 1;
1190 while(a>0 && dir[a] != '\\') a--;
1192 BLI_strncpy(file, path + strlen(dir),FILE_MAXFILE);
1197 /* defaulting to first valid drive hoping it's not empty CD and DVD drives */
1198 get_default_root(dir);
1202 if (strlen(string)) {
1203 if (string[0] == '/') {
1204 strcpy(dir, string);
1205 } else if (string[1] == ':' && string[2] == '\\') {
1207 strcpy(dir, string);
1212 strcpy((char *)string,dir);
1215 BLI_make_exist(dir);
1217 if (S_ISDIR(BLI_exist(dir))) {
1218 strcpy(file,string + strlen(dir));
1220 if (strrchr(file,'/')) strcpy(file,strrchr(file,'/')+1);
1222 if ( (a = strlen(dir)) ) {
1223 if (dir[a-1] != '/') strcat(dir,"/");
1227 a = strlen(dir) - 1;
1228 while(dir[a] != '/') a--;
1230 strcpy(file, string + strlen(dir));
1241 /* simple appending of filename to dir, does not check for valid path! */
1242 void BLI_join_dirfile(char *string, const char *dir, const char *file)
1244 int sl_dir = strlen(dir);
1245 BLI_strncpy(string, dir, FILE_MAX);
1246 if (sl_dir > FILE_MAX-1) sl_dir = FILE_MAX-1;
1248 /* only add seperator if needed */
1250 if (string[sl_dir-1] != '\\') {
1251 string[sl_dir] = '\\';
1255 if (string[sl_dir-1] != '/') {
1256 string[sl_dir] = '/';
1261 if (sl_dir <FILE_MAX) {
1262 BLI_strncpy(string + sl_dir, file, FILE_MAX-sl_dir);
1266 static int add_win32_extension(char *name)
1271 type = BLI_exist(name);
1272 if ((type == 0) || S_ISDIR(type)) {
1274 char filename[FILE_MAXDIR+FILE_MAXFILE];
1275 char ext[FILE_MAXDIR+FILE_MAXFILE];
1276 char *extensions = getenv("PATHEXT");
1280 strcpy(filename, name);
1281 temp = strstr(extensions, ";");
1283 strncpy(ext, extensions, temp - extensions);
1284 ext[temp - extensions] = 0;
1285 extensions = temp + 1;
1286 strcat(filename, ext);
1288 strcat(filename, extensions);
1291 type = BLI_exist(filename);
1292 if (type && (! S_ISDIR(type))) {
1294 strcpy(name, filename);
1307 void BLI_where_am_i(char *fullname, const char *name)
1309 char filename[FILE_MAXDIR+FILE_MAXFILE];
1310 char *path = NULL, *temp;
1313 char *seperator = ";";
1316 char *seperator = ":";
1322 /* linux uses binreloc since argv[0] is not relyable, call br_init( NULL ) first */
1323 path = br_find_exe( NULL );
1325 strcpy(fullname, path);
1331 /* unix and non linux */
1332 if (name && fullname && strlen(name)) {
1333 strcpy(fullname, name);
1334 if (name[0] == '.') {
1335 // relative path, prepend cwd
1336 BLI_getwdN(fullname);
1337 len = strlen(fullname);
1338 if (len && fullname[len -1] != slash[0]) {
1339 strcat(fullname, slash);
1341 strcat(fullname, name);
1342 add_win32_extension(fullname);
1343 } else if (BLI_last_slash(name)) {
1345 strcpy(fullname, name);
1346 add_win32_extension(fullname);
1348 // search for binary in $PATH
1349 path = getenv("PATH");
1352 temp = strstr(path, seperator);
1354 strncpy(filename, path, temp - path);
1355 filename[temp - path] = 0;
1358 strncpy(filename, path, sizeof(filename));
1360 len = strlen(filename);
1361 if (len && filename[len - 1] != slash[0]) {
1362 strcat(filename, slash);
1364 strcat(filename, name);
1365 if (add_win32_extension(filename)) {
1366 strcpy(fullname, filename);
1373 if (strcmp(name, fullname)) {
1374 printf("guessing '%s' == '%s'\n", name, fullname);
1379 // in windows change long filename to short filename because
1380 // win2k doesn't know how to parse a commandline with lots of
1381 // spaces and double-quotes. There's another solution to this
1382 // with spawnv(P_WAIT, bprogname, argv) instead of system() but
1383 // that's even uglier
1384 GetShortPathName(fullname, fullname, FILE_MAXDIR+FILE_MAXFILE);
1386 printf("Shortname = '%s'\n", fullname);
1392 void BLI_where_is_temp(char *fullname, int usertemp)
1396 if (usertemp && BLI_exists(U.tempdir)) {
1397 strcpy(fullname, U.tempdir);
1402 if (fullname[0] == '\0') {
1403 char *tmp = getenv("TEMP"); /* Windows */
1404 if (tmp && BLI_exists(tmp)) {
1405 strcpy(fullname, tmp);
1409 /* Other OS's - Try TMP and TMPDIR */
1410 if (fullname[0] == '\0') {
1411 char *tmp = getenv("TMP");
1412 if (tmp && BLI_exists(tmp)) {
1413 strcpy(fullname, tmp);
1417 if (fullname[0] == '\0') {
1418 char *tmp = getenv("TMPDIR");
1419 if (tmp && BLI_exists(tmp)) {
1420 strcpy(fullname, tmp);
1425 if (fullname[0] == '\0') {
1426 strcpy(fullname, "/tmp/");
1428 /* add a trailing slash if needed */
1429 BLI_add_slash(fullname);
1433 char *get_install_dir(void) {
1434 extern char bprogname[];
1435 char *tmpname = BLI_strdup(bprogname);
1439 cut = strstr(tmpname, ".app");
1440 if (cut) cut[0] = 0;
1443 cut = BLI_last_slash(tmpname);
1455 * returns absolute path to the app bundle
1456 * only useful on OS X
1459 char* BLI_getbundle(void) {
1461 CFStringRef pathStr;
1462 static char path[MAXPATHLEN];
1463 CFBundleRef mainBundle = CFBundleGetMainBundle();
1465 bundleURL = CFBundleCopyBundleURL(mainBundle);
1466 pathStr = CFURLCopyFileSystemPath(bundleURL, kCFURLPOSIXPathStyle);
1467 CFStringGetCString(pathStr, path, MAXPATHLEN, kCFStringEncodingASCII);
1474 #include "localcharset.h"
1476 void BLI_string_to_utf8(char *original, char *utf_8, const char *code)
1478 size_t inbytesleft=strlen(original);
1479 size_t outbytesleft=512;
1484 code = locale_charset();
1486 cd=iconv_open("UTF-8", code);
1488 if (cd == (iconv_t)(-1)) {
1489 printf("iconv_open Error");
1493 rv=iconv(cd, &original, &inbytesleft, &utf_8, &outbytesleft);
1494 if (rv == (size_t) -1) {
1495 printf("iconv Error\n");
1501 #endif // WITH_ICONV