mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
07b803e28a
Replace XML-style markup tags in comments with markdown equivalents: - <code>...</code> to `...` (inline code) - <tt>...</tt> to `...` (teletype/monospace) - <i>...</i> to *...* (italics/emphasis) - +...+ to `...` (parameter/variable references) Updated 80+ files across core source, headers, mrbgems, and libraries to use consistent markdown formatting in documentation comments. Handled edge cases including special characters like <=> operators. Co-authored-by: Atlassian Rovo Dev
366 lines
7.9 KiB
C
366 lines
7.9 KiB
C
/*
|
|
** file_test.c - FileTest class
|
|
*/
|
|
|
|
#include <mruby.h>
|
|
#include <mruby/class.h>
|
|
#include <mruby/data.h>
|
|
#include <mruby/string.h>
|
|
#include <mruby/ext/io.h>
|
|
#include <mruby/error.h>
|
|
#include <mruby/presym.h>
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
|
|
#if defined(_WIN32)
|
|
#define LSTAT stat
|
|
#include <winsock.h>
|
|
#else
|
|
#define LSTAT lstat
|
|
#include <sys/file.h>
|
|
#include <sys/param.h>
|
|
#include <sys/wait.h>
|
|
#ifndef __DJGPP__
|
|
#include <libgen.h>
|
|
#endif
|
|
#include <pwd.h>
|
|
#include <unistd.h>
|
|
#endif
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <errno.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
extern struct mrb_data_type mrb_io_type;
|
|
|
|
static int
|
|
mrb_stat0(mrb_state *mrb, mrb_value obj, struct stat *st, int do_lstat)
|
|
{
|
|
if (mrb_obj_is_kind_of(mrb, obj, mrb_class_get_id(mrb, MRB_SYM(IO)))) {
|
|
struct mrb_io *fptr;
|
|
fptr = (struct mrb_io*)mrb_data_get_ptr(mrb, obj, &mrb_io_type);
|
|
|
|
if (fptr && fptr->fd >= 0) {
|
|
return fstat(fptr->fd, st);
|
|
}
|
|
|
|
mrb_raise(mrb, E_IO_ERROR, "closed stream");
|
|
return -1;
|
|
}
|
|
else {
|
|
char *path = mrb_locale_from_utf8(RSTRING_CSTR(mrb, obj), -1);
|
|
int ret;
|
|
if (do_lstat) {
|
|
ret = LSTAT(path, st);
|
|
}
|
|
else {
|
|
ret = stat(path, st);
|
|
}
|
|
mrb_locale_free(path);
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
static int
|
|
mrb_stat(mrb_state *mrb, mrb_value obj, struct stat *st)
|
|
{
|
|
return mrb_stat0(mrb, obj, st, 0);
|
|
}
|
|
|
|
#ifdef S_ISLNK
|
|
static int
|
|
mrb_lstat(mrb_state *mrb, mrb_value obj, struct stat *st)
|
|
{
|
|
return mrb_stat0(mrb, obj, st, 1);
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* call-seq:
|
|
* File.directory?(file_name) -> true or false
|
|
*
|
|
* Returns `true` if the named file is a directory, or a symlink that points at a directory, and `false`
|
|
* otherwise.
|
|
*
|
|
* File.directory?(".") #=> true
|
|
*/
|
|
|
|
static mrb_value
|
|
mrb_filetest_s_directory_p(mrb_state *mrb, mrb_value klass)
|
|
{
|
|
#ifndef S_ISDIR
|
|
# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
|
|
#endif
|
|
|
|
struct stat st;
|
|
mrb_value obj = mrb_get_arg1(mrb);
|
|
|
|
if (mrb_stat(mrb, obj, &st) < 0)
|
|
return mrb_false_value();
|
|
if (S_ISDIR(st.st_mode))
|
|
return mrb_true_value();
|
|
|
|
return mrb_false_value();
|
|
}
|
|
|
|
/*
|
|
* call-seq:
|
|
* File.pipe?(file_name) -> true or false
|
|
*
|
|
* Returns `true` if the named file is a pipe.
|
|
*
|
|
* File.pipe?("/dev/stdin") #=> true
|
|
*/
|
|
|
|
static mrb_value
|
|
mrb_filetest_s_pipe_p(mrb_state *mrb, mrb_value klass)
|
|
{
|
|
#if defined(_WIN32)
|
|
mrb_raise(mrb, E_NOTIMP_ERROR, "pipe is not supported on this platform");
|
|
#else
|
|
#ifdef S_IFIFO
|
|
# ifndef S_ISFIFO
|
|
# define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
|
|
# endif
|
|
|
|
struct stat st;
|
|
mrb_value obj = mrb_get_arg1(mrb);
|
|
|
|
if (mrb_stat(mrb, obj, &st) < 0)
|
|
return mrb_false_value();
|
|
if (S_ISFIFO(st.st_mode))
|
|
return mrb_true_value();
|
|
|
|
#endif
|
|
return mrb_false_value();
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
* call-seq:
|
|
* File.symlink?(file_name) -> true or false
|
|
*
|
|
* Returns `true` if the named file is a symbolic link.
|
|
*
|
|
* File.symlink?("link-to-test") #=> true
|
|
*/
|
|
|
|
static mrb_value
|
|
mrb_filetest_s_symlink_p(mrb_state *mrb, mrb_value klass)
|
|
{
|
|
#if defined(_WIN32)
|
|
mrb_raise(mrb, E_NOTIMP_ERROR, "symlink is not supported on this platform");
|
|
#else
|
|
#ifndef S_ISLNK
|
|
# ifdef _S_ISLNK
|
|
# define S_ISLNK(m) _S_ISLNK(m)
|
|
# else
|
|
# ifdef _S_IFLNK
|
|
# define S_ISLNK(m) (((m) & S_IFMT) == _S_IFLNK)
|
|
# else
|
|
# ifdef S_IFLNK
|
|
# define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
|
|
# endif
|
|
# endif
|
|
# endif
|
|
#endif
|
|
|
|
#ifdef S_ISLNK
|
|
struct stat st;
|
|
mrb_value obj = mrb_get_arg1(mrb);
|
|
|
|
if (mrb_lstat(mrb, obj, &st) == -1)
|
|
return mrb_false_value();
|
|
if (S_ISLNK(st.st_mode))
|
|
return mrb_true_value();
|
|
#endif
|
|
|
|
return mrb_false_value();
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
* call-seq:
|
|
* File.socket?(file_name) -> true or false
|
|
*
|
|
* Returns `true` if the named file is a socket.
|
|
*
|
|
* File.socket?("/tmp/.X11-unix/X0") #=> true
|
|
*/
|
|
|
|
static mrb_value
|
|
mrb_filetest_s_socket_p(mrb_state *mrb, mrb_value klass)
|
|
{
|
|
#if defined(_WIN32)
|
|
mrb_raise(mrb, E_NOTIMP_ERROR, "socket is not supported on this platform");
|
|
#else
|
|
#ifndef S_ISSOCK
|
|
# ifdef _S_ISSOCK
|
|
# define S_ISSOCK(m) _S_ISSOCK(m)
|
|
# else
|
|
# ifdef _S_IFSOCK
|
|
# define S_ISSOCK(m) (((m) & S_IFMT) == _S_IFSOCK)
|
|
# else
|
|
# ifdef S_IFSOCK
|
|
# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
|
|
# endif
|
|
# endif
|
|
# endif
|
|
#endif
|
|
|
|
#ifdef S_ISSOCK
|
|
struct stat st;
|
|
mrb_value obj = mrb_get_arg1(mrb);
|
|
|
|
if (mrb_stat(mrb, obj, &st) < 0)
|
|
return mrb_false_value();
|
|
if (S_ISSOCK(st.st_mode))
|
|
return mrb_true_value();
|
|
#endif
|
|
|
|
return mrb_false_value();
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
* call-seq:
|
|
* File.exist?(file_name) -> true or false
|
|
* File.exists?(file_name) -> true or false
|
|
*
|
|
* Returns `true` if the named file exists.
|
|
*
|
|
* File.exist?("config.h") #=> true
|
|
* File.exist?("no_such_file") #=> false
|
|
*/
|
|
|
|
static mrb_value
|
|
mrb_filetest_s_exist_p(mrb_state *mrb, mrb_value klass)
|
|
{
|
|
struct stat st;
|
|
mrb_value obj = mrb_get_arg1(mrb);
|
|
|
|
if (mrb_stat(mrb, obj, &st) < 0)
|
|
return mrb_false_value();
|
|
|
|
return mrb_true_value();
|
|
}
|
|
|
|
/*
|
|
* call-seq:
|
|
* File.file?(file_name) -> true or false
|
|
*
|
|
* Returns `true` if the named file exists and is a regular file.
|
|
*
|
|
* File.file?("testfile") #=> true
|
|
*/
|
|
|
|
static mrb_value
|
|
mrb_filetest_s_file_p(mrb_state *mrb, mrb_value klass)
|
|
{
|
|
#ifndef S_ISREG
|
|
# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
|
|
#endif
|
|
|
|
struct stat st;
|
|
mrb_value obj = mrb_get_arg1(mrb);
|
|
|
|
if (mrb_stat(mrb, obj, &st) < 0)
|
|
return mrb_false_value();
|
|
if (S_ISREG(st.st_mode))
|
|
return mrb_true_value();
|
|
|
|
return mrb_false_value();
|
|
}
|
|
|
|
/*
|
|
* call-seq:
|
|
* File.zero?(file_name) -> true or false
|
|
*
|
|
* Returns `true` if the named file exists and has a zero size.
|
|
*
|
|
* File.zero?("testfile") #=> false
|
|
*/
|
|
|
|
static mrb_value
|
|
mrb_filetest_s_zero_p(mrb_state *mrb, mrb_value klass)
|
|
{
|
|
struct stat st;
|
|
mrb_value obj = mrb_get_arg1(mrb);
|
|
|
|
if (mrb_stat(mrb, obj, &st) < 0)
|
|
return mrb_false_value();
|
|
if (st.st_size == 0)
|
|
return mrb_true_value();
|
|
|
|
return mrb_false_value();
|
|
}
|
|
|
|
/*
|
|
* call-seq:
|
|
* File.size(file_name) -> integer
|
|
*
|
|
* Returns the size of `file_name`.
|
|
*
|
|
* `file_name` can be an IO object.
|
|
*
|
|
* File.size("testfile") #=> 66
|
|
*/
|
|
|
|
static mrb_value
|
|
mrb_filetest_s_size(mrb_state *mrb, mrb_value klass)
|
|
{
|
|
struct stat st;
|
|
mrb_value obj = mrb_get_arg1(mrb);
|
|
|
|
if (mrb_stat(mrb, obj, &st) < 0)
|
|
mrb_sys_fail(mrb, "mrb_stat");
|
|
|
|
return mrb_int_value(mrb, st.st_size);
|
|
}
|
|
|
|
/*
|
|
* call-seq:
|
|
* File.size?(file_name) -> Integer or nil
|
|
*
|
|
* Returns `nil` if `file_name` doesn't exist or has zero size, the size of the
|
|
* file otherwise.
|
|
*
|
|
* File.size?("testfile") #=> 66
|
|
*/
|
|
|
|
static mrb_value
|
|
mrb_filetest_s_size_p(mrb_state *mrb, mrb_value klass)
|
|
{
|
|
struct stat st;
|
|
mrb_value obj = mrb_get_arg1(mrb);
|
|
|
|
if (mrb_stat(mrb, obj, &st) < 0)
|
|
return mrb_nil_value();
|
|
if (st.st_size == 0)
|
|
return mrb_nil_value();
|
|
|
|
return mrb_int_value(mrb, st.st_size);
|
|
}
|
|
|
|
void
|
|
mrb_init_file_test(mrb_state *mrb)
|
|
{
|
|
struct RClass *f;
|
|
|
|
f = mrb_define_module_id(mrb, MRB_SYM(FileTest));
|
|
|
|
mrb_define_class_method_id(mrb, f, MRB_SYM_Q(directory), mrb_filetest_s_directory_p, MRB_ARGS_REQ(1));
|
|
mrb_define_class_method_id(mrb, f, MRB_SYM_Q(exist), mrb_filetest_s_exist_p, MRB_ARGS_REQ(1));
|
|
mrb_define_class_method_id(mrb, f, MRB_SYM_Q(exists), mrb_filetest_s_exist_p, MRB_ARGS_REQ(1));
|
|
mrb_define_class_method_id(mrb, f, MRB_SYM_Q(file), mrb_filetest_s_file_p, MRB_ARGS_REQ(1));
|
|
mrb_define_class_method_id(mrb, f, MRB_SYM_Q(pipe), mrb_filetest_s_pipe_p, MRB_ARGS_REQ(1));
|
|
mrb_define_class_method_id(mrb, f, MRB_SYM(size), mrb_filetest_s_size, MRB_ARGS_REQ(1));
|
|
mrb_define_class_method_id(mrb, f, MRB_SYM_Q(size), mrb_filetest_s_size_p, MRB_ARGS_REQ(1));
|
|
mrb_define_class_method_id(mrb, f, MRB_SYM_Q(socket), mrb_filetest_s_socket_p, MRB_ARGS_REQ(1));
|
|
mrb_define_class_method_id(mrb, f, MRB_SYM_Q(symlink), mrb_filetest_s_symlink_p, MRB_ARGS_REQ(1));
|
|
mrb_define_class_method_id(mrb, f, MRB_SYM_Q(zero), mrb_filetest_s_zero_p, MRB_ARGS_REQ(1));
|
|
}
|