use BLI_strncpy and BLI_snprintf when the size of the string is known.
[blender.git] / source / blender / blenlib / intern / path_util.c
index e0a08d0..6d63105 100644 (file)
@@ -1,6 +1,4 @@
 /*
- *  $Id$
- *
  * ***** BEGIN GPL LICENSE BLOCK *****
  *
  * This program is free software; you can redistribute it and/or
 
 #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_string_utf8.h"
 #include "BLI_utildefines.h"
 
 #include "BKE_utildefines.h"
@@ -56,7 +53,7 @@
 #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
 #  ifndef _GNU_SOURCE
 #    define _GNU_SOURCE
 #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 WITH_BINRELOC
-#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
 
-extern char bprogname[];
+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(const int ver);
@@ -153,7 +163,7 @@ void BLI_stringenc(char *string, const char *head, const char *tail, unsigned sh
 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));
@@ -211,18 +221,27 @@ int BLI_uniquename_cb(int (*unique_check)(void *, const char *), void *arg, cons
        }
 
        if(unique_check(arg, name)) {
+               char    numstr[16];
                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';
+                       int numlen= BLI_snprintf(numstr, sizeof(numstr), "%c%03d", delim, ++number);
+
+                       /* highly unlikely the string only has enough room for the number
+                        * but support anyway */
+                       if ((len == 0) || (numlen >= name_len)) {
+                               /* number is know not to be utf-8 */
+                               BLI_strncpy(tempname, numstr, name_len);
                        }
-               } while(number++, unique_check(arg, tempname));
+                       else {
+                               char *tempname_buf;
+                               tempname[0]= '\0';
+                               tempname_buf =BLI_strncat_utf8(tempname, left, name_len - numlen);
+                               memcpy(tempname_buf, numstr, numlen + 1);
+                       }
+               } while(unique_check(arg, tempname));
 
                BLI_strncpy(name, tempname, name_len);
                
@@ -298,7 +317,7 @@ void BLI_uniquename(ListBase *list, void *vlink, const char defname[], char deli
 
 void BLI_cleanup_path(const char *relabase, char *dir)
 {
-       short a;
+       ptrdiff_t a;
        char *start, *eind;
        if (relabase) {
                BLI_path_abs(dir, relabase);
@@ -407,8 +426,8 @@ void BLI_cleanup_file(const char *relabase, char *dir)
 void BLI_path_rel(char *file, const char *relfile)
 {
        char * lslash;
-       char temp[FILE_MAXDIR+FILE_MAXFILE];
-       char res[FILE_MAXDIR+FILE_MAXFILE];
+       char temp[FILE_MAX];
+       char res[FILE_MAX];
        
        /* if file is already relative, bail out */
        if(file[0]=='/' && file[1]=='/') return;
@@ -426,9 +445,9 @@ void BLI_path_rel(char *file, const char *relfile)
                if (relfile[0] != '\\' && relfile[0] != '/') {
                        ptemp++;
                }
-               BLI_strncpy(ptemp, relfile, FILE_MAXDIR + FILE_MAXFILE-3);
+               BLI_strncpy(ptemp, relfile, FILE_MAX-3);
        } else {
-               BLI_strncpy(temp, relfile, FILE_MAXDIR + FILE_MAXFILE);
+               BLI_strncpy(temp, relfile, FILE_MAX);
        }
 
        if (BLI_strnlen(file, 3) > 2) {
@@ -520,7 +539,7 @@ int BLI_has_parent(char *path)
 int BLI_parent_dir(char *path)
 {
        static char parent_dir[]= {'.', '.', SEP, '\0'}; /* "../" or "..\\" */
-       char tmp[FILE_MAXDIR+FILE_MAXFILE+4];
+       char tmp[FILE_MAX+4];
        BLI_strncpy(tmp, path, sizeof(tmp)-4);
        BLI_add_slash(tmp);
        strcat(tmp, parent_dir);
@@ -608,8 +627,10 @@ int BLI_path_frame_range(char *path, int sta, int end, int digits)
 
        if (stringframe_chars(path, &ch_sta, &ch_end)) { /* warning, ch_end is the last # +1 */
                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);
+               BLI_snprintf(tmp, sizeof(tmp),
+                            "%.*s%.*d-%.*d%s",
+                            ch_sta, path, ch_end-ch_sta, sta, ch_end-ch_sta, end, path+ch_end);
+               BLI_strncpy(path, tmp, FILE_MAX);
                return 1;
        }
        return 0;
@@ -725,8 +746,8 @@ int BLI_path_cwd(char *path)
 #endif
        
        if (wasrelative==1) {
-               char cwd[FILE_MAXDIR + FILE_MAXFILE]= "";
-               BLI_getwdN(cwd, sizeof(cwd)); /* incase the full path to the blend isnt used */
+               char cwd[FILE_MAX]= "";
+               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.");
@@ -738,8 +759,8 @@ int BLI_path_cwd(char *path)
                        * blend file which isnt a feature we want to use in this case since were dealing
                        * 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);
+                       char origpath[FILE_MAX];
+                       BLI_strncpy(origpath, path, FILE_MAX);
                        
                        BLI_make_file_string(NULL, path, cwd, origpath); 
                }
@@ -785,11 +806,20 @@ void BLI_getlastdir(const char* dir, char *last, const size_t 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 */
-const 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 */
+#else /* Windows */
                const char * ret;
                static char documentfolder[MAXPATHLEN];
                HRESULT hResult;
@@ -814,7 +844,7 @@ const char *BLI_getDefaultDocumentFolder(void) {
                }
                
                return NULL;
-       #endif
+#endif /* WIN32 */
 }
 
 /* NEW stuff, to be cleaned up when fully migrated */
@@ -874,7 +904,6 @@ static int test_env_path(char *path, const char *envvar)
 
 static int get_path_local(char *targetpath, const char *folder_name, const char *subfolder_name, const int ver)
 {
-       char bprogdir[FILE_MAX];
        char relfolder[FILE_MAX];
        
 #ifdef PATH_DEBUG2
@@ -891,10 +920,7 @@ static int get_path_local(char *targetpath, const char *folder_name, const char
        else {
                relfolder[0]= '\0';
        }
-       
-       /* use argv[0] (bprogname) to get the path to the executable */
-       BLI_split_dirfile(bprogname, bprogdir, NULL);
-       
+
        /* try EXECUTABLE_DIR/2.5x/folder_name - new default directory for local blender installed files */
        if(test_path(targetpath, bprogdir, blender_version_decimal(ver), relfolder))
                return 1;
@@ -962,10 +988,6 @@ static int get_path_system(char *targetpath, const char *folder_name, const char
         * these are only used when running blender from source */
        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(folder_name) {
                if (subfolder_name) {
@@ -979,7 +1001,7 @@ static int get_path_system(char *targetpath, const char *folder_name, const char
        }
 
        /* try CWD/release/folder_name */
-       if(BLI_getwdN(cwd, sizeof(cwd))) {
+       if(BLI_current_working_dir(cwd, sizeof(cwd))) {
                if(test_path(targetpath, cwd, "release", relfolder)) {
                        return 1;
                }
@@ -1024,26 +1046,6 @@ static int get_path_system(char *targetpath, const char *folder_name, const char
        }
 }
 
-#if defined(WIN32) && BLENDER_VERSION < 258
-
-static int path_have_257_script_install(void)
-{
-       const int ver= BLENDER_VERSION;
-       char path[FILE_MAX] = "";
-       char system_pyfile[FILE_MAX];
-
-       if (get_path_user(path, "scripts", NULL, "BLENDER_USER_SCRIPTS", ver)) {
-               BLI_join_dirfile(system_pyfile, sizeof(system_pyfile), path, "modules/bpy_types.py");
-
-               if (BLI_exists(system_pyfile))
-                       return 1;
-       }
-
-       return 0;
-}
-
-#endif
-
 /* 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, const char *subfolder)
@@ -1076,20 +1078,7 @@ char *BLI_get_folder(int folder_id, const char *subfolder)
                        return NULL;
                        
                case BLENDER_USER_SCRIPTS:
-#if defined(WIN32) && BLENDER_VERSION < 258
-                       /* if we have a 2.57 installation, then we may have system script
-                        * files in the user configuration folder. avoid using that folder
-                        * if they are there, until the version gets bumped to 2.58, so
-                        * we can be sure that folder only has addons etc. */
-                       if (path_have_257_script_install()) {
-                               if (get_path_local(path, "scripts", subfolder, ver)) break;
-                       }
-                       else
-#endif
-                       {
-                               if (get_path_user(path, "scripts", subfolder, "BLENDER_USER_SCRIPTS", ver)) break;
-                       }
-
+                       if (get_path_user(path, "scripts", subfolder, "BLENDER_USER_SCRIPTS", ver)) break;
                        return NULL;
                        
                case BLENDER_SYSTEM_SCRIPTS:
@@ -1143,7 +1132,7 @@ char *BLI_get_folder_create(int folder_id, const 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;
@@ -1188,8 +1177,8 @@ char *BLI_get_folder_version(const int id, const int ver, const int do_check)
 
 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);
@@ -1239,7 +1228,8 @@ void BLI_char_switch(char *string, char from, char to)
        }
 }
 
-void BLI_make_exist(char *dir) {
+void BLI_make_exist(char *dir)
+{
        int a;
 
        BLI_char_switch(dir, ALTSEP, SEP);
@@ -1268,14 +1258,14 @@ void BLI_make_exist(char *dir) {
 
 void BLI_make_existing_file(const char *name)
 {
-       char di[FILE_MAXDIR+FILE_MAXFILE], fi[FILE_MAXFILE];
+       char di[FILE_MAX], fi[FILE_MAXFILE];
 
        BLI_strncpy(di, name, sizeof(di));
        BLI_splitdirstring(di, fi);
        
        /* test exist */
        if (BLI_exists(di) == 0) {
-               BLI_recurdir_fileops(di);
+               BLI_dir_create_recursive(di);
        }
 }
 
@@ -1284,9 +1274,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 */
@@ -1417,22 +1416,55 @@ int BLI_testextensie_glob(const char *str, const char *ext_fnmatch)
 
 int BLI_replace_extension(char *path, size_t maxlen, const char *ext)
 {
-       size_t a;
+       size_t path_len= strlen(path);
+       size_t ext_len= strlen(ext);
+       ssize_t a;
 
-       for(a=strlen(path); a>0; a--) {
-               if(path[a-1] == '.' || path[a-1] == '/' || path[a-1] == '\\') {
-                       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 < 0) || (path[a] != '.')) {
+               a= path_len;
+       }
+
+       if(a + ext_len >= maxlen)
+               return 0;
+
+       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);
+       ssize_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;
 
-       strcpy(path+a, ext);
+       memcpy(path+a, ext, ext_len + 1);
        return 1;
 }
 
@@ -1442,40 +1474,70 @@ int BLI_replace_extension(char *path, size_t 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 size_t maxlen, 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, maxlen);
+       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 (dirlen + 1 >= maxlen) {
+               return; /* fills the path */
+       }
 
-       if (!file)
+       /* 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, maxlen - sl_dir);
        }
+
+       BLI_strncpy(dst + dirlen, file, maxlen - dirlen);
 }
 
 /* like pythons os.path.basename( ) */
@@ -1527,7 +1589,7 @@ int BKE_rebase_path(char *abs, size_t abs_len, char *rel, size_t rel_len, const
        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;
@@ -1538,7 +1600,7 @@ int BKE_rebase_path(char *abs, size_t abs_len, char *rel, size_t rel_len, const
        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);
 
@@ -1583,7 +1645,8 @@ int BKE_rebase_path(char *abs, size_t abs_len, char *rel, size_t rel_len, const
        return 1;
 }
 
-char *BLI_first_slash(char *string) {
+char *BLI_first_slash(char *string)
+{
        char *ffslash, *fbslash;
        
        ffslash= strchr(string, '/');   
@@ -1596,7 +1659,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, '/');  
@@ -1610,33 +1674,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] = '\\';
-               string[len+1] = '\0';
-               return len+1;
-       }
-#else
-       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;
        }
-#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 {
@@ -1650,11 +1704,11 @@ 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 filename[FILE_MAX];
+               char ext[FILE_MAX];
                const char *extensions = getenv("PATHEXT");
                if (extensions) {
                        char *temp;
@@ -1670,7 +1724,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);
@@ -1686,10 +1740,21 @@ static int add_win32_extension(char *name)
        return (retval);
 }
 
-/* filename must be FILE_MAX length minimum */
-void BLI_where_am_i(char *fullname, const size_t maxlen, 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 filename[FILE_MAX];
        const char *path = NULL, *temp;
 
 #ifdef _WIN32
@@ -1700,7 +1765,7 @@ void BLI_where_am_i(char *fullname, const size_t maxlen, const char *name)
 
        
 #ifdef WITH_BINRELOC
-       /* linux uses binreloc since argv[0] is not relyable, call br_init( NULL ) first */
+       /* 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, maxlen);
@@ -1713,7 +1778,7 @@ void BLI_where_am_i(char *fullname, const size_t maxlen, const char *name)
        if(GetModuleFileName(0, fullname, maxlen)) {
                if(!BLI_exists(fullname)) {
                        printf("path can't be found: \"%.*s\"\n", maxlen, fullname);
-                       MessageBox(NULL, "path constains invalid characters or is too long (see console)", "Error", MB_OK);
+                       MessageBox(NULL, "path contains invalid characters or is too long (see console)", "Error", MB_OK);
                }
                return;
        }
@@ -1724,7 +1789,7 @@ void BLI_where_am_i(char *fullname, const size_t maxlen, const char *name)
                BLI_strncpy(fullname, name, maxlen);
                if (name[0] == '.') {
                        char wdir[FILE_MAX]= "";
-                       BLI_getwdN(wdir, sizeof(wdir));  /* backup cwd to restore after */
+                       BLI_current_working_dir(wdir, sizeof(wdir));     /* backup cwd to restore after */
 
                        // not needed but avoids annoying /./ in name
                        if(name[1]==SEP)
@@ -1767,12 +1832,37 @@ void BLI_where_am_i(char *fullname, const size_t maxlen, const char *name)
        }
 }
 
-void BLI_where_is_temp(char *fullname, const size_t maxlen, 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 
+*/
+static void BLI_where_is_temp(char *fullname, const size_t maxlen, char *userdir)
 {
        fullname[0] = '\0';
        
-       if (usertemp && BLI_is_dir(U.tempdir)) {
-               BLI_strncpy(fullname, U.tempdir, maxlen);
+       if (userdir && BLI_is_dir(userdir)) {
+               BLI_strncpy(fullname, userdir, maxlen);
        }
        
        
@@ -1806,13 +1896,28 @@ void BLI_where_is_temp(char *fullname, const size_t maxlen, int usertemp)
                /* add a trailing slash if needed */
                BLI_add_slash(fullname);
 #ifdef WIN32
-               if(U.tempdir != fullname) {
-                       BLI_strncpy(U.tempdir, fullname, maxlen); /* 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
        }
 }
 
+void BLI_init_temporary_dir(char *userdir)
+{
+       BLI_where_is_temp(btempdir, FILE_MAX, userdir);
+}
+
+const char *BLI_temporary_dir(void)
+{
+       return btempdir;
+}
+
+void BLI_system_temporary_dir(char *dir)
+{
+       BLI_where_is_temp(dir, FILE_MAX, NULL);
+}
+
 #ifdef WITH_ICONV
 
 void BLI_string_to_utf8(char *original, char *utf_8, const char *code)