Skip to content

Commit

Permalink
Welp, that did not work out
Browse files Browse the repository at this point in the history
  • Loading branch information
herwinw committed Jul 10, 2024
1 parent c4937a6 commit 9f40640
Show file tree
Hide file tree
Showing 3 changed files with 22 additions and 11 deletions.
3 changes: 3 additions & 0 deletions include/natalie/io_object.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ class IoObject : public Object {
static Value binwrite(Env *, Args);
Value binmode(Env *);
Value close(Env *);
Value close_read(Env *);
static Value copy_stream(Env *, Value, Value, Value = nullptr, Value = nullptr);
Value dup(Env *) const;
Value each_byte(Env *, Block *);
Expand All @@ -78,6 +79,7 @@ class IoObject : public Object {
bool is_close_on_exec(Env *) const;
bool is_eof(Env *);
bool is_nonblock(Env *) const;
bool is_readable() const;
bool isatty(Env *) const;
int lineno(Env *) const;
Value pid(Env *) const;
Expand Down Expand Up @@ -147,6 +149,7 @@ class IoObject : public Object {
int m_fileno { -1 };
FILE *m_fileptr { nullptr };
int m_pid { -1 };
bool m_is_readable { true };
int m_lineno { 0 };
std::atomic<bool> m_closed { false };
bool m_autoclose { true };
Expand Down
1 change: 1 addition & 0 deletions lib/natalie/compiler/binding_gen.rb
Original file line number Diff line number Diff line change
Expand Up @@ -891,6 +891,7 @@ def generate_name
gen.binding('IO', 'binmode', 'IoObject', 'binmode', argc: 0, pass_env: true, pass_block: false, return_type: :Object)
gen.binding('IO', 'binmode?', 'IoObject', 'is_binmode', argc: 0, pass_env: true, pass_block: false, return_type: :bool)
gen.binding('IO', 'close', 'IoObject', 'close', argc: 0, pass_env: true, pass_block: false, return_type: :Object)
gen.binding('IO', 'close_read', 'IoObject', 'close_read', argc: 0, pass_env: true, pass_block: false, return_type: :Object)
gen.binding('IO', 'closed?', 'IoObject', 'is_closed', argc: 0, pass_env: false, pass_block: false, return_type: :bool)
gen.binding('IO', 'close_on_exec?', 'IoObject', 'is_close_on_exec', argc: 0, pass_env: true, pass_block: false, return_type: :bool)
gen.binding('IO', 'close_on_exec=', 'IoObject', 'set_close_on_exec', argc: 1, pass_env: true, pass_block: false, return_type: :Object)
Expand Down
29 changes: 18 additions & 11 deletions src/io_object.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,14 @@ static inline bool flags_is_writable(const int flags) {
return (flags & (O_RDONLY | O_WRONLY | O_RDWR)) != O_RDONLY;
}

static inline bool is_readable(const int fd) {
return flags_is_readable(fcntl(fd, F_GETFL));
}

static inline bool is_writable(const int fd) {
return flags_is_writable(fcntl(fd, F_GETFL));
}

static void throw_unless_readable(Env *env, const IoObject *const self) {
// read(2) assigns EBADF to errno if not readable, we want an IOError instead
const auto old_errno = errno;
if (!is_readable(self->fileno(env)))
if (!self->is_readable())
env->raise("IOError", "not opened for reading");
errno = old_errno; // errno may have been changed by fcntl, revert to the old value
env->raise_errno();
Expand Down Expand Up @@ -245,7 +241,7 @@ bool IoObject::is_close_on_exec(Env *env) const {

bool IoObject::is_eof(Env *env) {
raise_if_closed(env);
if (!is_readable(m_fileno))
if (!is_readable())
env->raise("IOError", "not opened for reading");
if (!m_read_buffer.is_empty())
return false;
Expand All @@ -262,14 +258,20 @@ bool IoObject::is_nonblock(Env *env) const {
return (flags & O_NONBLOCK);
}

bool IoObject::is_readable() const {
if (!m_is_readable)
return false;
return flags_is_readable(::fcntl(fileno(), F_GETFL));
}

bool IoObject::isatty(Env *env) const {
raise_if_closed(env);
return ::isatty(m_fileno) == 1;
}

int IoObject::lineno(Env *env) const {
raise_if_closed(env);
if (!is_readable(m_fileno))
if (!is_readable())
env->raise("IOError", "not opened for reading");
return m_lineno;
}
Expand Down Expand Up @@ -434,7 +436,7 @@ Value IoObject::copy_stream(Env *env, Value src, Value dst, Value src_length, Va
Value data = new StringObject {};
if (src->is_io() || src->respond_to(env, "to_io"_s)) {
auto src_io = src->to_io(env);
if (!is_readable(src_io->fileno(env)))
if (!src_io->is_readable())
env->raise("IOError", "not opened for reading");
if (src_offset && !src_offset->is_nil()) {
src_io->pread(env, src_length, src_offset, data);
Expand Down Expand Up @@ -580,7 +582,7 @@ Value IoObject::pid(Env *env) const {

Value IoObject::pread(Env *env, Value count, Value offset, Value out_string) {
raise_if_closed(env);
if (!is_readable(m_fileno))
if (!is_readable())
env->raise("IOError", "not opened for reading");
const auto count_int = count->to_int(env)->to_nat_int_t();
if (count_int < 0)
Expand Down Expand Up @@ -714,6 +716,11 @@ Value IoObject::close(Env *env) {
return NilObject::the();
}

Value IoObject::close_read(Env *env) {
m_is_readable = false;
return NilObject::the();
}

Value IoObject::seek(Env *env, Value amount_value, Value whence_value) {
raise_if_closed(env);
nat_int_t amount = IntegerObject::convert_to_nat_int_t(env, amount_value);
Expand Down Expand Up @@ -795,7 +802,7 @@ Value IoObject::set_encoding(Env *env, Value ext_enc, Value int_enc) {

Value IoObject::set_lineno(Env *env, Value lineno) {
raise_if_closed(env);
if (!is_readable(m_fileno))
if (!is_readable())
env->raise("IOError", "not opened for reading");
m_lineno = IntegerObject::convert_to_int(env, lineno);
return lineno;
Expand Down Expand Up @@ -865,7 +872,7 @@ Value IoObject::try_convert(Env *env, Value val) {

Value IoObject::ungetbyte(Env *env, Value byte) {
raise_if_closed(env);
if (!is_readable(m_fileno))
if (!is_readable())
env->raise("IOError", "not opened for reading");
if (!byte || byte->is_nil())
return NilObject::the();
Expand Down

0 comments on commit 9f40640

Please sign in to comment.