meta: rename io module to fx.io namespace

This commit is contained in:
2026-05-02 14:37:29 +01:00
parent 47feee7b1a
commit 274a48a845
21 changed files with 0 additions and 0 deletions
+366
View File
@@ -0,0 +1,366 @@
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <fx/io/directory.h>
#include <stdlib.h>
#include <string.h>
struct fx_directory {
struct fx_dsref base;
HANDLE handle;
struct fx_path *abs_path;
};
struct z__fx_directory_iterator {
fx_queue state_stack;
};
struct iteration_state {
const fx_path *search_path;
fx_queue_entry entry;
HANDLE search;
WIN32_FIND_DATAA data;
bool child_search_complete;
};
static void directory_release(struct fx_dsref *obj);
static struct fx_dsref_type directory_type = {
.t_name = "corelib::directory",
.t_flags = FX_DSREF_FUNDAMENTAL,
.t_id = FX_DSREF_TYPE_PATH,
.t_instance_size = sizeof(struct fx_directory),
.t_release = directory_release,
};
static enum fx_status status_from_win32_error(int error, enum fx_status default_value)
{
switch (error) {
case ERROR_FILE_NOT_FOUND:
return FX_ERR_NO_ENTRY;
default:
return default_value;
}
}
enum fx_status fx_directory_open(
struct fx_directory *root, const struct fx_path *path,
struct fx_directory **out)
{
enum fx_status status = FX_SUCCESS;
const fx_path *parts[] = {
root ? root->abs_path : NULL,
path,
};
fx_path *new_path = fx_path_join(parts, sizeof parts / sizeof *parts);
if (!new_path) {
return FX_ERR_NO_MEMORY;
}
HANDLE dir_handle = CreateFileA(
fx_path_ptr(new_path), GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, INVALID_HANDLE_VALUE);
if (dir_handle == INVALID_HANDLE_VALUE) {
status = status_from_win32_error(GetLastError(), FX_ERR_IO_FAILURE);
fx_path_release(new_path);
return status;
}
BY_HANDLE_FILE_INFORMATION dir_info;
if (!GetFileInformationByHandle(dir_handle, &dir_info)) {
status = status_from_win32_error(GetLastError(), FX_ERR_IO_FAILURE);
CloseHandle(dir_handle);
fx_path_release(new_path);
return status;
}
if (!(dir_info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
CloseHandle(dir_handle);
fx_path_release(new_path);
return FX_ERR_NOT_DIRECTORY;
}
struct fx_directory *dir
= (struct fx_directory *)fx_dsref_type_instantiate(&directory_type);
if (!path) {
CloseHandle(dir_handle);
fx_path_release(new_path);
return FX_ERR_NO_MEMORY;
}
dir->abs_path = new_path;
dir->handle = dir_handle;
*out = dir;
return FX_SUCCESS;
}
static struct iteration_state *get_iteration_state(
struct z__fx_directory_iterator *it)
{
fx_queue_entry *last = fx_queue_last(&it->state_stack);
if (!last) {
return NULL;
}
return fx_unbox(struct iteration_state, last, entry);
}
static struct iteration_state *push_iteration_state(
struct z__fx_directory_iterator *it)
{
struct iteration_state *state = malloc(sizeof *state);
if (!state) {
return NULL;
}
memset(state, 0x0, sizeof *state);
fx_queue_push_back(&it->state_stack, &state->entry);
return state;
}
static void pop_iteration_state(struct z__fx_directory_iterator *it)
{
struct iteration_state *state = get_iteration_state(it);
if (!state) {
return;
}
fx_queue_pop_back(&it->state_stack);
FindClose(state->search);
free(state);
}
static void cleanup_iterator(struct fx_directory_iterator *it)
{
while (!fx_queue_empty(&it->_z->state_stack)) {
pop_iteration_state(it->_z);
}
free(it->_z);
it->_z = NULL;
}
static void update_iterator_data(struct fx_directory_iterator *it)
{
if (it->filepath) {
fx_path_release(FX_PATH(it->filepath));
it->filepath = NULL;
}
struct iteration_state *state = get_iteration_state(it->_z);
if (state) {
it->filename = state->data.cFileName;
struct fx_path *filename = fx_path_create_from_cstr(it->filename);
const struct fx_path *parts[] = {
state->search_path,
filename,
};
it->filepath = fx_path_join(parts, sizeof parts / sizeof parts[0]);
}
}
static bool move_into_directory(struct fx_directory_iterator *it, const char *dir_name)
{
struct iteration_state *state = get_iteration_state(it->_z);
struct fx_path *dir_name_p = fx_path_create_from_cstr(dir_name);
struct fx_path *wildcard = fx_path_create_from_cstr("*");
const struct fx_path *parts[] = {
state ? state->search_path : NULL,
dir_name_p,
};
struct fx_path *dir_path = fx_path_join(parts, sizeof parts / sizeof *parts);
parts[0] = dir_path;
parts[1] = wildcard;
struct fx_path *search_path
= fx_path_join(parts, sizeof parts / sizeof *parts);
state = push_iteration_state(it->_z);
state->search_path = dir_path;
state->search = FindFirstFileA(fx_path_ptr(search_path), &state->data);
fx_path_release(search_path);
fx_path_release(wildcard);
fx_path_release(dir_name_p);
if (state->search == INVALID_HANDLE_VALUE) {
pop_iteration_state(it->_z);
return false;
}
while (!strcmp(state->data.cFileName, ".")
|| !strcmp(state->data.cFileName, "..")) {
BOOL ok = FindNextFileA(state->search, &state->data);
if (!ok) {
pop_iteration_state(it->_z);
return false;
}
}
return true;
}
static bool move_to_first_item(
struct fx_directory_iterator *it, const struct fx_path *root_dir)
{
bool has_results = move_into_directory(it, fx_path_ptr(root_dir));
if (!has_results) {
return false;
}
if (it->flags & FX_DIRECTORY_ITERATE_PARENT_FIRST) {
return true;
}
while (true) {
struct iteration_state *state = get_iteration_state(it->_z);
if (!(state->data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
break;
}
has_results = move_into_directory(it, state->data.cFileName);
if (!has_results) {
pop_iteration_state(it->_z);
break;
}
}
return true;
}
static bool move_to_next_item(struct fx_directory_iterator *it)
{
while (true) {
struct iteration_state *state = get_iteration_state(it->_z);
if (!state->child_search_complete
&& (state->data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
&& (it->flags & FX_DIRECTORY_ITERATE_PARENT_FIRST)) {
if (move_into_directory(it, state->data.cFileName)) {
return true;
}
}
bool has_items = FindNextFileA(state->search, &state->data);
if (!has_items) {
pop_iteration_state(it->_z);
state = get_iteration_state(it->_z);
if (it->flags & FX_DIRECTORY_ITERATE_PARENT_FIRST
&& state != NULL) {
state->child_search_complete = true;
continue;
}
return state != NULL;
}
state->child_search_complete = false;
if (!(state->data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
return true;
}
if (it->flags & FX_DIRECTORY_ITERATE_PARENT_FIRST) {
return true;
}
while (true) {
state = get_iteration_state(it->_z);
has_items = move_into_directory(it, state->data.cFileName);
if (!has_items) {
pop_iteration_state(it->_z);
return true;
}
state = get_iteration_state(it->_z);
if (!(state->data.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY)) {
return true;
}
}
}
return true;
}
int fx_directory_iterator_begin(
struct fx_directory *directory, struct fx_directory_iterator *it,
enum fx_directory_iterator_flags flags)
{
if (fx_directory_iterator_is_valid(it)) {
cleanup_iterator(it);
}
it->flags = flags;
struct z__fx_directory_iterator *it_data = malloc(sizeof *it_data);
memset(it_data, 0x0, sizeof *it_data);
it->_z = it_data;
move_to_first_item(it, directory->abs_path);
update_iterator_data(it);
return 0;
}
bool fx_directory_iterator_next(struct fx_directory_iterator *it)
{
if (!it->_z) {
return false;
}
bool result = move_to_next_item(it);
update_iterator_data(it);
return result;
}
enum fx_status fx_directory_iterator_erase(struct fx_directory_iterator *it)
{
return FX_SUCCESS;
}
bool fx_directory_iterator_is_valid(const struct fx_directory_iterator *it)
{
if (!it->_z) {
return false;
}
if (!get_iteration_state(it->_z)) {
return false;
}
return true;
}
static void directory_release(struct fx_dsref *obj)
{
}
+248
View File
@@ -0,0 +1,248 @@
#define WIN32_LEAN_AND_MEAN
#include <fx/core/stringstream.h>
#include <fx/io/path.h>
#include <fx/ds/string.h>
#include <Windows.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
struct fx_path {
struct fx_dsref base;
struct fx_string *pathstr;
};
static void path_release(struct fx_dsref *obj);
static void path_to_string(struct fx_dsref *obj, struct fx_stringstream *out);
static struct fx_dsref_type path_type = {
.t_name = "corelib::path",
.t_flags = FX_DSREF_FUNDAMENTAL,
.t_id = FX_DSREF_TYPE_PATH,
.t_instance_size = sizeof(struct fx_path),
.t_release = path_release,
.t_to_string = path_to_string,
};
struct fx_path *fx_path_create()
{
struct fx_path *path
= (struct fx_path *)fx_dsref_type_instantiate(&path_type);
if (!path) {
return NULL;
}
path->pathstr = fx_string_create();
if (!path->pathstr) {
fx_path_release(path);
return NULL;
}
return path;
}
struct fx_path *fx_path_create_root()
{
const char *system_drive = getenv("SystemDrive");
if (!system_drive) {
/* take an educated guess. */
system_drive = "C:";
}
size_t system_drive_len = strlen(system_drive);
struct fx_path *path = fx_path_create();
if (!path) {
return NULL;
}
fx_string_append_cstr(path->pathstr, system_drive);
if (system_drive[system_drive_len - 1] != '\\') {
fx_string_append_cstr(path->pathstr, "\\");
}
return path;
}
struct fx_path *fx_path_create_cwd()
{
DWORD cwd_len = GetCurrentDirectory(0, NULL);
if (cwd_len == 0) {
return NULL;
}
TCHAR *cwd_buf = malloc(cwd_len + 1);
if (!cwd_buf) {
return NULL;
}
cwd_len = GetCurrentDirectory(cwd_len + 1, cwd_buf);
if (cwd_len == 0) {
free(cwd_buf);
return NULL;
}
struct fx_path *path = fx_path_create();
if (!path) {
return NULL;
}
for (DWORD i = 0; i < cwd_len; i++) {
TCHAR c = cwd_buf[i];
char s[] = {(c >= 128 ? '?' : (char)c), 0};
fx_string_append_cstr(path->pathstr, s);
}
free(cwd_buf);
return path;
}
struct fx_path *fx_path_create_from_cstr(const char *cstr)
{
struct fx_path *path = fx_path_create();
if (!path) {
return NULL;
}
char prev = 0;
for (size_t i = 0; cstr[i]; i++) {
char c = cstr[i];
if (c == '\\') {
c = '/';
}
if (prev == '/' && c == '/') {
continue;
}
char s[] = {c, 0};
fx_string_append_cstr(path->pathstr, s);
prev = c;
}
while (fx_string_get_last_char(path->pathstr) == '/') {
fx_string_pop_back(path->pathstr);
}
return path;
}
static void append_path(struct fx_path *dest, const struct fx_path *src)
{
if (fx_path_is_absolute(src)) {
fx_string_clear(dest->pathstr);
fx_string_append_s(dest->pathstr, src->pathstr);
return;
}
if (fx_string_get_last_char(dest->pathstr) != '/'
&& fx_string_get_first_char(src->pathstr) != '/') {
char s[] = {'/', 0};
fx_string_append_cstr(dest->pathstr, s);
}
fx_string_append_s(dest->pathstr, src->pathstr);
}
struct fx_path *fx_path_join(
const fx_path *paths[], size_t nr_paths)
{
struct fx_path *result = fx_path_create();
if (!result) {
return NULL;
}
for (size_t i = 0; i < nr_paths; i++) {
if (paths[i]) {
append_path(result, paths[i]);
}
}
return result;
}
struct fx_path *fx_path_make_absolute(const struct fx_path *in)
{
return NULL;
}
struct fx_path *fx_path_make_relative(const struct fx_path *in)
{
return NULL;
}
struct fx_path *fx_path_make_canonical(const struct fx_path *in)
{
return NULL;
}
bool fx_path_is_absolute(const struct fx_path *path)
{
const char *s = fx_string_get_cstr(path->pathstr);
size_t i;
for (i = 0; s[i]; i++) {
char c = s[i];
if (!isalpha(c)) {
break;
}
}
if (s[i++] != ':') {
return false;
}
if (s[i++] != '/') {
return false;
}
return true;
}
bool fx_path_exists(const struct fx_path *path)
{
DWORD attrib = GetFileAttributesA(fx_path_ptr(path));
return attrib != INVALID_FILE_ATTRIBUTES;
}
bool fx_path_is_file(const struct fx_path *path)
{
DWORD attrib = GetFileAttributesA(fx_path_ptr(path));
if (attrib == INVALID_FILE_ATTRIBUTES) {
return false;
}
return (attrib & FILE_ATTRIBUTE_NORMAL) != 0;
}
bool fx_path_is_directory(const struct fx_path *path)
{
DWORD attrib = GetFileAttributesA(fx_path_ptr(path));
if (attrib == INVALID_FILE_ATTRIBUTES) {
return false;
}
return (attrib & FILE_ATTRIBUTE_DIRECTORY) != 0;
}
const char *fx_path_ptr(const struct fx_path *path)
{
return fx_string_get_cstr(path->pathstr);
}
void path_release(struct fx_dsref* obj)
{
struct fx_path *path = FX_PATH(obj);
fx_string_release(path->pathstr);
}
void path_to_string(struct fx_dsref* obj, struct fx_stringstream* out)
{
struct fx_path *path = (struct fx_path *)obj;
fx_stringstream_add(out, fx_string_get_cstr(path->pathstr));
}