Commit 3bd866f
Changed files (8)
io/file.h
@@ -0,0 +1,147 @@
+#ifndef KC_HEADER_IO_FILE_INCLUDED
+#define KC_HEADER_IO_FILE_INCLUDED
+
+#include "./stream.h"
+#include "../types/string.h"
+#include "../memory/arenas.h"
+
+typedef struct _File File;
+
+void File_to_stream_source( File *f, SourceGeneric *stream );
+void File_to_stream_sink( File *f, SinkGeneric *stream );
+
+enum FileOption {
+ FILEOPTION_READ = (1<<0),
+ FILEOPTION_WRITE = (1<<1),
+ FILEOPTION_READWRITE = FILEOPTION_READ | FILEOPTION_WRITE,
+
+ FILEOPTION_DISALLOW_CREATION = (1<<2),
+ FILEOPTION_NO_FOLLOW_LINKS = (1<<3),
+
+};
+
+status File_open( File* fout, const string *path, u64 file_options, MemArena scratch );
+status File_close( File* f );
+
+status File_read( File *f, u64 *amount, u8 *out);
+status File_write( File *f, u64 *amount, const u8 *in);
+
+#ifdef KC_IMPLEMENT
+
+ void File_to_stream_source( File *f, SourceGeneric *stream ) {
+ stream->self = f;
+ stream->close = (StreamCloseFunction)&File_close;
+ stream->consume = (StreamInteractFunction)&File_read;
+ }
+
+ void File_to_stream_sink( File *f, SinkGeneric *stream ) {
+ stream->self = f;
+ stream->close = (StreamCloseFunction)&File_close;
+ stream->produce = (StreamInteractFunction)&File_write;
+ }
+
+ #if defined(KC_PLATFORM_LINUX)
+ #ifdef KC_USE_PLATFORM_LIBC
+ #include <fcntl.h>
+ #include <unistd.h>
+
+ struct _File {
+ i32 fd;
+ };
+
+ status File_open( File *fout, const string *path, u64 file_options, MemArena scratch ) {
+ u8* path_c = 0;
+ PROPAGATE_ERROR( string_to_cstring( path, &scratch, &path_c ) );
+
+ mode_t mode = 0;
+
+ if( file_options & FILEOPTION_READ ) {
+ if( file_options & FILEOPTION_WRITE ) {
+ mode = O_RDWR;
+ } else {
+ mode = O_RDONLY;
+ }
+ } else if( file_options & FILEOPTION_WRITE ) {
+ mode = O_RDWR;
+ } else {
+ return ERROR_INVALID_ARGUMENTS;
+ }
+
+ if( !file_options ) {
+ return ERROR_INVALID_ARGUMENTS;
+ }
+
+ if( !(file_options & FILEOPTION_DISALLOW_CREATION) ) {
+ mode |= O_CREAT;
+ }
+
+ if( file_options & FILEOPTION_NO_FOLLOW_LINKS ) {
+ mode |= O_NOFOLLOW;
+ }
+
+ fout->fd = open( (char*)path_c, mode );
+
+ if( fout->fd < 0 ) {
+ return ERROR_PLATFORM_FILE_OPEN_FAILED;
+ }
+
+ return STATUS_SUCCESS;
+ }
+
+ status File_close(File *f) {
+ assert( f->fd != -1 );
+
+ if( close(f->fd) != 0 ) {
+ return ERROR_PLATFORM_FILE_CLOSE_FAILED;
+ }
+
+ f->fd = -1;
+ return STATUS_SUCCESS;
+ }
+
+ status File_read(File *f, u64 *amount, u8 *out) {
+
+ size_t res = read( f->fd, out, *amount );
+
+ if( res == 0 || res < *amount ) {
+ *amount = res;
+ return STATUS_STREAM_ENDED;
+ }
+
+ if( res == (size_t)-1 ) {
+ return ERROR_PLATFORM_FILE_READ_FAILED;
+ }
+
+ return STATUS_SUCCESS;
+ }
+
+ status File_write(File *f, u64 *amount, const u8 *in) {
+
+ size_t res = write( f->fd, (char*)in, *amount );
+
+ if( res != *amount ) {
+ *amount = res;
+ return STATUS_PARTIAL_WRITE;
+ }
+
+ if( res == (size_t)-1 ) {
+ return ERROR_PLATFORM_FILE_WRITE_FAILED;
+ }
+
+ return STATUS_SUCCESS;
+ }
+
+
+ #else
+ #error I/O is not supported without libc for now (due to syscalls missing - after adding syscall wrappers this will be possible)
+ #endif
+
+ #elif defined(KC_PLATFORM_WINDOWS)
+ #error Unsupported platform for I/O
+ #else
+ #error Unsupported platform for I/O
+ #endif
+
+#endif
+
+#endif
io/stream.h
@@ -0,0 +1,52 @@
+#ifndef KC_HEADER_IO_STREAM_INCLUDED
+#define KC_HEADER_IO_STREAM_INCLUDED
+
+#include "../types/types.h"
+#include "../memory/arenas.h"
+
+typedef status (*StreamInteractFunction)(void*, u64*, u8*);
+typedef status (*StreamCloseFunction)(void*);
+
+typedef struct _SourceGeneric {
+ void* self;
+ status (*consume)(void *self, u64 *amount, u8* buf);
+ status (*close)(void *self);
+} SourceGeneric;
+
+typedef struct _SinkGeneric{
+ void* self;
+ status (*produce)(void *self, u64 *amount, u8* buf);
+ status (*close)(void *self);
+} SinkGeneric;
+
+status Stream_into_arena( SourceGeneric *s, MemArena *a, u64 blocksize, u64 *amount_out );
+
+
+#ifdef KC_IMPLEMENT
+
+ status Stream_into_arena( SourceGeneric *s, MemArena *a, u64 blocksize, u64 *amount_out ) {
+ *amount_out = 0;
+ u8* block = 0;
+ u64 read = blocksize;
+ status state;
+
+ PROPAGATE_ERROR( MemArena_take_amount( a, blocksize, &block ) );
+
+ read = blocksize;
+ while( (state = s->consume(s->self, &read, block)) == STATUS_SUCCESS ) {
+ read = blocksize;
+ PROPAGATE_ERROR( MemArena_take_amount( a, blocksize, &block ) );
+ *amount_out += read;
+ }
+
+ if( state == STATUS_STREAM_ENDED ) {
+ *amount_out += read;
+ return STATUS_SUCCESS;
+ } else {
+ return state;
+ }
+ }
+
+#endif
+
+#endif
memory/arenas.h
@@ -23,7 +23,7 @@ status MemArena_destroy( MemArena *arena );
MemArena MemArena_from( MemArena *arena ); /* Get a sub arena, with a new arena "frame" */
-status MemArena_take_amount( MemArena *arena, u64 size, void** out );
+status MemArena_take_amount( MemArena *arena, u64 size, u8** out );
#define MemArena_take( arena, type, count, out ) MemArena_take_amount( arena, (sizeof(type))*(count), out )
status MemArena_give_amount( MemArena *arena, u64 size );
#define MemArena_give( arena, type, count ) MemArena_give_amount( arena, (sizeof(type))*(count) )
@@ -73,7 +73,7 @@ status MemArena_uncommit_unused( MemArena *arena );
};
}
- status MemArena_take_amount( MemArena *arena, u64 size, void **outptr ) {
+ status MemArena_take_amount( MemArena *arena, u64 size, u8 **outptr ) {
ASSERT_MEM_ARENA_IS_SANE(arena);
assert(size);
@@ -146,7 +146,7 @@ status MemArena_uncommit_unused( MemArena *arena );
#if defined(KC_ZERO_MEMORY_STRICT)
mem_set_range( new_commited, arena->last_commited, 0 );
#endif
- PROPAGATE_ERROR( kc_platform_mem_va_uncommit( new_commited, arena->last_commited - new_commited ) );
+ PROPAGATE_ERROR( kc_platform_mem_va_uncommit( new_commited, arena->end - new_commited ) ); /* We have to get rid of it until the end, in case a subarena has also allocated more. */
arena->last_commited = new_commited;
memory/ops.h
@@ -2,10 +2,23 @@
#define KC_HEADER_MEMORY_OPS_INCLUDED
#include "../types/types.h"
+#include <stddef.h>
-status mem_copy( void *src, void *dst, u64 size );
+void mem_copy( const void *src, void *dst, u64 size );
status mem_move( void *src, void *dst, u64 size );
status mem_set( void *buf, u64 size, u8 value );
status mem_set_range( void *start, void *end, u8 value );
+#ifdef KC_IMPLEMENT
+
+void mem_copy( const void *src, void *dst, u64 size ) {
+ const u8 *s = src;
+ u8 *d = dst;
+ for( u64 i = 0; i < size; ++i ) {
+ d[i] = s[i];
+ }
+}
+
+#endif
+
#endif
tests/a.out
Binary file
tests/main.c
@@ -9,6 +9,7 @@
#include "../platform/assert.h"
#include "../include/testing.h"
+#include "../io/file.h"
KC_TESTFUNC( test0,
printf("Good riddance!\n");
@@ -17,21 +18,30 @@ KC_TESTFUNC( test0,
int main(void) {
MemArena a;
+ MemArena scratch;
- assert(OK( MemArena_create( &a, GiB(120) )) );
+ assert(OK( MemArena_create( &a, GiB(4) )) );
+ assert(OK( MemArena_create( &scratch, MiB(1) )) );
- u8* data;
- assert( OK(MemArena_take( &a, u8, GiB(1), (void**)&data ) ));
+ File f = {0};
- for( u64 i = 0; i < GiB(1); ++i ) {
- data[i] = 'K';
- }
+ STATIC_STRING( testfile_name, "./testfile" );
- assert( OK(MemArena_give_amount( &a, MiB(512) ) ));
- assert( OK(MemArena_uncommit_unused( &a )));
+ assert(OK( File_open( &f, (string*)&testfile_name, FILEOPTION_READ, MemArena_from( &scratch ) ) ));
- assert( OK(MemArena_give_amount( &a, MiB(512) ) ));
- assert( OK(MemArena_uncommit_unused( &a )));
+ SourceGeneric s = {0};
+
+ File_to_stream_source( &f, &s );
+
+ u64 amount = 0;
+ Stream_into_arena( &s, &a, 64, &amount );
+
+ printf("%lu", amount );
+ putchar('\n');
+ write(1, a.start, amount);
+
+
+ assert(OK( File_close( &f ) ));
assert(OK(MemArena_destroy(&a)));
}
types/string.h
@@ -0,0 +1,38 @@
+#ifndef KC_HEADER_TYPES_STRING_INCLUDED
+#define KC_HEADER_TYPES_STRING_INCLUDED
+
+#include "../platform/types.h"
+#include "../memory/arenas.h"
+
+typedef struct _string {
+ u64 len;
+ u8 data[];
+} string;
+
+
+#define STATIC_STRING( varname, str ) \
+ const struct { \
+ u64 len; \
+ u8 data[sizeof( str ) - 1] __attribute__( ( nonstring ) ); \
+ } varname = { .len = sizeof( str ) - 1, .data = str }
+
+status string_to_cstring( const string *str, MemArena *a, u8** out );
+
+#ifdef KC_IMPLEMENT
+
+status string_to_cstring( const string *str, MemArena *a, u8** out ) {
+ u8* c_str;
+ u64 l = str->len;
+
+ PROPAGATE_ERROR(MemArena_take( a, u8, l + 1, &c_str ));
+ mem_copy( &str->data[0], c_str, l );
+ c_str[l] = '\0';
+
+ *out = c_str;
+ return STATUS_SUCCESS;
+}
+
+#endif
+
+
+#endif
types/types.h
@@ -16,14 +16,24 @@ typedef i32 status;
enum _Status {
STATUS_SUCCESS = 0,
- ERROR_GENERIC = 1,
- ERROR_WOULD_OVERRUN = 2,
- ERROR_WOULD_UNDERRUN = 3,
-
- ERROR_PLATFORM_GENERIC = 10000,
- ERROR_PLATFORM_MAPPING_FAILED = 10001,
- ERROR_PLATFORM_MEMORY_PERMISSION_CHANGE_FAILED = 10002,
- ERROR_PLATFORM_MEMORY_HINT_CHANGE_FAILED = 10003,
+
+ STATUS_STREAM_ENDED = 100,
+ STATUS_PARTIAL_WRITE = 101,
+
+ ERROR_GENERIC = -1,
+ ERROR_WOULD_OVERRUN = -2,
+ ERROR_WOULD_UNDERRUN = -3,
+ ERROR_INVALID_ARGUMENTS = -4,
+
+
+ ERROR_PLATFORM_GENERIC = -10000,
+ ERROR_PLATFORM_MAPPING_FAILED = -10001,
+ ERROR_PLATFORM_MEMORY_PERMISSION_CHANGE_FAILED = -10002,
+ ERROR_PLATFORM_MEMORY_HINT_CHANGE_FAILED = -10003,
+ ERROR_PLATFORM_FILE_OPEN_FAILED = -10004,
+ ERROR_PLATFORM_FILE_CLOSE_FAILED = -10005,
+ ERROR_PLATFORM_FILE_READ_FAILED = -10006,
+ ERROR_PLATFORM_FILE_WRITE_FAILED = -10007,
};