Compare commits

4 Commits

Author SHA1 Message Date
b372447a46 Implement Windows file IO 2026-01-03 03:15:25 +00:00
fac9cb57eb Update windows include 2026-01-03 03:15:03 +00:00
abad2fa02a Add padding to stack array 2026-01-03 03:14:53 +00:00
576699996f Update POSIX file IO 2026-01-03 03:13:42 +00:00
12 changed files with 397 additions and 204 deletions

View File

@@ -45,123 +45,126 @@ typedef iptr *IptrArray;
typedef Str8 *Str8Array; typedef Str8 *Str8Array;
#ifdef WAPP_PLATFORM_CPP #ifdef WAPP_PLATFORM_CPP
#define wapp_array(TYPE, ...) ([&]() { \ #define wapp_array(TYPE, ...) ([&]() { \
u64 capacity = _calc_array_capacity(TYPE, __VA_ARGS__); \ u64 capacity = _calc_array_capacity(TYPE, __VA_ARGS__); \
\ \
TYPE items[_calc_array_capacity(TYPE, __VA_ARGS__)] = {__VA_ARGS__}; \ TYPE items[_calc_array_capacity(TYPE, __VA_ARGS__)] = {__VA_ARGS__}; \
\ \
wapp_persist u8 array[ \ wapp_persist u8 array[ \
sizeof(ArrayHeader) + _calc_array_capacity(TYPE, __VA_ARGS__) * sizeof(TYPE) \ sizeof(ArrayHeader) + _calc_array_capacity(TYPE, __VA_ARGS__) * sizeof(TYPE) \
] = {0}; \ ] = {0}; \
ArrayHeader *header = (ArrayHeader *)array; \ ArrayHeader *header = (ArrayHeader *)array; \
header->magic = WAPP_ARRAY_MAGIC; \ header->magic = WAPP_ARRAY_MAGIC; \
header->count = _calc_array_count(TYPE, __VA_ARGS__); \ header->count = _calc_array_count(TYPE, __VA_ARGS__); \
header->capacity = _calc_array_capacity(TYPE, __VA_ARGS__); \ header->capacity = _calc_array_capacity(TYPE, __VA_ARGS__); \
header->item_size = sizeof(TYPE); \ header->item_size = sizeof(TYPE); \
\ \
u8 *buf = (u8 *)(header + 1); \ u8 *buf = (u8 *)(header + 1); \
memcpy(buf, items, capacity * sizeof(TYPE)); \ memcpy(buf, items, capacity * sizeof(TYPE)); \
return (TYPE *)buf; \ return (TYPE *)buf; \
}()) }())
#define wapp_array_with_capacity(TYPE, CAPACITY, FILL) ([&]() { \ #define wapp_array_with_capacity(TYPE, CAPACITY, FILL) ([&]() { \
wapp_persist u8 array[ \ wapp_persist u8 array[ \
sizeof(ArrayHeader) + CAPACITY * sizeof(TYPE) \ sizeof(ArrayHeader) + CAPACITY * sizeof(TYPE) \
] = {0}; \ ] = {0}; \
ArrayHeader *header = (ArrayHeader *)array; \ ArrayHeader *header = (ArrayHeader *)array; \
header->magic = WAPP_ARRAY_MAGIC; \ header->magic = WAPP_ARRAY_MAGIC; \
header->count = FILL ? CAPACITY : 0; \ header->count = FILL ? CAPACITY : 0; \
header->capacity = CAPACITY; \ header->capacity = CAPACITY; \
header->item_size = sizeof(TYPE); \ header->item_size = sizeof(TYPE); \
\ \
return (TYPE *)(header + 1); \ return (TYPE *)(header + 1); \
}()) }())
#define wapp_array_pop(TYPE, ARRAY) ([&]() { \ #define wapp_array_pop(TYPE, ARRAY) ([&]() { \
if (ARRAY == NULL || _array_count((GenericArray)ARRAY) == 0) { \ if (ARRAY == NULL || _array_count((GenericArray)ARRAY) == 0) { \
TYPE result{}; \ TYPE result{}; \
return result; \ return result; \
} \ } \
\ \
return *((TYPE *)_array_pop((GenericArray)ARRAY, sizeof(TYPE))); \ return *((TYPE *)_array_pop((GenericArray)ARRAY, sizeof(TYPE))); \
}()) }())
#else #else
#define _stack_array(TYPE, SIZE) struct { ArrayHeader header; TYPE items[SIZE]; } #define _stack_array(TYPE, SIZE) struct {ArrayHeader header; \
#define wapp_array(TYPE, ...) \ TYPE items[SIZE]; \
(TYPE *)( \ wapp_misc_utils_padding_size(sizeof(ArrayHeader) + \
(_stack_array(TYPE, _calc_array_capacity(TYPE, __VA_ARGS__))){ \ sizeof(TYPE) * SIZE);}
.header = { \ #define wapp_array(TYPE, ...) \
.magic = WAPP_ARRAY_MAGIC, \ (TYPE *)( \
.count = _calc_array_count(TYPE, __VA_ARGS__), \ (_stack_array(TYPE, _calc_array_capacity(TYPE, __VA_ARGS__))){ \
.capacity = _calc_array_capacity(TYPE, __VA_ARGS__), \ .header = { \
.item_size = sizeof(TYPE), \ .magic = WAPP_ARRAY_MAGIC, \
}, \ .count = _calc_array_count(TYPE, __VA_ARGS__), \
.items = {__VA_ARGS__}, \ .capacity = _calc_array_capacity(TYPE, __VA_ARGS__), \
}.items \ .item_size = sizeof(TYPE), \
}, \
.items = {__VA_ARGS__}, \
}.items \
) )
#define wapp_array_with_capacity(TYPE, CAPACITY, FILL) \ #define wapp_array_with_capacity(TYPE, CAPACITY, FILL) \
(TYPE *)( \ (TYPE *)( \
(_stack_array(TYPE, CAPACITY)){ \ (_stack_array(TYPE, CAPACITY)){ \
.header = { \ .header = { \
.magic = WAPP_ARRAY_MAGIC, \ .magic = WAPP_ARRAY_MAGIC, \
.count = FILL ? CAPACITY : 0, \ .count = FILL ? CAPACITY : 0, \
.capacity = CAPACITY, \ .capacity = CAPACITY, \
.item_size = sizeof(TYPE), \ .item_size = sizeof(TYPE), \
}, \ }, \
.items = {0}, \ .items = {0}, \
}.items \ }.items \
) )
#define wapp_array_pop(TYPE, ARRAY) \ #define wapp_array_pop(TYPE, ARRAY) \
(ARRAY == NULL || _array_count((GenericArray)ARRAY) == 0 ? \ (ARRAY == NULL || _array_count((GenericArray)ARRAY) == 0 ? \
(TYPE){0} : \ (TYPE){0} : \
*((TYPE *)_array_pop((GenericArray)ARRAY, sizeof(TYPE))) \ *((TYPE *)_array_pop((GenericArray)ARRAY, sizeof(TYPE))) \
) )
#endif // !WAPP_PLATFORM_CPP #endif // !WAPP_PLATFORM_CPP
#define wapp_array_count(ARRAY) \ #define wapp_array_count(ARRAY) \
_array_count((GenericArray)ARRAY) _array_count((GenericArray)ARRAY)
#define wapp_array_capacity(ARRAY) \ #define wapp_array_capacity(ARRAY) \
_array_capacity((GenericArray)ARRAY) _array_capacity((GenericArray)ARRAY)
#define wapp_array_item_size(ARRAY) \ #define wapp_array_item_size(ARRAY) \
_array_item_size((GenericArray)ARRAY) _array_item_size((GenericArray)ARRAY)
#define wapp_array_set_count(ARRAY, COUNT) \ #define wapp_array_set_count(ARRAY, COUNT) \
_array_set_count((GenericArray)ARRAY, COUNT) _array_set_count((GenericArray)ARRAY, COUNT)
#define wapp_array_get(TYPE, ARRAY, INDEX) \ #define wapp_array_get(TYPE, ARRAY, INDEX) \
((TYPE *)_array_get((GenericArray)ARRAY, \ ((TYPE *)_array_get((GenericArray)ARRAY, \
INDEX, \ INDEX, \
sizeof(TYPE))) sizeof(TYPE)))
#define wapp_array_set(TYPE, ARRAY, INDEX, VALUE_PTR) \ #define wapp_array_set(TYPE, ARRAY, INDEX, VALUE_PTR) \
_array_set((GenericArray)ARRAY, \ _array_set((GenericArray)ARRAY, \
INDEX, \ INDEX, \
(u8 *)VALUE_PTR, \ (u8 *)VALUE_PTR, \
sizeof(TYPE)) sizeof(TYPE))
#define wapp_array_append_capped(TYPE, ARRAY, VALUE_PTR) \ #define wapp_array_append_capped(TYPE, ARRAY, VALUE_PTR) \
_array_append_capped((GenericArray)ARRAY, \ _array_append_capped((GenericArray)ARRAY, \
(u8 *)VALUE_PTR, \ (u8 *)VALUE_PTR, \
sizeof(TYPE)) sizeof(TYPE))
#define wapp_array_extend_capped(TYPE, DST_ARRAY, SRC_ARRAY) \ #define wapp_array_extend_capped(TYPE, DST_ARRAY, SRC_ARRAY) \
_array_extend_capped((GenericArray)DST_ARRAY, \ _array_extend_capped((GenericArray)DST_ARRAY, \
(GenericArray)SRC_ARRAY, \ (GenericArray)SRC_ARRAY, \
sizeof(TYPE)) sizeof(TYPE))
#define wapp_array_copy_capped(TYPE, DST_ARRAY, SRC_ARRAY) \ #define wapp_array_copy_capped(TYPE, DST_ARRAY, SRC_ARRAY) \
_array_copy_capped((GenericArray)DST_ARRAY, \ _array_copy_capped((GenericArray)DST_ARRAY, \
(GenericArray)SRC_ARRAY, \ (GenericArray)SRC_ARRAY, \
sizeof(TYPE)) sizeof(TYPE))
#define wapp_array_append_alloc(TYPE, ALLOCATOR_PTR, ARRAY, VALUE_PTR) \ #define wapp_array_append_alloc(TYPE, ALLOCATOR_PTR, ARRAY, VALUE_PTR) \
(TYPE *)_array_append_alloc(ALLOCATOR_PTR, \ (TYPE *)_array_append_alloc(ALLOCATOR_PTR, \
(GenericArray)ARRAY, \ (GenericArray)ARRAY, \
(u8 *)VALUE_PTR, \ (u8 *)VALUE_PTR, \
sizeof(TYPE)) sizeof(TYPE))
#define wapp_array_extend_alloc(TYPE, ALLOCATOR_PTR, DST_ARRAY, SRC_ARRAY) \ #define wapp_array_extend_alloc(TYPE, ALLOCATOR_PTR, DST_ARRAY, SRC_ARRAY) \
(TYPE *)_array_extend_alloc(ALLOCATOR_PTR, \ (TYPE *)_array_extend_alloc(ALLOCATOR_PTR, \
(GenericArray)DST_ARRAY, \ (GenericArray)DST_ARRAY, \
(GenericArray)SRC_ARRAY, \ (GenericArray)SRC_ARRAY, \
sizeof(TYPE)) sizeof(TYPE))
#define wapp_array_copy_alloc(TYPE, ALLOCATOR_PTR, DST_ARRAY, SRC_ARRAY) \ #define wapp_array_copy_alloc(TYPE, ALLOCATOR_PTR, DST_ARRAY, SRC_ARRAY) \
(TYPE *)_array_copy_alloc(ALLOCATOR_PTR, \ (TYPE *)_array_copy_alloc(ALLOCATOR_PTR, \
(GenericArray)DST_ARRAY, \ (GenericArray)DST_ARRAY, \
(GenericArray)SRC_ARRAY, \ (GenericArray)SRC_ARRAY, \
sizeof(TYPE)) sizeof(TYPE))
#define wapp_array_clear(TYPE, ARRAY) \ #define wapp_array_clear(TYPE, ARRAY) \
_array_clear((GenericArray)ARRAY, \ _array_clear((GenericArray)ARRAY, \
sizeof(TYPE)) sizeof(TYPE))
typedef struct header ArrayHeader; typedef struct header ArrayHeader;

View File

@@ -18,7 +18,7 @@ BEGIN_C_LINKAGE
#define WAPP_PATH_MAX PATH_MAX #define WAPP_PATH_MAX PATH_MAX
#elif defined(WAPP_PLATFORM_WINDOWS) #elif defined(WAPP_PLATFORM_WINDOWS)
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#include <windows.h> #include <Windows.h>
#define WAPP_PATH_SEP '\\' #define WAPP_PATH_SEP '\\'
#define WAPP_PATH_MAX MAX_PATH #define WAPP_PATH_MAX MAX_PATH
#else #else

View File

@@ -15,7 +15,7 @@ WFile *wapp_file_open(const Allocator *allocator, Str8RO *filepath, FileAccessMo
i64 wapp_file_get_current_position(WFile *file) { i64 wapp_file_get_current_position(WFile *file) {
wapp_debug_assert(file != NULL, "`file` should not be NULL."); wapp_debug_assert(file != NULL, "`file` should not be NULL.");
return _file_get_current_position(file); return _file_seek(file, 0, WAPP_SEEK_CURRENT);
} }
i64 wapp_file_seek(WFile *file, i64 offset, FileSeekOrigin origin) { i64 wapp_file_seek(WFile *file, i64 offset, FileSeekOrigin origin) {
@@ -25,13 +25,29 @@ i64 wapp_file_seek(WFile *file, i64 offset, FileSeekOrigin origin) {
i64 wapp_file_get_length(WFile *file) { i64 wapp_file_get_length(WFile *file) {
wapp_debug_assert(file != NULL, "`file` should not be NULL."); wapp_debug_assert(file != NULL, "`file` should not be NULL.");
return _file_get_length(file);
i64 current = wapp_file_get_current_position(file);
_file_seek(file, 0, WAPP_SEEK_END);
i64 output = wapp_file_get_current_position(file);
// Restore position
_file_seek(file, current, WAPP_SEEK_START);
return output;
} }
u64 wapp_file_read(void *dst_buf, WFile *file, u64 byte_count) { u64 wapp_file_read(void *dst_buf, WFile *file, u64 byte_count) {
wapp_debug_assert(dst_buf != NULL && file != NULL, wapp_debug_assert(dst_buf != NULL && file != NULL,
"`dst_buf` and `file` should not be NULL."); "`dst_buf` and `file` should not be NULL.");
return _file_read(dst_buf, file, byte_count);
i64 file_length = wapp_file_get_length(file);
if (file_length < 0) {
return 0;
}
return _file_read(dst_buf, byte_count, file, file_length);
} }
i64 wapp_file_write(const void *src_buf, WFile *file, u64 byte_count) { i64 wapp_file_write(const void *src_buf, WFile *file, u64 byte_count) {
@@ -43,13 +59,49 @@ i64 wapp_file_write(const void *src_buf, WFile *file, u64 byte_count) {
u64 wapp_file_read_array(GenericArray dst_buf, WFile *file, u64 item_count) { u64 wapp_file_read_array(GenericArray dst_buf, WFile *file, u64 item_count) {
wapp_debug_assert(dst_buf != NULL && file != NULL, wapp_debug_assert(dst_buf != NULL && file != NULL,
"`dst_buf` and `file` should not be NULL."); "`dst_buf` and `file` should not be NULL.");
return _file_read_array(dst_buf, file, item_count);
i64 _file_length = wapp_file_get_length(file);
if (_file_length < 0) {
return 0;
}
u64 file_length = (u64)_file_length;
u64 item_size = wapp_array_item_size(dst_buf);
u64 dst_byte_capacity = wapp_array_capacity(dst_buf) * item_size;
u64 req_byte_count = item_count * item_size;
u64 copy_byte_count = 0;
if (req_byte_count <= file_length && req_byte_count <= dst_byte_capacity) {
copy_byte_count = req_byte_count;
} else {
copy_byte_count = file_length <= dst_byte_capacity ? file_length : dst_byte_capacity;
}
u64 byte_count = _file_read(dst_buf, copy_byte_count, file, file_length);
if (byte_count == 0) {
return 0;
}
wapp_array_set_count(dst_buf, byte_count / item_size);
return wapp_array_count(dst_buf);
} }
i64 wapp_file_write_array(const GenericArray src_buf, WFile *file, u64 item_count) { i64 wapp_file_write_array(const GenericArray src_buf, WFile *file, u64 item_count) {
wapp_debug_assert(src_buf != NULL && file != NULL, wapp_debug_assert(src_buf != NULL && file != NULL,
"`src_buf` and `file` should not be NULL."); "`src_buf` and `file` should not be NULL.");
return _file_write_array(src_buf, file, item_count);
u64 item_size = wapp_array_item_size(src_buf);
u64 src_byte_count = wapp_array_count(src_buf) * item_size;
u64 req_byte_count = item_count * item_size;
u64 to_copy = req_byte_count <= src_byte_count ? req_byte_count : src_byte_count;
i64 bytes_written = _file_write(src_buf, file, to_copy);
if (bytes_written < 0) {
return 0;
}
return (u64)bytes_written / item_size;
} }
i32 wapp_file_flush(WFile *file) { i32 wapp_file_flush(WFile *file) {

View File

@@ -20,16 +20,8 @@ typedef enum {
WAPP_ACCESS_READ_EX, // Equivalent to r+ WAPP_ACCESS_READ_EX, // Equivalent to r+
WAPP_ACCESS_WRITE_EX, // Equivalent to w+ WAPP_ACCESS_WRITE_EX, // Equivalent to w+
WAPP_ACCESS_APPEND_EX, // Equivalent to a+ WAPP_ACCESS_APPEND_EX, // Equivalent to a+
WAPP_ACCESS_READ_BIN, // Equivalent to rb
WAPP_ACCESS_WRITE_BIN, // Equivalent to wb
WAPP_ACCESS_APPEND_BIN, // Equivalent to ab
WAPP_ACCESS_READ_BIN_EX, // Equivalent to rb+
WAPP_ACCESS_WRITE_BIN_EX, // Equivalent to wb+
WAPP_ACCESS_APPEND_BIN_EX, // Equivalent to ab+
WAPP_ACCESS_WRITE_FAIL_ON_EXIST, // Equivalent to wx WAPP_ACCESS_WRITE_FAIL_ON_EXIST, // Equivalent to wx
WAPP_ACCESS_WRITE_FAIL_ON_EXIST_EX, // Equivalent to wx+ WAPP_ACCESS_WRITE_FAIL_ON_EXIST_EX, // Equivalent to wx+
WAPP_ACCESS_WRITE_BIN_FAIL_ON_EXIST, // Equivalent to wbx
WAPP_ACCESS_WRITE_BIN_FAIL_ON_EXIST_EX, // Equivalent to wbx+
FILE_ACCESS_MODE_COUNT, FILE_ACCESS_MODE_COUNT,
} FileAccessMode; } FileAccessMode;
@@ -56,13 +48,9 @@ i32 wapp_file_rename(Str8RO *old_filepath, Str8RO *new_filepath);
i32 wapp_file_remove(Str8RO *filepath); i32 wapp_file_remove(Str8RO *filepath);
extern WFile *_file_open(const Allocator *allocator, Str8RO *filepath, FileAccessMode mode); extern WFile *_file_open(const Allocator *allocator, Str8RO *filepath, FileAccessMode mode);
extern i64 _file_get_current_position(WFile *file);
extern i64 _file_seek(WFile *file, i64 offset, FileSeekOrigin origin); extern i64 _file_seek(WFile *file, i64 offset, FileSeekOrigin origin);
extern i64 _file_get_length(WFile *file); extern u64 _file_read(void *dst_buf, u64 byte_count, WFile *file, u64 file_length);
extern u64 _file_read(void *dst_buf, WFile *file, u64 byte_count);
extern i64 _file_write(const void *src_buf, WFile *file, u64 byte_count); extern i64 _file_write(const void *src_buf, WFile *file, u64 byte_count);
extern u64 _file_read_array(GenericArray dst_buf, WFile *file, u64 item_count);
extern i64 _file_write_array(const GenericArray src_buf, WFile *file, u64 item_count);
extern i32 _file_flush(WFile *file); extern i32 _file_flush(WFile *file);
extern i32 _file_close(WFile *file); extern i32 _file_close(WFile *file);
extern i32 _file_rename(Str8RO *old_filepath, Str8RO *new_filepath); extern i32 _file_rename(Str8RO *old_filepath, Str8RO *new_filepath);

View File

@@ -21,16 +21,8 @@ wapp_intern i32 file_flags[FILE_ACCESS_MODE_COUNT] = {
[WAPP_ACCESS_READ_EX] = O_RDWR, [WAPP_ACCESS_READ_EX] = O_RDWR,
[WAPP_ACCESS_WRITE_EX] = O_RDWR | O_CREAT, [WAPP_ACCESS_WRITE_EX] = O_RDWR | O_CREAT,
[WAPP_ACCESS_APPEND_EX] = O_RDWR | O_APPEND | O_CREAT, [WAPP_ACCESS_APPEND_EX] = O_RDWR | O_APPEND | O_CREAT,
[WAPP_ACCESS_READ_BIN] = O_RDONLY,
[WAPP_ACCESS_WRITE_BIN] = O_WRONLY | O_CREAT,
[WAPP_ACCESS_APPEND_BIN] = O_WRONLY | O_APPEND | O_CREAT,
[WAPP_ACCESS_READ_BIN_EX] = O_RDWR,
[WAPP_ACCESS_WRITE_BIN_EX] = O_RDWR | O_CREAT,
[WAPP_ACCESS_APPEND_BIN_EX] = O_RDWR | O_APPEND | O_CREAT,
[WAPP_ACCESS_WRITE_FAIL_ON_EXIST] = O_WRONLY | O_CREAT | O_EXCL, [WAPP_ACCESS_WRITE_FAIL_ON_EXIST] = O_WRONLY | O_CREAT | O_EXCL,
[WAPP_ACCESS_WRITE_FAIL_ON_EXIST_EX] = O_RDWR | O_CREAT | O_EXCL, [WAPP_ACCESS_WRITE_FAIL_ON_EXIST_EX] = O_RDWR | O_CREAT | O_EXCL,
[WAPP_ACCESS_WRITE_BIN_FAIL_ON_EXIST] = O_WRONLY | O_CREAT | O_EXCL,
[WAPP_ACCESS_WRITE_BIN_FAIL_ON_EXIST_EX] = O_RDWR | O_CREAT | O_EXCL,
}; };
wapp_intern mode_t file_modes[FILE_ACCESS_MODE_COUNT] = { wapp_intern mode_t file_modes[FILE_ACCESS_MODE_COUNT] = {
@@ -40,16 +32,8 @@ wapp_intern mode_t file_modes[FILE_ACCESS_MODE_COUNT] = {
[WAPP_ACCESS_READ_EX] = 0, [WAPP_ACCESS_READ_EX] = 0,
[WAPP_ACCESS_WRITE_EX] = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, [WAPP_ACCESS_WRITE_EX] = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
[WAPP_ACCESS_APPEND_EX] = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, [WAPP_ACCESS_APPEND_EX] = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
[WAPP_ACCESS_READ_BIN] = 0,
[WAPP_ACCESS_WRITE_BIN] = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
[WAPP_ACCESS_APPEND_BIN] = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
[WAPP_ACCESS_READ_BIN_EX] = 0,
[WAPP_ACCESS_WRITE_BIN_EX] = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
[WAPP_ACCESS_APPEND_BIN_EX] = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
[WAPP_ACCESS_WRITE_FAIL_ON_EXIST] = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, [WAPP_ACCESS_WRITE_FAIL_ON_EXIST] = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
[WAPP_ACCESS_WRITE_FAIL_ON_EXIST_EX] = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, [WAPP_ACCESS_WRITE_FAIL_ON_EXIST_EX] = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
[WAPP_ACCESS_WRITE_BIN_FAIL_ON_EXIST] = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
[WAPP_ACCESS_WRITE_BIN_FAIL_ON_EXIST_EX] = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
}; };
wapp_intern i32 file_seek_origins[FILE_SEEK_ORIGIN_COUNT] = { wapp_intern i32 file_seek_origins[FILE_SEEK_ORIGIN_COUNT] = {
@@ -76,29 +60,11 @@ WFile *_file_open(const Allocator *allocator, Str8RO *filepath, FileAccessMode m
return output; return output;
} }
i64 _file_get_current_position(WFile *file) {
return lseek64(file->fd, 0, WAPP_SEEK_CURRENT);
}
i64 _file_seek(WFile *file, i64 offset, FileSeekOrigin origin) { i64 _file_seek(WFile *file, i64 offset, FileSeekOrigin origin) {
return lseek64(file->fd, offset, file_seek_origins[origin]); return lseek64(file->fd, offset, file_seek_origins[origin]);
} }
i64 _file_get_length(WFile *file) { u64 _file_read(void *dst_buf, u64 byte_count, WFile *file, u64 file_length) {
i64 current = _file_get_current_position(file);
_file_seek(file, 0, WAPP_SEEK_END);
i64 output = _file_get_current_position(file);
// Restore position
_file_seek(file, current, WAPP_SEEK_START);
return output;
}
u64 _file_read(void *dst_buf, WFile *file, u64 byte_count) {
u64 file_length = _file_get_length(file);
u64 copy_byte_count = file_length <= byte_count ? file_length : byte_count; u64 copy_byte_count = file_length <= byte_count ? file_length : byte_count;
i64 count = read(file->fd, dst_buf, copy_byte_count); i64 count = read(file->fd, dst_buf, copy_byte_count);
@@ -111,40 +77,6 @@ i64 _file_write(const void *src_buf, WFile *file, u64 byte_count) {
return write(file->fd, src_buf, byte_count); return write(file->fd, src_buf, byte_count);
} }
u64 _file_read_array(GenericArray dst_buf, WFile *file, u64 item_count) {
u64 file_length = _file_get_length(file);
u64 item_size = wapp_array_item_size(dst_buf);
u64 dst_byte_capacity = wapp_array_capacity(dst_buf) * item_size;
u64 req_byte_count = item_count * item_size;
u64 copy_byte_count = 0;
if (req_byte_count <= file_length && req_byte_count <= dst_byte_capacity) {
copy_byte_count = req_byte_count;
} else {
copy_byte_count = file_length <= dst_byte_capacity ? file_length : dst_byte_capacity;
}
u64 byte_count = _file_read(dst_buf, file, copy_byte_count);
if (byte_count == 0) {
return 0;
}
wapp_array_set_count(dst_buf, byte_count / item_size);
return wapp_array_count(dst_buf);
}
i64 _file_write_array(const GenericArray src_buf, WFile *file, u64 item_count) {
u64 item_size = wapp_array_item_size(src_buf);
u64 src_byte_count = wapp_array_count(src_buf) * item_size;
u64 req_byte_count = item_count * item_size;
u64 to_copy = req_byte_count <= src_byte_count ? req_byte_count : src_byte_count;
u64 byte_count = _file_write(src_buf, file, to_copy);
return byte_count / item_size;
}
i32 _file_flush(WFile *file) { i32 _file_flush(WFile *file) {
return fsync(file->fd); return fsync(file->fd);
} }

View File

@@ -12,6 +12,8 @@ BEGIN_C_LINKAGE
#ifdef WAPP_PLATFORM_POSIX #ifdef WAPP_PLATFORM_POSIX
#define END_OF_LINE "\n"
struct WFile { struct WFile {
i32 fd; i32 fd;
}; };

159
src/os/file/win/file_win.c Normal file
View File

@@ -0,0 +1,159 @@
// vim:fileencoding=utf-8:foldmethod=marker
#include "file_win.h"
#include "../../../common/platform/platform.h"
#ifdef WAPP_PLATFORM_WINDOWS
#include "../file.h"
#include "../../cpath/cpath.h"
#include "../../../common/aliases/aliases.h"
#include "../../../base/array/array.h"
#include "../../../base/strings/str8/str8.h"
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <fileapi.h>
#include <intsafe.h>
wapp_intern DWORD file_accesses[FILE_ACCESS_MODE_COUNT] = {
[WAPP_ACCESS_READ] = FILE_READ_DATA,
[WAPP_ACCESS_WRITE] = FILE_WRITE_DATA,
[WAPP_ACCESS_APPEND] = FILE_APPEND_DATA,
[WAPP_ACCESS_READ_EX] = FILE_READ_DATA | FILE_WRITE_DATA,
[WAPP_ACCESS_WRITE_EX] = FILE_READ_DATA | FILE_WRITE_DATA,
[WAPP_ACCESS_APPEND_EX] = FILE_READ_DATA | FILE_APPEND_DATA,
[WAPP_ACCESS_WRITE_FAIL_ON_EXIST] = FILE_WRITE_DATA,
[WAPP_ACCESS_WRITE_FAIL_ON_EXIST_EX] = FILE_READ_DATA | FILE_WRITE_DATA,
};
wapp_intern DWORD creation_dispositions[FILE_ACCESS_MODE_COUNT] = {
[WAPP_ACCESS_READ] = OPEN_EXISTING,
[WAPP_ACCESS_WRITE] = CREATE_ALWAYS,
[WAPP_ACCESS_APPEND] = OPEN_ALWAYS,
[WAPP_ACCESS_READ_EX] = OPEN_EXISTING,
[WAPP_ACCESS_WRITE_EX] = CREATE_ALWAYS,
[WAPP_ACCESS_APPEND_EX] = OPEN_ALWAYS,
[WAPP_ACCESS_WRITE_FAIL_ON_EXIST] = CREATE_NEW,
[WAPP_ACCESS_WRITE_FAIL_ON_EXIST_EX] = CREATE_NEW,
};
wapp_intern DWORD sharing_modes[FILE_ACCESS_MODE_COUNT] = {
[WAPP_ACCESS_READ] = FILE_SHARE_READ | FILE_SHARE_WRITE,
[WAPP_ACCESS_WRITE] = FILE_SHARE_READ,
[WAPP_ACCESS_APPEND] = FILE_SHARE_READ,
[WAPP_ACCESS_READ_EX] = FILE_SHARE_READ | FILE_SHARE_WRITE,
[WAPP_ACCESS_WRITE_EX] = FILE_SHARE_READ,
[WAPP_ACCESS_APPEND_EX] = FILE_SHARE_READ,
[WAPP_ACCESS_WRITE_FAIL_ON_EXIST] = FILE_SHARE_READ,
[WAPP_ACCESS_WRITE_FAIL_ON_EXIST_EX] = FILE_SHARE_READ,
};
wapp_intern DWORD file_seek_origins[FILE_SEEK_ORIGIN_COUNT] = {
[WAPP_SEEK_START] = FILE_BEGIN,
[WAPP_SEEK_CURRENT] = FILE_CURRENT,
[WAPP_SEEK_END] = FILE_END,
};
WFile *_file_open(const Allocator *allocator, Str8RO *filepath, FileAccessMode mode) {
wapp_persist c8 tmp[WAPP_PATH_MAX] = {0};
memset(tmp, 0, WAPP_PATH_MAX);
memcpy(tmp, filepath->buf, filepath->size);
HANDLE fh = CreateFileA((LPCSTR)tmp,
file_accesses[mode],
sharing_modes[mode],
NULL,
creation_dispositions[mode],
FILE_ATTRIBUTE_NORMAL,
NULL);
if (fh == INVALID_HANDLE_VALUE) {
return NULL;
}
WFile *output = wapp_mem_allocator_alloc(allocator, sizeof(WFile));
if (output) {
output->fh = fh;
}
return output;
}
i64 _file_seek(WFile *file, i64 offset, FileSeekOrigin origin) {
LARGE_INTEGER distance = {0};
LARGE_INTEGER output = {0};
distance.QuadPart = offset;
if (!SetFilePointerEx(file->fh, distance, &output, file_seek_origins[origin])) {
return -1;
}
return output.QuadPart;
}
u64 _file_read(void* dst_buf, u64 byte_count, WFile* file, u64 file_length) {
u64 copy_byte_count = file_length <= byte_count ? file_length : byte_count;
wapp_debug_assert(copy_byte_count <= DWORD_MAX, "Attempting to read large number of bytes at once");
DWORD read_count = 0;
if (!ReadFile(file->fh, dst_buf, (DWORD)copy_byte_count, &read_count, NULL)) {
return 0;
}
return (u64)read_count;
}
i64 _file_write(const void *src_buf, WFile *file, u64 byte_count) {
wapp_debug_assert(byte_count <= DWORD_MAX, "Attempting to write large number of bytes at once");
DWORD write_count = 0;
if (!WriteFile(file->fh, src_buf, (DWORD)byte_count, &write_count, NULL)) {
return 0;
}
return (i64)write_count;
}
i32 _file_flush(WFile *file) {
if (!FlushFileBuffers(file->fh)) {
return -1;
}
return 0;
}
i32 _file_close(WFile *file) {
if (!CloseHandle(file->fh)) {
return -1;
}
return 0;
}
i32 _file_rename(Str8RO *old_filepath, Str8RO *new_filepath) {
wapp_persist c8 old_tmp[WAPP_PATH_MAX] = {0};
wapp_persist c8 new_tmp[WAPP_PATH_MAX] = {0};
memset(old_tmp, 0, WAPP_PATH_MAX);
memcpy(old_tmp, old_filepath->buf, old_filepath->size);
memset(new_tmp, 0, WAPP_PATH_MAX);
memcpy(new_tmp, new_filepath->buf, new_filepath->size);
if (!MoveFile((LPCSTR)old_tmp, (LPCSTR)new_tmp)) {
return -1;
}
return 0;
}
i32 _file_remove(Str8RO *filepath) {
wapp_persist c8 tmp[WAPP_PATH_MAX] = {0};
memset(tmp, 0, WAPP_PATH_MAX);
memcpy(tmp, filepath->buf, filepath->size);
if (!DeleteFile((LPCSTR)tmp)) {
return -1;
}
return 0;
}
#endif // !WAPP_PLATFORM_WINDOWS

View File

@@ -0,0 +1,31 @@
// vim:fileencoding=utf-8:foldmethod=marker
#ifndef FILE_WIN_H
#define FILE_WIN_H
#include "../../../common/aliases/aliases.h"
#include "../../../common/platform/platform.h"
#ifdef WAPP_PLATFORM_CPP
BEGIN_C_LINKAGE
#endif // !WAPP_PLATFORM_CPP
#ifdef WAPP_PLATFORM_WINDOWS
#define END_OF_LINE "\r\n"
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <fileapi.h>
struct WFile {
HANDLE fh;
};
#endif // !WAPP_PLATFORM_WINDOWS
#ifdef WAPP_PLATFORM_CPP
END_C_LINKAGE
#endif // !WAPP_PLATFORM_CPP
#endif // !FILE_WIN_H

View File

@@ -6,6 +6,7 @@
#include "wapp_os.h" #include "wapp_os.h"
#include "file/file.c" #include "file/file.c"
#include "file/posix/file_posix.c" #include "file/posix/file_posix.c"
#include "file/win/file_win.c"
#include "shell/termcolour/posix/termcolour_posix.c" #include "shell/termcolour/posix/termcolour_posix.c"
#include "shell/termcolour/win/termcolour_win.c" #include "shell/termcolour/win/termcolour_win.c"
#include "shell/termcolour/termcolour.c" #include "shell/termcolour/termcolour.c"

View File

@@ -5,6 +5,7 @@
#include "file/file.h" #include "file/file.h"
#include "file/posix/file_posix.h" #include "file/posix/file_posix.h"
#include "file/win/file_win.h"
#include "shell/termcolour/termcolour.h" #include "shell/termcolour/termcolour.h"
#include "shell/termcolour/terminal_colours.h" #include "shell/termcolour/terminal_colours.h"
#include "shell/commander/commander.h" #include "shell/commander/commander.h"

View File

@@ -15,12 +15,12 @@ wapp_intern i32 dst_buf[DST_CAPACITY] = {0};
TestFuncResult test_wapp_file_open(void) { TestFuncResult test_wapp_file_open(void) {
arena = wapp_mem_arena_allocator_init(KiB(16)); arena = wapp_mem_arena_allocator_init(KiB(16));
test_fp = wapp_file_open(&arena, &test_filename, WAPP_ACCESS_WRITE_BIN_EX); test_fp = wapp_file_open(&arena, &test_filename, WAPP_ACCESS_WRITE_EX);
return wapp_tester_result(test_fp != NULL); return wapp_tester_result(test_fp != NULL);
} }
TestFuncResult test_wapp_file_get_current_position(void) { TestFuncResult test_wapp_file_get_current_position(void) {
u64 pos = wapp_file_get_current_position(test_fp); i64 pos = wapp_file_get_current_position(test_fp);
return wapp_tester_result(pos == 0); return wapp_tester_result(pos == 0);
} }
@@ -47,8 +47,14 @@ TestFuncResult test_wapp_file_read(void) {
u64 count = wapp_file_read((void *)dst_buf, test_fp, byte_count); u64 count = wapp_file_read((void *)dst_buf, test_fp, byte_count);
b8 result = count == byte_count; b8 result = count == byte_count;
for (u64 i = 0; i < DST_CAPACITY; ++i) { // NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of
result = result && (dst_buf[i] == *wapp_array_get(i32, src_array1, i)); // MSVC Spectre mitigation warnings
u64 index = 0;
b8 running = true;
while (running) {
result = result && (dst_buf[index] == *wapp_array_get(i32, src_array1, index));
++index;
running = index < DST_CAPACITY;
} }
return wapp_tester_result(result); return wapp_tester_result(result);
@@ -58,9 +64,9 @@ TestFuncResult test_wapp_file_write(void) {
wapp_file_seek(test_fp, 0, WAPP_SEEK_END); wapp_file_seek(test_fp, 0, WAPP_SEEK_END);
u64 expected_count = wapp_array_count(src_array2) * wapp_array_item_size(src_array2); u64 expected_count = wapp_array_count(src_array2) * wapp_array_item_size(src_array2);
u64 count = wapp_file_write((void *)src_array2, test_fp, expected_count); i64 count = wapp_file_write((void *)src_array2, test_fp, expected_count);
return wapp_tester_result(count == expected_count); return wapp_tester_result(count >= 0 && (u64)count == expected_count);
} }
TestFuncResult test_wapp_file_read_array(void) { TestFuncResult test_wapp_file_read_array(void) {
@@ -70,8 +76,14 @@ TestFuncResult test_wapp_file_read_array(void) {
b8 result = count == wapp_array_count(src_array1) && b8 result = count == wapp_array_count(src_array1) &&
wapp_array_count(dst_array) == wapp_array_count(src_array1); wapp_array_count(dst_array) == wapp_array_count(src_array1);
for (u64 i = 0; i < wapp_array_count(dst_array); ++i) { // NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of
result = result && (*wapp_array_get(i32, dst_array, i) == *wapp_array_get(i32, src_array1, i)); // MSVC Spectre mitigation warnings
u64 index = 0;
b8 running = true;
while (running) {
result = result && (*wapp_array_get(i32, dst_array, index) == *wapp_array_get(i32, src_array1, index));
++index;
running = index < wapp_array_count(dst_array);
} }
return wapp_tester_result(result); return wapp_tester_result(result);
@@ -80,9 +92,9 @@ TestFuncResult test_wapp_file_read_array(void) {
TestFuncResult test_wapp_file_write_array(void) { TestFuncResult test_wapp_file_write_array(void) {
wapp_file_seek(test_fp, 0, WAPP_SEEK_END); wapp_file_seek(test_fp, 0, WAPP_SEEK_END);
u64 count = wapp_file_write_array((GenericArray)src_array3, test_fp, wapp_array_count(src_array3)); i64 count = wapp_file_write_array((GenericArray)src_array3, test_fp, wapp_array_count(src_array3));
return wapp_tester_result(count == wapp_array_count(src_array3)); return wapp_tester_result(count >= 0 && (u64)count == wapp_array_count(src_array3));
} }
TestFuncResult test_wapp_file_flush(void) { TestFuncResult test_wapp_file_flush(void) {

View File

@@ -19,12 +19,12 @@ TestFuncResult test_wapp_file_open(void) {
src_array2 = wapp_array(i32, 5, 6, 7, 8, 9); src_array2 = wapp_array(i32, 5, 6, 7, 8, 9);
src_array3 = wapp_array(i32, 10, 11, 12, 13, 14); src_array3 = wapp_array(i32, 10, 11, 12, 13, 14);
dst_array = wapp_array_with_capacity(i32, DST_CAPACITY, false); dst_array = wapp_array_with_capacity(i32, DST_CAPACITY, false);
test_fp = wapp_file_open(&arena, &test_filename, WAPP_ACCESS_WRITE_BIN_EX); test_fp = wapp_file_open(&arena, &test_filename, WAPP_ACCESS_WRITE_EX);
return wapp_tester_result(test_fp != NULL); return wapp_tester_result(test_fp != NULL);
} }
TestFuncResult test_wapp_file_get_current_position(void) { TestFuncResult test_wapp_file_get_current_position(void) {
u64 pos = wapp_file_get_current_position(test_fp); i64 pos = wapp_file_get_current_position(test_fp);
return wapp_tester_result(pos == 0); return wapp_tester_result(pos == 0);
} }
@@ -51,8 +51,14 @@ TestFuncResult test_wapp_file_read(void) {
u64 count = wapp_file_read((void *)dst_buf, test_fp, byte_count); u64 count = wapp_file_read((void *)dst_buf, test_fp, byte_count);
b8 result = count == byte_count; b8 result = count == byte_count;
for (u64 i = 0; i < DST_CAPACITY; ++i) { // NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of
result = result && (dst_buf[i] == *wapp_array_get(i32, src_array1, i)); // MSVC Spectre mitigation warnings
u64 index = 0;
b8 running = true;
while (running) {
result = result && (dst_buf[index] == *wapp_array_get(i32, src_array1, index));
++index;
running = index < DST_CAPACITY;
} }
return wapp_tester_result(result); return wapp_tester_result(result);
@@ -62,9 +68,9 @@ TestFuncResult test_wapp_file_write(void) {
wapp_file_seek(test_fp, 0, WAPP_SEEK_END); wapp_file_seek(test_fp, 0, WAPP_SEEK_END);
u64 expected_count = wapp_array_count(src_array2) * wapp_array_item_size(src_array2); u64 expected_count = wapp_array_count(src_array2) * wapp_array_item_size(src_array2);
u64 count = wapp_file_write((void *)src_array2, test_fp, expected_count); i64 count = wapp_file_write((void *)src_array2, test_fp, expected_count);
return wapp_tester_result(count == expected_count); return wapp_tester_result(count >= 0 && (u64)count == expected_count);
} }
TestFuncResult test_wapp_file_read_array(void) { TestFuncResult test_wapp_file_read_array(void) {
@@ -74,8 +80,14 @@ TestFuncResult test_wapp_file_read_array(void) {
b8 result = count == wapp_array_count(src_array1) && b8 result = count == wapp_array_count(src_array1) &&
wapp_array_count(dst_array) == wapp_array_count(src_array1); wapp_array_count(dst_array) == wapp_array_count(src_array1);
for (u64 i = 0; i < wapp_array_count(dst_array); ++i) { // NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of
result = result && (*wapp_array_get(i32, dst_array, i) == *wapp_array_get(i32, src_array1, i)); // MSVC Spectre mitigation warnings
u64 index = 0;
b8 running = true;
while (running) {
result = result && (*wapp_array_get(i32, dst_array, index) == *wapp_array_get(i32, src_array1, index));
++index;
running = index < wapp_array_count(dst_array);
} }
return wapp_tester_result(result); return wapp_tester_result(result);
@@ -84,9 +96,9 @@ TestFuncResult test_wapp_file_read_array(void) {
TestFuncResult test_wapp_file_write_array(void) { TestFuncResult test_wapp_file_write_array(void) {
wapp_file_seek(test_fp, 0, WAPP_SEEK_END); wapp_file_seek(test_fp, 0, WAPP_SEEK_END);
u64 count = wapp_file_write_array((GenericArray)src_array3, test_fp, wapp_array_count(src_array3)); i64 count = wapp_file_write_array((GenericArray)src_array3, test_fp, wapp_array_count(src_array3));
return wapp_tester_result(count == wapp_array_count(src_array3)); return wapp_tester_result(count >= 0 && (u64)count == wapp_array_count(src_array3));
} }
TestFuncResult test_wapp_file_flush(void) { TestFuncResult test_wapp_file_flush(void) {