mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
mruby-dir: introduce HAL for platform abstraction
platform-specific directory operations separated into hal-posix-dir and hal-win-dir gems. this allows mruby-dir to support embedded platforms and simplifies platform-specific implementations. Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -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
|
||||
@@ -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 <mruby.h>
|
||||
#include "dir_hal.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <dirent.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
#ifdef HAVE_SYS_PARAM_H
|
||||
#include <sys/param.h>
|
||||
#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 */
|
||||
}
|
||||
@@ -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
|
||||
@@ -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 <mruby.h>
|
||||
#include "dir_hal.h"
|
||||
|
||||
#include <windows.h>
|
||||
#include <direct.h>
|
||||
#include <io.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
@@ -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 <mruby.h>
|
||||
|
||||
/*
|
||||
* 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 */
|
||||
@@ -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
|
||||
|
||||
@@ -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 <errno.h>
|
||||
#include <io.h> /* _findfirst and _findnext set errno iff they return -1 */
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#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.
|
||||
|
||||
*/
|
||||
+69
-91
@@ -11,36 +11,15 @@
|
||||
#include <mruby/error.h>
|
||||
#include <mruby/string.h>
|
||||
#include <mruby/presym.h>
|
||||
#include <sys/types.h>
|
||||
#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 <direct.h>
|
||||
#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 <sys/param.h>
|
||||
#include <dirent.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
#include "dir_hal.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user