summaryrefslogtreecommitdiff
path: root/include/ruby/io.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/ruby/io.h')
-rw-r--r--include/ruby/io.h370
1 files changed, 240 insertions, 130 deletions
diff --git a/include/ruby/io.h b/include/ruby/io.h
index 88029b1bb9..ed0967abad 100644
--- a/include/ruby/io.h
+++ b/include/ruby/io.h
@@ -49,11 +49,11 @@
/** @endcond */
#include "ruby/internal/attr/const.h"
+#include "ruby/internal/attr/packed_struct.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
@@ -66,6 +66,21 @@ RBIMPL_SYMBOL_EXPORT_BEGIN()
struct stat;
struct timeval;
+#if defined(HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC)
+# define RUBY_USE_STATX 0
+#elif defined(HAVE_STRUCT_STATX_STX_BTIME)
+# define RUBY_USE_STATX 1
+struct statx;
+#else
+# define RUBY_USE_STATX 0
+#endif
+
+#if RUBY_USE_STATX
+typedef struct statx rb_io_stat_data;
+#else
+typedef struct stat rb_io_stat_data;
+#endif
+
/**
* Indicates that a timeout has occurred while performing an IO operation.
*/
@@ -78,17 +93,20 @@ RUBY_EXTERN VALUE rb_eIOTimeoutError;
*
* This is visible from extension libraries because `io/wait` wants it.
*/
-typedef enum {
+enum rb_io_event {
RUBY_IO_READABLE = RB_WAITFD_IN, /**< `IO::READABLE` */
RUBY_IO_WRITABLE = RB_WAITFD_OUT, /**< `IO::WRITABLE` */
RUBY_IO_PRIORITY = RB_WAITFD_PRI, /**< `IO::PRIORITY` */
-} rb_io_event_t;
+};
+
+typedef enum rb_io_event rb_io_event_t;
/**
* 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 {
+RBIMPL_ATTR_PACKED_STRUCT_UNALIGNED_BEGIN()
+struct rb_io_internal_buffer {
/** Pointer to the underlying memory region, of at least `capa` bytes. */
char *ptr; /* off + len <= capa */
@@ -101,10 +119,10 @@ PACKED_STRUCT_UNALIGNED(struct rb_io_buffer_t {
/** Designed capacity of the buffer. */
int capa;
-});
+} RBIMPL_ATTR_PACKED_STRUCT_UNALIGNED_END();
/** @alias{rb_io_buffer_t} */
-typedef struct rb_io_buffer_t rb_io_buffer_t;
+typedef struct rb_io_internal_buffer rb_io_buffer_t;
/** Decomposed encoding flags (e.g. `"enc:enc2""`). */
/*
@@ -113,7 +131,7 @@ typedef struct rb_io_buffer_t rb_io_buffer_t;
* e1 NULL force_encoding(e1) convert str.encoding to e1
* e1 e2 convert from e2 to e1 convert str.encoding to e2
*/
-struct rb_io_enc_t {
+struct rb_io_encoding {
/** Internal encoding. */
rb_encoding *enc;
/** External encoding. */
@@ -134,113 +152,6 @@ struct rb_io_enc_t {
VALUE ecopts;
};
-/** Ruby's IO, metadata and buffers. */
-typedef struct rb_io_t {
-
- /** The IO's Ruby level counterpart. */
- VALUE self;
-
- /** stdio ptr for read/write, if available. */
- FILE *stdio_file;
-
- /** file descriptor. */
- int fd;
-
- /** mode flags: FMODE_XXXs */
- int mode;
-
- /** child's pid (for pipes) */
- rb_pid_t pid;
-
- /** number of lines read */
- int lineno;
-
- /** pathname for file */
- VALUE pathv;
-
- /** finalize proc */
- void (*finalize)(struct rb_io_t*,int);
-
- /** Write buffer. */
- rb_io_buffer_t wbuf;
-
- /**
- * (Byte) read buffer. Note also that there is a field called
- * ::rb_io_t::cbuf, which also concerns read IO.
- */
- rb_io_buffer_t rbuf;
-
- /**
- * 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_econv_t *readconv;
-
- /**
- * rb_io_ungetc() destination. This buffer is read before checking
- * ::rb_io_t::rbuf
- */
- rb_io_buffer_t cbuf;
-
- /** Encoding converter used when writing to this IO. */
- rb_econv_t *writeconv;
-
- /**
- * 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
- * ::rb_io_t::writeconv.
- */
- 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
- * next to its arguments.
- *
- * This of course doesn't help inter-process IO interleaves, though.
- */
- VALUE write_lock;
-
- /**
- * The timeout associated with this IO when performing blocking operations.
- */
- VALUE timeout;
-} rb_io_t;
-
-/** @alias{rb_io_enc_t} */
-typedef struct rb_io_enc_t rb_io_enc_t;
-
-/**
- * @private
- *
- * @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.
- */
-#define HAVE_RB_IO_T 1
-
/**
* @name Possible flags for ::rb_io_t::mode
*
@@ -330,7 +241,16 @@ typedef struct rb_io_enc_t rb_io_enc_t;
* Setting this one and #FMODE_BINMODE at the same time is a contradiction.
*/
#define FMODE_TEXTMODE 0x00001000
-/* #define FMODE_PREP 0x00010000 */
+/**
+ * This flag means that an IO object is wrapping an "external" file descriptor,
+ * which is owned by something outside the Ruby interpreter (usually a C extension).
+ * Ruby will not close this file when the IO object is garbage collected.
+ * If this flag is set, then IO#autoclose? is false, and vice-versa.
+ *
+ * This flag was previously called FMODE_PREP internally.
+ */
+#define FMODE_EXTERNAL 0x00010000
+
/* #define FMODE_SIGNAL_ON_EPIPE 0x00020000 */
/**
@@ -344,6 +264,166 @@ typedef struct rb_io_enc_t rb_io_enc_t;
/** @} */
+enum rb_io_mode {
+ RUBY_IO_MODE_EXTERNAL = FMODE_EXTERNAL,
+
+ RUBY_IO_MODE_READABLE = FMODE_READABLE,
+ RUBY_IO_MODE_WRITABLE = FMODE_WRITABLE,
+ RUBY_IO_MODE_READABLE_WRITABLE = (RUBY_IO_MODE_READABLE|RUBY_IO_MODE_WRITABLE),
+
+ RUBY_IO_MODE_BINARY = FMODE_BINMODE,
+ RUBY_IO_MODE_TEXT = FMODE_TEXTMODE,
+ RUBY_IO_MODE_TEXT_SET_ENCODING_FROM_BOM = FMODE_SETENC_BY_BOM,
+
+ RUBY_IO_MODE_SYNCHRONISED = FMODE_SYNC,
+
+ RUBY_IO_MODE_TTY = FMODE_TTY,
+
+ RUBY_IO_MODE_DUPLEX = FMODE_DUPLEX,
+
+ RUBY_IO_MODE_APPEND = FMODE_APPEND,
+ RUBY_IO_MODE_CREATE = FMODE_CREATE,
+ RUBY_IO_MODE_EXCLUSIVE = FMODE_EXCL,
+ RUBY_IO_MODE_TRUNCATE = FMODE_TRUNC,
+};
+
+typedef enum rb_io_mode rb_io_mode_t;
+
+#ifndef HAVE_RB_IO_T
+#define HAVE_RB_IO_T 1
+/** Ruby's IO, metadata and buffers. */
+struct rb_io {
+ /** The IO's Ruby level counterpart. */
+ RBIMPL_ATTR_DEPRECATED(("with no replacement"))
+ VALUE self;
+
+ /** stdio ptr for read/write, if available. */
+ RBIMPL_ATTR_DEPRECATED(("with no replacement"))
+ FILE *stdio_file;
+
+ /** file descriptor. */
+ RBIMPL_ATTR_DEPRECATED(("rb_io_descriptor"))
+ int fd;
+
+ /** mode flags: FMODE_XXXs */
+ RBIMPL_ATTR_DEPRECATED(("rb_io_mode"))
+ enum rb_io_mode mode;
+
+ /** child's pid (for pipes) */
+ RBIMPL_ATTR_DEPRECATED(("with no replacement"))
+ rb_pid_t pid;
+
+ /** number of lines read */
+ RBIMPL_ATTR_DEPRECATED(("with no replacement"))
+ int lineno;
+
+ /** pathname for file */
+ RBIMPL_ATTR_DEPRECATED(("rb_io_path"))
+ VALUE pathv;
+
+ /** finalize proc */
+ RBIMPL_ATTR_DEPRECATED(("with no replacement"))
+ void (*finalize)(struct rb_io*,int);
+
+ /** Write buffer. */
+ RBIMPL_ATTR_DEPRECATED(("with no replacement"))
+ rb_io_buffer_t wbuf;
+
+ /**
+ * (Byte) read buffer. Note also that there is a field called
+ * ::rb_io_t::cbuf, which also concerns read IO.
+ */
+ RBIMPL_ATTR_DEPRECATED(("with no replacement"))
+ rb_io_buffer_t rbuf;
+
+ /**
+ * Duplex IO object, if set.
+ *
+ * @see rb_io_set_write_io()
+ */
+ RBIMPL_ATTR_DEPRECATED(("rb_io_get_write_io"))
+ VALUE tied_io_for_writing;
+
+ RBIMPL_ATTR_DEPRECATED(("with no replacement"))
+ struct rb_io_encoding encs; /**< Decomposed encoding flags. */
+
+ /** Encoding converter used when reading from this IO. */
+ RBIMPL_ATTR_DEPRECATED(("with no replacement"))
+ rb_econv_t *readconv;
+
+ /**
+ * rb_io_ungetc() destination. This buffer is read before checking
+ * ::rb_io_t::rbuf
+ */
+ RBIMPL_ATTR_DEPRECATED(("with no replacement"))
+ rb_io_buffer_t cbuf;
+
+ /** Encoding converter used when writing to this IO. */
+ RBIMPL_ATTR_DEPRECATED(("with no replacement"))
+ rb_econv_t *writeconv;
+
+ /**
+ * 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.
+ */
+ RBIMPL_ATTR_DEPRECATED(("with no replacement"))
+ VALUE writeconv_asciicompat;
+
+ /** Whether ::rb_io_t::writeconv is already set up. */
+ RBIMPL_ATTR_DEPRECATED(("with no replacement"))
+ int writeconv_initialized;
+
+ /**
+ * Value of ::rb_io_t::rb_io_enc_t::ecflags stored right before
+ * initialising ::rb_io_t::writeconv.
+ */
+ RBIMPL_ATTR_DEPRECATED(("with no replacement"))
+ int writeconv_pre_ecflags;
+
+ /**
+ * Value of ::rb_io_t::rb_io_enc_t::ecopts stored right before initialising
+ * ::rb_io_t::writeconv.
+ */
+ RBIMPL_ATTR_DEPRECATED(("with no replacement"))
+ 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
+ * next to its arguments.
+ *
+ * This of course doesn't help inter-process IO interleaves, though.
+ */
+ RBIMPL_ATTR_DEPRECATED(("with no replacement"))
+ VALUE write_lock;
+
+ /**
+ * The timeout associated with this IO when performing blocking operations.
+ */
+ RBIMPL_ATTR_DEPRECATED(("rb_io_timeout/rb_io_set_timeout"))
+ VALUE timeout;
+};
+#endif
+
+typedef struct rb_io rb_io_t;
+
+/** @alias{rb_io_enc_t} */
+typedef struct rb_io_encoding rb_io_enc_t;
+
+/**
+ * Allocate a new IO object, with the given file descriptor.
+ */
+VALUE rb_io_open_descriptor(VALUE klass, int descriptor, int mode, VALUE path, VALUE timeout, struct rb_io_encoding *encoding);
+
+/**
+ * Returns whether or not the underlying IO is closed.
+ *
+ * @return Whether the underlying IO is closed.
+ */
+VALUE rb_io_closed_p(VALUE io);
+
/**
* Queries the underlying IO pointer.
*
@@ -414,14 +494,14 @@ rb_io_t *rb_io_make_open_file(VALUE obj);
* like this:
*
* ```CXX
- * typedef struct rb_io_t {
+ * typedef struct rb_io {
* 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
+ * void (*finalize) _((struct rb_io*,int)); // finalize proc
* } rb_io_t;
*```
*
@@ -485,7 +565,7 @@ FILE *rb_fdopen(int fd, const char *modestr);
*
* rb_io_modestr_fmode() is not a pure function because it raises.
*/
-int rb_io_modestr_fmode(const char *modestr);
+enum rb_io_mode rb_io_modestr_fmode(const char *modestr);
/**
* Identical to rb_io_modestr_fmode(), except it returns a mixture of `O_`
@@ -703,6 +783,12 @@ VALUE rb_io_set_write_io(VALUE io, VALUE w);
void rb_io_set_nonblock(rb_io_t *fptr);
/**
+ * Returns the path for the given IO.
+ *
+ */
+VALUE rb_io_path(VALUE io);
+
+/**
* Returns an integer representing the numeric file descriptor for
* <em>io</em>.
*
@@ -712,6 +798,12 @@ void rb_io_set_nonblock(rb_io_t *fptr);
int rb_io_descriptor(VALUE io);
/**
+ * Get the mode of the IO.
+ *
+ */
+int rb_io_mode(VALUE io);
+
+/**
* This function breaks down the option hash that `IO#initialize` takes into
* components. This is an implementation detail of rb_io_extract_modeenc()
* today. People prefer that API instead.
@@ -728,7 +820,7 @@ int rb_io_descriptor(VALUE io);
* @post `enc2_p` is the specified external encoding.
* @post `fmode_p` is the specified set of `FMODE_` modes.
*/
-int rb_io_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding **enc2_p, int *fmode_p);
+int rb_io_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding **enc2_p, enum rb_io_mode *fmode_p);
/**
* This function can be seen as an extended version of
@@ -797,7 +889,7 @@ int rb_io_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding **
* ) -> void
* ```
*/
-void rb_io_extract_modeenc(VALUE *vmode_p, VALUE *vperm_p, VALUE opthash, int *oflags_p, int *fmode_p, rb_io_enc_t *convconfig_p);
+void rb_io_extract_modeenc(VALUE *vmode_p, VALUE *vperm_p, VALUE opthash, int *oflags_p, enum rb_io_mode *fmode_p, rb_io_enc_t *convconfig_p);
/* :TODO: can this function be __attribute__((warn_unused_result)) or not? */
/**
@@ -912,6 +1004,9 @@ VALUE rb_io_wait(VALUE io, VALUE events, VALUE timeout);
* }
* ```
*
+ * On timeout, ::RUBY_Qfalse is returned. Unless you are specifically handling
+ * the timeouts, you should typically raise ::rb_eIOTimeoutError in this case.
+ *
* @param[in] error System errno.
* @param[in] io An IO object to wait.
* @param[in] events An integer set of interests.
@@ -920,19 +1015,19 @@ VALUE rb_io_wait(VALUE io, VALUE events, VALUE timeout);
* @exception rb_eRangeError `timeout` is out of range.
* @exception rb_eSystemCallError `select(2)` failed for some reason.
* @retval RUBY_Qfalse Operation timed out.
+ * @retval RUBY_Qnil Operation failed for some other reason (errno).
* @retval Otherwise Actual events reached.
*
- * @internal
- *
- * This function to return ::RUBY_Qfalse on timeout could be unintended. It
- * seems timeout feature has some rough edge.
*/
VALUE rb_io_maybe_wait(int error, VALUE io, VALUE events, VALUE timeout);
/**
* Blocks until the passed IO is ready for reading, if that makes sense for the
- * passed errno. This is a special case of rb_io_maybe_wait() that only
- * concerns for reading.
+ * passed errno. This is a special case of rb_io_maybe_wait() that is
+ * only concerned with reading and handles the timeout.
+ *
+ * If you do not want the default timeout handling, consider using
+ * ::rb_io_maybe_wait directly.
*
* @param[in] error System errno.
* @param[in] io An IO object to wait.
@@ -940,15 +1035,18 @@ VALUE rb_io_maybe_wait(int error, VALUE io, VALUE events, VALUE timeout);
* @exception rb_eIOError `io` is not open.
* @exception rb_eRangeError `timeout` is out of range.
* @exception rb_eSystemCallError `select(2)` failed for some reason.
- * @retval 0 Operation timed out.
+ * @exception rb_eIOTimeoutError The wait operation timed out.
* @retval Otherwise Always returns ::RUBY_IO_READABLE.
*/
int rb_io_maybe_wait_readable(int error, VALUE io, VALUE timeout);
/**
* Blocks until the passed IO is ready for writing, if that makes sense for the
- * passed errno. This is a special case of rb_io_maybe_wait() that only
- * concernsfor writing.
+ * passed errno. This is a special case of rb_io_maybe_wait() that is
+ * only concerned with writing, and handles the timeout.
+ *
+ * If you do not want the default timeout handling, consider using
+ * ::rb_io_maybe_wait directly.
*
* @param[in] error System errno.
* @param[in] io An IO object to wait.
@@ -956,7 +1054,7 @@ int rb_io_maybe_wait_readable(int error, VALUE io, VALUE timeout);
* @exception rb_eIOError `io` is not open.
* @exception rb_eRangeError `timeout` is out of range.
* @exception rb_eSystemCallError `select(2)` failed for some reason.
- * @retval 0 Operation timed out.
+ * @exception rb_eIOTimeoutError The wait operation timed out.
* @retval Otherwise Always returns ::RUBY_IO_WRITABLE.
*/
int rb_io_maybe_wait_writable(int error, VALUE io, VALUE timeout);
@@ -1015,6 +1113,18 @@ int rb_io_read_pending(rb_io_t *fptr);
*/
VALUE rb_stat_new(const struct stat *st);
+#if RUBY_USE_STATX
+/**
+ * Constructs an instance of ::rb_cStat from the passed information.
+ *
+ * @param[in] st A stat.
+ * @return Allocated new instance of ::rb_cStat.
+ */
+VALUE rb_statx_new(const rb_io_stat_data *st);
+#else
+# define rb_statx_new rb_stat_new
+#endif
+
/* gc.c */
RBIMPL_SYMBOL_EXPORT_END()