diff --git a/io/include/blue/io/file.h b/io/include/blue/io/file.h index 70fc4d9..4187cbe 100644 --- a/io/include/blue/io/file.h +++ b/io/include/blue/io/file.h @@ -3,6 +3,7 @@ #include #include +#include #include #define B_FILE(p) ((b_file *)(p)) @@ -55,6 +56,7 @@ BLUE_API b_status b_file_open_temp(b_file_mode mode, b_file **out); BLUE_API b_status b_file_open_shadow( b_file *original, b_file_mode mode, b_file **out); +BLUE_API b_status b_file_open_stream(b_file *file, b_stream **out); BLUE_API b_status b_file_stat(b_file *file, b_file_info *out); BLUE_API b_status b_file_size(b_file *file, size_t *out_len); BLUE_API b_status b_file_cursor(b_file *file, size_t *out_pos); diff --git a/io/sys/darwin/file.c b/io/sys/darwin/file.c index 6073b05..35ed94b 100644 --- a/io/sys/darwin/file.c +++ b/io/sys/darwin/file.c @@ -8,6 +8,8 @@ #include #include #include +#include +#include #include #include @@ -28,29 +30,31 @@ static struct b_object_type file_type = { .t_release = file_release, }; +#define CHECK_FLAG(v, f) (((v) & (f)) == (f)) + static unsigned int b_mode_to_unix_mode(enum b_file_mode mode) { unsigned int result = 0; - if (mode & B_FILE_READ_WRITE) { + if (CHECK_FLAG(mode, B_FILE_READ_WRITE)) { result |= O_RDWR; - } else if (mode & B_FILE_READ_ONLY) { + } else if (CHECK_FLAG(mode, B_FILE_READ_ONLY)) { result |= O_RDONLY; - } else if (mode & B_FILE_WRITE_ONLY) { + } else if (CHECK_FLAG(mode, B_FILE_WRITE_ONLY)) { result |= O_WRONLY; } else { - return 0; + return (unsigned int)-1; } - if (mode & B_FILE_TRUNCATE) { + if (CHECK_FLAG(mode, B_FILE_TRUNCATE)) { result |= O_TRUNC; } - if (mode & B_FILE_CREATE) { + if (CHECK_FLAG(mode, B_FILE_CREATE)) { result |= O_CREAT; } - if ((mode & B_FILE_CREATE_ONLY) == B_FILE_CREATE_ONLY) { + if (CHECK_FLAG(mode, B_FILE_CREATE_ONLY)) { result |= O_EXCL; } @@ -64,7 +68,7 @@ enum b_status b_file_open( struct b_path *file_path = b_path_retain((struct b_path *)path); unsigned int flags = b_mode_to_unix_mode(mode); - if (flags == 0) { + if (flags == (unsigned int)-1) { b_path_release(file_path); return B_ERR_INVALID_ARGUMENT; } @@ -202,6 +206,123 @@ enum b_status b_file_open_shadow( return B_SUCCESS; } +enum b_status stream_close(struct b_stream *stream) +{ + struct b_file *file = stream->s_ptr; + b_file_release(file); + + return B_SUCCESS; +} + +enum b_status stream_getc(struct b_stream *stream, int *out) +{ + struct b_file *file = stream->s_ptr; + char c; + size_t nr_read = 0; + + enum b_status status + = b_file_read(file, stream->s_cursor, sizeof c, &c, &nr_read); + if (status != B_SUCCESS) { + return status; + } + + if (nr_read == 0) { + return B_ERR_NO_DATA; + } + + stream->s_cursor += nr_read; + *out = c; + return B_SUCCESS; +} + +enum b_status stream_read( + struct b_stream *stream, unsigned char *buf, size_t max, size_t *nr_read) +{ + struct b_file *file = stream->s_ptr; + + enum b_status status + = b_file_read(file, stream->s_cursor, max, buf, nr_read); + + stream->s_cursor += *nr_read; + + return status; +} + +enum b_status stream_write( + struct b_stream *stream, const unsigned char *buf, size_t count, + size_t *nr_written) +{ + struct b_file *file = stream->s_ptr; + + enum b_status status + = b_file_write(file, stream->s_cursor, count, buf, nr_written); + + stream->s_cursor += *nr_written; + + return status; +} + +enum b_status stream_seek( + struct b_stream *stream, long long offset, b_stream_seek_origin origin) +{ + b_seek_basis basis; + switch (origin) { + case B_STREAM_SEEK_START: + basis = B_SEEK_BEGINNING; + break; + case B_STREAM_SEEK_CURRENT: + basis = B_SEEK_CURRENT; + break; + case B_STREAM_SEEK_END: + basis = B_SEEK_END; + break; + default: + return B_ERR_INVALID_ARGUMENT; + } + + struct b_file *file = stream->s_ptr; + + enum b_status status = b_file_seek(file, offset, basis); + if (!B_OK(status)) { + return status; + } + + return b_file_cursor(file, &stream->s_cursor); +} + +enum b_status b_file_open_stream(struct b_file *file, struct b_stream **out) +{ + struct b_stream *stream = malloc(sizeof *stream); + if (!stream) { + return B_ERR_NO_MEMORY; + } + + memset(stream, 0x0, sizeof *stream); + + if (file->mode & B_FILE_READ_ONLY) { + stream->s_mode |= B_STREAM_READ; + } + + if (file->mode & B_FILE_WRITE_ONLY) { + stream->s_mode |= B_STREAM_WRITE; + } + + if (file->mode & B_FILE_BINARY) { + stream->s_mode |= B_STREAM_BINARY; + } + + stream->s_ptr = b_file_retain(file); + stream->s_close = stream_close; + stream->s_getc = stream_getc; + stream->s_read = stream_read; + stream->s_write = stream_write; + stream->s_seek = stream_seek; + + *out = stream; + + return B_SUCCESS; +} + enum b_status b_file_stat(struct b_file *file, struct b_file_info *out) { struct stat st;