use BLI_strncpy and BLI_snprintf when the size of the string is known.
[blender-staging.git] / source / blender / blenlib / intern / storage.c
index 3204d5f74e19847fdff625564cf6ee421876eda3..df0634e4fcff59076935b622bc86a7735442fffa 100644 (file)
@@ -1,6 +1,4 @@
-/**
- * $Id$
- *
+/*
  * ***** BEGIN GPL LICENSE BLOCK *****
  *
  * This program is free software; you can redistribute it and/or
@@ -15,7 +13,7 @@
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  *
  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
  * All rights reserved.
  * Some really low-level file thingies.
  */
 
+/** \file blender/blenlib/intern/storage.c
+ *  \ingroup bli
+ */
+
+
 #include <sys/types.h>
 #include <stdio.h>
 #include <stdlib.h>    
 
-#ifdef WIN32
-#include "BLI_winstuff.h"
-#include <sys/types.h>
-#include <io.h>
-#include <direct.h>
-#endif
-
 #ifndef WIN32
 #include <dirent.h>
 #endif
 #include <time.h>
 #include <sys/stat.h>
 
-#if defined (__sun__) || defined (__sun) || defined (__sgi)
+#if defined (__sun__) || defined (__sun) || defined (__NetBSD__)
 #include <sys/statvfs.h> /* Other modern unix os's should probably use this also */
 #elif !defined(__FreeBSD__) && !defined(linux) && (defined(__sparc) || defined(__sparc__))
 #include <sys/statfs.h>
 #endif
 
-#if defined (__FreeBSD__) || defined (__OpenBSD__) || defined (__NetBSD__)
+#if defined (__FreeBSD__) || defined (__OpenBSD__)
 #include <sys/param.h>
 #include <sys/mount.h>
 #endif
 
-#if defined(linux) || defined(__CYGWIN32__) || defined(__hpux)
+#if defined(linux) || defined(__CYGWIN32__) || defined(__hpux) || defined(__GNU__) || defined(__GLIBC__)
 #include <sys/vfs.h>
 #endif
 
@@ -70,9 +66,6 @@
 
 
 #include <fcntl.h>
-#if !defined(WIN32)
-#include <sys/mtio.h>                  /* tape comando's */
-#endif
 #include <string.h>                    /* strcpy etc.. */
 
 #ifndef WIN32
 #include <pwd.h>
 #endif
 
-#if !defined(__FreeBSD__) && !defined(__APPLE__)
-#include <malloc.h>
+#ifdef WIN32
+#include <io.h>
+#include <direct.h>
+#include "BLI_winstuff.h"
 #endif
 
+
 /* lib includes */
 #include "MEM_guardedalloc.h"
 
 #include "DNA_listBase.h"
-#include "BLI_blenlib.h"
-#include "BLI_storage.h"
-#include "BLI_storage_types.h"
 
-#include "BLI_util.h"
+#include "BLI_fileops.h"
+#include "BLI_listbase.h"
 #include "BLI_linklist.h"
+#include "BLI_string.h"
 
 #include "BKE_utildefines.h"
 
 static int totnum,actnum;
 static struct direntry *files;
 
-static struct ListBase dirbase_={
-       0,0};
+static struct ListBase dirbase_={NULL, NULL};
 static struct ListBase *dirbase = &dirbase_;
 
-
-char *BLI_getwdN(char *dir)
+/* can return NULL when the size is not big enough */
+char *BLI_current_working_dir(char *dir, const int maxncpy)
 {
-       char *pwd;
-
-       if (dir) {
-               pwd = getenv("PWD");
-               if (pwd){
-                       strcpy(dir, pwd);
-                       return(dir);
-               }
-               /* 160 is FILE_MAXDIR in filesel.c */
-               return( getcwd(dir, 160) );
+       const char *pwd= getenv("PWD");
+       if (pwd){
+               BLI_strncpy(dir, pwd, maxncpy);
+               return dir;
        }
-       return(0);
+
+       return getcwd(dir, maxncpy);
 }
 
 
-int BLI_compare(struct direntry *entry1, struct direntry *entry2)
+static int bli_compare(struct direntry *entry1, struct direntry *entry2)
 {
        /* type is equal to stat.st_mode */
 
@@ -151,7 +140,7 @@ int BLI_compare(struct direntry *entry1, struct direntry *entry2)
 }
 
 
-double BLI_diskfree(char *dir)
+double BLI_dir_free_space(const char *dir)
 {
 #ifdef WIN32
        DWORD sectorspc, bytesps, freec, clusters;
@@ -173,7 +162,7 @@ double BLI_diskfree(char *dir)
        return (double) (freec*bytesps*sectorspc);
 #else
 
-#if defined (__sun__) || defined (__sun) || defined (__sgi)
+#if defined (__sun__) || defined (__sun) || defined (__NetBSD__)
        struct statvfs disk;
 #else
        struct statfs disk;
@@ -191,11 +180,11 @@ double BLI_diskfree(char *dir)
                if (slash) slash[1] = 0;
        } else strcpy(name,"/");
 
-#if defined (__FreeBSD__) || defined (linux) || defined (__OpenBSD__) || defined (__APPLE__) 
+#if defined (__FreeBSD__) || defined (linux) || defined (__OpenBSD__) || defined (__APPLE__) || defined(__GNU__) || defined(__GLIBC__)
        if (statfs(name, &disk)) return(-1);
 #endif
 
-#if defined (__sun__) || defined (__sun) || defined (__sgi)
+#if defined (__sun__) || defined (__sun) || defined (__NetBSD__)
        if (statvfs(name, &disk)) return(-1);   
 #elif !defined(__FreeBSD__) && !defined(linux) && (defined(__sparc) || defined(__sparc__))
        /* WARNING - This may not be supported by geeneric unix os's - Campbell */
@@ -206,23 +195,15 @@ double BLI_diskfree(char *dir)
 #endif
 }
 
-static int hide_dot= 0;
-
-void BLI_hide_dot_files(int set)
-{
-       if(set) hide_dot= 1;
-       else hide_dot= 0;
-}
-
-void BLI_builddir(char *dirname, char *relname)
+static void bli_builddir(const char *dirname, const char *relname)
 {
        struct dirent *fname;
        struct dirlink *dlink;
-       int rellen, newnum = 0, ignore;
+       int rellen, newnum = 0;
        char buf[256];
        DIR *dir;
 
-       strcpy(buf,relname);
+       BLI_strncpy(buf, relname, sizeof(buf));
        rellen=strlen(relname);
 
        if (rellen){
@@ -237,35 +218,46 @@ void BLI_builddir(char *dirname, char *relname)
 
        if ( (dir = (DIR *)opendir(".")) ){
                while ((fname = (struct dirent*) readdir(dir)) != NULL) {
-                       
-                       if(hide_dot && fname->d_name[0]=='.' && fname->d_name[1]!='.' && fname->d_name[1]!=0) {
-                       }
-                       else if ( ( (fname->d_name[0] == '.') && (fname->d_name[1] == 0) ) ||
-                                         ( (fname->d_name[0] == '.') && (fname->d_name[1] == '.') && (fname->d_name[2] == 0)) ) {
-                               /* ignore '.' and '..' */
-                       }
-                       else {
-                               dlink = (struct dirlink *)malloc(sizeof(struct dirlink));
-                               if (dlink){
-                                       strcpy(buf+rellen,fname->d_name);
-                                       dlink->name = BLI_strdup(buf);
-                                       BLI_addhead(dirbase,dlink);
-                                       newnum++;
-                               }
+                       dlink = (struct dirlink *)malloc(sizeof(struct dirlink));
+                       if (dlink){
+                               BLI_strncpy(buf + rellen ,fname->d_name, sizeof(buf) - rellen);
+                               dlink->name = BLI_strdup(buf);
+                               BLI_addhead(dirbase,dlink);
+                               newnum++;
                        }
                }
                
                if (newnum){
 
-                       if (files) files=(struct direntry *)realloc(files,(totnum+newnum) * sizeof(struct direntry));
-                       else files=(struct direntry *)malloc(newnum * sizeof(struct direntry));
+                       if(files) {
+                               void *tmp= realloc(files, (totnum+newnum) * sizeof(struct direntry));
+                               if(tmp) {
+                                       files= (struct direntry *)tmp;
+                               }
+                               else { /* realloc fail */
+                                       free(files);
+                                       files= NULL;
+                               }
+                       }
+                       
+                       if(files==NULL)
+                               files=(struct direntry *)malloc(newnum * sizeof(struct direntry));
 
                        if (files){
                                dlink = (struct dirlink *) dirbase->first;
                                while(dlink){
                                        memset(&files[actnum], 0 , sizeof(struct direntry));
                                        files[actnum].relname = dlink->name;
+                                       files[actnum].path = BLI_strdupcat(dirname, dlink->name);
+// use 64 bit file size, only needed for WIN32 and WIN64. 
+// Excluding other than current MSVC compiler until able to test.
+#if (defined(WIN32) || defined(WIN64)) && (_MSC_VER>=1500)
+                                       _stat64(dlink->name,&files[actnum].s);
+#elif defined(__MINGW32__)
+                                       _stati64(dlink->name,&files[actnum].s);
+#else
                                        stat(dlink->name,&files[actnum].s);
+#endif
                                        files[actnum].type=files[actnum].s.st_mode;
                                        files[actnum].flags = 0;
                                        totnum++;
@@ -278,7 +270,7 @@ void BLI_builddir(char *dirname, char *relname)
                        }
 
                        BLI_freelist(dirbase);
-                       if (files) qsort(files, actnum, sizeof(struct direntry), (int (*)(const void *,const void*))BLI_compare);
+                       if (files) qsort(files, actnum, sizeof(struct direntry), (int (*)(const void *,const void*))bli_compare);
                } else {
                        printf("%s empty directory\n",dirname);
                }
@@ -289,12 +281,12 @@ void BLI_builddir(char *dirname, char *relname)
        }
 }
 
-void BLI_adddirstrings()
+static void bli_adddirstrings(void)
 {
        char datum[100];
        char buf[512];
        char size[250];
-       static char * types[8] = {"---", "--x", "-w-", "-wx", "r--", "r-x", "rw-", "rwx"};
+       static const char * types[8] = {"---", "--x", "-w-", "-wx", "r--", "r-x", "rw-", "rwx"};
        int num, mode;
 #ifdef WIN32
        __int64 st_size;
@@ -305,21 +297,19 @@ void BLI_adddirstrings()
        struct direntry * file;
        struct tm *tm;
        time_t zero= 0;
-
-       file = &files[0];
        
-       for(num=0;num<actnum;num++){
+       for(num=0, file= files; num<actnum; num++, file++){
 #ifdef WIN32
                mode = 0;
-               strcpy(file->mode1, types[0]);
-               strcpy(file->mode2, types[0]);
-               strcpy(file->mode3, types[0]);
+               BLI_strncpy(file->mode1, types[0], sizeof(file->mode1));
+               BLI_strncpy(file->mode2, types[0], sizeof(file->mode2));
+               BLI_strncpy(file->mode3, types[0], sizeof(file->mode3));
 #else
                mode = file->s.st_mode;
 
-               strcpy(file->mode1, types[(mode & 0700) >> 6]);
-               strcpy(file->mode2, types[(mode & 0070) >> 3]);
-               strcpy(file->mode3, types[(mode & 0007)]);
+               BLI_strncpy(file->mode1, types[(mode & 0700) >> 6], sizeof(file->mode1));
+               BLI_strncpy(file->mode2, types[(mode & 0070) >> 3], sizeof(file->mode2));
+               BLI_strncpy(file->mode3, types[(mode & 0007)], sizeof(file->mode3));
                
                if (((mode & S_ISGID) == S_ISGID) && (file->mode2[2]=='-'))file->mode2[2]='l';
 
@@ -337,81 +327,84 @@ void BLI_adddirstrings()
 #endif
 
 #ifdef WIN32
-               strcpy(files[num].owner,"user");
+               strcpy(file->owner,"user");
 #else
                {
                        struct passwd *pwuser;
-                       pwuser = getpwuid(files[num].s.st_uid);
+                       pwuser = getpwuid(file->s.st_uid);
                        if ( pwuser ) {
-                       strcpy(files[num].owner, pwuser->pw_name);
+                               BLI_strncpy(file->owner, pwuser->pw_name, sizeof(file->owner));
                        } else {
-                               sprintf(files[num].owner, "%d", files[num].s.st_uid);
-            }
+                               BLI_snprintf(file->owner, sizeof(file->owner), "%d", file->s.st_uid);
+                       }
                }
 #endif
 
-               tm= localtime(&files[num].s.st_mtime);
+               tm= localtime(&file->s.st_mtime);
                // prevent impossible dates in windows
                if(tm==NULL) tm= localtime(&zero);
-               strftime(files[num].time, 8, "%H:%M", tm);
-               strftime(files[num].date, 16, "%d-%b-%y", tm);
+               strftime(file->time, sizeof(file->time), "%H:%M", tm);
+               strftime(file->date, sizeof(file->date), "%d-%b-%y", tm);
 
                /*
                 * Seems st_size is signed 32-bit value in *nix and Windows.  This
                 * will buy us some time until files get bigger than 4GB or until
                 * everyone starts using __USE_FILE_OFFSET64 or equivalent.
                 */
-               st_size= (off_t)files[num].s.st_size;
+               st_size= file->s.st_size;
 
                if (st_size > 1024*1024*1024) {
-                       sprintf(files[num].size, "%.2f GB", ((double)st_size)/(1024*1024*1024));        
+                       BLI_snprintf(file->size, sizeof(file->size), "%.2f GB", ((double)st_size)/(1024*1024*1024));
                }
                else if (st_size > 1024*1024) {
-                       sprintf(files[num].size, "%.1f MB", ((double)st_size)/(1024*1024));
+                       BLI_snprintf(file->size, sizeof(file->size), "%.1f MB", ((double)st_size)/(1024*1024));
                }
                else if (st_size > 1024) {
-                       sprintf(files[num].size, "%d KB", (int)(st_size/1024));
+                       BLI_snprintf(file->size, sizeof(file->size), "%d KB", (int)(st_size/1024));
                }
                else {
-                       sprintf(files[num].size, "%d B", (int)st_size);
+                       BLI_snprintf(file->size, sizeof(file->size), "%d B", (int)st_size);
                }
 
-               strftime(datum, 32, "%d-%b-%y %H:%M", tm);
+               strftime(datum, 32, "%d-%b-%y %H:%M", tm); /* XXX, is this used? - campbell */
 
                if (st_size < 1000) {
-                       sprintf(size, "%10d", (int) st_size);
-               } else if (st_size < 1000 * 1000) {
-                       sprintf(size, "%6d %03d", (int) (st_size / 1000), (int) (st_size % 1000));
-               } else if (st_size < 100 * 1000 * 1000) {
-                       sprintf(size, "%2d %03d %03d", (int) (st_size / (1000 * 1000)), (int) ((st_size / 1000) % 1000), (int) ( st_size % 1000));
-               } else {
-                       sprintf(size, "> %4.1f M", (double) (st_size / (1024.0 * 1024.0)));
-                       sprintf(size, "%10d", (int) st_size);
+                       BLI_snprintf(size, sizeof(size), "%10d",
+                                    (int) st_size);
                }
-
-               sprintf(buf,"%s %s %s %7s %s %s %10s %s", file->mode1, file->mode2, file->mode3, files[num].owner, files[num].date, files[num].time, size,
-                       files[num].relname);
-
-               files[num].string=MEM_mallocN(strlen(buf)+1, "filestring");
-               if (files[num].string){
-                       strcpy(files[num].string,buf);
+               else if (st_size < 1000 * 1000) {
+                       BLI_snprintf(size, sizeof(size), "%6d %03d",
+                                    (int) (st_size / 1000), (int) (st_size % 1000));
+               }
+               else if (st_size < 100 * 1000 * 1000) {
+                       BLI_snprintf(size, sizeof(size), "%2d %03d %03d",
+                                    (int) (st_size / (1000 * 1000)), (int) ((st_size / 1000) % 1000), (int) ( st_size % 1000));
+               }
+               else {
+                       /* XXX, whats going on here?. 2x calls - campbell */
+                       BLI_snprintf(size, sizeof(size), "> %4.1f M", (double) (st_size / (1024.0 * 1024.0)));
+                       BLI_snprintf(size, sizeof(size), "%10d", (int) st_size);
                }
 
-               file++;
+               BLI_snprintf(buf, sizeof(buf), "%s %s %s %7s %s %s %10s %s",
+                            file->mode1, file->mode2, file->mode3, file->owner,
+                            file->date, file->time, size, file->relname);
+
+               file->string = BLI_strdup(buf);
        }
 }
 
-unsigned int BLI_getdir(char *dirname,  struct direntry **filelist)
+unsigned int BLI_dir_contents(const char *dirname,  struct direntry **filelist)
 {
        // reset global variables
        // memory stored in files is free()'d in
        // filesel.c:freefilelist()
 
        actnum = totnum = 0;
-       files = 0;
+       files = NULL;
 
-       BLI_builddir(dirname,"");
-       BLI_adddirstrings();
+       bli_builddir(dirname,"");
+       bli_adddirstrings();
 
        if (files) {
                *(filelist) = files;
@@ -425,7 +418,7 @@ unsigned int BLI_getdir(char *dirname,  struct direntry **filelist)
 }
 
 
-int BLI_filesize(int file)
+size_t BLI_file_descriptor_size(int file)
 {
        struct stat buf;
 
@@ -434,54 +427,77 @@ int BLI_filesize(int file)
        return (buf.st_size);
 }
 
-int BLI_filepathsize(const char *path)
+size_t BLI_file_size(const char *path)
 {
        int size, file = open(path, O_BINARY|O_RDONLY);
        
-       if (file <= 0)
+       if (file == -1)
                return -1;
        
-       size = BLI_filesize(file);
+       size = BLI_file_descriptor_size(file);
        close(file);
        return size;
 }
 
 
-int BLI_exist(char *name)
+int BLI_exists(const char *name)
 {
-       struct stat st;
-#ifdef WIN32
+#if defined(WIN32) && !defined(__MINGW32__)
+       struct _stat64i32 st;
        /*  in Windows stat doesn't recognize dir ending on a slash 
                To not break code where the ending slash is expected we
                don't mess with the argument name directly here - elubie */
-       char tmp[FILE_MAXDIR+FILE_MAXFILE];
-       int len;
-       BLI_strncpy(tmp, name, FILE_MAXDIR+FILE_MAXFILE);
+       char tmp[FILE_MAX];
+       int len, res;
+       BLI_strncpy(tmp, name, FILE_MAX);
        len = strlen(tmp);
        if (len > 3 && ( tmp[len-1]=='\\' || tmp[len-1]=='/') ) tmp[len-1] = '\0';
-       if (stat(tmp,&st)) return(0);
+       res = _stat(tmp, &st);
+       if (res == -1) return(0);
+#elif defined(__MINGW32__)
+       struct _stati64 st;
+       char tmp[FILE_MAX];
+       int len, res;
+       BLI_strncpy(tmp, name, FILE_MAX);
+       len = strlen(tmp);
+       if (len > 3 && ( tmp[len-1]=='\\' || tmp[len-1]=='/') ) tmp[len-1] = '\0';
+       res = _stati64(tmp, &st);
+       if (res) return(0);
 #else
+       struct stat st;
        if (stat(name,&st)) return(0);  
 #endif
        return(st.st_mode);
 }
 
-LinkNode *BLI_read_file_as_lines(char *name)
+/* would be better in fileops.c except that it needs stat.h so add here */
+int BLI_is_dir(const char *file)
+{
+       return S_ISDIR(BLI_exists(file));
+}
+
+int BLI_is_file(const char *path)
+{
+       int mode= BLI_exists(path);
+       return (mode && !S_ISDIR(mode));
+}
+
+LinkNode *BLI_file_read_as_lines(const char *name)
 {
        FILE *fp= fopen(name, "r");
        LinkNode *lines= NULL;
        char *buf;
-       int size;
+       size_t size;
 
        if (!fp) return NULL;
                
        fseek(fp, 0, SEEK_END);
-       size= ftell(fp);
+       size= (size_t)ftell(fp);
        fseek(fp, 0, SEEK_SET);
 
-       buf= malloc(size);
+       buf= MEM_mallocN(size, "file_as_lines");
        if (buf) {
-               int i, last= 0;
+               size_t i, last= 0;
                
                        /* 
                         * size = because on win32 reading
@@ -498,7 +514,7 @@ LinkNode *BLI_read_file_as_lines(char *name)
                        }
                }
                
-               free(buf);
+               MEM_freeN(buf);
        }
        
        fclose(fp);
@@ -507,7 +523,18 @@ LinkNode *BLI_read_file_as_lines(char *name)
        return lines;
 }
 
-void BLI_free_file_lines(LinkNode *lines)
+void BLI_file_free_lines(LinkNode *lines)
 {
        BLI_linklist_free(lines, (void(*)(void*)) MEM_freeN);
 }
+
+int BLI_file_older(const char *file1, const char *file2)
+{
+       struct stat st1, st2;
+
+       if(stat(file1, &st1)) return 0;
+       if(stat(file2, &st2)) return 0;
+
+       return (st1.st_mtime < st2.st_mtime);
+}
+