Blender V2.61 - r43446
|
00001 /* 00002 * ***** BEGIN GPL LICENSE BLOCK ***** 00003 * 00004 * This program is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU General Public License 00006 * as published by the Free Software Foundation; either version 2 00007 * of the License, or (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License 00015 * along with this program; if not, write to the Free Software Foundation, 00016 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00017 * 00018 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. 00019 * All rights reserved. 00020 * 00021 * The Original Code is: all of this file. 00022 * 00023 * Contributor(s): none yet. 00024 * 00025 * ***** END GPL LICENSE BLOCK ***** 00026 * 00027 * various string, file, list operations. 00028 */ 00029 00035 #include <ctype.h> 00036 #include <string.h> 00037 #include <stdlib.h> 00038 #include <assert.h> 00039 00040 #include "MEM_guardedalloc.h" 00041 00042 #include "DNA_listBase.h" 00043 00044 #include "BLI_fileops.h" 00045 #include "BLI_path_util.h" 00046 #include "BLI_string.h" 00047 #include "BLI_string_utf8.h" 00048 #include "BLI_utildefines.h" 00049 00050 #include "BKE_utildefines.h" 00051 #include "BKE_blender.h" // BLENDER_VERSION 00052 00053 #include "GHOST_Path-api.h" 00054 00055 #if defined WIN32 && !defined _LIBC || defined __sun 00056 # include "BLI_fnmatch.h" /* use fnmatch included in blenlib */ 00057 #else 00058 # ifndef _GNU_SOURCE 00059 # define _GNU_SOURCE 00060 # endif 00061 # include <fnmatch.h> 00062 #endif 00063 00064 #ifdef WIN32 00065 # include <io.h> 00066 # ifdef _WIN32_IE 00067 # undef _WIN32_IE 00068 # endif 00069 # define _WIN32_IE 0x0501 00070 # include <windows.h> 00071 # include <shlobj.h> 00072 # include "BLI_winstuff.h" 00073 #else /* non windows */ 00074 # ifdef WITH_BINRELOC 00075 # include "binreloc.h" 00076 # endif 00077 #endif /* WIN32 */ 00078 00079 /* standard paths */ 00080 #ifdef WIN32 00081 # define BLENDER_USER_FORMAT "%s\\Blender Foundation\\Blender\\%s" 00082 # define BLENDER_SYSTEM_FORMAT "%s\\Blender Foundation\\Blender\\%s" 00083 #elif defined(__APPLE__) 00084 # define BLENDER_USER_FORMAT "%s/Blender/%s" 00085 # define BLENDER_SYSTEM_FORMAT "%s/Blender/%s" 00086 #else /* UNIX */ 00087 # ifndef WITH_XDG_USER_DIRS /* oldschool unix ~/.blender/ */ 00088 # define BLENDER_USER_FORMAT "%s/.blender/%s" 00089 # else /* new XDG ~/blender/.config/ */ 00090 # define BLENDER_USER_FORMAT "%s/blender/%s" 00091 # endif // WITH_XDG_USER_DIRS 00092 # define BLENDER_SYSTEM_FORMAT "%s/blender/%s" 00093 #endif 00094 00095 /* local */ 00096 #define UNIQUE_NAME_MAX 128 00097 00098 static char bprogname[FILE_MAX]; /* path to program executable */ 00099 static char bprogdir[FILE_MAX]; /* path in which executable is located */ 00100 static char btempdir[FILE_MAX]; /* temporary directory */ 00101 00102 static int add_win32_extension(char *name); 00103 static char *blender_version_decimal(const int ver); 00104 00105 /* implementation */ 00106 00107 int BLI_stringdec(const char *string, char *head, char *tail, unsigned short *numlen) 00108 { 00109 unsigned short len, len2, lenlslash = 0, nums = 0, nume = 0; 00110 short i, found = 0; 00111 char *lslash = BLI_last_slash(string); 00112 len2 = len = strlen(string); 00113 if(lslash) 00114 lenlslash= (int)(lslash - string); 00115 00116 while(len > lenlslash && string[--len] != '.') {}; 00117 if(len == lenlslash && string[len] != '.') len = len2; 00118 00119 for (i = len - 1; i >= lenlslash; i--) { 00120 if (isdigit(string[i])) { 00121 if (found){ 00122 nums = i; 00123 } 00124 else{ 00125 nume = i; 00126 nums = i; 00127 found = 1; 00128 } 00129 } 00130 else { 00131 if (found) break; 00132 } 00133 } 00134 if (found) { 00135 if (tail) strcpy(tail, &string[nume+1]); 00136 if (head) { 00137 strcpy(head,string); 00138 head[nums]=0; 00139 } 00140 if (numlen) *numlen = nume-nums+1; 00141 return ((int)atoi(&(string[nums]))); 00142 } 00143 if (tail) strcpy(tail, string + len); 00144 if (head) { 00145 strncpy(head, string, len); 00146 head[len] = '\0'; 00147 } 00148 if (numlen) *numlen=0; 00149 return 0; 00150 } 00151 00152 00153 void BLI_stringenc(char *string, const char *head, const char *tail, unsigned short numlen, int pic) 00154 { 00155 char fmtstr[16]=""; 00156 if(pic < 0) pic= 0; 00157 sprintf(fmtstr, "%%s%%.%dd%%s", numlen); 00158 sprintf(string, fmtstr, head, pic, tail); 00159 } 00160 00161 /* Foo.001 -> "Foo", 1 00162 * Returns the length of "Foo" */ 00163 int BLI_split_name_num(char *left, int *nr, const char *name, const char delim) 00164 { 00165 int a; 00166 00167 *nr= 0; 00168 a= strlen(name); 00169 memcpy(left, name, (a + 1) * sizeof(char)); 00170 00171 if(a>1 && name[a-1]==delim) return a; 00172 00173 while(a--) { 00174 if( name[a]==delim ) { 00175 left[a]= 0; 00176 *nr= atol(name+a+1); 00177 /* casting down to an int, can overflow for large numbers */ 00178 if(*nr < 0) 00179 *nr= 0; 00180 return a; 00181 } 00182 if( isdigit(name[a])==0 ) break; 00183 00184 left[a]= 0; 00185 } 00186 00187 for(a= 0; name[a]; a++) 00188 left[a]= name[a]; 00189 00190 return a; 00191 } 00192 00193 void BLI_newname(char *name, int add) 00194 { 00195 char head[UNIQUE_NAME_MAX], tail[UNIQUE_NAME_MAX]; 00196 int pic; 00197 unsigned short digits; 00198 00199 pic = BLI_stringdec(name, head, tail, &digits); 00200 00201 /* are we going from 100 -> 99 or from 10 -> 9 */ 00202 if (add < 0 && digits < 4 && digits > 0) { 00203 int i, exp; 00204 exp = 1; 00205 for (i = digits; i > 1; i--) exp *= 10; 00206 if (pic >= exp && (pic + add) < exp) digits--; 00207 } 00208 00209 pic += add; 00210 00211 if (digits==4 && pic<0) pic= 0; 00212 BLI_stringenc(name, head, tail, digits, pic); 00213 } 00214 00215 00216 00217 int BLI_uniquename_cb(int (*unique_check)(void *, const char *), void *arg, const char defname[], char delim, char *name, short name_len) 00218 { 00219 if(name[0] == '\0') { 00220 BLI_strncpy(name, defname, name_len); 00221 } 00222 00223 if(unique_check(arg, name)) { 00224 char numstr[16]; 00225 char tempname[UNIQUE_NAME_MAX]; 00226 char left[UNIQUE_NAME_MAX]; 00227 int number; 00228 int len= BLI_split_name_num(left, &number, name, delim); 00229 do { 00230 int numlen= BLI_snprintf(numstr, sizeof(numstr), "%c%03d", delim, ++number); 00231 00232 /* highly unlikely the string only has enough room for the number 00233 * but support anyway */ 00234 if ((len == 0) || (numlen >= name_len)) { 00235 /* number is know not to be utf-8 */ 00236 BLI_strncpy(tempname, numstr, name_len); 00237 } 00238 else { 00239 char *tempname_buf; 00240 tempname[0]= '\0'; 00241 tempname_buf =BLI_strncat_utf8(tempname, left, name_len - numlen); 00242 memcpy(tempname_buf, numstr, numlen + 1); 00243 } 00244 } while(unique_check(arg, tempname)); 00245 00246 BLI_strncpy(name, tempname, name_len); 00247 00248 return 1; 00249 } 00250 00251 return 0; 00252 } 00253 00254 /* little helper macro for BLI_uniquename */ 00255 #ifndef GIVE_STRADDR 00256 #define GIVE_STRADDR(data, offset) ( ((char *)data) + offset ) 00257 #endif 00258 00259 /* Generic function to set a unique name. It is only designed to be used in situations 00260 * where the name is part of the struct, and also that the name is at most UNIQUE_NAME_MAX chars long. 00261 * 00262 * For places where this is used, see constraint.c for example... 00263 * 00264 * name_offs: should be calculated using offsetof(structname, membername) macro from stddef.h 00265 * len: maximum length of string (to prevent overflows, etc.) 00266 * defname: the name that should be used by default if none is specified already 00267 * delim: the character which acts as a delimeter between parts of the name 00268 */ 00269 static int uniquename_find_dupe(ListBase *list, void *vlink, const char *name, short name_offs) 00270 { 00271 Link *link; 00272 00273 for (link = list->first; link; link= link->next) { 00274 if (link != vlink) { 00275 if (!strcmp(GIVE_STRADDR(link, name_offs), name)) { 00276 return 1; 00277 } 00278 } 00279 } 00280 00281 return 0; 00282 } 00283 00284 static int uniquename_unique_check(void *arg, const char *name) 00285 { 00286 struct {ListBase *lb; void *vlink; short name_offs;} *data= arg; 00287 return uniquename_find_dupe(data->lb, data->vlink, name, data->name_offs); 00288 } 00289 00290 void BLI_uniquename(ListBase *list, void *vlink, const char defname[], char delim, short name_offs, short name_len) 00291 { 00292 struct {ListBase *lb; void *vlink; short name_offs;} data; 00293 data.lb= list; 00294 data.vlink= vlink; 00295 data.name_offs= name_offs; 00296 00297 assert((name_len > 1) && (name_len <= UNIQUE_NAME_MAX)); 00298 00299 /* See if we are given an empty string */ 00300 if (ELEM(NULL, vlink, defname)) 00301 return; 00302 00303 BLI_uniquename_cb(uniquename_unique_check, &data, defname, delim, GIVE_STRADDR(vlink, name_offs), name_len); 00304 } 00305 00306 00307 00308 /* ******************** string encoding ***************** */ 00309 00310 /* This is quite an ugly function... its purpose is to 00311 * take the dir name, make it absolute, and clean it up, replacing 00312 * excess file entry stuff (like /tmp/../tmp/../) 00313 * note that dir isn't protected for max string names... 00314 * 00315 * If relbase is NULL then its ignored 00316 */ 00317 00318 void BLI_cleanup_path(const char *relabase, char *dir) 00319 { 00320 ptrdiff_t a; 00321 char *start, *eind; 00322 if (relabase) { 00323 BLI_path_abs(dir, relabase); 00324 } else { 00325 if (dir[0]=='/' && dir[1]=='/') { 00326 if (dir[2]== '\0') { 00327 return; /* path is "//" - cant clean it */ 00328 } 00329 dir = dir+2; /* skip the first // */ 00330 } 00331 } 00332 00333 /* Note 00334 * memmove( start, eind, strlen(eind)+1 ); 00335 * is the same as 00336 * strcpy( start, eind ); 00337 * except strcpy should not be used because there is overlap, 00338 * so use memmove's slightly more obscure syntax - Campbell 00339 */ 00340 00341 #ifdef WIN32 00342 00343 /* Note, this should really be moved to the file selector, 00344 * since this function is used in many areas */ 00345 if(strcmp(dir, ".")==0) { /* happens for example in FILE_MAIN */ 00346 get_default_root(dir); 00347 return; 00348 } 00349 00350 while ( (start = strstr(dir, "\\..\\")) ) { 00351 eind = start + strlen("\\..\\") - 1; 00352 a = start-dir-1; 00353 while (a>0) { 00354 if (dir[a] == '\\') break; 00355 a--; 00356 } 00357 if (a<0) { 00358 break; 00359 } else { 00360 memmove( dir+a, eind, strlen(eind)+1 ); 00361 } 00362 } 00363 00364 while ( (start = strstr(dir,"\\.\\")) ){ 00365 eind = start + strlen("\\.\\") - 1; 00366 memmove( start, eind, strlen(eind)+1 ); 00367 } 00368 00369 while ( (start = strstr(dir,"\\\\" )) ){ 00370 eind = start + strlen("\\\\") - 1; 00371 memmove( start, eind, strlen(eind)+1 ); 00372 } 00373 #else 00374 if(dir[0]=='.') { /* happens, for example in FILE_MAIN */ 00375 dir[0]= '/'; 00376 dir[1]= 0; 00377 return; 00378 } 00379 00380 /* support for odd paths: eg /../home/me --> /home/me 00381 * this is a valid path in blender but we cant handle this the useual way below 00382 * simply strip this prefix then evaluate the path as useual. pythons os.path.normpath() does this */ 00383 while((strncmp(dir, "/../", 4)==0)) { 00384 memmove( dir, dir + 4, strlen(dir + 4) + 1 ); 00385 } 00386 00387 while ( (start = strstr(dir, "/../")) ) { 00388 eind = start + (4 - 1) /* strlen("/../") - 1 */; 00389 a = start-dir-1; 00390 while (a>0) { 00391 if (dir[a] == '/') break; 00392 a--; 00393 } 00394 if (a<0) { 00395 break; 00396 } else { 00397 memmove( dir+a, eind, strlen(eind)+1 ); 00398 } 00399 } 00400 00401 while ( (start = strstr(dir,"/./")) ){ 00402 eind = start + (3 - 1) /* strlen("/./") - 1 */; 00403 memmove( start, eind, strlen(eind)+1 ); 00404 } 00405 00406 while ( (start = strstr(dir,"//" )) ){ 00407 eind = start + (2 - 1) /* strlen("//") - 1 */; 00408 memmove( start, eind, strlen(eind)+1 ); 00409 } 00410 #endif 00411 } 00412 00413 void BLI_cleanup_dir(const char *relabase, char *dir) 00414 { 00415 BLI_cleanup_path(relabase, dir); 00416 BLI_add_slash(dir); 00417 00418 } 00419 00420 void BLI_cleanup_file(const char *relabase, char *dir) 00421 { 00422 BLI_cleanup_path(relabase, dir); 00423 BLI_del_slash(dir); 00424 } 00425 00426 void BLI_path_rel(char *file, const char *relfile) 00427 { 00428 char * lslash; 00429 char temp[FILE_MAX]; 00430 char res[FILE_MAX]; 00431 00432 /* if file is already relative, bail out */ 00433 if(file[0]=='/' && file[1]=='/') return; 00434 00435 /* also bail out if relative path is not set */ 00436 if (relfile[0] == 0) return; 00437 00438 #ifdef WIN32 00439 if (BLI_strnlen(relfile, 3) > 2 && relfile[1] != ':') { 00440 char* ptemp; 00441 /* fix missing volume name in relative base, 00442 can happen with old recent-files.txt files */ 00443 get_default_root(temp); 00444 ptemp = &temp[2]; 00445 if (relfile[0] != '\\' && relfile[0] != '/') { 00446 ptemp++; 00447 } 00448 BLI_strncpy(ptemp, relfile, FILE_MAX-3); 00449 } else { 00450 BLI_strncpy(temp, relfile, FILE_MAX); 00451 } 00452 00453 if (BLI_strnlen(file, 3) > 2) { 00454 if ( temp[1] == ':' && file[1] == ':' && temp[0] != file[0] ) 00455 return; 00456 } 00457 #else 00458 BLI_strncpy(temp, relfile, FILE_MAX); 00459 #endif 00460 00461 BLI_char_switch(temp, '\\', '/'); 00462 BLI_char_switch(file, '\\', '/'); 00463 00464 /* remove /./ which confuse the following slash counting... */ 00465 BLI_cleanup_path(NULL, file); 00466 BLI_cleanup_path(NULL, temp); 00467 00468 /* the last slash in the file indicates where the path part ends */ 00469 lslash = BLI_last_slash(temp); 00470 00471 if (lslash) 00472 { 00473 /* find the prefix of the filename that is equal for both filenames. 00474 This is replaced by the two slashes at the beginning */ 00475 char *p= temp; 00476 char *q= file; 00477 00478 #ifdef WIN32 00479 while (tolower(*p) == tolower(*q)) 00480 #else 00481 while (*p == *q) 00482 #endif 00483 { 00484 ++p; ++q; 00485 /* dont search beyond the end of the string 00486 * in the rare case they match */ 00487 if ((*p=='\0') || (*q=='\0')) { 00488 break; 00489 } 00490 } 00491 00492 /* we might have passed the slash when the beginning of a dir matches 00493 so we rewind. Only check on the actual filename 00494 */ 00495 if (*q != '/') { 00496 while ( (q >= file) && (*q != '/') ) { --q; --p; } 00497 } 00498 else if (*p != '/') { 00499 while ( (p >= temp) && (*p != '/') ) { --p; --q; } 00500 } 00501 00502 strcpy(res, "//"); 00503 00504 /* p now points to the slash that is at the beginning of the part 00505 where the path is different from the relative path. 00506 We count the number of directories we need to go up in the 00507 hierarchy to arrive at the common 'prefix' of the path 00508 */ 00509 while (p && p < lslash) { 00510 if (*p == '/') 00511 strcat(res, "../"); 00512 ++p; 00513 } 00514 00515 strcat(res, q+1); /* don't copy the slash at the beginning */ 00516 00517 #ifdef WIN32 00518 BLI_char_switch(res+2, '/', '\\'); 00519 #endif 00520 strcpy(file, res); 00521 } 00522 } 00523 00524 int BLI_has_parent(char *path) 00525 { 00526 int len; 00527 int slashes = 0; 00528 BLI_clean(path); 00529 len = BLI_add_slash(path) - 1; 00530 00531 while (len>=0) { 00532 if ((path[len] == '\\') || (path[len] == '/')) 00533 slashes++; 00534 len--; 00535 } 00536 return slashes > 1; 00537 } 00538 00539 int BLI_parent_dir(char *path) 00540 { 00541 static char parent_dir[]= {'.', '.', SEP, '\0'}; /* "../" or "..\\" */ 00542 char tmp[FILE_MAX+4]; 00543 BLI_strncpy(tmp, path, sizeof(tmp)-4); 00544 BLI_add_slash(tmp); 00545 strcat(tmp, parent_dir); 00546 BLI_cleanup_dir(NULL, tmp); 00547 00548 if (!BLI_testextensie(tmp, parent_dir)) { 00549 BLI_strncpy(path, tmp, sizeof(tmp)); 00550 return 1; 00551 } else { 00552 return 0; 00553 } 00554 } 00555 00556 static int stringframe_chars(char *path, int *char_start, int *char_end) 00557 { 00558 int ch_sta, ch_end, i; 00559 /* Insert current frame: file### -> file001 */ 00560 ch_sta = ch_end = 0; 00561 for (i = 0; path[i] != '\0'; i++) { 00562 if (path[i] == '\\' || path[i] == '/') { 00563 ch_end = 0; /* this is a directory name, dont use any hashes we found */ 00564 } else if (path[i] == '#') { 00565 ch_sta = i; 00566 ch_end = ch_sta+1; 00567 while (path[ch_end] == '#') { 00568 ch_end++; 00569 } 00570 i = ch_end-1; /* keep searching */ 00571 00572 /* dont break, there may be a slash after this that invalidates the previous #'s */ 00573 } 00574 } 00575 00576 if(ch_end) { 00577 *char_start= ch_sta; 00578 *char_end= ch_end; 00579 return 1; 00580 } 00581 else { 00582 *char_start= -1; 00583 *char_end= -1; 00584 return 0; 00585 } 00586 } 00587 00588 static void ensure_digits(char *path, int digits) 00589 { 00590 char *file= BLI_last_slash(path); 00591 00592 if(file==NULL) 00593 file= path; 00594 00595 if(strrchr(file, '#') == NULL) { 00596 int len= strlen(file); 00597 00598 while(digits--) { 00599 file[len++]= '#'; 00600 } 00601 file[len]= '\0'; 00602 } 00603 } 00604 00605 int BLI_path_frame(char *path, int frame, int digits) 00606 { 00607 int ch_sta, ch_end; 00608 00609 if(digits) 00610 ensure_digits(path, digits); 00611 00612 if (stringframe_chars(path, &ch_sta, &ch_end)) { /* warning, ch_end is the last # +1 */ 00613 char tmp[FILE_MAX]; 00614 sprintf(tmp, "%.*s%.*d%s", ch_sta, path, ch_end-ch_sta, frame, path+ch_end); 00615 strcpy(path, tmp); 00616 return 1; 00617 } 00618 return 0; 00619 } 00620 00621 int BLI_path_frame_range(char *path, int sta, int end, int digits) 00622 { 00623 int ch_sta, ch_end; 00624 00625 if(digits) 00626 ensure_digits(path, digits); 00627 00628 if (stringframe_chars(path, &ch_sta, &ch_end)) { /* warning, ch_end is the last # +1 */ 00629 char tmp[FILE_MAX]; 00630 BLI_snprintf(tmp, sizeof(tmp), 00631 "%.*s%.*d-%.*d%s", 00632 ch_sta, path, ch_end-ch_sta, sta, ch_end-ch_sta, end, path+ch_end); 00633 BLI_strncpy(path, tmp, FILE_MAX); 00634 return 1; 00635 } 00636 return 0; 00637 } 00638 00639 int BLI_path_abs(char *path, const char *basepath) 00640 { 00641 int wasrelative = (strncmp(path, "//", 2)==0); 00642 char tmp[FILE_MAX]; 00643 char base[FILE_MAX]; 00644 #ifdef WIN32 00645 char vol[3] = {'\0', '\0', '\0'}; 00646 00647 BLI_strncpy(vol, path, 3); 00648 /* we are checking here if we have an absolute path that is not in the current 00649 blend file as a lib main - we are basically checking for the case that a 00650 UNIX root '/' is passed. 00651 */ 00652 if (!wasrelative && (vol[1] != ':' && (vol[0] == '\0' || vol[0] == '/' || vol[0] == '\\'))) { 00653 char *p = path; 00654 get_default_root(tmp); 00655 // get rid of the slashes at the beginning of the path 00656 while (*p == '\\' || *p == '/') { 00657 p++; 00658 } 00659 strcat(tmp, p); 00660 } 00661 else { 00662 BLI_strncpy(tmp, path, FILE_MAX); 00663 } 00664 #else 00665 BLI_strncpy(tmp, path, sizeof(tmp)); 00666 00667 /* Check for loading a windows path on a posix system 00668 * in this case, there is no use in trying C:/ since it 00669 * will never exist on a unix os. 00670 * 00671 * Add a / prefix and lowercase the driveletter, remove the : 00672 * C:\foo.JPG -> /c/foo.JPG */ 00673 00674 if (isalpha(tmp[0]) && tmp[1] == ':' && (tmp[2]=='\\' || tmp[2]=='/') ) { 00675 tmp[1] = tolower(tmp[0]); /* replace ':' with driveletter */ 00676 tmp[0] = '/'; 00677 /* '\' the slash will be converted later */ 00678 } 00679 00680 #endif 00681 00682 BLI_strncpy(base, basepath, sizeof(base)); 00683 00684 /* file component is ignored, so dont bother with the trailing slash */ 00685 BLI_cleanup_path(NULL, base); 00686 00687 /* push slashes into unix mode - strings entering this part are 00688 potentially messed up: having both back- and forward slashes. 00689 Here we push into one conform direction, and at the end we 00690 push them into the system specific dir. This ensures uniformity 00691 of paths and solving some problems (and prevent potential future 00692 ones) -jesterKing. */ 00693 BLI_char_switch(tmp, '\\', '/'); 00694 BLI_char_switch(base, '\\', '/'); 00695 00696 /* Paths starting with // will get the blend file as their base, 00697 * this isnt standard in any os but is uesed in blender all over the place */ 00698 if (wasrelative) { 00699 char *lslash= BLI_last_slash(base); 00700 if (lslash) { 00701 int baselen= (int) (lslash-base) + 1; 00702 /* use path for temp storage here, we copy back over it right away */ 00703 BLI_strncpy(path, tmp+2, FILE_MAX); 00704 00705 memcpy(tmp, base, baselen); 00706 BLI_strncpy(tmp+baselen, path, sizeof(tmp)-baselen); 00707 BLI_strncpy(path, tmp, FILE_MAX); 00708 } else { 00709 BLI_strncpy(path, tmp+2, FILE_MAX); 00710 } 00711 } else { 00712 BLI_strncpy(path, tmp, FILE_MAX); 00713 } 00714 00715 BLI_cleanup_path(NULL, path); 00716 00717 #ifdef WIN32 00718 /* skip first two chars, which in case of 00719 absolute path will be drive:/blabla and 00720 in case of relpath //blabla/. So relpath 00721 // will be retained, rest will be nice and 00722 shiny win32 backward slashes :) -jesterKing 00723 */ 00724 BLI_char_switch(path+2, '/', '\\'); 00725 #endif 00726 00727 return wasrelative; 00728 } 00729 00730 00731 /* 00732 * Should only be done with command line paths. 00733 * this is NOT somthing blenders internal paths support like the // prefix 00734 */ 00735 int BLI_path_cwd(char *path) 00736 { 00737 int wasrelative = 1; 00738 int filelen = strlen(path); 00739 00740 #ifdef WIN32 00741 if (filelen >= 3 && path[1] == ':' && (path[2] == '\\' || path[2] == '/')) 00742 wasrelative = 0; 00743 #else 00744 if (filelen >= 2 && path[0] == '/') 00745 wasrelative = 0; 00746 #endif 00747 00748 if (wasrelative==1) { 00749 char cwd[FILE_MAX]= ""; 00750 BLI_current_working_dir(cwd, sizeof(cwd)); /* incase the full path to the blend isnt used */ 00751 00752 if (cwd[0] == '\0') { 00753 printf( "Could not get the current working directory - $PWD for an unknown reason."); 00754 } else { 00755 /* uses the blend path relative to cwd important for loading relative linked files. 00756 * 00757 * cwd should contain c:\ etc on win32 so the relbase can be NULL 00758 * relbase being NULL also prevents // being misunderstood as relative to the current 00759 * blend file which isnt a feature we want to use in this case since were dealing 00760 * with a path from the command line, rather than from inside Blender */ 00761 00762 char origpath[FILE_MAX]; 00763 BLI_strncpy(origpath, path, FILE_MAX); 00764 00765 BLI_make_file_string(NULL, path, cwd, origpath); 00766 } 00767 } 00768 00769 return wasrelative; 00770 } 00771 00772 00773 /* 'di's filename component is moved into 'fi', di is made a dir path */ 00774 void BLI_splitdirstring(char *di, char *fi) 00775 { 00776 char *lslash= BLI_last_slash(di); 00777 00778 if (lslash) { 00779 BLI_strncpy(fi, lslash+1, FILE_MAXFILE); 00780 *(lslash+1)=0; 00781 } else { 00782 BLI_strncpy(fi, di, FILE_MAXFILE); 00783 di[0]= 0; 00784 } 00785 } 00786 00787 void BLI_getlastdir(const char* dir, char *last, const size_t maxlen) 00788 { 00789 const char *s = dir; 00790 const char *lslash = NULL; 00791 const char *prevslash = NULL; 00792 while (*s) { 00793 if ((*s == '\\') || (*s == '/')) { 00794 prevslash = lslash; 00795 lslash = s; 00796 } 00797 s++; 00798 } 00799 if (prevslash) { 00800 BLI_strncpy(last, prevslash+1, maxlen); 00801 } else { 00802 BLI_strncpy(last, dir, maxlen); 00803 } 00804 } 00805 00806 /* This is now only used to really get the user's default document folder */ 00807 /* On Windows I chose the 'Users/<MyUserName>/Documents' since it's used 00808 as default location to save documents */ 00809 const char *BLI_getDefaultDocumentFolder(void) 00810 { 00811 #ifndef WIN32 00812 00813 #ifdef WITH_XDG_USER_DIRS 00814 const char *xdg_documents_dir= getenv("XDG_DOCUMENTS_DIR"); 00815 if (xdg_documents_dir) { 00816 return xdg_documents_dir; 00817 } 00818 #endif 00819 00820 return getenv("HOME"); 00821 00822 #else /* Windows */ 00823 const char * ret; 00824 static char documentfolder[MAXPATHLEN]; 00825 HRESULT hResult; 00826 00827 /* Check for %HOME% env var */ 00828 00829 ret = getenv("HOME"); 00830 if(ret) { 00831 if (BLI_is_dir(ret)) return ret; 00832 } 00833 00834 /* add user profile support for WIN 2K / NT. 00835 * This is %APPDATA%, which translates to either 00836 * %USERPROFILE%\Application Data or since Vista 00837 * to %USERPROFILE%\AppData\Roaming 00838 */ 00839 hResult = SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, documentfolder); 00840 00841 if (hResult == S_OK) 00842 { 00843 if (BLI_is_dir(documentfolder)) return documentfolder; 00844 } 00845 00846 return NULL; 00847 #endif /* WIN32 */ 00848 } 00849 00850 /* NEW stuff, to be cleaned up when fully migrated */ 00851 /* ************************************************************* */ 00852 /* ************************************************************* */ 00853 00854 // #define PATH_DEBUG2 00855 00856 static char *blender_version_decimal(const int ver) 00857 { 00858 static char version_str[5]; 00859 sprintf(version_str, "%d.%02d", ver/100, ver%100); 00860 return version_str; 00861 } 00862 00863 static int test_path(char *targetpath, const char *path_base, const char *path_sep, const char *folder_name) 00864 { 00865 char tmppath[FILE_MAX]; 00866 00867 if(path_sep) BLI_join_dirfile(tmppath, sizeof(tmppath), path_base, path_sep); 00868 else BLI_strncpy(tmppath, path_base, sizeof(tmppath)); 00869 00870 /* rare cases folder_name is omitted (when looking for ~/.blender/2.xx dir only) */ 00871 if(folder_name) 00872 BLI_make_file_string("/", targetpath, tmppath, folder_name); 00873 else 00874 BLI_strncpy(targetpath, tmppath, sizeof(tmppath)); 00875 00876 if (BLI_is_dir(targetpath)) { 00877 #ifdef PATH_DEBUG2 00878 printf("\tpath found: %s\n", targetpath); 00879 #endif 00880 return 1; 00881 } 00882 else { 00883 #ifdef PATH_DEBUG2 00884 printf("\tpath missing: %s\n", targetpath); 00885 #endif 00886 //targetpath[0] = '\0'; 00887 return 0; 00888 } 00889 } 00890 00891 static int test_env_path(char *path, const char *envvar) 00892 { 00893 const char *env = envvar?getenv(envvar):NULL; 00894 if (!env) return 0; 00895 00896 if (BLI_is_dir(env)) { 00897 BLI_strncpy(path, env, FILE_MAX); 00898 return 1; 00899 } else { 00900 path[0] = '\0'; 00901 return 0; 00902 } 00903 } 00904 00905 static int get_path_local(char *targetpath, const char *folder_name, const char *subfolder_name, const int ver) 00906 { 00907 char relfolder[FILE_MAX]; 00908 00909 #ifdef PATH_DEBUG2 00910 printf("get_path_local...\n"); 00911 #endif 00912 00913 if(folder_name) { 00914 if (subfolder_name) { 00915 BLI_join_dirfile(relfolder, sizeof(relfolder), folder_name, subfolder_name); 00916 } else { 00917 BLI_strncpy(relfolder, folder_name, sizeof(relfolder)); 00918 } 00919 } 00920 else { 00921 relfolder[0]= '\0'; 00922 } 00923 00924 /* try EXECUTABLE_DIR/2.5x/folder_name - new default directory for local blender installed files */ 00925 if(test_path(targetpath, bprogdir, blender_version_decimal(ver), relfolder)) 00926 return 1; 00927 00928 return 0; 00929 } 00930 00931 static int is_portable_install(void) 00932 { 00933 /* detect portable install by the existance of config folder */ 00934 const int ver= BLENDER_VERSION; 00935 char path[FILE_MAX]; 00936 00937 return get_path_local(path, "config", NULL, ver); 00938 } 00939 00940 static int get_path_user(char *targetpath, const char *folder_name, const char *subfolder_name, const char *envvar, const int ver) 00941 { 00942 char user_path[FILE_MAX]; 00943 const char *user_base_path; 00944 00945 /* for portable install, user path is always local */ 00946 if (is_portable_install()) 00947 return get_path_local(targetpath, folder_name, subfolder_name, ver); 00948 00949 user_path[0] = '\0'; 00950 00951 if (test_env_path(user_path, envvar)) { 00952 if (subfolder_name) { 00953 return test_path(targetpath, user_path, NULL, subfolder_name); 00954 } else { 00955 BLI_strncpy(targetpath, user_path, FILE_MAX); 00956 return 1; 00957 } 00958 } 00959 00960 user_base_path = (const char *)GHOST_getUserDir(); 00961 if (user_base_path) { 00962 BLI_snprintf(user_path, FILE_MAX, BLENDER_USER_FORMAT, user_base_path, blender_version_decimal(ver)); 00963 } 00964 00965 if(!user_path[0]) 00966 return 0; 00967 00968 #ifdef PATH_DEBUG2 00969 printf("get_path_user: %s\n", user_path); 00970 #endif 00971 00972 if (subfolder_name) { 00973 /* try $HOME/folder_name/subfolder_name */ 00974 return test_path(targetpath, user_path, folder_name, subfolder_name); 00975 } else { 00976 /* try $HOME/folder_name */ 00977 return test_path(targetpath, user_path, NULL, folder_name); 00978 } 00979 } 00980 00981 static int get_path_system(char *targetpath, const char *folder_name, const char *subfolder_name, const char *envvar, const int ver) 00982 { 00983 char system_path[FILE_MAX]; 00984 const char *system_base_path; 00985 00986 00987 /* first allow developer only overrides to the system path 00988 * these are only used when running blender from source */ 00989 char cwd[FILE_MAX]; 00990 char relfolder[FILE_MAX]; 00991 00992 if(folder_name) { 00993 if (subfolder_name) { 00994 BLI_join_dirfile(relfolder, sizeof(relfolder), folder_name, subfolder_name); 00995 } else { 00996 BLI_strncpy(relfolder, folder_name, sizeof(relfolder)); 00997 } 00998 } 00999 else { 01000 relfolder[0]= '\0'; 01001 } 01002 01003 /* try CWD/release/folder_name */ 01004 if(BLI_current_working_dir(cwd, sizeof(cwd))) { 01005 if(test_path(targetpath, cwd, "release", relfolder)) { 01006 return 1; 01007 } 01008 } 01009 01010 /* try EXECUTABLE_DIR/release/folder_name */ 01011 if(test_path(targetpath, bprogdir, "release", relfolder)) 01012 return 1; 01013 /* end developer overrides */ 01014 01015 01016 01017 system_path[0] = '\0'; 01018 01019 if (test_env_path(system_path, envvar)) { 01020 if (subfolder_name) { 01021 return test_path(targetpath, system_path, NULL, subfolder_name); 01022 } else { 01023 BLI_strncpy(targetpath, system_path, FILE_MAX); 01024 return 1; 01025 } 01026 } 01027 01028 system_base_path = (const char *)GHOST_getSystemDir(); 01029 if (system_base_path) { 01030 BLI_snprintf(system_path, FILE_MAX, BLENDER_SYSTEM_FORMAT, system_base_path, blender_version_decimal(ver)); 01031 } 01032 01033 if(!system_path[0]) 01034 return 0; 01035 01036 #ifdef PATH_DEBUG2 01037 printf("get_path_system: %s\n", system_path); 01038 #endif 01039 01040 if (subfolder_name) { 01041 /* try $BLENDERPATH/folder_name/subfolder_name */ 01042 return test_path(targetpath, system_path, folder_name, subfolder_name); 01043 } else { 01044 /* try $BLENDERPATH/folder_name */ 01045 return test_path(targetpath, system_path, NULL, folder_name); 01046 } 01047 } 01048 01049 /* get a folder out of the 'folder_id' presets for paths */ 01050 /* returns the path if found, NULL string if not */ 01051 char *BLI_get_folder(int folder_id, const char *subfolder) 01052 { 01053 const int ver= BLENDER_VERSION; 01054 static char path[FILE_MAX] = ""; 01055 01056 switch (folder_id) { 01057 case BLENDER_DATAFILES: /* general case */ 01058 if (get_path_user(path, "datafiles", subfolder, "BLENDER_USER_DATAFILES", ver)) break; 01059 if (get_path_local(path, "datafiles", subfolder, ver)) break; 01060 if (get_path_system(path, "datafiles", subfolder, "BLENDER_SYSTEM_DATAFILES", ver)) break; 01061 return NULL; 01062 01063 case BLENDER_USER_DATAFILES: 01064 if (get_path_user(path, "datafiles", subfolder, "BLENDER_USER_DATAFILES", ver)) break; 01065 return NULL; 01066 01067 case BLENDER_SYSTEM_DATAFILES: 01068 if (get_path_local(path, "datafiles", subfolder, ver)) break; 01069 if (get_path_system(path, "datafiles", subfolder, "BLENDER_SYSTEM_DATAFILES", ver)) break; 01070 return NULL; 01071 01072 case BLENDER_USER_AUTOSAVE: 01073 if (get_path_user(path, "autosave", subfolder, "BLENDER_USER_DATAFILES", ver)) break; 01074 return NULL; 01075 01076 case BLENDER_USER_CONFIG: 01077 if (get_path_user(path, "config", subfolder, "BLENDER_USER_CONFIG", ver)) break; 01078 return NULL; 01079 01080 case BLENDER_USER_SCRIPTS: 01081 if (get_path_user(path, "scripts", subfolder, "BLENDER_USER_SCRIPTS", ver)) break; 01082 return NULL; 01083 01084 case BLENDER_SYSTEM_SCRIPTS: 01085 if (get_path_local(path, "scripts", subfolder, ver)) break; 01086 if (get_path_system(path, "scripts", subfolder, "BLENDER_SYSTEM_SCRIPTS", ver)) break; 01087 return NULL; 01088 01089 case BLENDER_SYSTEM_PYTHON: 01090 if (get_path_local(path, "python", subfolder, ver)) break; 01091 if (get_path_system(path, "python", subfolder, "BLENDER_SYSTEM_PYTHON", ver)) break; 01092 return NULL; 01093 } 01094 01095 return path; 01096 } 01097 01098 char *BLI_get_user_folder_notest(int folder_id, const char *subfolder) 01099 { 01100 const int ver= BLENDER_VERSION; 01101 static char path[FILE_MAX] = ""; 01102 01103 switch (folder_id) { 01104 case BLENDER_USER_DATAFILES: 01105 get_path_user(path, "datafiles", subfolder, "BLENDER_USER_DATAFILES", ver); 01106 break; 01107 case BLENDER_USER_CONFIG: 01108 get_path_user(path, "config", subfolder, "BLENDER_USER_CONFIG", ver); 01109 break; 01110 case BLENDER_USER_AUTOSAVE: 01111 get_path_user(path, "autosave", subfolder, "BLENDER_USER_AUTOSAVE", ver); 01112 break; 01113 case BLENDER_USER_SCRIPTS: 01114 get_path_user(path, "scripts", subfolder, "BLENDER_USER_SCRIPTS", ver); 01115 break; 01116 } 01117 if ('\0' == path[0]) { 01118 return NULL; 01119 } 01120 return path; 01121 } 01122 01123 char *BLI_get_folder_create(int folder_id, const char *subfolder) 01124 { 01125 char *path; 01126 01127 /* only for user folders */ 01128 if (!ELEM4(folder_id, BLENDER_USER_DATAFILES, BLENDER_USER_CONFIG, BLENDER_USER_SCRIPTS, BLENDER_USER_AUTOSAVE)) 01129 return NULL; 01130 01131 path = BLI_get_folder(folder_id, subfolder); 01132 01133 if (!path) { 01134 path = BLI_get_user_folder_notest(folder_id, subfolder); 01135 if (path) BLI_dir_create_recursive(path); 01136 } 01137 01138 return path; 01139 } 01140 01141 char *BLI_get_folder_version(const int id, const int ver, const int do_check) 01142 { 01143 static char path[FILE_MAX] = ""; 01144 int ok; 01145 switch(id) { 01146 case BLENDER_RESOURCE_PATH_USER: 01147 ok= get_path_user(path, NULL, NULL, NULL, ver); 01148 break; 01149 case BLENDER_RESOURCE_PATH_LOCAL: 01150 ok= get_path_local(path, NULL, NULL, ver); 01151 break; 01152 case BLENDER_RESOURCE_PATH_SYSTEM: 01153 ok= get_path_system(path, NULL, NULL, NULL, ver); 01154 break; 01155 default: 01156 path[0]= '\0'; /* incase do_check is false */ 01157 ok= FALSE; 01158 BLI_assert(!"incorrect ID"); 01159 } 01160 01161 if((ok == FALSE) && do_check) { 01162 return NULL; 01163 } 01164 01165 return path; 01166 } 01167 01168 /* End new stuff */ 01169 /* ************************************************************* */ 01170 /* ************************************************************* */ 01171 01172 01173 01174 #ifdef PATH_DEBUG 01175 #undef PATH_DEBUG 01176 #endif 01177 01178 void BLI_setenv(const char *env, const char*val) 01179 { 01180 /* free windows */ 01181 #if (defined(WIN32) || defined(WIN64)) && defined(FREE_WINDOWS) 01182 char *envstr= MEM_mallocN(sizeof(char) * (strlen(env) + strlen(val) + 2), "envstr"); /* one for = another for \0 */ 01183 01184 sprintf(envstr, "%s=%s", env, val); 01185 putenv(envstr); 01186 MEM_freeN(envstr); 01187 01188 /* non-free windows */ 01189 #elif (defined(WIN32) || defined(WIN64)) /* not free windows */ 01190 _putenv_s(env, val); 01191 #else 01192 /* linux/osx/bsd */ 01193 setenv(env, val, 1); 01194 #endif 01195 } 01196 01197 01202 void BLI_setenv_if_new(const char *env, const char* val) 01203 { 01204 if(getenv(env) == NULL) 01205 BLI_setenv(env, val); 01206 } 01207 01208 01209 void BLI_clean(char *path) 01210 { 01211 if(path==NULL) return; 01212 01213 #ifdef WIN32 01214 if(path && BLI_strnlen(path, 3) > 2) { 01215 BLI_char_switch(path+2, '/', '\\'); 01216 } 01217 #else 01218 BLI_char_switch(path, '\\', '/'); 01219 #endif 01220 } 01221 01222 void BLI_char_switch(char *string, char from, char to) 01223 { 01224 if(string==NULL) return; 01225 while (*string != 0) { 01226 if (*string == from) *string = to; 01227 string++; 01228 } 01229 } 01230 01231 void BLI_make_exist(char *dir) 01232 { 01233 int a; 01234 01235 BLI_char_switch(dir, ALTSEP, SEP); 01236 01237 a = strlen(dir); 01238 01239 while(BLI_is_dir(dir) == 0){ 01240 a --; 01241 while(dir[a] != SEP){ 01242 a--; 01243 if (a <= 0) break; 01244 } 01245 if (a >= 0) { 01246 dir[a+1] = '\0'; 01247 } 01248 else { 01249 #ifdef WIN32 01250 get_default_root(dir); 01251 #else 01252 strcpy(dir,"/"); 01253 #endif 01254 break; 01255 } 01256 } 01257 } 01258 01259 void BLI_make_existing_file(const char *name) 01260 { 01261 char di[FILE_MAX], fi[FILE_MAXFILE]; 01262 01263 BLI_strncpy(di, name, sizeof(di)); 01264 BLI_splitdirstring(di, fi); 01265 01266 /* test exist */ 01267 if (BLI_exists(di) == 0) { 01268 BLI_dir_create_recursive(di); 01269 } 01270 } 01271 01272 01273 void BLI_make_file_string(const char *relabase, char *string, const char *dir, const char *file) 01274 { 01275 int sl; 01276 01277 if (string) { 01278 /* ensure this is always set even if dir/file are NULL */ 01279 string[0]= '\0'; 01280 01281 if (ELEM(NULL, dir, file)) { 01282 return; /* We don't want any NULLs */ 01283 } 01284 } 01285 else { 01286 return; /* string is NULL, probably shouldnt happen but return anyway */ 01287 } 01288 01289 01290 /* we first push all slashes into unix mode, just to make sure we don't get 01291 any mess with slashes later on. -jesterKing */ 01292 /* constant strings can be passed for those parameters - don't change them - elubie */ 01293 /* 01294 BLI_char_switch(relabase, '\\', '/'); 01295 BLI_char_switch(dir, '\\', '/'); 01296 BLI_char_switch(file, '\\', '/'); 01297 */ 01298 01299 /* Resolve relative references */ 01300 if (relabase && dir[0] == '/' && dir[1] == '/') { 01301 char *lslash; 01302 01303 /* Get the file name, chop everything past the last slash (ie. the filename) */ 01304 strcpy(string, relabase); 01305 01306 lslash= BLI_last_slash(string); 01307 if(lslash) *(lslash+1)= 0; 01308 01309 dir+=2; /* Skip over the relative reference */ 01310 } 01311 #ifdef WIN32 01312 else { 01313 if (BLI_strnlen(dir, 3) >= 2 && dir[1] == ':' ) { 01314 BLI_strncpy(string, dir, 3); 01315 dir += 2; 01316 } 01317 else { /* no drive specified */ 01318 /* first option: get the drive from the relabase if it has one */ 01319 if (relabase && strlen(relabase) >= 2 && relabase[1] == ':' ) { 01320 BLI_strncpy(string, relabase, 3); 01321 string[2] = '\\'; 01322 string[3] = '\0'; 01323 } 01324 else { /* we're out of luck here, guessing the first valid drive, usually c:\ */ 01325 get_default_root(string); 01326 } 01327 01328 /* ignore leading slashes */ 01329 while (*dir == '/' || *dir == '\\') dir++; 01330 } 01331 } 01332 #endif 01333 01334 strcat(string, dir); 01335 01336 /* Make sure string ends in one (and only one) slash */ 01337 /* first trim all slashes from the end of the string */ 01338 sl = strlen(string); 01339 while (sl>0 && ( string[sl-1] == '/' || string[sl-1] == '\\') ) { 01340 string[sl-1] = '\0'; 01341 sl--; 01342 } 01343 /* since we've now removed all slashes, put back one slash at the end. */ 01344 strcat(string, "/"); 01345 01346 while (*file && (*file == '/' || *file == '\\')) /* Trim slashes from the front of file */ 01347 file++; 01348 01349 strcat (string, file); 01350 01351 /* Push all slashes to the system preferred direction */ 01352 BLI_clean(string); 01353 } 01354 01355 int BLI_testextensie(const char *str, const char *ext) 01356 { 01357 short a, b; 01358 int retval; 01359 01360 a= strlen(str); 01361 b= strlen(ext); 01362 01363 if(a==0 || b==0 || b>=a) { 01364 retval = 0; 01365 } else if (BLI_strcasecmp(ext, str + a - b)) { 01366 retval = 0; 01367 } else { 01368 retval = 1; 01369 } 01370 01371 return (retval); 01372 } 01373 01374 int BLI_testextensie_array(const char *str, const char **ext_array) 01375 { 01376 int i=0; 01377 while(ext_array[i]) { 01378 if(BLI_testextensie(str, ext_array[i])) { 01379 return 1; 01380 } 01381 01382 i++; 01383 } 01384 return 0; 01385 } 01386 01387 /* semicolon separated wildcards, eg: 01388 * '*.zip;*.py;*.exe' */ 01389 int BLI_testextensie_glob(const char *str, const char *ext_fnmatch) 01390 { 01391 const char *ext_step= ext_fnmatch; 01392 char pattern[16]; 01393 01394 while(ext_step[0]) { 01395 char *ext_next; 01396 int len_ext; 01397 01398 if((ext_next=strchr(ext_step, ';'))) { 01399 len_ext= (int)(ext_next - ext_step) + 1; 01400 } 01401 else { 01402 len_ext= sizeof(pattern); 01403 } 01404 01405 BLI_strncpy(pattern, ext_step, len_ext); 01406 01407 if(fnmatch(pattern, str, FNM_CASEFOLD)==0) { 01408 return 1; 01409 } 01410 ext_step += len_ext; 01411 } 01412 01413 return 0; 01414 } 01415 01416 01417 int BLI_replace_extension(char *path, size_t maxlen, const char *ext) 01418 { 01419 size_t path_len= strlen(path); 01420 size_t ext_len= strlen(ext); 01421 ssize_t a; 01422 01423 for(a= path_len - 1; a >= 0; a--) { 01424 if (ELEM3(path[a], '.', '/', '\\')) { 01425 break; 01426 } 01427 } 01428 01429 if ((a < 0) || (path[a] != '.')) { 01430 a= path_len; 01431 } 01432 01433 if(a + ext_len >= maxlen) 01434 return 0; 01435 01436 memcpy(path+a, ext, ext_len + 1); 01437 return 1; 01438 } 01439 01440 /* strip's trailing '.'s and adds the extension only when needed */ 01441 int BLI_ensure_extension(char *path, size_t maxlen, const char *ext) 01442 { 01443 size_t path_len= strlen(path); 01444 size_t ext_len= strlen(ext); 01445 ssize_t a; 01446 01447 /* first check the extension is alread there */ 01448 if ( (ext_len <= path_len) && 01449 (strcmp(path + (path_len - ext_len), ext) == 0)) 01450 { 01451 return 1; 01452 } 01453 01454 for(a= path_len - 1; a >= 0; a--) { 01455 if (path[a] == '.') { 01456 path[a]= '\0'; 01457 } 01458 else { 01459 break; 01460 } 01461 } 01462 a++; 01463 01464 if(a + ext_len >= maxlen) 01465 return 0; 01466 01467 memcpy(path+a, ext, ext_len + 1); 01468 return 1; 01469 } 01470 01471 /* Converts "/foo/bar.txt" to "/foo/" and "bar.txt" 01472 * - wont change 'string' 01473 * - wont create any directories 01474 * - dosnt use CWD, or deal with relative paths. 01475 * - Only fill's in *dir and *file when they are non NULL 01476 * */ 01477 void BLI_split_dirfile(const char *string, char *dir, char *file, const size_t dirlen, const size_t filelen) 01478 { 01479 char *lslash_str = BLI_last_slash(string); 01480 size_t lslash= lslash_str ? (size_t)(lslash_str - string) + 1 : 0; 01481 01482 if (dir) { 01483 if (lslash) { 01484 BLI_strncpy( dir, string, MIN2(dirlen, lslash + 1)); /* +1 to include the slash and the last char */ 01485 } 01486 else { 01487 dir[0] = '\0'; 01488 } 01489 } 01490 01491 if (file) { 01492 BLI_strncpy(file, string+lslash, filelen); 01493 } 01494 } 01495 01496 void BLI_split_dir_part(const char *string, char *dir, const size_t dirlen) 01497 { 01498 BLI_split_dirfile(string, dir, NULL, dirlen, 0); 01499 } 01500 01501 void BLI_split_file_part(const char *string, char *file, const size_t filelen) 01502 { 01503 BLI_split_dirfile(string, NULL, file, 0, filelen); 01504 } 01505 01506 /* simple appending of filename to dir, does not check for valid path! */ 01507 void BLI_join_dirfile(char *dst, const size_t maxlen, const char *dir, const char *file) 01508 { 01509 size_t dirlen= BLI_strnlen(dir, maxlen); 01510 01511 if (dst != dir) { 01512 if(dirlen == maxlen) { 01513 memcpy(dst, dir, dirlen); 01514 dst[dirlen - 1]= '\0'; 01515 return; /* dir fills the path */ 01516 } 01517 else { 01518 memcpy(dst, dir, dirlen + 1); 01519 } 01520 } 01521 01522 if (dirlen + 1 >= maxlen) { 01523 return; /* fills the path */ 01524 } 01525 01526 /* inline BLI_add_slash */ 01527 if (dst[dirlen - 1] != SEP) { 01528 dst[dirlen++]= SEP; 01529 dst[dirlen ]= '\0'; 01530 } 01531 01532 if (dirlen >= maxlen) { 01533 return; /* fills the path */ 01534 } 01535 01536 if (file == NULL) { 01537 return; 01538 } 01539 01540 BLI_strncpy(dst + dirlen, file, maxlen - dirlen); 01541 } 01542 01543 /* like pythons os.path.basename( ) */ 01544 char *BLI_path_basename(char *path) 01545 { 01546 char *filename= BLI_last_slash(path); 01547 return filename ? filename + 1 : path; 01548 } 01549 01550 /* 01551 Produce image export path. 01552 01553 Fails returning 0 if image filename is empty or if destination path 01554 matches image path (i.e. both are the same file). 01555 01556 Trailing slash in dest_dir is optional. 01557 01558 Logic: 01559 01560 - if an image is "below" current .blend file directory, rebuild the 01561 same dir structure in dest_dir 01562 01563 For example //textures/foo/bar.png becomes 01564 [dest_dir]/textures/foo/bar.png. 01565 01566 - if an image is not "below" current .blend file directory, 01567 disregard it's path and copy it in the same directory where 3D file 01568 goes. 01569 01570 For example //../foo/bar.png becomes [dest_dir]/bar.png. 01571 01572 This logic will help ensure that all image paths are relative and 01573 that a user gets his images in one place. It'll also provide 01574 consistent behaviour across exporters. 01575 */ 01576 int BKE_rebase_path(char *abs, size_t abs_len, char *rel, size_t rel_len, const char *base_dir, const char *src_dir, const char *dest_dir) 01577 { 01578 char path[FILE_MAX]; 01579 char dir[FILE_MAX]; 01580 char base[FILE_MAX]; 01581 char blend_dir[FILE_MAX]; /* directory, where current .blend file resides */ 01582 char dest_path[FILE_MAX]; 01583 char rel_dir[FILE_MAX]; 01584 int len; 01585 01586 if (abs) 01587 abs[0]= 0; 01588 01589 if (rel) 01590 rel[0]= 0; 01591 01592 BLI_split_dir_part(base_dir, blend_dir, sizeof(blend_dir)); 01593 01594 if (src_dir[0]=='\0') 01595 return 0; 01596 01597 BLI_strncpy(path, src_dir, sizeof(path)); 01598 01599 /* expand "//" in filename and get absolute path */ 01600 BLI_path_abs(path, base_dir); 01601 01602 /* get the directory part */ 01603 BLI_split_dirfile(path, dir, base, sizeof(dir), sizeof(base)); 01604 01605 len= strlen(blend_dir); 01606 01607 rel_dir[0] = 0; 01608 01609 /* if image is "below" current .blend file directory */ 01610 if (!strncmp(path, blend_dir, len)) { 01611 01612 /* if image is _in_ current .blend file directory */ 01613 if (BLI_path_cmp(dir, blend_dir) == 0) { 01614 BLI_join_dirfile(dest_path, sizeof(dest_path), dest_dir, base); 01615 } 01616 /* "below" */ 01617 else { 01618 /* rel = image_path_dir - blend_dir */ 01619 BLI_strncpy(rel_dir, dir + len, sizeof(rel_dir)); 01620 01621 BLI_join_dirfile(dest_path, sizeof(dest_path), dest_dir, rel_dir); 01622 BLI_join_dirfile(dest_path, sizeof(dest_path), dest_path, base); 01623 } 01624 01625 } 01626 /* image is out of current directory */ 01627 else { 01628 BLI_join_dirfile(dest_path, sizeof(dest_path), dest_dir, base); 01629 } 01630 01631 if (abs) 01632 BLI_strncpy(abs, dest_path, abs_len); 01633 01634 if (rel) { 01635 strncat(rel, rel_dir, rel_len); 01636 strncat(rel, base, rel_len); 01637 } 01638 01639 /* return 2 if src=dest */ 01640 if (BLI_path_cmp(path, dest_path) == 0) { 01641 // if (G.f & G_DEBUG) printf("%s and %s are the same file\n", path, dest_path); 01642 return 2; 01643 } 01644 01645 return 1; 01646 } 01647 01648 char *BLI_first_slash(char *string) 01649 { 01650 char *ffslash, *fbslash; 01651 01652 ffslash= strchr(string, '/'); 01653 fbslash= strchr(string, '\\'); 01654 01655 if (!ffslash) return fbslash; 01656 else if (!fbslash) return ffslash; 01657 01658 if ((intptr_t)ffslash < (intptr_t)fbslash) return ffslash; 01659 else return fbslash; 01660 } 01661 01662 char *BLI_last_slash(const char *string) 01663 { 01664 char *lfslash, *lbslash; 01665 01666 lfslash= strrchr(string, '/'); 01667 lbslash= strrchr(string, '\\'); 01668 01669 if (!lfslash) return lbslash; 01670 else if (!lbslash) return lfslash; 01671 01672 if ((intptr_t)lfslash < (intptr_t)lbslash) return lbslash; 01673 else return lfslash; 01674 } 01675 01676 /* adds a slash if there isnt one there already */ 01677 int BLI_add_slash(char *string) 01678 { 01679 int len = strlen(string); 01680 if (len==0 || string[len-1] != SEP) { 01681 string[len] = SEP; 01682 string[len+1] = '\0'; 01683 return len+1; 01684 } 01685 return len; 01686 } 01687 01688 /* removes a slash if there is one */ 01689 void BLI_del_slash(char *string) 01690 { 01691 int len = strlen(string); 01692 while (len) { 01693 if (string[len-1] == SEP) { 01694 string[len-1] = '\0'; 01695 len--; 01696 } else { 01697 break; 01698 } 01699 } 01700 } 01701 01702 static int add_win32_extension(char *name) 01703 { 01704 int retval = 0; 01705 int type; 01706 01707 type = BLI_exists(name); 01708 if ((type == 0) || S_ISDIR(type)) { 01709 #ifdef _WIN32 01710 char filename[FILE_MAX]; 01711 char ext[FILE_MAX]; 01712 const char *extensions = getenv("PATHEXT"); 01713 if (extensions) { 01714 char *temp; 01715 do { 01716 strcpy(filename, name); 01717 temp = strstr(extensions, ";"); 01718 if (temp) { 01719 strncpy(ext, extensions, temp - extensions); 01720 ext[temp - extensions] = 0; 01721 extensions = temp + 1; 01722 strcat(filename, ext); 01723 } else { 01724 strcat(filename, extensions); 01725 } 01726 01727 type = BLI_exists(filename); 01728 if (type && (! S_ISDIR(type))) { 01729 retval = 1; 01730 strcpy(name, filename); 01731 break; 01732 } 01733 } while (temp); 01734 } 01735 #endif 01736 } else { 01737 retval = 1; 01738 } 01739 01740 return (retval); 01741 } 01742 01743 /* 01744 * Checks if name is a fully qualified filename to an executable. 01745 * If not it searches $PATH for the file. On Windows it also 01746 * adds the correct extension (.com .exe etc) from 01747 * $PATHEXT if necessary. Also on Windows it translates 01748 * the name to its 8.3 version to prevent problems with 01749 * spaces and stuff. Final result is returned in fullname. 01750 * 01751 * @param fullname The full path and full name of the executable 01752 * (must be FILE_MAX minimum) 01753 * @param name The name of the executable (usually argv[0]) to be checked 01754 */ 01755 static void bli_where_am_i(char *fullname, const size_t maxlen, const char *name) 01756 { 01757 char filename[FILE_MAX]; 01758 const char *path = NULL, *temp; 01759 01760 #ifdef _WIN32 01761 const char *separator = ";"; 01762 #else 01763 const char *separator = ":"; 01764 #endif 01765 01766 01767 #ifdef WITH_BINRELOC 01768 /* linux uses binreloc since argv[0] is not reliable, call br_init( NULL ) first */ 01769 path = br_find_exe( NULL ); 01770 if (path) { 01771 BLI_strncpy(fullname, path, maxlen); 01772 free((void *)path); 01773 return; 01774 } 01775 #endif 01776 01777 #ifdef _WIN32 01778 if(GetModuleFileName(0, fullname, maxlen)) { 01779 if(!BLI_exists(fullname)) { 01780 printf("path can't be found: \"%.*s\"\n", maxlen, fullname); 01781 MessageBox(NULL, "path contains invalid characters or is too long (see console)", "Error", MB_OK); 01782 } 01783 return; 01784 } 01785 #endif 01786 01787 /* unix and non linux */ 01788 if (name && name[0]) { 01789 BLI_strncpy(fullname, name, maxlen); 01790 if (name[0] == '.') { 01791 char wdir[FILE_MAX]= ""; 01792 BLI_current_working_dir(wdir, sizeof(wdir)); /* backup cwd to restore after */ 01793 01794 // not needed but avoids annoying /./ in name 01795 if(name[1]==SEP) 01796 BLI_join_dirfile(fullname, maxlen, wdir, name+2); 01797 else 01798 BLI_join_dirfile(fullname, maxlen, wdir, name); 01799 01800 add_win32_extension(fullname); /* XXX, doesnt respect length */ 01801 } 01802 else if (BLI_last_slash(name)) { 01803 // full path 01804 BLI_strncpy(fullname, name, maxlen); 01805 add_win32_extension(fullname); 01806 } else { 01807 // search for binary in $PATH 01808 path = getenv("PATH"); 01809 if (path) { 01810 do { 01811 temp = strstr(path, separator); 01812 if (temp) { 01813 strncpy(filename, path, temp - path); 01814 filename[temp - path] = 0; 01815 path = temp + 1; 01816 } else { 01817 strncpy(filename, path, sizeof(filename)); 01818 } 01819 BLI_join_dirfile(fullname, maxlen, fullname, name); 01820 if (add_win32_extension(filename)) { 01821 BLI_strncpy(fullname, filename, maxlen); 01822 break; 01823 } 01824 } while (temp); 01825 } 01826 } 01827 #if defined(DEBUG) 01828 if (strcmp(name, fullname)) { 01829 printf("guessing '%s' == '%s'\n", name, fullname); 01830 } 01831 #endif 01832 } 01833 } 01834 01835 void BLI_init_program_path(const char *argv0) 01836 { 01837 bli_where_am_i(bprogname, sizeof(bprogname), argv0); 01838 BLI_split_dir_part(bprogname, bprogdir, sizeof(bprogdir)); 01839 } 01840 01841 const char *BLI_program_path(void) 01842 { 01843 return bprogname; 01844 } 01845 01846 const char *BLI_program_dir(void) 01847 { 01848 return bprogdir; 01849 } 01850 01860 static void BLI_where_is_temp(char *fullname, const size_t maxlen, char *userdir) 01861 { 01862 fullname[0] = '\0'; 01863 01864 if (userdir && BLI_is_dir(userdir)) { 01865 BLI_strncpy(fullname, userdir, maxlen); 01866 } 01867 01868 01869 #ifdef WIN32 01870 if (fullname[0] == '\0') { 01871 const char *tmp = getenv("TEMP"); /* Windows */ 01872 if (tmp && BLI_is_dir(tmp)) { 01873 BLI_strncpy(fullname, tmp, maxlen); 01874 } 01875 } 01876 #else 01877 /* Other OS's - Try TMP and TMPDIR */ 01878 if (fullname[0] == '\0') { 01879 const char *tmp = getenv("TMP"); 01880 if (tmp && BLI_is_dir(tmp)) { 01881 BLI_strncpy(fullname, tmp, maxlen); 01882 } 01883 } 01884 01885 if (fullname[0] == '\0') { 01886 const char *tmp = getenv("TMPDIR"); 01887 if (tmp && BLI_is_dir(tmp)) { 01888 BLI_strncpy(fullname, tmp, maxlen); 01889 } 01890 } 01891 #endif 01892 01893 if (fullname[0] == '\0') { 01894 BLI_strncpy(fullname, "/tmp/", maxlen); 01895 } else { 01896 /* add a trailing slash if needed */ 01897 BLI_add_slash(fullname); 01898 #ifdef WIN32 01899 if(userdir && userdir != fullname) { 01900 BLI_strncpy(userdir, fullname, maxlen); /* also set user pref to show %TEMP%. /tmp/ is just plain confusing for Windows users. */ 01901 } 01902 #endif 01903 } 01904 } 01905 01906 void BLI_init_temporary_dir(char *userdir) 01907 { 01908 BLI_where_is_temp(btempdir, FILE_MAX, userdir); 01909 } 01910 01911 const char *BLI_temporary_dir(void) 01912 { 01913 return btempdir; 01914 } 01915 01916 void BLI_system_temporary_dir(char *dir) 01917 { 01918 BLI_where_is_temp(dir, FILE_MAX, NULL); 01919 } 01920 01921 #ifdef WITH_ICONV 01922 01923 void BLI_string_to_utf8(char *original, char *utf_8, const char *code) 01924 { 01925 size_t inbytesleft=strlen(original); 01926 size_t outbytesleft=512; 01927 size_t rv=0; 01928 iconv_t cd; 01929 01930 if (NULL == code) { 01931 code = locale_charset(); 01932 } 01933 cd=iconv_open("UTF-8", code); 01934 01935 if (cd == (iconv_t)(-1)) { 01936 printf("iconv_open Error"); 01937 *utf_8='\0'; 01938 return ; 01939 } 01940 rv=iconv(cd, &original, &inbytesleft, &utf_8, &outbytesleft); 01941 if (rv == (size_t) -1) { 01942 printf("iconv Error\n"); 01943 return ; 01944 } 01945 *utf_8 = '\0'; 01946 iconv_close(cd); 01947 } 01948 #endif // WITH_ICONV 01949 01950