bugfix [#24462] UV Layouts saved as PNG results in two files (one is 0 KB, other...
[blender.git] / source / blender / blenlib / intern / path_util.c
index 9a56722..91558d4 100644 (file)
 
 #include "GHOST_Path-api.h"
 
+#if defined WIN32 && !defined _LIBC
+# include "BLI_fnmatch.h" /* use fnmatch included in blenlib */
+#else
+# define _GNU_SOURCE
+# include <fnmatch.h>
+#endif
 
 #ifdef WIN32
 #include <io.h>
@@ -311,10 +317,17 @@ void BLI_cleanup_file(const char *relabase, char *dir)
           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,12 +341,12 @@ 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 );
        }
 
@@ -458,13 +471,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 +543,20 @@ 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];
+               char tmp[FILE_MAX];
+#if 0  // neat but breaks on non ascii strings.
+               char 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);
+#else
+               char format[8];
+               char *p;
+               sprintf(format, "%%.%dd", ch_end-ch_sta); /* example result: "%.5d" */
+               memcpy(tmp, path, sizeof(char) * ch_sta);
+               p= tmp + ch_sta;
+               p += sprintf(p, format, frame);
+               memcpy(p, path + ch_end, strlen(path + ch_end));
+#endif
                strcpy(path, tmp);
                return 1;
        }
@@ -586,7 +606,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,7 +623,7 @@ int BLI_path_abs(char *path, const char *basepath)
        
 #endif
 
-       BLI_strncpy(base, basepath, FILE_MAX);
+       BLI_strncpy(base, basepath, sizeof(base));
        
        BLI_cleanup_file(NULL, base);
        
@@ -626,17 +646,19 @@ 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]=='/') {
+                       /* 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);
@@ -823,9 +845,6 @@ static int get_path_local(char *targetpath, char *folder_name, char *subfolder_n
        extern char bprogname[]; /* argv[0] from creator.c */
        char bprogdir[FILE_MAX];
        char relfolder[FILE_MAX];
-       char cwd[FILE_MAX];
-       char *s;
-       int i;
        
 #ifdef PATH_DEBUG2
        printf("get_path_local...\n");
@@ -838,30 +857,12 @@ static int get_path_local(char *targetpath, char *folder_name, char *subfolder_n
        }
        
        /* 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, "", relfolder))
-               return 1;
-       
-       /* try CWD/release/folder_name */
-       if(test_path(targetpath, BLI_getwdN(cwd), "release", relfolder))
-               return 1;
+       BLI_split_dirfile(bprogname, bprogdir, NULL);
        
-       /* try EXECUTABLE_DIR/release/folder_name */
-       if(test_path(targetpath, bprogdir, "release", relfolder))
-               return 1;
-       
-       /* try EXECUTABLE_DIR/2.5/folder_name - new default directory for local blender installed files */
+       /* 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;
 
-       /* try ./.blender/folder_name -- DEPRECATED, need to update build systems */
-       if(test_path(targetpath, bprogdir, ".blender", relfolder))
-               return 1;
-
        return 0;
 }
 
@@ -907,6 +908,34 @@ static int get_path_system(char *targetpath, char *folder_name, char *subfolder_
        char system_path[FILE_MAX];
        const char *system_base_path;
 
+
+       /* 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);
+       }
+
+       /* try CWD/release/folder_name */
+       if(test_path(targetpath, BLI_getwdN(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)) {
@@ -1013,7 +1042,7 @@ char *BLI_get_folder(int folder_id, char *subfolder)
        return path;
 }
 
-static char *BLI_get_user_folder_notest(int folder_id, char *subfolder)
+char *BLI_get_user_folder_notest(int folder_id, char *subfolder)
 {
        static char path[FILE_MAX] = "";
 
@@ -1027,6 +1056,9 @@ static char *BLI_get_user_folder_notest(int folder_id, char *subfolder)
                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]) {
                return NULL;
@@ -1039,7 +1071,7 @@ char *BLI_get_folder_create(int folder_id, char *subfolder)
        char *path;
 
        /* only for user folders */
-       if (!ELEM3(folder_id, BLENDER_USER_DATAFILES, BLENDER_USER_CONFIG, BLENDER_USER_AUTOSAVE))
+       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);
@@ -1118,49 +1150,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)
 {
        char di[FILE_MAXDIR+FILE_MAXFILE], fi[FILE_MAXFILE];
 
-       strcpy(di, name);
+       BLI_strncpy(di, name, sizeof(di));
        BLI_splitdirstring(di, fi);
        
        /* test exist */
@@ -1194,8 +1212,7 @@ 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 */
@@ -1276,6 +1293,36 @@ int BLI_testextensie_array(const char *str, const char **ext_array)
        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;
+}
+
+
 int BLI_replace_extension(char *path, int maxlen, const char *ext)
 {
        int a;
@@ -1441,6 +1488,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)
 {
@@ -1553,7 +1661,7 @@ void BLI_where_am_i(char *fullname, const char *name)
                                } while (temp);
                        }
                }
-#ifndef NDEBUG
+#if defined(DEBUG)
                if (strcmp(name, fullname)) {
                        printf("guessing '%s' == '%s'\n", name, fullname);
                }
@@ -1566,7 +1674,7 @@ void BLI_where_am_i(char *fullname, const char *name)
                // with spawnv(P_WAIT, bprogname, argv) instead of system() but
                // that's even uglier
                GetShortPathName(fullname, fullname, FILE_MAXDIR+FILE_MAXFILE);
-#ifndef NDEBUG
+#if defined(DEBUG)
                printf("Shortname = '%s'\n", fullname);
 #endif
 #endif
@@ -1611,6 +1719,9 @@ void BLI_where_is_temp(char *fullname, int usertemp)
        } 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. */
+#endif
        }
 }