Blender V2.61 - r43446

path_util.c

Go to the documentation of this file.
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