#ifndef RUBY_IO_H /*-*-C++-*-vi:se ft=cpp:*/
* @date Fri Nov 12 16:47:09 JST 1993
* @copyright Copyright (C) 1993-2007 Yukihiro Matsumoto
* @copyright This file is a part of the programming language Ruby.
* Permission is hereby granted, to either redistribute and/or
* modify this file, provided that the conditions mentioned in the
* file COPYING are met. Consult the file for details.
#include "ruby/internal/config.h"
#include "ruby/encoding.h"
#if defined(HAVE_STDIO_EXT_H)
/** @cond INTERNAL_MACRO */
# define reqevents events
# define rtnevents revents
# define RB_WAITFD_IN POLLIN
# define RB_WAITFD_PRI POLLPRI
# define RB_WAITFD_OUT POLLOUT
# define RB_WAITFD_IN 0x001
# define RB_WAITFD_PRI 0x002
# define RB_WAITFD_OUT 0x004
#include "ruby/internal/attr/const.h"
#include "ruby/internal/attr/pure.h"
#include "ruby/internal/attr/noreturn.h"
#include "ruby/internal/dllexport.h"
#include "ruby/internal/value.h"
#include "ruby/backward/2/attributes.h" /* PACKED_STRUCT_UNALIGNED */
// IO#wait, IO#wait_readable, IO#wait_writable, IO#wait_priority are defined by this implementation.
#define RUBY_IO_WAIT_METHODS
// Used as the default timeout argument to `rb_io_wait` to use the `IO#timeout` value.
#define RUBY_IO_TIMEOUT_DEFAULT Qnil
RBIMPL_SYMBOL_EXPORT_BEGIN()
* Indicates that a timeout has occurred while performing an IO operation.
RUBY_EXTERN VALUE rb_eIOTimeoutError;
* Type of events that an IO can wait.
* This is visible from extension libraries because `io/wait` wants it.
RUBY_IO_READABLE = RB_WAITFD_IN, /**< `IO::READABLE` */
RUBY_IO_WRITABLE = RB_WAITFD_OUT, /**< `IO::WRITABLE` */
RUBY_IO_PRIORITY = RB_WAITFD_PRI, /**< `IO::PRIORITY` */
* IO buffers. This is an implementation detail of ::rb_io_t::wbuf and
* ::rb_io_t::rbuf. People don't manipulate it directly.
PACKED_STRUCT_UNALIGNED(struct rb_io_buffer_t {
/** Pointer to the underlying memory region, of at least `capa` bytes. */
char *ptr; /* off + len <= capa */
/** Offset inside of `ptr`. */
/** Length of the buffer. */
/** Designed capacity of the buffer. */
/** @alias{rb_io_buffer_t} */
typedef struct rb_io_buffer_t rb_io_buffer_t;
/** Decomposed encoding flags (e.g. `"enc:enc2""`). */
* enc enc2 read action write action
* NULL NULL force_encoding(default_external) write the byte sequence of str
* e1 NULL force_encoding(e1) convert str.encoding to e1
* e1 e2 convert from e2 to e1 convert str.encoding to e2
/** Internal encoding. */
/** External encoding. */
* @see enum ::ruby_econv_flag_type
* This is set. But used from nowhere maybe?
/** Ruby's IO, metadata and buffers. */
/** The IO's Ruby level counterpart. */
/** stdio ptr for read/write, if available. */
/** mode flags: FMODE_XXXs */
/** child's pid (for pipes) */
/** number of lines read */
void (*finalize)(struct rb_io_t*,int);
* (Byte) read buffer. Note also that there is a field called
* ::rb_io_t::cbuf, which also concerns read IO.
* Duplex IO object, if set.
* @see rb_io_set_write_io()
VALUE tied_io_for_writing;
struct rb_io_enc_t encs; /**< Decomposed encoding flags. */
/** Encoding converter used when reading from this IO. */
* rb_io_ungetc() destination. This buffer is read before checking
/** Encoding converter used when writing to this IO. */
* This is, when set, an instance of ::rb_cString which holds the "common"
* encoding. Write conversion can convert strings twice... In case
* conversion from encoding X to encoding Y does not exist, Ruby finds an
* encoding Z that bridges the two, so that X to Z to Y conversion happens.
VALUE writeconv_asciicompat;
/** Whether ::rb_io_t::writeconv is already set up. */
int writeconv_initialized;
* Value of ::rb_io_t::rb_io_enc_t::ecflags stored right before
* initialising ::rb_io_t::writeconv.
int writeconv_pre_ecflags;
* Value of ::rb_io_t::rb_io_enc_t::ecopts stored right before initialising
VALUE writeconv_pre_ecopts;
* This is a Ruby level mutex. It avoids multiple threads to write to an
* IO at once; helps for instance rb_io_puts() to ensure newlines right
* This of course doesn't help inter-process IO interleaves, though.
* The timeout associated with this IO when performing blocking operations.
/** @alias{rb_io_enc_t} */
typedef struct rb_io_enc_t rb_io_enc_t;
* @deprecated This macro once was a thing in the old days, but makes no sense
* any longer today. Exists here for backwards compatibility
* only. You can safely forget about it.
* @name Possible flags for ::rb_io_t::mode
/** The IO is opened for reading. */
#define FMODE_READABLE 0x00000001
/** The IO is opened for writing. */
#define FMODE_WRITABLE 0x00000002
/** The IO is opened for both read/write. */
#define FMODE_READWRITE (FMODE_READABLE|FMODE_WRITABLE)
* The IO is in "binary mode". This is not what everything rb_io_binmode()
* concerns. This low-level flag is to stop CR <-> CRLF conversions that would
* happen in the underlying operating system.
* Setting this one and #FMODE_TEXTMODE at the same time is a contradiction.
* Setting this one and #ECONV_NEWLINE_DECORATOR_MASK at the same time is also
#define FMODE_BINMODE 0x00000004
* The IO is in "sync mode". All output is immediately flushed to the
* underlying operating system then. Can be set via rb_io_synchronized(), but
* there is no way except calling `IO#sync=` to reset.
#define FMODE_SYNC 0x00000008
* The IO is a TTY. What is a TTY and what isn't depends on the underlying
* operating system's `isatty(3)` output. You cannot change this.
#define FMODE_TTY 0x00000010
* Ruby eventually detects that the IO is bidirectional. For instance a TTY
* has such property. There are several other things known to be duplexed.
* Additionally you (extension library authors) can also implement your own
* bidirectional IO subclasses. One of such example is `Socket`.
#define FMODE_DUPLEX 0x00000020
* The IO is opened for appending. This mode always writes at the end of the
* IO. Ruby manages this flag for record but basically the logic behind this
* mode is at the underlying operating system. We almost do nothing.
#define FMODE_APPEND 0x00000040
* The IO is opened for creating. This makes sense only when the destination
* file does not exist at the time the IO object was created. This is the
* default mode for writing, but you can pass `"r+"` to `IO.open` etc., to
#define FMODE_CREATE 0x00000080
/* #define FMODE_NOREVLOOKUP 0x00000100 */
* This flag amends the effect of #FMODE_CREATE, so that if there already is a
* file at the given path the operation fails. Using this you can be sure that
* the file you get is a fresh new one.
#define FMODE_EXCL 0x00000400
* This flag amends the effect of #FMODE_CREATE, so that if there already is a
* file at the given path it gets truncated.
#define FMODE_TRUNC 0x00000800
* The IO is in "text mode". On systems where such mode make sense, this flag
* changes the way the IO handles the contents. On POSIX systems it is
* basically a no-op, but with this flag set you can optionally let Ruby
* manually convert newlines, unlike when in binary mode:
* IO.open("/p/a/t/h", "wt", crlf_newline: true) # "wb" is NG.
* Setting this one and #FMODE_BINMODE at the same time is a contradiction.
#define FMODE_TEXTMODE 0x00001000
/* #define FMODE_PREP 0x00010000 */
/* #define FMODE_SIGNAL_ON_EPIPE 0x00020000 */
* This flag amends the encoding of the IO so that the BOM of the contents of
#define FMODE_SETENC_BY_BOM 0x00100000
/* #define FMODE_UNIX 0x00200000 */
/* #define FMODE_INET 0x00400000 */
/* #define FMODE_INET6 0x00800000 */
* Queries the underlying IO pointer.
* @param[in] obj An IO object.
* @param[out] fp A variable of type ::rb_io_t.
* @exception rb_eFrozenError `obj` is frozen.
* @exception rb_eIOError `obj` is closed.
* @post `fp` holds `obj`'s underlying IO.
#define RB_IO_POINTER(obj,fp) rb_io_check_closed((fp) = RFILE(rb_io_taint_check(obj))->fptr)
* This is an old name of #RB_IO_POINTER. Not sure if we want to deprecate
* this macro. There still are tons of usages out there in the wild.
#define GetOpenFile RB_IO_POINTER
* Fills an IO object. This makes the best sense when called from inside of an
* `#initialize` method of a 3rd party extension library that inherits
* If the passed IO is already opened for something it first closes that and
* opens a new one instead.
* @param[out] obj An IO object to fill in.
* @param[out] fp A variable of type ::rb_io_t.
* @exception rb_eTypeError `obj` is not ::RUBY_T_FILE.
* @post `fp` holds `obj`'s underlying IO.
#define RB_IO_OPEN(obj, fp) do {\
(fp) = rb_io_make_open_file(obj);\
* This is an old name of #RB_IO_OPEN. Not sure if we want to deprecate this
* macro. There still are usages out there in the wild.
#define MakeOpenFile RB_IO_OPEN
* This is an implementation detail of #RB_IO_OPEN. People don't use it
* @param[out] obj An IO object to fill in.
* @exception rb_eTypeError `obj` is not ::RUBY_T_FILE.
* @return `obj`'s backend IO.
* @post `obj` is initialised.
rb_io_t *rb_io_make_open_file(VALUE obj);
* Finds or creates a stdio's file structure from a Ruby's one. This can be
* handy if you want to call an external API that accepts `FILE *`.
* @note Note however, that `FILE`s can have their own buffer. Mixing Ruby's
* and stdio's file are basically dangerous. Use with care.
* @param[in,out] fptr Target IO.
* @return A stdio's file, created if absent.
* @post `fptr` has its corresponding stdio's file.
* We had rich support for `FILE` before! In the days of 1.8.x ::rb_io_t was
* typedef struct rb_io_t {
* FILE *f; // stdio ptr for read/write
* FILE *f2; // additional ptr for rw pipes
* int mode; // mode flags
* int pid; // child's pid (for pipes)
* int lineno; // number of lines read
* char *path; // pathname for file
* void (*finalize) _((struct rb_io_t*,int)); // finalize proc
* But we eventually abandoned this layout. It was too difficult. We could
* not have fine-grained control over the `f` field.
* - `FILE` tends to be an opaque struct. It does not interface well with
* `select(2)` etc. This makes IO multiplexing quite hard. Using stdio,
* there is arguably no portable way to know if `fwrite(3)` blocks.
* - Nonblocking mode, which is another core concept that enables IO
* multiplexing, does not interface with stdio routines at all.
* - Detection of duplexed IO is also hard for the same reason.
* - `feof(3)` is not portable.
* https://mail.python.org/pipermail/python-dev/2001-January/011390.html
* - Solaris was a thing back then. They could not have more than 256 `FILE`
* structures at a time. Their file descriptors ware stored in an
* - It is next to impossible to avoid SEGV, especially when a thread tries to
* `ungetc(3)`-ing from a `FILE` which is `fread(3)`-ed by another one.
* In short, it is a bad idea to let someone else manage IO buffers, especially
* someone you cannot control. This still applies to extension libraries
* methinks. Ruby doesn't prevent you from shooting yourself in the foot, but
* consider yourself warned here.
FILE *rb_io_stdio_file(rb_io_t *fptr);
* Identical to rb_io_stdio_file(), except it takes file descriptors instead of
* Ruby's IO. It can also be seen as a compatibility layer to wrap
* `fdopen(3)`. Nowadays all supporting systems, including Windows, have
* `fdopen`. Why not use them.
* @param[in] fd A file descriptor.
* @param[in] modestr C string, something like `"r+"`.
* @exception rb_eSystemCallError `fdopen` failed for some reason.
* @return A stdio's file associated with `fd`.
* @note Interpretation of `modestr` depends on the underlying operating
* system. On glibc you might be able to pass e.g. `"rm"`, but
* that's an extension to POSIX.
FILE *rb_fdopen(int fd, const char *modestr);
* Maps a file mode string (that rb_file_open() takes) into a mixture of
* `FMODE_` flags. This for instance returns
* `FMODE_WRITABLE | FMODE_TRUNC | FMODE_CREATE | FMODE_EXCL` for `"wx"`.
* @note You cannot pass this return value to OS provided `open(2)` etc.
* @param[in] modestr File mode, in C's string.
* @exception rb_eArgError `modestr` is broken.
* @return A set of flags.
* rb_io_modestr_fmode() is not a pure function because it raises.
int rb_io_modestr_fmode(const char *modestr);
* Identical to rb_io_modestr_fmode(), except it returns a mixture of `O_`
* flags. This for instance returns `O_WRONLY | O_TRUNC | O_CREAT | O_EXCL` for
* @param[in] modestr File mode, in C's string.
* @exception rb_eArgError `modestr` is broken.
* @return A set of flags.