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