quiet msvc/mingw compiler warnings.
[blender.git] / source / blender / blenlib / intern / path_util.c
index 423bf45..06dc510 100644 (file)
@@ -1,4 +1,4 @@
-/**
+/*
  *  $Id$
  *
  * ***** BEGIN GPL LICENSE BLOCK *****
  * 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 "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 */
+#else
+#  ifndef _GNU_SOURCE
+#    define _GNU_SOURCE
+#  endif
+#  include <fnmatch.h>
+#endif
 
 #ifdef WIN32
 #include <io.h>
 
 #else /* non windows */
 
-#ifdef __linux__
+#ifdef WITH_BINRELOC
 #include "binreloc.h"
 #endif
 
 #endif /* WIN32 */
 
 /* local */
+#define UNIQUE_NAME_MAX 128
+
+extern char bprogname[];
 
 static int add_win32_extension(char *name);
 static char *blender_version_decimal(void);
@@ -130,10 +148,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;
        
@@ -153,13 +202,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(number++, 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...
  *
@@ -168,65 +247,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
@@ -237,14 +296,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;
@@ -299,22 +351,22 @@ 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;
-       }       
+       }
+
+       /* support for odd paths: eg /../home/me --> /home/me
+        * this is a valid path in blender but we cant handle this the useual way below
+        * simply strip this prefix then evaluate the path as useual. pythons os.path.normpath() does this */
+       while((strncmp(dir, "/../", 4)==0)) {
+               memmove( dir, dir + 4, strlen(dir + 4) + 1 );
+       }
 
        while ( (start = strstr(dir, "/../")) ) {
-               eind = start + strlen("/../") - 1;
+               eind = start + (4 - 1) /* strlen("/../") - 1 */;
                a = start-dir-1;
                while (a>0) {
                        if (dir[a] == '/') break;
@@ -328,25 +380,29 @@ void BLI_cleanup_file(const char *relabase, char *dir)
        }
 
        while ( (start = strstr(dir,"/./")) ){
-               eind = start + strlen("/./") - 1;
+               eind = start + (3 - 1) /* strlen("/./") - 1 */;
                memmove( start, eind, strlen(eind)+1 );
        }
 
        while ( (start = strstr(dir,"//" )) ){
-               eind = start + strlen("//") - 1;
+               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)
 {
@@ -360,11 +416,11 @@ 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 .Blog files */
+                  can happen with old recent-files.txt files */
                get_default_root(temp);
                ptemp = &temp[2];
                if (relfile[0] != '\\' && relfile[0] != '/') {
@@ -375,7 +431,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;
        }
@@ -387,8 +443,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);
@@ -400,7 +456,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 */
@@ -458,13 +519,9 @@ int BLI_has_parent(char *path)
 
 int BLI_parent_dir(char *path)
 {
-#ifdef WIN32
-       static char *parent_dir="..\\";
-#else
-       static char *parent_dir="../";
-#endif
+       static char parent_dir[]= {'.', '.', SEP, '\0'}; /* "../" or "..\\" */
        char tmp[FILE_MAXDIR+FILE_MAXFILE+4];
-       BLI_strncpy(tmp, path, sizeof(tmp));
+       BLI_strncpy(tmp, path, sizeof(tmp)-4);
        BLI_add_slash(tmp);
        strcat(tmp, parent_dir);
        BLI_cleanup_dir(NULL, tmp);
@@ -534,9 +591,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;
        }
@@ -551,9 +607,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;
        }
@@ -586,7 +641,7 @@ int BLI_path_abs(char *path, const char *basepath)
                BLI_strncpy(tmp, path, FILE_MAX);
        }
 #else
-       BLI_strncpy(tmp, path, FILE_MAX);
+       BLI_strncpy(tmp, path, sizeof(tmp));
        
        /* Check for loading a windows path on a posix system
         * in this case, there is no use in trying C:/ since it 
@@ -603,9 +658,10 @@ int BLI_path_abs(char *path, const char *basepath)
        
 #endif
 
-       BLI_strncpy(base, basepath, FILE_MAX);
-       
-       BLI_cleanup_file(NULL, base);
+       BLI_strncpy(base, basepath, sizeof(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.
@@ -626,23 +682,17 @@ int BLI_path_abs(char *path, const char *basepath)
                        BLI_strncpy(path, tmp+2, FILE_MAX);
                        
                        memcpy(tmp, base, baselen);
-                       strcpy(tmp+baselen, path);
-                       strcpy(path, tmp);
+                       BLI_strncpy(tmp+baselen, path, sizeof(tmp)-baselen);
+                       BLI_strncpy(path, tmp, FILE_MAX);
                } else {
-                       strcpy(path, tmp+2);
+                       BLI_strncpy(path, tmp+2, FILE_MAX);
                }
        } else {
-               strcpy(path, tmp);
+               BLI_strncpy(path, tmp, FILE_MAX);
        }
-       
-       if (path[0]!='\0') {
-               if ( path[strlen(path)-1]=='/') {
-                       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
@@ -675,8 +725,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_getwdN(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.");
@@ -732,184 +782,41 @@ void BLI_getlastdir(const char* dir, char *last, int maxlen)
        }
 }
 
-char *BLI_gethome(void) {
+/* 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)
                return getenv("HOME");
 
        #else /* Windows */
-               char * ret;
-               static char dir[512];
-               static char appdatapath[MAXPATHLEN];
+               const char * ret;
+               static char documentfolder[MAXPATHLEN];
                HRESULT hResult;
 
                /* Check for %HOME% env var */
 
                ret = getenv("HOME");
                if(ret) {
-                       sprintf(dir, "%s\\%s", ret, blender_version_decimal());
-                       if (BLI_is_dir(dir)) return dir;
-               }
-
-               /* else, check install dir (path containing blender.exe) */
-
-               if(BLI_getInstallationDir(dir))
-               {
-                       sprintf(dir, "%s", dir, blender_version_decimal());
-                       if (BLI_is_dir(dir)) return(dir);
+                       if (BLI_is_dir(ret)) return ret;
                }
-
                                
                /* add user profile support for WIN 2K / NT.
                 * This is %APPDATA%, which translates to either
                 * %USERPROFILE%\Application Data or since Vista
                 * to %USERPROFILE%\AppData\Roaming
                 */
-               hResult = SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT, appdatapath);
+               hResult = SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, documentfolder);
                
                if (hResult == S_OK)
                {
-                       if (BLI_is_dir(appdatapath)) { /* from fop, also below... */
-                               sprintf(dir, "%s\\Blender Foundation\\Blender", appdatapath);
-                               BLI_recurdir_fileops(dir);
-                               if (BLI_is_dir(dir)) {
-                                       sprintf(dir,"%s\\%s", dir, blender_version_decimal());
-                                       if(BLI_is_dir(dir)) return(dir);
-                               }
-                       }
-                       hResult = SHGetFolderPath(NULL, CSIDL_COMMON_APPDATA, NULL, SHGFP_TYPE_CURRENT, appdatapath);
-                       if (hResult == S_OK)
-                       {
-                               if (BLI_is_dir(appdatapath)) 
-                               { /* from fop, also below... */
-                                       sprintf(dir, "%s\\Blender Foundation\\Blender", appdatapath);
-                                       BLI_recurdir_fileops(dir);
-                                       if (BLI_is_dir(dir)) {
-                                               sprintf(dir,"%s\\%s", dir, blender_version_decimal());
-                                               if(BLI_is_dir(dir)) return(dir);
-                                       }
-                               }
-                       }
+                       if (BLI_is_dir(documentfolder)) return documentfolder;
                }
                
-               return "C:\\Temp";      /* sheesh! bad, bad, bad! (aphex) */
+               return NULL;
        #endif
 }
 
-/* this function returns the path to a blender folder, if it exists
- * utility functions for BLI_gethome_folder */
-
-// #define PATH_DEBUG /* for testing paths that are checked */
-
-static int test_data_path(char *targetpath, char *path_base, char *path_sep, char *folder_name)
-{
-       char tmppath[FILE_MAXDIR];
-       
-       if(path_sep)    BLI_join_dirfile(tmppath, path_base, path_sep);
-       else                    BLI_strncpy(tmppath, path_base, sizeof(tmppath));
-       
-       BLI_make_file_string("/", targetpath, tmppath, folder_name);
-       
-       if (BLI_is_dir(targetpath)) {
-#ifdef PATH_DEBUG
-               printf("\tpath found: %s\n", targetpath);
-#endif
-               return 1;
-       }
-       else {
-#ifdef PATH_DEBUG
-               printf("\tpath missing: %s\n", targetpath);
-#endif
-               targetpath[0] = '\0';
-               return 0;
-       }
-}
-
-static int gethome_path_local(char *targetpath, char *folder_name)
-{
-       extern char bprogname[]; /* argv[0] from creator.c */
-       char bprogdir[FILE_MAXDIR];
-       char cwd[FILE_MAXDIR];
-       char *s;
-       int i;
-       
-#ifdef PATH_DEBUG
-       printf("gethome_path_local...\n");
-#endif
-       
-       /* try release/folder_name (binary relative) */
-       /* use argv[0] (bprogname) to get the path to the executable */
-       s = BLI_last_slash(bprogname);
-       i = s - bprogname + 1;
-       BLI_strncpy(bprogdir, bprogname, i);
-
-       /* try release/folder_name (BIN relative) */
-       if(test_data_path(targetpath, bprogdir, "release", folder_name))
-               return 1;
-
-       /* try release/folder_name (CWD relative) */
-       if(test_data_path(targetpath, BLI_getwdN(cwd), "release", folder_name))
-               return 1;
-
-       /* try ./.blender/folder_name */
-       if(test_data_path(targetpath, bprogdir, ".blender", folder_name))
-               return 1;
-       
-       return 0;
-}
-
-static int gethome_path_user(char *targetpath, char *folder_name)
-{
-       char *home_path= BLI_gethome();
-
-#ifdef PATH_DEBUG
-       printf("gethome_path_user...\n");
-#endif
-       
-       /* try $HOME/folder_name */
-       return test_data_path(targetpath, home_path, ".blender", folder_name);
-}
-
-static int gethome_path_system(char *targetpath, char *folder_name)
-{
-       extern char blender_path[]; /* unix prefix eg. /usr/share/blender/2.5 creator.c */
-       
-       if(!blender_path[0])
-               return 0;
-       
-#ifdef PATH_DEBUG
-       printf("gethome_path_system...\n");
-#endif
-       
-       /* try $BLENDERPATH/folder_name */
-       return test_data_path(targetpath, blender_path, NULL, folder_name);
-}
-
-char *BLI_gethome_folder(char *folder_name, int flag)
-{
-       static char fulldir[FILE_MAXDIR] = "";
-       
-       /* first check if this is a redistributable bundle */
-       if(flag & BLI_GETHOME_LOCAL) {
-               if (gethome_path_local(fulldir, folder_name))
-                       return fulldir;
-       }
-
-       /* then check if the OS has blender data files installed in a global location */
-       if(flag & BLI_GETHOME_SYSTEM) {
-               if (gethome_path_system(fulldir, folder_name))
-                       return fulldir;
-       }
-       
-       /* now check the users home dir for data files */
-       if(flag & BLI_GETHOME_USER) {
-               if (gethome_path_user(fulldir, folder_name))
-                       return fulldir;
-       }
-       
-       return NULL;
-}
-
-
 /* NEW stuff, to be cleaned up when fully migrated */
 /* ************************************************************* */
 /* ************************************************************* */
@@ -923,11 +830,11 @@ static char *blender_version_decimal(void)
        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);
@@ -947,9 +854,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)) {
@@ -961,57 +868,47 @@ static int test_env_path(char *path, char *envvar)
        }
 }
 
-static int get_path_local(char *targetpath, char *folder_name)
+static int get_path_local(char *targetpath, const char *folder_name, const char *subfolder_name)
 {
-       extern char bprogname[]; /* argv[0] from creator.c */
        char bprogdir[FILE_MAX];
-       char cwd[FILE_MAX];
-       char *s;
-       int i;
+       char relfolder[FILE_MAX];
        
 #ifdef PATH_DEBUG2
        printf("get_path_local...\n");
 #endif
        
+       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 */
-       s = BLI_last_slash(bprogname);
-       i = s - bprogname + 1;
-       BLI_strncpy(bprogdir, bprogname, i);
-       
-       /* try EXECUTABLE_DIR/folder_name */
-       if(test_path(targetpath, bprogdir, "", folder_name))
-               return 1;
-       
-       /* try CWD/release/folder_name */
-       if(test_path(targetpath, BLI_getwdN(cwd), "release", folder_name))
-               return 1;
-       
-       /* try EXECUTABLE_DIR/release/folder_name */
-       if(test_path(targetpath, bprogdir, "release", folder_name))
-               return 1;
+       BLI_split_dirfile(bprogname, bprogdir, NULL);
        
-       /* try EXECUTABLE_DIR/2.5/folder_name - new default directory for local blender installed files */
-       if(test_path(targetpath, bprogdir, blender_version_decimal(), folder_name))
-               return 1;
-
-       /* try ./.blender/folder_name -- DEPRECATED, need to update build systems */
-       if(test_path(targetpath, bprogdir, ".blender", folder_name))
+       /* try EXECUTABLE_DIR/2.5x/folder_name - new default directory for local blender installed files */
+       if(test_path(targetpath, bprogdir, blender_version_decimal(), relfolder))
                return 1;
 
        return 0;
 }
 
-static int get_path_user(char *targetpath, char *folder_name, char *envvar)
+static int get_path_user(char *targetpath, const char *folder_name, const char *subfolder_name, const char *envvar)
 {
        char user_path[FILE_MAX];
        const char *user_base_path;
        
        user_path[0] = '\0';
 
-       if (test_env_path(targetpath, envvar))
-               return 1;
-       
+       if (test_env_path(user_path, envvar)) {
+               if (subfolder_name) {
+                       return test_path(targetpath, user_path, NULL, subfolder_name);
+               } else {
+                       BLI_strncpy(targetpath, user_path, FILE_MAX);
+                       return 1;
+               }
+       }
+
        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());
@@ -1024,19 +921,60 @@ static int get_path_user(char *targetpath, char *folder_name, char *envvar)
        printf("get_path_user: %s\n", user_path);
 #endif
        
-       /* try $HOME/folder_name */
-       return test_path(targetpath, user_path, NULL, folder_name);
+       if (subfolder_name) {
+               /* try $HOME/folder_name/subfolder_name */
+               return test_path(targetpath, user_path, folder_name, subfolder_name);
+       } else {
+               /* try $HOME/folder_name */
+               return test_path(targetpath, user_path, NULL, folder_name);
+       }
 }
 
-static int get_path_system(char *targetpath, char *folder_name, char *envvar)
+static int get_path_system(char *targetpath, const char *folder_name, const char *subfolder_name, const char *envvar)
 {
        char system_path[FILE_MAX];
        const char *system_base_path;
 
-       system_path[0] = '\0';
 
-       if (test_env_path(targetpath, envvar))
+       /* first allow developer only overrides to the system path
+        * 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 (subfolder_name) {
+               BLI_join_dirfile(relfolder, sizeof(relfolder), folder_name, subfolder_name);
+       } else {
+               BLI_strncpy(relfolder, folder_name, sizeof(relfolder));
+       }
+
+       /* try CWD/release/folder_name */
+       if(BLI_getwdN(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;
+       /* end developer overrides */
+
+
+
+       system_path[0] = '\0';
+
+       if (test_env_path(system_path, envvar)) {
+               if (subfolder_name) {
+                       return test_path(targetpath, system_path, NULL, subfolder_name);
+               } else {
+                       BLI_strncpy(targetpath, system_path, FILE_MAX);
+                       return 1;
+               }
+       }
 
        system_base_path = (const char *)GHOST_getSystemDir();
        if (system_base_path) {
@@ -1050,100 +988,105 @@ static int get_path_system(char *targetpath, char *folder_name, char *envvar)
        printf("get_path_system: %s\n", system_path);
 #endif
        
-       /* try $BLENDERPATH/folder_name */
-       return test_path(targetpath, system_path, NULL, folder_name);
+       if (subfolder_name) {
+               /* try $BLENDERPATH/folder_name/subfolder_name */
+               return test_path(targetpath, system_path, folder_name, subfolder_name);
+       } else {
+               /* try $BLENDERPATH/folder_name */
+               return test_path(targetpath, system_path, NULL, folder_name);
+       }
 }
 
 /* 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)
 {
        static char path[FILE_MAX] = "";
-       char search_path[FILE_MAX];
        
        switch (folder_id) {
                case BLENDER_DATAFILES:         /* general case */
-                       BLI_join_dirfile(search_path, "datafiles", subfolder);
-                       if (get_path_local(path, search_path)) break;
-                       if (get_path_user(path, search_path, "BLENDER_USER_DATAFILES")) break;
-                       if (get_path_system(path, search_path, "BLENDER_SYSTEM_DATAFILES")) break;
+                       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;
                        return NULL;
                        
                case BLENDER_USER_DATAFILES:
-                       BLI_join_dirfile(search_path, "datafiles", subfolder);
-                       if (get_path_local(path, search_path)) break;
-                       if (get_path_user(path, search_path, "BLENDER_USER_DATAFILES")) break;
+                       if (get_path_local(path, "datafiles", subfolder)) break;
+                       if (get_path_user(path, "datafiles", subfolder, "BLENDER_USER_DATAFILES"))      break;
                        return NULL;
                        
                case BLENDER_SYSTEM_DATAFILES:
-                       BLI_join_dirfile(search_path, "datafiles", subfolder);
-                       if (get_path_system(path, search_path, "BLENDER_SYSTEM_DATAFILES"))     break;
+                       if (get_path_local(path, "datafiles", subfolder)) break;
+                       if (get_path_system(path, "datafiles", subfolder, "BLENDER_SYSTEM_DATAFILES"))  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;
+                       return NULL;
+
                case BLENDER_CONFIG:            /* general case */
-                       BLI_join_dirfile(search_path, "config", subfolder);
-                       if (get_path_local(path, search_path)) break;
-                       if (get_path_user(path, search_path, "BLENDER_USER_CONFIG")) break;
-                       if (get_path_system(path, search_path, "BLENDER_SYSTEM_CONFIG")) break;
+                       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:
-                       BLI_join_dirfile(search_path, "config", subfolder);
-                       if (get_path_local(path, search_path)) break;
-                       if (get_path_user(path, search_path, "BLENDER_USER_CONFIG")) break;
+                       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:
-                       BLI_join_dirfile(search_path, "config", subfolder);
-                       if (get_path_system(path, search_path, "BLENDER_SYSTEM_CONFIG")) break;
+                       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 */
-                       BLI_join_dirfile(search_path, "scripts", subfolder);
-                       if (get_path_local(path, search_path)) break;
-                       if (get_path_user(path, search_path, "BLENDER_USER_SCRIPTS")) break;            
-                       if (get_path_system(path, search_path, "BLENDER_SYSTEM_SCRIPTS")) break;
+                       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;
                        return NULL;
                        
                case BLENDER_USER_SCRIPTS:
-                       BLI_join_dirfile(search_path, "scripts", subfolder);
-                       if (get_path_local(path, search_path)) break;
-                       if (get_path_user(path, search_path, "BLENDER_USER_SCRIPTS")) break;
+                       if (get_path_local(path, "scripts", subfolder)) break;
+                       if (get_path_user(path, "scripts", subfolder, "BLENDER_USER_SCRIPTS")) break;
                        return NULL;
                        
                case BLENDER_SYSTEM_SCRIPTS:
-                       BLI_join_dirfile(search_path, "scripts", subfolder);
-                       if (get_path_system(path, search_path, "BLENDER_SYSTEM_SCRIPTS")) break;
+                       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 */
-                       BLI_join_dirfile(search_path, "python", subfolder);
-                       if (get_path_local(path, search_path)) break;
-                       if (get_path_system(path, search_path, "BLENDER_SYSTEM_PYTHON")) break;
+                       if (get_path_local(path, "python", subfolder)) break;
+                       if (get_path_system(path, "python", subfolder, "BLENDER_SYSTEM_PYTHON")) break;
                        return NULL;
                        
                case BLENDER_SYSTEM_PYTHON:
-                       BLI_join_dirfile(search_path, "python", subfolder);
-                       if (get_path_system(path, search_path, "BLENDER_SYSTEM_PYTHON")) break;
+                       if (get_path_local(path, "python", subfolder)) break;
+                       if (get_path_system(path, "python", subfolder, "BLENDER_SYSTEM_PYTHON")) break;
                        return NULL;
        }
        
        return path;
 }
 
-static char *BLI_get_user_folder_notest(int folder_id, char *subfolder)
+char *BLI_get_user_folder_notest(int folder_id, const char *subfolder)
 {
        static char path[FILE_MAX] = "";
-       char search_path[FILE_MAX];
 
        switch (folder_id) {
                case BLENDER_USER_DATAFILES:
-                       BLI_join_dirfile(search_path, "datafiles", subfolder);
-                       get_path_user(path, search_path, "BLENDER_USER_DATAFILES");
+                       get_path_user(path, "datafiles", subfolder, "BLENDER_USER_DATAFILES");
                        break;
                case BLENDER_USER_CONFIG:
-                       BLI_join_dirfile(search_path, "config", subfolder);
-                       get_path_user(path, search_path, "BLENDER_USER_CONFIG");
+                       get_path_user(path, "config", subfolder, "BLENDER_USER_CONFIG");
+                       break;
+               case BLENDER_USER_AUTOSAVE:
+                       get_path_user(path, "autosave", subfolder, "BLENDER_USER_AUTOSAVE");
+                       break;
+               case BLENDER_USER_SCRIPTS:
+                       get_path_user(path, "scripts", subfolder, "BLENDER_USER_SCRIPTS");
                        break;
        }
        if ('\0' == path[0]) {
@@ -1152,12 +1095,12 @@ static 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;
 
        /* only for user folders */
-       if (!ELEM(folder_id, BLENDER_USER_DATAFILES, BLENDER_USER_CONFIG))
+       if (!ELEM4(folder_id, BLENDER_USER_DATAFILES, BLENDER_USER_CONFIG, BLENDER_USER_SCRIPTS, BLENDER_USER_AUTOSAVE))
                return NULL;
        
        path = BLI_get_folder(folder_id, subfolder);
@@ -1214,9 +1157,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
@@ -1226,7 +1170,7 @@ 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++;
@@ -1236,49 +1180,35 @@ void BLI_char_switch(char *string, char from, char to)
 void BLI_make_exist(char *dir) {
        int a;
 
-       #ifdef WIN32
-               BLI_char_switch(dir, '/', '\\');
-       #else
-               BLI_char_switch(dir, '\\', '/');
-       #endif  
-       
+       BLI_char_switch(dir, ALTSEP, SEP);
+
        a = strlen(dir);
-       
-#ifdef WIN32   
+
        while(BLI_is_dir(dir) == 0){
                a --;
-               while(dir[a] != '\\'){
+               while(dir[a] != SEP){
                        a--;
                        if (a <= 0) break;
                }
-               if (a >= 0) dir[a+1] = 0;
+               if (a >= 0) {
+                       dir[a+1] = '\0';
+               }
                else {
-                       /* defaulting to drive (usually 'C:') of Windows installation */
+#ifdef WIN32
                        get_default_root(dir);
-                       break;
-               }
-       }
 #else
-       while(BLI_is_dir(dir) == 0){
-               a --;
-               while(dir[a] != '/'){
-                       a--;
-                       if (a <= 0) break;
-               }
-               if (a >= 0) dir[a+1] = 0;
-               else {
                        strcpy(dir,"/");
+#endif
                        break;
                }
        }
-#endif
 }
 
-void BLI_make_existing_file(char *name)
+void BLI_make_existing_file(const char *name)
 {
        char di[FILE_MAXDIR+FILE_MAXFILE], fi[FILE_MAXFILE];
 
-       strcpy(di, name);
+       BLI_strncpy(di, name, sizeof(di));
        BLI_splitdirstring(di, fi);
        
        /* test exist */
@@ -1312,15 +1242,14 @@ void BLI_make_file_string(const char *relabase, char *string,  const char *dir,
                /* Get the file name, chop everything past the last slash (ie. the filename) */
                strcpy(string, relabase);
                
-               lslash= (strrchr(string, '/')>strrchr(string, '\\'))?strrchr(string, '/'):strrchr(string, '\\');
-               
+               lslash= BLI_last_slash(string);
                if(lslash) *(lslash+1)= 0;
 
                dir+=2; /* Skip over the relative reference */
        }
 #ifdef WIN32
        else {
-               if (strlen(dir) >= 2 && dir[1] == ':' ) {
+               if (BLI_strnlen(dir, 3) >= 2 && dir[1] == ':' ) {
                        BLI_strncpy(string, dir, 3);
                        dir += 2;
                }
@@ -1366,10 +1295,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)) {
@@ -1377,17 +1306,63 @@ int BLI_testextensie(const char *str, const char *ext)
        } else {
                retval = 1;
        }
-
+       
        return (retval);
 }
 
-int BLI_replace_extension(char *path, int maxlen, const char *ext)
+int BLI_testextensie_array(const char *str, const char **ext_array)
 {
-       int a;
+       int i=0;
+       while(ext_array[i]) {
+               if(BLI_testextensie(str, ext_array[i])) {
+                       return 1;
+               }
+
+               i++;
+       }
+       return 0;
+}
+
+/* semicolon separated wildcards, eg:
+ *  '*.zip;*.py;*.exe' */
+int BLI_testextensie_glob(const char *str, const char *ext_fnmatch)
+{
+       const char *ext_step= ext_fnmatch;
+       char pattern[16];
+
+       while(ext_step[0]) {
+               char *ext_next;
+               int len_ext;
+
+               if((ext_next=strchr(ext_step, ';'))) {
+                       len_ext= (int)(ext_next - ext_step) + 1;
+               }
+               else {
+                       len_ext= sizeof(pattern);
+               }
+
+               BLI_strncpy(pattern, ext_step, len_ext);
+
+               if(fnmatch(pattern, str, FNM_CASEFOLD)==0) {
+                       return 1;
+               }
+               ext_step += len_ext;
+       }
+
+       return 0;
+}
+
 
-       for(a=strlen(path)-1; a>=0; a--)
-               if(path[a] == '.' || path[a] == '/' || path[a] == '\\')
+int BLI_replace_extension(char *path, size_t maxlen, const char *ext)
+{
+       size_t a;
+
+       for(a=strlen(path); a>0; a--) {
+               if(path[a-1] == '.' || path[a-1] == '/' || path[a-1] == '\\') {
+                       a--;
                        break;
+               }
+       }
        
        if(path[a] != '.')
                a= strlen(path);
@@ -1424,12 +1399,12 @@ void BLI_split_dirfile(const char *string, char *dir, char *file)
 }
 
 /* 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 *string, const int maxlen, const char *dir, const char *file)
 {
        int sl_dir;
        
        if(string != dir) /* compare pointers */
-               BLI_strncpy(string, dir, FILE_MAX);
+               BLI_strncpy(string, dir, maxlen);
 
        if (!file)
                return;
@@ -1437,7 +1412,7 @@ void BLI_join_dirfile(char *string, const char *dir, const char *file)
        sl_dir= BLI_add_slash(string);
        
        if (sl_dir <FILE_MAX) {
-               BLI_strncpy(string + sl_dir, file, FILE_MAX-sl_dir);
+               BLI_strncpy(string + sl_dir, file, maxlen - sl_dir);
        }
 }
 
@@ -1511,22 +1486,22 @@ 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)
@@ -1538,7 +1513,7 @@ int BKE_rebase_path(char *abs, int abs_size, char *rel, int rel_size, const char
        }
 
        /* 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;
        }
@@ -1546,6 +1521,67 @@ 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 *ffslash, *fbslash;
+       
+       ffslash= strchr(string, '/');   
+       fbslash= strchr(string, '\\');
+       
+       if (!ffslash) return fbslash;
+       else if (!fbslash) return ffslash;
+       
+       if ((intptr_t)ffslash < (intptr_t)fbslash) return ffslash;
+       else return fbslash;
+}
+
+char *BLI_last_slash(const char *string) {
+       char *lfslash, *lbslash;
+       
+       lfslash= strrchr(string, '/');  
+       lbslash= strrchr(string, '\\');
+
+       if (!lfslash) return lbslash; 
+       else if (!lbslash) return lfslash;
+       
+       if ((intptr_t)lfslash < (intptr_t)lbslash) return lbslash;
+       else return lfslash;
+}
+
+/* adds a slash if there isnt one there already */
+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] = '/';
+               string[len+1] = '\0';
+               return len+1;
+       }
+#endif
+       return len;
+}
+
+/* removes a slash if there is one */
+void BLI_del_slash(char *string) {
+       int len = strlen(string);
+       while (len) {
+#ifdef WIN32
+               if (string[len-1]=='\\') {
+#else
+               if (string[len-1]=='/') {
+#endif
+                       string[len-1] = '\0';
+                       len--;
+               } else {
+                       break;
+               }
+       }
+}
 
 static int add_win32_extension(char *name)
 {
@@ -1557,7 +1593,7 @@ static int add_win32_extension(char *name)
 #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 {
@@ -1588,54 +1624,54 @@ static int add_win32_extension(char *name)
        return (retval);
 }
 
-void BLI_where_am_i(char *fullname, const char *name)
+/* filename must be FILE_MAX length minimum */
+void BLI_where_am_i(char *fullname, const int 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__
+#ifdef WITH_BINRELOC
        /* linux uses binreloc since argv[0] is not relyable, 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)) {
+               GetShortPathName(fullname, fullname, maxlen);
                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_getwdN(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
@@ -1650,15 +1686,15 @@ 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);
                        }
                }
-#ifndef NDEBUG
+#if defined(DEBUG)
                if (strcmp(name, fullname)) {
                        printf("guessing '%s' == '%s'\n", name, fullname);
                }
@@ -1670,57 +1706,61 @@ void BLI_where_am_i(char *fullname, const char *name)
                // 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);
-#ifndef NDEBUG
+               GetShortPathName(fullname, fullname, maxlen);
+#if defined(DEBUG)
                printf("Shortname = '%s'\n", fullname);
 #endif
 #endif
        }
 }
 
-void BLI_where_is_temp(char *fullname, int usertemp)
+void BLI_where_is_temp(char *fullname, const int maxlen, int usertemp)
 {
        fullname[0] = '\0';
        
        if (usertemp && BLI_is_dir(U.tempdir)) {
-               strcpy(fullname, U.tempdir);
+               BLI_strncpy(fullname, U.tempdir, 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
+               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. */
+               }
+#endif
        }
 }
 
 char *get_install_dir(void) {
-       extern char bprogname[];
        char *tmpname = BLI_strdup(bprogname);
        char *cut;