diff --git a/mrbgems/hal-posix-dir/mrbgem.rake b/mrbgems/hal-posix-dir/mrbgem.rake new file mode 100644 index 000000000..877b110cb --- /dev/null +++ b/mrbgems/hal-posix-dir/mrbgem.rake @@ -0,0 +1,7 @@ +MRuby::Gem::Specification.new('hal-posix-dir') do |spec| + spec.license = 'MIT' + spec.authors = 'mruby developers' + spec.summary = 'POSIX HAL for mruby-dir (Linux, macOS, BSD, Unix)' + + spec.add_dependency 'mruby-dir', core: 'mruby-dir' +end diff --git a/mrbgems/hal-posix-dir/src/dir_hal.c b/mrbgems/hal-posix-dir/src/dir_hal.c new file mode 100644 index 000000000..42ab52b09 --- /dev/null +++ b/mrbgems/hal-posix-dir/src/dir_hal.c @@ -0,0 +1,193 @@ +/* +** dir_hal.c - POSIX HAL implementation for mruby-dir +** +** See Copyright Notice in mruby.h +** +** POSIX implementation for directory operations using standard POSIX APIs. +** Supported platforms: Linux, macOS, BSD, Unix +*/ + +#include +#include "dir_hal.h" + +#include +#include +#include +#include +#include + +#ifdef HAVE_SYS_PARAM_H +#include +#endif + +/* On POSIX, mrb_dir_handle wraps DIR */ +struct mrb_dir_handle { + DIR *dir; +}; + +/* + * Directory Operations + */ + +mrb_dir_handle* +mrb_dir_hal_open(mrb_state *mrb, const char *path) +{ + DIR *dir = opendir(path); + if (dir == NULL) { + return NULL; + } + + mrb_dir_handle *handle = (mrb_dir_handle*)mrb_malloc(mrb, sizeof(mrb_dir_handle)); + handle->dir = dir; + return handle; +} + +int +mrb_dir_hal_close(mrb_state *mrb, mrb_dir_handle *handle) +{ + int result = closedir(handle->dir); + mrb_free(mrb, handle); + return result; +} + +const char* +mrb_dir_hal_read(mrb_state *mrb, mrb_dir_handle *handle) +{ + (void)mrb; + struct dirent *dp = readdir(handle->dir); + return dp ? dp->d_name : NULL; +} + +void +mrb_dir_hal_rewind(mrb_state *mrb, mrb_dir_handle *handle) +{ + (void)mrb; + rewinddir(handle->dir); +} + +/* + * Optional Operations + */ + +int +mrb_dir_hal_seek(mrb_state *mrb, mrb_dir_handle *handle, long pos) +{ +#if defined(__ANDROID__) + /* Android doesn't have reliable seekdir */ + (void)mrb; (void)handle; (void)pos; + errno = ENOSYS; + return -1; +#else + (void)mrb; + seekdir(handle->dir, pos); + return 0; +#endif +} + +long +mrb_dir_hal_tell(mrb_state *mrb, mrb_dir_handle *handle) +{ +#if defined(__ANDROID__) + /* Android doesn't have reliable telldir */ + (void)mrb; (void)handle; + errno = ENOSYS; + return -1; +#else + (void)mrb; + return telldir(handle->dir); +#endif +} + +/* + * Filesystem Operations + */ + +int +mrb_dir_hal_mkdir(mrb_state *mrb, const char *path, int mode) +{ + (void)mrb; + return mkdir(path, (mode_t)mode); +} + +int +mrb_dir_hal_rmdir(mrb_state *mrb, const char *path) +{ + (void)mrb; + return rmdir(path); +} + +int +mrb_dir_hal_chdir(mrb_state *mrb, const char *path) +{ + (void)mrb; + return chdir(path); +} + +int +mrb_dir_hal_getcwd(mrb_state *mrb, char *buf, size_t size) +{ + (void)mrb; + return getcwd(buf, size) ? 0 : -1; +} + +int +mrb_dir_hal_chroot(mrb_state *mrb, const char *path) +{ +#if defined(__ANDROID__) || defined(__MSDOS__) + /* Not available on these platforms */ + (void)mrb; (void)path; + errno = ENOSYS; + return -1; +#else + (void)mrb; + return chroot(path); +#endif +} + +int +mrb_dir_hal_is_directory(mrb_state *mrb, const char *path) +{ + struct stat sb; + (void)mrb; + + if (stat(path, &sb) == 0 && S_ISDIR(sb.st_mode)) { + return 1; + } + return 0; +} + +/* + * HAL Initialization/Finalization + */ + +void +mrb_dir_hal_init(mrb_state *mrb) +{ + (void)mrb; + /* No initialization needed for POSIX */ +} + +void +mrb_dir_hal_final(mrb_state *mrb) +{ + (void)mrb; + /* No cleanup needed for POSIX */ +} + +/* + * Gem initialization + */ + +void +mrb_hal_posix_dir_gem_init(mrb_state *mrb) +{ + (void)mrb; + /* HAL interface functions are called by mruby-dir gem */ +} + +void +mrb_hal_posix_dir_gem_final(mrb_state *mrb) +{ + (void)mrb; + /* Cleanup handled by mrb_dir_hal_final called from mruby-dir */ +} diff --git a/mrbgems/hal-win-dir/mrbgem.rake b/mrbgems/hal-win-dir/mrbgem.rake new file mode 100644 index 000000000..426829dbb --- /dev/null +++ b/mrbgems/hal-win-dir/mrbgem.rake @@ -0,0 +1,7 @@ +MRuby::Gem::Specification.new('hal-win-dir') do |spec| + spec.license = 'MIT and MIT-like license' + spec.authors = ['mruby developers', 'Kevlin Henney'] + spec.summary = 'Windows HAL for mruby-dir' + + spec.add_dependency 'mruby-dir', core: 'mruby-dir' +end diff --git a/mrbgems/hal-win-dir/src/dir_hal.c b/mrbgems/hal-win-dir/src/dir_hal.c new file mode 100644 index 000000000..cf4419936 --- /dev/null +++ b/mrbgems/hal-win-dir/src/dir_hal.c @@ -0,0 +1,249 @@ +/* +** dir_hal.c - Windows HAL implementation for mruby-dir +** +** See Copyright Notice in mruby.h +** +** Windows implementation for directory operations using _findfirst/_findnext APIs. +** Provides POSIX-compatible interface on Windows. +** +** Based on dirent.c by Kevlin Henney (kevlin@acm.org, kevlin@curbralan.com) +** Original implementation: Created March 1997. Updated June 2003 and July 2012. +** See end of file for Kevlin Henney's copyright notice. +*/ + +#include +#include "dir_hal.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +/* Windows directory handle implementation */ +struct mrb_dir_handle { + intptr_t handle; /* _findfirst/_findnext handle */ + struct _finddata_t info; /* Current entry info */ + char *pattern; /* Search pattern (e.g., "dir/*") */ + int first; /* Flag: haven't read first entry yet */ +}; + +/* + * Directory Operations + */ + +mrb_dir_handle* +mrb_dir_hal_open(mrb_state *mrb, const char *path) +{ + mrb_dir_handle *handle; + size_t len = strlen(path); + const char *suffix; + + /* Add wildcard suffix if needed */ + suffix = (len > 0 && (path[len-1] == '/' || path[len-1] == '\\')) ? "*" : "/*"; + + handle = (mrb_dir_handle*)mrb_malloc(mrb, sizeof(mrb_dir_handle)); + handle->pattern = (char*)mrb_malloc(mrb, len + strlen(suffix) + 1); + strcpy(handle->pattern, path); + strcat(handle->pattern, suffix); + + handle->handle = _findfirst(handle->pattern, &handle->info); + if (handle->handle == -1) { + mrb_free(mrb, handle->pattern); + mrb_free(mrb, handle); + return NULL; + } + + handle->first = 1; + return handle; +} + +int +mrb_dir_hal_close(mrb_state *mrb, mrb_dir_handle *handle) +{ + int result = -1; + + if (handle->handle != -1) { + result = _findclose(handle->handle); + } + + mrb_free(mrb, handle->pattern); + mrb_free(mrb, handle); + + if (result == -1) { + /* Map all errors to EBADF */ + errno = EBADF; + } + + return result; +} + +const char* +mrb_dir_hal_read(mrb_state *mrb, mrb_dir_handle *handle) +{ + (void)mrb; + + if (handle->handle == -1) { + errno = EBADF; + return NULL; + } + + /* First call returns the result from _findfirst */ + if (handle->first) { + handle->first = 0; + return handle->info.name; + } + + /* Subsequent calls use _findnext */ + if (_findnext(handle->handle, &handle->info) == -1) { + return NULL; + } + + return handle->info.name; +} + +void +mrb_dir_hal_rewind(mrb_state *mrb, mrb_dir_handle *handle) +{ + (void)mrb; + + if (handle->handle == -1) { + errno = EBADF; + return; + } + + /* Close and reopen to rewind */ + _findclose(handle->handle); + handle->handle = _findfirst(handle->pattern, &handle->info); + handle->first = 1; +} + +/* + * Optional Operations + */ + +int +mrb_dir_hal_seek(mrb_state *mrb, mrb_dir_handle *handle, long pos) +{ + /* Not supported on Windows */ + (void)mrb; (void)handle; (void)pos; + errno = ENOSYS; + return -1; +} + +long +mrb_dir_hal_tell(mrb_state *mrb, mrb_dir_handle *handle) +{ + /* Not supported on Windows */ + (void)mrb; (void)handle; + errno = ENOSYS; + return -1; +} + +/* + * Filesystem Operations + */ + +int +mrb_dir_hal_mkdir(mrb_state *mrb, const char *path, int mode) +{ + /* Windows _mkdir ignores mode parameter */ + (void)mrb; (void)mode; + return _mkdir(path); +} + +int +mrb_dir_hal_rmdir(mrb_state *mrb, const char *path) +{ + (void)mrb; + return _rmdir(path); +} + +int +mrb_dir_hal_chdir(mrb_state *mrb, const char *path) +{ + (void)mrb; + return _chdir(path); +} + +int +mrb_dir_hal_getcwd(mrb_state *mrb, char *buf, size_t size) +{ + (void)mrb; + return _getcwd(buf, (int)size) ? 0 : -1; +} + +int +mrb_dir_hal_chroot(mrb_state *mrb, const char *path) +{ + /* Not available on Windows */ + (void)mrb; (void)path; + errno = ENOSYS; + return -1; +} + +int +mrb_dir_hal_is_directory(mrb_state *mrb, const char *path) +{ + struct _stat sb; + (void)mrb; + + if (_stat(path, &sb) == 0 && (sb.st_mode & _S_IFDIR)) { + return 1; + } + return 0; +} + +/* + * HAL Initialization/Finalization + */ + +void +mrb_dir_hal_init(mrb_state *mrb) +{ + (void)mrb; + /* No initialization needed for Windows */ +} + +void +mrb_dir_hal_final(mrb_state *mrb) +{ + (void)mrb; + /* No cleanup needed for Windows */ +} + +/* + * Gem initialization + */ + +void +mrb_hal_win_dir_gem_init(mrb_state *mrb) +{ + (void)mrb; + /* HAL interface functions are called by mruby-dir gem */ +} + +void +mrb_hal_win_dir_gem_final(mrb_state *mrb) +{ + (void)mrb; + /* Cleanup handled by mrb_dir_hal_final called from mruby-dir */ +} + +/* +** Portions derived from dirent.c by Kevlin Henney: +** +** Copyright Kevlin Henney, 1997, 2003, 2012. All rights reserved. +** +** Permission to use, copy, modify, and distribute this software and its +** documentation for any purpose is hereby granted without fee, provided +** that this copyright and permissions notice appear in all copies and +** derivatives. +** +** This software is supplied "as is" without express or implied warranty. +** +** But that said, if there are any problems please get in touch. +*/ diff --git a/mrbgems/mruby-dir/include/dir_hal.h b/mrbgems/mruby-dir/include/dir_hal.h new file mode 100644 index 000000000..02c087e8f --- /dev/null +++ b/mrbgems/mruby-dir/include/dir_hal.h @@ -0,0 +1,79 @@ +/* +** dir_hal.h - Directory HAL interface for mruby +** +** See Copyright Notice in mruby.h +** +** Hardware Abstraction Layer for directory operations. +** Provides platform-independent interface for filesystem directory operations. +*/ + +#ifndef MRUBY_DIR_HAL_H +#define MRUBY_DIR_HAL_H + +#include + +/* + * Platform-independent directory handle + * Each HAL implementation defines this structure internally + */ +typedef struct mrb_dir_handle mrb_dir_handle; + +/* + * Directory Operations + */ + +/* Open directory for reading. Returns handle or NULL on error (sets errno). */ +mrb_dir_handle* mrb_dir_hal_open(mrb_state *mrb, const char *path); + +/* Close directory handle. Returns 0 on success, -1 on error. */ +int mrb_dir_hal_close(mrb_state *mrb, mrb_dir_handle *dir); + +/* Read next entry from directory. Returns name or NULL at end/error. */ +const char* mrb_dir_hal_read(mrb_state *mrb, mrb_dir_handle *dir); + +/* Rewind directory to beginning */ +void mrb_dir_hal_rewind(mrb_state *mrb, mrb_dir_handle *dir); + +/* + * Optional Operations (may not be available on all platforms) + */ + +/* Seek to position in directory. Returns -1 if unsupported (sets errno to ENOSYS). */ +int mrb_dir_hal_seek(mrb_state *mrb, mrb_dir_handle *dir, long pos); + +/* Get current position in directory. Returns -1 if unsupported (sets errno to ENOSYS). */ +long mrb_dir_hal_tell(mrb_state *mrb, mrb_dir_handle *dir); + +/* + * Filesystem Operations + */ + +/* Create directory with mode (mode may be ignored on some platforms). Returns 0 on success, -1 on error. */ +int mrb_dir_hal_mkdir(mrb_state *mrb, const char *path, int mode); + +/* Remove empty directory. Returns 0 on success, -1 on error. */ +int mrb_dir_hal_rmdir(mrb_state *mrb, const char *path); + +/* Change current working directory. Returns 0 on success, -1 on error. */ +int mrb_dir_hal_chdir(mrb_state *mrb, const char *path); + +/* Get current working directory. Returns 0 on success, -1 on error. */ +int mrb_dir_hal_getcwd(mrb_state *mrb, char *buf, size_t size); + +/* Change root directory (privileged operation). Returns -1 if unsupported (sets errno to ENOSYS). */ +int mrb_dir_hal_chroot(mrb_state *mrb, const char *path); + +/* Check if path is a directory. Returns 1 if directory, 0 if not. */ +int mrb_dir_hal_is_directory(mrb_state *mrb, const char *path); + +/* + * HAL Initialization/Finalization + */ + +/* Initialize HAL (called once at gem initialization) */ +void mrb_dir_hal_init(mrb_state *mrb); + +/* Cleanup HAL (called once at gem finalization) */ +void mrb_dir_hal_final(mrb_state *mrb); + +#endif /* MRUBY_DIR_HAL_H */ diff --git a/mrbgems/mruby-dir/mrbgem.rake b/mrbgems/mruby-dir/mrbgem.rake index ed05e14d1..71ed21cbd 100644 --- a/mrbgems/mruby-dir/mrbgem.rake +++ b/mrbgems/mruby-dir/mrbgem.rake @@ -1,4 +1,35 @@ MRuby::Gem::Specification.new('mruby-dir') do |spec| spec.license = 'MIT and MIT-like license' spec.authors = ['Internet Initiative Japan Inc.', 'Kevlin Henney'] + + # Check if HAL gem is loaded + # HAL gems must be explicitly specified in build config (recommended) or via auto-selection below + spec.build.gems.one? { |g| g.name =~ /^hal-.*-dir$/ } or begin + # No HAL found - determine appropriate error message or auto-load + suggested_hal = if ENV['MRUBY_DIR_HAL'] + ENV['MRUBY_DIR_HAL'] + elsif spec.for_windows? + 'hal-win-dir' + elsif RUBY_PLATFORM =~ /linux|darwin|bsd/ + 'hal-posix-dir' + else + nil + end + + if suggested_hal + # Auto-load HAL gem for convenience (for development) + # This works because HAL gems declare dependency on mruby-dir + warn "mruby-dir: No HAL specified, loading #{suggested_hal} (explicit selection recommended)" + spec.build.gem core: suggested_hal + else + # Unknown platform - fail with helpful message + fail "mruby-dir: No HAL available for platform '#{RUBY_PLATFORM}'.\n" \ + "Please specify HAL gem explicitly in your build config:\n" \ + " conf.gem core: 'hal-posix-dir' # For Linux/macOS/BSD\n" \ + " conf.gem core: 'hal-win-dir' # For Windows\n" \ + "Or set environment variable:\n" \ + " MRUBY_DIR_HAL=hal-myplatform-dir\n" \ + "See mrbgems/mruby-dir/README.md for creating custom HAL." + end + end end diff --git a/mrbgems/mruby-dir/src/Win/dirent.c b/mrbgems/mruby-dir/src/Win/dirent.c deleted file mode 100644 index 086aaf972..000000000 --- a/mrbgems/mruby-dir/src/Win/dirent.c +++ /dev/null @@ -1,140 +0,0 @@ -/* - - Implementation of POSIX directory browsing functions and types for Win32. - - Author: Kevlin Henney (kevlin@acm.org, kevlin@curbralan.com) - History: Created March 1997. Updated June 2003 and July 2012. - Rights: See end of file. - -*/ - -#include -#include /* _findfirst and _findnext set errno iff they return -1 */ -#include -#include - -#ifdef __cplusplus -extern "C" -{ -#endif - -typedef ptrdiff_t handle_type; /* C99's intptr_t not sufficiently portable */ - -struct dirent -{ - char *d_name; -}; - -struct DIR -{ - handle_type handle; /* -1 for failed rewind */ - struct _finddata_t info; - struct dirent result; /* d_name null iff first time */ - char *name; /* null-terminated char string */ -}; - -typedef struct DIR DIR; - -DIR *opendir(const char *name) -{ - DIR *dir = 0; - - if (name && name[0]) { - size_t base_length = strlen(name); - const char *all = /* search pattern must end with suitable wildcard */ - strchr("/\\", name[base_length - 1]) ? "*" : "/*"; - - if ((dir = (DIR *) malloc(sizeof *dir)) != 0 && - (dir->name = (char *) malloc(base_length + strlen(all) + 1)) != 0) { - strcat(strcpy(dir->name, name), all); - - if ((dir->handle = (handle_type) _findfirst(dir->name, &dir->info)) != -1) { - dir->result.d_name = 0; - } - else { /* rollback */ - free(dir->name); - free(dir); - dir = 0; - } - } - else { /* rollback */ - free(dir); - dir = 0; - errno = ENOMEM; - } - } - else { - errno = EINVAL; - } - - return dir; -} - -int closedir(DIR *dir) -{ - int result = -1; - - if (dir) { - if (dir->handle != -1) - { - result = _findclose(dir->handle); - } - - free(dir->name); - free(dir); - } - - if (result == -1) { /* map all errors to EBADF */ - errno = EBADF; - } - - return result; -} - -struct dirent *readdir(DIR *dir) -{ - struct dirent *result = 0; - - if (dir && dir->handle != -1) { - if (!dir->result.d_name || _findnext(dir->handle, &dir->info) != -1) { - result = &dir->result; - result->d_name = dir->info.name; - } - } - else { - errno = EBADF; - } - - return result; -} - -void rewinddir(DIR *dir) -{ - if (dir && dir->handle != -1) { - _findclose(dir->handle); - dir->handle = (handle_type) _findfirst(dir->name, &dir->info); - dir->result.d_name = 0; - } - else { - errno = EBADF; - } -} - -#ifdef __cplusplus -} -#endif - -/* - - Copyright Kevlin Henney, 1997, 2003, 2012. All rights reserved. - - Permission to use, copy, modify, and distribute this software and its - documentation for any purpose is hereby granted without fee, provided - that this copyright and permissions notice appear in all copies and - derivatives. - - This software is supplied "as is" without express or implied warranty. - - But that said, if there are any problems please get in touch. - -*/ diff --git a/mrbgems/mruby-dir/src/dir.c b/mrbgems/mruby-dir/src/dir.c index 28cc85c5d..11a8c1c7f 100644 --- a/mrbgems/mruby-dir/src/dir.c +++ b/mrbgems/mruby-dir/src/dir.c @@ -11,36 +11,15 @@ #include #include #include -#include -#if defined(_WIN32) - #define MAXPATHLEN 1024 - #if !defined(PATH_MAX) - #define PATH_MAX MAX_PATH - #endif - #define S_ISDIR(B) ((B)&_S_IFDIR) - #include "Win/dirent.c" - #include - #define rmdir(path) _rmdir(path) - #define getcwd(path,len) _getcwd(path,len) - #define mkdir(path,mode) _mkdir(path) - #define chdir(path) _chdir(path) -#else - #include - #include - #include -#endif -#include -#include -#include -#include -#include +#include "dir_hal.h" + #include #include #define E_IO_ERROR mrb_exc_get_id(mrb, MRB_SYM(IOError)) struct mrb_dir { - DIR *dir; + mrb_dir_handle *handle; }; static void @@ -48,9 +27,9 @@ mrb_dir_free(mrb_state *mrb, void *ptr) { struct mrb_dir *mdir = (struct mrb_dir*)ptr; - if (mdir->dir) { - closedir(mdir->dir); - mdir->dir = NULL; + if (mdir->handle) { + mrb_dir_hal_close(mrb, mdir->handle); + mdir->handle = NULL; } mrb_free(mrb, mdir); } @@ -73,13 +52,13 @@ mrb_dir_close(mrb_state *mrb, mrb_value self) struct mrb_dir *mdir; mdir = (struct mrb_dir*)mrb_get_datatype(mrb, self, &mrb_dir_type); if (!mdir) return mrb_nil_value(); - if (!mdir->dir) { + if (!mdir->handle) { mrb_raise(mrb, E_IO_ERROR, "closed directory"); } - if (closedir(mdir->dir) == -1) { + if (mrb_dir_hal_close(mrb, mdir->handle) == -1) { mrb_sys_fail(mrb, "closedir"); } - mdir->dir = NULL; + mdir->handle = NULL; return mrb_nil_value(); } @@ -94,7 +73,7 @@ mrb_dir_close(mrb_state *mrb, mrb_value self) static mrb_value mrb_dir_init(mrb_state *mrb, mrb_value self) { - DIR *dir; + mrb_dir_handle *handle; struct mrb_dir *mdir; const char *path; @@ -106,14 +85,14 @@ mrb_dir_init(mrb_state *mrb, mrb_value self) DATA_PTR(self) = NULL; mdir = (struct mrb_dir*)mrb_malloc(mrb, sizeof(*mdir)); - mdir->dir = NULL; + mdir->handle = NULL; DATA_PTR(self) = mdir; mrb_get_args(mrb, "z", &path); - if ((dir = opendir(path)) == NULL) { + if ((handle = mrb_dir_hal_open(mrb, path)) == NULL) { mrb_sys_fail(mrb, path); } - mdir->dir = dir; + mdir->handle = handle; return self; } @@ -132,7 +111,7 @@ mrb_dir_delete(mrb_state *mrb, mrb_value klass) const char *path; mrb_get_args(mrb, "z", &path); - if (rmdir(path) == -1) { + if (mrb_dir_hal_rmdir(mrb, path) == -1) { mrb_sys_fail(mrb, path); } return mrb_fixnum_value(0); @@ -150,11 +129,10 @@ mrb_dir_delete(mrb_state *mrb, mrb_value klass) static mrb_value mrb_dir_existp(mrb_state *mrb, mrb_value klass) { - struct stat sb; const char *path; mrb_get_args(mrb, "z", &path); - if (stat(path, &sb) == 0 && S_ISDIR(sb.st_mode)) { + if (mrb_dir_hal_is_directory(mrb, path)) { return mrb_true_value(); } else { @@ -178,7 +156,7 @@ mrb_dir_getwd(mrb_state *mrb, mrb_value klass) mrb_int size = 64; path = mrb_str_buf_new(mrb, size); - while (getcwd(RSTRING_PTR(path), (size_t)size) == NULL) { + while (mrb_dir_hal_getcwd(mrb, RSTRING_PTR(path), (size_t)size) == -1) { int e = errno; if (e != ERANGE) { mrb_sys_fail(mrb, "getcwd(2)"); @@ -210,7 +188,7 @@ mrb_dir_mkdir(mrb_state *mrb, mrb_value klass) mode = 0777; mrb_get_args(mrb, "z|i", &path, &mode); - if (mkdir(path, mode) == -1) { + if (mrb_dir_hal_mkdir(mrb, path, (int)mode) == -1) { mrb_sys_fail(mrb, path); } return mrb_fixnum_value(0); @@ -223,7 +201,7 @@ mrb_dir_chdir(mrb_state *mrb, mrb_value klass) const char *path; mrb_get_args(mrb, "z", &path); - if (chdir(path) == -1) { + if (mrb_dir_hal_chdir(mrb, path) == -1) { mrb_sys_fail(mrb, path); } return mrb_fixnum_value(0); @@ -241,21 +219,19 @@ mrb_dir_chdir(mrb_state *mrb, mrb_value klass) static mrb_value mrb_dir_chroot(mrb_state *mrb, mrb_value self) { -#if defined(_WIN32) || defined(__ANDROID__) || defined(__MSDOS__) - mrb_raise(mrb, E_NOTIMP_ERROR, "chroot() unreliable on your system"); - return mrb_fixnum_value(0); -#else const char *path; - mrb_int res; + int res; mrb_get_args(mrb, "z", &path); - res = chroot(path); + res = mrb_dir_hal_chroot(mrb, path); if (res == -1) { + if (errno == ENOSYS) { + mrb_raise(mrb, E_NOTIMP_ERROR, "chroot() unreliable on your system"); + } mrb_sys_fail(mrb, path); } return mrb_fixnum_value(res); -#endif } static mrb_bool @@ -280,22 +256,22 @@ skip_name_p(const char *name) static mrb_value mrb_dir_empty(mrb_state *mrb, mrb_value self) { - DIR *dir; - struct dirent *dp; + mrb_dir_handle *handle; + const char *name; const char *path; mrb_value result = mrb_true_value(); mrb_get_args(mrb, "z", &path); - if ((dir = opendir(path)) == NULL) { + if ((handle = mrb_dir_hal_open(mrb, path)) == NULL) { mrb_sys_fail(mrb, path); } - while ((dp = readdir(dir))) { - if (!skip_name_p(dp->d_name)) { + while ((name = mrb_dir_hal_read(mrb, handle)) != NULL) { + if (!skip_name_p(name)) { result = mrb_false_value(); break; } } - closedir(dir); + mrb_dir_hal_close(mrb, handle); return result; } @@ -315,16 +291,16 @@ static mrb_value mrb_dir_read(mrb_state *mrb, mrb_value self) { struct mrb_dir *mdir; - struct dirent *dp; + const char *name; mdir = (struct mrb_dir*)mrb_get_datatype(mrb, self, &mrb_dir_type); if (!mdir) return mrb_nil_value(); - if (!mdir->dir) { + if (!mdir->handle) { mrb_raise(mrb, E_IO_ERROR, "closed directory"); } - dp = readdir(mdir->dir); - if (dp != NULL) { - return mrb_str_new_cstr(mrb, dp->d_name); + name = mrb_dir_hal_read(mrb, mdir->handle); + if (name != NULL) { + return mrb_str_new_cstr(mrb, name); } else { return mrb_nil_value(); @@ -349,10 +325,10 @@ mrb_dir_rewind(mrb_state *mrb, mrb_value self) mdir = (struct mrb_dir*)mrb_get_datatype(mrb, self, &mrb_dir_type); if (!mdir) return mrb_nil_value(); - if (!mdir->dir) { + if (!mdir->handle) { mrb_raise(mrb, E_IO_ERROR, "closed directory"); } - rewinddir(mdir->dir); + mrb_dir_hal_rewind(mrb, mdir->handle); return self; } @@ -372,22 +348,21 @@ mrb_dir_rewind(mrb_state *mrb, mrb_value self) static mrb_value mrb_dir_seek(mrb_state *mrb, mrb_value self) { - #if defined(_WIN32) || defined(__ANDROID__) - mrb_raise(mrb, E_NOTIMP_ERROR, "dirseek() unreliable on your system"); - return self; - #else struct mrb_dir *mdir; mrb_int pos; mdir = (struct mrb_dir*)mrb_get_datatype(mrb, self, &mrb_dir_type); if (!mdir) return mrb_nil_value(); - if (!mdir->dir) { + if (!mdir->handle) { mrb_raise(mrb, E_IO_ERROR, "closed directory"); } mrb_get_args(mrb, "i", &pos); - seekdir(mdir->dir, (long)pos); + if (mrb_dir_hal_seek(mrb, mdir->handle, (long)pos) == -1) { + if (errno == ENOSYS) { + mrb_raise(mrb, E_NOTIMP_ERROR, "dirseek() unreliable on your system"); + } + } return self; - #endif } /* @@ -405,21 +380,21 @@ mrb_dir_seek(mrb_state *mrb, mrb_value self) static mrb_value mrb_dir_tell(mrb_state *mrb, mrb_value self) { -#if defined(_WIN32) || defined(__ANDROID__) - mrb_raise(mrb, E_NOTIMP_ERROR, "dirtell() unreliable on your system"); - return mrb_fixnum_value(0); -#else struct mrb_dir *mdir; - mrb_int pos; + long pos; mdir = (struct mrb_dir*)mrb_get_datatype(mrb, self, &mrb_dir_type); if (!mdir) return mrb_nil_value(); - if (!mdir->dir) { + if (!mdir->handle) { mrb_raise(mrb, E_IO_ERROR, "closed directory"); } - pos = (mrb_int)telldir(mdir->dir); - return mrb_fixnum_value(pos); -#endif + pos = mrb_dir_hal_tell(mrb, mdir->handle); + if (pos == -1) { + if (errno == ENOSYS) { + mrb_raise(mrb, E_NOTIMP_ERROR, "dirtell() unreliable on your system"); + } + } + return mrb_fixnum_value((mrb_int)pos); } /* @@ -433,23 +408,23 @@ static mrb_value mrb_dir_entries(mrb_state *mrb, mrb_value klass) { const char *path; - DIR *dir; - struct dirent *dp; + mrb_dir_handle *handle; + const char *name; mrb_value ary; mrb_get_args(mrb, "z", &path); - dir = opendir(path); - if (dir == NULL) { + handle = mrb_dir_hal_open(mrb, path); + if (handle == NULL) { mrb_sys_fail(mrb, path); } ary = mrb_ary_new(mrb); - while ((dp = readdir(dir)) != NULL) { - mrb_ary_push(mrb, ary, mrb_str_new_cstr(mrb, dp->d_name)); + while ((name = mrb_dir_hal_read(mrb, handle)) != NULL) { + mrb_ary_push(mrb, ary, mrb_str_new_cstr(mrb, name)); } - closedir(dir); + mrb_dir_hal_close(mrb, handle); return ary; } @@ -465,25 +440,25 @@ static mrb_value mrb_dir_children(mrb_state *mrb, mrb_value klass) { const char *path; - DIR *dir; - struct dirent *dp; + mrb_dir_handle *handle; + const char *name; mrb_value ary; mrb_get_args(mrb, "z", &path); - dir = opendir(path); - if (dir == NULL) { + handle = mrb_dir_hal_open(mrb, path); + if (handle == NULL) { mrb_sys_fail(mrb, path); } ary = mrb_ary_new(mrb); - while ((dp = readdir(dir)) != NULL) { - if (!skip_name_p(dp->d_name)) { - mrb_ary_push(mrb, ary, mrb_str_new_cstr(mrb, dp->d_name)); + while ((name = mrb_dir_hal_read(mrb, handle)) != NULL) { + if (!skip_name_p(name)) { + mrb_ary_push(mrb, ary, mrb_str_new_cstr(mrb, name)); } } - closedir(dir); + mrb_dir_hal_close(mrb, handle); return ary; } @@ -492,6 +467,8 @@ mrb_mruby_dir_gem_init(mrb_state *mrb) { struct RClass *d; + mrb_dir_hal_init(mrb); + d = mrb_define_class_id(mrb, MRB_SYM(Dir), mrb->object_class); MRB_SET_INSTANCE_TT(d, MRB_TT_DATA); mrb_define_class_method_id(mrb, d, MRB_SYM(delete), mrb_dir_delete, MRB_ARGS_REQ(1)); @@ -517,4 +494,5 @@ mrb_mruby_dir_gem_init(mrb_state *mrb) void mrb_mruby_dir_gem_final(mrb_state *mrb) { + mrb_dir_hal_final(mrb); }