build system revision
[vg.git] / vg_io.c
diff --git a/vg_io.c b/vg_io.c
new file mode 100644 (file)
index 0000000..76e8ca3
--- /dev/null
+++ b/vg_io.c
@@ -0,0 +1,235 @@
+/* Copyright (C) 2021-2024 Harry Godden (hgn) - All Rights Reserved */
+
+#include "vg_io.h"
+#include "vg_platform.h"
+#include "vg_log.h"
+#include "vg_mem.h"
+#include <string.h>
+#include <errno.h>
+
+int vg_dir_open( vg_dir *dir, const char *name )
+{
+#ifdef _WIN32
+   char q_buf[4096];
+   vg_str q;
+   vg_strnull( &q, q_buf, 4096 );
+   vg_strcat( &q, name );
+   vg_strcat( &q, "/*" );
+   if( !vg_strgood(&q) ) return 0;
+
+   vg_info( "FindFirstFile( '%s' )\n", q.buffer );
+   dir->h = FindFirstFile( q.buffer, &dir->data );
+   if( dir->h == INVALID_HANDLE_VALUE ){
+      if( GetLastError() == ERROR_FILE_NOT_FOUND ){
+         dir->index = 0;
+         return 1;
+      }
+      else return 0;
+   }
+#else
+   dir->h = opendir( name );
+   if( !dir->h ) return 0;
+#endif
+   dir->index = 1;
+   return 1;
+}
+
+const char *vg_dir_entry_name( vg_dir *dir )
+{
+#ifdef _WIN32
+   return dir->data.cFileName;
+#else
+   return dir->data->d_name;
+#endif
+}
+
+int vg_dirskip( vg_dir *dir )
+{
+   const char *s = vg_dir_entry_name(dir);
+#ifdef _WIN32
+   if( dir->data.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN ) return 1;
+#endif
+   if( s[0] == '.' ){
+      if( s[1] == '\0' ) return 1;
+      else if( s[1] == '.' ){
+         if( s[2] == '\0' ) return 1;
+      }
+   }
+   return 0;
+}
+
+int vg_dir_next_entry( vg_dir *dir )
+{
+#ifdef _WIN32
+   if( dir->index == 0 ) return 0;
+   if( dir->index > 1 ) {
+      dir->index ++;
+      if( !FindNextFile( dir->h, &dir->data ) ) return 0;
+   }
+   while( vg_dirskip(dir) ){
+      dir->index ++;
+      if( !FindNextFile( dir->h, &dir->data ) ) return 0;
+   }
+   if( dir->index == 1 ) dir->index ++;
+   return 1;
+#else
+   while( (dir->data = readdir(dir->h)) ){
+      dir->index ++;
+      if( !vg_dirskip(dir) ) break;
+   }
+   if( dir->data ) return 1;
+   else return 0;
+#endif
+}
+
+enum vg_entry_type vg_dir_entry_type( vg_dir *dir )
+{
+#ifdef _WIN32
+   if( dir->data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) 
+      return k_vg_entry_type_dir;
+   return k_vg_entry_type_file; /* sketchy? */
+#else
+   if( dir->data->d_type == DT_DIR ) return k_vg_entry_type_dir;
+   if( dir->data->d_type == DT_REG ) return k_vg_entry_type_file;
+#endif
+   return 0;
+}
+
+void vg_dir_close( vg_dir *dir )
+{
+#ifdef _WIN32
+   if( dir->index ) FindClose( dir->h );
+   dir->h = INVALID_HANDLE_VALUE;
+#else
+   closedir( dir->h );
+   dir->h = NULL;
+   dir->data = NULL;
+#endif
+   dir->index = 0;
+}
+
+void vg_file_print_invalid( FILE *fp )
+{
+   if( feof( fp )) {
+      vg_error( "mdl_open: header too short\n" );
+   }
+   else{
+      if( ferror( fp ))
+         vg_error( "mdl_open: %s\n", strerror(errno) );
+      else
+         vg_error( "mdl_open: unkown failure\n" );
+
+   }
+}
+
+#define VG_FILE_IO_CHUNK_SIZE 1024*256
+
+/* read entire binary file */
+void *vg_file_read( void *lin_alloc, const char *path, u32 *size )
+{
+       FILE *f = fopen( path, "rb" );
+       if( f ){
+      void *buffer = lin_alloc? vg_linear_alloc( lin_alloc, 0 ):
+                                NULL;
+      u64 current = 0;
+
+      /* read in chunks */
+      for( u32 i=0; 1; i++ ){
+         if( lin_alloc )
+            buffer = vg_linear_extend( lin_alloc,buffer,VG_FILE_IO_CHUNK_SIZE );
+         else 
+            buffer = realloc( buffer, current + VG_FILE_IO_CHUNK_SIZE );
+
+         u64 l = fread( buffer + current, 1, VG_FILE_IO_CHUNK_SIZE, f );
+         current += l;
+
+         if( l != VG_FILE_IO_CHUNK_SIZE ){
+            if( feof( f ) ){
+               break;
+            }
+            else{
+               if( ferror( f ) ){
+                  fclose(f);
+                  vg_fatal_error( "read error" );
+               }
+               else{
+                  fclose(f);
+                  vg_fatal_error( "unknown error codition" );
+               }
+            }
+         }
+      }
+
+      if( lin_alloc )
+         buffer = vg_linear_resize( lin_alloc, buffer, vg_align8(current) );
+      else
+         buffer = realloc( buffer, vg_align8(current) );
+
+               fclose( f );
+
+      *size = (u32)current;
+      return buffer;
+       }
+       else{
+      vg_error( "vg_disk_open_read: %s (file: %s)\n", strerror(errno), path );
+               return NULL;
+       }
+}
+
+/* read entire file and append a null on the end */
+char *vg_file_read_text( void *lin_alloc, const char *path, u32 *sz )
+{
+   u32 size;
+   char *str = vg_file_read( lin_alloc, path, &size );
+
+   if( !str )
+      return NULL;
+
+   /* include null terminator */
+   if( lin_alloc )
+      str = vg_linear_extend( lin_alloc, str, 1 );
+   else
+      str = realloc( str, size+1 );
+
+   str[ size ] = '\0';
+   *sz = size+1;
+
+   return str;
+}
+
+
+int vg_asset_write( const char *path, void *data, i64 size )
+{
+       FILE *f = fopen( path, "wb" );
+       if( f ){
+               fwrite( data, size, 1, f );
+               fclose( f );
+               return 1;
+       }
+       else{
+               return 0;
+       }
+}
+
+/* TODO: error handling if read fails */
+int vg_file_copy( const char *src, const char *dst, void *lin_alloc )
+{
+   vg_info( "vg_file_copy( %s -> %s )\n", src, dst );
+   u32 size;
+   void *data = vg_file_read( lin_alloc, src, &size );
+   return vg_asset_write( dst, data, size );
+}
+
+const char *vg_path_filename( const char *path )
+{
+   const char *base = path;
+   
+   for( int i=0; i<1024; i++ ){
+      if( path[i] == '\0' ) break;
+      if( path[i] == '/' ){
+         base = path+i+1;
+      }
+   }
+
+   return base;
+}