patch [#28947] Patches for #28943 (Support for XDG Base Directory Specification)
[blender.git] / source / blender / blenlib / intern / path_util.c
index 8a6f620..7aa8452 100644 (file)
@@ -1,6 +1,4 @@
-/**
- *  $Id$
- *
+/*
  * ***** BEGIN GPL LICENSE BLOCK *****
  *
  * This program is free software; you can redistribute it and/or
  * various string, file, list operations.
  */
 
+/** \file blender/blenlib/intern/path_util.c
+ *  \ingroup bli
+ */
+
+
 #include <ctype.h>
 #include <string.h>
 #include <stdlib.h>
+#include <assert.h>
 
 #include "MEM_guardedalloc.h"
 
-#include "DNA_userdef_types.h"
+#include "DNA_listBase.h"
 
 #include "BLI_fileops.h"
 #include "BLI_path_util.h"
 #include "BLI_string.h"
-#include "BLI_storage.h"
-#include "BLI_storage_types.h"
+#include "BLI_utildefines.h"
 
 #include "BKE_utildefines.h"
 #include "BKE_blender.h"       // BLENDER_VERSION
 #include "GHOST_Path-api.h"
 
 #if defined WIN32 && !defined _LIBC
-# include "BLI_fnmatch.h" /* use fnmatch included in blenlib */
+#  include "BLI_fnmatch.h" /* use fnmatch included in blenlib */
 #else
-# define _GNU_SOURCE
-# include <fnmatch.h>
+#  ifndef _GNU_SOURCE
+#    define _GNU_SOURCE
+#  endif
+#  include <fnmatch.h>
 #endif
 
 #ifdef WIN32
-#include <io.h>
-
-#ifdef _WIN32_IE
-#undef _WIN32_IE
-#endif
-#define _WIN32_IE 0x0501
-#include <windows.h>
-#include <shlobj.h>
-
-#include "BLI_winstuff.h"
-
+#  include <io.h>
+#  ifdef _WIN32_IE
+#    undef _WIN32_IE
+#  endif
+#  define _WIN32_IE 0x0501
+#  include <windows.h>
+#  include <shlobj.h>
+#  include "BLI_winstuff.h"
 #else /* non windows */
+#  ifdef WITH_BINRELOC
+#    include "binreloc.h"
+#  endif
+#endif /* WIN32 */
 
-#ifdef __linux__
-#include "binreloc.h"
+/* standard paths */
+#ifdef WIN32
+#  define BLENDER_USER_FORMAT          "%s\\Blender Foundation\\Blender\\%s"
+#  define BLENDER_SYSTEM_FORMAT                "%s\\Blender Foundation\\Blender\\%s"
+#elif defined(__APPLE__)
+#  define BLENDER_USER_FORMAT                  "%s/Blender/%s"
+#  define BLENDER_SYSTEM_FORMAT                        "%s/Blender/%s"
+#else /* UNIX */
+#  ifndef WITH_XDG_USER_DIRS /* oldschool unix ~/.blender/ */
+#    define BLENDER_USER_FORMAT                        "%s/.blender/%s"
+#  else /* new XDG ~/blender/.config/ */
+#    define BLENDER_USER_FORMAT                        "%s/blender/%s"
+#  endif // WITH_XDG_USER_DIRS
+#  define BLENDER_SYSTEM_FORMAT                        "%s/blender/%s"
 #endif
 
-#endif /* WIN32 */
-
 /* local */
+#define UNIQUE_NAME_MAX 128
+
+static char bprogname[FILE_MAX];       /* path to program executable */
+static char bprogdir[FILE_MAX];                /* path in which executable is located */
+static char btempdir[FILE_MAX];                /* temporary directory */
 
 static int add_win32_extension(char *name);
-static char *blender_version_decimal(void);
+static char *blender_version_decimal(const int ver);
 
 /* implementation */
 
@@ -136,10 +157,41 @@ void BLI_stringenc(char *string, const char *head, const char *tail, unsigned sh
        sprintf(string, fmtstr, head, pic, tail);
 }
 
+/* Foo.001 -> "Foo", 1
+ * Returns the length of "Foo" */
+int BLI_split_name_num(char *left, int *nr, const char *name, const char delim)
+{
+       int a;
+
+       *nr= 0;
+       a= strlen(name);
+       memcpy(left, name, (a + 1) * sizeof(char));
+
+       if(a>1 && name[a-1]==delim) return a;
+       
+       while(a--) {
+               if( name[a]==delim ) {
+                       left[a]= 0;
+                       *nr= atol(name+a+1);
+                       /* casting down to an int, can overflow for large numbers */
+                       if(*nr < 0)
+                               *nr= 0;
+                       return a;
+               }
+               if( isdigit(name[a])==0 ) break;
+               
+               left[a]= 0;
+       }
+
+       for(a= 0; name[a]; a++)
+               left[a]= name[a];
+
+       return a;
+}
 
 void BLI_newname(char *name, int add)
 {
-       char head[128], tail[128];
+       char head[UNIQUE_NAME_MAX], tail[UNIQUE_NAME_MAX];
        int pic;
        unsigned short digits;
        
@@ -159,13 +211,43 @@ void BLI_newname(char *name, int add)
        BLI_stringenc(name, head, tail, digits, pic);
 }
 
+
+
+int BLI_uniquename_cb(int (*unique_check)(void *, const char *), void *arg, const char defname[], char delim, char *name, short name_len)
+{
+       if(name[0] == '\0') {
+               BLI_strncpy(name, defname, name_len);
+       }
+
+       if(unique_check(arg, name)) {
+               char    tempname[UNIQUE_NAME_MAX];
+               char    left[UNIQUE_NAME_MAX];
+               int             number;
+               int             len= BLI_split_name_num(left, &number, name, delim);
+               do {
+                       int newlen= BLI_snprintf(tempname, name_len, "%s%c%03d", left, delim, ++number);
+                       if(newlen >= name_len) {
+                               len -= ((newlen + 1) - name_len);
+                               if(len < 0) len= number= 0;
+                               left[len]= '\0';
+                       }
+               } while(unique_check(arg, tempname));
+
+               BLI_strncpy(name, tempname, name_len);
+               
+               return 1;
+       }
+       
+       return 0;
+}
+
 /* little helper macro for BLI_uniquename */
 #ifndef GIVE_STRADDR
        #define GIVE_STRADDR(data, offset) ( ((char *)data) + offset )
 #endif
 
 /* Generic function to set a unique name. It is only designed to be used in situations
- * where the name is part of the struct, and also that the name is at most 128 chars long.
+ * where the name is part of the struct, and also that the name is at most UNIQUE_NAME_MAX chars long.
  * 
  * For places where this is used, see constraint.c for example...
  *
@@ -174,65 +256,45 @@ void BLI_newname(char *name, int add)
  *     defname: the name that should be used by default if none is specified already
  *     delim: the character which acts as a delimeter between parts of the name
  */
-void BLI_uniquename(ListBase *list, void *vlink, const char defname[], char delim, short name_offs, short len)
+static int uniquename_find_dupe(ListBase *list, void *vlink, const char *name, short name_offs)
 {
        Link *link;
-       char tempname[128];
-       int     number = 1, exists = 0;
-       char *dot;
-       
-       /* Make sure length can be handled */
-       if ((len < 0) || (len > 128))
-               return;
-       
-       /* See if we are given an empty string */
-       if (ELEM(NULL, vlink, defname))
-               return;
-       
-       if (GIVE_STRADDR(vlink, name_offs) == '\0') {
-               /* give it default name first */
-               BLI_strncpy(GIVE_STRADDR(vlink, name_offs), defname, len);
-       }
-       
-       /* See if we even need to do this */
-       if (list == NULL)
-               return;
-       
+
        for (link = list->first; link; link= link->next) {
                if (link != vlink) {
-                       if (!strcmp(GIVE_STRADDR(link, name_offs), GIVE_STRADDR(vlink, name_offs))) {
-                               exists = 1;
-                               break;
+                       if (!strcmp(GIVE_STRADDR(link, name_offs), name)) {
+                               return 1;
                        }
                }
        }
-       if (exists == 0)
+
+       return 0;
+}
+
+static int uniquename_unique_check(void *arg, const char *name)
+{
+       struct {ListBase *lb; void *vlink; short name_offs;} *data= arg;
+       return uniquename_find_dupe(data->lb, data->vlink, name, data->name_offs);
+}
+
+void BLI_uniquename(ListBase *list, void *vlink, const char defname[], char delim, short name_offs, short name_len)
+{
+       struct {ListBase *lb; void *vlink; short name_offs;} data;
+       data.lb= list;
+       data.vlink= vlink;
+       data.name_offs= name_offs;
+
+       assert((name_len > 1) && (name_len <= UNIQUE_NAME_MAX));
+
+       /* See if we are given an empty string */
+       if (ELEM(NULL, vlink, defname))
                return;
 
-       /* Strip off the suffix */
-       dot = strrchr(GIVE_STRADDR(vlink, name_offs), delim);
-       if (dot)
-               *dot=0;
-       
-       for (number = 1; number <= 999; number++) {
-               BLI_snprintf(tempname, sizeof(tempname), "%s%c%03d", GIVE_STRADDR(vlink, name_offs), delim, number);
-               
-               exists = 0;
-               for (link= list->first; link; link= link->next) {
-                       if (vlink != link) {
-                               if (!strcmp(GIVE_STRADDR(link, name_offs), tempname)) {
-                                       exists = 1;
-                                       break;
-                               }
-                       }
-               }
-               if (exists == 0) {
-                       BLI_strncpy(GIVE_STRADDR(vlink, name_offs), tempname, len);
-                       return;
-               }
-       }
+       BLI_uniquename_cb(uniquename_unique_check, &data, defname, delim, GIVE_STRADDR(vlink, name_offs), name_len);
 }
 
+
+
 /* ******************** string encoding ***************** */
 
 /* This is quite an ugly function... its purpose is to
@@ -243,14 +305,7 @@ void BLI_uniquename(ListBase *list, void *vlink, const char defname[], char deli
  * If relbase is NULL then its ignored
  */
 
-void BLI_cleanup_dir(const char *relabase, char *dir)
-{
-       BLI_cleanup_file(relabase, dir);
-       BLI_add_slash(dir);
-
-}
-
-void BLI_cleanup_file(const char *relabase, char *dir)
+void BLI_cleanup_path(const char *relabase, char *dir)
 {
        short a;
        char *start, *eind;
@@ -278,8 +333,8 @@ void BLI_cleanup_file(const char *relabase, char *dir)
        /* Note, this should really be moved to the file selector,
         * since this function is used in many areas */
        if(strcmp(dir, ".")==0) {       /* happens for example in FILE_MAIN */
-          get_default_root(dir);
-          return;
+               get_default_root(dir);
+               return;
        }       
 
        while ( (start = strstr(dir, "\\..\\")) ) {
@@ -305,18 +360,11 @@ void BLI_cleanup_file(const char *relabase, char *dir)
                eind = start + strlen("\\\\") - 1;
                memmove( start, eind, strlen(eind)+1 );
        }
-
-       if((a = strlen(dir))){                          /* remove the '\\' at the end */
-               while(a>0 && dir[a-1] == '\\'){
-                       a--;
-                       dir[a] = 0;
-               }
-       }
 #else
        if(dir[0]=='.') {       /* happens, for example in FILE_MAIN */
-          dir[0]= '/';
-          dir[1]= 0;
-          return;
+               dir[0]= '/';
+               dir[1]= 0;
+               return;
        }
 
        /* support for odd paths: eg /../home/me --> /home/me
@@ -349,17 +397,21 @@ void BLI_cleanup_file(const char *relabase, char *dir)
                eind = start + (2 - 1) /* strlen("//") - 1 */;
                memmove( start, eind, strlen(eind)+1 );
        }
-
-       if( (a = strlen(dir)) ){                                /* remove all '/' at the end */
-               while(dir[a-1] == '/'){
-                       a--;
-                       dir[a] = 0;
-                       if (a<=0) break;
-               }
-       }
 #endif
 }
 
+void BLI_cleanup_dir(const char *relabase, char *dir)
+{
+       BLI_cleanup_path(relabase, dir);
+       BLI_add_slash(dir);
+
+}
+
+void BLI_cleanup_file(const char *relabase, char *dir)
+{
+       BLI_cleanup_path(relabase, dir);
+       BLI_del_slash(dir);
+}
 
 void BLI_path_rel(char *file, const char *relfile)
 {
@@ -373,8 +425,8 @@ void BLI_path_rel(char *file, const char *relfile)
        /* also bail out if relative path is not set */
        if (relfile[0] == 0) return;
 
-#ifdef WIN32 
-       if (strlen(relfile) > 2 && relfile[1] != ':') {
+#ifdef WIN32
+       if (BLI_strnlen(relfile, 3) > 2 && relfile[1] != ':') {
                char* ptemp;
                /* fix missing volume name in relative base,
                   can happen with old recent-files.txt files */
@@ -388,7 +440,7 @@ void BLI_path_rel(char *file, const char *relfile)
                BLI_strncpy(temp, relfile, FILE_MAXDIR + FILE_MAXFILE);
        }
 
-       if (strlen(file) > 2) {
+       if (BLI_strnlen(file, 3) > 2) {
                if ( temp[1] == ':' && file[1] == ':' && temp[0] != file[0] )
                        return;
        }
@@ -400,8 +452,8 @@ void BLI_path_rel(char *file, const char *relfile)
        BLI_char_switch(file, '\\', '/');
        
        /* remove /./ which confuse the following slash counting... */
-       BLI_cleanup_file(NULL, file);
-       BLI_cleanup_file(NULL, temp);
+       BLI_cleanup_path(NULL, file);
+       BLI_cleanup_path(NULL, temp);
        
        /* the last slash in the file indicates where the path part ends */
        lslash = BLI_last_slash(temp);
@@ -413,7 +465,12 @@ void BLI_path_rel(char *file, const char *relfile)
                char *p= temp;
                char *q= file;
 
-               while ((*p == *q)) {
+#ifdef WIN32
+               while (tolower(*p) == tolower(*q))
+#else
+               while (*p == *q)
+#endif
+               {
                        ++p; ++q;
                        /* dont search beyond the end of the string
                         * in the rare case they match */
@@ -477,7 +534,7 @@ int BLI_parent_dir(char *path)
        BLI_add_slash(tmp);
        strcat(tmp, parent_dir);
        BLI_cleanup_dir(NULL, tmp);
-       
+
        if (!BLI_testextensie(tmp, parent_dir)) {
                BLI_strncpy(path, tmp, sizeof(tmp));    
                return 1;
@@ -543,9 +600,8 @@ int BLI_path_frame(char *path, int frame, int digits)
                ensure_digits(path, digits);
 
        if (stringframe_chars(path, &ch_sta, &ch_end)) { /* warning, ch_end is the last # +1 */
-               char tmp[FILE_MAX], format[64];
-               sprintf(format, "%%.%ds%%.%dd%%s", ch_sta, ch_end-ch_sta); /* example result: "%.12s%.5d%s" */
-               sprintf(tmp, format, path, frame, path+ch_end);
+               char tmp[FILE_MAX];
+               sprintf(tmp, "%.*s%.*d%s", ch_sta, path, ch_end-ch_sta, frame, path+ch_end);
                strcpy(path, tmp);
                return 1;
        }
@@ -560,9 +616,8 @@ int BLI_path_frame_range(char *path, int sta, int end, int digits)
                ensure_digits(path, digits);
 
        if (stringframe_chars(path, &ch_sta, &ch_end)) { /* warning, ch_end is the last # +1 */
-               char tmp[FILE_MAX], format[64];
-               sprintf(format, "%%.%ds%%.%dd_%%.%dd%%s", ch_sta, ch_end-ch_sta, ch_end-ch_sta); /* example result: "%.12s%.5d-%.5d%s" */
-               sprintf(tmp, format, path, sta, end, path+ch_end);
+               char tmp[FILE_MAX];
+               sprintf(tmp, "%.*s%.*d-%.*d%s", ch_sta, path, ch_end-ch_sta, sta, ch_end-ch_sta, end, path+ch_end);
                strcpy(path, tmp);
                return 1;
        }
@@ -613,8 +668,9 @@ int BLI_path_abs(char *path, const char *basepath)
 #endif
 
        BLI_strncpy(base, basepath, sizeof(base));
-       
-       BLI_cleanup_file(NULL, base);
+
+       /* file component is ignored, so dont bother with the trailing slash */
+       BLI_cleanup_path(NULL, base);
        
        /* push slashes into unix mode - strings entering this part are
           potentially messed up: having both back- and forward slashes.
@@ -643,17 +699,9 @@ int BLI_path_abs(char *path, const char *basepath)
        } else {
                BLI_strncpy(path, tmp, FILE_MAX);
        }
-       
-       if (path[0]!='\0') {
-               if ( path[strlen(path)-1]=='/') {
-                       /* remove the '/' so we avoid BLI_cleanup_dir adding an extra \ in WIN32 */
-                       path[strlen(path)-1] = '\0';
-                       BLI_cleanup_dir(NULL, path);
-               } else {
-                       BLI_cleanup_file(NULL, path);
-               }
-       }
-       
+
+       BLI_cleanup_path(NULL, path);
+
 #ifdef WIN32
        /* skip first two chars, which in case of
           absolute path will be drive:/blabla and
@@ -686,8 +734,8 @@ int BLI_path_cwd(char *path)
 #endif
        
        if (wasrelative==1) {
-               char cwd[FILE_MAXDIR + FILE_MAXFILE];
-               BLI_getwdN(cwd); /* incase the full path to the blend isnt used */
+               char cwd[FILE_MAXDIR + FILE_MAXFILE]= "";
+               BLI_current_working_dir(cwd, sizeof(cwd)); /* incase the full path to the blend isnt used */
                
                if (cwd[0] == '\0') {
                        printf( "Could not get the current working directory - $PWD for an unknown reason.");
@@ -697,7 +745,7 @@ int BLI_path_cwd(char *path)
                        * cwd should contain c:\ etc on win32 so the relbase can be NULL
                        * relbase being NULL also prevents // being misunderstood as relative to the current
                        * blend file which isnt a feature we want to use in this case since were dealing
-                       * with a path from the command line, rather then from inside Blender */
+                       * with a path from the command line, rather than from inside Blender */
                        
                        char origpath[FILE_MAXDIR + FILE_MAXFILE];
                        BLI_strncpy(origpath, path, FILE_MAXDIR + FILE_MAXFILE);
@@ -724,7 +772,7 @@ void BLI_splitdirstring(char *di, char *fi)
        }
 }
 
-void BLI_getlastdir(const char* dir, char *last, int maxlen)
+void BLI_getlastdir(const char* dir, char *last, const size_t maxlen)
 {
        const char *s = dir;
        const char *lslash = NULL;
@@ -746,12 +794,21 @@ void BLI_getlastdir(const char* dir, char *last, int maxlen)
 /* This is now only used to really get the user's default document folder */
 /* On Windows I chose the 'Users/<MyUserName>/Documents' since it's used
    as default location to save documents */
-char *BLI_getDefaultDocumentFolder(void) {
-       #if !defined(WIN32)
+const char *BLI_getDefaultDocumentFolder(void)
+{
+#ifndef WIN32
+
+#ifdef WITH_XDG_USER_DIRS
+               const char *xdg_documents_dir= getenv("XDG_DOCUMENTS_DIR");
+               if (xdg_documents_dir) {
+                       return xdg_documents_dir;
+               }
+#endif
+
                return getenv("HOME");
 
-       #else /* Windows */
-               char * ret;
+#else /* Windows */
+               const char * ret;
                static char documentfolder[MAXPATHLEN];
                HRESULT hResult;
 
@@ -775,7 +832,7 @@ char *BLI_getDefaultDocumentFolder(void) {
                }
                
                return NULL;
-       #endif
+#endif /* WIN32 */
 }
 
 /* NEW stuff, to be cleaned up when fully migrated */
@@ -784,22 +841,26 @@ char *BLI_getDefaultDocumentFolder(void) {
 
 // #define PATH_DEBUG2
 
-static char *blender_version_decimal(void)
+static char *blender_version_decimal(const int ver)
 {
        static char version_str[5];
-       sprintf(version_str, "%d.%02d", BLENDER_VERSION/100, BLENDER_VERSION%100);
+       sprintf(version_str, "%d.%02d", ver/100, ver%100);
        return version_str;
 }
 
-static int test_path(char *targetpath, char *path_base, char *path_sep, char *folder_name)
+static int test_path(char *targetpath, const char *path_base, const char *path_sep, const char *folder_name)
 {
        char tmppath[FILE_MAX];
        
-       if(path_sep)    BLI_join_dirfile(tmppath, path_base, path_sep);
+       if(path_sep)    BLI_join_dirfile(tmppath, sizeof(tmppath), path_base, path_sep);
        else                    BLI_strncpy(tmppath, path_base, sizeof(tmppath));
-       
-       BLI_make_file_string("/", targetpath, tmppath, folder_name);
-       
+
+       /* rare cases folder_name is omitted (when looking for ~/.blender/2.xx dir only) */
+       if(folder_name)
+               BLI_make_file_string("/", targetpath, tmppath, folder_name);
+       else
+               BLI_strncpy(targetpath, tmppath, sizeof(tmppath));
+
        if (BLI_is_dir(targetpath)) {
 #ifdef PATH_DEBUG2
                printf("\tpath found: %s\n", targetpath);
@@ -815,9 +876,9 @@ static int test_path(char *targetpath, char *path_base, char *path_sep, char *fo
        }
 }
 
-static int test_env_path(char *path, char *envvar)
+static int test_env_path(char *path, const char *envvar)
 {
-       char *env = envvar?getenv(envvar):NULL;
+       const char *env = envvar?getenv(envvar):NULL;
        if (!env) return 0;
        
        if (BLI_is_dir(env)) {
@@ -829,36 +890,49 @@ static int test_env_path(char *path, char *envvar)
        }
 }
 
-static int get_path_local(char *targetpath, char *folder_name, char *subfolder_name)
+static int get_path_local(char *targetpath, const char *folder_name, const char *subfolder_name, const int ver)
 {
-       extern char bprogname[]; /* argv[0] from creator.c */
-       char bprogdir[FILE_MAX];
        char relfolder[FILE_MAX];
        
 #ifdef PATH_DEBUG2
        printf("get_path_local...\n");
 #endif
-       
-       if (subfolder_name) {
-               BLI_join_dirfile(relfolder, folder_name, subfolder_name);
-       } else {
-               BLI_strncpy(relfolder, folder_name, FILE_MAX);
+
+       if(folder_name) {
+               if (subfolder_name) {
+                       BLI_join_dirfile(relfolder, sizeof(relfolder), folder_name, subfolder_name);
+               } else {
+                       BLI_strncpy(relfolder, folder_name, sizeof(relfolder));
+               }
        }
-       
-       /* use argv[0] (bprogname) to get the path to the executable */
-       BLI_split_dirfile(bprogname, bprogdir, NULL);
-       
+       else {
+               relfolder[0]= '\0';
+       }
+
        /* try EXECUTABLE_DIR/2.5x/folder_name - new default directory for local blender installed files */
-       if(test_path(targetpath, bprogdir, blender_version_decimal(), relfolder))
+       if(test_path(targetpath, bprogdir, blender_version_decimal(ver), relfolder))
                return 1;
 
        return 0;
 }
 
-static int get_path_user(char *targetpath, char *folder_name, char *subfolder_name, char *envvar)
+static int is_portable_install(void)
+{
+       /* detect portable install by the existance of config folder */
+       const int ver= BLENDER_VERSION;
+       char path[FILE_MAX];
+
+       return get_path_local(path, "config", NULL, ver);
+}
+
+static int get_path_user(char *targetpath, const char *folder_name, const char *subfolder_name, const char *envvar, const int ver)
 {
        char user_path[FILE_MAX];
        const char *user_base_path;
+
+       /* for portable install, user path is always local */
+       if (is_portable_install())
+               return get_path_local(targetpath, folder_name, subfolder_name, ver);
        
        user_path[0] = '\0';
 
@@ -873,7 +947,7 @@ static int get_path_user(char *targetpath, char *folder_name, char *subfolder_na
 
        user_base_path = (const char *)GHOST_getUserDir();
        if (user_base_path) {
-               BLI_snprintf(user_path, FILE_MAX, BLENDER_USER_FORMAT, user_base_path, blender_version_decimal());
+               BLI_snprintf(user_path, FILE_MAX, BLENDER_USER_FORMAT, user_base_path, blender_version_decimal(ver));
        }
 
        if(!user_path[0])
@@ -892,7 +966,7 @@ static int get_path_user(char *targetpath, char *folder_name, char *subfolder_na
        }
 }
 
-static int get_path_system(char *targetpath, char *folder_name, char *subfolder_name, char *envvar)
+static int get_path_system(char *targetpath, const char *folder_name, const char *subfolder_name, const char *envvar, const int ver)
 {
        char system_path[FILE_MAX];
        const char *system_base_path;
@@ -900,24 +974,27 @@ static int get_path_system(char *targetpath, char *folder_name, char *subfolder_
 
        /* first allow developer only overrides to the system path
         * these are only used when running blender from source */
-       extern char bprogname[]; /* argv[0] from creator.c */
        char cwd[FILE_MAX];
        char relfolder[FILE_MAX];
-       char bprogdir[FILE_MAX];
 
-       /* use argv[0] (bprogname) to get the path to the executable */
-       BLI_split_dirfile(bprogname, bprogdir, NULL);
-
-       if (subfolder_name) {
-               BLI_join_dirfile(relfolder, folder_name, subfolder_name);
-       } else {
-               BLI_strncpy(relfolder, folder_name, FILE_MAX);
+       if(folder_name) {
+               if (subfolder_name) {
+                       BLI_join_dirfile(relfolder, sizeof(relfolder), folder_name, subfolder_name);
+               } else {
+                       BLI_strncpy(relfolder, folder_name, sizeof(relfolder));
+               }
+       }
+       else {
+               relfolder[0]= '\0';
        }
 
        /* try CWD/release/folder_name */
-       if(test_path(targetpath, BLI_getwdN(cwd), "release", relfolder))
-               return 1;
-       
+       if(BLI_current_working_dir(cwd, sizeof(cwd))) {
+               if(test_path(targetpath, cwd, "release", relfolder)) {
+                       return 1;
+               }
+       }
+
        /* try EXECUTABLE_DIR/release/folder_name */
        if(test_path(targetpath, bprogdir, "release", relfolder))
                return 1;
@@ -938,7 +1015,7 @@ static int get_path_system(char *targetpath, char *folder_name, char *subfolder_
 
        system_base_path = (const char *)GHOST_getSystemDir();
        if (system_base_path) {
-               BLI_snprintf(system_path, FILE_MAX, BLENDER_SYSTEM_FORMAT, system_base_path, blender_version_decimal());
+               BLI_snprintf(system_path, FILE_MAX, BLENDER_SYSTEM_FORMAT, system_base_path, blender_version_decimal(ver));
        }
        
        if(!system_path[0])
@@ -959,94 +1036,70 @@ static int get_path_system(char *targetpath, char *folder_name, char *subfolder_
 
 /* get a folder out of the 'folder_id' presets for paths */
 /* returns the path if found, NULL string if not */
-char *BLI_get_folder(int folder_id, char *subfolder)
+char *BLI_get_folder(int folder_id, const char *subfolder)
 {
+       const int ver= BLENDER_VERSION;
        static char path[FILE_MAX] = "";
        
        switch (folder_id) {
                case BLENDER_DATAFILES:         /* general case */
-                       if (get_path_local(path, "datafiles", subfolder)) break;
-                       if (get_path_user(path, "datafiles", subfolder, "BLENDER_USER_DATAFILES"))      break;
-                       if (get_path_system(path, "datafiles", subfolder, "BLENDER_SYSTEM_DATAFILES")) break;
+                       if (get_path_user(path, "datafiles", subfolder, "BLENDER_USER_DATAFILES", ver)) break;
+                       if (get_path_local(path, "datafiles", subfolder, ver)) break;
+                       if (get_path_system(path, "datafiles", subfolder, "BLENDER_SYSTEM_DATAFILES", ver)) break;
                        return NULL;
                        
                case BLENDER_USER_DATAFILES:
-                       if (get_path_local(path, "datafiles", subfolder)) break;
-                       if (get_path_user(path, "datafiles", subfolder, "BLENDER_USER_DATAFILES"))      break;
+                       if (get_path_user(path, "datafiles", subfolder, "BLENDER_USER_DATAFILES", ver)) break;
                        return NULL;
                        
                case BLENDER_SYSTEM_DATAFILES:
-                       if (get_path_local(path, "datafiles", subfolder)) break;
-                       if (get_path_system(path, "datafiles", subfolder, "BLENDER_SYSTEM_DATAFILES"))  break;
+                       if (get_path_local(path, "datafiles", subfolder, ver)) break;
+                       if (get_path_system(path, "datafiles", subfolder, "BLENDER_SYSTEM_DATAFILES", ver))     break;
                        return NULL;
                        
                case BLENDER_USER_AUTOSAVE:
-                       if (get_path_local(path, "autosave", subfolder)) break;
-                       if (get_path_user(path, "autosave", subfolder, "BLENDER_USER_DATAFILES"))       break;
+                       if (get_path_user(path, "autosave", subfolder, "BLENDER_USER_DATAFILES", ver))  break;
                        return NULL;
 
-               case BLENDER_CONFIG:            /* general case */
-                       if (get_path_local(path, "config", subfolder)) break;
-                       if (get_path_user(path, "config", subfolder, "BLENDER_USER_CONFIG")) break;
-                       if (get_path_system(path, "config", subfolder, "BLENDER_SYSTEM_CONFIG")) break;
-                       return NULL;
-                       
                case BLENDER_USER_CONFIG:
-                       if (get_path_local(path, "config", subfolder)) break;
-                       if (get_path_user(path, "config", subfolder, "BLENDER_USER_CONFIG")) break;
-                       return NULL;
-                       
-               case BLENDER_SYSTEM_CONFIG:
-                       if (get_path_local(path, "config", subfolder)) break;
-                       if (get_path_system(path, "config", subfolder, "BLENDER_SYSTEM_CONFIG")) break;
-                       return NULL;
-                       
-               case BLENDER_SCRIPTS:           /* general case */
-                       if (get_path_local(path, "scripts", subfolder)) break;
-                       if (get_path_user(path, "scripts", subfolder, "BLENDER_USER_SCRIPTS")) break;           
-                       if (get_path_system(path, "scripts", subfolder, "BLENDER_SYSTEM_SCRIPTS")) break;
+                       if (get_path_user(path, "config", subfolder, "BLENDER_USER_CONFIG", ver)) break;
                        return NULL;
                        
                case BLENDER_USER_SCRIPTS:
-                       if (get_path_local(path, "scripts", subfolder)) break;
-                       if (get_path_user(path, "scripts", subfolder, "BLENDER_USER_SCRIPTS")) break;
+                       if (get_path_user(path, "scripts", subfolder, "BLENDER_USER_SCRIPTS", ver)) break;
                        return NULL;
                        
                case BLENDER_SYSTEM_SCRIPTS:
-                       if (get_path_local(path, "scripts", subfolder)) break;
-                       if (get_path_system(path, "scripts", subfolder, "BLENDER_SYSTEM_SCRIPTS")) break;
-                       return NULL;
-                       
-               case BLENDER_PYTHON:            /* general case */
-                       if (get_path_local(path, "python", subfolder)) break;
-                       if (get_path_system(path, "python", subfolder, "BLENDER_SYSTEM_PYTHON")) break;
+                       if (get_path_local(path, "scripts", subfolder, ver)) break;
+                       if (get_path_system(path, "scripts", subfolder, "BLENDER_SYSTEM_SCRIPTS", ver)) break;
                        return NULL;
                        
                case BLENDER_SYSTEM_PYTHON:
-                       if (get_path_local(path, "python", subfolder)) break;
-                       if (get_path_system(path, "python", subfolder, "BLENDER_SYSTEM_PYTHON")) break;
+                       if (get_path_local(path, "python", subfolder, ver)) break;
+                       if (get_path_system(path, "python", subfolder, "BLENDER_SYSTEM_PYTHON", ver)) break;
                        return NULL;
        }
        
        return path;
 }
 
-char *BLI_get_user_folder_notest(int folder_id, char *subfolder)
+char *BLI_get_user_folder_notest(int folder_id, const char *subfolder)
 {
+       const int ver= BLENDER_VERSION;
        static char path[FILE_MAX] = "";
 
        switch (folder_id) {
                case BLENDER_USER_DATAFILES:
-                       get_path_user(path, "datafiles", subfolder, "BLENDER_USER_DATAFILES");
+                       get_path_user(path, "datafiles", subfolder, "BLENDER_USER_DATAFILES", ver);
                        break;
                case BLENDER_USER_CONFIG:
-                       get_path_user(path, "config", subfolder, "BLENDER_USER_CONFIG");
+                       get_path_user(path, "config", subfolder, "BLENDER_USER_CONFIG", ver);
                        break;
                case BLENDER_USER_AUTOSAVE:
-                       get_path_user(path, "autosave", subfolder, "BLENDER_USER_AUTOSAVE");
+                       get_path_user(path, "autosave", subfolder, "BLENDER_USER_AUTOSAVE", ver);
                        break;
                case BLENDER_USER_SCRIPTS:
-                       get_path_user(path, "scripts", subfolder, "BLENDER_USER_SCRIPTS");
+                       get_path_user(path, "scripts", subfolder, "BLENDER_USER_SCRIPTS", ver);
                        break;
        }
        if ('\0' == path[0]) {
@@ -1055,7 +1108,7 @@ char *BLI_get_user_folder_notest(int folder_id, char *subfolder)
        return path;
 }
 
-char *BLI_get_folder_create(int folder_id, char *subfolder)
+char *BLI_get_folder_create(int folder_id, const char *subfolder)
 {
        char *path;
 
@@ -1067,12 +1120,38 @@ char *BLI_get_folder_create(int folder_id, char *subfolder)
        
        if (!path) {
                path = BLI_get_user_folder_notest(folder_id, subfolder);
-               if (path) BLI_recurdir_fileops(path);
+               if (path) BLI_dir_create_recursive(path);
        }
        
        return path;
 }
 
+char *BLI_get_folder_version(const int id, const int ver, const int do_check)
+{
+       static char path[FILE_MAX] = "";
+       int ok;
+       switch(id) {
+       case BLENDER_RESOURCE_PATH_USER:
+               ok= get_path_user(path, NULL, NULL, NULL, ver);
+               break;
+       case BLENDER_RESOURCE_PATH_LOCAL:
+               ok= get_path_local(path, NULL, NULL, ver);
+               break;
+       case BLENDER_RESOURCE_PATH_SYSTEM:
+               ok= get_path_system(path, NULL, NULL, NULL, ver);
+               break;
+       default:
+               path[0]= '\0'; /* incase do_check is false */
+               ok= FALSE;
+               BLI_assert(!"incorrect ID");
+       }
+
+       if((ok == FALSE) && do_check) {
+               return NULL;
+       }
+
+       return path;
+}
 
 /* End new stuff */
 /* ************************************************************* */
@@ -1086,8 +1165,8 @@ char *BLI_get_folder_create(int folder_id, char *subfolder)
 
 void BLI_setenv(const char *env, const char*val)
 {
-       /* SGI or free windows */
-#if (defined(__sgi) || ((defined(WIN32) || defined(WIN64)) && defined(FREE_WINDOWS)))
+       /* free windows */
+#if (defined(WIN32) || defined(WIN64)) && defined(FREE_WINDOWS)
        char *envstr= MEM_mallocN(sizeof(char) * (strlen(env) + strlen(val) + 2), "envstr"); /* one for = another for \0 */
 
        sprintf(envstr, "%s=%s", env, val);
@@ -1117,9 +1196,10 @@ void BLI_setenv_if_new(const char *env, const char* val)
 
 void BLI_clean(char *path)
 {
-       if(path==0) return;
+       if(path==NULL) return;
+
 #ifdef WIN32
-       if(path && strlen(path)>2) {
+       if(path && BLI_strnlen(path, 3) > 2) {
                BLI_char_switch(path+2, '/', '\\');
        }
 #else
@@ -1129,14 +1209,15 @@ void BLI_clean(char *path)
 
 void BLI_char_switch(char *string, char from, char to) 
 {
-       if(string==0) return;
+       if(string==NULL) return;
        while (*string != 0) {
                if (*string == from) *string = to;
                string++;
        }
 }
 
-void BLI_make_exist(char *dir) {
+void BLI_make_exist(char *dir)
+{
        int a;
 
        BLI_char_switch(dir, ALTSEP, SEP);
@@ -1163,7 +1244,7 @@ void BLI_make_exist(char *dir) {
        }
 }
 
-void BLI_make_existing_file(char *name)
+void BLI_make_existing_file(const char *name)
 {
        char di[FILE_MAXDIR+FILE_MAXFILE], fi[FILE_MAXFILE];
 
@@ -1172,7 +1253,7 @@ void BLI_make_existing_file(char *name)
        
        /* test exist */
        if (BLI_exists(di) == 0) {
-               BLI_recurdir_fileops(di);
+               BLI_dir_create_recursive(di);
        }
 }
 
@@ -1181,9 +1262,18 @@ void BLI_make_file_string(const char *relabase, char *string,  const char *dir,
 {
        int sl;
 
-       if (!string || !dir || !file) return; /* We don't want any NULLs */
-       
-       string[0]= 0; /* ton */
+       if (string) {
+               /* ensure this is always set even if dir/file are NULL */
+               string[0]= '\0';
+
+               if (ELEM(NULL, dir, file)) {
+                       return; /* We don't want any NULLs */
+               }
+       }
+       else {
+               return; /* string is NULL, probably shouldnt happen but return anyway */
+       }
+
 
        /* we first push all slashes into unix mode, just to make sure we don't get
           any mess with slashes later on. -jesterKing */
@@ -1208,7 +1298,7 @@ void BLI_make_file_string(const char *relabase, char *string,  const char *dir,
        }
 #ifdef WIN32
        else {
-               if (strlen(dir) >= 2 && dir[1] == ':' ) {
+               if (BLI_strnlen(dir, 3) >= 2 && dir[1] == ':' ) {
                        BLI_strncpy(string, dir, 3);
                        dir += 2;
                }
@@ -1254,10 +1344,10 @@ int BLI_testextensie(const char *str, const char *ext)
 {
        short a, b;
        int retval;
-
+       
        a= strlen(str);
        b= strlen(ext);
-
+       
        if(a==0 || b==0 || b>=a) {
                retval = 0;
        } else if (BLI_strcasecmp(ext, str + a - b)) {
@@ -1265,7 +1355,7 @@ int BLI_testextensie(const char *str, const char *ext)
        } else {
                retval = 1;
        }
-
+       
        return (retval);
 }
 
@@ -1312,21 +1402,53 @@ int BLI_testextensie_glob(const char *str, const char *ext_fnmatch)
 }
 
 
-int BLI_replace_extension(char *path, int maxlen, const char *ext)
+int BLI_replace_extension(char *path, size_t maxlen, const char *ext)
 {
-       int a;
+       size_t path_len= strlen(path);
+       size_t ext_len= strlen(ext);
+       size_t a;
 
-       for(a=strlen(path)-1; a>=0; a--)
-               if(path[a] == '.' || path[a] == '/' || path[a] == '\\')
+       for(a= path_len - 1; a >= 0; a--) {
+               if (ELEM3(path[a], '.', '/', '\\')) {
                        break;
-       
-       if(path[a] != '.')
-               a= strlen(path);
+               }
+       }
 
-       if(a + strlen(ext) >= maxlen)
+       if(a + ext_len >= maxlen)
                return 0;
 
-       strcpy(path+a, ext);
+       memcpy(path+a, ext, ext_len + 1);
+       return 1;
+}
+
+/* strip's trailing '.'s and adds the extension only when needed */
+int BLI_ensure_extension(char *path, size_t maxlen, const char *ext)
+{
+       size_t path_len= strlen(path);
+       size_t ext_len= strlen(ext);
+       size_t a;
+
+       /* first check the extension is alread there */
+       if (    (ext_len <= path_len) &&
+               (strcmp(path + (path_len - ext_len), ext) == 0))
+       {
+               return 1;
+       }
+
+       for(a= path_len - 1; a >= 0; a--) {
+               if (path[a] == '.') {
+                       path[a]= '\0';
+               }
+               else {
+                       break;
+               }
+       }
+       a++;
+
+       if(a + ext_len >= maxlen)
+               return 0;
+
+       memcpy(path+a, ext, ext_len + 1);
        return 1;
 }
 
@@ -1336,40 +1458,70 @@ int BLI_replace_extension(char *path, int maxlen, const char *ext)
  * - dosnt use CWD, or deal with relative paths.
  * - Only fill's in *dir and *file when they are non NULL
  * */
-void BLI_split_dirfile(const char *string, char *dir, char *file)
+void BLI_split_dirfile(const char *string, char *dir, char *file, const size_t dirlen, const size_t filelen)
 {
        char *lslash_str = BLI_last_slash(string);
-       int lslash= lslash_str ? (int)(lslash_str - string) + 1 : 0;
+       size_t lslash= lslash_str ? (size_t)(lslash_str - string) + 1 : 0;
 
        if (dir) {
                if (lslash) {
-                       BLI_strncpy( dir, string, lslash + 1); /* +1 to include the slash and the last char */
-               } else {
+                       BLI_strncpy( dir, string, MIN2(dirlen, lslash + 1)); /* +1 to include the slash and the last char */
+               }
+               else {
                        dir[0] = '\0';
                }
        }
        
        if (file) {
-               strcpy( file, string+lslash);
+               BLI_strncpy(file, string+lslash, filelen);
        }
 }
 
+void BLI_split_dir_part(const char *string, char *dir, const size_t dirlen)
+{
+       BLI_split_dirfile(string, dir, NULL, dirlen, 0);
+}
+
+void BLI_split_file_part(const char *string, char *file, const size_t filelen)
+{
+       BLI_split_dirfile(string, NULL, file, 0, filelen);
+}
+
 /* simple appending of filename to dir, does not check for valid path! */
-void BLI_join_dirfile(char *string, const char *dir, const char *file)
+void BLI_join_dirfile(char *dst, const size_t maxlen, const char *dir, const char *file)
 {
-       int sl_dir;
-       
-       if(string != dir) /* compare pointers */
-               BLI_strncpy(string, dir, FILE_MAX);
+       size_t dirlen= BLI_strnlen(dir, maxlen);
+
+       if (dst != dir) {
+               if(dirlen  == maxlen) {
+                       memcpy(dst, dir, dirlen);
+                       dst[dirlen - 1]= '\0';
+                       return; /* dir fills the path */
+               }
+               else {
+                       memcpy(dst, dir, dirlen + 1);
+               }
+       }
 
-       if (!file)
+       if (dirlen + 1 >= maxlen) {
+               return; /* fills the path */
+       }
+
+       /* inline BLI_add_slash */
+       if (dst[dirlen - 1] != SEP) {
+               dst[dirlen++]= SEP;
+               dst[dirlen  ]= '\0';
+       }
+
+       if (dirlen >= maxlen) {
+               return; /* fills the path */
+       }
+
+       if (file == NULL) {
                return;
-       
-       sl_dir= BLI_add_slash(string);
-       
-       if (sl_dir <FILE_MAX) {
-               BLI_strncpy(string + sl_dir, file, FILE_MAX-sl_dir);
        }
+
+       BLI_strncpy(dst + dirlen, file, maxlen - dirlen);
 }
 
 /* like pythons os.path.basename( ) */
@@ -1405,7 +1557,7 @@ char *BLI_path_basename(char *path)
   that a user gets his images in one place. It'll also provide
   consistent behaviour across exporters.
  */
-int BKE_rebase_path(char *abs, int abs_size, char *rel, int rel_size, const char *base_dir, const char *src_dir, const char *dest_dir)
+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)
 {
        char path[FILE_MAX];
        char dir[FILE_MAX];
@@ -1421,7 +1573,7 @@ int BKE_rebase_path(char *abs, int abs_size, char *rel, int rel_size, const char
        if (rel)
                rel[0]= 0;
 
-       BLI_split_dirfile(base_dir, blend_dir, NULL);
+       BLI_split_dir_part(base_dir, blend_dir, sizeof(blend_dir));
 
        if (src_dir[0]=='\0')
                return 0;
@@ -1432,7 +1584,7 @@ int BKE_rebase_path(char *abs, int abs_size, char *rel, int rel_size, const char
        BLI_path_abs(path, base_dir);
 
        /* get the directory part */
-       BLI_split_dirfile(path, dir, base);
+       BLI_split_dirfile(path, dir, base, sizeof(dir), sizeof(base));
 
        len= strlen(blend_dir);
 
@@ -1442,34 +1594,34 @@ int BKE_rebase_path(char *abs, int abs_size, char *rel, int rel_size, const char
        if (!strncmp(path, blend_dir, len)) {
 
                /* if image is _in_ current .blend file directory */
-               if (!strcmp(dir, blend_dir)) {
-                       BLI_join_dirfile(dest_path, dest_dir, base);
+               if (BLI_path_cmp(dir, blend_dir) == 0) {
+                       BLI_join_dirfile(dest_path, sizeof(dest_path), dest_dir, base);
                }
                /* "below" */
                else {
                        /* rel = image_path_dir - blend_dir */
                        BLI_strncpy(rel_dir, dir + len, sizeof(rel_dir));
 
-                       BLI_join_dirfile(dest_path, dest_dir, rel_dir);
-                       BLI_join_dirfile(dest_path, dest_path, base);
+                       BLI_join_dirfile(dest_path, sizeof(dest_path), dest_dir, rel_dir);
+                       BLI_join_dirfile(dest_path, sizeof(dest_path), dest_path, base);
                }
 
        }
        /* image is out of current directory */
        else {
-               BLI_join_dirfile(dest_path, dest_dir, base);
+               BLI_join_dirfile(dest_path, sizeof(dest_path), dest_dir, base);
        }
 
        if (abs)
-               BLI_strncpy(abs, dest_path, abs_size);
+               BLI_strncpy(abs, dest_path, abs_len);
 
        if (rel) {
-               strncat(rel, rel_dir, rel_size);
-               strncat(rel, base, rel_size);
+               strncat(rel, rel_dir, rel_len);
+               strncat(rel, base, rel_len);
        }
 
        /* return 2 if src=dest */
-       if (!strcmp(path, dest_path)) {
+       if (BLI_path_cmp(path, dest_path) == 0) {
                // if (G.f & G_DEBUG) printf("%s and %s are the same file\n", path, dest_path);
                return 2;
        }
@@ -1477,7 +1629,8 @@ int BKE_rebase_path(char *abs, int abs_size, char *rel, int rel_size, const char
        return 1;
 }
 
-char *BLI_first_slash(char *string) {
+char *BLI_first_slash(char *string)
+{
        char *ffslash, *fbslash;
        
        ffslash= strchr(string, '/');   
@@ -1490,7 +1643,8 @@ char *BLI_first_slash(char *string) {
        else return fbslash;
 }
 
-char *BLI_last_slash(const char *string) {
+char *BLI_last_slash(const char *string)
+{
        char *lfslash, *lbslash;
        
        lfslash= strrchr(string, '/');  
@@ -1504,33 +1658,23 @@ char *BLI_last_slash(const char *string) {
 }
 
 /* adds a slash if there isnt one there already */
-int BLI_add_slash(char *string) {
+int BLI_add_slash(char *string)
+{
        int len = strlen(string);
-#ifdef WIN32
-       if (len==0 || string[len-1]!='\\') {
-               string[len] = '\\';
+       if (len==0 || string[len-1] != SEP) {
+               string[len] = SEP;
                string[len+1] = '\0';
                return len+1;
        }
-#else
-       if (len==0 || string[len-1]!='/') {
-               string[len] = '/';
-               string[len+1] = '\0';
-               return len+1;
-       }
-#endif
        return len;
 }
 
 /* removes a slash if there is one */
-void BLI_del_slash(char *string) {
+void BLI_del_slash(char *string)
+{
        int len = strlen(string);
        while (len) {
-#ifdef WIN32
-               if (string[len-1]=='\\') {
-#else
-               if (string[len-1]=='/') {
-#endif
+               if (string[len-1] == SEP) {
                        string[len-1] = '\0';
                        len--;
                } else {
@@ -1544,12 +1688,12 @@ static int add_win32_extension(char *name)
        int retval = 0;
        int type;
 
-       type = BLI_exist(name);
+       type = BLI_exists(name);
        if ((type == 0) || S_ISDIR(type)) {
 #ifdef _WIN32
                char filename[FILE_MAXDIR+FILE_MAXFILE];
                char ext[FILE_MAXDIR+FILE_MAXFILE];
-               char *extensions = getenv("PATHEXT");
+               const char *extensions = getenv("PATHEXT");
                if (extensions) {
                        char *temp;
                        do {
@@ -1564,7 +1708,7 @@ static int add_win32_extension(char *name)
                                        strcat(filename, extensions);
                                }
 
-                               type = BLI_exist(filename);
+                               type = BLI_exists(filename);
                                if (type && (! S_ISDIR(type))) {
                                        retval = 1;
                                        strcpy(name, filename);
@@ -1580,54 +1724,68 @@ static int add_win32_extension(char *name)
        return (retval);
 }
 
-void BLI_where_am_i(char *fullname, const char *name)
+/*
+* Checks if name is a fully qualified filename to an executable.
+* If not it searches $PATH for the file. On Windows it also
+* adds the correct extension (.com .exe etc) from
+* $PATHEXT if necessary. Also on Windows it translates
+* the name to its 8.3 version to prevent problems with
+* spaces and stuff. Final result is returned in fullname.
+*
+* @param fullname The full path and full name of the executable
+* (must be FILE_MAX minimum)
+* @param name The name of the executable (usually argv[0]) to be checked
+*/
+static void bli_where_am_i(char *fullname, const size_t maxlen, const char *name)
 {
        char filename[FILE_MAXDIR+FILE_MAXFILE];
-       char *path = NULL, *temp;
-       
+       const char *path = NULL, *temp;
+
 #ifdef _WIN32
-       char *separator = ";";
-       char slash = '\\';
+       const char *separator = ";";
 #else
-       char *separator = ":";
-       char slash = '/';
+       const char *separator = ":";
 #endif
 
        
-#ifdef __linux__
-       /* linux uses binreloc since argv[0] is not relyable, call br_init( NULL ) first */
+#ifdef WITH_BINRELOC
+       /* linux uses binreloc since argv[0] is not reliable, call br_init( NULL ) first */
        path = br_find_exe( NULL );
        if (path) {
-               BLI_strncpy(fullname, path, FILE_MAXDIR+FILE_MAXFILE);
-               free(path);
+               BLI_strncpy(fullname, path, maxlen);
+               free((void *)path);
                return;
        }
 #endif
 
 #ifdef _WIN32
-       if(GetModuleFileName(0, fullname, FILE_MAXDIR+FILE_MAXFILE)) {
-               GetShortPathName(fullname, fullname, FILE_MAXDIR+FILE_MAXFILE);
+       if(GetModuleFileName(0, fullname, maxlen)) {
+               if(!BLI_exists(fullname)) {
+                       printf("path can't be found: \"%.*s\"\n", maxlen, fullname);
+                       MessageBox(NULL, "path contains invalid characters or is too long (see console)", "Error", MB_OK);
+               }
                return;
        }
 #endif
 
        /* unix and non linux */
-       if (name && fullname && strlen(name)) {
-               strcpy(fullname, name);
+       if (name && name[0]) {
+               BLI_strncpy(fullname, name, maxlen);
                if (name[0] == '.') {
-                       // relative path, prepend cwd
-                       BLI_getwdN(fullname);
-                       
+                       char wdir[FILE_MAX]= "";
+                       BLI_current_working_dir(wdir, sizeof(wdir));     /* backup cwd to restore after */
+
                        // not needed but avoids annoying /./ in name
-                       if(name && name[0]=='.' && name[1]==slash)
-                               BLI_join_dirfile(fullname, fullname, name+2);
+                       if(name[1]==SEP)
+                               BLI_join_dirfile(fullname, maxlen, wdir, name+2);
                        else
-                               BLI_join_dirfile(fullname, fullname, name);
-                       
-                       add_win32_extension(fullname);
-               } else if (BLI_last_slash(name)) {
+                               BLI_join_dirfile(fullname, maxlen, wdir, name);
+
+                       add_win32_extension(fullname); /* XXX, doesnt respect length */
+               }
+               else if (BLI_last_slash(name)) {
                        // full path
-                       strcpy(fullname, name);
+                       BLI_strncpy(fullname, name, maxlen);
                        add_win32_extension(fullname);
                } else {
                        // search for binary in $PATH
@@ -1642,9 +1800,9 @@ void BLI_where_am_i(char *fullname, const char *name)
                                        } else {
                                                strncpy(filename, path, sizeof(filename));
                                        }
-                                       BLI_join_dirfile(fullname, fullname, name);
+                                       BLI_join_dirfile(fullname, maxlen, fullname, name);
                                        if (add_win32_extension(filename)) {
-                                               strcpy(fullname, filename);
+                                               BLI_strncpy(fullname, filename, maxlen);
                                                break;
                                        }
                                } while (temp);
@@ -1654,85 +1812,94 @@ void BLI_where_am_i(char *fullname, const char *name)
                if (strcmp(name, fullname)) {
                        printf("guessing '%s' == '%s'\n", name, fullname);
                }
-#endif
-
-#ifdef _WIN32
-               // in windows change long filename to short filename because
-               // win2k doesn't know how to parse a commandline with lots of
-               // spaces and double-quotes. There's another solution to this
-               // with spawnv(P_WAIT, bprogname, argv) instead of system() but
-               // that's even uglier
-               GetShortPathName(fullname, fullname, FILE_MAXDIR+FILE_MAXFILE);
-#if defined(DEBUG)
-               printf("Shortname = '%s'\n", fullname);
-#endif
 #endif
        }
 }
 
-void BLI_where_is_temp(char *fullname, int usertemp)
+void BLI_init_program_path(const char *argv0)
+{
+       bli_where_am_i(bprogname, sizeof(bprogname), argv0);
+       BLI_split_dir_part(bprogname, bprogdir, sizeof(bprogdir));
+}
+
+const char *BLI_program_path(void)
+{
+       return bprogname;
+}
+
+const char *BLI_program_dir(void)
+{
+       return bprogdir;
+}
+
+/**
+* Gets the temp directory when blender first runs.
+* If the default path is not found, use try $TEMP
+* 
+* Also make sure the temp dir has a trailing slash
+*
+* @param fullname The full path to the temp directory
+* @param userdir Directory specified in user preferences 
+*/
+void BLI_where_is_temp(char *fullname, const size_t maxlen, char *userdir)
 {
        fullname[0] = '\0';
        
-       if (usertemp && BLI_is_dir(U.tempdir)) {
-               strcpy(fullname, U.tempdir);
+       if (userdir && BLI_is_dir(userdir)) {
+               BLI_strncpy(fullname, userdir, maxlen);
        }
        
        
 #ifdef WIN32
        if (fullname[0] == '\0') {
-               char *tmp = getenv("TEMP"); /* Windows */
+               const char *tmp = getenv("TEMP"); /* Windows */
                if (tmp && BLI_is_dir(tmp)) {
-                       strcpy(fullname, tmp);
+                       BLI_strncpy(fullname, tmp, maxlen);
                }
        }
 #else
        /* Other OS's - Try TMP and TMPDIR */
        if (fullname[0] == '\0') {
-               char *tmp = getenv("TMP");
+               const char *tmp = getenv("TMP");
                if (tmp && BLI_is_dir(tmp)) {
-                       strcpy(fullname, tmp);
+                       BLI_strncpy(fullname, tmp, maxlen);
                }
        }
        
        if (fullname[0] == '\0') {
-               char *tmp = getenv("TMPDIR");
+               const char *tmp = getenv("TMPDIR");
                if (tmp && BLI_is_dir(tmp)) {
-                       strcpy(fullname, tmp);
+                       BLI_strncpy(fullname, tmp, maxlen);
                }
        }
 #endif 
        
        if (fullname[0] == '\0') {
-               strcpy(fullname, "/tmp/");
+               BLI_strncpy(fullname, "/tmp/", maxlen);
        } else {
                /* add a trailing slash if needed */
                BLI_add_slash(fullname);
 #ifdef WIN32
-               strcpy(U.tempdir, fullname); /* also set user pref to show %TEMP%. /tmp/ is just plain confusing for Windows users. */
+               if(userdir && userdir != fullname) {
+                       BLI_strncpy(userdir, fullname, maxlen); /* also set user pref to show %TEMP%. /tmp/ is just plain confusing for Windows users. */
+               }
 #endif
        }
 }
 
-char *get_install_dir(void) {
-       extern char bprogname[];
-       char *tmpname = BLI_strdup(bprogname);
-       char *cut;
-
-#ifdef __APPLE__
-       cut = strstr(tmpname, ".app");
-       if (cut) cut[0] = 0;
-#endif
+void BLI_init_temporary_dir(char *userdir)
+{
+       BLI_where_is_temp(btempdir, FILE_MAX, userdir);
+}
 
-       cut = BLI_last_slash(tmpname);
+const char *BLI_temporary_dir(void)
+{
+       return btempdir;
+}
 
-       if (cut) {
-               cut[0] = 0;
-               return tmpname;
-       } else {
-               MEM_freeN(tmpname);
-               return NULL;
-       }
+void BLI_system_temporary_dir(char *dir)
+{
+       BLI_where_is_temp(dir, FILE_MAX, NULL);
 }
 
 #ifdef WITH_ICONV