diff options
author | Campbell Barton <ideasman42@gmail.com> | 2009-12-13 17:56:45 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2009-12-13 17:56:45 +0300 |
commit | abe8c09b8a98f8a4b71e47324b2c6b12624d5440 (patch) | |
tree | 5abfe161b878b35f8f9f908ab6ea29a8166ddff6 /source/blender/blenlib/intern/path_util.c | |
parent | 7fc4ab2aab403e5db27c7dc7097c8db8afc2cfe8 (diff) |
* renamed BKE_sequence.h and sequence.c --> sequencer
* renamed util.c --> path_util.c since there are more then 1 of these files which makes setting breakpoints annoying.
Diffstat (limited to 'source/blender/blenlib/intern/path_util.c')
-rw-r--r-- | source/blender/blenlib/intern/path_util.c | 1586 |
1 files changed, 1586 insertions, 0 deletions
diff --git a/source/blender/blenlib/intern/path_util.c b/source/blender/blenlib/intern/path_util.c new file mode 100644 index 00000000000..5ff4dfe4e96 --- /dev/null +++ b/source/blender/blenlib/intern/path_util.c @@ -0,0 +1,1586 @@ +/* util.c + * + * various string, file, list operations. + * + * + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + * + */ + +#include <stdio.h> +#include <fcntl.h> +#include <ctype.h> +#include <string.h> +#include <stdlib.h> +#include <stdarg.h> +#include <math.h> /* for log10 */ + +#include "MEM_guardedalloc.h" + +#include "DNA_listBase.h" +#include "DNA_userdef_types.h" + +#include "BLI_blenlib.h" +#include "BLI_storage.h" +#include "BLI_storage_types.h" +#include "BLI_dynamiclist.h" + +#include "BLI_util.h" +#include "BKE_utildefines.h" + + + + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#ifndef WIN32 +#include <unistd.h> +#else +#include <io.h> +#endif + +#ifdef WIN32 + +#ifdef _WIN32_IE +#undef _WIN32_IE +#endif +#define _WIN32_IE 0x0501 +#include <windows.h> +#include <shlobj.h> + +#include "BLI_winstuff.h" + +#endif + + +#ifndef WIN32 +#include <sys/time.h> +#endif + +#ifdef __APPLE__ +#include <sys/param.h> +#include <CoreFoundation/CoreFoundation.h> +#endif + +#ifdef __linux__ +#include "binreloc.h" +#endif + +/* local */ + +static int add_win32_extension(char *name); + +/* implementation */ + +int BLI_stringdec(char *string, char *kop, char *start, unsigned short *numlen) +{ + unsigned short len, len2, nums = 0, nume = 0; + short i, found = 0; + + len2 = len = strlen(string); + + if (len > 6) { + if (BLI_strncasecmp(string + len - 6, ".blend", 6) == 0) len -= 6; + else if (BLI_strncasecmp(string + len - 6, ".trace", 6) == 0) len -= 6; + } + + if (len > 9) { + if (BLI_strncasecmp(string + len - 9, ".blend.gz", 9) == 0) len -= 9; + } + + if (len == len2) { + if (len > 4) { + /* handle .jf0 en .jf1 for jstreams */ + if (BLI_strncasecmp(string + len - 4, ".jf", 3) == 0) len -= 4; + else if (BLI_strncasecmp(string + len - 4, ".tga", 4) == 0) len -= 4; + else if (BLI_strncasecmp(string + len - 4, ".jpg", 4) == 0) len -= 4; + else if (BLI_strncasecmp(string + len - 4, ".png", 4) == 0) len -= 4; + else if (BLI_strncasecmp(string + len - 4, ".txt", 4) == 0) len -= 4; + else if (BLI_strncasecmp(string + len - 4, ".cyc", 4) == 0) len -= 4; + else if (BLI_strncasecmp(string + len - 4, ".enh", 4) == 0) len -= 4; + else if (BLI_strncasecmp(string + len - 4, ".rgb", 4) == 0) len -= 4; + else if (BLI_strncasecmp(string + len - 4, ".psx", 4) == 0) len -= 4; + else if (BLI_strncasecmp(string + len - 4, ".ble", 4) == 0) len -= 4; + else if (BLI_strncasecmp(string + len - 4, ".exr", 4) == 0) len -= 4; + } + } + + for (i = len - 1; i >= 0; i--) { + if (string[i] == '/') break; + if (isdigit(string[i])) { + if (found){ + nums = i; + } + else{ + nume = i; + nums = i; + found = 1; + } + } + else { + if (found) break; + } + } + if (found){ + if (start) strcpy(start,&string[nume+1]); + if (kop) { + strcpy(kop,string); + kop[nums]=0; + } + if (numlen) *numlen = nume-nums+1; + return ((int)atoi(&(string[nums]))); + } + if (start) strcpy(start, string + len); + if (kop) { + strncpy(kop, string, len); + kop[len] = 0; + } + if (numlen) *numlen=0; + return 0; +} + + +void BLI_stringenc(char *string, char *kop, char *start, unsigned short numlen, int pic) +{ + char numstr[10]=""; + unsigned short len,i; + + strcpy(string,kop); + + if (pic>0 || numlen==4) { + len= sprintf(numstr,"%d",pic); + + for(i=len;i<numlen;i++){ + strcat(string,"0"); + } + strcat(string,numstr); + } + strcat(string, start); +} + + +void BLI_newname(char *name, int add) +{ + char head[128], tail[128]; + int pic; + unsigned short digits; + + pic = BLI_stringdec(name, head, tail, &digits); + + /* are we going from 100 -> 99 or from 10 -> 9 */ + if (add < 0 && digits < 4 && digits > 0) { + int i, exp; + exp = 1; + for (i = digits; i > 1; i--) exp *= 10; + if (pic >= exp && (pic + add) < exp) digits--; + } + + pic += add; + + if (digits==4 && pic<0) pic= 0; + BLI_stringenc(name, head, tail, digits, pic); +} + +/* little helper macro for BLI_uniquename */ +#ifndef GIVE_STRADDR + #define GIVE_STRADDR(data, offset) ( ((char *)data) + offset ) +#endif + +/* Generic function to set a unique name. It is only designed to be used in situations + * where the name is part of the struct, and also that the name is at most 128 chars long. + * + * For places where this is used, see constraint.c for example... + * + * name_offs: should be calculated using offsetof(structname, membername) macro from stddef.h + * len: maximum length of string (to prevent overflows, etc.) + * defname: the name that should be used by default if none is specified already + * delim: the character which acts as a delimeter between parts of the name + */ +void BLI_uniquename(ListBase *list, void *vlink, const char defname[], char delim, short name_offs, short len) +{ + Link *link; + char tempname[128]; + int number = 1, exists = 0; + char *dot; + + /* Make sure length can be handled */ + if ((len < 0) || (len > 128)) + return; + + /* See if we are given an empty string */ + if (ELEM(NULL, vlink, defname)) + return; + + if (GIVE_STRADDR(vlink, name_offs) == '\0') { + /* give it default name first */ + BLI_strncpy(GIVE_STRADDR(vlink, name_offs), defname, len); + } + + /* See if we even need to do this */ + if (list == NULL) + return; + + for (link = list->first; link; link= link->next) { + if (link != vlink) { + if (!strcmp(GIVE_STRADDR(link, name_offs), GIVE_STRADDR(vlink, name_offs))) { + exists = 1; + break; + } + } + } + if (exists == 0) + return; + + /* Strip off the suffix */ + dot = strchr(GIVE_STRADDR(vlink, name_offs), delim); + if (dot) + *dot=0; + + for (number = 1; number <= 999; number++) { + BLI_snprintf(tempname, 128, "%s%c%03d", GIVE_STRADDR(vlink, name_offs), delim, number); + + exists = 0; + for (link= list->first; link; link= link->next) { + if (vlink != link) { + if (!strcmp(GIVE_STRADDR(link, name_offs), tempname)) { + exists = 1; + break; + } + } + } + if (exists == 0) { + BLI_strncpy(GIVE_STRADDR(vlink, name_offs), tempname, len); + return; + } + } +} + +/* ******************** string encoding ***************** */ + +/* This is quite an ugly function... its purpose is to + * take the dir name, make it absolute, and clean it up, replacing + * excess file entry stuff (like /tmp/../tmp/../) + * note that dir isn't protected for max string names... + * + * If relbase is NULL then its ignored + */ + +void BLI_cleanup_dir(const char *relabase, char *dir) +{ + BLI_cleanup_file(relabase, dir); + BLI_add_slash(dir); + +} + +void BLI_cleanup_file(const char *relabase, char *dir) +{ + short a; + char *start, *eind; + if (relabase) { + BLI_convertstringcode(dir, relabase); + } else { + if (dir[0]=='/' && dir[1]=='/') { + if (dir[2]== '\0') { + return; /* path is "//" - cant clean it */ + } + dir = dir+2; /* skip the first // */ + } + } + + /* Note + * memmove( start, eind, strlen(eind)+1 ); + * is the same as + * strcpy( start, eind ); + * except strcpy should not be used because there is overlap, + * so use memmove's slightly more obscure syntax - Campbell + */ + +#ifdef WIN32 + + /* Note, this should really be moved to the file selector, + * since this function is used in many areas */ + if(strcmp(dir, ".")==0) { /* happens for example in FILE_MAIN */ + get_default_root(dir); + return; + } + + while ( (start = strstr(dir, "\\..\\")) ) { + eind = start + strlen("\\..\\") - 1; + a = start-dir-1; + while (a>0) { + if (dir[a] == '\\') break; + a--; + } + if (a<0) { + break; + } else { + memmove( dir+a, eind, strlen(eind)+1 ); + } + } + + while ( (start = strstr(dir,"\\.\\")) ){ + eind = start + strlen("\\.\\") - 1; + memmove( start, eind, strlen(eind)+1 ); + } + + while ( (start = strstr(dir,"\\\\" )) ){ + eind = start + strlen("\\\\") - 1; + memmove( start, eind, strlen(eind)+1 ); + } + + if((a = strlen(dir))){ /* remove the '\\' at the end */ + while(a>0 && dir[a-1] == '\\'){ + a--; + dir[a] = 0; + } + } +#else + if(dir[0]=='.') { /* happens, for example in FILE_MAIN */ + dir[0]= '/'; + dir[1]= 0; + return; + } + + while ( (start = strstr(dir, "/../")) ) { + eind = start + strlen("/../") - 1; + a = start-dir-1; + while (a>0) { + if (dir[a] == '/') break; + a--; + } + if (a<0) { + break; + } else { + memmove( dir+a, eind, strlen(eind)+1 ); + } + } + + while ( (start = strstr(dir,"/./")) ){ + eind = start + strlen("/./") - 1; + memmove( start, eind, strlen(eind)+1 ); + } + + while ( (start = strstr(dir,"//" )) ){ + eind = start + strlen("//") - 1; + memmove( start, eind, strlen(eind)+1 ); + } + + if( (a = strlen(dir)) ){ /* remove all '/' at the end */ + while(dir[a-1] == '/'){ + a--; + dir[a] = 0; + if (a<=0) break; + } + } +#endif +} + + +void BLI_makestringcode(const char *relfile, char *file) +{ + char * p; + char * q; + char * lslash; + char temp[FILE_MAXDIR+FILE_MAXFILE]; + char res[FILE_MAXDIR+FILE_MAXFILE]; + + /* if file is already relative, bail out */ + if(file[0]=='/' && file[1]=='/') return; + + /* also bail out if relative path is not set */ + if (relfile[0] == 0) return; + +#ifdef WIN32 + if (strlen(relfile) > 2 && relfile[1] != ':') { + char* ptemp; + /* fix missing volume name in relative base, + can happen with old .Blog files */ + get_default_root(temp); + ptemp = &temp[2]; + if (relfile[0] != '\\' && relfile[0] != '/') { + ptemp++; + } + BLI_strncpy(ptemp, relfile, FILE_MAXDIR + FILE_MAXFILE-3); + } else { + BLI_strncpy(temp, relfile, FILE_MAXDIR + FILE_MAXFILE); + } + + if (strlen(file) > 2) { + if ( temp[1] == ':' && file[1] == ':' && temp[0] != file[0] ) + return; + } +#else + BLI_strncpy(temp, relfile, FILE_MAX); +#endif + + BLI_char_switch(temp, '\\', '/'); + BLI_char_switch(file, '\\', '/'); + + /* remove /./ which confuse the following slash counting... */ + BLI_cleanup_file(NULL, file); + BLI_cleanup_file(NULL, temp); + + /* the last slash in the file indicates where the path part ends */ + lslash = BLI_last_slash(temp); + + if (lslash) + { + /* find the prefix of the filename that is equal for both filenames. + This is replaced by the two slashes at the beginning */ + p = temp; + q = file; + while (*p == *q) { + ++p; ++q; + } + /* we might have passed the slash when the beginning of a dir matches + so we rewind. Only check on the actual filename + */ + if (*q != '/') { + while ( (q >= file) && (*q != '/') ) { --q; --p; } + } + else if (*p != '/') { + while ( (p >= temp) && (*p != '/') ) { --p; --q; } + } + + strcpy(res, "//"); + + /* p now points to the slash that is at the beginning of the part + where the path is different from the relative path. + We count the number of directories we need to go up in the + hierarchy to arrive at the common 'prefix' of the path + */ + while (p && p < lslash) { + if (*p == '/') + strcat(res, "../"); + ++p; + } + + strcat(res, q+1); /* don't copy the slash at the beginning */ + +#ifdef WIN32 + BLI_char_switch(res+2, '/', '\\'); +#endif + strcpy(file, res); + } +} + +int BLI_has_parent(char *path) +{ + int len; + int slashes = 0; + BLI_clean(path); + len = BLI_add_slash(path) - 1; + + while (len>=0) { + if ((path[len] == '\\') || (path[len] == '/')) + slashes++; + len--; + } + return slashes > 1; +} + +int BLI_parent_dir(char *path) +{ +#ifdef WIN32 + static char *parent_dir="..\\"; +#else + static char *parent_dir="../"; +#endif + char tmp[FILE_MAXDIR+FILE_MAXFILE+4]; + BLI_strncpy(tmp, path, sizeof(tmp)); + BLI_add_slash(tmp); + strcat(tmp, parent_dir); + BLI_cleanup_dir(NULL, tmp); + + if (!BLI_testextensie(tmp, parent_dir)) { + BLI_strncpy(path, tmp, sizeof(tmp)); + return 1; + } else { + return 0; + } +} + +int BLI_convertstringframe(char *path, int frame) +{ + int ch_sta, ch_end, i; + /* Insert current frame: file### -> file001 */ + ch_sta = ch_end = 0; + for (i = 0; path[i] != '\0'; i++) { + if (path[i] == '\\' || path[i] == '/') { + ch_end = 0; /* this is a directory name, dont use any hashes we found */ + } else if (path[i] == '#') { + ch_sta = i; + ch_end = ch_sta+1; + while (path[ch_end] == '#') { + ch_end++; + } + i = ch_end-1; /* keep searching */ + + /* dont break, there may be a slash after this that invalidates the previous #'s */ + } + } + if (ch_end) { /* warning, ch_end is the last # +1 */ + /* Add the frame number? */ + short numlen, hashlen; + char tmp[FILE_MAX]; + + char format[16]; /* 6 is realistically the maxframe (300000), so 8 should be enough, but 16 to be safe. */ + if (((ch_end-1)-ch_sta) >= 16) { + ch_end = ch_sta+15; /* disallow values longer then 'format' can hold */ + } + + strcpy(tmp, path); + + numlen = 1 + (int)log10((double)frame); /* this is the number of chars in the number */ + hashlen = ch_end - ch_sta; + + sprintf(format, "%d", frame); + + if (numlen==hashlen) { /* simple case */ + memcpy(tmp+ch_sta, format, numlen); + } else if (numlen < hashlen) { + memcpy(tmp+ch_sta + (hashlen-numlen), format, numlen); /*dont copy the string terminator */ + memset(tmp+ch_sta, '0', hashlen-numlen); + } else { + /* number is longer then number of #'s */ + if (tmp[ch_end] == '\0') { /* hashes are last, no need to move any string*/ + /* bad juju - not testing string length here :/ */ + memcpy(tmp+ch_sta, format, numlen+1); /* add 1 to get the string terminator \0 */ + } else { + /* we need to move the end characters, reuse i */ + int j; + + i = strlen(tmp); /* +1 to copy the string terminator */ + j = i + (numlen-hashlen); /* from/to */ + + while (i >= ch_end) { + tmp[j] = tmp[i]; + i--; + j--; + } + memcpy(tmp + ch_sta, format, numlen); + } + } + strcpy(path, tmp); + return 1; + } + return 0; +} + + +int BLI_convertstringcode(char *path, const char *basepath) +{ + int wasrelative = (strncmp(path, "//", 2)==0); + char tmp[FILE_MAX]; + char base[FILE_MAX]; +#ifdef WIN32 + char vol[3] = {'\0', '\0', '\0'}; + + BLI_strncpy(vol, path, 3); + /* we are checking here if we have an absolute path that is not in the current + blend file as a lib main - we are basically checking for the case that a + UNIX root '/' is passed. + */ + if (!wasrelative && (vol[1] != ':' && (vol[0] == '\0' || vol[0] == '/' || vol[0] == '\\'))) { + char *p = path; + get_default_root(tmp); + // get rid of the slashes at the beginning of the path + while (*p == '\\' || *p == '/') { + p++; + } + strcat(tmp, p); + } + else { + BLI_strncpy(tmp, path, FILE_MAX); + } +#else + BLI_strncpy(tmp, path, FILE_MAX); + + /* Check for loading a windows path on a posix system + * in this case, there is no use in trying C:/ since it + * will never exist on a unix os. + * + * Add a / prefix and lowercase the driveletter, remove the : + * C:\foo.JPG -> /c/foo.JPG */ + + if (isalpha(tmp[0]) && tmp[1] == ':' && (tmp[2]=='\\' || tmp[2]=='/') ) { + tmp[1] = tolower(tmp[0]); /* replace ':' with driveletter */ + tmp[0] = '/'; + /* '\' the slash will be converted later */ + } + +#endif + + BLI_strncpy(base, basepath, FILE_MAX); + + BLI_cleanup_file(NULL, base); + + /* push slashes into unix mode - strings entering this part are + potentially messed up: having both back- and forward slashes. + Here we push into one conform direction, and at the end we + push them into the system specific dir. This ensures uniformity + of paths and solving some problems (and prevent potential future + ones) -jesterKing. */ + BLI_char_switch(tmp, '\\', '/'); + BLI_char_switch(base, '\\', '/'); + + /* Paths starting with // will get the blend file as their base, + * this isnt standard in any os but is uesed in blender all over the place */ + if (wasrelative) { + char *lslash= BLI_last_slash(base); + if (lslash) { + int baselen= (int) (lslash-base) + 1; + /* use path for for temp storage here, we copy back over it right away */ + BLI_strncpy(path, tmp+2, FILE_MAX); + + memcpy(tmp, base, baselen); + strcpy(tmp+baselen, path); + strcpy(path, tmp); + } else { + strcpy(path, tmp+2); + } + } else { + strcpy(path, tmp); + } + + if (path[0]!='\0') { + if ( path[strlen(path)-1]=='/') { + BLI_cleanup_dir(NULL, path); + } else { + BLI_cleanup_file(NULL, path); + } + } + +#ifdef WIN32 + /* skip first two chars, which in case of + absolute path will be drive:/blabla and + in case of relpath //blabla/. So relpath + // will be retained, rest will be nice and + shiny win32 backward slashes :) -jesterKing + */ + BLI_char_switch(path+2, '/', '\\'); +#endif + + return wasrelative; +} + + +/* + * Should only be done with command line paths. + * this is NOT somthing blenders internal paths support like the // prefix + */ +int BLI_convertstringcwd(char *path) +{ + int wasrelative = 1; + int filelen = strlen(path); + +#ifdef WIN32 + if (filelen >= 3 && path[1] == ':' && (path[2] == '\\' || path[2] == '/')) + wasrelative = 0; +#else + if (filelen >= 2 && path[0] == '/') + wasrelative = 0; +#endif + + if (wasrelative==1) { + char cwd[FILE_MAXDIR + FILE_MAXFILE]; + BLI_getwdN(cwd); /* incase the full path to the blend isnt used */ + + if (cwd[0] == '\0') { + printf( "Could not get the current working directory - $PWD for an unknown reason."); + } else { + /* uses the blend path relative to cwd important for loading relative linked files. + * + * cwd should contain c:\ etc on win32 so the relbase can be NULL + * relbase being NULL also prevents // being misunderstood as relative to the current + * blend file which isnt a feature we want to use in this case since were dealing + * with a path from the command line, rather then from inside Blender */ + + char origpath[FILE_MAXDIR + FILE_MAXFILE]; + BLI_strncpy(origpath, path, FILE_MAXDIR + FILE_MAXFILE); + + BLI_make_file_string(NULL, path, cwd, origpath); + } + } + + return wasrelative; +} + + +/* copy di to fi, filename only */ +void BLI_splitdirstring(char *di, char *fi) +{ + char *lslash= BLI_last_slash(di); + + if (lslash) { + BLI_strncpy(fi, lslash+1, FILE_MAXFILE); + *(lslash+1)=0; + } else { + BLI_strncpy(fi, di, FILE_MAXFILE); + di[0]= 0; + } +} + +void BLI_getlastdir(const char* dir, char *last, int maxlen) +{ + const char *s = dir; + const char *lslash = NULL; + const char *prevslash = NULL; + while (*s) { + if ((*s == '\\') || (*s == '/')) { + prevslash = lslash; + lslash = s; + } + s++; + } + if (prevslash) { + BLI_strncpy(last, prevslash+1, maxlen); + } else { + BLI_strncpy(last, dir, maxlen); + } +} + +char *BLI_gethome(void) { + #if !defined(WIN32) + return getenv("HOME"); + + #else /* Windows */ + char * ret; + static char dir[512]; + static char appdatapath[MAXPATHLEN]; + HRESULT hResult; + + /* Check for %HOME% env var */ + + ret = getenv("HOME"); + if(ret) { + sprintf(dir, "%s\\.blender", ret); + if (BLI_exists(dir)) return dir; + } + + /* else, check install dir (path containing blender.exe) */ + + BLI_getInstallationDir(dir); + + if (BLI_exists(dir)) + { + strcat(dir,"\\.blender"); + if (BLI_exists(dir)) return(dir); + } + + + /* add user profile support for WIN 2K / NT */ + hResult = SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT, appdatapath); + + if (hResult == S_OK) + { + if (BLI_exists(appdatapath)) { /* from fop, also below... */ + sprintf(dir, "%s\\Blender Foundation\\Blender", appdatapath); + BLI_recurdir_fileops(dir); + if (BLI_exists(dir)) { + strcat(dir,"\\.blender"); + if(BLI_exists(dir)) return(dir); + } + } + hResult = SHGetFolderPath(NULL, CSIDL_COMMON_APPDATA, NULL, SHGFP_TYPE_CURRENT, appdatapath); + if (hResult == S_OK) + { + if (BLI_exists(appdatapath)) + { /* from fop, also below... */ + sprintf(dir, "%s\\Blender Foundation\\Blender", appdatapath); + BLI_recurdir_fileops(dir); + if (BLI_exists(dir)) { + strcat(dir,"\\.blender"); + if(BLI_exists(dir)) return(dir); + } + } + } + } +#if 0 + ret = getenv("USERPROFILE"); + if (ret) { + if (BLI_exists(ret)) { /* from fop, also below... */ + sprintf(dir, "%s\\Application Data\\Blender Foundation\\Blender", ret); + BLI_recurdir_fileops(dir); + if (BLI_exists(dir)) { + strcat(dir,"\\.blender"); + if(BLI_exists(dir)) return(dir); + } + } + } +#endif + + /* + Saving in the Windows dir is less than desirable. + Use as a last resort ONLY! (aphex) + */ + + ret = getenv("WINDOWS"); + if (ret) { + if(BLI_exists(ret)) return ret; + } + + ret = getenv("WINDIR"); + if (ret) { + if(BLI_exists(ret)) return ret; + } + + return "C:\\Temp"; /* sheesh! bad, bad, bad! (aphex) */ + #endif +} + +/* this function returns the path to a blender folder, if it exists + * utility functions for BLI_gethome_folder */ + +/* #define PATH_DEBUG */ /* for testing paths that are checked */ + +static int test_data_path(char *targetpath, char *path_base, char *path_sep, char *folder_name) +{ + char tmppath[FILE_MAXDIR]; + + if(path_sep) BLI_join_dirfile(tmppath, path_base, path_sep); + else BLI_strncpy(tmppath, path_base, sizeof(tmppath)); + + BLI_make_file_string("/", targetpath, tmppath, folder_name); + + if (BLI_exists(targetpath)) { +#ifdef PATH_DEBUG + printf("\tpath found: %s\n", targetpath); +#endif + return 1; + } + else { +#ifdef PATH_DEBUG + printf("\tpath missing: %s\n", targetpath); +#endif + targetpath[0] = '\0'; + return 0; + } +} + +static int gethome_path_local(char *targetpath, char *folder_name) +{ + extern char bprogname[]; /* argv[0] from creator.c */ + char bprogdir[FILE_MAXDIR]; + char cwd[FILE_MAXDIR]; + char *s; + int i; + +#ifdef PATH_DEBUG + printf("gethome_path_local...\n"); +#endif + + /* try release/folder_name (binary relative) */ + /* use argv[0] (bprogname) to get the path to the executable */ + s = BLI_last_slash(bprogname); + i = s - bprogname + 1; + BLI_strncpy(bprogdir, bprogname, i); + + /* try release/folder_name (CWD relative) */ + if(test_data_path(targetpath, BLI_getwdN(cwd), "release", folder_name)) + return 1; + + if(test_data_path(targetpath, bprogdir, "release", folder_name)) + return 1; + + /* try ./.blender/folder_name */ + if(test_data_path(targetpath, bprogdir, ".blender", folder_name)) + return 1; + + return 0; +} + +static int gethome_path_user(char *targetpath, char *folder_name) +{ + char *home_path= BLI_gethome(); + +#ifdef PATH_DEBUG + printf("gethome_path_user...\n"); +#endif + + /* try $HOME/folder_name */ + return test_data_path(targetpath, home_path, ".blender", folder_name); +} + +static int gethome_path_system(char *targetpath, char *folder_name) +{ + extern char blender_path[]; /* unix prefix eg. /usr/share/blender/2.5 creator.c */ + + if(!blender_path[0]) + return 0; + +#ifdef PATH_DEBUG + printf("gethome_path_system...\n"); +#endif + + /* try $BLENDERPATH/folder_name */ + return test_data_path(targetpath, blender_path, NULL, folder_name); +} + +char *BLI_gethome_folder(char *folder_name, int flag) +{ + static char fulldir[FILE_MAXDIR] = ""; + + /* first check if this is a redistributable bundle */ + if(flag & BLI_GETHOME_LOCAL) { + if (gethome_path_local(fulldir, folder_name)) + return fulldir; + } + + /* then check if the OS has blender data files installed in a global location */ + if(flag & BLI_GETHOME_SYSTEM) { + if (gethome_path_system(fulldir, folder_name)) + return fulldir; + } + + /* now check the users home dir for data files */ + if(flag & BLI_GETHOME_USER) { + if (gethome_path_user(fulldir, folder_name)) + return fulldir; + } + + return NULL; +} + +#ifdef PATH_DEBUG +#undef PATH_DEBUG +#endif + +void BLI_setenv(const char *env, const char*val) +{ + /* SGI or free windows */ +#if (defined(__sgi) || ((defined(WIN32) || defined(WIN64)) && defined(FREE_WINDOWS))) + char *envstr= malloc(sizeof(char) * (strlen(env) + strlen(val) + 2)); /* one for = another for \0 */ + + sprintf(envstr, "%s=%s", env, val); + putenv(envstr); + free(envstr); + + /* non-free windows */ +#elif (defined(WIN32) || defined(WIN64)) /* not free windows */ + _putenv_s(env, val); +#else + /* linux/osx/bsd */ + setenv(env, val, 1); +#endif +} + + +/** + Only set an env var if already not there. + Like Unix setenv(env, val, 0); + */ +void BLI_setenv_if_new(const char *env, const char* val) +{ + if(getenv(env) == NULL) + BLI_setenv(env, val); +} + + +void BLI_clean(char *path) +{ + if(path==0) return; +#ifdef WIN32 + if(path && strlen(path)>2) { + BLI_char_switch(path+2, '/', '\\'); + } +#else + BLI_char_switch(path, '\\', '/'); +#endif +} + +void BLI_char_switch(char *string, char from, char to) +{ + if(string==0) return; + while (*string != 0) { + if (*string == from) *string = to; + string++; + } +} + +void BLI_make_exist(char *dir) { + int a; + + #ifdef WIN32 + BLI_char_switch(dir, '/', '\\'); + #else + BLI_char_switch(dir, '\\', '/'); + #endif + + a = strlen(dir); + +#ifdef WIN32 + while(BLI_exists(dir) == 0){ + a --; + while(dir[a] != '\\'){ + a--; + if (a <= 0) break; + } + if (a >= 0) dir[a+1] = 0; + else { + /* defaulting to drive (usually 'C:') of Windows installation */ + get_default_root(dir); + break; + } + } +#else + while(BLI_exist(dir) == 0){ + a --; + while(dir[a] != '/'){ + a--; + if (a <= 0) break; + } + if (a >= 0) dir[a+1] = 0; + else { + strcpy(dir,"/"); + break; + } + } +#endif +} + +void BLI_make_existing_file(char *name) +{ + char di[FILE_MAXDIR], fi[FILE_MAXFILE]; + + strcpy(di, name); + BLI_splitdirstring(di, fi); + + /* test exist */ + if (BLI_exists(di) == 0) { + BLI_recurdir_fileops(di); + } +} + + +void BLI_make_file_string(const char *relabase, char *string, const char *dir, const char *file) +{ + int sl; + + if (!string || !dir || !file) return; /* We don't want any NULLs */ + + string[0]= 0; /* ton */ + + /* we first push all slashes into unix mode, just to make sure we don't get + any mess with slashes later on. -jesterKing */ + /* constant strings can be passed for those parameters - don't change them - elubie */ + /* + BLI_char_switch(relabase, '\\', '/'); + BLI_char_switch(dir, '\\', '/'); + BLI_char_switch(file, '\\', '/'); + */ + + /* Resolve relative references */ + if (relabase && dir[0] == '/' && dir[1] == '/') { + char *lslash; + + /* Get the file name, chop everything past the last slash (ie. the filename) */ + strcpy(string, relabase); + + lslash= (strrchr(string, '/')>strrchr(string, '\\'))?strrchr(string, '/'):strrchr(string, '\\'); + + if(lslash) *(lslash+1)= 0; + + dir+=2; /* Skip over the relative reference */ + } +#ifdef WIN32 + else { + if (strlen(dir) >= 2 && dir[1] == ':' ) { + BLI_strncpy(string, dir, 3); + dir += 2; + } + else { /* no drive specified */ + /* first option: get the drive from the relabase if it has one */ + if (relabase && strlen(relabase) >= 2 && relabase[1] == ':' ) { + BLI_strncpy(string, relabase, 3); + string[2] = '\\'; + string[3] = '\0'; + } + else { /* we're out of luck here, guessing the first valid drive, usually c:\ */ + get_default_root(string); + } + + /* ignore leading slashes */ + while (*dir == '/' || *dir == '\\') dir++; + } + } +#endif + + strcat(string, dir); + + /* Make sure string ends in one (and only one) slash */ + /* first trim all slashes from the end of the string */ + sl = strlen(string); + while (sl>0 && ( string[sl-1] == '/' || string[sl-1] == '\\') ) { + string[sl-1] = '\0'; + sl--; + } + /* since we've now removed all slashes, put back one slash at the end. */ + strcat(string, "/"); + + while (*file && (*file == '/' || *file == '\\')) /* Trim slashes from the front of file */ + file++; + + strcat (string, file); + + /* Push all slashes to the system preferred direction */ + BLI_clean(string); +} + +int BLI_testextensie(const char *str, const char *ext) +{ + short a, b; + int retval; + + a= strlen(str); + b= strlen(ext); + + if(a==0 || b==0 || b>=a) { + retval = 0; + } else if (BLI_strcasecmp(ext, str + a - b)) { + retval = 0; + } else { + retval = 1; + } + + return (retval); +} + +/* + * This is a simple version of BLI_split_dirfile that has the following advantages... + * + * Converts "/foo/bar.txt" to "/foo/" and "bar.txt" + * - wont change 'string' + * - wont create any directories + * - dosnt use CWD, or deal with relative paths. + * - Only fill's in *dir and *file when they are non NULL + * */ +void BLI_split_dirfile_basic(const char *string, char *dir, char *file) +{ + int lslash=0, i = 0; + for (i=0; string[i]!='\0'; i++) { + if (string[i]=='\\' || string[i]=='/') + lslash = i+1; + } + if (dir) { + if (lslash) { + BLI_strncpy( dir, string, lslash+1); /* +1 to include the slash and the last char */ + } else { + dir[0] = '\0'; + } + } + + if (file) { + strcpy( file, string+lslash); + } +} + + +/* Warning, + * - May modify 'string' variable + * - May create the directory if it dosnt exist + * if this is not needed use BLI_split_dirfile_basic(...) + */ +void BLI_split_dirfile(char *string, char *dir, char *file) +{ + int a; +#ifdef WIN32 + int sl; + short is_relative = 0; + char path[FILE_MAX]; +#endif + + dir[0]= 0; + file[0]= 0; + +#ifdef WIN32 + BLI_strncpy(path, string, FILE_MAX); + BLI_char_switch(path, '/', '\\'); /* make sure we have a valid path format */ + sl = strlen(path); + if (sl) { + int len; + if (path[0] == '/' || path[0] == '\\') { + BLI_strncpy(dir, path, FILE_MAXDIR); + if (sl > 1 && path[0] == '\\' && path[1] == '\\') is_relative = 1; + } else if (sl > 2 && path[1] == ':' && path[2] == '\\') { + BLI_strncpy(dir, path, FILE_MAXDIR); + } else { + BLI_getwdN(dir); + strcat(dir,"\\"); + strcat(dir,path); + BLI_strncpy(path,dir,FILE_MAXDIR+FILE_MAXFILE); + } + + // BLI_exist doesn't recognize a slashed dirname as a dir + // check if a trailing slash exists, and remove it. Do not do this + // when we are already at root. -jesterKing + a = strlen(dir); + if(a>=4 && dir[a-1]=='\\') dir[a-1] = 0; + + if (is_relative) { + printf("WARNING: BLI_split_dirfile needs absolute dir\n"); + } + else { + BLI_make_exist(dir); + } + + if (S_ISDIR(BLI_exist(dir))) { + + /* copy from end of string into file, to ensure filename itself isn't truncated + if string is too long. (aphex) */ + + len = FILE_MAXFILE - strlen(path); + + if (len < 0) + BLI_strncpy(file,path + abs(len),FILE_MAXFILE); + else + BLI_strncpy(file,path,FILE_MAXFILE); + + if (strrchr(path,'\\')) { + BLI_strncpy(file,strrchr(path,'\\')+1,FILE_MAXFILE); + } + + if ( (a = strlen(dir)) ) { + if (dir[a-1] != '\\') strcat(dir,"\\"); + } + } + else { + a = strlen(dir) - 1; + while(a>0 && dir[a] != '\\') a--; + dir[a + 1] = 0; + BLI_strncpy(file, path + strlen(dir),FILE_MAXFILE); + } + + } + else { + /* defaulting to first valid drive hoping it's not empty CD and DVD drives */ + get_default_root(dir); + file[0]=0; + } +#else + if (strlen(string)) { + if (string[0] == '/') { + strcpy(dir, string); + } else if (string[1] == ':' && string[2] == '\\') { + string+=2; + strcpy(dir, string); + } else { + BLI_getwdN(dir); + strcat(dir,"/"); + strcat(dir,string); + strcpy((char *)string,dir); + } + + BLI_make_exist(dir); + + if (S_ISDIR(BLI_exist(dir))) { + strcpy(file,string + strlen(dir)); + + if (strrchr(file,'/')) strcpy(file,strrchr(file,'/')+1); + + if ( (a = strlen(dir)) ) { + if (dir[a-1] != '/') strcat(dir,"/"); + } + } + else { + a = strlen(dir) - 1; + while(dir[a] != '/') a--; + dir[a + 1] = 0; + strcpy(file, string + strlen(dir)); + } + } + else { + BLI_getwdN(dir); + strcat(dir, "/"); + file[0] = 0; + } +#endif +} + +/* simple appending of filename to dir, does not check for valid path! */ +void BLI_join_dirfile(char *string, const char *dir, const char *file) +{ + int sl_dir; + + if(string != dir) /* compare pointers */ + BLI_strncpy(string, dir, FILE_MAX); + + sl_dir= BLI_add_slash(string); + + if (sl_dir <FILE_MAX) { + BLI_strncpy(string + sl_dir, file, FILE_MAX-sl_dir); + } +} + +static int add_win32_extension(char *name) +{ + int retval = 0; + int type; + + type = BLI_exist(name); + if ((type == 0) || S_ISDIR(type)) { +#ifdef _WIN32 + char filename[FILE_MAXDIR+FILE_MAXFILE]; + char ext[FILE_MAXDIR+FILE_MAXFILE]; + char *extensions = getenv("PATHEXT"); + if (extensions) { + char *temp; + do { + strcpy(filename, name); + temp = strstr(extensions, ";"); + if (temp) { + strncpy(ext, extensions, temp - extensions); + ext[temp - extensions] = 0; + extensions = temp + 1; + strcat(filename, ext); + } else { + strcat(filename, extensions); + } + + type = BLI_exist(filename); + if (type && (! S_ISDIR(type))) { + retval = 1; + strcpy(name, filename); + break; + } + } while (temp); + } +#endif + } else { + retval = 1; + } + + return (retval); +} + +void BLI_where_am_i(char *fullname, const char *name) +{ + char filename[FILE_MAXDIR+FILE_MAXFILE]; + char *path = NULL, *temp; + +#ifdef _WIN32 + char *separator = ";"; + char slash = '\\'; +#else + char *separator = ":"; + char slash = '/'; +#endif + + +#ifdef __linux__ + /* linux uses binreloc since argv[0] is not relyable, call br_init( NULL ) first */ + path = br_find_exe( NULL ); + if (path) { + strcpy(fullname, path); + free(path); + return; + } +#endif + +#ifdef _WIN32 + if(GetModuleFileName(0, fullname, FILE_MAXDIR+FILE_MAXFILE)) { + GetShortPathName(fullname, fullname, FILE_MAXDIR+FILE_MAXFILE); + return; + } +#endif + + /* unix and non linux */ + if (name && fullname && strlen(name)) { + strcpy(fullname, name); + if (name[0] == '.') { + // relative path, prepend cwd + BLI_getwdN(fullname); + + // not needed but avoids annoying /./ in name + if(name && name[0]=='.' && name[1]==slash) + BLI_join_dirfile(fullname, fullname, name+2); + else + BLI_join_dirfile(fullname, fullname, name); + + add_win32_extension(fullname); + } else if (BLI_last_slash(name)) { + // full path + strcpy(fullname, name); + add_win32_extension(fullname); + } else { + // search for binary in $PATH + path = getenv("PATH"); + if (path) { + do { + temp = strstr(path, separator); + if (temp) { + strncpy(filename, path, temp - path); + filename[temp - path] = 0; + path = temp + 1; + } else { + strncpy(filename, path, sizeof(filename)); + } + BLI_join_dirfile(fullname, fullname, name); + if (add_win32_extension(filename)) { + strcpy(fullname, filename); + break; + } + } while (temp); + } + } +#ifndef NDEBUG + if (strcmp(name, fullname)) { + printf("guessing '%s' == '%s'\n", name, fullname); + } +#endif + +#ifdef _WIN32 + // in windows change long filename to short filename because + // win2k doesn't know how to parse a commandline with lots of + // spaces and double-quotes. There's another solution to this + // with spawnv(P_WAIT, bprogname, argv) instead of system() but + // that's even uglier + GetShortPathName(fullname, fullname, FILE_MAXDIR+FILE_MAXFILE); +#ifndef NDEBUG + printf("Shortname = '%s'\n", fullname); +#endif +#endif + } +} + +void BLI_where_is_temp(char *fullname, int usertemp) +{ + fullname[0] = '\0'; + + if (usertemp && BLI_exists(U.tempdir)) { + strcpy(fullname, U.tempdir); + } + + +#ifdef WIN32 + if (fullname[0] == '\0') { + char *tmp = getenv("TEMP"); /* Windows */ + if (tmp && BLI_exists(tmp)) { + strcpy(fullname, tmp); + } + } +#else + /* Other OS's - Try TMP and TMPDIR */ + if (fullname[0] == '\0') { + char *tmp = getenv("TMP"); + if (tmp && BLI_exists(tmp)) { + strcpy(fullname, tmp); + } + } + + if (fullname[0] == '\0') { + char *tmp = getenv("TMPDIR"); + if (tmp && BLI_exists(tmp)) { + strcpy(fullname, tmp); + } + } +#endif + + if (fullname[0] == '\0') { + strcpy(fullname, "/tmp/"); + } else { + /* add a trailing slash if needed */ + BLI_add_slash(fullname); + } +} + +char *get_install_dir(void) { + extern char bprogname[]; + char *tmpname = BLI_strdup(bprogname); + char *cut; + +#ifdef __APPLE__ + cut = strstr(tmpname, ".app"); + if (cut) cut[0] = 0; +#endif + + cut = BLI_last_slash(tmpname); + + if (cut) { + cut[0] = 0; + return tmpname; + } else { + MEM_freeN(tmpname); + return NULL; + } +} + +/* + * returns absolute path to the app bundle + * only useful on OS X + */ +#ifdef __APPLE__ +char* BLI_getbundle(void) { + CFURLRef bundleURL; + CFStringRef pathStr; + static char path[MAXPATHLEN]; + CFBundleRef mainBundle = CFBundleGetMainBundle(); + + bundleURL = CFBundleCopyBundleURL(mainBundle); + pathStr = CFURLCopyFileSystemPath(bundleURL, kCFURLPOSIXPathStyle); + CFStringGetCString(pathStr, path, MAXPATHLEN, kCFStringEncodingASCII); + CFRelease(pathStr); + CFRelease(bundleURL); + return path; +} +#endif + +#ifdef WITH_ICONV +#include "iconv.h" +#include "localcharset.h" + +void BLI_string_to_utf8(char *original, char *utf_8, const char *code) +{ + size_t inbytesleft=strlen(original); + size_t outbytesleft=512; + size_t rv=0; + iconv_t cd; + + if (NULL == code) { + code = locale_charset(); + } + cd=iconv_open("UTF-8", code); + + if (cd == (iconv_t)(-1)) { + printf("iconv_open Error"); + *utf_8='\0'; + return ; + } + rv=iconv(cd, &original, &inbytesleft, &utf_8, &outbytesleft); + if (rv == (size_t) -1) { + printf("iconv Error\n"); + return ; + } + *utf_8 = '\0'; + iconv_close(cd); +} +#endif // WITH_ICONV + + |