Ruby 4.1.0dev (2026-10-02 revision bac5fe37358bdf2c0dc72c676eec8ca34392b970)
io.c (bac5fe37358bdf2c0dc72c676eec8ca34392b970)
1/**********************************************************************
2
3 io.c -
4
5 $Author$
6 created at: Fri Oct 15 18:08:59 JST 1993
7
8 Copyright (C) 1993-2007 Yukihiro Matsumoto
9 Copyright (C) 2000 Network Applied Communication Laboratory, Inc.
10 Copyright (C) 2000 Information-technology Promotion Agency, Japan
11
12**********************************************************************/
13
14#include "ruby/internal/config.h"
15
17#include "ruby/io/buffer.h"
18
19#include <ctype.h>
20#include <errno.h>
21#include <stddef.h>
22
23/* non-Linux poll may not work on all FDs */
24#if defined(HAVE_POLL)
25# if defined(__linux__)
26# define USE_POLL 1
27# endif
28# if defined(__FreeBSD_version) && __FreeBSD_version >= 1100000
29# define USE_POLL 1
30# endif
31#endif
32
33#ifndef USE_POLL
34# define USE_POLL 0
35#endif
36
37#undef free
38#define free(x) xfree(x)
39
40#ifdef __CYGWIN__
41#include <io.h>
42#endif
43
44#include <sys/types.h>
45#if defined HAVE_NET_SOCKET_H
46# include <net/socket.h>
47#elif defined HAVE_SYS_SOCKET_H
48# include <sys/socket.h>
49#endif
50
51#if defined(__CYGWIN__) || defined(_WIN32)
52# define NO_SAFE_RENAME
53#endif
54
55#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__sun) || defined(_nec_ews)
56# define USE_SETVBUF
57#endif
58
59#include <sys/types.h>
60#ifdef HAVE_SYS_IOCTL_H
61#include <sys/ioctl.h>
62#endif
63#if defined(HAVE_FCNTL_H)
64#include <fcntl.h>
65#elif defined(HAVE_SYS_FCNTL_H)
66#include <sys/fcntl.h>
67#endif
68
69#ifdef HAVE_SYS_TIME_H
70# include <sys/time.h>
71#endif
72
73#include <sys/stat.h>
74
75#if defined(HAVE_SYS_PARAM_H)
76# include <sys/param.h>
77#endif
78
79#if !defined NOFILE
80# define NOFILE 64
81#endif
82
83#ifdef HAVE_UNISTD_H
84#include <unistd.h>
85#endif
86
87#ifdef HAVE_SYSCALL_H
88#include <syscall.h>
89#elif defined HAVE_SYS_SYSCALL_H
90#include <sys/syscall.h>
91#endif
92
93#ifdef HAVE_SYS_UIO_H
94#include <sys/uio.h>
95#endif
96
97#ifdef HAVE_SYS_WAIT_H
98# include <sys/wait.h> /* for WNOHANG on BSD */
99#endif
100
101#ifdef HAVE_COPYFILE_H
102# include <copyfile.h>
103
104# ifndef COPYFILE_STATE_COPIED
105/*
106 * Some OSes (e.g., OSX < 10.6) implement fcopyfile() but not
107 * COPYFILE_STATE_COPIED. Since the only use of the former here
108 * requires the latter, we disable the former when the latter is undefined.
109 */
110# undef HAVE_FCOPYFILE
111# endif
112
113#endif
114
115#if defined __APPLE__
116# include <AvailabilityMacros.h>
117#endif
118
120#include "ccan/list/list.h"
121#include "dln.h"
122#include "encindex.h"
123#include "id.h"
124#include "internal.h"
125#include "internal/class.h"
126#include "internal/encoding.h"
127#include "internal/error.h"
128#include "internal/inits.h"
129#include "internal/io.h"
130#include "internal/numeric.h"
131#include "internal/object.h"
132#include "internal/process.h"
133#include "internal/thread.h"
134#include "internal/transcode.h"
135#include "internal/variable.h"
136#include "ruby/io.h"
137#include "ruby/io/buffer.h"
138#include "ruby/missing.h"
139#include "ruby/thread.h"
140#include "ruby/util.h"
141#include "ruby_atomic.h"
142#include "ruby/ractor.h"
143
144#if !USE_POLL
145# include "vm_core.h"
146#endif
147
148#include "builtin.h"
149
150#ifndef O_ACCMODE
151#define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR)
152#endif
153
154#ifndef PIPE_BUF
155# ifdef _POSIX_PIPE_BUF
156# define PIPE_BUF _POSIX_PIPE_BUF
157# else
158# define PIPE_BUF 512 /* is this ok? */
159# endif
160#endif
161
162#ifndef EWOULDBLOCK
163# define EWOULDBLOCK EAGAIN
164#endif
165
166#if defined(HAVE___SYSCALL) && (defined(__APPLE__) || defined(__OpenBSD__))
167/* Mac OS X and OpenBSD have __syscall but don't define it in headers */
168off_t __syscall(quad_t number, ...);
169#endif
170
171#define IO_RBUF_CAPA_MIN 8192
172#define IO_CBUF_CAPA_MIN (128*1024)
173#define IO_RBUF_CAPA_FOR(fptr) (NEED_READCONV(fptr) ? IO_CBUF_CAPA_MIN : IO_RBUF_CAPA_MIN)
174#define IO_WBUF_CAPA_MIN 8192
175
176#define IO_MAX_BUFFER_GROWTH 8 * 1024 * 1024 // 8MB
177
178/* define system APIs */
179#ifdef _WIN32
180#undef open
181#define open rb_w32_uopen
182#undef rename
183#define rename(f, t) rb_w32_urename((f), (t))
184#include "win32/file.h"
185#endif
186
193
194static VALUE rb_eEAGAINWaitReadable;
195static VALUE rb_eEAGAINWaitWritable;
196#if EAGAIN != EWOULDBLOCK
197static VALUE rb_eEWOULDBLOCKWaitReadable;
198static VALUE rb_eEWOULDBLOCKWaitWritable;
199#endif
200static VALUE rb_eEINPROGRESSWaitWritable;
201static VALUE rb_eEINPROGRESSWaitReadable;
202
204static VALUE orig_stdout, orig_stderr;
205
207VALUE rb_rs;
210
211static VALUE argf;
212
213static ID id_write, id_read, id_flush, id_readpartial, id_set_encoding, id_fileno;
214static VALUE sym_mode, sym_perm, sym_flags, sym_extenc, sym_intenc, sym_encoding, sym_open_args;
215static VALUE sym_textmode, sym_binmode, sym_autoclose;
216static VALUE sym_SET, sym_CUR, sym_END;
217static VALUE sym_wait_readable, sym_wait_writable;
218#ifdef SEEK_DATA
219static VALUE sym_DATA;
220#endif
221#ifdef SEEK_HOLE
222static VALUE sym_HOLE;
223#endif
224
225static VALUE prep_io(int fd, enum rb_io_mode fmode, VALUE klass, const char *path);
226
227VALUE
228rb_io_blocking_region_wait(struct rb_io *io, rb_blocking_function_t *function, void *argument, enum rb_io_event events)
229{
230 return rb_thread_io_blocking_call(io, function, argument, events);
231}
232
233VALUE rb_io_blocking_region(struct rb_io *io, rb_blocking_function_t *function, void *argument)
234{
235 return rb_io_blocking_region_wait(io, function, argument, 0);
236}
237
238struct argf {
239 VALUE filename, current_file;
240 long last_lineno; /* $. */
241 long lineno;
242 VALUE argv;
243 VALUE inplace;
244 struct rb_io_encoding encs;
245 int8_t init_p, next_p, binmode;
246};
247
248
249#if defined(__APPLE__) && \
250 (!defined(MAC_OS_VERSION_27_0) || (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_VERSION_27_0))
251
252# if __has_attribute(availability) && __has_warning("-Wunguarded-availability-new")
253
255RBIMPL_WARNING_IGNORED(-Wunguarded-availability-new)
256
257# ifdef HAVE_DUP3
258static inline int (*rb_dup3(void))(int, int, int) {return &dup3;}
259# define dup3 rb_dup3()
260# endif
261
262# ifdef HAVE_PIPE2
263static inline int (*rb_pipe2(void))(int [2], int) {return &pipe2;}
264# define pipe2 rb_pipe2()
265# endif
266
268
269# else /* __API_AVAILABLE macro does nothing on gcc */
270
271# ifdef HAVE_DUP3
272__attribute__((weak)) int dup3(int, int, int);
273# endif
274# ifdef HAVE_PIPE2
275__attribute__((weak)) int pipe2(int [2], int);
276# endif
277
278# endif
279#endif /* __APPLE__ && < MAC_OS_X_VERSION_27_0 */
280
281static rb_atomic_t max_file_descriptor = NOFILE;
282void
284{
285 rb_atomic_t afd = (rb_atomic_t)fd;
286 rb_atomic_t max_fd = max_file_descriptor;
287 int err;
288
289 if (fd < 0 || afd <= max_fd)
290 return;
291
292#if defined(HAVE_FCNTL) && defined(F_GETFL)
293 err = fcntl(fd, F_GETFL) == -1;
294#else
295 {
296 struct stat buf;
297 err = fstat(fd, &buf) != 0;
298 }
299#endif
300 if (err && errno == EBADF) {
301 rb_bug("rb_update_max_fd: invalid fd (%d) given.", fd);
302 }
303
304 while (max_fd < afd) {
305 max_fd = ATOMIC_CAS(max_file_descriptor, max_fd, afd);
306 }
307}
308
309void
310rb_maygvl_fd_fix_cloexec(int fd)
311{
312 /* MinGW don't have F_GETFD and FD_CLOEXEC. [ruby-core:40281] */
313#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
314 int flags, flags2, ret;
315 flags = fcntl(fd, F_GETFD); /* should not fail except EBADF. */
316 if (flags == -1) {
317 rb_bug("rb_maygvl_fd_fix_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(errno));
318 }
319 if (fd <= 2)
320 flags2 = flags & ~FD_CLOEXEC; /* Clear CLOEXEC for standard file descriptors: 0, 1, 2. */
321 else
322 flags2 = flags | FD_CLOEXEC; /* Set CLOEXEC for non-standard file descriptors: 3, 4, 5, ... */
323 if (flags != flags2) {
324 ret = fcntl(fd, F_SETFD, flags2);
325 if (ret != 0) {
326 rb_bug("rb_maygvl_fd_fix_cloexec: fcntl(%d, F_SETFD, %d) failed: %s", fd, flags2, strerror(errno));
327 }
328 }
329#endif
330}
331
332void
334{
335 rb_maygvl_fd_fix_cloexec(fd);
337}
338
339/* this is only called once */
340static int
341rb_fix_detect_o_cloexec(int fd)
342{
343#if defined(O_CLOEXEC) && defined(F_GETFD)
344 int flags = fcntl(fd, F_GETFD);
345
346 if (flags == -1)
347 rb_bug("rb_fix_detect_o_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(errno));
348
349 if (flags & FD_CLOEXEC)
350 return 1;
351#endif /* fall through if O_CLOEXEC does not work: */
352 rb_maygvl_fd_fix_cloexec(fd);
353 return 0;
354}
355
356static inline bool
357io_again_p(int e)
358{
359 return (e == EWOULDBLOCK) || (e == EAGAIN);
360}
361
362int
363rb_cloexec_open(const char *pathname, int flags, mode_t mode)
364{
365 int ret;
366 static int o_cloexec_state = -1; /* <0: unknown, 0: ignored, >0: working */
367
368 static const int retry_interval = 0;
369 static const int retry_max_count = 10000;
370
371 int retry_count = 0;
372
373#ifdef O_CLOEXEC
374 /* O_CLOEXEC is available since Linux 2.6.23. Linux 2.6.18 silently ignore it. */
375 flags |= O_CLOEXEC;
376#elif defined O_NOINHERIT
377 flags |= O_NOINHERIT;
378#endif
379
380 while ((ret = open(pathname, flags, mode)) == -1) {
381 int e = errno;
382 if (!io_again_p(e)) break;
383 if (retry_count++ >= retry_max_count) break;
384
385 sleep(retry_interval);
386 }
387
388 if (ret < 0) return ret;
389 if (ret <= 2 || o_cloexec_state == 0) {
390 rb_maygvl_fd_fix_cloexec(ret);
391 }
392 else if (o_cloexec_state > 0) {
393 return ret;
394 }
395 else {
396 o_cloexec_state = rb_fix_detect_o_cloexec(ret);
397 }
398 return ret;
399}
400
401int
403{
404 /* Don't allocate standard file descriptors: 0, 1, 2 */
405 return rb_cloexec_fcntl_dupfd(oldfd, 3);
406}
407
408int
409rb_cloexec_dup2(int oldfd, int newfd)
410{
411 int ret;
412
413 /* When oldfd == newfd, dup2 succeeds but dup3 fails with EINVAL.
414 * rb_cloexec_dup2 succeeds as dup2. */
415 if (oldfd == newfd) {
416 ret = newfd;
417 }
418 else {
419#if defined(HAVE_DUP3) && defined(O_CLOEXEC)
420# if defined(__APPLE__)
421# define try_dup3 (dup3 != NULL)
422# define abandon_dup3() true
423# else
424 static bool try_dup3 = true;
425# define abandon_dup3() (errno != ENOSYS || !!(try_dup3 = false))
426# endif
427 if (newfd <= 2) {
428 /* pass stdin, stdout and stderr to children */
429 }
430 else if (try_dup3) {
431 ret = dup3(oldfd, newfd, O_CLOEXEC);
432 /* dup3 is available since:
433 * - Linux 2.6.27, glibc 2.9
434 * - macOS 27.0
435 */
436 if (ret != -1)
437 return ret;
438 if (abandon_dup3()) return ret;
439 }
440#endif
441 ret = dup2(oldfd, newfd);
442 if (ret < 0) return ret;
443 }
444 rb_maygvl_fd_fix_cloexec(ret);
445 return ret;
446}
447
448static int
449rb_fd_set_nonblock(int fd)
450{
451#ifdef _WIN32
452 return rb_w32_set_nonblock(fd);
453#elif defined(F_GETFL)
454 int oflags = fcntl(fd, F_GETFL);
455
456 if (oflags == -1)
457 return -1;
458 if (oflags & O_NONBLOCK)
459 return 0;
460 oflags |= O_NONBLOCK;
461 return fcntl(fd, F_SETFL, oflags);
462#endif
463 return 0;
464}
465
466static inline int
467cloexec_pipe(int descriptors[2], int flags, bool force_cloexec)
468{
469 int result = -1;
470#ifdef HAVE_PIPE2
471# if defined(__APPLE__)
472# define try_pipe2 (pipe2 != NULL)
473# define abandon_pipe2() true
474# else
475 static bool try_pipe2 = true;
476# define abandon_pipe2() (errno != ENOSYS || !!(try_pipe2 = false))
477# endif
478 if (try_pipe2) {
479 result = pipe2(descriptors, O_CLOEXEC | flags);
480 if (result == 0) return result;
481 if (abandon_pipe2()) return result;
482 }
483#endif
484 if (result < 0 && (result = pipe(descriptors)) < 0)
485 return result;
486
487#ifdef __CYGWIN__
488 if (result == 0 && descriptors[1] == -1) {
489 close(descriptors[0]);
490 descriptors[0] = -1;
491 errno = ENFILE;
492 return -1;
493 }
494#endif
495
496 if (!force_cloexec) return result;
497
498 /* no pipe2 or fallenback to dup */
499 rb_maygvl_fd_fix_cloexec(descriptors[0]);
500 rb_maygvl_fd_fix_cloexec(descriptors[1]);
501
502#ifndef _WIN32
503 rb_fd_set_nonblock(descriptors[0]);
504 rb_fd_set_nonblock(descriptors[1]);
505#endif
506
507 return result;
508}
509
510int
511rb_cloexec_pipe(int descriptors[2])
512{
513 return cloexec_pipe(descriptors, O_NONBLOCK, true);
514}
515
516int
517rb_cloexec_fcntl_dupfd(int fd, int minfd)
518{
519 int ret;
520
521#if defined(HAVE_FCNTL) && defined(F_DUPFD_CLOEXEC) && defined(F_DUPFD)
522 static int try_dupfd_cloexec = 1;
523 if (try_dupfd_cloexec) {
524 ret = fcntl(fd, F_DUPFD_CLOEXEC, minfd);
525 if (ret != -1) {
526 if (ret <= 2)
527 rb_maygvl_fd_fix_cloexec(ret);
528 return ret;
529 }
530 /* F_DUPFD_CLOEXEC is available since Linux 2.6.24. Linux 2.6.18 fails with EINVAL */
531 if (errno == EINVAL) {
532 ret = fcntl(fd, F_DUPFD, minfd);
533 if (ret != -1) {
534 try_dupfd_cloexec = 0;
535 }
536 }
537 }
538 else {
539 ret = fcntl(fd, F_DUPFD, minfd);
540 }
541#elif defined(HAVE_FCNTL) && defined(F_DUPFD)
542 ret = fcntl(fd, F_DUPFD, minfd);
543#else
544 ret = dup(fd);
545 if (ret >= 0 && ret < minfd) {
546 const int prev_fd = ret;
547 ret = rb_cloexec_fcntl_dupfd(fd, minfd);
548 close(prev_fd);
549 }
550 return ret;
551#endif
552 if (ret < 0) return ret;
553 rb_maygvl_fd_fix_cloexec(ret);
554 return ret;
555}
556
557#define argf_of(obj) (*(struct argf *)DATA_PTR(obj))
558#define ARGF argf_of(argf)
559#define ARGF_SET(field, value) RB_OBJ_WRITE(argf, &ARGF.field, value)
560
561#define GetWriteIO(io) rb_io_get_write_io(io)
562
563#define READ_DATA_PENDING(fptr) ((fptr)->rbuf.len)
564#define READ_DATA_PENDING_COUNT(fptr) ((fptr)->rbuf.len)
565#define READ_DATA_PENDING_PTR(fptr) ((fptr)->rbuf.ptr+(fptr)->rbuf.off)
566#define READ_DATA_BUFFERED(fptr) READ_DATA_PENDING(fptr)
567
568#define READ_CHAR_PENDING(fptr) ((fptr)->cbuf.len)
569#define READ_CHAR_PENDING_COUNT(fptr) ((fptr)->cbuf.len)
570#define READ_CHAR_PENDING_PTR(fptr) ((fptr)->cbuf.ptr+(fptr)->cbuf.off)
571
572#if defined(_WIN32)
573#define WAIT_FD_IN_WIN32(fptr) \
574 (rb_w32_io_cancelable_p((fptr)->fd) ? Qnil : rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), RUBY_IO_TIMEOUT_DEFAULT))
575#else
576#define WAIT_FD_IN_WIN32(fptr)
577#endif
578
579#define READ_CHECK(fptr) do {\
580 if (!READ_DATA_PENDING(fptr)) {\
581 WAIT_FD_IN_WIN32(fptr);\
582 rb_io_check_closed(fptr);\
583 }\
584} while(0)
585
586#ifndef S_ISSOCK
587# ifdef _S_ISSOCK
588# define S_ISSOCK(m) _S_ISSOCK(m)
589# else
590# ifdef _S_IFSOCK
591# define S_ISSOCK(m) (((m) & S_IFMT) == _S_IFSOCK)
592# else
593# ifdef S_IFSOCK
594# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
595# endif
596# endif
597# endif
598#endif
599
600static int io_fflush(rb_io_t *);
601static rb_io_t *flush_before_seek(rb_io_t *fptr, bool discard_rbuf);
602static void clear_readconv(rb_io_t *fptr);
603static void clear_codeconv(rb_io_t *fptr);
604
605#define FMODE_SIGNAL_ON_EPIPE (1<<17)
606
607#define fptr_signal_on_epipe(fptr) \
608 (((fptr)->mode & FMODE_SIGNAL_ON_EPIPE) != 0)
609
610#define fptr_set_signal_on_epipe(fptr, flag) \
611 ((flag) ? \
612 (fptr)->mode |= FMODE_SIGNAL_ON_EPIPE : \
613 (fptr)->mode &= ~FMODE_SIGNAL_ON_EPIPE)
614
615extern ID ruby_static_id_signo;
616
617NORETURN(static void rb_sys_fail_on_write(rb_io_t *fptr));
618static void
619rb_sys_fail_on_write(rb_io_t *fptr)
620{
621 int e = errno;
622 VALUE errinfo = rb_syserr_new_path(e, (fptr)->pathv);
623#if defined EPIPE
624 if (fptr_signal_on_epipe(fptr) && (e == EPIPE)) {
625 const VALUE sig =
626# if defined SIGPIPE
627 INT2FIX(SIGPIPE) - INT2FIX(0) +
628# endif
629 INT2FIX(0);
630 rb_ivar_set(errinfo, ruby_static_id_signo, sig);
631 }
632#endif
633 rb_exc_raise(errinfo);
634}
635
636#define NEED_NEWLINE_DECORATOR_ON_READ(fptr) ((fptr)->mode & FMODE_TEXTMODE)
637#define NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) ((fptr)->mode & FMODE_TEXTMODE)
638#if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)
639# define RUBY_CRLF_ENVIRONMENT 1
640#else
641# define RUBY_CRLF_ENVIRONMENT 0
642#endif
643
644#if RUBY_CRLF_ENVIRONMENT
645/* Windows */
646# define DEFAULT_TEXTMODE FMODE_TEXTMODE
647# define TEXTMODE_NEWLINE_DECORATOR_ON_WRITE ECONV_CRLF_NEWLINE_DECORATOR
648/*
649 * CRLF newline is set as default newline decorator.
650 * If only CRLF newline conversion is needed, we use binary IO process
651 * with OS's text mode for IO performance improvement.
652 * If encoding conversion is needed or a user sets text mode, we use encoding
653 * conversion IO process and universal newline decorator by default.
654 */
655#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || (fptr)->encs.ecflags & ~ECONV_CRLF_NEWLINE_DECORATOR)
656#define WRITECONV_MASK ( \
657 (ECONV_DECORATOR_MASK & ~ECONV_CRLF_NEWLINE_DECORATOR)|\
658 ECONV_STATEFUL_DECORATOR_MASK|\
659 0)
660#define NEED_WRITECONV(fptr) ( \
661 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
662 ((fptr)->encs.ecflags & WRITECONV_MASK) || \
663 0)
664#define SET_BINARY_MODE(fptr) setmode((fptr)->fd, O_BINARY)
665
666#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) do {\
667 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {\
668 if (((fptr)->mode & FMODE_READABLE) &&\
669 !((fptr)->encs.ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {\
670 setmode((fptr)->fd, O_BINARY);\
671 }\
672 else {\
673 setmode((fptr)->fd, O_TEXT);\
674 }\
675 }\
676} while(0)
677
678#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) do {\
679 if ((enc2) && ((ecflags) & ECONV_DEFAULT_NEWLINE_DECORATOR)) {\
680 (ecflags) |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;\
681 }\
682} while(0)
683
684/*
685 * IO unread with taking care of removed '\r' in text mode.
686 */
687static void
688io_unread(rb_io_t *fptr, bool discard_rbuf)
689{
690 rb_off_t r, pos;
691 ssize_t read_size;
692 long i;
693 long newlines = 0;
694 long extra_max;
695 char *p;
696 char *buf;
697
698 rb_io_check_closed(fptr);
699 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX) {
700 return;
701 }
702
703 errno = 0;
704 if (!rb_w32_fd_is_text(fptr->fd)) {
705 r = lseek(fptr->fd, -fptr->rbuf.len, SEEK_CUR);
706 if (r < 0 && errno) {
707 if (errno == ESPIPE)
708 fptr->mode |= FMODE_DUPLEX;
709 if (!discard_rbuf) return;
710 }
711
712 goto end;
713 }
714
715 pos = lseek(fptr->fd, 0, SEEK_CUR);
716 if (pos < 0 && errno) {
717 if (errno == ESPIPE)
718 fptr->mode |= FMODE_DUPLEX;
719 if (!discard_rbuf) goto end;
720 }
721
722 /* add extra offset for removed '\r' in rbuf */
723 extra_max = (long)(pos - fptr->rbuf.len);
724 p = fptr->rbuf.ptr + fptr->rbuf.off;
725
726 /* if the end of rbuf is '\r', rbuf doesn't have '\r' within rbuf.len */
727 if (*(fptr->rbuf.ptr + fptr->rbuf.capa - 1) == '\r') {
728 newlines++;
729 }
730
731 for (i = 0; i < fptr->rbuf.len; i++) {
732 if (*p == '\n') newlines++;
733 if (extra_max == newlines) break;
734 p++;
735 }
736
737 buf = ALLOC_N(char, fptr->rbuf.len + newlines);
738 while (newlines >= 0) {
739 r = lseek(fptr->fd, pos - fptr->rbuf.len - newlines, SEEK_SET);
740 if (newlines == 0) break;
741 if (r < 0) {
742 newlines--;
743 continue;
744 }
745 read_size = _read(fptr->fd, buf, fptr->rbuf.len + newlines);
746 if (read_size < 0) {
747 int e = errno;
748 free(buf);
749 rb_syserr_fail_path(e, fptr->pathv);
750 }
751 if (read_size == fptr->rbuf.len) {
752 lseek(fptr->fd, r, SEEK_SET);
753 break;
754 }
755 else {
756 newlines--;
757 }
758 }
759 free(buf);
760 end:
761 fptr->rbuf.off = 0;
762 fptr->rbuf.len = 0;
763 clear_codeconv(fptr);
764 return;
765}
766
767/*
768 * We use io_seek to back cursor position when changing mode from text to binary,
769 * but stdin and pipe cannot seek back. Stdin and pipe read should use encoding
770 * conversion for working properly with mode change.
771 *
772 * Return previous translation mode.
773 */
774static inline int
775set_binary_mode_with_seek_cur(rb_io_t *fptr)
776{
777 if (!rb_w32_fd_is_text(fptr->fd)) return O_BINARY;
778
779 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX) {
780 return setmode(fptr->fd, O_BINARY);
781 }
782 flush_before_seek(fptr, false);
783 return setmode(fptr->fd, O_BINARY);
784}
785#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) set_binary_mode_with_seek_cur(fptr)
786
787#else
788/* Unix */
789# define DEFAULT_TEXTMODE 0
790#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || NEED_NEWLINE_DECORATOR_ON_READ(fptr))
791#define NEED_WRITECONV(fptr) ( \
792 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
793 NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) || \
794 ((fptr)->encs.ecflags & (ECONV_DECORATOR_MASK|ECONV_STATEFUL_DECORATOR_MASK)) || \
795 0)
796#define SET_BINARY_MODE(fptr) (void)(fptr)
797#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) (void)(fptr)
798#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) ((void)(enc2), (void)(ecflags))
799#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) (void)(fptr)
800#endif
801
802#if !defined HAVE_SHUTDOWN && !defined shutdown
803#define shutdown(a,b) 0
804#endif
805
806#if defined(_WIN32)
807#define is_socket(fd, path) rb_w32_is_socket(fd)
808#elif !defined(S_ISSOCK)
809#define is_socket(fd, path) 0
810#else
811static int
812is_socket(int fd, VALUE path)
813{
814 struct stat sbuf;
815 if (fstat(fd, &sbuf) < 0)
816 rb_sys_fail_path(path);
817 return S_ISSOCK(sbuf.st_mode);
818}
819#endif
820
821static const char closed_stream[] = "closed stream";
822
823static void
824io_fd_check_closed(int fd)
825{
826 if (fd < 0) {
827 rb_thread_check_ints(); /* check for ruby_error_stream_closed */
828 rb_raise(rb_eIOError, closed_stream);
829 }
830}
831
832void
833rb_eof_error(void)
834{
835 rb_raise(rb_eEOFError, "end of file reached");
836}
837
838VALUE
840{
841 rb_check_frozen(io);
842 return io;
843}
844
845void
847{
848 if (!fptr) {
849 rb_raise(rb_eIOError, "uninitialized stream");
850 }
851}
852
853void
855{
857 io_fd_check_closed(fptr->fd);
858}
859
860static rb_io_t *
861rb_io_get_fptr(VALUE io)
862{
863 rb_io_t *fptr = RFILE(io)->fptr;
865 return fptr;
866}
867
868VALUE
870{
871 return rb_convert_type_with_id(io, T_FILE, "IO", idTo_io);
872}
873
874VALUE
876{
877 return rb_check_convert_type_with_id(io, T_FILE, "IO", idTo_io);
878}
879
880VALUE
882{
883 VALUE write_io;
884 write_io = rb_io_get_fptr(io)->tied_io_for_writing;
885 if (write_io) {
886 return write_io;
887 }
888 return io;
889}
890
891VALUE
893{
894 VALUE write_io;
895 rb_io_t *fptr = rb_io_get_fptr(io);
896 if (!RTEST(w)) {
897 w = 0;
898 }
899 else {
900 GetWriteIO(w);
901 }
902 write_io = fptr->tied_io_for_writing;
903 fptr->tied_io_for_writing = w;
904 return write_io ? write_io : Qnil;
905}
906
907/*
908 * call-seq:
909 * timeout -> duration or nil
910 *
911 * Get the internal timeout duration or nil if it was not set.
912 *
913 */
914VALUE
916{
917 rb_io_t *fptr = rb_io_get_fptr(self);
918
919 return fptr->timeout;
920}
921
922/*
923 * call-seq:
924 * timeout = duration -> duration
925 * timeout = nil -> nil
926 *
927 * Sets the internal timeout to the specified duration or nil. The timeout
928 * applies to all blocking operations where possible.
929 *
930 * When the operation performs longer than the timeout set, IO::TimeoutError
931 * is raised.
932 *
933 * This affects the following methods (but is not limited to): #gets, #puts,
934 * #read, #write, #wait_readable and #wait_writable. This also affects
935 * blocking socket operations like Socket#accept and Socket#connect.
936 *
937 * Some operations like File#open and IO#close are not affected by the
938 * timeout. A timeout during a write operation may leave the IO in an
939 * inconsistent state, e.g. data was partially written. Generally speaking, a
940 * timeout is a last ditch effort to prevent an application from hanging on
941 * slow I/O operations, such as those that occur during a slowloris attack.
942 */
943VALUE
945{
946 // Validate it:
947 if (RTEST(timeout)) {
948 rb_time_interval(timeout);
949 }
950
951 rb_io_t *fptr = rb_io_get_fptr(self);
952
953 RB_OBJ_WRITE(self, &fptr->timeout, timeout);
954
955 return self;
956}
957
958/*
959 * call-seq:
960 * IO.try_convert(object) -> new_io or nil
961 *
962 * Attempts to convert +object+ into an \IO object via method +to_io+;
963 * returns the new \IO object if successful, or +nil+ otherwise:
964 *
965 * IO.try_convert(STDOUT) # => #<IO:<STDOUT>>
966 * IO.try_convert(ARGF) # => #<IO:<STDIN>>
967 * IO.try_convert('STDOUT') # => nil
968 *
969 */
970static VALUE
971rb_io_s_try_convert(VALUE dummy, VALUE io)
972{
973 return rb_io_check_io(io);
974}
975
976#if !RUBY_CRLF_ENVIRONMENT
977static void
978io_unread(rb_io_t *fptr, bool discard_rbuf)
979{
980 rb_off_t r;
981 rb_io_check_closed(fptr);
982 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX)
983 return;
984 /* xxx: target position may be negative if buffer is filled by ungetc */
985 errno = 0;
986 r = lseek(fptr->fd, -fptr->rbuf.len, SEEK_CUR);
987 if (r < 0 && errno) {
988 if (errno == ESPIPE)
989 fptr->mode |= FMODE_DUPLEX;
990 if (!discard_rbuf) return;
991 }
992 fptr->rbuf.off = 0;
993 fptr->rbuf.len = 0;
994 clear_codeconv(fptr);
995 return;
996}
997#endif
998
999static rb_encoding *io_input_encoding(rb_io_t *fptr);
1000
1001static void
1002io_ungetbyte(VALUE str, rb_io_t *fptr)
1003{
1004 long len = RSTRING_LEN(str);
1005
1006 if (fptr->rbuf.ptr == NULL) {
1007 const int min_capa = IO_RBUF_CAPA_FOR(fptr);
1008 fptr->rbuf.off = 0;
1009 fptr->rbuf.len = 0;
1010#if SIZEOF_LONG > SIZEOF_INT
1011 if (len > INT_MAX)
1012 rb_raise(rb_eIOError, "ungetbyte failed");
1013#endif
1014 if (len > min_capa)
1015 fptr->rbuf.capa = (int)len;
1016 else
1017 fptr->rbuf.capa = min_capa;
1018 fptr->rbuf.ptr = ALLOC_N(char, fptr->rbuf.capa);
1019 }
1020 if (fptr->rbuf.capa < len + fptr->rbuf.len) {
1021 rb_raise(rb_eIOError, "ungetbyte failed");
1022 }
1023 if (fptr->rbuf.off < len) {
1024 MEMMOVE(fptr->rbuf.ptr+fptr->rbuf.capa-fptr->rbuf.len,
1025 fptr->rbuf.ptr+fptr->rbuf.off,
1026 char, fptr->rbuf.len);
1027 fptr->rbuf.off = fptr->rbuf.capa-fptr->rbuf.len;
1028 }
1029 fptr->rbuf.off-=(int)len;
1030 fptr->rbuf.len+=(int)len;
1031 MEMMOVE(fptr->rbuf.ptr+fptr->rbuf.off, RSTRING_PTR(str), char, len);
1032}
1033
1034static void
1035io_restore_read_buffer(VALUE str, rb_io_t *fptr)
1036{
1037 long len = RSTRING_LEN(str);
1038
1039 if (len > INT_MAX - fptr->rbuf.len) {
1040 rb_raise(rb_eIOError, "read buffer too large");
1041 }
1042 if (fptr->rbuf.ptr == NULL || fptr->rbuf.capa >= len + fptr->rbuf.len) {
1043 io_ungetbyte(str, fptr);
1044 }
1045 else {
1046 int pending = fptr->rbuf.len;
1047 int capa = (int)len + pending;
1048 char *ptr = ALLOC_N(char, capa);
1049
1050 MEMMOVE(ptr, RSTRING_PTR(str), char, len);
1051 MEMMOVE(ptr + len, fptr->rbuf.ptr + fptr->rbuf.off, char, pending);
1052 ruby_xfree(fptr->rbuf.ptr);
1053 fptr->rbuf.ptr = ptr;
1054 fptr->rbuf.off = 0;
1055 fptr->rbuf.len = capa;
1056 fptr->rbuf.capa = capa;
1057 }
1058}
1059
1060static rb_io_t *
1061flush_before_seek(rb_io_t *fptr, bool discard_rbuf)
1062{
1063 if (io_fflush(fptr) < 0)
1064 rb_sys_fail_on_write(fptr);
1065 io_unread(fptr, discard_rbuf);
1066 errno = 0;
1067 return fptr;
1068}
1069
1070#define io_seek(fptr, ofs, whence) (errno = 0, lseek(flush_before_seek(fptr, true)->fd, (ofs), (whence)))
1071#define io_tell(fptr) lseek(flush_before_seek(fptr, false)->fd, 0, SEEK_CUR)
1072
1073#ifndef SEEK_CUR
1074# define SEEK_SET 0
1075# define SEEK_CUR 1
1076# define SEEK_END 2
1077#endif
1078
1079void
1081{
1082 rb_io_check_closed(fptr);
1083 if (!(fptr->mode & FMODE_READABLE)) {
1084 rb_raise(rb_eIOError, "not opened for reading");
1085 }
1086 if (fptr->wbuf.len) {
1087 if (io_fflush(fptr) < 0)
1088 rb_sys_fail_on_write(fptr);
1089 }
1090 if (fptr->tied_io_for_writing) {
1091 rb_io_t *wfptr;
1092 GetOpenFile(fptr->tied_io_for_writing, wfptr);
1093 if (io_fflush(wfptr) < 0)
1094 rb_sys_fail_on_write(wfptr);
1095 }
1096}
1097
1098void
1100{
1102 if (READ_CHAR_PENDING(fptr)) {
1103 rb_raise(rb_eIOError, "byte oriented read for character buffered IO");
1104 }
1105}
1106
1107void
1112
1113static rb_encoding*
1114io_read_encoding(rb_io_t *fptr)
1115{
1116 if (fptr->encs.enc) {
1117 return fptr->encs.enc;
1118 }
1119 return rb_default_external_encoding();
1120}
1121
1122static rb_encoding*
1123io_input_encoding(rb_io_t *fptr)
1124{
1125 if (fptr->encs.enc2) {
1126 return fptr->encs.enc2;
1127 }
1128 return io_read_encoding(fptr);
1129}
1130
1131void
1133{
1134 rb_io_check_closed(fptr);
1135 if (!(fptr->mode & FMODE_WRITABLE)) {
1136 rb_raise(rb_eIOError, "not opened for writing");
1137 }
1138 if (fptr->rbuf.len) {
1139 io_unread(fptr, true);
1140 }
1141}
1142
1143int
1144rb_io_read_pending(rb_io_t *fptr)
1145{
1146 /* This function is used for bytes and chars. Confusing. */
1147 if (READ_CHAR_PENDING(fptr))
1148 return 1; /* should raise? */
1149 return READ_DATA_PENDING(fptr);
1150}
1151
1152void
1154{
1155 if (!READ_DATA_PENDING(fptr)) {
1156 rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), RUBY_IO_TIMEOUT_DEFAULT);
1157 }
1158 return;
1159}
1160
1161int
1162rb_gc_for_fd(int err)
1163{
1164 if (err == EMFILE || err == ENFILE || err == ENOMEM) {
1165 rb_gc();
1166 return 1;
1167 }
1168 return 0;
1169}
1170
1171/* try `expr` upto twice while it returns false and `errno`
1172 * is to GC. Each `errno`s are available as `first_errno` and
1173 * `retried_errno` respectively */
1174#define TRY_WITH_GC(expr) \
1175 for (int first_errno, retried_errno = 0, retried = 0; \
1176 (!retried && \
1177 !(expr) && \
1178 (!rb_gc_for_fd(first_errno = errno) || !(expr)) && \
1179 (retried_errno = errno, 1)); \
1180 (void)retried_errno, retried = 1)
1181
1182static int
1183ruby_dup(int orig)
1184{
1185 int fd = -1;
1186
1187 TRY_WITH_GC((fd = rb_cloexec_dup(orig)) >= 0) {
1188 rb_syserr_fail(first_errno, 0);
1189 }
1190 rb_update_max_fd(fd);
1191 return fd;
1192}
1193
1194static VALUE
1195io_alloc(VALUE klass)
1196{
1197 UNPROTECTED_NEWOBJ_OF(io, struct RFile, klass, T_FILE, sizeof(struct RFile));
1198
1199 io->fptr = 0;
1200
1201 return (VALUE)io;
1202}
1203
1204#ifndef S_ISREG
1205# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
1206#endif
1207
1209 VALUE th;
1210 rb_io_t *fptr;
1211 int nonblock;
1212 int fd;
1213
1214 void *buf;
1215 size_t capa;
1216 struct timeval *timeout;
1217};
1218
1220 VALUE th;
1221 rb_io_t *fptr;
1222 int nonblock;
1223 int fd;
1224
1225 const void *buf;
1226 size_t capa;
1227 struct timeval *timeout;
1228};
1229
1230#ifdef HAVE_WRITEV
1231struct io_internal_writev_struct {
1232 VALUE th;
1233 rb_io_t *fptr;
1234 int nonblock;
1235 int fd;
1236
1237 int iovcnt;
1238 const struct iovec *iov;
1239 struct timeval *timeout;
1240};
1241#endif
1242
1243static int nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout);
1244
1250static inline int
1251io_internal_wait(VALUE thread, rb_io_t *fptr, int error, int events, struct timeval *timeout)
1252{
1253 if (!timeout && rb_thread_mn_schedulable(thread)) {
1254 RUBY_ASSERT(errno == EWOULDBLOCK || errno == EAGAIN);
1255 return -1;
1256 }
1257
1258 int ready = nogvl_wait_for(thread, fptr, events, timeout);
1259
1260 if (ready > 0) {
1261 return ready;
1262 }
1263 else if (ready == 0) {
1264 errno = ETIMEDOUT;
1265 return -1;
1266 }
1267
1268 // If there was an error BEFORE we started waiting, return it:
1269 if (error) {
1270 errno = error;
1271 return -1;
1272 }
1273 else {
1274 // Otherwise, whatever error was generated by `nogvl_wait_for` is the one we want:
1275 return ready;
1276 }
1277}
1278
1279static VALUE
1280internal_read_func(void *ptr)
1281{
1282 struct io_internal_read_struct *iis = ptr;
1283 ssize_t result;
1284
1285 if (iis->timeout && !iis->nonblock) {
1286 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_IN, iis->timeout) == -1) {
1287 return -1;
1288 }
1289 }
1290
1291 retry:
1292 result = read(iis->fd, iis->buf, iis->capa);
1293
1294 if (result < 0 && !iis->nonblock) {
1295 if (io_again_p(errno)) {
1296 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_IN, iis->timeout) == -1) {
1297 return -1;
1298 }
1299 else {
1300 goto retry;
1301 }
1302 }
1303 }
1304
1305 return result;
1306}
1307
1308#if defined __APPLE__
1309# define do_write_retry(code) do {result = code;} while (result == -1 && errno == EPROTOTYPE)
1310#else
1311# define do_write_retry(code) result = code
1312#endif
1313
1314static VALUE
1315internal_write_func(void *ptr)
1316{
1317 struct io_internal_write_struct *iis = ptr;
1318 ssize_t result;
1319
1320 if (iis->timeout && !iis->nonblock) {
1321 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1322 return -1;
1323 }
1324 }
1325
1326 retry:
1327 do_write_retry(write(iis->fd, iis->buf, iis->capa));
1328
1329 if (result < 0 && !iis->nonblock) {
1330 int e = errno;
1331 if (io_again_p(e)) {
1332 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1333 return -1;
1334 }
1335 else {
1336 goto retry;
1337 }
1338 }
1339 }
1340
1341 return result;
1342}
1343
1344#ifdef HAVE_WRITEV
1345static VALUE
1346internal_writev_func(void *ptr)
1347{
1348 struct io_internal_writev_struct *iis = ptr;
1349 ssize_t result;
1350
1351 if (iis->timeout && !iis->nonblock) {
1352 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1353 return -1;
1354 }
1355 }
1356
1357 retry:
1358 do_write_retry(writev(iis->fd, iis->iov, iis->iovcnt));
1359
1360 if (result < 0 && !iis->nonblock) {
1361 if (io_again_p(errno)) {
1362 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1363 return -1;
1364 }
1365 else {
1366 goto retry;
1367 }
1368 }
1369 }
1370
1371 return result;
1372}
1373#endif
1374
1375static ssize_t
1376rb_io_read_memory(rb_io_t *fptr, void *buf, size_t count)
1377{
1378 rb_thread_t *th = GET_THREAD();
1380 if (scheduler != Qnil) {
1381 VALUE result = rb_fiber_scheduler_io_read_memory(scheduler, fptr->self, buf, count);
1382
1383 if (!UNDEF_P(result)) {
1385 }
1386 }
1387
1388 struct io_internal_read_struct iis = {
1389 .th = th->self,
1390 .fptr = fptr,
1391 .nonblock = 0,
1392 .fd = fptr->fd,
1393
1394 .buf = buf,
1395 .capa = count,
1396 .timeout = NULL,
1397 };
1398
1399 struct timeval timeout_storage;
1400
1401 if (fptr->timeout != Qnil) {
1402 timeout_storage = rb_time_interval(fptr->timeout);
1403 iis.timeout = &timeout_storage;
1404 }
1405
1406 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_read_func, &iis, RUBY_IO_READABLE);
1407}
1408
1409static ssize_t
1410rb_io_write_memory(rb_io_t *fptr, const void *buf, size_t count)
1411{
1412 rb_thread_t *th = GET_THREAD();
1414 if (scheduler != Qnil) {
1415 VALUE result = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, buf, count);
1416
1417 if (!UNDEF_P(result)) {
1419 }
1420 }
1421
1422 struct io_internal_write_struct iis = {
1423 .th = th->self,
1424 .fptr = fptr,
1425 .nonblock = 0,
1426 .fd = fptr->fd,
1427
1428 .buf = buf,
1429 .capa = count,
1430 .timeout = NULL
1431 };
1432
1433 struct timeval timeout_storage;
1434
1435 if (fptr->timeout != Qnil) {
1436 timeout_storage = rb_time_interval(fptr->timeout);
1437 iis.timeout = &timeout_storage;
1438 }
1439
1440 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_write_func, &iis, RUBY_IO_WRITABLE);
1441}
1442
1443#ifdef HAVE_WRITEV
1444static ssize_t
1445rb_writev_internal(rb_io_t *fptr, const struct iovec *iov, int iovcnt)
1446{
1447 if (!iovcnt) return 0;
1448
1449 rb_thread_t *th = GET_THREAD();
1450
1452 if (scheduler != Qnil) {
1453 // This path assumes at least one `iov`:
1454 VALUE result = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, iov[0].iov_base, iov[0].iov_len);
1455
1456 if (!UNDEF_P(result)) {
1458 }
1459 }
1460
1461 struct io_internal_writev_struct iis = {
1462 .th = th->self,
1463 .fptr = fptr,
1464 .nonblock = 0,
1465 .fd = fptr->fd,
1466
1467 .iov = iov,
1468 .iovcnt = iovcnt,
1469 .timeout = NULL
1470 };
1471
1472 struct timeval timeout_storage;
1473
1474 if (fptr->timeout != Qnil) {
1475 timeout_storage = rb_time_interval(fptr->timeout);
1476 iis.timeout = &timeout_storage;
1477 }
1478
1479 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_writev_func, &iis, RUBY_IO_WRITABLE);
1480}
1481#endif
1482
1483static VALUE
1484io_flush_buffer_sync(void *arg)
1485{
1486 rb_io_t *fptr = arg;
1487 long l = fptr->wbuf.len;
1488 ssize_t r = write(fptr->fd, fptr->wbuf.ptr+fptr->wbuf.off, (size_t)l);
1489
1490 if (fptr->wbuf.len <= r) {
1491 fptr->wbuf.off = 0;
1492 fptr->wbuf.len = 0;
1493 return 0;
1494 }
1495
1496 if (0 <= r) {
1497 fptr->wbuf.off += (int)r;
1498 fptr->wbuf.len -= (int)r;
1499 errno = EAGAIN;
1500 }
1501
1502 return (VALUE)-1;
1503}
1504
1505static inline VALUE
1506io_flush_buffer_fiber_scheduler(VALUE scheduler, rb_io_t *fptr)
1507{
1508 VALUE ret = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, fptr->wbuf.ptr+fptr->wbuf.off, fptr->wbuf.len);
1509 if (!UNDEF_P(ret)) {
1510 ssize_t result = rb_fiber_scheduler_io_result_apply(ret);
1511 if (result > 0) {
1512 fptr->wbuf.off += result;
1513 fptr->wbuf.len -= result;
1514 }
1515 return result >= 0 ? (VALUE)0 : (VALUE)-1;
1516 }
1517 return ret;
1518}
1519
1520static VALUE
1521io_flush_buffer_async(VALUE arg)
1522{
1523 rb_io_t *fptr = (rb_io_t *)arg;
1524
1525 VALUE scheduler = rb_fiber_scheduler_current();
1526 if (scheduler != Qnil) {
1527 VALUE result = io_flush_buffer_fiber_scheduler(scheduler, fptr);
1528 if (!UNDEF_P(result)) {
1529 return result;
1530 }
1531 }
1532
1533 return rb_io_blocking_region_wait(fptr, io_flush_buffer_sync, fptr, RUBY_IO_WRITABLE);
1534}
1535
1536static inline int
1537io_flush_buffer(rb_io_t *fptr)
1538{
1539 if (!NIL_P(fptr->write_lock) && rb_mutex_owned_p(fptr->write_lock)) {
1540 return (int)io_flush_buffer_async((VALUE)fptr);
1541 }
1542 else {
1543 return (int)rb_mutex_synchronize(fptr->write_lock, io_flush_buffer_async, (VALUE)fptr);
1544 }
1545}
1546
1547static int
1548io_fflush(rb_io_t *fptr)
1549{
1550 rb_io_check_closed(fptr);
1551
1552 if (fptr->wbuf.len == 0)
1553 return 0;
1554
1555 while (fptr->wbuf.len > 0 && io_flush_buffer(fptr) != 0) {
1556 if (!rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT))
1557 return -1;
1558
1559 rb_io_check_closed(fptr);
1560 }
1561
1562 return 0;
1563}
1564
1565VALUE
1566rb_io_wait(VALUE io, VALUE events, VALUE timeout)
1567{
1568 rb_thread_t *th = GET_THREAD();
1570
1571 if (scheduler != Qnil) {
1572 return rb_fiber_scheduler_io_wait(scheduler, io, events, timeout);
1573 }
1574
1575 rb_io_t * fptr = NULL;
1576 RB_IO_POINTER(io, fptr);
1577
1578 struct timeval tv_storage;
1579 struct timeval *tv = NULL;
1580
1581 if (NIL_OR_UNDEF_P(timeout)) {
1582 timeout = fptr->timeout;
1583 }
1584
1585 if (timeout != Qnil) {
1586 tv_storage = rb_time_interval(timeout);
1587 tv = &tv_storage;
1588 }
1589
1590 int ready = rb_thread_io_wait(th, fptr, RB_NUM2INT(events), tv);
1591
1592 if (ready < 0) {
1593 rb_sys_fail(0);
1594 }
1595
1596 // Not sure if this is necessary:
1597 rb_io_check_closed(fptr);
1598
1599 if (ready) {
1600 return RB_INT2NUM(ready);
1601 }
1602 else {
1603 return Qfalse;
1604 }
1605}
1606
1607static VALUE
1608io_from_fd(int fd)
1609{
1610 return prep_io(fd, FMODE_EXTERNAL, rb_cIO, NULL);
1611}
1612
1613static int
1614io_wait_for_single_fd(int fd, int events, struct timeval *timeout, rb_thread_t *th, VALUE scheduler)
1615{
1616 if (scheduler != Qnil) {
1617 return RTEST(
1618 rb_fiber_scheduler_io_wait(scheduler, io_from_fd(fd), RB_INT2NUM(events), rb_fiber_scheduler_make_timeout(timeout))
1619 );
1620 }
1621
1622 return rb_thread_wait_for_single_fd(th, fd, events, timeout);
1623}
1624
1625int
1627{
1628 io_fd_check_closed(f);
1629
1630 rb_thread_t *th = GET_THREAD();
1632
1633 switch (errno) {
1634 case EINTR:
1635#if defined(ERESTART)
1636 case ERESTART:
1637#endif
1639 return TRUE;
1640
1641 case EAGAIN:
1642#if EWOULDBLOCK != EAGAIN
1643 case EWOULDBLOCK:
1644#endif
1645 if (scheduler != Qnil) {
1646 return RTEST(
1647 rb_fiber_scheduler_io_wait_readable(scheduler, io_from_fd(f))
1648 );
1649 }
1650 else {
1651 io_wait_for_single_fd(f, RUBY_IO_READABLE, NULL, th, scheduler);
1652 }
1653 return TRUE;
1654
1655 default:
1656 return FALSE;
1657 }
1658}
1659
1660int
1662{
1663 io_fd_check_closed(f);
1664
1665 rb_thread_t *th = GET_THREAD();
1667
1668 switch (errno) {
1669 case EINTR:
1670#if defined(ERESTART)
1671 case ERESTART:
1672#endif
1673 /*
1674 * In old Linux, several special files under /proc and /sys don't handle
1675 * select properly. Thus we need avoid to call if don't use O_NONBLOCK.
1676 * Otherwise, we face nasty hang up. Sigh.
1677 * e.g. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1678 * https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1679 * In EINTR case, we only need to call RUBY_VM_CHECK_INTS_BLOCKING().
1680 * Then rb_thread_check_ints() is enough.
1681 */
1683 return TRUE;
1684
1685 case EAGAIN:
1686#if EWOULDBLOCK != EAGAIN
1687 case EWOULDBLOCK:
1688#endif
1689 if (scheduler != Qnil) {
1690 return RTEST(
1691 rb_fiber_scheduler_io_wait_writable(scheduler, io_from_fd(f))
1692 );
1693 }
1694 else {
1695 io_wait_for_single_fd(f, RUBY_IO_WRITABLE, NULL, th, scheduler);
1696 }
1697 return TRUE;
1698
1699 default:
1700 return FALSE;
1701 }
1702}
1703
1704int
1705rb_wait_for_single_fd(int fd, int events, struct timeval *timeout)
1706{
1707 rb_thread_t *th = GET_THREAD();
1709 return io_wait_for_single_fd(fd, events, timeout, th, scheduler);
1710}
1711
1712int
1714{
1715 return rb_wait_for_single_fd(fd, RUBY_IO_READABLE, NULL);
1716}
1717
1718int
1720{
1721 return rb_wait_for_single_fd(fd, RUBY_IO_WRITABLE, NULL);
1722}
1723
1724VALUE
1725rb_io_maybe_wait(int error, VALUE io, VALUE events, VALUE timeout)
1726{
1727 // fptr->fd can be set to -1 at any time by another thread when the GVL is
1728 // released. Many code, e.g. `io_bufread` didn't check this correctly and
1729 // instead relies on `read(-1) -> -1` which causes this code path. We then
1730 // check here whether the IO was in fact closed. Probably it's better to
1731 // check that `fptr->fd != -1` before using it in syscall.
1732 rb_io_check_closed(RFILE(io)->fptr);
1733
1734 switch (error) {
1735 // In old Linux, several special files under /proc and /sys don't handle
1736 // select properly. Thus we need avoid to call if don't use O_NONBLOCK.
1737 // Otherwise, we face nasty hang up. Sigh.
1738 // e.g. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1739 // https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1740 // In EINTR case, we only need to call RUBY_VM_CHECK_INTS_BLOCKING().
1741 // Then rb_thread_check_ints() is enough.
1742 case EINTR:
1743#if defined(ERESTART)
1744 case ERESTART:
1745#endif
1746 // We might have pending interrupts since the previous syscall was interrupted:
1748
1749 // The operation was interrupted, so retry it immediately:
1750 return events;
1751
1752 case EAGAIN:
1753#if EWOULDBLOCK != EAGAIN
1754 case EWOULDBLOCK:
1755#endif
1756 {
1757 // The operation would block, so wait for the specified events:
1758 VALUE result = rb_io_wait(io, events, timeout);
1759 // The scheduler may change errno while waiting. Preserve the original
1760 // error in case no events are ready and the caller reports the failure.
1761 errno = error;
1762 return result;
1763 }
1764
1765 default:
1766 // Non-specific error, no event is ready:
1767 return Qnil;
1768 }
1769}
1770
1771int
1773{
1774 VALUE result = rb_io_maybe_wait(error, io, RB_INT2NUM(RUBY_IO_READABLE), timeout);
1775
1776 if (RTEST(result)) {
1777 return RB_NUM2INT(result);
1778 }
1779 else if (result == RUBY_Qfalse) {
1780 rb_raise(rb_eIOTimeoutError, "Timed out waiting for IO to become readable!");
1781 }
1782
1783 return 0;
1784}
1785
1786int
1788{
1789 VALUE result = rb_io_maybe_wait(error, io, RB_INT2NUM(RUBY_IO_WRITABLE), timeout);
1790
1791 if (RTEST(result)) {
1792 return RB_NUM2INT(result);
1793 }
1794 else if (result == RUBY_Qfalse) {
1795 rb_raise(rb_eIOTimeoutError, "Timed out waiting for IO to become writable!");
1796 }
1797
1798 return 0;
1799}
1800
1801static void
1802make_writeconv(rb_io_t *fptr)
1803{
1804 if (!fptr->writeconv_initialized) {
1805 const char *senc, *denc;
1806 rb_encoding *enc;
1807 int ecflags;
1808 VALUE ecopts;
1809
1810 fptr->writeconv_initialized = 1;
1811
1812 ecflags = fptr->encs.ecflags & ~ECONV_NEWLINE_DECORATOR_READ_MASK;
1813 ecopts = fptr->encs.ecopts;
1814
1815 if (!fptr->encs.enc || (rb_is_ascii8bit_enc(fptr->encs.enc) && !fptr->encs.enc2)) {
1816 /* no encoding conversion */
1817 fptr->writeconv_pre_ecflags = 0;
1818 fptr->writeconv_pre_ecopts = Qnil;
1819 fptr->writeconv = rb_econv_open_opts("", "", ecflags, ecopts);
1820 if (!fptr->writeconv)
1821 rb_exc_raise(rb_econv_open_exc("", "", ecflags));
1823 }
1824 else {
1825 enc = fptr->encs.enc2 ? fptr->encs.enc2 : fptr->encs.enc;
1826 senc = rb_econv_asciicompat_encoding(rb_enc_name(enc));
1827 if (!senc && !(fptr->encs.ecflags & ECONV_STATEFUL_DECORATOR_MASK)) {
1828 /* single conversion */
1829 fptr->writeconv_pre_ecflags = ecflags;
1830 fptr->writeconv_pre_ecopts = ecopts;
1831 fptr->writeconv = NULL;
1833 }
1834 else {
1835 /* double conversion */
1836 fptr->writeconv_pre_ecflags = ecflags & ~ECONV_STATEFUL_DECORATOR_MASK;
1837 fptr->writeconv_pre_ecopts = ecopts;
1838 if (senc) {
1839 denc = rb_enc_name(enc);
1840 fptr->writeconv_asciicompat = rb_str_new2(senc);
1841 }
1842 else {
1843 senc = denc = "";
1844 fptr->writeconv_asciicompat = rb_str_new2(rb_enc_name(enc));
1845 }
1847 ecopts = fptr->encs.ecopts;
1848 fptr->writeconv = rb_econv_open_opts(senc, denc, ecflags, ecopts);
1849 if (!fptr->writeconv)
1850 rb_exc_raise(rb_econv_open_exc(senc, denc, ecflags));
1851 }
1852 }
1853 }
1854}
1855
1856/* writing functions */
1858 rb_io_t *fptr;
1859 const char *ptr;
1860 long length;
1861};
1862
1864 VALUE io;
1865 VALUE str;
1866 int nosync;
1867};
1868
1869#ifdef HAVE_WRITEV
1870static ssize_t
1871io_binwrite_string_internal(rb_io_t *fptr, const char *ptr, long length)
1872{
1873 if (fptr->wbuf.len) {
1874 struct iovec iov[2];
1875
1876 iov[0].iov_base = fptr->wbuf.ptr+fptr->wbuf.off;
1877 iov[0].iov_len = fptr->wbuf.len;
1878 iov[1].iov_base = (void*)ptr;
1879 iov[1].iov_len = length;
1880
1881 ssize_t result = rb_writev_internal(fptr, iov, 2);
1882
1883 if (result < 0)
1884 return result;
1885
1886 if (result >= fptr->wbuf.len) {
1887 // We wrote more than the internal buffer:
1888 result -= fptr->wbuf.len;
1889 fptr->wbuf.off = 0;
1890 fptr->wbuf.len = 0;
1891 }
1892 else {
1893 // We only wrote less data than the internal buffer:
1894 fptr->wbuf.off += (int)result;
1895 fptr->wbuf.len -= (int)result;
1896
1897 result = 0;
1898 }
1899
1900 return result;
1901 }
1902 else {
1903 return rb_io_write_memory(fptr, ptr, length);
1904 }
1905}
1906#else
1907static ssize_t
1908io_binwrite_string_internal(rb_io_t *fptr, const char *ptr, long length)
1909{
1910 long remaining = length;
1911
1912 if (fptr->wbuf.len) {
1913 if (fptr->wbuf.len+length <= fptr->wbuf.capa) {
1914 if (fptr->wbuf.capa < fptr->wbuf.off+fptr->wbuf.len+length) {
1915 MEMMOVE(fptr->wbuf.ptr, fptr->wbuf.ptr+fptr->wbuf.off, char, fptr->wbuf.len);
1916 fptr->wbuf.off = 0;
1917 }
1918
1919 MEMMOVE(fptr->wbuf.ptr+fptr->wbuf.off+fptr->wbuf.len, ptr, char, length);
1920 fptr->wbuf.len += (int)length;
1921
1922 // We copied the entire incoming data to the internal buffer:
1923 remaining = 0;
1924 }
1925
1926 // Flush the internal buffer:
1927 if (io_fflush(fptr) < 0) {
1928 return -1;
1929 }
1930
1931 // If all the data was buffered, we are done:
1932 if (remaining == 0) {
1933 return length;
1934 }
1935 }
1936
1937 // Otherwise, we should write the data directly:
1938 return rb_io_write_memory(fptr, ptr, length);
1939}
1940#endif
1941
1942static VALUE
1943io_binwrite_string(VALUE arg)
1944{
1945 struct binwrite_arg *p = (struct binwrite_arg *)arg;
1946
1947 const char *ptr = p->ptr;
1948 size_t remaining = p->length;
1949
1950 while (remaining) {
1951 // Write as much as possible:
1952 ssize_t result = io_binwrite_string_internal(p->fptr, ptr, remaining);
1953
1954 if (result == 0) {
1955 // If only the internal buffer is written, result will be zero [bytes of given data written]. This means we
1956 // should try again immediately.
1957 }
1958 else if (result > 0) {
1959 if ((size_t)result == remaining) break;
1960 ptr += result;
1961 remaining -= result;
1962 }
1963 // Wait for it to become writable:
1964 else if (rb_io_maybe_wait_writable(errno, p->fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
1965 rb_io_check_closed(p->fptr);
1966 }
1967 else {
1968 // The error was unrelated to waiting for it to become writable, so we fail:
1969 return -1;
1970 }
1971 }
1972
1973 return p->length;
1974}
1975
1976inline static void
1977io_allocate_write_buffer(rb_io_t *fptr, int sync)
1978{
1979 if (fptr->wbuf.ptr == NULL && !(sync && (fptr->mode & FMODE_SYNC))) {
1980 fptr->wbuf.off = 0;
1981 fptr->wbuf.len = 0;
1982 fptr->wbuf.capa = IO_WBUF_CAPA_MIN;
1983 fptr->wbuf.ptr = ALLOC_N(char, fptr->wbuf.capa);
1984 }
1985
1986 if (NIL_P(fptr->write_lock)) {
1987 fptr->write_lock = rb_mutex_new();
1988 rb_mutex_allow_trap(fptr->write_lock, 1);
1989 }
1990}
1991
1992static inline int
1993io_binwrite_requires_flush_write(rb_io_t *fptr, long len, int nosync)
1994{
1995 // If the requested operation was synchronous and the output mode is synchronous or a TTY:
1996 if (!nosync && (fptr->mode & (FMODE_SYNC|FMODE_TTY)))
1997 return 1;
1998
1999 // If the amount of data we want to write exceeds the internal buffer:
2000 if (fptr->wbuf.ptr && fptr->wbuf.capa <= fptr->wbuf.len + len)
2001 return 1;
2002
2003 // Otherwise, we can append to the internal buffer:
2004 return 0;
2005}
2006
2007static long
2008io_binwrite(const char *ptr, long len, rb_io_t *fptr, int nosync)
2009{
2010 if (len <= 0) return len;
2011
2012 // Don't write anything if current thread has a pending interrupt:
2014
2015 io_allocate_write_buffer(fptr, !nosync);
2016
2017 if (io_binwrite_requires_flush_write(fptr, len, nosync)) {
2018 struct binwrite_arg arg;
2019
2020 arg.fptr = fptr;
2021 arg.ptr = ptr;
2022 arg.length = len;
2023
2024 if (!NIL_P(fptr->write_lock)) {
2025 return rb_mutex_synchronize(fptr->write_lock, io_binwrite_string, (VALUE)&arg);
2026 }
2027 else {
2028 return io_binwrite_string((VALUE)&arg);
2029 }
2030 }
2031 else {
2032 if (fptr->wbuf.off) {
2033 if (fptr->wbuf.len)
2034 MEMMOVE(fptr->wbuf.ptr, fptr->wbuf.ptr+fptr->wbuf.off, char, fptr->wbuf.len);
2035 fptr->wbuf.off = 0;
2036 }
2037
2038 MEMMOVE(fptr->wbuf.ptr+fptr->wbuf.off+fptr->wbuf.len, ptr, char, len);
2039 fptr->wbuf.len += (int)len;
2040
2041 return len;
2042 }
2043}
2044
2045# define MODE_BTMODE(a,b,c) ((fmode & FMODE_BINMODE) ? (b) : \
2046 (fmode & FMODE_TEXTMODE) ? (c) : (a))
2047
2048#define MODE_BTXMODE(a, b, c, d, e, f) ((fmode & FMODE_EXCL) ? \
2049 MODE_BTMODE(d, e, f) : \
2050 MODE_BTMODE(a, b, c))
2051
2052static VALUE
2053do_writeconv(VALUE str, rb_io_t *fptr, int *converted)
2054{
2055 if (NEED_WRITECONV(fptr)) {
2056 VALUE common_encoding = Qnil;
2057 SET_BINARY_MODE(fptr);
2058
2059 make_writeconv(fptr);
2060
2061 if (fptr->writeconv) {
2062#define fmode (fptr->mode)
2063 if (!NIL_P(fptr->writeconv_asciicompat))
2064 common_encoding = fptr->writeconv_asciicompat;
2065 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1) && !rb_enc_asciicompat(rb_enc_get(str))) {
2066 rb_raise(rb_eArgError, "ASCII incompatible string written for text mode IO without encoding conversion: %s",
2067 rb_enc_name(rb_enc_get(str)));
2068 }
2069#undef fmode
2070 }
2071 else {
2072 if (fptr->encs.enc2)
2073 common_encoding = rb_enc_from_encoding(fptr->encs.enc2);
2074 else if (fptr->encs.enc != rb_ascii8bit_encoding())
2075 common_encoding = rb_enc_from_encoding(fptr->encs.enc);
2076 }
2077
2078 if (!NIL_P(common_encoding)) {
2079 str = rb_str_encode(str, common_encoding,
2081 *converted = 1;
2082 }
2083
2084 if (fptr->writeconv) {
2086 *converted = 1;
2087 }
2088 }
2089#if RUBY_CRLF_ENVIRONMENT
2090#define fmode (fptr->mode)
2091 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1)) {
2092 if ((fptr->mode & FMODE_READABLE) &&
2094 setmode(fptr->fd, O_BINARY);
2095 }
2096 else {
2097 setmode(fptr->fd, O_TEXT);
2098 }
2099 if (!rb_enc_asciicompat(rb_enc_get(str))) {
2100 rb_raise(rb_eArgError, "ASCII incompatible string written for text mode IO without encoding conversion: %s",
2101 rb_enc_name(rb_enc_get(str)));
2102 }
2103 }
2104#undef fmode
2105#endif
2106 return str;
2107}
2108
2109static long
2110io_fwrite(VALUE str, rb_io_t *fptr, int nosync)
2111{
2112 int converted = 0;
2113 VALUE tmp;
2114 long n, len;
2115 const char *ptr;
2116
2117#ifdef _WIN32
2118 if (fptr->mode & FMODE_TTY) {
2119 if (rb_w32_write_console(str, fptr->fd) > 0) return RSTRING_LEN(str);
2120 }
2121#endif
2122
2123 str = do_writeconv(str, fptr, &converted);
2124 if (converted)
2125 OBJ_FREEZE(str);
2126
2127 tmp = rb_str_no_gvl_safe_acquire(str);
2128 RSTRING_GETMEM(tmp, ptr, len);
2129 n = io_binwrite(ptr, len, fptr, nosync);
2131
2132 return n;
2133}
2134
2135ssize_t
2136rb_io_bufwrite(VALUE io, const void *buf, size_t size)
2137{
2138 rb_io_t *fptr;
2139
2140 GetOpenFile(io, fptr);
2142 return (ssize_t)io_binwrite(buf, (long)size, fptr, 0);
2143}
2144
2145static VALUE
2146io_write(VALUE io, VALUE str, int nosync)
2147{
2148 rb_io_t *fptr;
2149 long n;
2150 VALUE tmp;
2151
2152 io = GetWriteIO(io);
2153 str = rb_obj_as_string(str);
2154 tmp = rb_io_check_io(io);
2155
2156 if (NIL_P(tmp)) {
2157 /* port is not IO, call write method for it. */
2158 return rb_funcall(io, id_write, 1, str);
2159 }
2160
2161 io = tmp;
2162 if (RSTRING_LEN(str) == 0) return INT2FIX(0);
2163
2164 GetOpenFile(io, fptr);
2166
2167 n = io_fwrite(str, fptr, nosync);
2168 if (n < 0L) rb_sys_fail_on_write(fptr);
2169
2170 return LONG2FIX(n);
2171}
2172
2173#ifdef HAVE_WRITEV
2174struct binwritev_arg {
2175 rb_io_t *fptr;
2176 struct iovec *iov;
2177 int iovcnt;
2178 size_t total;
2179};
2180
2181static VALUE
2182io_binwritev_internal(VALUE arg)
2183{
2184 struct binwritev_arg *p = (struct binwritev_arg *)arg;
2185
2186 size_t remaining = p->total;
2187 size_t offset = 0;
2188
2189 rb_io_t *fptr = p->fptr;
2190 struct iovec *iov = p->iov;
2191 int iovcnt = p->iovcnt;
2192
2193 while (remaining) {
2194 long result = rb_writev_internal(fptr, iov, iovcnt);
2195
2196 if (result >= 0) {
2197 offset += result;
2198 if (fptr->wbuf.ptr && fptr->wbuf.len) {
2199 if (offset < (size_t)fptr->wbuf.len) {
2200 fptr->wbuf.off += result;
2201 fptr->wbuf.len -= result;
2202 }
2203 else {
2204 offset -= (size_t)fptr->wbuf.len;
2205 fptr->wbuf.off = 0;
2206 fptr->wbuf.len = 0;
2207 }
2208 }
2209
2210 if (offset == p->total) {
2211 return p->total;
2212 }
2213
2214 while (result >= (ssize_t)iov->iov_len) {
2215 /* iovcnt > 0 */
2216 result -= iov->iov_len;
2217 iov->iov_len = 0;
2218 iov++;
2219
2220 if (!--iovcnt) {
2221 // I don't believe this code path can ever occur.
2222 return offset;
2223 }
2224 }
2225
2226 iov->iov_base = (char *)iov->iov_base + result;
2227 iov->iov_len -= result;
2228 }
2229 else if (rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
2230 rb_io_check_closed(fptr);
2231 }
2232 else {
2233 return -1;
2234 }
2235 }
2236
2237 return offset;
2238}
2239
2240static long
2241io_binwritev(struct iovec *iov, int iovcnt, rb_io_t *fptr)
2242{
2243 // Don't write anything if current thread has a pending interrupt:
2245
2246 if (iovcnt == 0) return 0;
2247
2248 size_t total = 0;
2249 for (int i = 1; i < iovcnt; i++) total += iov[i].iov_len;
2250
2251 io_allocate_write_buffer(fptr, 1);
2252
2253 if (fptr->wbuf.ptr && fptr->wbuf.len) {
2254 // The end of the buffered data:
2255 size_t offset = fptr->wbuf.off + fptr->wbuf.len;
2256
2257 if (offset + total <= (size_t)fptr->wbuf.capa) {
2258 for (int i = 1; i < iovcnt; i++) {
2259 memcpy(fptr->wbuf.ptr+offset, iov[i].iov_base, iov[i].iov_len);
2260 offset += iov[i].iov_len;
2261 }
2262
2263 fptr->wbuf.len += total;
2264
2265 /* io_binwritev is only reached in sync/TTY mode (it is called only
2266 * from io_fwritev, which io_writev uses only when FMODE_SYNC or
2267 * FMODE_TTY is set), so the coalesced data must be flushed
2268 * immediately rather than left in the buffer until the next flush
2269 * or close. Otherwise a multi-argument write with many arguments
2270 * would not be observably atomic under sync. */
2271 if (io_fflush(fptr) < 0) return -1;
2272
2273 return total;
2274 }
2275 else {
2276 iov[0].iov_base = fptr->wbuf.ptr + fptr->wbuf.off;
2277 iov[0].iov_len = fptr->wbuf.len;
2278 }
2279 }
2280 else {
2281 // The first iov is reserved for the internal buffer, and it's empty.
2282 iov++;
2283
2284 if (!--iovcnt) {
2285 // If there are no other io vectors we are done.
2286 return 0;
2287 }
2288 }
2289
2290 struct binwritev_arg arg;
2291 arg.fptr = fptr;
2292 arg.iov = iov;
2293 arg.iovcnt = iovcnt;
2294 arg.total = total;
2295
2296 if (!NIL_P(fptr->write_lock)) {
2297 return rb_mutex_synchronize(fptr->write_lock, io_binwritev_internal, (VALUE)&arg);
2298 }
2299 else {
2300 return io_binwritev_internal((VALUE)&arg);
2301 }
2302}
2303
2304static long
2305io_fwritev(int argc, const VALUE *argv, rb_io_t *fptr)
2306{
2307 int i, converted, iovcnt = argc + 1;
2308 long n;
2309 VALUE v1, v2, str, tmp, *tmp_array;
2310 struct iovec *iov;
2311
2312 iov = ALLOCV_N(struct iovec, v1, iovcnt);
2313 tmp_array = ALLOCV_N(VALUE, v2, argc);
2314
2315 for (i = 0; i < argc; i++) {
2316 str = rb_obj_as_string(argv[i]);
2317 converted = 0;
2318 str = do_writeconv(str, fptr, &converted);
2319
2320 if (converted)
2321 OBJ_FREEZE(str);
2322
2323 tmp = rb_str_tmp_frozen_acquire(str);
2324 tmp_array[i] = tmp;
2325
2326 /* iov[0] is reserved for buffer of fptr */
2327 iov[i+1].iov_base = RSTRING_PTR(tmp);
2328 iov[i+1].iov_len = RSTRING_LEN(tmp);
2329 }
2330
2331 n = io_binwritev(iov, iovcnt, fptr);
2332 if (v1) ALLOCV_END(v1);
2333
2334 for (i = 0; i < argc; i++) {
2335 rb_str_tmp_frozen_release(argv[i], tmp_array[i]);
2336 }
2337
2338 if (v2) ALLOCV_END(v2);
2339
2340 return n;
2341}
2342
2343static int
2344iovcnt_ok(int iovcnt)
2345{
2346#ifdef IOV_MAX
2347 return iovcnt < IOV_MAX;
2348#else /* GNU/Hurd has writev, but no IOV_MAX */
2349 return 1;
2350#endif
2351}
2352#endif /* HAVE_WRITEV */
2353
2354static VALUE
2355io_writev(int argc, const VALUE *argv, VALUE io)
2356{
2357 rb_io_t *fptr;
2358 long n;
2359 VALUE tmp, total = INT2FIX(0);
2360 int i, cnt = 1;
2361
2362 io = GetWriteIO(io);
2363 tmp = rb_io_check_io(io);
2364
2365 if (NIL_P(tmp)) {
2366 /* port is not IO, call write method for it. */
2367 return rb_funcallv(io, id_write, argc, argv);
2368 }
2369
2370 io = tmp;
2371
2372 GetOpenFile(io, fptr);
2374
2375 for (i = 0; i < argc; i += cnt) {
2376#ifdef HAVE_WRITEV
2377 if ((fptr->mode & (FMODE_SYNC|FMODE_TTY)) && iovcnt_ok(cnt = argc - i)) {
2378 n = io_fwritev(cnt, &argv[i], fptr);
2379 }
2380 else
2381#endif
2382 {
2383 cnt = 1;
2384 /* sync at last item */
2385 n = io_fwrite(rb_obj_as_string(argv[i]), fptr, (i < argc-1));
2386 }
2387
2388 if (n < 0L)
2389 rb_sys_fail_on_write(fptr);
2390
2391 total = rb_fix_plus(LONG2FIX(n), total);
2392 }
2393
2394 return total;
2395}
2396
2397/*
2398 * call-seq:
2399 * write(*objects) -> integer
2400 *
2401 * Writes each of the given +objects+ to +self+,
2402 * which must be opened for writing
2403 * (see {Access Modes}[rdoc-ref:File@Access+Modes]);
2404 * returns the total number bytes written;
2405 * each of +objects+ that is not a string is converted via method +to_s+:
2406 *
2407 * $stdout.write('Hello', ', ', 'World!', "\n") # => 14
2408 * $stdout.write('foo', :bar, 2, "\n") # => 8
2409 *
2410 * Output:
2411 *
2412 * Hello, World!
2413 * foobar2
2414 *
2415 * Related: IO#read.
2416 */
2417
2418static VALUE
2419io_write_m(int argc, VALUE *argv, VALUE io)
2420{
2421 if (argc != 1) {
2422 return io_writev(argc, argv, io);
2423 }
2424 else {
2425 VALUE str = argv[0];
2426 return io_write(io, str, 0);
2427 }
2428}
2429
2430VALUE
2431rb_io_write(VALUE io, VALUE str)
2432{
2433 return rb_funcallv(io, id_write, 1, &str);
2434}
2435
2436static VALUE
2437rb_io_writev(VALUE io, int argc, const VALUE *argv)
2438{
2439 if (argc > 1 && rb_obj_method_arity(io, id_write) == 1) {
2440 if (io != rb_ractor_stderr() && RTEST(ruby_verbose)) {
2441 VALUE klass = CLASS_OF(io);
2442 char sep = RCLASS_SINGLETON_P(klass) ? (klass = io, '.') : '#';
2444 RB_WARN_CATEGORY_DEPRECATED, "%+"PRIsVALUE"%c""write is outdated interface"
2445 " which accepts just one argument",
2446 klass, sep
2447 );
2448 }
2449
2450 do rb_io_write(io, *argv++); while (--argc);
2451
2452 return Qnil;
2453 }
2454
2455 return rb_funcallv(io, id_write, argc, argv);
2456}
2457
2458/*
2459 * call-seq:
2460 * self << object -> self
2461 *
2462 * Writes the given +object+ to +self+,
2463 * which must be opened for writing (see {Access Modes}[rdoc-ref:File@Access+Modes]);
2464 * returns +self+;
2465 * if +object+ is not a string, it is converted via method +to_s+:
2466 *
2467 * $stdout << 'Hello' << ', ' << 'World!' << "\n"
2468 * $stdout << 'foo' << :bar << 2 << "\n"
2469 *
2470 * Output:
2471 *
2472 * Hello, World!
2473 * foobar2
2474 *
2475 */
2476
2477
2478VALUE
2480{
2481 rb_io_write(io, str);
2482 return io;
2483}
2484
2485#ifdef HAVE_FSYNC
2486static VALUE
2487nogvl_fsync(void *ptr)
2488{
2489 rb_io_t *fptr = ptr;
2490
2491#ifdef _WIN32
2492 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->fd)) != FILE_TYPE_DISK)
2493 return 0;
2494#endif
2495 return (VALUE)fsync(fptr->fd);
2496}
2497#endif
2498
2499VALUE
2500rb_io_flush_raw(VALUE io, int sync)
2501{
2502 rb_io_t *fptr;
2503
2504 if (!RB_TYPE_P(io, T_FILE)) {
2505 return rb_funcall(io, id_flush, 0);
2506 }
2507
2508 io = GetWriteIO(io);
2509 GetOpenFile(io, fptr);
2510
2511 if (fptr->mode & FMODE_WRITABLE) {
2512 if (io_fflush(fptr) < 0)
2513 rb_sys_fail_on_write(fptr);
2514 }
2515 if (fptr->mode & FMODE_READABLE) {
2516 io_unread(fptr, true);
2517 }
2518
2519 return io;
2520}
2521
2522/*
2523 * call-seq:
2524 * flush -> self
2525 *
2526 * Flushes data buffered in +self+ to the operating system
2527 * (but does not necessarily flush data buffered in the operating system):
2528 *
2529 * $stdout.print 'no newline' # Not necessarily flushed.
2530 * $stdout.flush # Flushed.
2531 *
2532 */
2533
2534VALUE
2535rb_io_flush(VALUE io)
2536{
2537 return rb_io_flush_raw(io, 1);
2538}
2539
2540/*
2541 * call-seq:
2542 * tell -> integer
2543 *
2544 * Returns the current position (in bytes) in +self+
2545 * (see {Position}[rdoc-ref:IO@Position]):
2546 *
2547 * f = File.open('t.txt')
2548 * f.tell # => 0
2549 * f.gets # => "First line\n"
2550 * f.tell # => 12
2551 * f.close
2552 *
2553 * Related: IO#pos=, IO#seek.
2554 */
2555
2556static VALUE
2557rb_io_tell(VALUE io)
2558{
2559 rb_io_t *fptr;
2560 rb_off_t pos;
2561
2562 GetOpenFile(io, fptr);
2563 pos = io_tell(fptr);
2564 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2565 pos -= fptr->rbuf.len;
2566 return OFFT2NUM(pos);
2567}
2568
2569static VALUE
2570rb_io_seek(VALUE io, VALUE offset, int whence)
2571{
2572 rb_io_t *fptr;
2573 rb_off_t pos;
2574
2575 pos = NUM2OFFT(offset);
2576 GetOpenFile(io, fptr);
2577 pos = io_seek(fptr, pos, whence);
2578 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2579 if (fptr->readconv) clear_readconv(fptr);
2580
2581 return INT2FIX(0);
2582}
2583
2584static int
2585interpret_seek_whence(VALUE vwhence)
2586{
2587 if (vwhence == sym_SET)
2588 return SEEK_SET;
2589 if (vwhence == sym_CUR)
2590 return SEEK_CUR;
2591 if (vwhence == sym_END)
2592 return SEEK_END;
2593#ifdef SEEK_DATA
2594 if (vwhence == sym_DATA)
2595 return SEEK_DATA;
2596#endif
2597#ifdef SEEK_HOLE
2598 if (vwhence == sym_HOLE)
2599 return SEEK_HOLE;
2600#endif
2601 return NUM2INT(vwhence);
2602}
2603
2604/*
2605 * call-seq:
2606 * seek(offset, whence = IO::SEEK_SET) -> 0
2607 *
2608 * Seeks to the position given by integer +offset+
2609 * (see {Position}[rdoc-ref:IO@Position])
2610 * and constant +whence+, which is one of:
2611 *
2612 * - +:CUR+ or <tt>IO::SEEK_CUR</tt>:
2613 * Repositions the stream to its current position plus the given +offset+:
2614 *
2615 * f = File.open('t.txt')
2616 * f.tell # => 0
2617 * f.seek(20, :CUR) # => 0
2618 * f.tell # => 20
2619 * f.seek(-10, :CUR) # => 0
2620 * f.tell # => 10
2621 * f.close
2622 *
2623 * - +:END+ or <tt>IO::SEEK_END</tt>:
2624 * Repositions the stream to its end plus the given +offset+:
2625 *
2626 * f = File.open('t.txt')
2627 * f.tell # => 0
2628 * f.seek(0, :END) # => 0 # Repositions to stream end.
2629 * f.tell # => 52
2630 * f.seek(-20, :END) # => 0
2631 * f.tell # => 32
2632 * f.seek(-40, :END) # => 0
2633 * f.tell # => 12
2634 * f.close
2635 *
2636 * - +:SET+ or <tt>IO::SEEK_SET</tt>:
2637 * Repositions the stream to the given +offset+:
2638 *
2639 * f = File.open('t.txt')
2640 * f.tell # => 0
2641 * f.seek(20, :SET) # => 0
2642 * f.tell # => 20
2643 * f.seek(40, :SET) # => 0
2644 * f.tell # => 40
2645 * f.close
2646 *
2647 * Related: IO#pos=, IO#tell.
2648 *
2649 */
2650
2651static VALUE
2652rb_io_seek_m(int argc, VALUE *argv, VALUE io)
2653{
2654 VALUE offset, ptrname;
2655 int whence = SEEK_SET;
2656
2657 if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
2658 whence = interpret_seek_whence(ptrname);
2659 }
2660
2661 return rb_io_seek(io, offset, whence);
2662}
2663
2664/*
2665 * call-seq:
2666 * pos = new_position -> new_position
2667 *
2668 * Seeks to the given +new_position+ (in bytes);
2669 * see {Position}[rdoc-ref:IO@Position]:
2670 *
2671 * f = File.open('t.txt')
2672 * f.tell # => 0
2673 * f.pos = 20 # => 20
2674 * f.tell # => 20
2675 * f.close
2676 *
2677 * Related: IO#seek, IO#tell.
2678 *
2679 */
2680
2681static VALUE
2682rb_io_set_pos(VALUE io, VALUE offset)
2683{
2684 rb_io_t *fptr;
2685 rb_off_t pos;
2686
2687 pos = NUM2OFFT(offset);
2688 GetOpenFile(io, fptr);
2689 pos = io_seek(fptr, pos, SEEK_SET);
2690 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2691 if (fptr->readconv) clear_readconv(fptr);
2692
2693 return OFFT2NUM(pos);
2694}
2695
2696/*
2697 * call-seq:
2698 * rewind -> 0
2699 *
2700 * Repositions the stream to its beginning,
2701 * setting both the position and the line number to zero;
2702 * see {Position}[rdoc-ref:IO@Position]
2703 * and {Line Number}[rdoc-ref:IO@Line+Number]:
2704 *
2705 * f = File.open('t.txt')
2706 * f.tell # => 0
2707 * f.lineno # => 0
2708 * f.gets # => "First line\n"
2709 * f.tell # => 12
2710 * f.lineno # => 1
2711 * f.rewind # => 0
2712 * f.tell # => 0
2713 * f.lineno # => 0
2714 * f.close
2715 *
2716 * Note that this method cannot be used with streams such as pipes, ttys, and sockets.
2717 *
2718 */
2719
2720static VALUE
2721rb_io_rewind(VALUE io)
2722{
2723 rb_io_t *fptr;
2724
2725 GetOpenFile(io, fptr);
2726 if (io_seek(fptr, 0L, 0) < 0 && errno) rb_sys_fail_path(fptr->pathv);
2727 if (io == ARGF.current_file) {
2728 ARGF.lineno -= fptr->lineno;
2729 }
2730 fptr->lineno = 0;
2731 if (fptr->readconv) {
2732 clear_readconv(fptr);
2733 }
2734
2735 return INT2FIX(0);
2736}
2737
2738static int
2739fptr_wait_readable(rb_io_t *fptr)
2740{
2741 int result = rb_io_maybe_wait_readable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT);
2742
2743 if (result)
2744 rb_io_check_closed(fptr);
2745
2746 return result;
2747}
2748
2749static int
2750io_fillbuf(rb_io_t *fptr)
2751{
2752 ssize_t r;
2753
2754 if (fptr->rbuf.ptr == NULL) {
2755 fptr->rbuf.off = 0;
2756 fptr->rbuf.len = 0;
2757 fptr->rbuf.capa = IO_RBUF_CAPA_FOR(fptr);
2758 fptr->rbuf.ptr = ALLOC_N(char, fptr->rbuf.capa);
2759 }
2760 if (fptr->rbuf.len == 0) {
2761 retry:
2762 r = rb_io_read_memory(fptr, fptr->rbuf.ptr, fptr->rbuf.capa);
2763
2764 if (r < 0) {
2765 if (fptr_wait_readable(fptr))
2766 goto retry;
2767
2768 int e = errno;
2769 VALUE path = rb_sprintf("fd:%d ", fptr->fd);
2770 if (!NIL_P(fptr->pathv)) {
2771 rb_str_append(path, fptr->pathv);
2772 }
2773
2774 rb_syserr_fail_path(e, path);
2775 }
2776 if (r > 0) rb_io_check_closed(fptr);
2777 fptr->rbuf.off = 0;
2778 fptr->rbuf.len = (int)r; /* r should be <= rbuf_capa */
2779 if (r == 0)
2780 return -1; /* EOF */
2781 }
2782 return 0;
2783}
2784
2785/*
2786 * call-seq:
2787 * eof -> true or false
2788 *
2789 * Returns +true+ if the stream is positioned at its end, +false+ otherwise;
2790 * see {Position}[rdoc-ref:IO@Position]:
2791 *
2792 * f = File.open('t.txt')
2793 * f.eof # => false
2794 * f.seek(0, :END) # => 0
2795 * f.eof # => true
2796 * f.close
2797 *
2798 * Raises an exception unless the stream is opened for reading;
2799 * see {Mode}[rdoc-ref:File@Access+Modes].
2800 *
2801 * If +self+ is a stream such as pipe or socket, this method
2802 * blocks until the other end sends some data or closes it:
2803 *
2804 * r, w = IO.pipe
2805 * Thread.new { sleep 1; w.close }
2806 * r.eof? # => true # After 1-second wait.
2807 *
2808 * r, w = IO.pipe
2809 * Thread.new { sleep 1; w.puts "a" }
2810 * r.eof? # => false # After 1-second wait.
2811 *
2812 * r, w = IO.pipe
2813 * r.eof? # blocks forever
2814 *
2815 * Note that this method reads data to the input byte buffer. So
2816 * IO#sysread may not behave as you intend with IO#eof?, unless you
2817 * call IO#rewind first (which is not available for some streams).
2818 */
2819
2820VALUE
2822{
2823 rb_io_t *fptr;
2824
2825 GetOpenFile(io, fptr);
2827
2828 if (READ_CHAR_PENDING(fptr)) return Qfalse;
2829 if (READ_DATA_PENDING(fptr)) return Qfalse;
2830 READ_CHECK(fptr);
2831#if RUBY_CRLF_ENVIRONMENT
2832 if (!NEED_READCONV(fptr) && NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
2833 return RBOOL(eof(fptr->fd));
2834 }
2835#endif
2836 return RBOOL(io_fillbuf(fptr) < 0);
2837}
2838
2839/*
2840 * call-seq:
2841 * sync -> true or false
2842 *
2843 * Returns the current sync mode of the stream.
2844 * When sync mode is true, all output is immediately flushed to the underlying
2845 * operating system and is not buffered by Ruby internally. See also #fsync.
2846 *
2847 * f = File.open('t.tmp', 'w')
2848 * f.sync # => false
2849 * f.sync = true
2850 * f.sync # => true
2851 * f.close
2852 *
2853 */
2854
2855static VALUE
2856rb_io_sync(VALUE io)
2857{
2858 rb_io_t *fptr;
2859
2860 io = GetWriteIO(io);
2861 GetOpenFile(io, fptr);
2862 return RBOOL(fptr->mode & FMODE_SYNC);
2863}
2864
2865#ifdef HAVE_FSYNC
2866
2867/*
2868 * call-seq:
2869 * sync = boolean -> boolean
2870 *
2871 * Sets the _sync_ _mode_ for the stream to the given value;
2872 * returns the given value.
2873 *
2874 * Values for the sync mode:
2875 *
2876 * - +true+: All output is immediately flushed to the
2877 * underlying operating system and is not buffered internally.
2878 * - +false+: Output may be buffered internally.
2879 *
2880 * Example;
2881 *
2882 * f = File.open('t.tmp', 'w')
2883 * f.sync # => false
2884 * f.sync = true
2885 * f.sync # => true
2886 * f.close
2887 *
2888 * Related: IO#fsync.
2889 *
2890 */
2891
2892static VALUE
2893rb_io_set_sync(VALUE io, VALUE sync)
2894{
2895 rb_io_t *fptr;
2896
2897 io = GetWriteIO(io);
2898 GetOpenFile(io, fptr);
2899 if (RTEST(sync)) {
2900 fptr->mode |= FMODE_SYNC;
2901 }
2902 else {
2903 fptr->mode &= ~FMODE_SYNC;
2904 }
2905 return sync;
2906}
2907
2908/*
2909 * call-seq:
2910 * fsync -> 0
2911 *
2912 * Immediately writes to disk all data buffered in the stream,
2913 * via the operating system's <tt>fsync(2)</tt>.
2914
2915 * Note this difference:
2916 *
2917 * - IO#sync=: Ensures that data is flushed from the stream's internal buffers,
2918 * but does not guarantee that the operating system actually writes the data to disk.
2919 * - IO#fsync: Ensures both that data is flushed from internal buffers,
2920 * and that data is written to disk.
2921 *
2922 * Raises an exception if the operating system does not support <tt>fsync(2)</tt>.
2923 *
2924 */
2925
2926static VALUE
2927rb_io_fsync(VALUE io)
2928{
2929 rb_io_t *fptr;
2930
2931 io = GetWriteIO(io);
2932 GetOpenFile(io, fptr);
2933
2934 if (io_fflush(fptr) < 0)
2935 rb_sys_fail_on_write(fptr);
2936
2937 if ((int)rb_io_blocking_region(fptr, nogvl_fsync, fptr))
2938 rb_sys_fail_path(fptr->pathv);
2939
2940 return INT2FIX(0);
2941}
2942#else
2943# define rb_io_fsync rb_f_notimplement
2944# define rb_io_sync rb_f_notimplement
2945static VALUE
2946rb_io_set_sync(VALUE io, VALUE sync)
2947{
2948 rb_notimplement();
2950}
2951#endif
2952
2953#ifdef HAVE_FDATASYNC
2954static VALUE
2955nogvl_fdatasync(void *ptr)
2956{
2957 rb_io_t *fptr = ptr;
2958
2959 return (VALUE)fdatasync(fptr->fd);
2960}
2961
2962/*
2963 * call-seq:
2964 * fdatasync -> 0
2965 *
2966 * Immediately writes to disk all data buffered in the stream,
2967 * via the operating system's: <tt>fdatasync(2)</tt>, if supported,
2968 * otherwise via <tt>fsync(2)</tt>, if supported;
2969 * otherwise raises an exception.
2970 *
2971 */
2972
2973static VALUE
2974rb_io_fdatasync(VALUE io)
2975{
2976 rb_io_t *fptr;
2977
2978 io = GetWriteIO(io);
2979 GetOpenFile(io, fptr);
2980
2981 if (io_fflush(fptr) < 0)
2982 rb_sys_fail_on_write(fptr);
2983
2984 if ((int)rb_io_blocking_region(fptr, nogvl_fdatasync, fptr) == 0)
2985 return INT2FIX(0);
2986
2987 /* fall back */
2988 return rb_io_fsync(io);
2989}
2990#else
2991#define rb_io_fdatasync rb_io_fsync
2992#endif
2993
2994/*
2995 * call-seq:
2996 * fileno -> integer
2997 *
2998 * Returns the integer file descriptor for the stream:
2999 *
3000 * $stdin.fileno # => 0
3001 * $stdout.fileno # => 1
3002 * $stderr.fileno # => 2
3003 * File.open('t.txt').fileno # => 10
3004 * f.close
3005 *
3006 */
3007
3008static VALUE
3009rb_io_fileno(VALUE io)
3010{
3011 rb_io_t *fptr = RFILE(io)->fptr;
3012 int fd;
3013
3014 rb_io_check_closed(fptr);
3015 fd = fptr->fd;
3016 return INT2FIX(fd);
3017}
3018
3019int
3021{
3022 if (RB_TYPE_P(io, T_FILE)) {
3023 rb_io_t *fptr = RFILE(io)->fptr;
3024 rb_io_check_closed(fptr);
3025 return fptr->fd;
3026 }
3027 else {
3028 VALUE fileno = rb_check_funcall(io, id_fileno, 0, NULL);
3029 if (!UNDEF_P(fileno)) {
3030 return RB_NUM2INT(fileno);
3031 }
3032 }
3033
3034 rb_raise(rb_eTypeError, "expected IO or #fileno, %"PRIsVALUE" given", rb_obj_class(io));
3035
3037}
3038
3039int
3040rb_io_mode(VALUE io)
3041{
3042 rb_io_t *fptr;
3043 GetOpenFile(io, fptr);
3044 return fptr->mode;
3045}
3046
3047/*
3048 * call-seq:
3049 * pid -> integer or nil
3050 *
3051 * Returns the process ID of a child process associated with the stream,
3052 * which will have been set by IO#popen, or +nil+ if the stream was not
3053 * created by IO#popen:
3054 *
3055 * pipe = IO.popen("-")
3056 * if pipe
3057 * $stderr.puts "In parent, child pid is #{pipe.pid}"
3058 * else
3059 * $stderr.puts "In child, pid is #{$$}"
3060 * end
3061 *
3062 * Output:
3063 *
3064 * In child, pid is 26209
3065 * In parent, child pid is 26209
3066 *
3067 */
3068
3069static VALUE
3070rb_io_pid(VALUE io)
3071{
3072 rb_io_t *fptr;
3073
3074 GetOpenFile(io, fptr);
3075 if (!fptr->pid)
3076 return Qnil;
3077 return PIDT2NUM(fptr->pid);
3078}
3079
3080/*
3081 * :markup: markdown
3082 *
3083 * call-seq:
3084 * path -> string or nil
3085 *
3086 * Returns the string path associated with `self`,
3087 * or `nil` if there is no associated path:
3088 *
3089 * ```ruby
3090 * path = 'doc/maintainers.md'
3091 * fd = File.open(path).fileno # => 6
3092 * IO.new(fd, path: path).path # => "doc/maintainers.md"
3093 * IO.new(fd).path # => nil
3094 * ```
3095 *
3096 */
3097
3098VALUE
3100{
3101 rb_io_t *fptr = RFILE(io)->fptr;
3102
3103 if (!fptr)
3104 return Qnil;
3105
3106 return rb_obj_dup(fptr->pathv);
3107}
3108
3109/*
3110 * call-seq:
3111 * inspect -> string
3112 *
3113 * Returns a string representation of +self+:
3114 *
3115 * f = File.open('t.txt')
3116 * f.inspect # => "#<File:t.txt>"
3117 * f.close
3118 *
3119 */
3120
3121static VALUE
3122rb_io_inspect(VALUE obj)
3123{
3124 rb_io_t *fptr;
3125 VALUE result;
3126 static const char closed[] = " (closed)";
3127
3128 fptr = RFILE(obj)->fptr;
3129 if (!fptr) return rb_any_to_s(obj);
3130 result = rb_str_new_cstr("#<");
3131 rb_str_append(result, rb_class_name(CLASS_OF(obj)));
3132 rb_str_cat2(result, ":");
3133 if (NIL_P(fptr->pathv)) {
3134 if (fptr->fd < 0) {
3135 rb_str_cat(result, closed+1, strlen(closed)-1);
3136 }
3137 else {
3138 rb_str_catf(result, "fd %d", fptr->fd);
3139 }
3140 }
3141 else {
3142 rb_str_append(result, fptr->pathv);
3143 if (fptr->fd < 0) {
3144 rb_str_cat(result, closed, strlen(closed));
3145 }
3146 }
3147 return rb_str_cat2(result, ">");
3148}
3149
3150/*
3151 * call-seq:
3152 * to_io -> self
3153 *
3154 * Returns +self+.
3155 *
3156 */
3157
3158static VALUE
3159rb_io_to_io(VALUE io)
3160{
3161 return io;
3162}
3163
3164/* reading functions */
3165static long
3166read_buffered_data(char *ptr, long len, rb_io_t *fptr)
3167{
3168 int n;
3169
3170 n = READ_DATA_PENDING_COUNT(fptr);
3171 if (n <= 0) return 0;
3172 if (n > len) n = (int)len;
3173 MEMMOVE(ptr, fptr->rbuf.ptr+fptr->rbuf.off, char, n);
3174 fptr->rbuf.off += n;
3175 fptr->rbuf.len -= n;
3176 return n;
3177}
3178
3179static long
3180io_bufread(char *ptr, long len, rb_io_t *fptr, long *read_len)
3181{
3182 long offset = 0;
3183 long n = len;
3184 long c;
3185
3186 *read_len = 0;
3187 if (READ_DATA_PENDING(fptr) == 0) {
3188 while (n > 0) {
3189 again:
3190 rb_io_check_closed(fptr);
3191 c = rb_io_read_memory(fptr, ptr+offset, n);
3192 if (c == 0) break;
3193 if (c < 0) {
3194 if (fptr_wait_readable(fptr))
3195 goto again;
3196 return -1;
3197 }
3198 offset += c;
3199 *read_len = offset;
3200 if ((n -= c) <= 0) break;
3201 }
3202 return len - n;
3203 }
3204
3205 while (n > 0) {
3206 c = read_buffered_data(ptr+offset, n, fptr);
3207 if (c > 0) {
3208 offset += c;
3209 *read_len = offset;
3210 if ((n -= c) <= 0) break;
3211 }
3212 rb_io_check_closed(fptr);
3213 if (io_fillbuf(fptr) < 0) {
3214 break;
3215 }
3216 }
3217 return len - n;
3218}
3219
3220static int io_setstrbuf(VALUE *str, long len);
3221
3223 char *str_ptr;
3224 long offset;
3225 long len;
3226 long read_len;
3227 rb_io_t *fptr;
3228};
3229
3230static VALUE
3231bufread_body(VALUE arg)
3232{
3233 struct bufread_arg *p = (struct bufread_arg *)arg;
3234 p->len = io_bufread(p->str_ptr + p->offset, p->len, p->fptr, &p->read_len);
3235 return Qundef;
3236}
3237
3238static VALUE
3239bufread_timeout(VALUE arg, VALUE error)
3240{
3241 struct bufread_arg *p = (struct bufread_arg *)arg;
3242
3243 if (p->offset + p->read_len > 0) {
3244 VALUE str = rb_str_new(p->str_ptr, p->offset + p->read_len);
3245 io_restore_read_buffer(str, p->fptr);
3246 }
3247 rb_exc_raise(error);
3249}
3250
3251static VALUE
3252bufread_call(VALUE arg)
3253{
3254 struct bufread_arg *p = (struct bufread_arg *)arg;
3255
3256 if (NIL_P(p->fptr->timeout)) {
3257 return bufread_body(arg);
3258 }
3259 return rb_rescue2(bufread_body, arg, bufread_timeout, arg,
3260 rb_eIOTimeoutError, (VALUE)0);
3261}
3262
3263static long
3264io_fread(VALUE str, long offset, long size, rb_io_t *fptr)
3265{
3266 long len;
3267 struct bufread_arg arg;
3268
3269 io_setstrbuf(&str, offset + size);
3270 arg.str_ptr = RSTRING_PTR(str);
3271 arg.offset = offset;
3272 arg.len = size;
3273 arg.read_len = 0;
3274 arg.fptr = fptr;
3275 rb_str_locktmp_ensure(str, bufread_call, (VALUE)&arg);
3276 len = arg.len;
3277 if (len < 0) rb_sys_fail_path(fptr->pathv);
3278 return len;
3279}
3280
3281static long
3282remain_size(rb_io_t *fptr)
3283{
3284 struct stat st;
3285 rb_off_t siz = READ_DATA_PENDING_COUNT(fptr);
3286 rb_off_t pos;
3287
3288 if (fstat(fptr->fd, &st) == 0 && S_ISREG(st.st_mode)
3289#if defined(__HAIKU__)
3290 && (st.st_dev > 3)
3291#endif
3292 )
3293 {
3294 if (io_fflush(fptr) < 0)
3295 rb_sys_fail_on_write(fptr);
3296 pos = lseek(fptr->fd, 0, SEEK_CUR);
3297 if (st.st_size >= pos && pos >= 0) {
3298 siz += st.st_size - pos;
3299 if (siz > LONG_MAX) {
3300 rb_raise(rb_eIOError, "file too big for single read");
3301 }
3302 }
3303 }
3304 else {
3305 siz += BUFSIZ;
3306 }
3307 return (long)siz;
3308}
3309
3310static VALUE
3311io_enc_str(VALUE str, rb_io_t *fptr)
3312{
3313 rb_enc_associate(str, io_read_encoding(fptr));
3314 return str;
3315}
3316
3317static void
3318make_readconv(rb_io_t *fptr, int size)
3319{
3320 if (!fptr->readconv) {
3321 int ecflags;
3322 VALUE ecopts;
3323 const char *sname, *dname;
3324 ecflags = fptr->encs.ecflags & ~ECONV_NEWLINE_DECORATOR_WRITE_MASK;
3325 ecopts = fptr->encs.ecopts;
3326 if (fptr->encs.enc2) {
3327 sname = rb_enc_name(fptr->encs.enc2);
3328 dname = rb_enc_name(io_read_encoding(fptr));
3329 }
3330 else {
3331 sname = dname = "";
3332 }
3333 fptr->readconv = rb_econv_open_opts(sname, dname, ecflags, ecopts);
3334 if (!fptr->readconv)
3335 rb_exc_raise(rb_econv_open_exc(sname, dname, ecflags));
3336 fptr->cbuf.off = 0;
3337 fptr->cbuf.len = 0;
3338 if (size < IO_CBUF_CAPA_MIN) size = IO_CBUF_CAPA_MIN;
3339 fptr->cbuf.capa = size;
3340 fptr->cbuf.ptr = ALLOC_N(char, fptr->cbuf.capa);
3341 }
3342}
3343
3344#define MORE_CHAR_SUSPENDED Qtrue
3345#define MORE_CHAR_FINISHED Qnil
3346static VALUE
3347fill_cbuf(rb_io_t *fptr, int ec_flags)
3348{
3349 const unsigned char *ss, *sp, *se;
3350 unsigned char *ds, *dp, *de;
3352 int putbackable;
3353 int cbuf_len0;
3354 VALUE exc;
3355
3356 ec_flags |= ECONV_PARTIAL_INPUT;
3357
3358 if (fptr->cbuf.len == fptr->cbuf.capa)
3359 return MORE_CHAR_SUSPENDED; /* cbuf full */
3360 if (fptr->cbuf.len == 0)
3361 fptr->cbuf.off = 0;
3362 else if (fptr->cbuf.off + fptr->cbuf.len == fptr->cbuf.capa) {
3363 memmove(fptr->cbuf.ptr, fptr->cbuf.ptr+fptr->cbuf.off, fptr->cbuf.len);
3364 fptr->cbuf.off = 0;
3365 }
3366
3367 cbuf_len0 = fptr->cbuf.len;
3368
3369 while (1) {
3370 ss = sp = (const unsigned char *)fptr->rbuf.ptr + fptr->rbuf.off;
3371 se = sp + fptr->rbuf.len;
3372 ds = dp = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.off + fptr->cbuf.len;
3373 de = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.capa;
3374 res = rb_econv_convert(fptr->readconv, &sp, se, &dp, de, ec_flags);
3375 fptr->rbuf.off += (int)(sp - ss);
3376 fptr->rbuf.len -= (int)(sp - ss);
3377 fptr->cbuf.len += (int)(dp - ds);
3378
3379 putbackable = rb_econv_putbackable(fptr->readconv);
3380 if (putbackable) {
3381 rb_econv_putback(fptr->readconv, (unsigned char *)fptr->rbuf.ptr + fptr->rbuf.off - putbackable, putbackable);
3382 fptr->rbuf.off -= putbackable;
3383 fptr->rbuf.len += putbackable;
3384 }
3385
3386 exc = rb_econv_make_exception(fptr->readconv);
3387 if (!NIL_P(exc))
3388 return exc;
3389
3390 if (cbuf_len0 != fptr->cbuf.len)
3391 return MORE_CHAR_SUSPENDED;
3392
3393 if (res == econv_finished) {
3394 return MORE_CHAR_FINISHED;
3395 }
3396
3397 if (res == econv_source_buffer_empty) {
3398 if (fptr->rbuf.len == 0) {
3399 READ_CHECK(fptr);
3400 if (io_fillbuf(fptr) < 0) {
3401 if (!fptr->readconv) {
3402 return MORE_CHAR_FINISHED;
3403 }
3404 ds = dp = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.off + fptr->cbuf.len;
3405 de = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.capa;
3406 res = rb_econv_convert(fptr->readconv, NULL, NULL, &dp, de, 0);
3407 fptr->cbuf.len += (int)(dp - ds);
3409 break;
3410 }
3411 }
3412 }
3413 }
3414 if (cbuf_len0 != fptr->cbuf.len)
3415 return MORE_CHAR_SUSPENDED;
3416
3417 return MORE_CHAR_FINISHED;
3418}
3419
3420static VALUE
3421more_char(rb_io_t *fptr)
3422{
3423 VALUE v;
3424 v = fill_cbuf(fptr, ECONV_AFTER_OUTPUT);
3425 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED)
3426 rb_exc_raise(v);
3427 return v;
3428}
3429
3430static VALUE
3431io_shift_cbuf(rb_io_t *fptr, int len, VALUE *strp)
3432{
3433 VALUE str = Qnil;
3434 if (strp) {
3435 str = *strp;
3436 if (NIL_P(str)) {
3437 *strp = str = rb_str_new(fptr->cbuf.ptr+fptr->cbuf.off, len);
3438 }
3439 else {
3440 rb_str_cat(str, fptr->cbuf.ptr+fptr->cbuf.off, len);
3441 }
3442 rb_enc_associate(str, fptr->encs.enc);
3443 }
3444 fptr->cbuf.off += len;
3445 fptr->cbuf.len -= len;
3446 /* xxx: set coderange */
3447 if (fptr->cbuf.len == 0)
3448 fptr->cbuf.off = 0;
3449 else if (fptr->cbuf.capa/2 < fptr->cbuf.off) {
3450 memmove(fptr->cbuf.ptr, fptr->cbuf.ptr+fptr->cbuf.off, fptr->cbuf.len);
3451 fptr->cbuf.off = 0;
3452 }
3453 return str;
3454}
3455
3456static int
3457io_setstrbuf(VALUE *str, long len)
3458{
3459 if (NIL_P(*str)) {
3460 *str = rb_str_new(0, len);
3461 return TRUE;
3462 }
3463 else {
3464 VALUE s = StringValue(*str);
3465 rb_str_modify(s);
3466
3467 long clen = RSTRING_LEN(s);
3468 if (clen >= len) {
3469 return FALSE;
3470 }
3471 len -= clen;
3472 }
3473 if ((rb_str_capacity(*str) - (size_t)RSTRING_LEN(*str)) < (size_t)len) {
3475 }
3476 return FALSE;
3477}
3478
3479#define MAX_REALLOC_GAP 4096
3480static void
3481io_shrink_read_string(VALUE str, long n)
3482{
3483 if (rb_str_capacity(str) - n > MAX_REALLOC_GAP) {
3484 rb_str_resize(str, n);
3485 }
3486}
3487
3488static void
3489io_set_read_length(VALUE str, long n, int shrinkable)
3490{
3491 if (RSTRING_LEN(str) != n) {
3492 rb_str_modify(str);
3493 rb_str_set_len(str, n);
3494 if (shrinkable) io_shrink_read_string(str, n);
3495 }
3496}
3497
3498static VALUE
3499read_all(rb_io_t *fptr, long siz, VALUE str)
3500{
3501 long bytes;
3502 long n;
3503 long pos;
3504 rb_encoding *enc;
3505 int cr;
3506 int shrinkable;
3507
3508 if (NEED_READCONV(fptr)) {
3509 int first = !NIL_P(str);
3510 SET_BINARY_MODE(fptr);
3511 shrinkable = io_setstrbuf(&str,0);
3512 make_readconv(fptr, 0);
3513 while (1) {
3514 VALUE v;
3515 if (fptr->cbuf.len) {
3516 if (first) rb_str_set_len(str, first = 0);
3517 io_shift_cbuf(fptr, fptr->cbuf.len, &str);
3518 }
3519 v = fill_cbuf(fptr, 0);
3520 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED) {
3521 if (fptr->cbuf.len) {
3522 if (first) rb_str_set_len(str, first = 0);
3523 io_shift_cbuf(fptr, fptr->cbuf.len, &str);
3524 }
3525 rb_exc_raise(v);
3526 }
3527 if (v == MORE_CHAR_FINISHED) {
3528 clear_readconv(fptr);
3529 if (first) rb_str_set_len(str, first = 0);
3530 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3531 return io_enc_str(str, fptr);
3532 }
3533 }
3534 }
3535
3536 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3537 bytes = 0;
3538 pos = 0;
3539
3540 enc = io_read_encoding(fptr);
3541 cr = 0;
3542
3543 if (siz == 0) {
3544 siz = BUFSIZ;
3545 }
3546 else {
3547 // If `siz` is set, we got it from `stat(2)`.
3548 // We attempt to read one extra byte because:
3549 // - If the file was appended to since then, we'll continue reading.
3550 // - If the file is still the same length, we won't issue a second `io_fread`.
3551 siz++;
3552 }
3553 shrinkable = io_setstrbuf(&str, siz);
3554 for (;;) {
3555 READ_CHECK(fptr);
3556 n = io_fread(str, bytes, siz - bytes, fptr);
3557 if (n == 0 && bytes == 0) {
3558 rb_str_set_len(str, 0);
3559 break;
3560 }
3561 bytes += n;
3562 rb_str_set_len(str, bytes);
3563 if (cr != ENC_CODERANGE_BROKEN)
3564 pos += rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + bytes, enc, &cr);
3565 if (bytes < siz) break;
3566 siz += BUFSIZ;
3567
3568 size_t capa = rb_str_capacity(str);
3569 if (capa < (size_t)RSTRING_LEN(str) + BUFSIZ) {
3570 if (capa < BUFSIZ) {
3571 capa = BUFSIZ;
3572 }
3573 else if (capa > IO_MAX_BUFFER_GROWTH) {
3574 capa = IO_MAX_BUFFER_GROWTH;
3575 }
3577 }
3578 }
3579 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3580 str = io_enc_str(str, fptr);
3581 ENC_CODERANGE_SET(str, cr);
3582 return str;
3583}
3584
3585void
3587{
3588 if (rb_fd_set_nonblock(fptr->fd) != 0) {
3589 rb_sys_fail_path(fptr->pathv);
3590 }
3591}
3592
3593static VALUE
3594io_read_memory_call(VALUE arg)
3595{
3596 struct io_internal_read_struct *iis = (struct io_internal_read_struct *)arg;
3597
3598 VALUE scheduler = rb_fiber_scheduler_current();
3599 if (scheduler != Qnil) {
3600 VALUE result = rb_fiber_scheduler_io_read_memory(scheduler, iis->fptr->self, iis->buf, iis->capa);
3601
3602 if (!UNDEF_P(result)) {
3603 // This is actually returned as a pseudo-VALUE and later cast to a long:
3605 }
3606 }
3607
3608 if (iis->nonblock) {
3609 return rb_io_blocking_region(iis->fptr, internal_read_func, iis);
3610 }
3611 else {
3612 return rb_io_blocking_region_wait(iis->fptr, internal_read_func, iis, RUBY_IO_READABLE);
3613 }
3614}
3615
3616static long
3617io_read_memory_locktmp(VALUE str, struct io_internal_read_struct *iis)
3618{
3619 return (long)rb_str_locktmp_ensure(str, io_read_memory_call, (VALUE)iis);
3620}
3621
3622#define no_exception_p(opts) !rb_opts_exception_p((opts), TRUE)
3623
3624static VALUE
3625io_getpartial(int argc, VALUE *argv, VALUE io, int no_exception, int nonblock)
3626{
3627 rb_io_t *fptr;
3628 VALUE length, str;
3629 long n, len;
3630 struct io_internal_read_struct iis;
3631 int shrinkable;
3632
3633 rb_scan_args(argc, argv, "11", &length, &str);
3634
3635 if ((len = NUM2LONG(length)) < 0) {
3636 rb_raise(rb_eArgError, "negative length %ld given", len);
3637 }
3638
3639 shrinkable = io_setstrbuf(&str, len);
3640
3641 GetOpenFile(io, fptr);
3643
3644 if (len == 0) {
3645 io_set_read_length(str, 0, shrinkable);
3646 return str;
3647 }
3648
3649 if (!nonblock)
3650 READ_CHECK(fptr);
3651 n = read_buffered_data(RSTRING_PTR(str), len, fptr);
3652 if (n <= 0) {
3653 again:
3654 if (nonblock) {
3655 rb_io_set_nonblock(fptr);
3656 }
3657 io_setstrbuf(&str, len);
3658 iis.th = rb_thread_current();
3659 iis.fptr = fptr;
3660 iis.nonblock = nonblock;
3661 iis.fd = fptr->fd;
3662 iis.buf = RSTRING_PTR(str);
3663 iis.capa = len;
3664 iis.timeout = NULL;
3665 n = io_read_memory_locktmp(str, &iis);
3666 if (n < 0) {
3667 int e = errno;
3668 if (!nonblock && fptr_wait_readable(fptr))
3669 goto again;
3670 if (nonblock && (io_again_p(e))) {
3671 if (no_exception)
3672 return sym_wait_readable;
3673 else
3674 rb_readwrite_syserr_fail(RB_IO_WAIT_READABLE,
3675 e, "read would block");
3676 }
3677 rb_syserr_fail_path(e, fptr->pathv);
3678 }
3679 }
3680 io_set_read_length(str, n, shrinkable);
3681
3682 if (n == 0)
3683 return Qnil;
3684 else
3685 return str;
3686}
3687
3688/*
3689 * call-seq:
3690 * readpartial(maxlen) -> string
3691 * readpartial(maxlen, out_string) -> out_string
3692 *
3693 * Reads up to +maxlen+ bytes from the stream;
3694 * returns a string (either a new string or the given +out_string+).
3695 * Its encoding is:
3696 *
3697 * - The unchanged encoding of +out_string+, if +out_string+ is given.
3698 * - ASCII-8BIT, otherwise.
3699 *
3700 * - Contains +maxlen+ bytes from the stream, if available.
3701 * - Otherwise contains all available bytes, if any available.
3702 * - Is an empty string if +maxlen+ is zero.
3703 *
3704 * With the single non-negative integer argument +maxlen+ given,
3705 * returns a new string:
3706 *
3707 * f = File.new('t.txt')
3708 * f.readpartial(20) # => "First line\nSecond l"
3709 * f.readpartial(20) # => "ine\n\nFourth line\n"
3710 * f.readpartial(20) # => "Fifth line\n"
3711 * f.readpartial(20) # Raises EOFError.
3712 * f.close
3713 *
3714 * With both argument +maxlen+ and string argument +out_string+ given,
3715 * returns modified +out_string+:
3716 *
3717 * f = File.new('t.txt')
3718 * s = 'foo'
3719 * f.readpartial(20, s) # => "First line\nSecond l"
3720 * s = 'bar'
3721 * f.readpartial(0, s) # => ""
3722 * f.close
3723 *
3724 * This method is useful for a stream such as a pipe, a socket, or a tty.
3725 * It blocks only when no data is immediately available.
3726 * This means that it blocks only when _all_ of the following are true:
3727 *
3728 * - The byte buffer in the stream is empty.
3729 * - The content of the stream is empty.
3730 * - The stream is not at EOF.
3731 *
3732 * When blocked, the method waits for either more data or EOF on the stream:
3733 *
3734 * - If more data is read, the method returns the data.
3735 * - If EOF is reached, the method raises EOFError.
3736 *
3737 * When not blocked, the method responds immediately:
3738 *
3739 * - Returns data from the buffer if there is any.
3740 * - Otherwise returns data from the stream if there is any.
3741 * - Otherwise raises EOFError if the stream has reached EOF.
3742 *
3743 * Note that this method is similar to sysread. The differences are:
3744 *
3745 * - If the byte buffer is not empty, read from the byte buffer
3746 * instead of "sysread for buffered IO (IOError)".
3747 * - It doesn't cause Errno::EWOULDBLOCK and Errno::EINTR. When
3748 * readpartial meets EWOULDBLOCK and EINTR by read system call,
3749 * readpartial retries the system call.
3750 *
3751 * The latter means that readpartial is non-blocking-flag insensitive.
3752 * It blocks on the situation IO#sysread causes Errno::EWOULDBLOCK as
3753 * if the fd is blocking mode.
3754 *
3755 * Examples:
3756 *
3757 * # # Returned Buffer Content Pipe Content
3758 * r, w = IO.pipe #
3759 * w << 'abc' # "" "abc".
3760 * r.readpartial(4096) # => "abc" "" ""
3761 * r.readpartial(4096) # (Blocks because buffer and pipe are empty.)
3762 *
3763 * # # Returned Buffer Content Pipe Content
3764 * r, w = IO.pipe #
3765 * w << 'abc' # "" "abc"
3766 * w.close # "" "abc" EOF
3767 * r.readpartial(4096) # => "abc" "" EOF
3768 * r.readpartial(4096) # raises EOFError
3769 *
3770 * # # Returned Buffer Content Pipe Content
3771 * r, w = IO.pipe #
3772 * w << "abc\ndef\n" # "" "abc\ndef\n"
3773 * r.gets # => "abc\n" "def\n" ""
3774 * w << "ghi\n" # "def\n" "ghi\n"
3775 * r.readpartial(4096) # => "def\n" "" "ghi\n"
3776 * r.readpartial(4096) # => "ghi\n" "" ""
3777 *
3778 */
3779
3780static VALUE
3781io_readpartial(int argc, VALUE *argv, VALUE io)
3782{
3783 VALUE ret;
3784
3785 ret = io_getpartial(argc, argv, io, Qnil, 0);
3786 if (NIL_P(ret))
3787 rb_eof_error();
3788 return ret;
3789}
3790
3791static VALUE
3792io_nonblock_eof(int no_exception)
3793{
3794 if (!no_exception) {
3795 rb_eof_error();
3796 }
3797 return Qnil;
3798}
3799
3800/* :nodoc: */
3801static VALUE
3802io_read_nonblock(rb_execution_context_t *ec, VALUE io, VALUE length, VALUE str, VALUE ex)
3803{
3804 rb_io_t *fptr;
3805 long n, len;
3806 struct io_internal_read_struct iis;
3807 int shrinkable;
3808
3809 if ((len = NUM2LONG(length)) < 0) {
3810 rb_raise(rb_eArgError, "negative length %ld given", len);
3811 }
3812
3813 shrinkable = io_setstrbuf(&str, len);
3814 rb_bool_expected(ex, "exception", TRUE);
3815
3816 GetOpenFile(io, fptr);
3818
3819 if (len == 0) {
3820 io_set_read_length(str, 0, shrinkable);
3821 return str;
3822 }
3823
3824 n = read_buffered_data(RSTRING_PTR(str), len, fptr);
3825 if (n <= 0) {
3826 rb_fd_set_nonblock(fptr->fd);
3827 shrinkable |= io_setstrbuf(&str, len);
3828 iis.fptr = fptr;
3829 iis.nonblock = 1;
3830 iis.fd = fptr->fd;
3831 iis.buf = RSTRING_PTR(str);
3832 iis.capa = len;
3833 iis.timeout = NULL;
3834 n = io_read_memory_locktmp(str, &iis);
3835 if (n < 0) {
3836 int e = errno;
3837 if (io_again_p(e)) {
3838 if (!ex) return sym_wait_readable;
3839 rb_readwrite_syserr_fail(RB_IO_WAIT_READABLE,
3840 e, "read would block");
3841 }
3842 rb_syserr_fail_path(e, fptr->pathv);
3843 }
3844 }
3845 io_set_read_length(str, n, shrinkable);
3846
3847 if (n == 0) {
3848 if (!ex) return Qnil;
3849 rb_eof_error();
3850 }
3851
3852 return str;
3853}
3854
3855/* :nodoc: */
3856static VALUE
3857io_write_nonblock(rb_execution_context_t *ec, VALUE io, VALUE str, VALUE ex)
3858{
3859 rb_io_t *fptr;
3860 long n;
3861
3862 if (!RB_TYPE_P(str, T_STRING))
3863 str = rb_obj_as_string(str);
3864 rb_bool_expected(ex, "exception", TRUE);
3865
3866 io = GetWriteIO(io);
3867 GetOpenFile(io, fptr);
3869
3870 if (io_fflush(fptr) < 0)
3871 rb_sys_fail_on_write(fptr);
3872
3873 rb_fd_set_nonblock(fptr->fd);
3874 n = write(fptr->fd, RSTRING_PTR(str), RSTRING_LEN(str));
3875 RB_GC_GUARD(str);
3876
3877 if (n < 0) {
3878 int e = errno;
3879 if (io_again_p(e)) {
3880 if (!ex) {
3881 return sym_wait_writable;
3882 }
3883 else {
3884 rb_readwrite_syserr_fail(RB_IO_WAIT_WRITABLE, e, "write would block");
3885 }
3886 }
3887 rb_syserr_fail_path(e, fptr->pathv);
3888 }
3889
3890 return LONG2FIX(n);
3891}
3892
3893/*
3894 * call-seq:
3895 * read(maxlen = nil, out_string = nil) -> new_string, out_string, or nil
3896 *
3897 * Reads bytes from the stream; the stream must be opened for reading
3898 * (see {Access Modes}[rdoc-ref:File@Access+Modes]):
3899 *
3900 * - If +maxlen+ is +nil+, reads all bytes using the stream's data mode.
3901 * - Otherwise reads up to +maxlen+ bytes in binary mode.
3902 *
3903 * Returns a string (either a new string or the given +out_string+)
3904 * containing the bytes read.
3905 * The encoding of the string depends on both +maxLen+ and +out_string+:
3906 *
3907 * - +maxlen+ is +nil+: uses internal encoding of +self+
3908 * (regardless of whether +out_string+ was given).
3909 * - +maxlen+ not +nil+:
3910 *
3911 * - +out_string+ given: encoding of +out_string+ not modified.
3912 * - +out_string+ not given: ASCII-8BIT is used.
3913 *
3914 * <b>Without Argument +out_string+</b>
3915 *
3916 * When argument +out_string+ is omitted,
3917 * the returned value is a new string:
3918 *
3919 * f = File.new('t.txt')
3920 * f.read
3921 * # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3922 * f.rewind
3923 * f.read(30) # => "First line\r\nSecond line\r\n\r\nFou"
3924 * f.read(30) # => "rth line\r\nFifth line\r\n"
3925 * f.read(30) # => nil
3926 * f.close
3927 *
3928 * If +maxlen+ is zero, returns an empty string.
3929 *
3930 * <b> With Argument +out_string+</b>
3931 *
3932 * When argument +out_string+ is given,
3933 * the returned value is +out_string+, whose content is replaced:
3934 *
3935 * f = File.new('t.txt')
3936 * s = 'foo' # => "foo"
3937 * f.read(nil, s) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3938 * s # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3939 * f.rewind
3940 * s = 'bar'
3941 * f.read(30, s) # => "First line\r\nSecond line\r\n\r\nFou"
3942 * s # => "First line\r\nSecond line\r\n\r\nFou"
3943 * s = 'baz'
3944 * f.read(30, s) # => "rth line\r\nFifth line\r\n"
3945 * s # => "rth line\r\nFifth line\r\n"
3946 * s = 'bat'
3947 * f.read(30, s) # => nil
3948 * s # => ""
3949 * f.close
3950 *
3951 * Note that this method behaves like the fread() function in C.
3952 * This means it retries to invoke read(2) system calls to read data
3953 * with the specified maxlen (or until EOF).
3954 *
3955 * This behavior is preserved even if the stream is in non-blocking mode.
3956 * (This method is non-blocking-flag insensitive as other methods.)
3957 *
3958 * If you need the behavior like a single read(2) system call,
3959 * consider #readpartial, #read_nonblock, and #sysread.
3960 *
3961 * Related: IO#write.
3962 */
3963
3964static VALUE
3965io_read(int argc, VALUE *argv, VALUE io)
3966{
3967 rb_io_t *fptr;
3968 long n, len;
3969 VALUE length, str;
3970 int shrinkable;
3971#if RUBY_CRLF_ENVIRONMENT
3972 int previous_mode;
3973#endif
3974
3975 rb_scan_args(argc, argv, "02", &length, &str);
3976
3977 if (NIL_P(length)) {
3978 GetOpenFile(io, fptr);
3980 return read_all(fptr, remain_size(fptr), str);
3981 }
3982 len = NUM2LONG(length);
3983 if (len < 0) {
3984 rb_raise(rb_eArgError, "negative length %ld given", len);
3985 }
3986
3987 shrinkable = io_setstrbuf(&str,len);
3988
3989 GetOpenFile(io, fptr);
3991 if (len == 0) {
3992 io_set_read_length(str, 0, shrinkable);
3993 return str;
3994 }
3995
3996 READ_CHECK(fptr);
3997#if RUBY_CRLF_ENVIRONMENT
3998 previous_mode = set_binary_mode_with_seek_cur(fptr);
3999#endif
4000 n = io_fread(str, 0, len, fptr);
4001 io_set_read_length(str, n, shrinkable);
4002#if RUBY_CRLF_ENVIRONMENT
4003 if (previous_mode == O_TEXT) {
4004 setmode(fptr->fd, O_TEXT);
4005 }
4006#endif
4007 if (n == 0) return Qnil;
4008
4009 return str;
4010}
4011
4012static void
4013rscheck(const char *rsptr, long rslen, VALUE rs)
4014{
4015 if (!rs) return;
4016 if (RSTRING_PTR(rs) != rsptr && RSTRING_LEN(rs) != rslen)
4017 rb_raise(rb_eRuntimeError, "rs modified");
4018}
4019
4020static const char *
4021search_delim(const char *p, long len, int delim, rb_encoding *enc)
4022{
4023 if (rb_enc_mbminlen(enc) == 1) {
4024 p = memchr(p, delim, len);
4025 if (p) return p + 1;
4026 }
4027 else {
4028 const char *end = p + len;
4029 while (p < end) {
4030 int r = rb_enc_precise_mbclen(p, end, enc);
4031 if (!MBCLEN_CHARFOUND_P(r)) {
4032 p += rb_enc_mbminlen(enc);
4033 continue;
4034 }
4035 int n = MBCLEN_CHARFOUND_LEN(r);
4036 if (rb_enc_mbc_to_codepoint(p, end, enc) == (unsigned int)delim) {
4037 return p + n;
4038 }
4039 p += n;
4040 }
4041 }
4042 return NULL;
4043}
4044
4045static int
4046read_raw_character(rb_io_t *fptr, rb_encoding *enc, char *buf)
4047{
4048 int n = 0;
4049 int r;
4050
4051 do {
4052 if (!READ_DATA_PENDING(fptr)) {
4053 READ_CHECK(fptr);
4054 if (io_fillbuf(fptr) < 0) break;
4055 }
4056 buf[n++] = *READ_DATA_PENDING_PTR(fptr);
4057 fptr->rbuf.off++;
4058 fptr->rbuf.len--;
4059 r = rb_enc_precise_mbclen(buf, buf + n, enc);
4060 } while (MBCLEN_NEEDMORE_P(r) && n < rb_enc_mbmaxlen(enc));
4061
4062 return n;
4063}
4064
4065static void
4066unread_raw_character(rb_io_t *fptr, const char *buf, int len)
4067{
4068 if (fptr->rbuf.capa - fptr->rbuf.len < len) {
4069 if (fptr->rbuf.capa > INT_MAX - len)
4070 rb_raise(rb_eIOError, "ungetbyte failed");
4071 fptr->rbuf.capa += len;
4072 REALLOC_N(fptr->rbuf.ptr, char, fptr->rbuf.capa);
4073 }
4074 io_ungetbyte(rb_str_new(buf, len), fptr);
4075}
4076
4077static const char *
4078search_wide_delim(const char *p, long len, const char *delim, int width)
4079{
4080 const char *e = p + len;
4081 int index = 0;
4082
4083 while (index < width && delim[index] == 0) index++;
4084 if (index == width) index = 0;
4085
4086 const char *candidate = p + index;
4087 while (candidate < e) {
4088 candidate = memchr(candidate, (unsigned char)delim[index], e - candidate);
4089 if (candidate == NULL) break;
4090 const char *start = candidate - index;
4091 if ((start - p) % width == 0 && start + width <= e &&
4092 memcmp(start, delim, width) == 0) {
4093 return start;
4094 }
4095 candidate++;
4096 }
4097 return NULL;
4098}
4099
4100static int
4101appendline(rb_io_t *fptr, int delim, VALUE *strp, long *lp, rb_encoding *enc)
4102{
4103 VALUE str = *strp;
4104 long limit = *lp;
4105
4106 if (NEED_READCONV(fptr)) {
4107 SET_BINARY_MODE(fptr);
4108 make_readconv(fptr, 0);
4109 do {
4110 const char *p, *e;
4111 int searchlen = READ_CHAR_PENDING_COUNT(fptr);
4112 if (searchlen) {
4113 p = READ_CHAR_PENDING_PTR(fptr);
4114 if (0 < limit && limit < searchlen)
4115 searchlen = (int)limit;
4116 e = search_delim(p, searchlen, delim, enc);
4117 if (e) {
4118 int len = (int)(e-p);
4119 if (NIL_P(str))
4120 *strp = str = rb_str_new(p, len);
4121 else
4122 rb_str_buf_cat(str, p, len);
4123 fptr->cbuf.off += len;
4124 fptr->cbuf.len -= len;
4125 limit -= len;
4126 *lp = limit;
4127 return delim;
4128 }
4129
4130 if (NIL_P(str))
4131 *strp = str = rb_str_new(p, searchlen);
4132 else
4133 rb_str_buf_cat(str, p, searchlen);
4134 fptr->cbuf.off += searchlen;
4135 fptr->cbuf.len -= searchlen;
4136 limit -= searchlen;
4137
4138 if (limit == 0) {
4139 *lp = limit;
4140 return (unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
4141 }
4142 }
4143 } while (more_char(fptr) != MORE_CHAR_FINISHED);
4144 clear_readconv(fptr);
4145 *lp = limit;
4146 return EOF;
4147 }
4148
4149 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4150 if (rb_enc_mbminlen(enc) != 1) {
4151 char buf[ONIGENC_CODE_TO_MBC_MAXLEN];
4152 int len;
4153
4154 if (limit < 0) {
4155 int width = rb_enc_mbminlen(enc);
4156 int delim_len = rb_enc_codelen(delim, enc);
4157
4158 if (delim_len == width) {
4159 rb_enc_mbcput(delim, buf, enc);
4160 for (;;) {
4161 if (!READ_DATA_PENDING(fptr)) {
4162 READ_CHECK(fptr);
4163 if (io_fillbuf(fptr) < 0) return EOF;
4164 }
4165 long pending = READ_DATA_PENDING_COUNT(fptr);
4166 long complete = pending - pending % width;
4167 const char *p = READ_DATA_PENDING_PTR(fptr);
4168 const char *q = complete ? search_wide_delim(p, complete, buf, width) : NULL;
4169 long take = q ? q - p + width : complete;
4170
4171 if (take > 0) {
4172 if (NIL_P(str))
4173 *strp = str = rb_str_buf_new(0);
4174 rb_str_buf_cat(str, p, take);
4175 fptr->rbuf.off += (int)take;
4176 fptr->rbuf.len -= (int)take;
4177 }
4178 if (q) return delim;
4179 if (complete == pending) continue;
4180
4181 len = read_raw_character(fptr, enc, buf);
4182 if (len == 0) return EOF;
4183 if (NIL_P(str))
4184 *strp = str = rb_str_buf_new(0);
4185 rb_str_buf_cat(str, buf, len);
4186 int r = rb_enc_precise_mbclen(buf, buf + len, enc);
4187 if (MBCLEN_CHARFOUND_P(r) &&
4188 rb_enc_mbc_to_codepoint(buf, buf + len, enc) == (unsigned int)delim)
4189 return delim;
4190 }
4191 }
4192 }
4193
4194 while ((len = read_raw_character(fptr, enc, buf)) > 0) {
4195 if (NIL_P(str))
4196 *strp = str = rb_str_buf_new(0);
4197 rb_str_buf_cat(str, buf, len);
4198 if (limit > 0) {
4199 if (len > limit) {
4200 *lp = 0;
4201 return (unsigned char)buf[len - 1];
4202 }
4203 *lp = limit -= len;
4204 }
4205 int r = rb_enc_precise_mbclen(buf, buf + len, enc);
4206 if (MBCLEN_CHARFOUND_P(r) &&
4207 rb_enc_mbc_to_codepoint(buf, buf + len, enc) == (unsigned int)delim)
4208 return delim;
4209 if (limit == 0)
4210 return (unsigned char)buf[len - 1];
4211 }
4212 *lp = limit;
4213 return EOF;
4214 }
4215 do {
4216 long pending = READ_DATA_PENDING_COUNT(fptr);
4217 if (pending > 0) {
4218 const char *p = READ_DATA_PENDING_PTR(fptr);
4219 const char *e;
4220 long last;
4221
4222 if (limit > 0 && pending > limit) pending = limit;
4223 e = search_delim(p, pending, delim, enc);
4224 if (e) pending = e - p;
4225 if (!NIL_P(str)) {
4226 last = RSTRING_LEN(str);
4227 rb_str_resize(str, last + pending);
4228 }
4229 else {
4230 last = 0;
4231 *strp = str = rb_str_buf_new(pending);
4232 rb_str_set_len(str, pending);
4233 }
4234 read_buffered_data(RSTRING_PTR(str) + last, pending, fptr); /* must not fail */
4235 limit -= pending;
4236 *lp = limit;
4237 if (e) return delim;
4238 if (limit == 0)
4239 return (unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
4240 }
4241 READ_CHECK(fptr);
4242 } while (io_fillbuf(fptr) >= 0);
4243 *lp = limit;
4244 return EOF;
4245}
4246
4247static inline int
4248swallow(rb_io_t *fptr, int term)
4249{
4250 if (NEED_READCONV(fptr)) {
4251 rb_encoding *enc = io_read_encoding(fptr);
4252 int needconv = rb_enc_mbminlen(enc) != 1;
4253 SET_BINARY_MODE(fptr);
4254 make_readconv(fptr, 0);
4255 do {
4256 size_t cnt;
4257 while ((cnt = READ_CHAR_PENDING_COUNT(fptr)) > 0) {
4258 const char *p = READ_CHAR_PENDING_PTR(fptr);
4259 int i;
4260 if (!needconv) {
4261 if (*p != term) return TRUE;
4262 i = (int)cnt;
4263 while (--i && *++p == term);
4264 }
4265 else {
4266 const char *e = p + cnt;
4267 if (rb_enc_ascget(p, e, &i, enc) != term) return TRUE;
4268 while ((p += i) < e && rb_enc_ascget(p, e, &i, enc) == term);
4269 i = (int)(e - p);
4270 }
4271 io_shift_cbuf(fptr, (int)cnt - i, NULL);
4272 }
4273 } while (more_char(fptr) != MORE_CHAR_FINISHED);
4274 return FALSE;
4275 }
4276
4277 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4278 rb_encoding *enc = io_read_encoding(fptr);
4279 int widechar = rb_enc_mbminlen(enc) != 1;
4280 if (widechar) {
4281 char buf[ONIGENC_CODE_TO_MBC_MAXLEN];
4282 int len;
4283
4284 while ((len = read_raw_character(fptr, enc, buf)) > 0) {
4285 if (rb_enc_ascget(buf, buf + len, NULL, enc) != term) {
4286 unread_raw_character(fptr, buf, len);
4287 return TRUE;
4288 }
4289 }
4290 return FALSE;
4291 }
4292 do {
4293 size_t cnt;
4294 while ((cnt = READ_DATA_PENDING_COUNT(fptr)) > 0) {
4295 char buf[1024];
4296 const char *p = READ_DATA_PENDING_PTR(fptr);
4297 int i;
4298 if (cnt > sizeof buf) cnt = sizeof buf;
4299 if (*p != term) return TRUE;
4300 i = (int)cnt;
4301 while (--i && *++p == term);
4302 if (!read_buffered_data(buf, cnt - i, fptr)) /* must not fail */
4303 rb_sys_fail_path(fptr->pathv);
4304 }
4305 READ_CHECK(fptr);
4306 } while (io_fillbuf(fptr) == 0);
4307 return FALSE;
4308}
4309
4310static VALUE
4311rb_io_getline_fast(rb_io_t *fptr, rb_encoding *enc, int chomp)
4312{
4313 VALUE str = Qnil;
4314 int len = 0;
4315 long pos = 0;
4316 int cr = 0;
4317
4318 do {
4319 int pending = READ_DATA_PENDING_COUNT(fptr);
4320
4321 if (pending > 0) {
4322 const char *p = READ_DATA_PENDING_PTR(fptr);
4323 const char *e;
4324 int chomplen = 0;
4325
4326 e = memchr(p, '\n', pending);
4327 if (e) {
4328 pending = (int)(e - p + 1);
4329 if (chomp) {
4330 chomplen = (pending > 1 && *(e-1) == '\r') + 1;
4331 }
4332 }
4333 if (NIL_P(str)) {
4334 str = rb_str_new(p, pending - chomplen);
4335 fptr->rbuf.off += pending;
4336 fptr->rbuf.len -= pending;
4337 }
4338 else {
4339 rb_str_resize(str, len + pending - chomplen);
4340 read_buffered_data(RSTRING_PTR(str)+len, pending - chomplen, fptr);
4341 fptr->rbuf.off += chomplen;
4342 fptr->rbuf.len -= chomplen;
4343 if (pending == 1 && chomplen == 1 && len > 0) {
4344 if (RSTRING_PTR(str)[len-1] == '\r') {
4345 rb_str_resize(str, --len);
4346 break;
4347 }
4348 }
4349 }
4350 len += pending - chomplen;
4351 if (cr != ENC_CODERANGE_BROKEN)
4352 pos += rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + len, enc, &cr);
4353 if (e) break;
4354 }
4355 READ_CHECK(fptr);
4356 } while (io_fillbuf(fptr) >= 0);
4357 if (NIL_P(str)) return Qnil;
4358
4359 str = io_enc_str(str, fptr);
4360 ENC_CODERANGE_SET(str, cr);
4361 fptr->lineno++;
4362
4363 return str;
4364}
4365
4367 VALUE io;
4368 VALUE rs;
4369 long limit;
4370 unsigned int chomp: 1;
4371};
4372
4373static void
4374extract_getline_opts(VALUE opts, struct getline_arg *args)
4375{
4376 int chomp = FALSE;
4377 if (!NIL_P(opts)) {
4378 static ID kwds[1];
4379 VALUE vchomp;
4380 if (!kwds[0]) {
4381 kwds[0] = rb_intern_const("chomp");
4382 }
4383 rb_get_kwargs(opts, kwds, 0, -2, &vchomp);
4384 chomp = (!UNDEF_P(vchomp)) && RTEST(vchomp);
4385 }
4386 args->chomp = chomp;
4387}
4388
4389static void
4390extract_getline_args(int argc, VALUE *argv, struct getline_arg *args)
4391{
4392 VALUE rs = rb_rs, lim = Qnil;
4393
4394 if (argc == 1) {
4395 VALUE tmp = Qnil;
4396
4397 if (NIL_P(argv[0]) || !NIL_P(tmp = rb_check_string_type(argv[0]))) {
4398 rs = tmp;
4399 }
4400 else {
4401 lim = argv[0];
4402 }
4403 }
4404 else if (2 <= argc) {
4405 rs = argv[0], lim = argv[1];
4406 if (!NIL_P(rs))
4407 StringValue(rs);
4408 }
4409 args->rs = rs;
4410 args->limit = NIL_P(lim) ? -1L : NUM2LONG(lim);
4411}
4412
4413static void
4414check_getline_args(VALUE *rsp, long *limit, VALUE io)
4415{
4416 rb_io_t *fptr;
4417 VALUE rs = *rsp;
4418
4419 if (!NIL_P(rs)) {
4420 rb_encoding *enc_rs, *enc_io;
4421
4422 GetOpenFile(io, fptr);
4423 enc_rs = rb_enc_get(rs);
4424 enc_io = io_read_encoding(fptr);
4425 if (enc_io != enc_rs &&
4426 (!is_ascii_string(rs) ||
4427 (RSTRING_LEN(rs) > 0 && !rb_enc_asciicompat(enc_io)))) {
4428 if (rs == rb_default_rs) {
4429 rs = rb_enc_str_new(0, 0, enc_io);
4430 rb_str_buf_cat_ascii(rs, "\n");
4431 *rsp = rs;
4432 }
4433 else {
4434 rb_raise(rb_eArgError, "encoding mismatch: %s IO with %s RS",
4435 rb_enc_name(enc_io),
4436 rb_enc_name(enc_rs));
4437 }
4438 }
4439 }
4440}
4441
4442static void
4443prepare_getline_args(int argc, VALUE *argv, struct getline_arg *args, VALUE io)
4444{
4445 VALUE opts;
4446 argc = rb_scan_args(argc, argv, "02:", NULL, NULL, &opts);
4447 extract_getline_args(argc, argv, args);
4448 extract_getline_opts(opts, args);
4449 check_getline_args(&args->rs, &args->limit, io);
4450}
4451
4452static VALUE
4453rb_io_getline_0(VALUE rs, long limit, int chomp, rb_io_t *fptr)
4454{
4455 VALUE str = Qnil;
4456 int nolimit = 0;
4457 rb_encoding *enc;
4458
4460 if (NIL_P(rs) && limit < 0) {
4461 str = read_all(fptr, 0, Qnil);
4462 if (RSTRING_LEN(str) == 0) return Qnil;
4463 }
4464 else if (limit == 0) {
4465 return rb_enc_str_new(0, 0, io_read_encoding(fptr));
4466 }
4467 else if (rs == rb_default_rs && limit < 0 && !NEED_READCONV(fptr) &&
4468 rb_enc_asciicompat(enc = io_read_encoding(fptr))) {
4469 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4470 return rb_io_getline_fast(fptr, enc, chomp);
4471 }
4472 else {
4473 int c, newline = -1;
4474 const char *rsptr = 0;
4475 long rslen = 0;
4476 int rspara = 0;
4477 int extra_limit = 16;
4478 int chomp_cr = chomp;
4479
4480 SET_BINARY_MODE(fptr);
4481 enc = io_read_encoding(fptr);
4482
4483 if (!NIL_P(rs)) {
4484 rslen = RSTRING_LEN(rs);
4485 if (rslen == 0) {
4486 rsptr = "\n\n";
4487 rslen = 2;
4488 rspara = 1;
4489 swallow(fptr, '\n');
4490 rs = 0;
4491 if (!rb_enc_asciicompat(enc)) {
4492 rs = rb_usascii_str_new(rsptr, rslen);
4493 rs = rb_str_conv_enc(rs, 0, enc);
4494 OBJ_FREEZE(rs);
4495 rsptr = RSTRING_PTR(rs);
4496 rslen = RSTRING_LEN(rs);
4497 }
4498 newline = '\n';
4499 }
4500 else if (rb_enc_mbminlen(enc) == 1) {
4501 rsptr = RSTRING_PTR(rs);
4502 newline = (unsigned char)rsptr[rslen - 1];
4503 }
4504 else {
4505 rs = rb_str_conv_enc(rs, 0, enc);
4506 rsptr = RSTRING_PTR(rs);
4507 const char *e = rsptr + rslen;
4508 const char *last = rb_enc_prev_char(rsptr, e, e, enc);
4509 int n;
4510 newline = rb_enc_codepoint_len(last, e, &n, enc);
4511 if (last + n != e) rb_raise(rb_eArgError, "broken separator");
4512 }
4513 chomp_cr = chomp && newline == '\n' && rslen == rb_enc_mbminlen(enc);
4514 }
4515
4516 /* MS - Optimization */
4517 while ((c = appendline(fptr, newline, &str, &limit, enc)) != EOF) {
4518 const char *s, *p, *pp, *e;
4519
4520 if (c == newline && RSTRING_LEN(str) >= rslen) {
4521 s = RSTRING_PTR(str);
4522 e = RSTRING_END(str);
4523 p = e - rslen;
4524 if (at_char_boundary(s, p, e, enc)) {
4525 if (!rspara) rscheck(rsptr, rslen, rs);
4526 if (memcmp(p, rsptr, rslen) == 0) {
4527 if (chomp) {
4528 if (chomp_cr && p > s && *(p-1) == '\r') --p;
4529 rb_str_set_len(str, p - s);
4530 }
4531 break;
4532 }
4533 }
4534 }
4535 if (limit == 0) {
4536 s = RSTRING_PTR(str);
4537 p = RSTRING_END(str);
4538 pp = rb_enc_prev_char(s, p, p, enc);
4539 if (extra_limit && pp &&
4540 MBCLEN_NEEDMORE_P(rb_enc_precise_mbclen(pp, p, enc))) {
4541 /* relax the limit while incomplete character.
4542 * extra_limit limits the relax length */
4543 limit = 1;
4544 extra_limit--;
4545 }
4546 else {
4547 nolimit = 1;
4548 break;
4549 }
4550 }
4551 }
4552
4553 if (rspara && c != EOF)
4554 swallow(fptr, '\n');
4555 if (!NIL_P(str))
4556 str = io_enc_str(str, fptr);
4557 }
4558
4559 if (!NIL_P(str) && !nolimit) {
4560 fptr->lineno++;
4561 }
4562
4563 return str;
4564}
4565
4566static VALUE
4567rb_io_getline_1(VALUE rs, long limit, int chomp, VALUE io)
4568{
4569 rb_io_t *fptr;
4570 int old_lineno, new_lineno;
4571 VALUE str;
4572
4573 GetOpenFile(io, fptr);
4574 old_lineno = fptr->lineno;
4575 str = rb_io_getline_0(rs, limit, chomp, fptr);
4576 if (!NIL_P(str) && (new_lineno = fptr->lineno) != old_lineno) {
4577 if (io == ARGF.current_file) {
4578 ARGF.lineno += new_lineno - old_lineno;
4579 ARGF.last_lineno = ARGF.lineno;
4580 }
4581 else {
4582 ARGF.last_lineno = new_lineno;
4583 }
4584 }
4585
4586 return str;
4587}
4588
4589static VALUE
4590rb_io_getline(int argc, VALUE *argv, VALUE io)
4591{
4592 struct getline_arg args;
4593
4594 prepare_getline_args(argc, argv, &args, io);
4595 return rb_io_getline_1(args.rs, args.limit, args.chomp, io);
4596}
4597
4598VALUE
4600{
4601 return rb_io_getline_1(rb_default_rs, -1, FALSE, io);
4602}
4603
4604VALUE
4605rb_io_gets_limit_internal(VALUE io, long limit)
4606{
4607 rb_io_t *fptr;
4608 GetOpenFile(io, fptr);
4609 return rb_io_getline_0(rb_default_rs, limit, FALSE, fptr);
4610}
4611
4612VALUE
4613rb_io_gets_internal(VALUE io)
4614{
4615 return rb_io_gets_limit_internal(io, -1);
4616}
4617
4618/*
4619 * call-seq:
4620 * gets(sep = $/, chomp: false) -> string or nil
4621 * gets(limit, chomp: false) -> string or nil
4622 * gets(sep, limit, chomp: false) -> string or nil
4623 *
4624 * Reads and returns a line from the stream;
4625 * assigns the return value to <tt>$_</tt>.
4626 * See {Line IO}[rdoc-ref:IO@Line+IO].
4627 *
4628 * With no arguments given, returns the next line
4629 * as determined by line separator <tt>$/</tt>, or +nil+ if none:
4630 *
4631 * f = File.open('t.txt')
4632 * f.gets # => "First line\n"
4633 * $_ # => "First line\n"
4634 * f.gets # => "\n"
4635 * f.gets # => "Fourth line\n"
4636 * f.gets # => "Fifth line\n"
4637 * f.gets # => nil
4638 * f.close
4639 *
4640 * With only string argument +sep+ given,
4641 * returns the next line as determined by line separator +sep+,
4642 * or +nil+ if none;
4643 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4644 *
4645 * f = File.new('t.txt')
4646 * f.gets('l') # => "First l"
4647 * f.gets('li') # => "ine\nSecond li"
4648 * f.gets('lin') # => "ne\n\nFourth lin"
4649 * f.gets # => "e\n"
4650 * f.close
4651 *
4652 * The two special values for +sep+ are honored:
4653 *
4654 * f = File.new('t.txt')
4655 * # Get all.
4656 * f.gets(nil) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
4657 * f.rewind
4658 * # Get paragraph (up to two line separators).
4659 * f.gets('') # => "First line\nSecond line\n\n"
4660 * f.close
4661 *
4662 * With only integer argument +limit+ given,
4663 * limits the number of bytes in the line;
4664 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4665 *
4666 * # No more than one line.
4667 * File.open('t.txt') {|f| f.gets(10) } # => "First line"
4668 * File.open('t.txt') {|f| f.gets(11) } # => "First line\n"
4669 * File.open('t.txt') {|f| f.gets(12) } # => "First line\n"
4670 *
4671 * With arguments +sep+ and +limit+ given,
4672 * combines the two behaviors
4673 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
4674 *
4675 * Optional keyword argument +chomp+ specifies whether line separators
4676 * are to be omitted:
4677 *
4678 * f = File.open('t.txt')
4679 * # Chomp the lines.
4680 * f.gets(chomp: true) # => "First line"
4681 * f.gets(chomp: true) # => "Second line"
4682 * f.gets(chomp: true) # => ""
4683 * f.gets(chomp: true) # => "Fourth line"
4684 * f.gets(chomp: true) # => "Fifth line"
4685 * f.gets(chomp: true) # => nil
4686 * f.close
4687 *
4688 */
4689
4690static VALUE
4691rb_io_gets_m(int argc, VALUE *argv, VALUE io)
4692{
4693 VALUE str;
4694
4695 str = rb_io_getline(argc, argv, io);
4696 rb_lastline_set(str);
4697
4698 return str;
4699}
4700
4701/*
4702 * call-seq:
4703 * lineno -> integer
4704 *
4705 * Returns the current line number for the stream;
4706 * see {Line Number}[rdoc-ref:IO@Line+Number].
4707 *
4708 */
4709
4710static VALUE
4711rb_io_lineno(VALUE io)
4712{
4713 rb_io_t *fptr;
4714
4715 GetOpenFile(io, fptr);
4717 return INT2NUM(fptr->lineno);
4718}
4719
4720/*
4721 * call-seq:
4722 * lineno = integer -> integer
4723 *
4724 * Sets and returns the line number for the stream;
4725 * see {Line Number}[rdoc-ref:IO@Line+Number].
4726 *
4727 */
4728
4729static VALUE
4730rb_io_set_lineno(VALUE io, VALUE lineno)
4731{
4732 rb_io_t *fptr;
4733
4734 GetOpenFile(io, fptr);
4736 fptr->lineno = NUM2INT(lineno);
4737 return lineno;
4738}
4739
4740/* :nodoc: */
4741static VALUE
4742io_readline(rb_execution_context_t *ec, VALUE io, VALUE sep, VALUE lim, VALUE chomp)
4743{
4744 long limit = -1;
4745 if (NIL_P(lim)) {
4746 VALUE tmp = Qnil;
4747 // If sep is specified, but it's not a string and not nil, then assume
4748 // it's the limit (it should be an integer)
4749 if (!NIL_P(sep) && NIL_P(tmp = rb_check_string_type(sep))) {
4750 // If the user has specified a non-nil / non-string value
4751 // for the separator, we assume it's the limit and set the
4752 // separator to default: rb_rs.
4753 lim = sep;
4754 limit = NUM2LONG(lim);
4755 sep = rb_rs;
4756 }
4757 else {
4758 sep = tmp;
4759 }
4760 }
4761 else {
4762 if (!NIL_P(sep)) StringValue(sep);
4763 limit = NUM2LONG(lim);
4764 }
4765
4766 check_getline_args(&sep, &limit, io);
4767
4768 VALUE line = rb_io_getline_1(sep, limit, RTEST(chomp), io);
4769 rb_lastline_set_up(line, 1);
4770
4771 if (NIL_P(line)) {
4772 rb_eof_error();
4773 }
4774 return line;
4775}
4776
4777static VALUE io_readlines(const struct getline_arg *arg, VALUE io);
4778
4779/*
4780 * call-seq:
4781 * readlines(sep = $/, chomp: false) -> array
4782 * readlines(limit, chomp: false) -> array
4783 * readlines(sep, limit, chomp: false) -> array
4784 *
4785 * Reads and returns all remaining line from the stream;
4786 * does not modify <tt>$_</tt>.
4787 * See {Line IO}[rdoc-ref:IO@Line+IO].
4788 *
4789 * With no arguments given, returns lines
4790 * as determined by line separator <tt>$/</tt>, or +nil+ if none:
4791 *
4792 * f = File.new('t.txt')
4793 * f.readlines
4794 * # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
4795 * f.readlines # => []
4796 * f.close
4797 *
4798 * With only string argument +sep+ given,
4799 * returns lines as determined by line separator +sep+,
4800 * or +nil+ if none;
4801 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4802 *
4803 * f = File.new('t.txt')
4804 * f.readlines('li')
4805 * # => ["First li", "ne\nSecond li", "ne\n\nFourth li", "ne\nFifth li", "ne\n"]
4806 * f.close
4807 *
4808 * The two special values for +sep+ are honored:
4809 *
4810 * f = File.new('t.txt')
4811 * # Get all into one string.
4812 * f.readlines(nil)
4813 * # => ["First line\nSecond line\n\nFourth line\nFifth line\n"]
4814 * # Get paragraphs (up to two line separators).
4815 * f.rewind
4816 * f.readlines('')
4817 * # => ["First line\nSecond line\n\n", "Fourth line\nFifth line\n"]
4818 * f.close
4819 *
4820 * With only integer argument +limit+ given,
4821 * limits the number of bytes in each line;
4822 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4823 *
4824 * f = File.new('t.txt')
4825 * f.readlines(8)
4826 * # => ["First li", "ne\n", "Second l", "ine\n", "\n", "Fourth l", "ine\n", "Fifth li", "ne\n"]
4827 * f.close
4828 *
4829 * With arguments +sep+ and +limit+ given,
4830 * combines the two behaviors
4831 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
4832 *
4833 * Optional keyword argument +chomp+ specifies whether line separators
4834 * are to be omitted:
4835 *
4836 * f = File.new('t.txt')
4837 * f.readlines(chomp: true)
4838 * # => ["First line", "Second line", "", "Fourth line", "Fifth line"]
4839 * f.close
4840 *
4841 */
4842
4843static VALUE
4844rb_io_readlines(int argc, VALUE *argv, VALUE io)
4845{
4846 struct getline_arg args;
4847
4848 prepare_getline_args(argc, argv, &args, io);
4849 return io_readlines(&args, io);
4850}
4851
4852static VALUE
4853io_readlines(const struct getline_arg *arg, VALUE io)
4854{
4855 VALUE line, ary;
4856
4857 if (arg->limit == 0)
4858 rb_raise(rb_eArgError, "invalid limit: 0 for readlines");
4859 ary = rb_ary_new();
4860 while (!NIL_P(line = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, io))) {
4861 rb_ary_push(ary, line);
4862 }
4863 return ary;
4864}
4865
4866/*
4867 * call-seq:
4868 * each_line(sep = $/, chomp: false) {|line| ... } -> self
4869 * each_line(limit, chomp: false) {|line| ... } -> self
4870 * each_line(sep, limit, chomp: false) {|line| ... } -> self
4871 * each_line -> enumerator
4872 *
4873 * Calls the block with each remaining line read from the stream;
4874 * returns +self+.
4875 * Does nothing if already at end-of-stream;
4876 * See {Line IO}[rdoc-ref:IO@Line+IO].
4877 *
4878 * With no arguments given, reads lines
4879 * as determined by line separator <tt>$/</tt>:
4880 *
4881 * f = File.new('t.txt')
4882 * f.each_line {|line| p line }
4883 * f.each_line {|line| fail 'Cannot happen' }
4884 * f.close
4885 *
4886 * Output:
4887 *
4888 * "First line\n"
4889 * "Second line\n"
4890 * "\n"
4891 * "Fourth line\n"
4892 * "Fifth line\n"
4893 *
4894 * With only string argument +sep+ given,
4895 * reads lines as determined by line separator +sep+;
4896 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4897 *
4898 * f = File.new('t.txt')
4899 * f.each_line('li') {|line| p line }
4900 * f.close
4901 *
4902 * Output:
4903 *
4904 * "First li"
4905 * "ne\nSecond li"
4906 * "ne\n\nFourth li"
4907 * "ne\nFifth li"
4908 * "ne\n"
4909 *
4910 * The two special values for +sep+ are honored:
4911 *
4912 * f = File.new('t.txt')
4913 * # Get all into one string.
4914 * f.each_line(nil) {|line| p line }
4915 * f.close
4916 *
4917 * Output:
4918 *
4919 * "First line\nSecond line\n\nFourth line\nFifth line\n"
4920 *
4921 * f.rewind
4922 * # Get paragraphs (up to two line separators).
4923 * f.each_line('') {|line| p line }
4924 *
4925 * Output:
4926 *
4927 * "First line\nSecond line\n\n"
4928 * "Fourth line\nFifth line\n"
4929 *
4930 * With only integer argument +limit+ given,
4931 * limits the number of bytes in each line;
4932 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4933 *
4934 * f = File.new('t.txt')
4935 * f.each_line(8) {|line| p line }
4936 * f.close
4937 *
4938 * Output:
4939 *
4940 * "First li"
4941 * "ne\n"
4942 * "Second l"
4943 * "ine\n"
4944 * "\n"
4945 * "Fourth l"
4946 * "ine\n"
4947 * "Fifth li"
4948 * "ne\n"
4949 *
4950 * With arguments +sep+ and +limit+ given,
4951 * combines the two behaviors
4952 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
4953 *
4954 * Optional keyword argument +chomp+ specifies whether line separators
4955 * are to be omitted:
4956 *
4957 * f = File.new('t.txt')
4958 * f.each_line(chomp: true) {|line| p line }
4959 * f.close
4960 *
4961 * Output:
4962 *
4963 * "First line"
4964 * "Second line"
4965 * ""
4966 * "Fourth line"
4967 * "Fifth line"
4968 *
4969 * Returns an Enumerator if no block is given.
4970 */
4971
4972static VALUE
4973rb_io_each_line(int argc, VALUE *argv, VALUE io)
4974{
4975 VALUE str;
4976 struct getline_arg args;
4977
4978 RETURN_ENUMERATOR(io, argc, argv);
4979 prepare_getline_args(argc, argv, &args, io);
4980 if (args.limit == 0)
4981 rb_raise(rb_eArgError, "invalid limit: 0 for each_line");
4982 while (!NIL_P(str = rb_io_getline_1(args.rs, args.limit, args.chomp, io))) {
4983 rb_yield(str);
4984 }
4985 return io;
4986}
4987
4988/*
4989 * call-seq:
4990 * each_byte {|byte| ... } -> self
4991 * each_byte -> enumerator
4992 *
4993 * Calls the given block with each byte (0..255) in the stream; returns +self+.
4994 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
4995 *
4996 * File.read('t.ja') # => "こんにちは"
4997 * f = File.new('t.ja')
4998 * a = []
4999 * f.each_byte {|b| a << b }
5000 * a # => [227, 129, 147, 227, 130, 147, 227, 129, 171, 227, 129, 161, 227, 129, 175]
5001 * f.close
5002 *
5003 * Returns an Enumerator if no block is given.
5004 *
5005 * Related: IO#each_char, IO#each_codepoint.
5006 *
5007 */
5008
5009static VALUE
5010rb_io_each_byte(VALUE io)
5011{
5012 rb_io_t *fptr;
5013
5014 RETURN_ENUMERATOR(io, 0, 0);
5015 GetOpenFile(io, fptr);
5016
5017 do {
5018 while (fptr->rbuf.len > 0) {
5019 char *p = fptr->rbuf.ptr + fptr->rbuf.off++;
5020 fptr->rbuf.len--;
5021 rb_yield(INT2FIX(*p & 0xff));
5023 errno = 0;
5024 }
5025 READ_CHECK(fptr);
5026 } while (io_fillbuf(fptr) >= 0);
5027 return io;
5028}
5029
5030static VALUE
5031io_getc(rb_io_t *fptr, rb_encoding *enc)
5032{
5033 int r, n, cr = 0;
5034 VALUE str;
5035
5036 if (NEED_READCONV(fptr)) {
5037 rb_encoding *read_enc = io_read_encoding(fptr);
5038
5039 str = Qnil;
5040 SET_BINARY_MODE(fptr);
5041 make_readconv(fptr, 0);
5042
5043 while (1) {
5044 if (fptr->cbuf.len) {
5045 r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
5046 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
5047 read_enc);
5048 if (!MBCLEN_NEEDMORE_P(r))
5049 break;
5050 if (fptr->cbuf.len == fptr->cbuf.capa) {
5051 rb_raise(rb_eIOError, "too long character");
5052 }
5053 }
5054
5055 if (more_char(fptr) == MORE_CHAR_FINISHED) {
5056 if (fptr->cbuf.len == 0) {
5057 clear_readconv(fptr);
5058 return Qnil;
5059 }
5060 /* return an unit of an incomplete character just before EOF */
5061 str = rb_enc_str_new(fptr->cbuf.ptr+fptr->cbuf.off, 1, read_enc);
5062 fptr->cbuf.off += 1;
5063 fptr->cbuf.len -= 1;
5064 if (fptr->cbuf.len == 0) clear_readconv(fptr);
5066 return str;
5067 }
5068 }
5069 if (MBCLEN_INVALID_P(r)) {
5070 r = rb_enc_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
5071 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
5072 read_enc);
5073 io_shift_cbuf(fptr, r, &str);
5075 }
5076 else {
5077 io_shift_cbuf(fptr, MBCLEN_CHARFOUND_LEN(r), &str);
5079 if (MBCLEN_CHARFOUND_LEN(r) == 1 && rb_enc_asciicompat(read_enc) &&
5080 ISASCII(RSTRING_PTR(str)[0])) {
5081 cr = ENC_CODERANGE_7BIT;
5082 }
5083 }
5084 str = io_enc_str(str, fptr);
5085 ENC_CODERANGE_SET(str, cr);
5086 return str;
5087 }
5088
5089 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
5090 if (io_fillbuf(fptr) < 0) {
5091 return Qnil;
5092 }
5093 if (rb_enc_asciicompat(enc) && ISASCII(fptr->rbuf.ptr[fptr->rbuf.off])) {
5094 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, 1);
5095 fptr->rbuf.off += 1;
5096 fptr->rbuf.len -= 1;
5097 cr = ENC_CODERANGE_7BIT;
5098 }
5099 else {
5100 r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off, fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
5101 if (MBCLEN_CHARFOUND_P(r) &&
5102 (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
5103 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, n);
5104 fptr->rbuf.off += n;
5105 fptr->rbuf.len -= n;
5107 }
5108 else if (MBCLEN_NEEDMORE_P(r)) {
5109 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, fptr->rbuf.len);
5110 fptr->rbuf.len = 0;
5111 getc_needmore:
5112 if (io_fillbuf(fptr) != -1) {
5113 rb_str_cat(str, fptr->rbuf.ptr+fptr->rbuf.off, 1);
5114 fptr->rbuf.off++;
5115 fptr->rbuf.len--;
5116 r = rb_enc_precise_mbclen(RSTRING_PTR(str), RSTRING_PTR(str)+RSTRING_LEN(str), enc);
5117 if (MBCLEN_NEEDMORE_P(r)) {
5118 goto getc_needmore;
5119 }
5120 else if (MBCLEN_CHARFOUND_P(r)) {
5122 }
5123 }
5124 }
5125 else {
5126 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, 1);
5127 fptr->rbuf.off++;
5128 fptr->rbuf.len--;
5129 }
5130 }
5131 if (!cr) cr = ENC_CODERANGE_BROKEN;
5132 str = io_enc_str(str, fptr);
5133 ENC_CODERANGE_SET(str, cr);
5134 return str;
5135}
5136
5137/*
5138 * call-seq:
5139 * each_char {|c| ... } -> self
5140 * each_char -> enumerator
5141 *
5142 * Calls the given block with each character in the stream; returns +self+.
5143 * See {Character IO}[rdoc-ref:IO@Character+IO].
5144 *
5145 * File.read('t.ja') # => "こんにちは"
5146 * f = File.new('t.ja')
5147 * a = []
5148 * f.each_char {|c| a << c.ord }
5149 * a # => [12371, 12435, 12395, 12385, 12399]
5150 * f.close
5151 *
5152 * Returns an Enumerator if no block is given.
5153 *
5154 * Related: IO#each_byte, IO#each_codepoint.
5155 *
5156 */
5157
5158static VALUE
5159rb_io_each_char(VALUE io)
5160{
5161 rb_io_t *fptr;
5162 rb_encoding *enc;
5163 VALUE c;
5164
5165 RETURN_ENUMERATOR(io, 0, 0);
5166 GetOpenFile(io, fptr);
5168
5169 enc = io_input_encoding(fptr);
5170 READ_CHECK(fptr);
5171 while (!NIL_P(c = io_getc(fptr, enc))) {
5172 rb_yield(c);
5173 }
5174 return io;
5175}
5176
5177/*
5178 * call-seq:
5179 * each_codepoint {|c| ... } -> self
5180 * each_codepoint -> enumerator
5181 *
5182 * Calls the given block with each codepoint in the stream; returns +self+:
5183 *
5184 * File.read('t.ja') # => "こんにちは"
5185 * f = File.new('t.ja')
5186 * a = []
5187 * f.each_codepoint {|c| a << c }
5188 * a # => [12371, 12435, 12395, 12385, 12399]
5189 * f.close
5190 *
5191 * Returns an Enumerator if no block is given.
5192 *
5193 * Related: IO#each_byte, IO#each_char.
5194 *
5195 */
5196
5197static VALUE
5198rb_io_each_codepoint(VALUE io)
5199{
5200 rb_io_t *fptr;
5201 rb_encoding *enc;
5202 unsigned int c;
5203 int r, n;
5204
5205 RETURN_ENUMERATOR(io, 0, 0);
5206 GetOpenFile(io, fptr);
5208
5209 READ_CHECK(fptr);
5210 enc = io_read_encoding(fptr);
5211 if (NEED_READCONV(fptr)) {
5212 SET_BINARY_MODE(fptr);
5213 r = 1; /* no invalid char yet */
5214 for (;;) {
5215 make_readconv(fptr, 0);
5216 for (;;) {
5217 if (fptr->cbuf.len) {
5218 r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
5219 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
5220 enc);
5221 if (!MBCLEN_NEEDMORE_P(r))
5222 break;
5223 if (fptr->cbuf.len == fptr->cbuf.capa) {
5224 rb_raise(rb_eIOError, "too long character");
5225 }
5226 }
5227 if (more_char(fptr) == MORE_CHAR_FINISHED) {
5228 clear_readconv(fptr);
5229 if (!MBCLEN_CHARFOUND_P(r)) {
5230 goto invalid;
5231 }
5232 return io;
5233 }
5234 }
5235 if (MBCLEN_INVALID_P(r)) {
5236 goto invalid;
5237 }
5238 n = MBCLEN_CHARFOUND_LEN(r);
5239 c = rb_enc_codepoint(fptr->cbuf.ptr+fptr->cbuf.off,
5240 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
5241 enc);
5242 fptr->cbuf.off += n;
5243 fptr->cbuf.len -= n;
5244 rb_yield(UINT2NUM(c));
5246 }
5247 }
5248 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
5249 while (io_fillbuf(fptr) >= 0) {
5250 r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off,
5251 fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
5252 if (MBCLEN_CHARFOUND_P(r) &&
5253 (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
5254 c = rb_enc_codepoint(fptr->rbuf.ptr+fptr->rbuf.off,
5255 fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
5256 fptr->rbuf.off += n;
5257 fptr->rbuf.len -= n;
5258 rb_yield(UINT2NUM(c));
5259 }
5260 else if (MBCLEN_INVALID_P(r)) {
5261 goto invalid;
5262 }
5263 else if (MBCLEN_NEEDMORE_P(r)) {
5264 char cbuf[8], *p = cbuf;
5265 int more = MBCLEN_NEEDMORE_LEN(r);
5266 if (more > numberof(cbuf)) goto invalid;
5267 more += n = fptr->rbuf.len;
5268 if (more > numberof(cbuf)) goto invalid;
5269 while ((n = (int)read_buffered_data(p, more, fptr)) > 0 &&
5270 (p += n, (more -= n) > 0)) {
5271 if (io_fillbuf(fptr) < 0) goto invalid;
5272 if ((n = fptr->rbuf.len) > more) n = more;
5273 }
5274 r = rb_enc_precise_mbclen(cbuf, p, enc);
5275 if (!MBCLEN_CHARFOUND_P(r)) goto invalid;
5276 c = rb_enc_codepoint(cbuf, p, enc);
5277 rb_yield(UINT2NUM(c));
5278 }
5279 else {
5280 continue;
5281 }
5283 }
5284 return io;
5285
5286 invalid:
5287 rb_raise(rb_eArgError, "invalid byte sequence in %s", rb_enc_name(enc));
5289}
5290
5291/*
5292 * call-seq:
5293 * getc -> character or nil
5294 *
5295 * Reads and returns the next 1-character string from the stream;
5296 * returns +nil+ if already at end-of-stream.
5297 * See {Character IO}[rdoc-ref:IO@Character+IO].
5298 *
5299 * f = File.open('t.txt')
5300 * f.getc # => "F"
5301 * f.close
5302 * File.read('t.ja') # => "こんにちは"
5303 * f = File.open('t.ja')
5304 * f.getc.ord # => 12371
5305 * f.close
5306 *
5307 * Related: IO#readchar (may raise EOFError).
5308 *
5309 */
5310
5311static VALUE
5312rb_io_getc(VALUE io)
5313{
5314 rb_io_t *fptr;
5315 rb_encoding *enc;
5316
5317 GetOpenFile(io, fptr);
5319
5320 enc = io_input_encoding(fptr);
5321 READ_CHECK(fptr);
5322 return io_getc(fptr, enc);
5323}
5324
5325/*
5326 * call-seq:
5327 * readchar -> string
5328 *
5329 * Reads and returns the next 1-character string from the stream;
5330 * raises EOFError if already at end-of-stream.
5331 * See {Character IO}[rdoc-ref:IO@Character+IO].
5332 *
5333 * f = File.open('t.txt')
5334 * f.readchar # => "F"
5335 * f.close
5336 * File.read('t.ja') # => "こんにちは"
5337 * f = File.open('t.ja')
5338 * f.readchar.ord # => 12371
5339 * f.close
5340 *
5341 * Related: IO#getc (will not raise EOFError).
5342 *
5343 */
5344
5345static VALUE
5346rb_io_readchar(VALUE io)
5347{
5348 VALUE c = rb_io_getc(io);
5349
5350 if (NIL_P(c)) {
5351 rb_eof_error();
5352 }
5353 return c;
5354}
5355
5356/*
5357 * call-seq:
5358 * getbyte -> integer or nil
5359 *
5360 * Reads and returns the next byte (in range 0..255) from the stream;
5361 * returns +nil+ if already at end-of-stream.
5362 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5363 *
5364 * f = File.open('t.txt')
5365 * f.getbyte # => 70
5366 * f.close
5367 * File.read('t.ja') # => "こんにちは"
5368 * f = File.open('t.ja')
5369 * f.getbyte # => 227
5370 * f.close
5371 *
5372 * Related: IO#readbyte (may raise EOFError).
5373 */
5374
5375VALUE
5377{
5378 rb_io_t *fptr;
5379 int c;
5380
5381 GetOpenFile(io, fptr);
5383 READ_CHECK(fptr);
5384 VALUE r_stdout = rb_ractor_stdout();
5385 if (fptr->fd == 0 && (fptr->mode & FMODE_TTY) && RB_TYPE_P(r_stdout, T_FILE)) {
5386 rb_io_t *ofp;
5387 GetOpenFile(r_stdout, ofp);
5388 if (ofp->mode & FMODE_TTY) {
5389 rb_io_flush(r_stdout);
5390 }
5391 }
5392 if (io_fillbuf(fptr) < 0) {
5393 return Qnil;
5394 }
5395 fptr->rbuf.off++;
5396 fptr->rbuf.len--;
5397 c = (unsigned char)fptr->rbuf.ptr[fptr->rbuf.off-1];
5398 return INT2FIX(c & 0xff);
5399}
5400
5401/*
5402 * call-seq:
5403 * readbyte -> integer
5404 *
5405 * Reads and returns the next byte (in range 0..255) from the stream;
5406 * raises EOFError if already at end-of-stream.
5407 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5408 *
5409 * f = File.open('t.txt')
5410 * f.readbyte # => 70
5411 * f.close
5412 * File.read('t.ja') # => "こんにちは"
5413 * f = File.open('t.ja')
5414 * f.readbyte # => 227
5415 * f.close
5416 *
5417 * Related: IO#getbyte (will not raise EOFError).
5418 *
5419 */
5420
5421static VALUE
5422rb_io_readbyte(VALUE io)
5423{
5424 VALUE c = rb_io_getbyte(io);
5425
5426 if (NIL_P(c)) {
5427 rb_eof_error();
5428 }
5429 return c;
5430}
5431
5432/*
5433 * call-seq:
5434 * ungetbyte(integer) -> nil
5435 * ungetbyte(string) -> nil
5436 *
5437 * Pushes back ("unshifts") the given data onto the stream's buffer,
5438 * placing the data so that it is next to be read; returns +nil+.
5439 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5440 *
5441 * Note that:
5442 *
5443 * - Calling the method has no effect with unbuffered reads (such as IO#sysread).
5444 * - Calling #rewind on the stream discards the pushed-back data.
5445 *
5446 * When argument +integer+ is given, uses only its low-order byte:
5447 *
5448 * File.write('t.tmp', '012')
5449 * f = File.open('t.tmp')
5450 * f.ungetbyte(0x41) # => nil
5451 * f.read # => "A012"
5452 * f.rewind
5453 * f.ungetbyte(0x4243) # => nil
5454 * f.read # => "C012"
5455 * f.close
5456 *
5457 * When argument +string+ is given, uses all bytes:
5458 *
5459 * File.write('t.tmp', '012')
5460 * f = File.open('t.tmp')
5461 * f.ungetbyte('A') # => nil
5462 * f.read # => "A012"
5463 * f.rewind
5464 * f.ungetbyte('BCDE') # => nil
5465 * f.read # => "BCDE012"
5466 * f.close
5467 *
5468 */
5469
5470VALUE
5472{
5473 rb_io_t *fptr;
5474
5475 GetOpenFile(io, fptr);
5477 switch (TYPE(b)) {
5478 case T_NIL:
5479 return Qnil;
5480 case T_FIXNUM:
5481 case T_BIGNUM: ;
5482 VALUE v = rb_int_modulo(b, INT2FIX(256));
5483 unsigned char c = NUM2INT(v) & 0xFF;
5484 b = rb_str_new((const char *)&c, 1);
5485 break;
5486 default:
5487 StringValue(b);
5488 }
5489 io_ungetbyte(b, fptr);
5490 return Qnil;
5491}
5492
5493/*
5494 * call-seq:
5495 * ungetc(integer) -> nil
5496 * ungetc(string) -> nil
5497 *
5498 * Pushes back ("unshifts") the given data onto the stream's buffer,
5499 * placing the data so that it is next to be read; returns +nil+.
5500 * See {Character IO}[rdoc-ref:IO@Character+IO].
5501 *
5502 * Note that:
5503 *
5504 * - Calling the method has no effect with unbuffered reads (such as IO#sysread).
5505 * - Calling #rewind on the stream discards the pushed-back data.
5506 *
5507 * When argument +integer+ is given, interprets the integer as a character:
5508 *
5509 * File.write('t.tmp', '012')
5510 * f = File.open('t.tmp')
5511 * f.ungetc(0x41) # => nil
5512 * f.read # => "A012"
5513 * f.rewind
5514 * f.ungetc(0x0442) # => nil
5515 * f.getc.ord # => 1090
5516 * f.close
5517 *
5518 * When argument +string+ is given, uses all characters:
5519 *
5520 * File.write('t.tmp', '012')
5521 * f = File.open('t.tmp')
5522 * f.ungetc('A') # => nil
5523 * f.read # => "A012"
5524 * f.rewind
5525 * f.ungetc("\u0442\u0435\u0441\u0442") # => nil
5526 * f.getc.ord # => 1090
5527 * f.getc.ord # => 1077
5528 * f.getc.ord # => 1089
5529 * f.getc.ord # => 1090
5530 * f.close
5531 *
5532 */
5533
5534VALUE
5536{
5537 rb_io_t *fptr;
5538 long len;
5539
5540 GetOpenFile(io, fptr);
5542 if (FIXNUM_P(c)) {
5543 c = rb_enc_uint_chr(FIX2UINT(c), io_read_encoding(fptr));
5544 }
5545 else if (RB_BIGNUM_TYPE_P(c)) {
5546 c = rb_enc_uint_chr(NUM2UINT(c), io_read_encoding(fptr));
5547 }
5548 else {
5549 StringValue(c);
5550 }
5551 if (NEED_READCONV(fptr)) {
5552 SET_BINARY_MODE(fptr);
5553 len = RSTRING_LEN(c);
5554#if SIZEOF_LONG > SIZEOF_INT
5555 if (len > INT_MAX)
5556 rb_raise(rb_eIOError, "ungetc failed");
5557#endif
5558 make_readconv(fptr, (int)len);
5559 if (fptr->cbuf.capa - fptr->cbuf.len < len)
5560 rb_raise(rb_eIOError, "ungetc failed");
5561 if (fptr->cbuf.off < len) {
5562 MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.capa-fptr->cbuf.len,
5563 fptr->cbuf.ptr+fptr->cbuf.off,
5564 char, fptr->cbuf.len);
5565 fptr->cbuf.off = fptr->cbuf.capa-fptr->cbuf.len;
5566 }
5567 fptr->cbuf.off -= (int)len;
5568 fptr->cbuf.len += (int)len;
5569 MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.off, RSTRING_PTR(c), char, len);
5570 }
5571 else {
5572 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
5573 io_ungetbyte(c, fptr);
5574 }
5575 return Qnil;
5576}
5577
5578/*
5579 * call-seq:
5580 * isatty -> true or false
5581 *
5582 * Returns +true+ if the stream is associated with a terminal device (tty),
5583 * +false+ otherwise:
5584 *
5585 * f = File.new('t.txt').isatty #=> false
5586 * f.close
5587 * f = File.new('/dev/tty').isatty #=> true
5588 * f.close
5589 *
5590 */
5591
5592static VALUE
5593rb_io_isatty(VALUE io)
5594{
5595 rb_io_t *fptr;
5596
5597 GetOpenFile(io, fptr);
5598 return RBOOL(isatty(fptr->fd) != 0);
5599}
5600
5601#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5602/*
5603 * call-seq:
5604 * close_on_exec? -> true or false
5605 *
5606 * Returns +true+ if the stream will be closed on exec, +false+ otherwise:
5607 *
5608 * f = File.open('t.txt')
5609 * f.close_on_exec? # => true
5610 * f.close_on_exec = false
5611 * f.close_on_exec? # => false
5612 * f.close
5613 *
5614 */
5615
5616static VALUE
5617rb_io_close_on_exec_p(VALUE io)
5618{
5619 rb_io_t *fptr;
5620 VALUE write_io;
5621 int fd, ret;
5622
5623 write_io = GetWriteIO(io);
5624 if (io != write_io) {
5625 GetOpenFile(write_io, fptr);
5626 if (fptr && 0 <= (fd = fptr->fd)) {
5627 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5628 if (!(ret & FD_CLOEXEC)) return Qfalse;
5629 }
5630 }
5631
5632 GetOpenFile(io, fptr);
5633 if (fptr && 0 <= (fd = fptr->fd)) {
5634 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5635 if (!(ret & FD_CLOEXEC)) return Qfalse;
5636 }
5637 return Qtrue;
5638}
5639#else
5640#define rb_io_close_on_exec_p rb_f_notimplement
5641#endif
5642
5643#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5644/*
5645 * call-seq:
5646 * self.close_on_exec = bool -> true or false
5647 *
5648 * Sets a close-on-exec flag.
5649 *
5650 * f = File.open(File::NULL)
5651 * f.close_on_exec = true
5652 * system("cat", "/proc/self/fd/#{f.fileno}") # cat: /proc/self/fd/3: No such file or directory
5653 * f.closed? #=> false
5654 *
5655 * Ruby sets close-on-exec flags of all file descriptors by default
5656 * since Ruby 2.0.0.
5657 * So you don't need to set by yourself.
5658 * Also, unsetting a close-on-exec flag can cause file descriptor leak
5659 * if another thread use fork() and exec() (via system() method for example).
5660 * If you really needs file descriptor inheritance to child process,
5661 * use spawn()'s argument such as fd=>fd.
5662 */
5663
5664static VALUE
5665rb_io_set_close_on_exec(VALUE io, VALUE arg)
5666{
5667 int flag = RTEST(arg) ? FD_CLOEXEC : 0;
5668 rb_io_t *fptr;
5669 VALUE write_io;
5670 int fd, ret;
5671
5672 write_io = GetWriteIO(io);
5673 if (io != write_io) {
5674 GetOpenFile(write_io, fptr);
5675 if (fptr && 0 <= (fd = fptr->fd)) {
5676 if ((ret = fcntl(fptr->fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5677 if ((ret & FD_CLOEXEC) != flag) {
5678 ret = (ret & ~FD_CLOEXEC) | flag;
5679 ret = fcntl(fd, F_SETFD, ret);
5680 if (ret != 0) rb_sys_fail_path(fptr->pathv);
5681 }
5682 }
5683
5684 }
5685
5686 GetOpenFile(io, fptr);
5687 if (fptr && 0 <= (fd = fptr->fd)) {
5688 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5689 if ((ret & FD_CLOEXEC) != flag) {
5690 ret = (ret & ~FD_CLOEXEC) | flag;
5691 ret = fcntl(fd, F_SETFD, ret);
5692 if (ret != 0) rb_sys_fail_path(fptr->pathv);
5693 }
5694 }
5695 return Qnil;
5696}
5697#else
5698#define rb_io_set_close_on_exec rb_f_notimplement
5699#endif
5700
5701#define RUBY_IO_EXTERNAL_P(f) ((f)->mode & FMODE_EXTERNAL)
5702#define PREP_STDIO_NAME(f) (RSTRING_PTR((f)->pathv))
5703
5704static VALUE
5705finish_writeconv(rb_io_t *fptr, int noalloc)
5706{
5707 unsigned char *ds, *dp, *de;
5709
5710 if (!fptr->wbuf.ptr) {
5711 unsigned char buf[1024];
5712
5714 while (res == econv_destination_buffer_full) {
5715 ds = dp = buf;
5716 de = buf + sizeof(buf);
5717 res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
5718 while (dp-ds) {
5719 size_t remaining = dp-ds;
5720 long result = rb_io_write_memory(fptr, ds, remaining);
5721
5722 if (result > 0) {
5723 ds += result;
5724 if ((size_t)result == remaining) break;
5725 }
5726 else if (rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
5727 if (fptr->fd < 0)
5728 return noalloc ? Qtrue : rb_exc_new3(rb_eIOError, rb_str_new_cstr(closed_stream));
5729 }
5730 else {
5731 return noalloc ? Qtrue : INT2NUM(errno);
5732 }
5733 }
5734 if (res == econv_invalid_byte_sequence ||
5735 res == econv_incomplete_input ||
5737 return noalloc ? Qtrue : rb_econv_make_exception(fptr->writeconv);
5738 }
5739 }
5740
5741 return Qnil;
5742 }
5743
5745 while (res == econv_destination_buffer_full) {
5746 if (fptr->wbuf.len == fptr->wbuf.capa) {
5747 if (io_fflush(fptr) < 0) {
5748 return noalloc ? Qtrue : INT2NUM(errno);
5749 }
5750 }
5751
5752 ds = dp = (unsigned char *)fptr->wbuf.ptr + fptr->wbuf.off + fptr->wbuf.len;
5753 de = (unsigned char *)fptr->wbuf.ptr + fptr->wbuf.capa;
5754 res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
5755 fptr->wbuf.len += (int)(dp - ds);
5756 if (res == econv_invalid_byte_sequence ||
5757 res == econv_incomplete_input ||
5759 return noalloc ? Qtrue : rb_econv_make_exception(fptr->writeconv);
5760 }
5761 }
5762 return Qnil;
5763}
5764
5766 rb_io_t *fptr;
5767 int noalloc;
5768};
5769
5770static VALUE
5771finish_writeconv_sync(VALUE arg)
5772{
5773 struct finish_writeconv_arg *p = (struct finish_writeconv_arg *)arg;
5774 return finish_writeconv(p->fptr, p->noalloc);
5775}
5776
5777static void*
5778nogvl_close(void *ptr)
5779{
5780 int *fd = ptr;
5781
5782 return (void*)(intptr_t)close(*fd);
5783}
5784
5785static int
5786maygvl_close(int fd, int keepgvl)
5787{
5788 if (keepgvl)
5789 return close(fd);
5790
5791 /*
5792 * close() may block for certain file types (NFS, SO_LINGER sockets,
5793 * inotify), so let other threads run.
5794 */
5795 return IO_WITHOUT_GVL_INT(nogvl_close, &fd);
5796}
5797
5798static void*
5799nogvl_fclose(void *ptr)
5800{
5801 FILE *file = ptr;
5802
5803 return (void*)(intptr_t)fclose(file);
5804}
5805
5806static int
5807maygvl_fclose(FILE *file, int keepgvl)
5808{
5809 if (keepgvl)
5810 return fclose(file);
5811
5812 return IO_WITHOUT_GVL_INT(nogvl_fclose, file);
5813}
5814
5815static void free_io_buffer(rb_io_buffer_t *buf);
5816
5817static void
5818fptr_finalize_flush(rb_io_t *fptr, int noraise, int keepgvl)
5819{
5820 VALUE error = Qnil;
5821 int fd = fptr->fd;
5822 FILE *stdio_file = fptr->stdio_file;
5823 int mode = fptr->mode;
5824
5825 if (fptr->writeconv) {
5826 if (!NIL_P(fptr->write_lock) && !noraise) {
5827 struct finish_writeconv_arg arg;
5828 arg.fptr = fptr;
5829 arg.noalloc = noraise;
5830 error = rb_mutex_synchronize(fptr->write_lock, finish_writeconv_sync, (VALUE)&arg);
5831 }
5832 else {
5833 error = finish_writeconv(fptr, noraise);
5834 }
5835 }
5836 /* Do not flush the write buffer on close when the stream is in sync
5837 * mode. In sync mode Ruby's write buffer is not authoritative (writes go
5838 * straight to the OS), so any bytes left in the buffer are the result of
5839 * writes made while sync was disabled. Setting sync = true is therefore a
5840 * way to abandon that pending output rather than replaying it on close,
5841 * which matters after an interrupted write where the amount actually
5842 * written is indeterminate. Call flush before enabling sync if the
5843 * buffered data should still be sent. */
5844 if (fptr->wbuf.len && !(fptr->mode & FMODE_SYNC)) {
5845 if (noraise) {
5846 io_flush_buffer_sync(fptr);
5847 }
5848 else {
5849 if (io_fflush(fptr) < 0 && NIL_P(error)) {
5850 error = INT2NUM(errno);
5851 }
5852 }
5853 }
5854
5855 int done = 0;
5856
5857 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2) {
5858 // Need to keep FILE objects of stdin, stdout and stderr, so we are done:
5859 done = 1;
5860 }
5861
5862 fptr->fd = -1;
5863 fptr->stdio_file = 0;
5865
5866 // Wait for blocking operations to ensure they do not hit EBADF:
5867 rb_thread_io_close_wait(fptr);
5868
5869 if (!done && stdio_file) {
5870 // stdio_file is deallocated anyway even if fclose failed.
5871 if ((maygvl_fclose(stdio_file, noraise) < 0) && NIL_P(error)) {
5872 if (!noraise) {
5873 error = INT2NUM(errno);
5874 }
5875 }
5876
5877 done = 1;
5878 }
5879
5880 VALUE scheduler = rb_fiber_scheduler_current();
5881 if (!done && fd >= 0 && scheduler != Qnil) {
5882 VALUE result = rb_fiber_scheduler_io_close(scheduler, RB_INT2NUM(fd));
5883
5884 if (!UNDEF_P(result)) {
5885 done = RTEST(result);
5886 }
5887 }
5888
5889 if (!done && fd >= 0) {
5890 // fptr->fd may be closed even if close fails. POSIX doesn't specify it.
5891 // We assumes it is closed.
5892
5893 keepgvl |= !(mode & FMODE_WRITABLE);
5894 keepgvl |= noraise;
5895 if ((maygvl_close(fd, keepgvl) < 0) && NIL_P(error)) {
5896 if (!noraise) {
5897 error = INT2NUM(errno);
5898 }
5899 }
5900
5901 done = 1;
5902 }
5903
5904 if (!NIL_P(error) && !noraise) {
5905 if (RB_INTEGER_TYPE_P(error))
5906 rb_syserr_fail_path(NUM2INT(error), fptr->pathv);
5907 else
5908 rb_exc_raise(error);
5909 }
5910}
5911
5912static void
5913fptr_finalize(rb_io_t *fptr, int noraise)
5914{
5915 fptr_finalize_flush(fptr, noraise, FALSE);
5916 free_io_buffer(&fptr->rbuf);
5917 free_io_buffer(&fptr->wbuf);
5918 clear_codeconv(fptr);
5919}
5920
5921static void
5922rb_io_fptr_cleanup(rb_io_t *fptr, int noraise)
5923{
5924 if (fptr->finalize) {
5925 (*fptr->finalize)(fptr, noraise);
5926 }
5927 else {
5928 fptr_finalize(fptr, noraise);
5929 }
5930}
5931
5932static void
5933free_io_buffer(rb_io_buffer_t *buf)
5934{
5935 if (buf->ptr) {
5936 ruby_xfree_sized(buf->ptr, (size_t)buf->capa);
5937 buf->ptr = NULL;
5938 }
5939 buf->off = buf->len = buf->capa = 0;
5940}
5941
5942static void
5943clear_readconv(rb_io_t *fptr)
5944{
5945 if (fptr->readconv) {
5946 rb_econv_close(fptr->readconv);
5947 fptr->readconv = NULL;
5948 }
5949 free_io_buffer(&fptr->cbuf);
5950}
5951
5952static void
5953clear_writeconv(rb_io_t *fptr)
5954{
5955 if (fptr->writeconv) {
5957 fptr->writeconv = NULL;
5958 }
5959 fptr->writeconv_initialized = 0;
5960}
5961
5962static void
5963clear_codeconv(rb_io_t *fptr)
5964{
5965 clear_readconv(fptr);
5966 clear_writeconv(fptr);
5967}
5968
5969static void
5970rb_io_fptr_cleanup_all(rb_io_t *fptr)
5971{
5972 fptr->pathv = Qnil;
5973 if (0 <= fptr->fd)
5974 rb_io_fptr_cleanup(fptr, TRUE);
5975 fptr->write_lock = Qnil;
5976 free_io_buffer(&fptr->rbuf);
5977 free_io_buffer(&fptr->wbuf);
5978 clear_codeconv(fptr);
5979}
5980
5981int
5983{
5984 if (!io) return 0;
5985 rb_io_fptr_cleanup_all(io);
5986 free(io);
5987
5988 return 1;
5989}
5990
5991bool
5992rb_io_fptr_finalize_closed(struct rb_io *io)
5993{
5994 if (!io) return true;
5995 if (io->fd >= 0) return false;
5997 return true;
5998}
5999
6000size_t
6001rb_io_memsize(const rb_io_t *io)
6002{
6003 size_t size = sizeof(rb_io_t);
6004 size += io->rbuf.capa;
6005 size += io->wbuf.capa;
6006 size += io->cbuf.capa;
6007 if (io->readconv) size += rb_econv_memsize(io->readconv);
6008 if (io->writeconv) size += rb_econv_memsize(io->writeconv);
6009
6010 struct rb_io_blocking_operation *blocking_operation = 0;
6011
6012 // Validate the fork generation of the IO object. If the IO object fork generation is different, the list of blocking operations is not valid memory. See `rb_io_blocking_operations` for the exact semantics.
6013 rb_serial_t fork_generation = GET_VM()->fork_gen;
6014 if (io->fork_generation == fork_generation) {
6015 ccan_list_for_each(&io->blocking_operations, blocking_operation, list) {
6016 size += sizeof(struct rb_io_blocking_operation);
6017 }
6018 }
6019
6020 return size;
6021}
6022
6023#ifdef _WIN32
6024/* keep GVL while closing to prevent crash on Windows */
6025# define KEEPGVL TRUE
6026#else
6027# define KEEPGVL FALSE
6028#endif
6029
6030static rb_io_t *
6031io_close_fptr(VALUE io)
6032{
6033 rb_io_t *fptr;
6034 VALUE write_io;
6035 rb_io_t *write_fptr;
6036
6037 write_io = GetWriteIO(io);
6038 if (io != write_io) {
6039 write_fptr = RFILE(write_io)->fptr;
6040 if (write_fptr && 0 <= write_fptr->fd) {
6041 rb_io_fptr_cleanup(write_fptr, TRUE);
6042 }
6043 }
6044
6045 fptr = RFILE(io)->fptr;
6046 if (!fptr) return 0;
6047 if (fptr->fd < 0) return 0;
6048
6049 // This guards against multiple threads closing the same IO object:
6050 if (rb_thread_io_close_interrupt(fptr)) {
6051 /* calls close(fptr->fd): */
6052 fptr_finalize_flush(fptr, FALSE, KEEPGVL);
6053 }
6054
6055 rb_io_fptr_cleanup(fptr, FALSE);
6056 return fptr;
6057}
6058
6059static void
6060fptr_waitpid(rb_io_t *fptr, int nohang)
6061{
6062 int status;
6063 if (fptr->pid) {
6064 rb_last_status_clear();
6065 rb_waitpid(fptr->pid, &status, nohang ? WNOHANG : 0);
6066 fptr->pid = 0;
6067 }
6068}
6069
6070VALUE
6072{
6073 rb_io_t *fptr = io_close_fptr(io);
6074 if (fptr) fptr_waitpid(fptr, 0);
6075 return Qnil;
6076}
6077
6078/*
6079 * call-seq:
6080 * close -> nil
6081 *
6082 * Closes the stream for both reading and writing
6083 * if open for either or both; returns +nil+.
6084 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
6085 *
6086 * If the stream is open for writing, flushes any buffered writes
6087 * to the operating system before closing.
6088 *
6089 * If the stream was opened by IO.popen, sets global variable <tt>$?</tt>
6090 * (child exit status).
6091 *
6092 * It is not an error to close an IO object that has already been closed.
6093 * It just returns nil.
6094 *
6095 * Example:
6096 *
6097 * IO.popen('ruby', 'r+') do |pipe|
6098 * puts pipe.closed?
6099 * pipe.close
6100 * puts $?
6101 * puts pipe.closed?
6102 * end
6103 *
6104 * Output:
6105 *
6106 * false
6107 * pid 13760 exit 0
6108 * true
6109 *
6110 * Related: IO#close_read, IO#close_write, IO#closed?.
6111 */
6112
6113static VALUE
6114rb_io_close_m(VALUE io)
6115{
6116 rb_io_t *fptr = rb_io_get_fptr(io);
6117 if (fptr->fd < 0) {
6118 return Qnil;
6119 }
6120 rb_io_close(io);
6121 return Qnil;
6122}
6123
6124static VALUE
6125io_call_close(VALUE io)
6126{
6127 rb_check_funcall(io, rb_intern("close"), 0, 0);
6128 return io;
6129}
6130
6131static VALUE
6132ignore_closed_stream(VALUE io, VALUE exc)
6133{
6134 enum {mesg_len = sizeof(closed_stream)-1};
6135 VALUE mesg = rb_attr_get(exc, idMesg);
6136 if (!RB_TYPE_P(mesg, T_STRING) ||
6137 RSTRING_LEN(mesg) != mesg_len ||
6138 memcmp(RSTRING_PTR(mesg), closed_stream, mesg_len)) {
6139 rb_exc_raise(exc);
6140 }
6141 return io;
6142}
6143
6144static VALUE
6145io_close(VALUE io)
6146{
6147 VALUE closed = rb_check_funcall(io, rb_intern("closed?"), 0, 0);
6148 if (!UNDEF_P(closed) && RTEST(closed)) return io;
6149 rb_rescue2(io_call_close, io, ignore_closed_stream, io,
6150 rb_eIOError, (VALUE)0);
6151 return io;
6152}
6153
6154/*
6155 * call-seq:
6156 * closed? -> true or false
6157 *
6158 * Returns +true+ if the stream is closed for both reading and writing,
6159 * +false+ otherwise.
6160 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
6161 *
6162 * IO.popen('ruby', 'r+') do |pipe|
6163 * puts pipe.closed?
6164 * pipe.close_read
6165 * puts pipe.closed?
6166 * pipe.close_write
6167 * puts pipe.closed?
6168 * end
6169 *
6170 * Output:
6171 *
6172 * false
6173 * false
6174 * true
6175 *
6176 * Related: IO#close_read, IO#close_write, IO#close.
6177 */
6178VALUE
6180{
6181 rb_io_t *fptr;
6182 VALUE write_io;
6183 rb_io_t *write_fptr;
6184
6185 write_io = GetWriteIO(io);
6186 if (io != write_io) {
6187 write_fptr = RFILE(write_io)->fptr;
6188 if (write_fptr && 0 <= write_fptr->fd) {
6189 return Qfalse;
6190 }
6191 }
6192
6193 fptr = rb_io_get_fptr(io);
6194 return RBOOL(0 > fptr->fd);
6195}
6196
6197/*
6198 * call-seq:
6199 * close_read -> nil
6200 *
6201 * Closes the stream for reading if open for reading;
6202 * returns +nil+.
6203 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
6204 *
6205 * If the stream was opened by IO.popen and is also closed for writing,
6206 * sets global variable <tt>$?</tt> (child exit status).
6207 *
6208 * Example:
6209 *
6210 * IO.popen('ruby', 'r+') do |pipe|
6211 * puts pipe.closed?
6212 * pipe.close_write
6213 * puts pipe.closed?
6214 * pipe.close_read
6215 * puts $?
6216 * puts pipe.closed?
6217 * end
6218 *
6219 * Output:
6220 *
6221 * false
6222 * false
6223 * pid 14748 exit 0
6224 * true
6225 *
6226 * Related: IO#close, IO#close_write, IO#closed?.
6227 */
6228
6229static VALUE
6230rb_io_close_read(VALUE io)
6231{
6232 rb_io_t *fptr;
6233 VALUE write_io;
6234
6235 fptr = rb_io_get_fptr(rb_io_taint_check(io));
6236 if (fptr->fd < 0) return Qnil;
6237 if (is_socket(fptr->fd, fptr->pathv)) {
6238#ifndef SHUT_RD
6239# define SHUT_RD 0
6240#endif
6241 if (shutdown(fptr->fd, SHUT_RD) < 0)
6242 rb_sys_fail_path(fptr->pathv);
6243 fptr->mode &= ~FMODE_READABLE;
6244 if (!(fptr->mode & FMODE_WRITABLE))
6245 return rb_io_close(io);
6246 return Qnil;
6247 }
6248
6249 write_io = GetWriteIO(io);
6250 if (io != write_io) {
6251 rb_io_t *wfptr;
6252 wfptr = rb_io_get_fptr(rb_io_taint_check(write_io));
6253 wfptr->pid = fptr->pid;
6254 fptr->pid = 0;
6255 RFILE(io)->fptr = wfptr;
6256 /* bind to write_io temporarily to get rid of memory/fd leak */
6257 fptr->tied_io_for_writing = 0;
6258 RFILE(write_io)->fptr = fptr;
6259 rb_io_fptr_cleanup(fptr, FALSE);
6260 /* should not finalize fptr because another thread may be reading it */
6261 return Qnil;
6262 }
6263
6264 if ((fptr->mode & (FMODE_DUPLEX|FMODE_WRITABLE)) == FMODE_WRITABLE) {
6265 rb_raise(rb_eIOError, "closing non-duplex IO for reading");
6266 }
6267 return rb_io_close(io);
6268}
6269
6270/*
6271 * call-seq:
6272 * close_write -> nil
6273 *
6274 * Closes the stream for writing if open for writing;
6275 * returns +nil+.
6276 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
6277 *
6278 * Flushes any buffered writes to the operating system before closing.
6279 *
6280 * If the stream was opened by IO.popen and is also closed for reading,
6281 * sets global variable <tt>$?</tt> (child exit status).
6282 *
6283 * IO.popen('ruby', 'r+') do |pipe|
6284 * puts pipe.closed?
6285 * pipe.close_read
6286 * puts pipe.closed?
6287 * pipe.close_write
6288 * puts $?
6289 * puts pipe.closed?
6290 * end
6291 *
6292 * Output:
6293 *
6294 * false
6295 * false
6296 * pid 15044 exit 0
6297 * true
6298 *
6299 * Related: IO#close, IO#close_read, IO#closed?.
6300 */
6301
6302static VALUE
6303rb_io_close_write(VALUE io)
6304{
6305 rb_io_t *fptr;
6306 VALUE write_io;
6307
6308 write_io = GetWriteIO(io);
6309 fptr = rb_io_get_fptr(rb_io_taint_check(write_io));
6310 if (fptr->fd < 0) return Qnil;
6311 if (is_socket(fptr->fd, fptr->pathv)) {
6312#ifndef SHUT_WR
6313# define SHUT_WR 1
6314#endif
6315 /* Flush any buffered data before shutting down the write side.
6316 * Otherwise the buffered bytes are silently dropped here, and a
6317 * subsequent #close would try to flush them into the now
6318 * shutdown(SHUT_WR) socket and fail with EPIPE. This matches the
6319 * behaviour of the non-socket path below, which flushes via
6320 * rb_io_close(). */
6321 if (fptr->mode & FMODE_WRITABLE) {
6322 if (io_fflush(fptr) < 0)
6323 rb_sys_fail_on_write(fptr);
6324 }
6325 if (shutdown(fptr->fd, SHUT_WR) < 0)
6326 rb_sys_fail_path(fptr->pathv);
6327 fptr->mode &= ~FMODE_WRITABLE;
6328 if (!(fptr->mode & FMODE_READABLE))
6329 return rb_io_close(write_io);
6330 return Qnil;
6331 }
6332
6333 if ((fptr->mode & (FMODE_DUPLEX|FMODE_READABLE)) == FMODE_READABLE) {
6334 rb_raise(rb_eIOError, "closing non-duplex IO for writing");
6335 }
6336
6337 if (io != write_io) {
6338 fptr = rb_io_get_fptr(rb_io_taint_check(io));
6339 fptr->tied_io_for_writing = 0;
6340 }
6341 rb_io_close(write_io);
6342 return Qnil;
6343}
6344
6345/*
6346 * call-seq:
6347 * sysseek(offset, whence = IO::SEEK_SET) -> integer
6348 *
6349 * Behaves like IO#seek, except that it:
6350 *
6351 * - Uses low-level system functions.
6352 * - Returns the new position.
6353 *
6354 */
6355
6356static VALUE
6357rb_io_sysseek(int argc, VALUE *argv, VALUE io)
6358{
6359 VALUE offset, ptrname;
6360 int whence = SEEK_SET;
6361 rb_io_t *fptr;
6362 rb_off_t pos;
6363
6364 if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
6365 whence = interpret_seek_whence(ptrname);
6366 }
6367 pos = NUM2OFFT(offset);
6368 GetOpenFile(io, fptr);
6369 if ((fptr->mode & FMODE_READABLE) &&
6370 (READ_DATA_BUFFERED(fptr) || READ_CHAR_PENDING(fptr))) {
6371 rb_raise(rb_eIOError, "sysseek for buffered IO");
6372 }
6373 if ((fptr->mode & FMODE_WRITABLE) && fptr->wbuf.len) {
6374 rb_warn("sysseek for buffered IO");
6375 }
6376 errno = 0;
6377 pos = lseek(fptr->fd, pos, whence);
6378 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
6379
6380 return OFFT2NUM(pos);
6381}
6382
6383/*
6384 * call-seq:
6385 * syswrite(object) -> integer
6386 *
6387 * Writes the given +object+ to self, which must be opened for writing (see Modes);
6388 * returns the number bytes written.
6389 * If +object+ is not a string is converted via method to_s:
6390 *
6391 * f = File.new('t.tmp', 'w')
6392 * f.syswrite('foo') # => 3
6393 * f.syswrite(30) # => 2
6394 * f.syswrite(:foo) # => 3
6395 * f.close
6396 *
6397 * This methods should not be used with other stream-writer methods.
6398 *
6399 */
6400
6401static VALUE
6402rb_io_syswrite(VALUE io, VALUE str)
6403{
6404 VALUE tmp;
6405 rb_io_t *fptr;
6406 long n, len;
6407 const char *ptr;
6408
6409 if (!RB_TYPE_P(str, T_STRING))
6410 str = rb_obj_as_string(str);
6411
6412 io = GetWriteIO(io);
6413 GetOpenFile(io, fptr);
6415
6416 if (fptr->wbuf.len) {
6417 rb_warn("syswrite for buffered IO");
6418 }
6419
6420 tmp = rb_str_tmp_frozen_acquire(str);
6421 RSTRING_GETMEM(tmp, ptr, len);
6422 n = rb_io_write_memory(fptr, ptr, len);
6423 if (n < 0) rb_sys_fail_path(fptr->pathv);
6424 rb_str_tmp_frozen_release(str, tmp);
6425
6426 return LONG2FIX(n);
6427}
6428
6429/*
6430 * call-seq:
6431 * sysread(maxlen) -> string
6432 * sysread(maxlen, out_string) -> string
6433 *
6434 * Behaves like IO#readpartial, except that it uses low-level system functions.
6435 *
6436 * This method should not be used with other stream-reader methods.
6437 *
6438 */
6439
6440static VALUE
6441rb_io_sysread(int argc, VALUE *argv, VALUE io)
6442{
6443 VALUE len, str;
6444 rb_io_t *fptr;
6445 long n, ilen;
6446 struct io_internal_read_struct iis;
6447 int shrinkable;
6448
6449 rb_scan_args(argc, argv, "11", &len, &str);
6450 ilen = NUM2LONG(len);
6451
6452 shrinkable = io_setstrbuf(&str, ilen);
6453 if (ilen == 0) return str;
6454
6455 GetOpenFile(io, fptr);
6457
6458 if (READ_DATA_BUFFERED(fptr)) {
6459 rb_raise(rb_eIOError, "sysread for buffered IO");
6460 }
6461
6462 rb_io_check_closed(fptr);
6463
6464 io_setstrbuf(&str, ilen);
6465 iis.th = rb_thread_current();
6466 iis.fptr = fptr;
6467 iis.nonblock = 0;
6468 iis.fd = fptr->fd;
6469 iis.buf = RSTRING_PTR(str);
6470 iis.capa = ilen;
6471 iis.timeout = NULL;
6472 n = io_read_memory_locktmp(str, &iis);
6473
6474 if (n < 0) {
6475 rb_sys_fail_path(fptr->pathv);
6476 }
6477
6478 io_set_read_length(str, n, shrinkable);
6479
6480 if (n == 0 && ilen > 0) {
6481 rb_eof_error();
6482 }
6483
6484 return str;
6485}
6486
6488 struct rb_io *io;
6489 int fd;
6490 void *buf;
6491 size_t count;
6492 rb_off_t offset;
6493};
6494
6495static VALUE
6496internal_pread_func(void *_arg)
6497{
6498 struct prdwr_internal_arg *arg = _arg;
6499
6500 return (VALUE)pread(arg->fd, arg->buf, arg->count, arg->offset);
6501}
6502
6503static VALUE
6504pread_internal_call(VALUE _arg)
6505{
6506 struct prdwr_internal_arg *arg = (struct prdwr_internal_arg *)_arg;
6507
6508 VALUE scheduler = rb_fiber_scheduler_current();
6509 if (scheduler != Qnil) {
6510 VALUE result = rb_fiber_scheduler_io_pread_memory(scheduler, arg->io->self, arg->offset, arg->buf, arg->count);
6511
6512 if (!UNDEF_P(result)) {
6514 }
6515 }
6516
6517 return rb_io_blocking_region_wait(arg->io, internal_pread_func, arg, RUBY_IO_READABLE);
6518}
6519
6520/*
6521 * call-seq:
6522 * pread(maxlen, offset) -> string
6523 * pread(maxlen, offset, out_string) -> string
6524 *
6525 * Behaves like IO#readpartial, except that it:
6526 *
6527 * - Reads at the given +offset+ (in bytes).
6528 * - Disregards, and does not modify, the stream's position
6529 * (see {Position}[rdoc-ref:IO@Position]).
6530 * - Bypasses any user space buffering in the stream.
6531 *
6532 * Because this method does not disturb the stream's state
6533 * (its position, in particular), +pread+ allows multiple threads and processes
6534 * to use the same \IO object for reading at various offsets.
6535 *
6536 * f = File.open('t.txt')
6537 * f.read # => "First line\nSecond line\n\nFourth line\nFifth line\n"
6538 * f.pos # => 52
6539 * # Read 12 bytes at offset 0.
6540 * f.pread(12, 0) # => "First line\n"
6541 * # Read 9 bytes at offset 8.
6542 * f.pread(9, 8) # => "ne\nSecon"
6543 * f.close
6544 *
6545 * Not available on some platforms.
6546 *
6547 */
6548static VALUE
6549rb_io_pread(int argc, VALUE *argv, VALUE io)
6550{
6551 VALUE len, offset, str;
6552 rb_io_t *fptr;
6553 ssize_t n;
6554 struct prdwr_internal_arg arg;
6555 int shrinkable;
6556
6557 rb_scan_args(argc, argv, "21", &len, &offset, &str);
6558 arg.count = NUM2SIZET(len);
6559 arg.offset = NUM2OFFT(offset);
6560
6561 shrinkable = io_setstrbuf(&str, (long)arg.count);
6562 if (arg.count == 0) return str;
6563 arg.buf = RSTRING_PTR(str);
6564
6565 GetOpenFile(io, fptr);
6567
6568 arg.io = fptr;
6569 arg.fd = fptr->fd;
6570 rb_io_check_closed(fptr);
6571
6572 rb_str_locktmp(str);
6573 n = (ssize_t)rb_ensure(pread_internal_call, (VALUE)&arg, rb_str_unlocktmp, str);
6574
6575 if (n < 0) {
6576 rb_sys_fail_path(fptr->pathv);
6577 }
6578 io_set_read_length(str, n, shrinkable);
6579 if (n == 0 && arg.count > 0) {
6580 rb_eof_error();
6581 }
6582
6583 return str;
6584}
6585
6586static VALUE
6587internal_pwrite_func(void *_arg)
6588{
6589 struct prdwr_internal_arg *arg = _arg;
6590
6591 return (VALUE)pwrite(arg->fd, arg->buf, arg->count, arg->offset);
6592}
6593
6594static VALUE
6595pwrite_internal_call(VALUE _arg)
6596{
6597 struct prdwr_internal_arg *arg = (struct prdwr_internal_arg *)_arg;
6598
6599 VALUE scheduler = rb_fiber_scheduler_current();
6600 if (scheduler != Qnil) {
6601 VALUE result = rb_fiber_scheduler_io_pwrite_memory(scheduler, arg->io->self, arg->offset, arg->buf, arg->count);
6602
6603 if (!UNDEF_P(result)) {
6605 }
6606 }
6607
6608 return rb_io_blocking_region_wait(arg->io, internal_pwrite_func, arg, RUBY_IO_WRITABLE);
6609}
6610
6611/*
6612 * call-seq:
6613 * pwrite(object, offset) -> integer
6614 *
6615 * Behaves like IO#write, except that it:
6616 *
6617 * - Writes at the given +offset+ (in bytes).
6618 * - Disregards, and does not modify, the stream's position
6619 * (see {Position}[rdoc-ref:IO@Position]).
6620 * - Bypasses any user space buffering in the stream.
6621 *
6622 * Because this method does not disturb the stream's state
6623 * (its position, in particular), +pwrite+ allows multiple threads and processes
6624 * to use the same \IO object for writing at various offsets.
6625 *
6626 * f = File.open('t.tmp', 'w+')
6627 * # Write 6 bytes at offset 3.
6628 * f.pwrite('ABCDEF', 3) # => 6
6629 * f.rewind
6630 * f.read # => "\u0000\u0000\u0000ABCDEF"
6631 * f.close
6632 *
6633 * Not available on some platforms.
6634 *
6635 */
6636static VALUE
6637rb_io_pwrite(VALUE io, VALUE str, VALUE offset)
6638{
6639 rb_io_t *fptr;
6640 ssize_t n;
6641 struct prdwr_internal_arg arg;
6642 VALUE tmp;
6643
6644 if (!RB_TYPE_P(str, T_STRING))
6645 str = rb_obj_as_string(str);
6646
6647 arg.offset = NUM2OFFT(offset);
6648
6649 io = GetWriteIO(io);
6650 GetOpenFile(io, fptr);
6652
6653 arg.io = fptr;
6654 arg.fd = fptr->fd;
6655
6656 tmp = rb_str_tmp_frozen_acquire(str);
6657 arg.buf = RSTRING_PTR(tmp);
6658 arg.count = (size_t)RSTRING_LEN(tmp);
6659
6660 n = (ssize_t)pwrite_internal_call((VALUE)&arg);
6661 if (n < 0) rb_sys_fail_path(fptr->pathv);
6662 rb_str_tmp_frozen_release(str, tmp);
6663
6664 return SSIZET2NUM(n);
6665}
6666
6667VALUE
6669{
6670 rb_io_t *fptr;
6671
6672 GetOpenFile(io, fptr);
6673 if (fptr->readconv)
6675 if (fptr->writeconv)
6677 fptr->mode |= FMODE_BINMODE;
6678 fptr->mode &= ~FMODE_TEXTMODE;
6679 fptr->writeconv_pre_ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
6680#ifdef O_BINARY
6681 if (!fptr->readconv) {
6682 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6683 }
6684 else {
6685 setmode(fptr->fd, O_BINARY);
6686 }
6687#endif
6688 return io;
6689}
6690
6691static void
6692io_ascii8bit_binmode(rb_io_t *fptr)
6693{
6694 if (fptr->readconv) {
6695 rb_econv_close(fptr->readconv);
6696 fptr->readconv = NULL;
6697 }
6698 if (fptr->writeconv) {
6700 fptr->writeconv = NULL;
6701 }
6702 fptr->mode |= FMODE_BINMODE;
6703 fptr->mode &= ~FMODE_TEXTMODE;
6704 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6705
6706 fptr->encs.enc = rb_ascii8bit_encoding();
6707 fptr->encs.enc2 = NULL;
6708 fptr->encs.ecflags = 0;
6709 fptr->encs.ecopts = Qnil;
6710 clear_codeconv(fptr);
6711}
6712
6713VALUE
6715{
6716 rb_io_t *fptr;
6717
6718 GetOpenFile(io, fptr);
6719 io_ascii8bit_binmode(fptr);
6720
6721 return io;
6722}
6723
6724/*
6725 * call-seq:
6726 * binmode -> self
6727 *
6728 * Sets the stream's data mode as binary
6729 * (see {Data Mode}[rdoc-ref:File@Data+Mode]).
6730 *
6731 * A stream's data mode may not be changed from binary to text.
6732 *
6733 */
6734
6735static VALUE
6736rb_io_binmode_m(VALUE io)
6737{
6738 VALUE write_io;
6739
6741
6742 write_io = GetWriteIO(io);
6743 if (write_io != io)
6744 rb_io_ascii8bit_binmode(write_io);
6745 return io;
6746}
6747
6748/*
6749 * call-seq:
6750 * binmode? -> true or false
6751 *
6752 * Returns +true+ if the stream is on binary mode, +false+ otherwise.
6753 * See {Data Mode}[rdoc-ref:File@Data+Mode].
6754 *
6755 */
6756static VALUE
6757rb_io_binmode_p(VALUE io)
6758{
6759 rb_io_t *fptr;
6760 GetOpenFile(io, fptr);
6761 return RBOOL(fptr->mode & FMODE_BINMODE);
6762}
6763
6764static const char*
6765rb_io_fmode_modestr(enum rb_io_mode fmode)
6766{
6767 if (fmode & FMODE_APPEND) {
6768 if ((fmode & FMODE_READWRITE) == FMODE_READWRITE) {
6769 return MODE_BTMODE("a+", "ab+", "at+");
6770 }
6771 return MODE_BTMODE("a", "ab", "at");
6772 }
6773 switch (fmode & FMODE_READWRITE) {
6774 default:
6775 rb_raise(rb_eArgError, "invalid access fmode 0x%x", fmode);
6776 case FMODE_READABLE:
6777 return MODE_BTMODE("r", "rb", "rt");
6778 case FMODE_WRITABLE:
6779 return MODE_BTXMODE("w", "wb", "wt", "wx", "wbx", "wtx");
6780 case FMODE_READWRITE:
6781 if (fmode & FMODE_CREATE) {
6782 return MODE_BTXMODE("w+", "wb+", "wt+", "w+x", "wb+x", "wt+x");
6783 }
6784 return MODE_BTMODE("r+", "rb+", "rt+");
6785 }
6786}
6787
6788static const char bom_prefix[] = "bom|";
6789static const char utf_prefix[] = "utf-";
6790enum {bom_prefix_len = (int)sizeof(bom_prefix) - 1};
6791enum {utf_prefix_len = (int)sizeof(utf_prefix) - 1};
6792
6793static int
6794io_encname_bom_p(const char *name, long len)
6795{
6796 return len > bom_prefix_len && STRNCASECMP(name, bom_prefix, bom_prefix_len) == 0;
6797}
6798
6799enum rb_io_mode
6800rb_io_modestr_fmode(const char *modestr)
6801{
6802 enum rb_io_mode fmode = 0;
6803 const char *m = modestr, *p = NULL;
6804
6805 switch (*m++) {
6806 case 'r':
6807 fmode |= FMODE_READABLE;
6808 break;
6809 case 'w':
6811 break;
6812 case 'a':
6814 break;
6815 default:
6816 goto error;
6817 }
6818
6819 while (*m) {
6820 switch (*m++) {
6821 case 'b':
6822 fmode |= FMODE_BINMODE;
6823 break;
6824 case 't':
6825 fmode |= FMODE_TEXTMODE;
6826 break;
6827 case '+':
6828 fmode |= FMODE_READWRITE;
6829 break;
6830 case 'x':
6831 if (modestr[0] != 'w')
6832 goto error;
6833 fmode |= FMODE_EXCL;
6834 break;
6835 default:
6836 goto error;
6837 case ':':
6838 p = strchr(m, ':');
6839 if (io_encname_bom_p(m, p ? (long)(p - m) : (long)strlen(m)))
6840 fmode |= FMODE_SETENC_BY_BOM;
6841 goto finished;
6842 }
6843 }
6844
6845 finished:
6846 if ((fmode & FMODE_BINMODE) && (fmode & FMODE_TEXTMODE))
6847 goto error;
6848
6849 return fmode;
6850
6851 error:
6852 rb_raise(rb_eArgError, "invalid access mode %s", modestr);
6854}
6855
6856int
6857rb_io_oflags_fmode(int oflags)
6858{
6859 enum rb_io_mode fmode = 0;
6860
6861 switch (oflags & O_ACCMODE) {
6862 case O_RDONLY:
6863 fmode = FMODE_READABLE;
6864 break;
6865 case O_WRONLY:
6866 fmode = FMODE_WRITABLE;
6867 break;
6868 case O_RDWR:
6869 fmode = FMODE_READWRITE;
6870 break;
6871 }
6872
6873 if (oflags & O_APPEND) {
6874 fmode |= FMODE_APPEND;
6875 }
6876 if (oflags & O_TRUNC) {
6877 fmode |= FMODE_TRUNC;
6878 }
6879 if (oflags & O_CREAT) {
6880 fmode |= FMODE_CREATE;
6881 }
6882 if (oflags & O_EXCL) {
6883 fmode |= FMODE_EXCL;
6884 }
6885#ifdef O_BINARY
6886 if (oflags & O_BINARY) {
6887 fmode |= FMODE_BINMODE;
6888 }
6889#endif
6890
6891 return fmode;
6892}
6893
6894static int
6895rb_io_fmode_oflags(enum rb_io_mode fmode)
6896{
6897 int oflags = 0;
6898
6899 switch (fmode & FMODE_READWRITE) {
6900 case FMODE_READABLE:
6901 oflags |= O_RDONLY;
6902 break;
6903 case FMODE_WRITABLE:
6904 oflags |= O_WRONLY;
6905 break;
6906 case FMODE_READWRITE:
6907 oflags |= O_RDWR;
6908 break;
6909 }
6910
6911 if (fmode & FMODE_APPEND) {
6912 oflags |= O_APPEND;
6913 }
6914 if (fmode & FMODE_TRUNC) {
6915 oflags |= O_TRUNC;
6916 }
6917 if (fmode & FMODE_CREATE) {
6918 oflags |= O_CREAT;
6919 }
6920 if (fmode & FMODE_EXCL) {
6921 oflags |= O_EXCL;
6922 }
6923#ifdef O_BINARY
6924 if (fmode & FMODE_BINMODE) {
6925 oflags |= O_BINARY;
6926 }
6927#endif
6928
6929 return oflags;
6930}
6931
6932int
6933rb_io_modestr_oflags(const char *modestr)
6934{
6935 return rb_io_fmode_oflags(rb_io_modestr_fmode(modestr));
6936}
6937
6938static const char*
6939rb_io_oflags_modestr(int oflags)
6940{
6941#ifdef O_BINARY
6942# define MODE_BINARY(a,b) ((oflags & O_BINARY) ? (b) : (a))
6943#else
6944# define MODE_BINARY(a,b) (a)
6945#endif
6946 int accmode;
6947 if (oflags & O_EXCL) {
6948 rb_raise(rb_eArgError, "exclusive access mode is not supported");
6949 }
6950 accmode = oflags & (O_RDONLY|O_WRONLY|O_RDWR);
6951 if (oflags & O_APPEND) {
6952 if (accmode == O_WRONLY) {
6953 return MODE_BINARY("a", "ab");
6954 }
6955 if (accmode == O_RDWR) {
6956 return MODE_BINARY("a+", "ab+");
6957 }
6958 }
6959 switch (accmode) {
6960 default:
6961 rb_raise(rb_eArgError, "invalid access oflags 0x%x", oflags);
6962 case O_RDONLY:
6963 return MODE_BINARY("r", "rb");
6964 case O_WRONLY:
6965 return MODE_BINARY("w", "wb");
6966 case O_RDWR:
6967 if (oflags & O_TRUNC) {
6968 return MODE_BINARY("w+", "wb+");
6969 }
6970 return MODE_BINARY("r+", "rb+");
6971 }
6972}
6973
6974/*
6975 * Convert external/internal encodings to enc/enc2
6976 * NULL => use default encoding
6977 * Qnil => no encoding specified (internal only)
6978 */
6979static void
6980rb_io_ext_int_to_encs(rb_encoding *ext, rb_encoding *intern, rb_encoding **enc, rb_encoding **enc2, enum rb_io_mode fmode)
6981{
6982 int default_ext = 0;
6983
6984 if (ext == NULL) {
6985 ext = rb_default_external_encoding();
6986 default_ext = 1;
6987 }
6988 if (rb_is_ascii8bit_enc(ext)) {
6989 /* If external is ASCII-8BIT, no transcoding */
6990 intern = NULL;
6991 }
6992 else if (intern == NULL) {
6993 intern = rb_default_internal_encoding();
6994 }
6995 if (intern == NULL || intern == (rb_encoding *)Qnil ||
6996 (!(fmode & FMODE_SETENC_BY_BOM) && (intern == ext))) {
6997 /* No internal encoding => use external + no transcoding */
6998 *enc = (default_ext && intern != ext) ? NULL : ext;
6999 *enc2 = NULL;
7000 }
7001 else {
7002 *enc = intern;
7003 *enc2 = ext;
7004 }
7005}
7006
7007static void
7008unsupported_encoding(const char *name, rb_encoding *enc)
7009{
7010 rb_enc_warn(enc, "Unsupported encoding %s ignored", name);
7011}
7012
7013static void
7014parse_mode_enc(const char *estr, rb_encoding *estr_enc,
7015 rb_encoding **enc_p, rb_encoding **enc2_p, enum rb_io_mode *fmode_p)
7016{
7017 const char *p;
7018 char encname[ENCODING_MAXNAMELEN+1];
7019 int idx, idx2;
7020 enum rb_io_mode fmode = fmode_p ? *fmode_p : 0;
7021 rb_encoding *ext_enc, *int_enc;
7022 long len;
7023
7024 /* parse estr as "enc" or "enc2:enc" or "enc:-" */
7025
7026 p = strrchr(estr, ':');
7027 len = p ? (p++ - estr) : (long)strlen(estr);
7028 if ((fmode & FMODE_SETENC_BY_BOM) || io_encname_bom_p(estr, len)) {
7029 estr += bom_prefix_len;
7030 len -= bom_prefix_len;
7031 if (!STRNCASECMP(estr, utf_prefix, utf_prefix_len)) {
7032 fmode |= FMODE_SETENC_BY_BOM;
7033 }
7034 else {
7035 rb_enc_warn(estr_enc, "BOM with non-UTF encoding %s is nonsense", estr);
7036 fmode &= ~FMODE_SETENC_BY_BOM;
7037 }
7038 }
7039 if (len == 0 || len > ENCODING_MAXNAMELEN) {
7040 idx = -1;
7041 }
7042 else {
7043 if (p) {
7044 memcpy(encname, estr, len);
7045 encname[len] = '\0';
7046 estr = encname;
7047 }
7048 idx = rb_enc_find_index(estr);
7049 }
7050 if (fmode_p) *fmode_p = fmode;
7051
7052 if (idx >= 0)
7053 ext_enc = rb_enc_from_index(idx);
7054 else {
7055 if (idx != -2)
7056 unsupported_encoding(estr, estr_enc);
7057 ext_enc = NULL;
7058 }
7059
7060 int_enc = NULL;
7061 if (p) {
7062 if (*p == '-' && *(p+1) == '\0') {
7063 /* Special case - "-" => no transcoding */
7064 int_enc = (rb_encoding *)Qnil;
7065 }
7066 else {
7067 idx2 = rb_enc_find_index(p);
7068 if (idx2 < 0)
7069 unsupported_encoding(p, estr_enc);
7070 else if (!(fmode & FMODE_SETENC_BY_BOM) && (idx2 == idx)) {
7071 int_enc = (rb_encoding *)Qnil;
7072 }
7073 else
7074 int_enc = rb_enc_from_index(idx2);
7075 }
7076 }
7077
7078 rb_io_ext_int_to_encs(ext_enc, int_enc, enc_p, enc2_p, fmode);
7079}
7080
7081int
7082rb_io_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding **enc2_p, enum rb_io_mode *fmode_p)
7083{
7084 VALUE encoding=Qnil, extenc=Qundef, intenc=Qundef, tmp;
7085 int extracted = 0;
7086 rb_encoding *extencoding = NULL;
7087 rb_encoding *intencoding = NULL;
7088
7089 if (!NIL_P(opt)) {
7090 VALUE v;
7091 v = rb_hash_lookup2(opt, sym_encoding, Qnil);
7092 if (v != Qnil) encoding = v;
7093 v = rb_hash_lookup2(opt, sym_extenc, Qundef);
7094 if (v != Qnil) extenc = v;
7095 v = rb_hash_lookup2(opt, sym_intenc, Qundef);
7096 if (!UNDEF_P(v)) intenc = v;
7097 }
7098 if ((!UNDEF_P(extenc) || !UNDEF_P(intenc)) && !NIL_P(encoding)) {
7099 if (!NIL_P(ruby_verbose)) {
7100 int idx = rb_to_encoding_index(encoding);
7101 if (idx >= 0) encoding = rb_enc_from_encoding(rb_enc_from_index(idx));
7102 rb_warn("Ignoring encoding parameter '%"PRIsVALUE"': %s_encoding is used",
7103 encoding, UNDEF_P(extenc) ? "internal" : "external");
7104 }
7105 encoding = Qnil;
7106 }
7107 if (!UNDEF_P(extenc) && !NIL_P(extenc)) {
7108 extencoding = rb_to_encoding(extenc);
7109 }
7110 if (!UNDEF_P(intenc)) {
7111 if (NIL_P(intenc)) {
7112 /* internal_encoding: nil => no transcoding */
7113 intencoding = (rb_encoding *)Qnil;
7114 }
7115 else if (!NIL_P(tmp = rb_check_string_type(intenc))) {
7116 char *p = StringValueCStr(tmp);
7117
7118 if (*p == '-' && *(p+1) == '\0') {
7119 /* Special case - "-" => no transcoding */
7120 intencoding = (rb_encoding *)Qnil;
7121 }
7122 else {
7123 intencoding = rb_to_encoding(intenc);
7124 }
7125 }
7126 else {
7127 intencoding = rb_to_encoding(intenc);
7128 }
7129 if (extencoding == intencoding) {
7130 intencoding = (rb_encoding *)Qnil;
7131 }
7132 }
7133 if (!NIL_P(encoding)) {
7134 extracted = 1;
7135 if (!NIL_P(tmp = rb_check_string_type(encoding))) {
7136 parse_mode_enc(StringValueCStr(tmp), rb_enc_get(tmp),
7137 enc_p, enc2_p, fmode_p);
7138 }
7139 else {
7140 rb_io_ext_int_to_encs(rb_to_encoding(encoding), NULL, enc_p, enc2_p, 0);
7141 }
7142 }
7143 else if (!UNDEF_P(extenc) || !UNDEF_P(intenc)) {
7144 extracted = 1;
7145 rb_io_ext_int_to_encs(extencoding, intencoding, enc_p, enc2_p, 0);
7146 }
7147 return extracted;
7148}
7149
7150static void
7151validate_enc_binmode(enum rb_io_mode *fmode_p, int ecflags, rb_encoding *enc, rb_encoding *enc2)
7152{
7153 enum rb_io_mode fmode = *fmode_p;
7154
7155 if ((fmode & FMODE_READABLE) &&
7156 !enc2 &&
7157 !(fmode & FMODE_BINMODE) &&
7158 !rb_enc_asciicompat(enc ? enc : rb_default_external_encoding()))
7159 rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
7160
7161 if ((fmode & FMODE_BINMODE) && (ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
7162 rb_raise(rb_eArgError, "newline decorator with binary mode");
7163 }
7164 if (!(fmode & FMODE_BINMODE) &&
7165 (DEFAULT_TEXTMODE || (ecflags & ECONV_NEWLINE_DECORATOR_MASK))) {
7166 fmode |= FMODE_TEXTMODE;
7167 *fmode_p = fmode;
7168 }
7169#if !DEFAULT_TEXTMODE
7170 else if (!(ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
7171 fmode &= ~FMODE_TEXTMODE;
7172 *fmode_p = fmode;
7173 }
7174#endif
7175}
7176
7177static void
7178extract_binmode(VALUE opthash, enum rb_io_mode *fmode)
7179{
7180 if (!NIL_P(opthash)) {
7181 VALUE v;
7182 v = rb_hash_aref(opthash, sym_textmode);
7183 if (!NIL_P(v)) {
7184 if (*fmode & FMODE_TEXTMODE)
7185 rb_raise(rb_eArgError, "textmode specified twice");
7186 if (*fmode & FMODE_BINMODE)
7187 rb_raise(rb_eArgError, "both textmode and binmode specified");
7188 if (RTEST(v))
7189 *fmode |= FMODE_TEXTMODE;
7190 }
7191 v = rb_hash_aref(opthash, sym_binmode);
7192 if (!NIL_P(v)) {
7193 if (*fmode & FMODE_BINMODE)
7194 rb_raise(rb_eArgError, "binmode specified twice");
7195 if (*fmode & FMODE_TEXTMODE)
7196 rb_raise(rb_eArgError, "both textmode and binmode specified");
7197 if (RTEST(v))
7198 *fmode |= FMODE_BINMODE;
7199 }
7200
7201 if ((*fmode & FMODE_BINMODE) && (*fmode & FMODE_TEXTMODE))
7202 rb_raise(rb_eArgError, "both textmode and binmode specified");
7203 }
7204}
7205
7206void
7207rb_io_extract_modeenc(VALUE *vmode_p, VALUE *vperm_p, VALUE opthash,
7208 int *oflags_p, enum rb_io_mode *fmode_p, struct rb_io_encoding *convconfig_p)
7209{
7210 VALUE vmode;
7211 int oflags;
7212 enum rb_io_mode fmode;
7213 rb_encoding *enc, *enc2;
7214 int ecflags;
7215 VALUE ecopts;
7216 int has_enc = 0, has_vmode = 0;
7217 VALUE intmode;
7218
7219 vmode = *vmode_p;
7220
7221 /* Set to defaults */
7222 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
7223
7224 vmode_handle:
7225 if (NIL_P(vmode)) {
7226 fmode = FMODE_READABLE;
7227 oflags = O_RDONLY;
7228 }
7229 else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int"))) {
7230 vmode = intmode;
7231 oflags = NUM2INT(intmode);
7232 fmode = rb_io_oflags_fmode(oflags);
7233 }
7234 else {
7235 const char *p;
7236
7237 StringValue(vmode);
7238 p = StringValueCStr(vmode);
7239 fmode = rb_io_modestr_fmode(p);
7240 oflags = rb_io_fmode_oflags(fmode);
7241 p = strchr(p, ':');
7242 if (p) {
7243 has_enc = 1;
7244 parse_mode_enc(p+1, rb_enc_get(vmode), &enc, &enc2, &fmode);
7245 }
7246 else {
7247 rb_encoding *e;
7248
7249 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
7250 rb_io_ext_int_to_encs(e, NULL, &enc, &enc2, fmode);
7251 }
7252 }
7253
7254 if (NIL_P(opthash)) {
7255 ecflags = (fmode & FMODE_READABLE) ?
7258#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7259 ecflags |= (fmode & FMODE_WRITABLE) ?
7260 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7261 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7262#endif
7263 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
7264 ecopts = Qnil;
7265 if (fmode & FMODE_BINMODE) {
7266#ifdef O_BINARY
7267 oflags |= O_BINARY;
7268#endif
7269 if (!has_enc)
7270 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
7271 }
7272#if DEFAULT_TEXTMODE
7273 else if (NIL_P(vmode)) {
7274 fmode |= DEFAULT_TEXTMODE;
7275 }
7276#endif
7277 }
7278 else {
7279 VALUE v;
7280 if (!has_vmode) {
7281 v = rb_hash_aref(opthash, sym_mode);
7282 if (!NIL_P(v)) {
7283 if (!NIL_P(vmode)) {
7284 rb_raise(rb_eArgError, "mode specified twice");
7285 }
7286 has_vmode = 1;
7287 vmode = v;
7288 goto vmode_handle;
7289 }
7290 }
7291 v = rb_hash_aref(opthash, sym_flags);
7292 if (!NIL_P(v)) {
7293 v = rb_to_int(v);
7294 oflags |= NUM2INT(v);
7295 vmode = INT2NUM(oflags);
7296 fmode = rb_io_oflags_fmode(oflags);
7297 }
7298 extract_binmode(opthash, &fmode);
7299 if (fmode & FMODE_BINMODE) {
7300#ifdef O_BINARY
7301 oflags |= O_BINARY;
7302#endif
7303 if (!has_enc)
7304 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
7305 }
7306#if DEFAULT_TEXTMODE
7307 else if (NIL_P(vmode)) {
7308 fmode |= DEFAULT_TEXTMODE;
7309 }
7310#endif
7311 v = rb_hash_aref(opthash, sym_perm);
7312 if (!NIL_P(v)) {
7313 if (vperm_p) {
7314 if (!NIL_P(*vperm_p)) {
7315 rb_raise(rb_eArgError, "perm specified twice");
7316 }
7317 *vperm_p = v;
7318 }
7319 else {
7320 /* perm no use, just ignore */
7321 }
7322 }
7323 ecflags = (fmode & FMODE_READABLE) ?
7326#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7327 ecflags |= (fmode & FMODE_WRITABLE) ?
7328 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7329 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7330#endif
7331
7332 if (rb_io_extract_encoding_option(opthash, &enc, &enc2, &fmode)) {
7333 if (has_enc) {
7334 rb_raise(rb_eArgError, "encoding specified twice");
7335 }
7336 }
7337 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
7338 ecflags = rb_econv_prepare_options(opthash, &ecopts, ecflags);
7339 }
7340
7341 validate_enc_binmode(&fmode, ecflags, enc, enc2);
7342
7343 *vmode_p = vmode;
7344
7345 *oflags_p = oflags;
7346 *fmode_p = fmode;
7347 convconfig_p->enc = enc;
7348 convconfig_p->enc2 = enc2;
7349 convconfig_p->ecflags = ecflags;
7350 convconfig_p->ecopts = ecopts;
7351}
7352
7354 VALUE fname;
7355 int oflags;
7356 mode_t perm;
7357};
7358
7359static void *
7360sysopen_func(void *ptr)
7361{
7362 const struct sysopen_struct *data = ptr;
7363 const char *fname = RSTRING_PTR(data->fname);
7364 return (void *)(VALUE)rb_cloexec_open(fname, data->oflags, data->perm);
7365}
7366
7367static inline int
7368rb_sysopen_internal(struct sysopen_struct *data)
7369{
7370 int fd;
7371 do {
7372 fd = IO_WITHOUT_GVL_INT(sysopen_func, data);
7373 } while (fd < 0 && errno == EINTR);
7374 if (0 <= fd)
7375 rb_update_max_fd(fd);
7376 return fd;
7377}
7378
7379static int
7380rb_sysopen(VALUE fname, int oflags, mode_t perm)
7381{
7382 int fd = -1;
7383 struct sysopen_struct data;
7384
7385 data.fname = rb_str_encode_ospath(fname);
7386 StringValueCStr(data.fname);
7387 data.oflags = oflags;
7388 data.perm = perm;
7389
7390 TRY_WITH_GC((fd = rb_sysopen_internal(&data)) >= 0) {
7391 rb_syserr_fail_path(first_errno, fname);
7392 }
7393 return fd;
7394}
7395
7396static inline FILE *
7397fdopen_internal(int fd, const char *modestr)
7398{
7399 FILE *file;
7400
7401#if defined(__sun)
7402 errno = 0;
7403#endif
7404 file = fdopen(fd, modestr);
7405 if (!file) {
7406#ifdef _WIN32
7407 if (errno == 0) errno = EINVAL;
7408#elif defined(__sun)
7409 if (errno == 0) errno = EMFILE;
7410#endif
7411 }
7412 return file;
7413}
7414
7415FILE *
7416rb_fdopen(int fd, const char *modestr)
7417{
7418 FILE *file = 0;
7419
7420 TRY_WITH_GC((file = fdopen_internal(fd, modestr)) != 0) {
7421 rb_syserr_fail(first_errno, 0);
7422 }
7423
7424 /* xxx: should be _IONBF? A buffer in FILE may have trouble. */
7425#ifdef USE_SETVBUF
7426 if (setvbuf(file, NULL, _IOFBF, 0) != 0)
7427 rb_warn("setvbuf() can't be honoured (fd=%d)", fd);
7428#endif
7429 return file;
7430}
7431
7432static int
7433io_check_tty(rb_io_t *fptr)
7434{
7435 int t = isatty(fptr->fd);
7436 if (t)
7437 fptr->mode |= FMODE_TTY|FMODE_DUPLEX;
7438 return t;
7439}
7440
7441static VALUE rb_io_internal_encoding(VALUE);
7442static void io_encoding_set(rb_io_t *, VALUE, VALUE, VALUE);
7443
7444static int
7445io_strip_bom(VALUE io)
7446{
7447 VALUE b1, b2, b3, b4;
7448 rb_io_t *fptr;
7449
7450 GetOpenFile(io, fptr);
7451 if (!(fptr->mode & FMODE_READABLE)) return 0;
7452 if (NIL_P(b1 = rb_io_getbyte(io))) return 0;
7453 switch (b1) {
7454 case INT2FIX(0xEF):
7455 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7456 if (b2 == INT2FIX(0xBB) && !NIL_P(b3 = rb_io_getbyte(io))) {
7457 if (b3 == INT2FIX(0xBF)) {
7458 return rb_utf8_encindex();
7459 }
7460 rb_io_ungetbyte(io, b3);
7461 }
7462 rb_io_ungetbyte(io, b2);
7463 break;
7464
7465 case INT2FIX(0xFE):
7466 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7467 if (b2 == INT2FIX(0xFF)) {
7468 return ENCINDEX_UTF_16BE;
7469 }
7470 rb_io_ungetbyte(io, b2);
7471 break;
7472
7473 case INT2FIX(0xFF):
7474 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7475 if (b2 == INT2FIX(0xFE)) {
7476 b3 = rb_io_getbyte(io);
7477 if (b3 == INT2FIX(0) && !NIL_P(b4 = rb_io_getbyte(io))) {
7478 if (b4 == INT2FIX(0)) {
7479 return ENCINDEX_UTF_32LE;
7480 }
7481 rb_io_ungetbyte(io, b4);
7482 }
7483 rb_io_ungetbyte(io, b3);
7484 return ENCINDEX_UTF_16LE;
7485 }
7486 rb_io_ungetbyte(io, b2);
7487 break;
7488
7489 case INT2FIX(0):
7490 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7491 if (b2 == INT2FIX(0) && !NIL_P(b3 = rb_io_getbyte(io))) {
7492 if (b3 == INT2FIX(0xFE) && !NIL_P(b4 = rb_io_getbyte(io))) {
7493 if (b4 == INT2FIX(0xFF)) {
7494 return ENCINDEX_UTF_32BE;
7495 }
7496 rb_io_ungetbyte(io, b4);
7497 }
7498 rb_io_ungetbyte(io, b3);
7499 }
7500 rb_io_ungetbyte(io, b2);
7501 break;
7502 }
7503 rb_io_ungetbyte(io, b1);
7504 return 0;
7505}
7506
7507static rb_encoding *
7508io_set_encoding_by_bom(VALUE io)
7509{
7510 int idx = io_strip_bom(io);
7511 rb_io_t *fptr;
7512 rb_encoding *extenc = NULL;
7513
7514 GetOpenFile(io, fptr);
7515 if (idx) {
7516 extenc = rb_enc_from_index(idx);
7517 io_encoding_set(fptr, rb_enc_from_encoding(extenc),
7518 rb_io_internal_encoding(io), Qnil);
7519 }
7520 else {
7521 fptr->encs.enc2 = NULL;
7522 }
7523 return extenc;
7524}
7525
7526static VALUE
7527rb_file_open_generic(VALUE io, VALUE filename, int oflags, enum rb_io_mode fmode,
7528 const struct rb_io_encoding *convconfig, mode_t perm)
7529{
7530 VALUE pathv;
7531 rb_io_t *fptr;
7532 struct rb_io_encoding cc;
7533 if (!convconfig) {
7534 /* Set to default encodings */
7535 rb_io_ext_int_to_encs(NULL, NULL, &cc.enc, &cc.enc2, fmode);
7536 cc.ecflags = 0;
7537 cc.ecopts = Qnil;
7538 convconfig = &cc;
7539 }
7540 validate_enc_binmode(&fmode, convconfig->ecflags,
7541 convconfig->enc, convconfig->enc2);
7542
7543 MakeOpenFile(io, fptr);
7544 fptr->mode = fmode;
7545 fptr->encs = *convconfig;
7546 pathv = rb_str_new_frozen(filename);
7547#ifdef O_TMPFILE
7548 if (!(oflags & O_TMPFILE)) {
7549 fptr->pathv = pathv;
7550 }
7551#else
7552 fptr->pathv = pathv;
7553#endif
7554 fptr->fd = rb_sysopen(pathv, oflags, perm);
7555 io_check_tty(fptr);
7556 if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
7557
7558 return io;
7559}
7560
7561static VALUE
7562rb_file_open_internal(VALUE io, VALUE filename, const char *modestr)
7563{
7564 enum rb_io_mode fmode = rb_io_modestr_fmode(modestr);
7565 const char *p = strchr(modestr, ':');
7566 struct rb_io_encoding convconfig;
7567
7568 if (p) {
7569 parse_mode_enc(p+1, rb_usascii_encoding(),
7570 &convconfig.enc, &convconfig.enc2, &fmode);
7571 }
7572 else {
7573 rb_encoding *e;
7574 /* Set to default encodings */
7575
7576 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
7577 rb_io_ext_int_to_encs(e, NULL, &convconfig.enc, &convconfig.enc2, fmode);
7578 }
7579
7580 convconfig.ecflags = (fmode & FMODE_READABLE) ?
7583#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7584 convconfig.ecflags |= (fmode & FMODE_WRITABLE) ?
7585 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7586 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7587#endif
7588 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.enc2, convconfig.ecflags);
7589 convconfig.ecopts = Qnil;
7590
7591 return rb_file_open_generic(io, filename,
7592 rb_io_fmode_oflags(fmode),
7593 fmode,
7594 &convconfig,
7595 0666);
7596}
7597
7598VALUE
7599rb_file_open_str(VALUE fname, const char *modestr)
7600{
7601 FilePathValue(fname);
7602 return rb_file_open_internal(io_alloc(rb_cFile), fname, modestr);
7603}
7604
7605VALUE
7606rb_file_open(const char *fname, const char *modestr)
7607{
7608 return rb_file_open_internal(io_alloc(rb_cFile), rb_str_new_cstr(fname), modestr);
7609}
7610
7611#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7612static struct pipe_list {
7613 rb_io_t *fptr;
7614 struct pipe_list *next;
7615} *pipe_list;
7616
7617static void
7618pipe_add_fptr(rb_io_t *fptr)
7619{
7620 struct pipe_list *list;
7621
7622 list = ALLOC(struct pipe_list);
7623 list->fptr = fptr;
7624 list->next = pipe_list;
7625 pipe_list = list;
7626}
7627
7628static void
7629pipe_del_fptr(rb_io_t *fptr)
7630{
7631 struct pipe_list **prev = &pipe_list;
7632 struct pipe_list *tmp;
7633
7634 while ((tmp = *prev) != 0) {
7635 if (tmp->fptr == fptr) {
7636 *prev = tmp->next;
7637 free(tmp);
7638 return;
7639 }
7640 prev = &tmp->next;
7641 }
7642}
7643
7644#if defined (_WIN32) || defined(__CYGWIN__)
7645static void
7646pipe_atexit(void)
7647{
7648 struct pipe_list *list = pipe_list;
7649 struct pipe_list *tmp;
7650
7651 /* The CRT calls this on whichever thread calls ExitProcess, which can be
7652 * one Ruby does not know, e.g. the console control handler on Ctrl+Break. */
7653 if (!rb_current_execution_context(false)) return;
7654
7655 while (list) {
7656 tmp = list->next;
7657 rb_io_fptr_finalize(list->fptr);
7658 list = tmp;
7659 }
7660}
7661#endif
7662
7663static void
7664pipe_finalize(rb_io_t *fptr, int noraise)
7665{
7666#if !defined(HAVE_WORKING_FORK) && !defined(_WIN32)
7667 int status = 0;
7668 if (fptr->stdio_file) {
7669 status = pclose(fptr->stdio_file);
7670 }
7671 fptr->fd = -1;
7672 fptr->stdio_file = 0;
7673 rb_last_status_set(status, fptr->pid);
7674#else
7675 fptr_finalize(fptr, noraise);
7676#endif
7677 pipe_del_fptr(fptr);
7678}
7679#endif
7680
7681static void
7682fptr_copy_finalizer(rb_io_t *fptr, const rb_io_t *orig)
7683{
7684#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7685 void (*const old_finalize)(struct rb_io*,int) = fptr->finalize;
7686
7687 if (old_finalize == orig->finalize) return;
7688#endif
7689
7690 fptr->finalize = orig->finalize;
7691
7692#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7693 if (old_finalize != pipe_finalize) {
7694 struct pipe_list *list;
7695 for (list = pipe_list; list; list = list->next) {
7696 if (list->fptr == fptr) break;
7697 }
7698 if (!list) pipe_add_fptr(fptr);
7699 }
7700 else {
7701 pipe_del_fptr(fptr);
7702 }
7703#endif
7704}
7705
7706void
7708{
7710 fptr->mode |= FMODE_SYNC;
7711}
7712
7713
7714int
7715rb_pipe(int *pipes)
7716{
7717 int ret;
7718 TRY_WITH_GC((ret = rb_cloexec_pipe(pipes)) >= 0);
7719 if (ret == 0) {
7720 rb_update_max_fd(pipes[0]);
7721 rb_update_max_fd(pipes[1]);
7722 }
7723 return ret;
7724}
7725
7726#ifdef _WIN32
7727#define spawnv(mode, cmd, args) rb_w32_uaspawn((mode), (cmd), (args))
7728#define spawn(mode, cmd) rb_w32_uspawn((mode), (cmd), 0)
7729#endif
7730
7731#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7732struct popen_arg {
7733 VALUE execarg_obj;
7734 struct rb_execarg *eargp;
7735 int modef;
7736 int pair[2];
7737 int write_pair[2];
7738};
7739#endif
7740
7741#ifdef HAVE_WORKING_FORK
7742# ifndef __EMSCRIPTEN__
7743static void
7744popen_redirect(struct popen_arg *p)
7745{
7746 if ((p->modef & FMODE_READABLE) && (p->modef & FMODE_WRITABLE)) {
7747 close(p->write_pair[1]);
7748 if (p->write_pair[0] != 0) {
7749 dup2(p->write_pair[0], 0);
7750 close(p->write_pair[0]);
7751 }
7752 close(p->pair[0]);
7753 if (p->pair[1] != 1) {
7754 dup2(p->pair[1], 1);
7755 close(p->pair[1]);
7756 }
7757 }
7758 else if (p->modef & FMODE_READABLE) {
7759 close(p->pair[0]);
7760 if (p->pair[1] != 1) {
7761 dup2(p->pair[1], 1);
7762 close(p->pair[1]);
7763 }
7764 }
7765 else {
7766 close(p->pair[1]);
7767 if (p->pair[0] != 0) {
7768 dup2(p->pair[0], 0);
7769 close(p->pair[0]);
7770 }
7771 }
7772}
7773# endif
7774
7775#if defined(__linux__)
7776/* Linux /proc/self/status contains a line: "FDSize:\t<nnn>\n"
7777 * Since /proc may not be available, linux_get_maxfd is just a hint.
7778 * This function, linux_get_maxfd, must be async-signal-safe.
7779 * I.e. opendir() is not usable.
7780 *
7781 * Note that memchr() and memcmp is *not* async-signal-safe in POSIX.
7782 * However they are easy to re-implement in async-signal-safe manner.
7783 * (Also note that there is missing/memcmp.c.)
7784 */
7785static int
7786linux_get_maxfd(void)
7787{
7788 int fd;
7789 char buf[4096], *p, *np, *e;
7790 ssize_t ss;
7791 fd = rb_cloexec_open("/proc/self/status", O_RDONLY|O_NOCTTY, 0);
7792 if (fd < 0) return fd;
7793 ss = read(fd, buf, sizeof(buf));
7794 if (ss < 0) goto err;
7795 p = buf;
7796 e = buf + ss;
7797 while ((int)sizeof("FDSize:\t0\n")-1 <= e-p &&
7798 (np = memchr(p, '\n', e-p)) != NULL) {
7799 if (memcmp(p, "FDSize:", sizeof("FDSize:")-1) == 0) {
7800 int fdsize;
7801 p += sizeof("FDSize:")-1;
7802 *np = '\0';
7803 fdsize = (int)ruby_strtoul(p, (char **)NULL, 10);
7804 close(fd);
7805 return fdsize;
7806 }
7807 p = np+1;
7808 }
7809 /* fall through */
7810
7811 err:
7812 close(fd);
7813 return (int)ss;
7814}
7815#endif
7816
7817/* This function should be async-signal-safe. */
7818void
7819rb_close_before_exec(int lowfd, int maxhint, VALUE noclose_fds)
7820{
7821#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
7822 int fd, ret;
7823 int max = (int)max_file_descriptor;
7824# ifdef F_MAXFD
7825 /* F_MAXFD is available since NetBSD 2.0. */
7826 ret = fcntl(0, F_MAXFD); /* async-signal-safe */
7827 if (ret != -1)
7828 maxhint = max = ret;
7829# elif defined(__linux__)
7830 ret = linux_get_maxfd();
7831 if (maxhint < ret)
7832 maxhint = ret;
7833 /* maxhint = max = ret; if (ret == -1) abort(); // test */
7834# endif
7835 if (max < maxhint)
7836 max = maxhint;
7837 for (fd = lowfd; fd <= max; fd++) {
7838 if (!NIL_P(noclose_fds) &&
7839 RTEST(rb_hash_lookup(noclose_fds, INT2FIX(fd)))) /* async-signal-safe */
7840 continue;
7841 ret = fcntl(fd, F_GETFD); /* async-signal-safe */
7842 if (ret != -1 && !(ret & FD_CLOEXEC)) {
7843 fcntl(fd, F_SETFD, ret|FD_CLOEXEC); /* async-signal-safe */
7844 }
7845# define CONTIGUOUS_CLOSED_FDS 20
7846 if (ret != -1) {
7847 if (max < fd + CONTIGUOUS_CLOSED_FDS)
7848 max = fd + CONTIGUOUS_CLOSED_FDS;
7849 }
7850 }
7851#endif
7852}
7853
7854# ifndef __EMSCRIPTEN__
7855static int
7856popen_exec(void *pp, char *errmsg, size_t errmsg_len)
7857{
7858 struct popen_arg *p = (struct popen_arg*)pp;
7859
7860 return rb_exec_async_signal_safe(p->eargp, errmsg, errmsg_len);
7861}
7862# endif
7863#endif
7864
7865#if (defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)) && !defined __EMSCRIPTEN__
7866static VALUE
7867rb_execarg_fixup_v(VALUE execarg_obj)
7868{
7869 rb_execarg_parent_start(execarg_obj);
7870 return Qnil;
7871}
7872#else
7873char *rb_execarg_commandline(const struct rb_execarg *eargp, VALUE *prog);
7874#endif
7875
7876#ifndef __EMSCRIPTEN__
7877static VALUE
7878pipe_open(VALUE execarg_obj, const char *modestr, enum rb_io_mode fmode,
7879 const struct rb_io_encoding *convconfig)
7880{
7881 struct rb_execarg *eargp = NIL_P(execarg_obj) ? NULL : rb_execarg_get(execarg_obj);
7882 VALUE prog = eargp ? (eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name) : Qfalse ;
7883 rb_pid_t pid = 0;
7884 rb_io_t *fptr;
7885 VALUE port;
7886 rb_io_t *write_fptr;
7887 VALUE write_port;
7888#if defined(HAVE_WORKING_FORK)
7889 int status;
7890 char errmsg[80] = { '\0' };
7891#endif
7892#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7893 int state;
7894 struct popen_arg arg;
7895#endif
7896 int e = 0;
7897#if defined(HAVE_SPAWNV)
7898# define DO_SPAWN(cmd, args) ((args) ? \
7899 spawnv(P_NOWAIT, (cmd), (args)) : \
7900 spawn(P_NOWAIT, (cmd)))
7901# if !defined(HAVE_WORKING_FORK)
7902 char **args = NULL;
7903# endif
7904#endif
7905#if !defined(HAVE_WORKING_FORK)
7906 struct rb_execarg sarg, *sargp = &sarg;
7907#endif
7908 FILE *fp = 0;
7909 int fd = -1;
7910 int write_fd = -1;
7911#if !defined(HAVE_WORKING_FORK)
7912 const char *cmd = 0;
7913
7914 if (prog)
7915 cmd = StringValueCStr(prog);
7916#endif
7917
7918#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7919 arg.execarg_obj = execarg_obj;
7920 arg.eargp = eargp;
7921 arg.modef = fmode;
7922 arg.pair[0] = arg.pair[1] = -1;
7923 arg.write_pair[0] = arg.write_pair[1] = -1;
7924# if !defined(HAVE_WORKING_FORK)
7925 if (eargp && !eargp->use_shell) {
7926 args = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
7927 }
7928# endif
7929 switch (fmode & (FMODE_READABLE|FMODE_WRITABLE)) {
7931 if (rb_pipe(arg.write_pair) < 0)
7932 rb_sys_fail_str(prog);
7933 if (rb_pipe(arg.pair) < 0) {
7934 e = errno;
7935 close(arg.write_pair[0]);
7936 close(arg.write_pair[1]);
7937 rb_syserr_fail_str(e, prog);
7938 }
7939 if (eargp) {
7940 rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.write_pair[0]));
7941 rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
7942 }
7943 break;
7944 case FMODE_READABLE:
7945 if (rb_pipe(arg.pair) < 0)
7946 rb_sys_fail_str(prog);
7947 if (eargp)
7948 rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
7949 break;
7950 case FMODE_WRITABLE:
7951 if (rb_pipe(arg.pair) < 0)
7952 rb_sys_fail_str(prog);
7953 if (eargp)
7954 rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.pair[0]));
7955 break;
7956 default:
7957 rb_sys_fail_str(prog);
7958 }
7959 if (!NIL_P(execarg_obj)) {
7960 rb_protect(rb_execarg_fixup_v, execarg_obj, &state);
7961 if (state) {
7962 if (0 <= arg.write_pair[0]) close(arg.write_pair[0]);
7963 if (0 <= arg.write_pair[1]) close(arg.write_pair[1]);
7964 if (0 <= arg.pair[0]) close(arg.pair[0]);
7965 if (0 <= arg.pair[1]) close(arg.pair[1]);
7966 rb_execarg_parent_end(execarg_obj);
7967 rb_jump_tag(state);
7968 }
7969
7970# if defined(HAVE_WORKING_FORK)
7971 pid = rb_fork_async_signal_safe(&status, popen_exec, &arg, arg.eargp->redirect_fds, errmsg, sizeof(errmsg));
7972# else
7973 rb_execarg_run_options(eargp, sargp, NULL, 0);
7974 while ((pid = DO_SPAWN(cmd, args)) < 0) {
7975 /* exec failed */
7976 switch (e = errno) {
7977 case EAGAIN:
7978# if EWOULDBLOCK != EAGAIN
7979 case EWOULDBLOCK:
7980# endif
7981 rb_thread_sleep(1);
7982 continue;
7983 }
7984 break;
7985 }
7986 if (eargp)
7987 rb_execarg_run_options(sargp, NULL, NULL, 0);
7988# endif
7989 rb_execarg_parent_end(execarg_obj);
7990 }
7991 else {
7992# if defined(HAVE_WORKING_FORK)
7993 pid = rb_call_proc__fork();
7994 if (pid == 0) { /* child */
7995 popen_redirect(&arg);
7996 rb_io_synchronized(RFILE(orig_stdout)->fptr);
7997 rb_io_synchronized(RFILE(orig_stderr)->fptr);
7998 return Qnil;
7999 }
8000# else
8001 rb_notimplement();
8002# endif
8003 }
8004
8005 /* parent */
8006 if (pid < 0) {
8007# if defined(HAVE_WORKING_FORK)
8008 e = errno;
8009# endif
8010 close(arg.pair[0]);
8011 close(arg.pair[1]);
8013 close(arg.write_pair[0]);
8014 close(arg.write_pair[1]);
8015 }
8016# if defined(HAVE_WORKING_FORK)
8017 if (errmsg[0])
8018 rb_syserr_fail(e, errmsg);
8019# endif
8020 rb_syserr_fail_str(e, prog);
8021 }
8022 if ((fmode & FMODE_READABLE) && (fmode & FMODE_WRITABLE)) {
8023 close(arg.pair[1]);
8024 fd = arg.pair[0];
8025 close(arg.write_pair[0]);
8026 write_fd = arg.write_pair[1];
8027 }
8028 else if (fmode & FMODE_READABLE) {
8029 close(arg.pair[1]);
8030 fd = arg.pair[0];
8031 }
8032 else {
8033 close(arg.pair[0]);
8034 fd = arg.pair[1];
8035 }
8036#else
8037 cmd = rb_execarg_commandline(eargp, &prog);
8038 if (!NIL_P(execarg_obj)) {
8039 rb_execarg_parent_start(execarg_obj);
8040 rb_execarg_run_options(eargp, sargp, NULL, 0);
8041 }
8042 fp = popen(cmd, modestr);
8043 e = errno;
8044 if (eargp) {
8045 rb_execarg_parent_end(execarg_obj);
8046 rb_execarg_run_options(sargp, NULL, NULL, 0);
8047 }
8048 if (!fp) rb_syserr_fail_path(e, prog);
8049 fd = fileno(fp);
8050#endif
8051
8052 port = io_alloc(rb_cIO);
8053 MakeOpenFile(port, fptr);
8054 fptr->fd = fd;
8055 fptr->stdio_file = fp;
8056 fptr->mode = fmode | FMODE_SYNC|FMODE_DUPLEX;
8057 if (convconfig) {
8058 fptr->encs = *convconfig;
8059#if RUBY_CRLF_ENVIRONMENT
8062 }
8063#endif
8064 }
8065 else {
8066 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
8068 }
8069#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
8070 if (NEED_NEWLINE_DECORATOR_ON_WRITE(fptr)) {
8071 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
8072 }
8073#endif
8074 }
8075 fptr->pid = pid;
8076
8077 if (0 <= write_fd) {
8078 write_port = io_alloc(rb_cIO);
8079 MakeOpenFile(write_port, write_fptr);
8080 write_fptr->fd = write_fd;
8081 write_fptr->mode = (fmode & ~FMODE_READABLE)| FMODE_SYNC|FMODE_DUPLEX;
8082 fptr->mode &= ~FMODE_WRITABLE;
8083 fptr->tied_io_for_writing = write_port;
8084 rb_ivar_set(port, rb_intern("@tied_io_for_writing"), write_port);
8085 }
8086
8087#if defined (__CYGWIN__) || !defined(HAVE_WORKING_FORK)
8088 fptr->finalize = pipe_finalize;
8089 pipe_add_fptr(fptr);
8090#endif
8091 return port;
8092}
8093#else
8094static VALUE
8095pipe_open(VALUE execarg_obj, const char *modestr, enum rb_io_mode fmode,
8096 const struct rb_io_encoding *convconfig)
8097{
8098 rb_raise(rb_eNotImpError, "popen() is not available");
8099}
8100#endif
8101
8102static int
8103is_popen_fork(VALUE prog)
8104{
8105 if (RSTRING_LEN(prog) == 1 && RSTRING_PTR(prog)[0] == '-') {
8106#if !defined(HAVE_WORKING_FORK)
8107 rb_raise(rb_eNotImpError,
8108 "fork() function is unimplemented on this machine");
8109#else
8110 return TRUE;
8111#endif
8112 }
8113 return FALSE;
8114}
8115
8116static VALUE
8117pipe_open_s(VALUE prog, const char *modestr, enum rb_io_mode fmode,
8118 const struct rb_io_encoding *convconfig)
8119{
8120 int argc = 1;
8121 VALUE *argv = &prog;
8122 VALUE execarg_obj = Qnil;
8123
8124 if (!is_popen_fork(prog))
8125 execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
8126 return pipe_open(execarg_obj, modestr, fmode, convconfig);
8127}
8128
8129static VALUE
8130pipe_close(VALUE io)
8131{
8132 rb_io_t *fptr = io_close_fptr(io);
8133 if (fptr) {
8134 fptr_waitpid(fptr, rb_thread_to_be_killed(rb_thread_current()));
8135 }
8136 return Qnil;
8137}
8138
8139static VALUE popen_finish(VALUE port, VALUE klass);
8140
8141/*
8142 * call-seq:
8143 * IO.popen(env = {}, cmd, mode = 'r', **opts) -> io
8144 * IO.popen(env = {}, cmd, mode = 'r', **opts) {|io| ... } -> object
8145 *
8146 * Executes the given command +cmd+ as a subprocess
8147 * whose $stdin and $stdout are connected to a new stream +io+.
8148 *
8149 * This method has potential security vulnerabilities if called with untrusted input;
8150 * see {Command Injection}[rdoc-ref:security/command_injection.rdoc].
8151 *
8152 * If no block is given, returns the new stream,
8153 * which depending on given +mode+ may be open for reading, writing, or both.
8154 * The stream should be explicitly closed (eventually) to avoid resource leaks.
8155 *
8156 * If a block is given, the stream is passed to the block
8157 * (again, open for reading, writing, or both);
8158 * when the block exits, the stream is closed,
8159 * the block's value is returned,
8160 * and the global variable <tt>$?</tt> is set to the child's exit status.
8161 *
8162 * Optional argument +mode+ may be any valid \IO mode.
8163 * See {Access Modes}[rdoc-ref:File@Access+Modes].
8164 *
8165 * Required argument +cmd+ determines which of the following occurs:
8166 *
8167 * - The process forks.
8168 * - A specified program runs in a shell.
8169 * - A specified program runs with specified arguments.
8170 * - A specified program runs with specified arguments and a specified +argv0+.
8171 *
8172 * Each of these is detailed below.
8173 *
8174 * The optional hash argument +env+ specifies name/value pairs that are to be added
8175 * to the environment variables for the subprocess:
8176 *
8177 * IO.popen({'FOO' => 'bar'}, 'ruby', 'r+') do |pipe|
8178 * pipe.puts 'puts ENV["FOO"]'
8179 * pipe.close_write
8180 * pipe.gets
8181 * end => "bar\n"
8182 *
8183 * Optional keyword arguments +opts+ specify:
8184 *
8185 * - {Open options}[rdoc-ref:IO@Open+Options].
8186 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
8187 * - Options for Kernel#spawn.
8188 *
8189 * <b>Forked Process</b>
8190 *
8191 * When argument +cmd+ is the 1-character string <tt>'-'</tt>, causes the process to fork:
8192 * IO.popen('-') do |pipe|
8193 * if pipe
8194 * $stderr.puts "In parent, child pid is #{pipe.pid}\n"
8195 * else
8196 * $stderr.puts "In child, pid is #{$$}\n"
8197 * end
8198 * end
8199 *
8200 * Output:
8201 *
8202 * In parent, child pid is 26253
8203 * In child, pid is 26253
8204 *
8205 * Note that this is not supported on all platforms.
8206 *
8207 * <b>Shell Subprocess</b>
8208 *
8209 * When argument +cmd+ is a single string (but not <tt>'-'</tt>),
8210 * the program named +cmd+ is run as a shell command:
8211 *
8212 * IO.popen('uname') do |pipe|
8213 * pipe.readlines
8214 * end
8215 *
8216 * Output:
8217 *
8218 * ["Linux\n"]
8219 *
8220 * Another example:
8221 *
8222 * IO.popen('/bin/sh', 'r+') do |pipe|
8223 * pipe.puts('ls')
8224 * pipe.close_write
8225 * $stderr.puts pipe.readlines.size
8226 * end
8227 *
8228 * Output:
8229 *
8230 * 213
8231 *
8232 * <b>Program Subprocess</b>
8233 *
8234 * When argument +cmd+ is an array of strings,
8235 * the program named <tt>cmd[0]</tt> is run with all elements of +cmd+ as its arguments:
8236 *
8237 * IO.popen(['du', '..', '.']) do |pipe|
8238 * $stderr.puts pipe.readlines.size
8239 * end
8240 *
8241 * Output:
8242 *
8243 * 1111
8244 *
8245 * <b>Program Subprocess with <tt>argv0</tt></b>
8246 *
8247 * When argument +cmd+ is an array whose first element is a 2-element string array
8248 * and whose remaining elements (if any) are strings:
8249 *
8250 * - <tt>cmd[0][0]</tt> (the first string in the nested array) is the name of a program that is run.
8251 * - <tt>cmd[0][1]</tt> (the second string in the nested array) is set as the program's <tt>argv[0]</tt>.
8252 * - <tt>cmd[1..-1]</tt> (the strings in the outer array) are the program's arguments.
8253 *
8254 * Example (sets <tt>$0</tt> to 'foo'):
8255 *
8256 * IO.popen([['/bin/sh', 'foo'], '-c', 'echo $0']).read # => "foo\n"
8257 *
8258 * <b>Some Special Examples</b>
8259 *
8260 * # Set IO encoding.
8261 * IO.popen("nkf -e filename", :external_encoding=>"EUC-JP") {|nkf_io|
8262 * euc_jp_string = nkf_io.read
8263 * }
8264 *
8265 * # Merge standard output and standard error using Kernel#spawn option. See Kernel#spawn.
8266 * IO.popen(["ls", "/", :err=>[:child, :out]]) do |io|
8267 * ls_result_with_error = io.read
8268 * end
8269 *
8270 * # Use mixture of spawn options and IO options.
8271 * IO.popen(["ls", "/"], :err=>[:child, :out]) do |io|
8272 * ls_result_with_error = io.read
8273 * end
8274 *
8275 * f = IO.popen("uname")
8276 * p f.readlines
8277 * f.close
8278 * puts "Parent is #{Process.pid}"
8279 * IO.popen("date") {|f| puts f.gets }
8280 * IO.popen("-") {|f| $stderr.puts "#{Process.pid} is here, f is #{f.inspect}"}
8281 * p $?
8282 * IO.popen(%w"sed -e s|^|<foo>| -e s&$&;zot;&", "r+") {|f|
8283 * f.puts "bar"; f.close_write; puts f.gets
8284 * }
8285 *
8286 * Output (from last section):
8287 *
8288 * ["Linux\n"]
8289 * Parent is 21346
8290 * Thu Jan 15 22:41:19 JST 2009
8291 * 21346 is here, f is #<IO:fd 3>
8292 * 21352 is here, f is nil
8293 * #<Process::Status: pid 21352 exit 0>
8294 * <foo>bar;zot;
8295 *
8296 * Raises exceptions that IO.pipe and Kernel.spawn raise.
8297 *
8298 */
8299
8300static VALUE
8301rb_io_s_popen(int argc, VALUE *argv, VALUE klass)
8302{
8303 VALUE pname, pmode = Qnil, opt = Qnil, env = Qnil;
8304
8305 if (argc > 1 && !NIL_P(opt = rb_check_hash_type(argv[argc-1]))) --argc;
8306 if (argc > 1 && !NIL_P(env = rb_check_hash_type(argv[0]))) --argc, ++argv;
8307 switch (argc) {
8308 case 2:
8309 pmode = argv[1];
8310 case 1:
8311 pname = argv[0];
8312 break;
8313 default:
8314 {
8315 int ex = !NIL_P(opt);
8316 rb_error_arity(argc + ex, 1 + ex, 2 + ex);
8317 }
8318 }
8319 return popen_finish(rb_io_popen(pname, pmode, env, opt), klass);
8320}
8321
8322VALUE
8323rb_io_popen(VALUE pname, VALUE pmode, VALUE env, VALUE opt)
8324{
8325 const char *modestr;
8326 VALUE tmp, execarg_obj = Qnil;
8327 int oflags;
8328 enum rb_io_mode fmode;
8329 struct rb_io_encoding convconfig;
8330
8331 tmp = rb_check_array_type(pname);
8332 if (!NIL_P(tmp)) {
8333 long len = RARRAY_LEN(tmp);
8334#if SIZEOF_LONG > SIZEOF_INT
8335 if (len > INT_MAX) {
8336 rb_raise(rb_eArgError, "too many arguments");
8337 }
8338#endif
8339 execarg_obj = rb_execarg_new((int)len, RARRAY_CONST_PTR(tmp), FALSE, FALSE);
8340 RB_GC_GUARD(tmp);
8341 }
8342 else {
8343 StringValue(pname);
8344 execarg_obj = Qnil;
8345 if (!is_popen_fork(pname))
8346 execarg_obj = rb_execarg_new(1, &pname, TRUE, FALSE);
8347 }
8348 if (!NIL_P(execarg_obj)) {
8349 if (!NIL_P(opt))
8350 opt = rb_execarg_extract_options(execarg_obj, opt);
8351 if (!NIL_P(env))
8352 rb_execarg_setenv(execarg_obj, env);
8353 }
8354 rb_io_extract_modeenc(&pmode, 0, opt, &oflags, &fmode, &convconfig);
8355 modestr = rb_io_oflags_modestr(oflags);
8356
8357 return pipe_open(execarg_obj, modestr, fmode, &convconfig);
8358}
8359
8360static VALUE
8361popen_finish(VALUE port, VALUE klass)
8362{
8363 if (NIL_P(port)) {
8364 /* child */
8365 if (rb_block_given_p()) {
8366 rb_protect(rb_yield, Qnil, NULL);
8367 rb_io_flush(rb_ractor_stdout());
8368 rb_io_flush(rb_ractor_stderr());
8369 _exit(EXIT_SUCCESS);
8370 }
8371 return Qnil;
8372 }
8373 RBASIC_SET_CLASS(port, klass);
8374 if (rb_block_given_p()) {
8375 return rb_ensure(rb_yield, port, pipe_close, port);
8376 }
8377 return port;
8378}
8379
8380#if defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)
8381struct popen_writer_arg {
8382 char *const *argv;
8383 struct popen_arg popen;
8384};
8385
8386static int
8387exec_popen_writer(void *arg, char *errmsg, size_t buflen)
8388{
8389 struct popen_writer_arg *pw = arg;
8390 pw->popen.modef = FMODE_WRITABLE;
8391 popen_redirect(&pw->popen);
8392 execv(pw->argv[0], pw->argv);
8393 strlcpy(errmsg, strerror(errno), buflen);
8394 return -1;
8395}
8396#endif
8397
8398FILE *
8399ruby_popen_writer(char *const *argv, rb_pid_t *pid)
8400{
8401#if (defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)) || defined(_WIN32)
8402# ifdef HAVE_WORKING_FORK
8403 struct popen_writer_arg pw;
8404 int *const write_pair = pw.popen.pair;
8405# else
8406 int write_pair[2];
8407# endif
8408
8409 *pid = -1;
8410 if (cloexec_pipe(write_pair, 0, false) == 0) {
8411# ifdef HAVE_WORKING_FORK
8412 pw.argv = argv;
8413 int status;
8414 char errmsg[80] = {'\0'};
8415 *pid = rb_fork_async_signal_safe(&status, exec_popen_writer, &pw, Qnil, errmsg, sizeof(errmsg));
8416# else
8417 *pid = rb_w32_uspawn_process(P_NOWAIT, argv[0], argv, write_pair[0], -1, -1, 0);
8418 const char *errmsg = (*pid < 0) ? strerror(errno) : NULL;
8419# endif
8420 close(write_pair[0]);
8421 if (*pid < 0) {
8422 close(write_pair[1]);
8423 fprintf(stderr, "ruby_popen_writer(%s): %s\n", argv[0], errmsg);
8424 }
8425 else {
8426 return fdopen(write_pair[1], "w");
8427 }
8428 }
8429#endif
8430 return NULL;
8431}
8432
8433static VALUE
8434rb_open_file(VALUE io, VALUE fname, VALUE vmode, VALUE vperm, VALUE opt)
8435{
8436 int oflags;
8437 enum rb_io_mode fmode;
8438 struct rb_io_encoding convconfig;
8439 mode_t perm;
8440
8441 FilePathValue(fname);
8442
8443 rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, &convconfig);
8444 perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
8445
8446 rb_file_open_generic(io, fname, oflags, fmode, &convconfig, perm);
8447
8448 return io;
8449}
8450
8451/*
8452 * Document-method: File::open
8453 *
8454 * :markup: markdown
8455 *
8456 * call-seq:
8457 * File.open(path, mode = 'r', permissions = 0666, **options) -> file
8458 * File.open(path, mode = 'r', permissions = 0666, **options) {|file| ... } -> object
8459 *
8460 * Creates a new \File object via File.new with the given arguments.
8461 *
8462 * With no block given, returns the \File object.
8463 *
8464 * With a block given, calls the block with the \File object,
8465 * closes the \File object, and returns the block's value:
8466 *
8467 * ```ruby
8468 * File.open('doc/maintainers.md') {|file| file.size } # => 14900
8469 * ```
8470 *
8471 * Note that the \File object is automatically closed
8472 * even if the block raises an exception.
8473 */
8474
8475/*
8476 * Document-method: IO::open
8477 *
8478 * :markup: markdown
8479 *
8480 * call-seq:
8481 * IO.open(fd, mode = 'r', **options) -> io
8482 * IO.open(fd, mode = 'r', **options) {|io| ... } -> object
8483 *
8484 * Creates a new \IO object via IO.new with the given arguments.
8485 *
8486 * With no block given, returns the \IO object.
8487 *
8488 * With a block given, calls the block with the \IO object,
8489 * closes the \IO object, and returns the block’s value:
8490 *
8491 * ```ruby
8492 * fd = File.sysopen('doc/maintainers.md') # => 6
8493 * IO.open(fd) {|io| io.read.size } # => 14897
8494 * ```
8495 */
8496
8497static VALUE
8498rb_io_s_open(int argc, VALUE *argv, VALUE klass)
8499{
8501
8502 if (rb_block_given_p()) {
8503 return rb_ensure(rb_yield, io, io_close, io);
8504 }
8505
8506 return io;
8507}
8508
8509/*
8510 * call-seq:
8511 * IO.sysopen(path, mode = 'r', perm = 0666) -> integer
8512 *
8513 * Opens the file at the given path with the given mode and permissions;
8514 * returns the integer file descriptor.
8515 *
8516 * If the file is to be readable, it must exist;
8517 * if the file is to be writable and does not exist,
8518 * it is created with the given permissions:
8519 *
8520 * File.write('t.tmp', '') # => 0
8521 * IO.sysopen('t.tmp') # => 8
8522 * IO.sysopen('t.tmp', 'w') # => 9
8523 *
8524 *
8525 */
8526
8527static VALUE
8528rb_io_s_sysopen(int argc, VALUE *argv, VALUE _)
8529{
8530 VALUE fname, vmode, vperm;
8531 VALUE intmode;
8532 int oflags, fd;
8533 mode_t perm;
8534
8535 rb_scan_args(argc, argv, "12", &fname, &vmode, &vperm);
8536 FilePathValue(fname);
8537
8538 if (NIL_P(vmode))
8539 oflags = O_RDONLY;
8540 else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int")))
8541 oflags = NUM2INT(intmode);
8542 else {
8543 StringValue(vmode);
8544 oflags = rb_io_modestr_oflags(StringValueCStr(vmode));
8545 }
8546 if (NIL_P(vperm)) perm = 0666;
8547 else perm = NUM2MODET(vperm);
8548
8549 RB_GC_GUARD(fname) = rb_str_new4(fname);
8550 fd = rb_sysopen(fname, oflags, perm);
8551 return INT2NUM(fd);
8552}
8553
8554/*
8555 * call-seq:
8556 * open(path, mode = 'r', perm = 0666, **opts) -> io or nil
8557 * open(path, mode = 'r', perm = 0666, **opts) {|io| ... } -> obj
8558 *
8559 * Creates an IO object connected to the given file.
8560 *
8561 * With no block given, file stream is returned:
8562 *
8563 * open('t.txt') # => #<File:t.txt>
8564 *
8565 * With a block given, calls the block with the open file stream,
8566 * then closes the stream:
8567 *
8568 * open('t.txt') {|f| p f } # => #<File:t.txt (closed)>
8569 *
8570 * Output:
8571 *
8572 * #<File:t.txt>
8573 *
8574 * See File.open for details.
8575 *
8576 */
8577
8578static VALUE
8579rb_f_open(int argc, VALUE *argv, VALUE _)
8580{
8581 ID to_open = 0;
8582 int redirect = FALSE;
8583
8584 if (argc >= 1) {
8585 CONST_ID(to_open, "to_open");
8586 if (rb_respond_to(argv[0], to_open)) {
8587 redirect = TRUE;
8588 }
8589 else {
8590 VALUE tmp = argv[0];
8591 FilePathValue(tmp);
8592 if (NIL_P(tmp)) {
8593 redirect = TRUE;
8594 }
8595 else {
8596 argv[0] = tmp;
8597 }
8598 }
8599 }
8600 if (redirect) {
8601 VALUE io = rb_funcallv_kw(argv[0], to_open, argc-1, argv+1, RB_PASS_CALLED_KEYWORDS);
8602
8603 if (rb_block_given_p()) {
8604 return rb_ensure(rb_yield, io, io_close, io);
8605 }
8606 return io;
8607 }
8608 return rb_io_s_open(argc, argv, rb_cFile);
8609}
8610
8611static VALUE
8612rb_io_open_generic(VALUE klass, VALUE filename, int oflags, enum rb_io_mode fmode,
8613 const struct rb_io_encoding *convconfig, mode_t perm)
8614{
8615 return rb_file_open_generic(io_alloc(klass), filename,
8616 oflags, fmode, convconfig, perm);
8617}
8618
8619static VALUE
8620rb_io_open(VALUE io, VALUE filename, VALUE vmode, VALUE vperm, VALUE opt)
8621{
8622 int oflags;
8623 enum rb_io_mode fmode;
8624 struct rb_io_encoding convconfig;
8625 mode_t perm;
8626
8627 rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, &convconfig);
8628 perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
8629 return rb_io_open_generic(io, filename, oflags, fmode, &convconfig, perm);
8630}
8631
8632static VALUE
8633io_reopen(VALUE io, VALUE nfile)
8634{
8635 rb_io_t *fptr, *orig;
8636 int fd, fd2;
8637 rb_off_t pos = 0;
8638
8639 nfile = rb_io_get_io(nfile);
8640 GetOpenFile(io, fptr);
8641 GetOpenFile(nfile, orig);
8642
8643 if (fptr == orig) return io;
8644 if (RUBY_IO_EXTERNAL_P(fptr)) {
8645 if ((fptr->stdio_file == stdin && !(orig->mode & FMODE_READABLE)) ||
8646 (fptr->stdio_file == stdout && !(orig->mode & FMODE_WRITABLE)) ||
8647 (fptr->stdio_file == stderr && !(orig->mode & FMODE_WRITABLE))) {
8648 rb_raise(rb_eArgError,
8649 "%s can't change access mode from \"%s\" to \"%s\"",
8650 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
8651 rb_io_fmode_modestr(orig->mode));
8652 }
8653 }
8654 flush_before_seek(fptr, true);
8655 /* in flush_before_seek, clear_codeconv called only if rbuf is filled */
8656 clear_codeconv(fptr);
8657 if (orig->mode & FMODE_READABLE) {
8658 pos = io_tell(orig);
8659 }
8660 if (orig->mode & FMODE_WRITABLE) {
8661 if (io_fflush(orig) < 0)
8662 rb_sys_fail_on_write(fptr);
8663 }
8664
8665 /* copy rb_io_t structure */
8666 fptr->mode = orig->mode | (fptr->mode & FMODE_EXTERNAL);
8667 fptr->encs = orig->encs;
8668 fptr->pid = orig->pid;
8669 fptr->lineno = orig->lineno;
8670 if (RTEST(orig->pathv)) fptr->pathv = orig->pathv;
8671 else if (!RUBY_IO_EXTERNAL_P(fptr)) fptr->pathv = Qnil;
8672 fptr_copy_finalizer(fptr, orig);
8673
8674 fd = fptr->fd;
8675 fd2 = orig->fd;
8676 if (fd != fd2) {
8677 // Interrupt all usage of the old file descriptor:
8678 rb_thread_io_close_interrupt(fptr);
8679 rb_thread_io_close_wait(fptr);
8680
8681 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2 || !fptr->stdio_file) {
8682 /* need to keep FILE objects of stdin, stdout and stderr */
8683 if (rb_cloexec_dup2(fd2, fd) < 0)
8684 rb_sys_fail_path(orig->pathv);
8685 rb_update_max_fd(fd);
8686 }
8687 else {
8688 fclose(fptr->stdio_file);
8689 fptr->stdio_file = 0;
8690 fptr->fd = -1;
8691 if (rb_cloexec_dup2(fd2, fd) < 0)
8692 rb_sys_fail_path(orig->pathv);
8693 rb_update_max_fd(fd);
8694 fptr->fd = fd;
8695 }
8696
8697 if ((orig->mode & FMODE_READABLE) && pos >= 0) {
8698 if (io_seek(fptr, pos, SEEK_SET) < 0 && errno) {
8699 rb_sys_fail_path(fptr->pathv);
8700 }
8701 if (io_seek(orig, pos, SEEK_SET) < 0 && errno) {
8702 rb_sys_fail_path(orig->pathv);
8703 }
8704 }
8705 }
8706
8707 if (fptr->mode & FMODE_BINMODE) {
8708 rb_io_binmode(io);
8709 }
8710
8711 RBASIC_SET_CLASS(io, rb_obj_class(nfile));
8712 return io;
8713}
8714
8715#ifdef _WIN32
8716int rb_freopen(VALUE fname, const char *mode, FILE *fp);
8717#else
8718static int
8719rb_freopen(VALUE fname, const char *mode, FILE *fp)
8720{
8721 if (!freopen(RSTRING_PTR(fname), mode, fp)) {
8722 RB_GC_GUARD(fname);
8723 return errno;
8724 }
8725 return 0;
8726}
8727#endif
8728
8729/*
8730 * call-seq:
8731 * reopen(other_io) -> self
8732 * reopen(path, mode = 'r', **opts) -> self
8733 *
8734 * Reassociates the stream with another stream,
8735 * which may be of a different class.
8736 * This method may be used to redirect an existing stream
8737 * to a new destination.
8738 *
8739 * With argument +other_io+ given, reassociates with that stream:
8740 *
8741 * # Redirect $stdin from a file.
8742 * f = File.open('t.txt')
8743 * $stdin.reopen(f)
8744 * f.close
8745 *
8746 * # Redirect $stdout to a file.
8747 * f = File.open('t.tmp', 'w')
8748 * $stdout.reopen(f)
8749 * f.close
8750 *
8751 * With argument +path+ given, reassociates with a new stream to that file path:
8752 *
8753 * $stdin.reopen('t.txt')
8754 * $stdout.reopen('t.tmp', 'w')
8755 *
8756 * Optional keyword arguments +opts+ specify:
8757 *
8758 * - {Open Options}[rdoc-ref:IO@Open+Options].
8759 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
8760 *
8761 */
8762
8763static VALUE
8764rb_io_reopen(int argc, VALUE *argv, VALUE file)
8765{
8766 VALUE fname, nmode, opt;
8767 int oflags;
8768 rb_io_t *fptr;
8769
8770 if (rb_scan_args(argc, argv, "11:", &fname, &nmode, &opt) == 1) {
8771 VALUE tmp = rb_io_check_io(fname);
8772 if (!NIL_P(tmp)) {
8773 return io_reopen(file, tmp);
8774 }
8775 }
8776
8777 FilePathValue(fname);
8778 rb_io_taint_check(file);
8779 fptr = RFILE(file)->fptr;
8780 if (!fptr) {
8781 fptr = RFILE(file)->fptr = ZALLOC(rb_io_t);
8782 }
8783
8784 if (!NIL_P(nmode) || !NIL_P(opt)) {
8785 enum rb_io_mode fmode;
8786 struct rb_io_encoding convconfig;
8787
8788 rb_io_extract_modeenc(&nmode, 0, opt, &oflags, &fmode, &convconfig);
8789 if (RUBY_IO_EXTERNAL_P(fptr) &&
8790 ((fptr->mode & FMODE_READWRITE) & (fmode & FMODE_READWRITE)) !=
8791 (fptr->mode & FMODE_READWRITE)) {
8792 rb_raise(rb_eArgError,
8793 "%s can't change access mode from \"%s\" to \"%s\"",
8794 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
8795 rb_io_fmode_modestr(fmode));
8796 }
8797 fptr->mode = fmode;
8798 fptr->encs = convconfig;
8799 }
8800 else {
8801 oflags = rb_io_fmode_oflags(fptr->mode);
8802 }
8803
8804 fptr->pathv = fname;
8805 if (fptr->fd < 0) {
8806 fptr->fd = rb_sysopen(fptr->pathv, oflags, 0666);
8807 fptr->stdio_file = 0;
8808 return file;
8809 }
8810
8811 if (fptr->mode & FMODE_WRITABLE) {
8812 if (io_fflush(fptr) < 0)
8813 rb_sys_fail_on_write(fptr);
8814 }
8815 fptr->rbuf.off = fptr->rbuf.len = 0;
8816 clear_codeconv(fptr);
8817
8818 if (fptr->stdio_file) {
8819 int e = rb_freopen(rb_str_encode_ospath(fptr->pathv),
8820 rb_io_oflags_modestr(oflags),
8821 fptr->stdio_file);
8822 if (e) rb_syserr_fail_path(e, fptr->pathv);
8823 fptr->fd = fileno(fptr->stdio_file);
8824 rb_fd_fix_cloexec(fptr->fd);
8825#ifdef USE_SETVBUF
8826 if (setvbuf(fptr->stdio_file, NULL, _IOFBF, 0) != 0)
8827 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8828#endif
8829 if (fptr->stdio_file == stderr) {
8830 if (setvbuf(fptr->stdio_file, NULL, _IONBF, BUFSIZ) != 0)
8831 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8832 }
8833 else if (fptr->stdio_file == stdout && isatty(fptr->fd)) {
8834 if (setvbuf(fptr->stdio_file, NULL, _IOLBF, BUFSIZ) != 0)
8835 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8836 }
8837 }
8838 else {
8839 int tmpfd = rb_sysopen(fptr->pathv, oflags, 0666);
8840 int err = 0;
8841 if (rb_cloexec_dup2(tmpfd, fptr->fd) < 0)
8842 err = errno;
8843 (void)close(tmpfd);
8844 if (err) {
8845 rb_syserr_fail_path(err, fptr->pathv);
8846 }
8847 }
8848
8849 return file;
8850}
8851
8852/* :nodoc: */
8853static VALUE
8854rb_io_init_copy(VALUE dest, VALUE io)
8855{
8856 rb_io_t *fptr, *orig;
8857 int fd;
8858 VALUE write_io;
8859 rb_off_t pos;
8860
8861 io = rb_io_get_io(io);
8862 if (!OBJ_INIT_COPY(dest, io)) return dest;
8863 GetOpenFile(io, orig);
8864 MakeOpenFile(dest, fptr);
8865
8866 rb_io_flush(io);
8867
8868 /* copy rb_io_t structure */
8869 fptr->mode = orig->mode & ~FMODE_EXTERNAL;
8870 fptr->encs = orig->encs;
8871 fptr->pid = orig->pid;
8872 fptr->lineno = orig->lineno;
8873 fptr->timeout = orig->timeout;
8874
8875 ccan_list_head_init(&fptr->blocking_operations);
8876 fptr->closing_ec = NULL;
8877 fptr->wakeup_mutex = Qnil;
8878 fptr->fork_generation = GET_VM()->fork_gen;
8879
8880 if (!NIL_P(orig->pathv)) fptr->pathv = orig->pathv;
8881 fptr_copy_finalizer(fptr, orig);
8882
8883 fd = ruby_dup(orig->fd);
8884 fptr->fd = fd;
8885 pos = io_tell(orig);
8886 if (0 <= pos)
8887 io_seek(fptr, pos, SEEK_SET);
8888 if (fptr->mode & FMODE_BINMODE) {
8889 rb_io_binmode(dest);
8890 }
8891
8892 write_io = GetWriteIO(io);
8893 if (io != write_io) {
8894 write_io = rb_obj_dup(write_io);
8895 fptr->tied_io_for_writing = write_io;
8896 rb_ivar_set(dest, rb_intern("@tied_io_for_writing"), write_io);
8897 }
8898
8899 return dest;
8900}
8901
8902/*
8903 * call-seq:
8904 * printf(format_string, *objects) -> nil
8905 *
8906 * Formats and writes +objects+ to the stream.
8907 *
8908 * For details on +format_string+, see
8909 * {Format Specifications}[rdoc-ref:language/format_specifications.rdoc].
8910 *
8911 */
8912
8913VALUE
8914rb_io_printf(int argc, const VALUE *argv, VALUE out)
8915{
8916 rb_io_write(out, rb_f_sprintf(argc, argv));
8917 return Qnil;
8918}
8919
8920/*
8921 * call-seq:
8922 * printf(format_string, *objects) -> nil
8923 * printf(io, format_string, *objects) -> nil
8924 *
8925 * Equivalent to:
8926 *
8927 * io.write(sprintf(format_string, *objects))
8928 *
8929 * For details on +format_string+, see
8930 * {Format Specifications}[rdoc-ref:language/format_specifications.rdoc].
8931 *
8932 * With the single argument +format_string+, formats +objects+ into the string,
8933 * then writes the formatted string to $stdout:
8934 *
8935 * printf('%4.4d %10s %2.2f', 24, 24, 24.0)
8936 *
8937 * Output (on $stdout):
8938 *
8939 * 0024 24 24.00#
8940 *
8941 * With arguments +io+ and +format_string+, formats +objects+ into the string,
8942 * then writes the formatted string to +io+:
8943 *
8944 * printf($stderr, '%4.4d %10s %2.2f', 24, 24, 24.0)
8945 *
8946 * Output (on $stderr):
8947 *
8948 * 0024 24 24.00# => nil
8949 *
8950 * With no arguments, does nothing.
8951 *
8952 */
8953
8954static VALUE
8955rb_f_printf(int argc, VALUE *argv, VALUE _)
8956{
8957 VALUE out;
8958
8959 if (argc == 0) return Qnil;
8960 if (RB_TYPE_P(argv[0], T_STRING)) {
8961 out = rb_ractor_stdout();
8962 }
8963 else {
8964 out = argv[0];
8965 argv++;
8966 argc--;
8967 }
8968 rb_io_write(out, rb_f_sprintf(argc, argv));
8969
8970 return Qnil;
8971}
8972
8973extern void rb_deprecated_str_setter(VALUE val, ID id, VALUE *var);
8974
8975static void
8976deprecated_rs_setter(VALUE val, ID id, VALUE *var)
8977{
8978 rb_deprecated_str_setter(val, id, &val);
8979 if (!NIL_P(val)) {
8980 if (rb_str_equal(val, rb_default_rs)) {
8981 val = rb_default_rs;
8982 }
8983 else {
8984 val = rb_str_frozen_bare_string(val);
8985 }
8986 }
8987 *var = val;
8988}
8989
8990/*
8991 * call-seq:
8992 * print(*objects) -> nil
8993 *
8994 * Writes the given objects to the stream; returns +nil+.
8995 * Appends the output record separator <tt>$OUTPUT_RECORD_SEPARATOR</tt>
8996 * (<tt>$\</tt>), if it is not +nil+.
8997 * See {Line IO}[rdoc-ref:IO@Line+IO].
8998 *
8999 * With argument +objects+ given, for each object:
9000 *
9001 * - Converts via its method +to_s+ if not a string.
9002 * - Writes to the stream.
9003 * - If not the last object, writes the output field separator
9004 * <tt>$OUTPUT_FIELD_SEPARATOR</tt> (<tt>$,</tt>) if it is not +nil+.
9005 *
9006 * With default separators:
9007 *
9008 * f = File.open('t.tmp', 'w+')
9009 * objects = [0, 0.0, Rational(0, 1), Complex(0, 0), :zero, 'zero']
9010 * p $OUTPUT_RECORD_SEPARATOR
9011 * p $OUTPUT_FIELD_SEPARATOR
9012 * f.print(*objects)
9013 * f.rewind
9014 * p f.read
9015 * f.close
9016 *
9017 * Output:
9018 *
9019 * nil
9020 * nil
9021 * "00.00/10+0izerozero"
9022 *
9023 * With specified separators:
9024 *
9025 * $\ = "\n"
9026 * $, = ','
9027 * f.rewind
9028 * f.print(*objects)
9029 * f.rewind
9030 * p f.read
9031 *
9032 * Output:
9033 *
9034 * "0,0.0,0/1,0+0i,zero,zero\n"
9035 *
9036 * With no argument given, writes the content of <tt>$_</tt>
9037 * (which is usually the most recent user input):
9038 *
9039 * f = File.open('t.tmp', 'w+')
9040 * gets # Sets $_ to the most recent user input.
9041 * f.print
9042 * f.close
9043 *
9044 */
9045
9046VALUE
9047rb_io_print(int argc, const VALUE *argv, VALUE out)
9048{
9049 int i;
9050 VALUE line;
9051
9052 /* if no argument given, print `$_' */
9053 if (argc == 0) {
9054 argc = 1;
9055 line = rb_lastline_get();
9056 argv = &line;
9057 }
9058 if (argc > 1 && !NIL_P(rb_output_fs)) {
9059 rb_category_warn(RB_WARN_CATEGORY_DEPRECATED, "$, is set to non-nil value");
9060 }
9061 for (i=0; i<argc; i++) {
9062 if (!NIL_P(rb_output_fs) && i>0) {
9063 rb_io_write(out, rb_output_fs);
9064 }
9065 rb_io_write(out, argv[i]);
9066 }
9067 if (argc > 0 && !NIL_P(rb_output_rs)) {
9068 rb_io_write(out, rb_output_rs);
9069 }
9070
9071 return Qnil;
9072}
9073
9074/*
9075 * call-seq:
9076 * print(*objects) -> nil
9077 *
9078 * Equivalent to <tt>$stdout.print(*objects)</tt>,
9079 * this method is the straightforward way to write to <tt>$stdout</tt>.
9080 *
9081 * Writes the given objects to <tt>$stdout</tt>; returns +nil+.
9082 * Appends the output record separator <tt>$OUTPUT_RECORD_SEPARATOR</tt>
9083 * (<tt>$\</tt>), if it is not +nil+.
9084 *
9085 * With argument +objects+ given, for each object:
9086 *
9087 * - Converts via its method +to_s+ if not a string.
9088 * - Writes to <tt>stdout</tt>.
9089 * - If not the last object, writes the output field separator
9090 * <tt>$OUTPUT_FIELD_SEPARATOR</tt> (<tt>$,</tt>) if it is not +nil+.
9091 *
9092 * With default separators:
9093 *
9094 * objects = [0, 0.0, Rational(0, 1), Complex(0, 0), :zero, 'zero']
9095 * $OUTPUT_RECORD_SEPARATOR
9096 * $OUTPUT_FIELD_SEPARATOR
9097 * print(*objects)
9098 *
9099 * Output:
9100 *
9101 * nil
9102 * nil
9103 * 00.00/10+0izerozero
9104 *
9105 * With specified separators:
9106 *
9107 * $OUTPUT_RECORD_SEPARATOR = "\n"
9108 * $OUTPUT_FIELD_SEPARATOR = ','
9109 * print(*objects)
9110 *
9111 * Output:
9112 *
9113 * 0,0.0,0/1,0+0i,zero,zero
9114 *
9115 * With no argument given, writes the content of <tt>$_</tt>
9116 * (which is usually the most recent user input):
9117 *
9118 * gets # Sets $_ to the most recent user input.
9119 * print # Prints $_.
9120 *
9121 */
9122
9123static VALUE
9124rb_f_print(int argc, const VALUE *argv, VALUE _)
9125{
9126 rb_io_print(argc, argv, rb_ractor_stdout());
9127 return Qnil;
9128}
9129
9130/*
9131 * call-seq:
9132 * putc(object) -> object
9133 *
9134 * Writes a character to the stream.
9135 * See {Character IO}[rdoc-ref:IO@Character+IO].
9136 *
9137 * If +object+ is numeric, converts to integer if necessary,
9138 * then writes the character whose code is the
9139 * least significant byte;
9140 * if +object+ is a string, writes the first character:
9141 *
9142 * $stdout.putc "A"
9143 * $stdout.putc 65
9144 *
9145 * Output:
9146 *
9147 * AA
9148 *
9149 */
9150
9151static VALUE
9152rb_io_putc(VALUE io, VALUE ch)
9153{
9154 VALUE str;
9155 if (RB_TYPE_P(ch, T_STRING)) {
9156 str = rb_str_substr(ch, 0, 1);
9157 }
9158 else {
9159 char c = NUM2CHR(ch);
9160 str = rb_str_new(&c, 1);
9161 }
9162 rb_io_write(io, str);
9163 return ch;
9164}
9165
9166#define forward(obj, id, argc, argv) \
9167 rb_funcallv_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
9168#define forward_public(obj, id, argc, argv) \
9169 rb_funcallv_public_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
9170#define forward_current(id, argc, argv) \
9171 forward_public(ARGF.current_file, id, argc, argv)
9172
9173/*
9174 * call-seq:
9175 * putc(int) -> int
9176 *
9177 * Equivalent to:
9178 *
9179 * $stdout.putc(int)
9180 *
9181 * See IO#putc for important information regarding multi-byte characters.
9182 *
9183 */
9184
9185static VALUE
9186rb_f_putc(VALUE recv, VALUE ch)
9187{
9188 VALUE r_stdout = rb_ractor_stdout();
9189 if (recv == r_stdout) {
9190 return rb_io_putc(recv, ch);
9191 }
9192 return forward(r_stdout, rb_intern("putc"), 1, &ch);
9193}
9194
9195
9196int
9197rb_str_end_with_asciichar(VALUE str, int c)
9198{
9199 long len = RSTRING_LEN(str);
9200 const char *ptr = RSTRING_PTR(str);
9201 rb_encoding *enc = rb_enc_from_index(ENCODING_GET(str));
9202 int n;
9203
9204 if (len == 0) return 0;
9205 if ((n = rb_enc_mbminlen(enc)) == 1) {
9206 return ptr[len - 1] == c;
9207 }
9208 return rb_enc_ascget(ptr + ((len - 1) / n) * n, ptr + len, &n, enc) == c;
9209}
9210
9211static VALUE
9212io_puts_ary(VALUE ary, VALUE out, int recur)
9213{
9214 VALUE tmp;
9215 long i;
9216
9217 if (recur) {
9218 tmp = rb_str_new2("[...]");
9219 rb_io_puts(1, &tmp, out);
9220 return Qtrue;
9221 }
9222 ary = rb_check_array_type(ary);
9223 if (NIL_P(ary)) return Qfalse;
9224 for (i=0; i<RARRAY_LEN(ary); i++) {
9225 tmp = RARRAY_AREF(ary, i);
9226 rb_io_puts(1, &tmp, out);
9227 }
9228 return Qtrue;
9229}
9230
9231/*
9232 * call-seq:
9233 * puts(*objects) -> nil
9234 *
9235 * Writes the given +objects+ to the stream, which must be open for writing;
9236 * returns +nil+.\
9237 * Writes a newline after each that does not already end with a newline sequence.
9238 * If called without arguments, writes a newline.
9239 * See {Line IO}[rdoc-ref:IO@Line+IO].
9240 *
9241 * Note that each added newline is the character <tt>"\n"</tt>,
9242 * not the output record separator (<tt>$\</tt>).
9243 *
9244 * Treatment for each object:
9245 *
9246 * - String: writes the string.
9247 * - Neither string nor array: writes <tt>object.to_s</tt>.
9248 * - Array: writes each element of the array; arrays may be nested.
9249 *
9250 * To keep these examples brief, we define this helper method:
9251 *
9252 * def show(*objects)
9253 * # Puts objects to file.
9254 * f = File.new('t.tmp', 'w+')
9255 * f.puts(objects)
9256 * # Return file content.
9257 * f.rewind
9258 * p f.read
9259 * f.close
9260 * end
9261 *
9262 * # Strings without newlines.
9263 * show('foo', 'bar', 'baz') # => "foo\nbar\nbaz\n"
9264 * # Strings, some with newlines.
9265 * show("foo\n", 'bar', "baz\n") # => "foo\nbar\nbaz\n"
9266 *
9267 * # Neither strings nor arrays:
9268 * show(0, 0.0, Rational(0, 1), Complex(9, 0), :zero)
9269 * # => "0\n0.0\n0/1\n9+0i\nzero\n"
9270 *
9271 * # Array of strings.
9272 * show(['foo', "bar\n", 'baz']) # => "foo\nbar\nbaz\n"
9273 * # Nested arrays.
9274 * show([[[0, 1], 2, 3], 4, 5]) # => "0\n1\n2\n3\n4\n5\n"
9275 *
9276 */
9277
9278VALUE
9279rb_io_puts(int argc, const VALUE *argv, VALUE out)
9280{
9281 VALUE line, args[2];
9282
9283 /* if no argument given, print newline. */
9284 if (argc == 0) {
9285 rb_io_write(out, rb_default_rs);
9286 return Qnil;
9287 }
9288 for (int i = 0; i < argc; i++) {
9289 // Convert the argument to a string:
9290 if (RB_TYPE_P(argv[i], T_STRING)) {
9291 line = argv[i];
9292 }
9293 else if (rb_exec_recursive(io_puts_ary, argv[i], out)) {
9294 continue;
9295 }
9296 else {
9297 line = rb_obj_as_string(argv[i]);
9298 }
9299
9300 // Write the line:
9301 int n = 0;
9302 if (RSTRING_LEN(line) == 0) {
9303 args[n++] = rb_default_rs;
9304 }
9305 else {
9306 args[n++] = line;
9307 if (!rb_str_end_with_asciichar(line, '\n')) {
9308 args[n++] = rb_default_rs;
9309 }
9310 }
9311
9312 rb_io_writev(out, n, args);
9313 }
9314
9315 return Qnil;
9316}
9317
9318/*
9319 * call-seq:
9320 * puts(*objects) -> nil
9321 *
9322 * Equivalent to
9323 *
9324 * $stdout.puts(objects)
9325 */
9326
9327static VALUE
9328rb_f_puts(int argc, VALUE *argv, VALUE recv)
9329{
9330 VALUE r_stdout = rb_ractor_stdout();
9331 if (recv == r_stdout) {
9332 return rb_io_puts(argc, argv, recv);
9333 }
9334 return forward(r_stdout, rb_intern("puts"), argc, argv);
9335}
9336
9337static VALUE
9338rb_p_write(VALUE str)
9339{
9340 VALUE args[2];
9341 args[0] = str;
9342 args[1] = rb_default_rs;
9343 VALUE r_stdout = rb_ractor_stdout();
9344 if (RB_TYPE_P(r_stdout, T_FILE) &&
9345 rb_method_basic_definition_p(CLASS_OF(r_stdout), id_write)) {
9346 io_writev(2, args, r_stdout);
9347 }
9348 else {
9349 rb_io_writev(r_stdout, 2, args);
9350 }
9351 return Qnil;
9352}
9353
9354void
9355rb_p(VALUE obj) /* for debug print within C code */
9356{
9357 rb_p_write(rb_obj_as_string(rb_inspect(obj)));
9358}
9359
9360static VALUE
9361rb_p_result(int argc, const VALUE *argv)
9362{
9363 VALUE ret = Qnil;
9364
9365 if (argc == 1) {
9366 ret = argv[0];
9367 }
9368 else if (argc > 1) {
9369 ret = rb_ary_new4(argc, argv);
9370 }
9371 VALUE r_stdout = rb_ractor_stdout();
9372 if (RB_TYPE_P(r_stdout, T_FILE)) {
9373 rb_uninterruptible(rb_io_flush, r_stdout);
9374 }
9375 return ret;
9376}
9377
9378/*
9379 * call-seq:
9380 * p(object) -> obj
9381 * p(*objects) -> array of objects
9382 * p -> nil
9383 *
9384 * For each object +obj+, executes:
9385 *
9386 * $stdout.write(obj.inspect, "\n")
9387 *
9388 * With one object given, returns the object;
9389 * with multiple objects given, returns an array containing the objects;
9390 * with no object given, returns +nil+.
9391 *
9392 * Examples:
9393 *
9394 * r = Range.new(0, 4)
9395 * p r # => 0..4
9396 * p [r, r, r] # => [0..4, 0..4, 0..4]
9397 * p # => nil
9398 *
9399 * Output:
9400 *
9401 * 0..4
9402 * [0..4, 0..4, 0..4]
9403 *
9404 * Kernel#p is designed for debugging purposes.
9405 * Ruby implementations may define Kernel#p to be uninterruptible
9406 * in whole or in part.
9407 * On CRuby, Kernel#p's writing of data is uninterruptible.
9408 */
9409
9410static VALUE
9411rb_f_p(int argc, VALUE *argv, VALUE self)
9412{
9413 int i;
9414 for (i=0; i<argc; i++) {
9415 VALUE inspected = rb_obj_as_string(rb_inspect(argv[i]));
9416 rb_uninterruptible(rb_p_write, inspected);
9417 }
9418 return rb_p_result(argc, argv);
9419}
9420
9421/*
9422 * call-seq:
9423 * display(port = $>) -> nil
9424 *
9425 * Writes +self+ on the given port:
9426 *
9427 * 1.display
9428 * "cat".display
9429 * [ 4, 5, 6 ].display
9430 * puts
9431 *
9432 * Output:
9433 *
9434 * 1cat[4, 5, 6]
9435 *
9436 */
9437
9438static VALUE
9439rb_obj_display(int argc, VALUE *argv, VALUE self)
9440{
9441 VALUE out;
9442
9443 out = (!rb_check_arity(argc, 0, 1) ? rb_ractor_stdout() : argv[0]);
9444 rb_io_write(out, self);
9445
9446 return Qnil;
9447}
9448
9449static int
9450rb_stderr_to_original_p(VALUE err)
9451{
9452 return (err == orig_stderr || RFILE(orig_stderr)->fptr->fd < 0);
9453}
9454
9455void
9456rb_write_error2(const char *mesg, long len)
9457{
9458 VALUE out = rb_ractor_stderr();
9459 if (rb_stderr_to_original_p(out)) {
9460#ifdef _WIN32
9461 if (isatty(fileno(stderr))) {
9462 if (rb_w32_write_console(rb_str_new(mesg, len), fileno(stderr)) > 0) return;
9463 }
9464#endif
9465 if (fwrite(mesg, sizeof(char), (size_t)len, stderr) < (size_t)len) {
9466 /* failed to write to stderr, what can we do? */
9467 return;
9468 }
9469 }
9470 else {
9471 rb_io_write(out, rb_str_new(mesg, len));
9472 }
9473}
9474
9475void
9476rb_write_error(const char *mesg)
9477{
9478 rb_write_error2(mesg, strlen(mesg));
9479}
9480
9481void
9482rb_write_error_str(VALUE mesg)
9483{
9484 VALUE out = rb_ractor_stderr();
9485 /* a stopgap measure for the time being */
9486 if (rb_stderr_to_original_p(out)) {
9487 size_t len = (size_t)RSTRING_LEN(mesg);
9488#ifdef _WIN32
9489 if (isatty(fileno(stderr))) {
9490 if (rb_w32_write_console(mesg, fileno(stderr)) > 0) return;
9491 }
9492#endif
9493 if (fwrite(RSTRING_PTR(mesg), sizeof(char), len, stderr) < len) {
9494 RB_GC_GUARD(mesg);
9495 return;
9496 }
9497 }
9498 else {
9499 /* may unlock GVL, and */
9500 rb_io_write(out, mesg);
9501 }
9502}
9503
9504int
9505rb_stderr_tty_p(void)
9506{
9507 if (rb_stderr_to_original_p(rb_ractor_stderr()))
9508 return isatty(fileno(stderr));
9509 return 0;
9510}
9511
9512static void
9513must_respond_to(ID mid, VALUE val, ID id)
9514{
9515 if (!rb_respond_to(val, mid)) {
9516 rb_raise(rb_eTypeError, "%"PRIsVALUE" must have %"PRIsVALUE" method, %"PRIsVALUE" given",
9517 rb_id2str(id), rb_id2str(mid),
9518 rb_obj_class(val));
9519 }
9520}
9521
9522static void
9523stdin_setter(VALUE val, ID id, VALUE *ptr)
9524{
9526}
9527
9528static VALUE
9529stdin_getter(ID id, VALUE *ptr)
9530{
9531 return rb_ractor_stdin();
9532}
9533
9534static void
9535stdout_setter(VALUE val, ID id, VALUE *ptr)
9536{
9537 must_respond_to(id_write, val, id);
9539}
9540
9541static VALUE
9542stdout_getter(ID id, VALUE *ptr)
9543{
9544 return rb_ractor_stdout();
9545}
9546
9547static void
9548stderr_setter(VALUE val, ID id, VALUE *ptr)
9549{
9550 must_respond_to(id_write, val, id);
9552}
9553
9554static VALUE
9555stderr_getter(ID id, VALUE *ptr)
9556{
9557 return rb_ractor_stderr();
9558}
9559
9560static VALUE
9561allocate_and_open_new_file(VALUE klass)
9562{
9563 VALUE self = io_alloc(klass);
9564 rb_io_make_open_file(self);
9565 return self;
9566}
9567
9568VALUE
9569rb_io_open_descriptor(VALUE klass, int descriptor, int mode, VALUE path, VALUE timeout, struct rb_io_encoding *encoding)
9570{
9571 int state;
9572 VALUE self = rb_protect(allocate_and_open_new_file, klass, &state);
9573 if (state) {
9574 /* if we raised an exception allocating an IO object, but the caller
9575 intended to transfer ownership of this FD to us, close the fd before
9576 raising the exception. Otherwise, we would leak a FD - the caller
9577 expects GC to close the file, but we never got around to assigning
9578 it to a rb_io. */
9579 if (!(mode & FMODE_EXTERNAL)) {
9580 maygvl_close(descriptor, 0);
9581 }
9582 rb_jump_tag(state);
9583 }
9584
9585
9586 rb_io_t *io = RFILE(self)->fptr;
9587 io->self = self;
9588 io->fd = descriptor;
9589 io->mode = mode;
9590
9591 /* At this point, Ruby fully owns the descriptor, and will close it when
9592 the IO gets GC'd (unless FMODE_EXTERNAL was set), no matter what happens
9593 in the rest of this method. */
9594
9595 if (NIL_P(path)) {
9596 io->pathv = Qnil;
9597 }
9598 else {
9599 StringValue(path);
9600 io->pathv = rb_str_new_frozen(path);
9601 }
9602
9603 io->timeout = timeout;
9604
9605 ccan_list_head_init(&io->blocking_operations);
9606 io->closing_ec = NULL;
9607 io->wakeup_mutex = Qnil;
9608 io->fork_generation = GET_VM()->fork_gen;
9609
9610 if (encoding) {
9611 io->encs = *encoding;
9612 }
9613
9614 rb_update_max_fd(descriptor);
9615
9616 return self;
9617}
9618
9619static VALUE
9620prep_io(int fd, enum rb_io_mode fmode, VALUE klass, const char *path)
9621{
9622 VALUE path_value = Qnil;
9623 rb_encoding *e;
9624 struct rb_io_encoding convconfig;
9625
9626 if (path) {
9627 path_value = rb_obj_freeze(rb_str_new_cstr(path));
9628 }
9629
9630 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
9631 rb_io_ext_int_to_encs(e, NULL, &convconfig.enc, &convconfig.enc2, fmode);
9632 convconfig.ecflags = (fmode & FMODE_READABLE) ?
9635#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9636 convconfig.ecflags |= (fmode & FMODE_WRITABLE) ?
9637 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
9638 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
9639#endif
9640 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.enc2, convconfig.ecflags);
9641 convconfig.ecopts = Qnil;
9642
9643 VALUE self = rb_io_open_descriptor(klass, fd, fmode, path_value, Qnil, &convconfig);
9644 rb_io_t*io = RFILE(self)->fptr;
9645
9646 if (!io_check_tty(io)) {
9647#ifdef __CYGWIN__
9648 io->mode |= FMODE_BINMODE;
9649 setmode(fd, O_BINARY);
9650#endif
9651 }
9652
9653 return self;
9654}
9655
9656VALUE
9657rb_io_fdopen(int fd, int oflags, const char *path)
9658{
9659 VALUE klass = rb_cIO;
9660
9661 if (path && strcmp(path, "-")) klass = rb_cFile;
9662 return prep_io(fd, rb_io_oflags_fmode(oflags), klass, path);
9663}
9664
9665static VALUE
9666prep_stdio(FILE *f, enum rb_io_mode fmode, VALUE klass, const char *path)
9667{
9668 rb_io_t *fptr;
9669 VALUE io = prep_io(fileno(f), fmode|FMODE_EXTERNAL|DEFAULT_TEXTMODE, klass, path);
9670
9671 GetOpenFile(io, fptr);
9673#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9674 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
9675 if (fmode & FMODE_READABLE) {
9677 }
9678#endif
9679 fptr->stdio_file = f;
9680
9681 return io;
9682}
9683
9684VALUE
9685rb_io_prep_stdin(void)
9686{
9687 return prep_stdio(stdin, FMODE_READABLE, rb_cIO, "<STDIN>");
9688}
9689
9690VALUE
9691rb_io_prep_stdout(void)
9692{
9693 return prep_stdio(stdout, FMODE_WRITABLE|FMODE_SIGNAL_ON_EPIPE, rb_cIO, "<STDOUT>");
9694}
9695
9696VALUE
9697rb_io_prep_stderr(void)
9698{
9699 return prep_stdio(stderr, FMODE_WRITABLE|FMODE_SYNC, rb_cIO, "<STDERR>");
9700}
9701
9702FILE *
9704{
9705 if (!fptr->stdio_file) {
9706 int oflags = rb_io_fmode_oflags(fptr->mode) & ~O_EXCL;
9707 fptr->stdio_file = rb_fdopen(fptr->fd, rb_io_oflags_modestr(oflags));
9708 }
9709 return fptr->stdio_file;
9710}
9711
9712static inline void
9713rb_io_buffer_init(struct rb_io_internal_buffer *buf)
9714{
9715 buf->ptr = NULL;
9716 buf->off = 0;
9717 buf->len = 0;
9718 buf->capa = 0;
9719}
9720
9721static inline rb_io_t *
9722rb_io_fptr_new(void)
9723{
9724 rb_io_t *fp = ALLOC(rb_io_t);
9725 fp->self = Qnil;
9726 fp->fd = -1;
9727 fp->stdio_file = NULL;
9728 fp->mode = 0;
9729 fp->pid = 0;
9730 fp->lineno = 0;
9731 fp->pathv = Qnil;
9732 fp->finalize = 0;
9733 rb_io_buffer_init(&fp->wbuf);
9734 rb_io_buffer_init(&fp->rbuf);
9735 rb_io_buffer_init(&fp->cbuf);
9736 fp->readconv = NULL;
9737 fp->writeconv = NULL;
9739 fp->writeconv_pre_ecflags = 0;
9741 fp->writeconv_initialized = 0;
9742 fp->tied_io_for_writing = 0;
9743 fp->encs.enc = NULL;
9744 fp->encs.enc2 = NULL;
9745 fp->encs.ecflags = 0;
9746 fp->encs.ecopts = Qnil;
9747 fp->write_lock = Qnil;
9748 fp->timeout = Qnil;
9749 ccan_list_head_init(&fp->blocking_operations);
9750 fp->closing_ec = NULL;
9751 fp->wakeup_mutex = Qnil;
9752 fp->fork_generation = GET_VM()->fork_gen;
9753 return fp;
9754}
9755
9756rb_io_t *
9757rb_io_make_open_file(VALUE obj)
9758{
9759 rb_io_t *fp = 0;
9760
9761 Check_Type(obj, T_FILE);
9762 if (RFILE(obj)->fptr) {
9763 rb_io_close(obj);
9764 rb_io_fptr_finalize(RFILE(obj)->fptr);
9765 RFILE(obj)->fptr = 0;
9766 }
9767 fp = rb_io_fptr_new();
9768 fp->self = obj;
9769 RFILE(obj)->fptr = fp;
9770 return fp;
9771}
9772
9773static VALUE io_initialize(VALUE io, VALUE fnum, VALUE vmode, VALUE opt);
9774
9775/*
9776 * call-seq:
9777 * IO.new(fd, mode = 'r', **opts) -> io
9778 *
9779 * Creates and returns a new \IO object (file stream) from a file descriptor.
9780 *
9781 * \IO.new may be useful for interaction with low-level libraries.
9782 * For higher-level interactions, it may be simpler to create
9783 * the file stream using File.open.
9784 *
9785 * Argument +fd+ must be a valid file descriptor (integer):
9786 *
9787 * path = 't.tmp'
9788 * fd = IO.sysopen(path) # => 3
9789 * IO.new(fd) # => #<IO:fd 3>
9790 *
9791 * The new \IO object does not inherit encoding
9792 * (because the integer file descriptor does not have an encoding):
9793 *
9794 * File.read('t.ja') # => "こんにちは"
9795 * fd = IO.sysopen('t.ja', 'rb')
9796 * io = IO.new(fd)
9797 * io.external_encoding # => #<Encoding:UTF-8> # Not ASCII-8BIT.
9798 *
9799 * Optional argument +mode+ (defaults to 'r') must specify a valid mode;
9800 * see {Access Modes}[rdoc-ref:File@Access+Modes]:
9801 *
9802 * IO.new(fd, 'w') # => #<IO:fd 3>
9803 * IO.new(fd, File::WRONLY) # => #<IO:fd 3>
9804 *
9805 * Optional keyword arguments +opts+ specify:
9806 *
9807 * - {Open Options}[rdoc-ref:IO@Open+Options].
9808 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
9809 *
9810 * Examples:
9811 *
9812 * IO.new(fd, internal_encoding: nil) # => #<IO:fd 3>
9813 * IO.new(fd, autoclose: true) # => #<IO:fd 3>
9814 *
9815 */
9816
9817static VALUE
9818rb_io_initialize(int argc, VALUE *argv, VALUE io)
9819{
9820 VALUE fnum, vmode;
9821 VALUE opt;
9822
9823 rb_scan_args(argc, argv, "11:", &fnum, &vmode, &opt);
9824 return io_initialize(io, fnum, vmode, opt);
9825}
9826
9827static VALUE
9828io_initialize(VALUE io, VALUE fnum, VALUE vmode, VALUE opt)
9829{
9830 rb_io_t *fp;
9831 int fd, oflags = O_RDONLY;
9832 enum rb_io_mode fmode;
9833 struct rb_io_encoding convconfig;
9834#if defined(HAVE_FCNTL) && defined(F_GETFL)
9835 int ofmode;
9836#else
9837 struct stat st;
9838#endif
9839
9840 rb_io_extract_modeenc(&vmode, 0, opt, &oflags, &fmode, &convconfig);
9841
9842 fd = NUM2INT(fnum);
9843 if (rb_reserved_fd_p(fd)) {
9844 rb_raise(rb_eArgError, "The given fd is not accessible because RubyVM reserves it");
9845 }
9846#if defined(HAVE_FCNTL) && defined(F_GETFL)
9847 oflags = fcntl(fd, F_GETFL);
9848 if (oflags == -1) rb_sys_fail(0);
9849#else
9850 if (fstat(fd, &st) < 0) rb_sys_fail(0);
9851#endif
9852 rb_update_max_fd(fd);
9853#if defined(HAVE_FCNTL) && defined(F_GETFL)
9854 ofmode = rb_io_oflags_fmode(oflags);
9855 if (NIL_P(vmode)) {
9856 fmode = ofmode;
9857 }
9858 else if ((~ofmode & fmode) & FMODE_READWRITE) {
9859 VALUE error = INT2FIX(EINVAL);
9861 }
9862#endif
9863 VALUE path = Qnil;
9864
9865 if (!NIL_P(opt)) {
9866 if (rb_hash_aref(opt, sym_autoclose) == Qfalse) {
9867 fmode |= FMODE_EXTERNAL;
9868 }
9869
9870 path = rb_hash_aref(opt, RB_ID2SYM(idPath));
9871 if (!NIL_P(path)) {
9872 StringValue(path);
9873 path = rb_str_new_frozen(path);
9874 }
9875 }
9876
9877 MakeOpenFile(io, fp);
9878 fp->self = io;
9879 fp->fd = fd;
9880 fp->mode = fmode;
9881 fp->encs = convconfig;
9882 fp->pathv = path;
9883 fp->timeout = Qnil;
9884 ccan_list_head_init(&fp->blocking_operations);
9885 fp->closing_ec = NULL;
9886 fp->wakeup_mutex = Qnil;
9887 fp->fork_generation = GET_VM()->fork_gen;
9888 clear_codeconv(fp);
9889 io_check_tty(fp);
9890 if (fileno(stdin) == fd)
9891 fp->stdio_file = stdin;
9892 else if (fileno(stdout) == fd)
9893 fp->stdio_file = stdout;
9894 else if (fileno(stderr) == fd)
9895 fp->stdio_file = stderr;
9896
9897 if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
9898 return io;
9899}
9900
9901/*
9902 * call-seq:
9903 * set_encoding_by_bom -> encoding or nil
9904 *
9905 * If the stream begins with a BOM
9906 * ({byte order marker}[https://en.wikipedia.org/wiki/Byte_order_mark]),
9907 * consumes the BOM and sets the external encoding accordingly;
9908 * returns the result encoding if found, or +nil+ otherwise:
9909 *
9910 * File.write('t.tmp', "\u{FEFF}abc")
9911 * io = File.open('t.tmp', 'rb')
9912 * io.set_encoding_by_bom # => #<Encoding:UTF-8>
9913 * io.close
9914 *
9915 * File.write('t.tmp', 'abc')
9916 * io = File.open('t.tmp', 'rb')
9917 * io.set_encoding_by_bom # => nil
9918 * io.close
9919 *
9920 * Raises an exception if the stream is not binmode
9921 * or its encoding has already been set.
9922 *
9923 */
9924
9925static VALUE
9926rb_io_set_encoding_by_bom(VALUE io)
9927{
9928 rb_io_t *fptr;
9929
9930 GetOpenFile(io, fptr);
9931 if (!(fptr->mode & FMODE_BINMODE)) {
9932 rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
9933 }
9934 if (fptr->encs.enc2) {
9935 rb_raise(rb_eArgError, "encoding conversion is set");
9936 }
9937 else if (fptr->encs.enc && fptr->encs.enc != rb_ascii8bit_encoding()) {
9938 rb_raise(rb_eArgError, "encoding is set to %s already",
9939 rb_enc_name(fptr->encs.enc));
9940 }
9941 if (!io_set_encoding_by_bom(io)) return Qnil;
9942 return rb_enc_from_encoding(fptr->encs.enc);
9943}
9944
9945/*
9946 * :markup: markdown
9947 *
9948 * call-seq:
9949 * File.new(path, mode = 'r', permissions = 0666, **options) -> file
9950 *
9951 * Opens the file as specified by the given arguments.
9952 * Creates and returns a new open \File object for that file;
9953 * the opened file is in non-synchronous mode.
9954 *
9955 * Argument `path` must the string path to an existing filesystem entry:
9956 *
9957 * ```ruby
9958 * file = File.new('doc/maintainers.md') # => #<File:doc/maintainers.md>
9959 * file.close # Clean up.
9960 * tty = File.new('/dev/tty') # => #<File:/dev/tty>
9961 * tty.close # Clean up.
9962 * ```
9963 *
9964 * Note that the caller is responsible for closing the file;
9965 * see File.open for automatic closing.
9966 *
9967 * Optional argument `mode` (defaults to `'r'`) must specify a valid mode;
9968 * see [Access Modes](rdoc-ref:File@Access+Modes):
9969 *
9970 * ```ruby
9971 * file = File.new('t.tmp', 'w') # => #<File:t.tmp>
9972 * file.close # Clean up.
9973 * file = File.new('t.tmp', File::RDONLY) # => #<File:t.tmp>
9974 * file.close # Clean up.
9975 * ```
9976 *
9977 * Optional argument `permissions` (defaults to `0666`) must specify valid permissions;
9978 * see [File Permissions](rdoc-ref:File@File+Permissions):
9979 *
9980 * ```ruby
9981 * file = File.new('t.tmp', 'w', 0644) # => #<File:t.tmp>
9982 * file.close # Clean up.
9983 * file = File.new('t.tmp', 'w', 0444) # => #<File:t.tmp>
9984 * file.close # Clean up.
9985 * ```
9986 *
9987 * Optional keyword arguments `options` specify:
9988 *
9989 * - [Open Options](rdoc-ref:IO@Open+Options).
9990 * - [Encoding options](rdoc-ref:encodings.rdoc@Encoding+Options).
9991 *
9992 */
9993
9994static VALUE
9995rb_file_initialize(int argc, VALUE *argv, VALUE io)
9996{
9997 if (RFILE(io)->fptr) {
9998 rb_raise(rb_eRuntimeError, "reinitializing File");
9999 }
10000 VALUE fname, vmode, vperm, opt;
10001 int posargc = rb_scan_args(argc, argv, "12:", &fname, &vmode, &vperm, &opt);
10002 if (posargc < 3) { /* perm is File only */
10003 VALUE fd = rb_check_to_int(fname);
10004
10005 if (!NIL_P(fd)) {
10006 return io_initialize(io, fd, vmode, opt);
10007 }
10008 }
10009 return rb_open_file(io, fname, vmode, vperm, opt);
10010}
10011
10012/* :nodoc: */
10013static VALUE
10014rb_io_s_new(int argc, VALUE *argv, VALUE klass)
10015{
10016 if (rb_block_given_p()) {
10017 VALUE cname = rb_obj_as_string(klass);
10018
10019 rb_warn("%"PRIsVALUE"::new() does not take block; use %"PRIsVALUE"::open() instead",
10020 cname, cname);
10021 }
10022 return rb_class_new_instance_kw(argc, argv, klass, RB_PASS_CALLED_KEYWORDS);
10023}
10024
10025
10026/*
10027 * call-seq:
10028 * IO.for_fd(fd, mode = 'r', **opts) -> io
10029 *
10030 * Synonym for IO.new.
10031 *
10032 */
10033
10034static VALUE
10035rb_io_s_for_fd(int argc, VALUE *argv, VALUE klass)
10036{
10037 VALUE io = rb_obj_alloc(klass);
10038 rb_io_initialize(argc, argv, io);
10039 return io;
10040}
10041
10042/*
10043 * call-seq:
10044 * ios.autoclose? -> true or false
10045 *
10046 * Returns +true+ if the underlying file descriptor of _ios_ will be
10047 * closed at its finalization or at calling #close, otherwise +false+.
10048 */
10049
10050static VALUE
10051rb_io_autoclose_p(VALUE io)
10052{
10053 rb_io_t *fptr = RFILE(io)->fptr;
10054 rb_io_check_closed(fptr);
10055 return RBOOL(!(fptr->mode & FMODE_EXTERNAL));
10056}
10057
10058/*
10059 * call-seq:
10060 * io.autoclose = bool -> true or false
10061 *
10062 * Sets auto-close flag.
10063 *
10064 * f = File.open(File::NULL)
10065 * IO.for_fd(f.fileno).close
10066 * f.gets # raises Errno::EBADF
10067 *
10068 * f = File.open(File::NULL)
10069 * g = IO.for_fd(f.fileno)
10070 * g.autoclose = false
10071 * g.close
10072 * f.gets # won't cause Errno::EBADF
10073 */
10074
10075static VALUE
10076rb_io_set_autoclose(VALUE io, VALUE autoclose)
10077{
10078 rb_io_t *fptr;
10079 GetOpenFile(io, fptr);
10080 if (!RTEST(autoclose))
10081 fptr->mode |= FMODE_EXTERNAL;
10082 else
10083 fptr->mode &= ~FMODE_EXTERNAL;
10084 return autoclose;
10085}
10086
10087static VALUE
10088io_wait_event(VALUE io, int event, VALUE timeout, int return_io)
10089{
10090 VALUE result = rb_io_wait(io, RB_INT2NUM(event), timeout);
10091
10092 if (!RB_TEST(result)) {
10093 return Qnil;
10094 }
10095
10096 int mask = RB_NUM2INT(result);
10097
10098 if (mask & event) {
10099 if (return_io)
10100 return io;
10101 else
10102 return result;
10103 }
10104 else {
10105 return Qfalse;
10106 }
10107}
10108
10109/*
10110 * call-seq:
10111 * io.wait_readable -> truthy or falsy
10112 * io.wait_readable(timeout) -> truthy or falsy
10113 *
10114 * Waits until IO is readable and returns a truthy value, or a falsy
10115 * value when times out. Returns a truthy value immediately when
10116 * buffered data is available.
10117 */
10118
10119static VALUE
10120io_wait_readable(int argc, VALUE *argv, VALUE io)
10121{
10122 rb_io_t *fptr;
10123
10124 RB_IO_POINTER(io, fptr);
10126
10127 if (rb_io_read_pending(fptr)) return Qtrue;
10128
10129 rb_check_arity(argc, 0, 1);
10130 VALUE timeout = (argc == 1 ? argv[0] : Qnil);
10131
10132 return io_wait_event(io, RUBY_IO_READABLE, timeout, 1);
10133}
10134
10135/*
10136 * call-seq:
10137 * io.wait_writable -> truthy or falsy
10138 * io.wait_writable(timeout) -> truthy or falsy
10139 *
10140 * Waits until IO is writable and returns a truthy value or a falsy
10141 * value when times out.
10142 */
10143static VALUE
10144io_wait_writable(int argc, VALUE *argv, VALUE io)
10145{
10146 rb_io_t *fptr;
10147
10148 RB_IO_POINTER(io, fptr);
10150
10151 rb_check_arity(argc, 0, 1);
10152 VALUE timeout = (argc == 1 ? argv[0] : Qnil);
10153
10154 return io_wait_event(io, RUBY_IO_WRITABLE, timeout, 1);
10155}
10156
10157/*
10158 * call-seq:
10159 * io.wait_priority -> truthy or falsy
10160 * io.wait_priority(timeout) -> truthy or falsy
10161 *
10162 * Waits until IO is priority and returns a truthy value or a falsy
10163 * value when times out. Priority data is sent and received using
10164 * the Socket::MSG_OOB flag and is typically limited to streams.
10165 */
10166static VALUE
10167io_wait_priority(int argc, VALUE *argv, VALUE io)
10168{
10169 rb_io_t *fptr = NULL;
10170
10171 RB_IO_POINTER(io, fptr);
10173
10174 if (rb_io_read_pending(fptr)) return Qtrue;
10175
10176 rb_check_arity(argc, 0, 1);
10177 VALUE timeout = argc == 1 ? argv[0] : Qnil;
10178
10179 return io_wait_event(io, RUBY_IO_PRIORITY, timeout, 1);
10180}
10181
10182static int
10183wait_mode_sym(VALUE mode)
10184{
10185 if (mode == ID2SYM(rb_intern("r"))) {
10186 return RB_WAITFD_IN;
10187 }
10188 if (mode == ID2SYM(rb_intern("read"))) {
10189 return RB_WAITFD_IN;
10190 }
10191 if (mode == ID2SYM(rb_intern("readable"))) {
10192 return RB_WAITFD_IN;
10193 }
10194 if (mode == ID2SYM(rb_intern("w"))) {
10195 return RB_WAITFD_OUT;
10196 }
10197 if (mode == ID2SYM(rb_intern("write"))) {
10198 return RB_WAITFD_OUT;
10199 }
10200 if (mode == ID2SYM(rb_intern("writable"))) {
10201 return RB_WAITFD_OUT;
10202 }
10203 if (mode == ID2SYM(rb_intern("rw"))) {
10204 return RB_WAITFD_IN|RB_WAITFD_OUT;
10205 }
10206 if (mode == ID2SYM(rb_intern("read_write"))) {
10207 return RB_WAITFD_IN|RB_WAITFD_OUT;
10208 }
10209 if (mode == ID2SYM(rb_intern("readable_writable"))) {
10210 return RB_WAITFD_IN|RB_WAITFD_OUT;
10211 }
10212
10213 rb_raise(rb_eArgError, "unsupported mode: %"PRIsVALUE, mode);
10214}
10215
10216static inline enum rb_io_event
10217io_event_from_value(VALUE value)
10218{
10219 int events = RB_NUM2INT(value);
10220
10221 if (events <= 0) rb_raise(rb_eArgError, "Events must be positive integer!");
10222
10223 return events;
10224}
10225
10226/*
10227 * call-seq:
10228 * io.wait(events, timeout) -> event mask, false or nil
10229 * io.wait(*event_symbols[, timeout]) -> self, true, or false
10230 *
10231 * Waits until the IO becomes ready for the specified events and returns the
10232 * subset of events that become ready, or a falsy value when times out.
10233 *
10234 * The events can be a bit mask of +IO::READABLE+, +IO::WRITABLE+ or
10235 * +IO::PRIORITY+.
10236 *
10237 * Returns an event mask (truthy value) immediately when buffered data is
10238 * available.
10239 *
10240 * The second form: if one or more event symbols (+:read+, +:write+, or
10241 * +:read_write+) are passed, the event mask is the bit OR of the bitmask
10242 * corresponding to those symbols. In this form, +timeout+ is optional, the
10243 * order of the arguments is arbitrary, and returns +io+ if any of the
10244 * events is ready.
10245 */
10246
10247static VALUE
10248io_wait(int argc, VALUE *argv, VALUE io)
10249{
10250 VALUE timeout = Qundef;
10251 enum rb_io_event events = 0;
10252 int return_io = 0;
10253
10254 if (argc != 2 || (RB_SYMBOL_P(argv[0]) || RB_SYMBOL_P(argv[1]))) {
10255 // We'd prefer to return the actual mask, but this form would return the io itself:
10256 return_io = 1;
10257
10258 // Slow/messy path:
10259 for (int i = 0; i < argc; i += 1) {
10260 if (RB_SYMBOL_P(argv[i])) {
10261 events |= wait_mode_sym(argv[i]);
10262 }
10263 else if (UNDEF_P(timeout)) {
10264 rb_time_interval(timeout = argv[i]);
10265 }
10266 else {
10267 rb_raise(rb_eArgError, "timeout given more than once");
10268 }
10269 }
10270
10271 if (UNDEF_P(timeout)) timeout = Qnil;
10272
10273 if (events == 0) {
10274 events = RUBY_IO_READABLE;
10275 }
10276 }
10277 else /* argc == 2 and neither are symbols */ {
10278 // This is the fast path:
10279 events = io_event_from_value(argv[0]);
10280 timeout = argv[1];
10281 }
10282
10283 if (events & RUBY_IO_READABLE) {
10284 rb_io_t *fptr = NULL;
10285 RB_IO_POINTER(io, fptr);
10286
10287 if (rb_io_read_pending(fptr)) {
10288 // This was the original behaviour:
10289 if (return_io) return Qtrue;
10290 // New behaviour always returns an event mask:
10291 else return RB_INT2NUM(RUBY_IO_READABLE);
10292 }
10293 }
10294
10295 return io_wait_event(io, events, timeout, return_io);
10296}
10297
10298static void
10299argf_mark_and_move(void *ptr)
10300{
10301 struct argf *p = ptr;
10302 rb_gc_mark_and_move(&p->filename);
10303 rb_gc_mark_and_move(&p->current_file);
10304 rb_gc_mark_and_move(&p->argv);
10305 rb_gc_mark_and_move(&p->inplace);
10306 rb_gc_mark_and_move(&p->encs.ecopts);
10307}
10308
10309static size_t
10310argf_memsize(const void *ptr)
10311{
10312 const struct argf *p = ptr;
10313 size_t size = sizeof(*p);
10314 return size;
10315}
10316
10317static const rb_data_type_t argf_type = {
10318 "ARGF",
10319 {argf_mark_and_move, RUBY_TYPED_DEFAULT_FREE, argf_memsize, argf_mark_and_move},
10320 0, 0, RUBY_TYPED_THREAD_SAFE_FREE | RUBY_TYPED_WB_PROTECTED
10321};
10322
10323static inline void
10324argf_init(VALUE argf, struct argf *p, VALUE v)
10325{
10326 p->filename = Qnil;
10327 p->current_file = Qnil;
10328 p->lineno = 0;
10329 RB_OBJ_WRITE(argf, &p->argv, v);
10330}
10331
10332static VALUE
10333argf_alloc(VALUE klass)
10334{
10335 struct argf *p;
10336 VALUE argf = TypedData_Make_Struct(klass, struct argf, &argf_type, p);
10337
10338 argf_init(argf, p, Qnil);
10339 return argf;
10340}
10341
10342#undef rb_argv
10343
10344/* :nodoc: */
10345static VALUE
10346argf_initialize(VALUE argf, VALUE argv)
10347{
10348 memset(&ARGF, 0, sizeof(ARGF));
10349 argf_init(argf, &ARGF, argv);
10350
10351 return argf;
10352}
10353
10354/* :nodoc: */
10355static VALUE
10356argf_initialize_copy(VALUE argf, VALUE orig)
10357{
10358 if (!OBJ_INIT_COPY(argf, orig)) return argf;
10359 ARGF = argf_of(orig);
10360 rb_gc_writebarrier_remember(argf);
10361 ARGF_SET(argv, rb_obj_dup(ARGF.argv));
10362 return argf;
10363}
10364
10365/*
10366 * call-seq:
10367 * ARGF.lineno = integer -> integer
10368 *
10369 * Sets the line number of ARGF as a whole to the given Integer.
10370 *
10371 * ARGF sets the line number automatically as you read data, so normally
10372 * you will not need to set it explicitly. To access the current line number
10373 * use ARGF.lineno.
10374 *
10375 * For example:
10376 *
10377 * ARGF.lineno #=> 0
10378 * ARGF.readline #=> "This is line 1\n"
10379 * ARGF.lineno #=> 1
10380 * ARGF.lineno = 0 #=> 0
10381 * ARGF.lineno #=> 0
10382 */
10383static VALUE
10384argf_set_lineno(VALUE argf, VALUE val)
10385{
10386 ARGF.lineno = NUM2INT(val);
10387 ARGF.last_lineno = ARGF.lineno;
10388 return val;
10389}
10390
10391/*
10392 * call-seq:
10393 * ARGF.lineno -> integer
10394 *
10395 * Returns the current line number of ARGF as a whole. This value
10396 * can be set manually with ARGF.lineno=.
10397 *
10398 * For example:
10399 *
10400 * ARGF.lineno #=> 0
10401 * ARGF.readline #=> "This is line 1\n"
10402 * ARGF.lineno #=> 1
10403 */
10404static VALUE
10405argf_lineno(VALUE argf)
10406{
10407 return INT2FIX(ARGF.lineno);
10408}
10409
10410static VALUE
10411argf_forward(int argc, VALUE *argv, VALUE argf)
10412{
10413 return forward_current(rb_frame_this_func(), argc, argv);
10414}
10415
10416#define next_argv() argf_next_argv(argf)
10417#define ARGF_GENERIC_INPUT_P() \
10418 (ARGF.current_file == rb_stdin && !RB_TYPE_P(ARGF.current_file, T_FILE))
10419#define ARGF_FORWARD(argc, argv) do {\
10420 if (ARGF_GENERIC_INPUT_P())\
10421 return argf_forward((argc), (argv), argf);\
10422} while (0)
10423#define NEXT_ARGF_FORWARD(argc, argv) do {\
10424 if (!next_argv()) return Qnil;\
10425 ARGF_FORWARD((argc), (argv));\
10426} while (0)
10427
10428static void
10429argf_close(VALUE argf)
10430{
10431 VALUE file = ARGF.current_file;
10432 if (file == rb_stdin) return;
10433 if (RB_TYPE_P(file, T_FILE)) {
10434 rb_io_set_write_io(file, Qnil);
10435 }
10436 io_close(file);
10437 ARGF.init_p = -1;
10438}
10439
10440static int
10441argf_next_argv(VALUE argf)
10442{
10443 char *fn;
10444 rb_io_t *fptr;
10445 int stdout_binmode = 0;
10446 enum rb_io_mode fmode;
10447
10448 VALUE r_stdout = rb_ractor_stdout();
10449
10450 if (RB_TYPE_P(r_stdout, T_FILE)) {
10451 GetOpenFile(r_stdout, fptr);
10452 if (fptr->mode & FMODE_BINMODE)
10453 stdout_binmode = 1;
10454 }
10455
10456 if (ARGF.init_p == 0) {
10457 if (!NIL_P(ARGF.argv) && RARRAY_LEN(ARGF.argv) > 0) {
10458 ARGF.next_p = 1;
10459 }
10460 else {
10461 ARGF.next_p = -1;
10462 }
10463 ARGF.init_p = 1;
10464 }
10465 else {
10466 if (NIL_P(ARGF.argv)) {
10467 ARGF.next_p = -1;
10468 }
10469 else if (ARGF.next_p == -1 && RARRAY_LEN(ARGF.argv) > 0) {
10470 ARGF.next_p = 1;
10471 }
10472 }
10473
10474 if (ARGF.next_p == 1) {
10475 if (ARGF.init_p == 1) argf_close(argf);
10476 retry:
10477 if (RARRAY_LEN(ARGF.argv) > 0) {
10478 VALUE filename = rb_ary_shift(ARGF.argv);
10479 FilePathValue(filename);
10480 ARGF_SET(filename, filename);
10481 filename = rb_str_encode_ospath(filename);
10482 fn = StringValueCStr(filename);
10483 if (RSTRING_LEN(filename) == 1 && fn[0] == '-') {
10484 ARGF_SET(current_file, rb_stdin);
10485 if (ARGF.inplace) {
10486 rb_warn("Can't do inplace edit for stdio; skipping");
10487 goto retry;
10488 }
10489 }
10490 else {
10491 VALUE write_io = Qnil;
10492 int fr = rb_sysopen(filename, O_RDONLY, 0);
10493
10494 if (ARGF.inplace) {
10495 struct stat st;
10496#ifndef NO_SAFE_RENAME
10497 struct stat st2;
10498#endif
10499 VALUE str;
10500 int fw;
10501
10502 if (RB_TYPE_P(r_stdout, T_FILE) && r_stdout != orig_stdout) {
10503 rb_io_close(r_stdout);
10504 }
10505 fstat(fr, &st);
10506 str = filename;
10507 if (!NIL_P(ARGF.inplace)) {
10508 VALUE suffix = ARGF.inplace;
10509 str = rb_str_dup(str);
10510 if (NIL_P(rb_str_cat_conv_enc_opts(str, RSTRING_LEN(str),
10511 RSTRING_PTR(suffix), RSTRING_LEN(suffix),
10512 rb_enc_get(suffix), 0, Qnil))) {
10513 rb_str_append(str, suffix);
10514 }
10515#ifdef NO_SAFE_RENAME
10516 (void)close(fr);
10517 (void)unlink(RSTRING_PTR(str));
10518 if (rename(fn, RSTRING_PTR(str)) < 0) {
10519 rb_warn("Can't rename %"PRIsVALUE" to %"PRIsVALUE": %s, skipping file",
10520 filename, str, strerror(errno));
10521 goto retry;
10522 }
10523 fr = rb_sysopen(str, O_RDONLY, 0);
10524#else
10525 if (rename(fn, RSTRING_PTR(str)) < 0) {
10526 rb_warn("Can't rename %"PRIsVALUE" to %"PRIsVALUE": %s, skipping file",
10527 filename, str, strerror(errno));
10528 close(fr);
10529 goto retry;
10530 }
10531#endif
10532 }
10533 else {
10534#ifdef NO_SAFE_RENAME
10535 rb_fatal("Can't do inplace edit without backup");
10536#else
10537 if (unlink(fn) < 0) {
10538 rb_warn("Can't remove %"PRIsVALUE": %s, skipping file",
10539 filename, strerror(errno));
10540 close(fr);
10541 goto retry;
10542 }
10543#endif
10544 }
10545 fw = rb_sysopen(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666);
10546#ifndef NO_SAFE_RENAME
10547 fstat(fw, &st2);
10548#ifdef HAVE_FCHMOD
10549 fchmod(fw, st.st_mode);
10550#else
10551 chmod(fn, st.st_mode);
10552#endif
10553 if (st.st_uid!=st2.st_uid || st.st_gid!=st2.st_gid) {
10554 int err;
10555#ifdef HAVE_FCHOWN
10556 err = fchown(fw, st.st_uid, st.st_gid);
10557#else
10558 err = chown(fn, st.st_uid, st.st_gid);
10559#endif
10560 if (err && getuid() == 0 && st2.st_uid == 0) {
10561 const char *wkfn = RSTRING_PTR(filename);
10562 rb_warn("Can't set owner/group of %"PRIsVALUE" to same as %"PRIsVALUE": %s, skipping file",
10563 filename, str, strerror(errno));
10564 (void)close(fr);
10565 (void)close(fw);
10566 (void)unlink(wkfn);
10567 goto retry;
10568 }
10569 }
10570#endif
10571 write_io = prep_io(fw, FMODE_WRITABLE, rb_cFile, fn);
10572 rb_ractor_stdout_set(write_io);
10573 if (stdout_binmode) rb_io_binmode(rb_stdout);
10574 }
10575 fmode = FMODE_READABLE;
10576 if (!ARGF.binmode) {
10577 fmode |= DEFAULT_TEXTMODE;
10578 }
10579 ARGF_SET(current_file, prep_io(fr, fmode, rb_cFile, fn));
10580 if (!NIL_P(write_io)) {
10581 rb_io_set_write_io(ARGF.current_file, write_io);
10582 }
10583 RB_GC_GUARD(filename);
10584 }
10585 if (ARGF.binmode) rb_io_ascii8bit_binmode(ARGF.current_file);
10586 GetOpenFile(ARGF.current_file, fptr);
10587 if (ARGF.encs.enc) {
10588 fptr->encs = ARGF.encs;
10589 clear_codeconv(fptr);
10590 }
10591 else {
10592 fptr->encs.ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
10593 if (!ARGF.binmode) {
10595#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
10596 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
10597#endif
10598 }
10599 }
10600 ARGF.next_p = 0;
10601 }
10602 else {
10603 ARGF.next_p = 1;
10604 return FALSE;
10605 }
10606 }
10607 else if (ARGF.next_p == -1) {
10608 ARGF_SET(current_file, rb_stdin);
10609 ARGF_SET(filename, rb_str_new2("-"));
10610 if (ARGF.inplace) {
10611 rb_warn("Can't do inplace edit for stdio");
10612 rb_ractor_stdout_set(orig_stdout);
10613 }
10614 }
10615 if (ARGF.init_p == -1) ARGF.init_p = 1;
10616 return TRUE;
10617}
10618
10619static VALUE
10620argf_getline(int argc, VALUE *argv, VALUE argf)
10621{
10622 VALUE line;
10623 long lineno = ARGF.lineno;
10624
10625 retry:
10626 if (!next_argv()) return Qnil;
10627 if (ARGF_GENERIC_INPUT_P()) {
10628 line = forward_current(idGets, argc, argv);
10629 }
10630 else {
10631 if (argc == 0 && rb_rs == rb_default_rs) {
10632 line = rb_io_gets(ARGF.current_file);
10633 }
10634 else {
10635 line = rb_io_getline(argc, argv, ARGF.current_file);
10636 }
10637 if (NIL_P(line) && ARGF.next_p != -1) {
10638 argf_close(argf);
10639 ARGF.next_p = 1;
10640 goto retry;
10641 }
10642 }
10643 if (!NIL_P(line)) {
10644 ARGF.lineno = ++lineno;
10645 ARGF.last_lineno = ARGF.lineno;
10646 }
10647 return line;
10648}
10649
10650static VALUE
10651argf_lineno_getter(ID id, VALUE *var)
10652{
10653 VALUE argf = *var;
10654 return INT2FIX(ARGF.last_lineno);
10655}
10656
10657static void
10658argf_lineno_setter(VALUE val, ID id, VALUE *var)
10659{
10660 VALUE argf = *var;
10661 int n = NUM2INT(val);
10662 ARGF.last_lineno = ARGF.lineno = n;
10663}
10664
10665void
10666rb_reset_argf_lineno(long n)
10667{
10668 ARGF.last_lineno = ARGF.lineno = n;
10669}
10670
10671static VALUE argf_gets(int, VALUE *, VALUE);
10672
10673/*
10674 * call-seq:
10675 * gets(sep=$/ [, getline_args]) -> string or nil
10676 * gets(limit [, getline_args]) -> string or nil
10677 * gets(sep, limit [, getline_args]) -> string or nil
10678 *
10679 * Returns (and assigns to <code>$_</code>) the next line from the list
10680 * of files in +ARGV+ (or <code>$*</code>), or from standard input if
10681 * no files are present on the command line. Returns +nil+ at end of
10682 * file. The optional argument specifies the record separator. The
10683 * separator is included with the contents of each record. A separator
10684 * of +nil+ reads the entire contents, and a zero-length separator
10685 * reads the input one paragraph at a time, where paragraphs are
10686 * divided by two consecutive newlines. If the first argument is an
10687 * integer, or optional second argument is given, the returning string
10688 * would not be longer than the given value in bytes. If multiple
10689 * filenames are present in +ARGV+, <code>gets(nil)</code> will read
10690 * the contents one file at a time.
10691 *
10692 * ARGV << "testfile"
10693 * print while gets
10694 *
10695 * <em>produces:</em>
10696 *
10697 * This is line one
10698 * This is line two
10699 * This is line three
10700 * And so on...
10701 *
10702 * The style of programming using <code>$_</code> as an implicit
10703 * parameter is gradually losing favor in the Ruby community.
10704 */
10705
10706static VALUE
10707rb_f_gets(int argc, VALUE *argv, VALUE recv)
10708{
10709 if (recv == argf) {
10710 return argf_gets(argc, argv, argf);
10711 }
10712 return forward(argf, idGets, argc, argv);
10713}
10714
10715/*
10716 * call-seq:
10717 * ARGF.gets(sep=$/ [, getline_args]) -> string or nil
10718 * ARGF.gets(limit [, getline_args]) -> string or nil
10719 * ARGF.gets(sep, limit [, getline_args]) -> string or nil
10720 *
10721 * Returns the next line from the current file in ARGF.
10722 *
10723 * By default lines are assumed to be separated by <code>$/</code>;
10724 * to use a different character as a separator, supply it as a String
10725 * for the _sep_ argument.
10726 *
10727 * The optional _limit_ argument specifies how many characters of each line
10728 * to return. By default all characters are returned.
10729 *
10730 * See IO.readlines for details about getline_args.
10731 *
10732 */
10733static VALUE
10734argf_gets(int argc, VALUE *argv, VALUE argf)
10735{
10736 VALUE line;
10737
10738 line = argf_getline(argc, argv, argf);
10739 rb_lastline_set(line);
10740
10741 return line;
10742}
10743
10744VALUE
10746{
10747 VALUE line;
10748
10749 if (rb_rs != rb_default_rs) {
10750 return rb_f_gets(0, 0, argf);
10751 }
10752
10753 retry:
10754 if (!next_argv()) return Qnil;
10755 line = rb_io_gets(ARGF.current_file);
10756 if (NIL_P(line) && ARGF.next_p != -1) {
10757 rb_io_close(ARGF.current_file);
10758 ARGF.next_p = 1;
10759 goto retry;
10760 }
10761 rb_lastline_set(line);
10762 if (!NIL_P(line)) {
10763 ARGF.lineno++;
10764 ARGF.last_lineno = ARGF.lineno;
10765 }
10766
10767 return line;
10768}
10769
10770static VALUE argf_readline(int, VALUE *, VALUE);
10771
10772/*
10773 * call-seq:
10774 * readline(sep = $/, chomp: false) -> string
10775 * readline(limit, chomp: false) -> string
10776 * readline(sep, limit, chomp: false) -> string
10777 *
10778 * Equivalent to method Kernel#gets, except that it raises an exception
10779 * if called at end-of-stream:
10780 *
10781 * $ cat t.txt | ruby -e "p readlines; readline"
10782 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10783 * in `readline': end of file reached (EOFError)
10784 *
10785 * Optional keyword argument +chomp+ specifies whether line separators
10786 * are to be omitted.
10787 */
10788
10789static VALUE
10790rb_f_readline(int argc, VALUE *argv, VALUE recv)
10791{
10792 if (recv == argf) {
10793 return argf_readline(argc, argv, argf);
10794 }
10795 return forward(argf, rb_intern("readline"), argc, argv);
10796}
10797
10798
10799/*
10800 * call-seq:
10801 * ARGF.readline(sep=$/) -> string
10802 * ARGF.readline(limit) -> string
10803 * ARGF.readline(sep, limit) -> string
10804 *
10805 * Returns the next line from the current file in ARGF.
10806 *
10807 * By default lines are assumed to be separated by <code>$/</code>;
10808 * to use a different character as a separator, supply it as a String
10809 * for the _sep_ argument.
10810 *
10811 * The optional _limit_ argument specifies how many characters of each line
10812 * to return. By default all characters are returned.
10813 *
10814 * An EOFError is raised at the end of the file.
10815 */
10816static VALUE
10817argf_readline(int argc, VALUE *argv, VALUE argf)
10818{
10819 VALUE line;
10820
10821 if (!next_argv()) rb_eof_error();
10822 ARGF_FORWARD(argc, argv);
10823 line = argf_gets(argc, argv, argf);
10824 if (NIL_P(line)) {
10825 rb_eof_error();
10826 }
10827
10828 return line;
10829}
10830
10831static VALUE argf_readlines(int, VALUE *, VALUE);
10832
10833/*
10834 * call-seq:
10835 * readlines(sep = $/, chomp: false, **enc_opts) -> array
10836 * readlines(limit, chomp: false, **enc_opts) -> array
10837 * readlines(sep, limit, chomp: false, **enc_opts) -> array
10838 *
10839 * Returns an array containing the lines returned by calling
10840 * Kernel#gets until the end-of-stream is reached;
10841 * (see {Line IO}[rdoc-ref:IO@Line+IO]).
10842 *
10843 * With only string argument +sep+ given,
10844 * returns the remaining lines as determined by line separator +sep+,
10845 * or +nil+ if none;
10846 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
10847 *
10848 * # Default separator.
10849 * $ cat t.txt | ruby -e "p readlines"
10850 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10851 *
10852 * # Specified separator.
10853 * $ cat t.txt | ruby -e "p readlines 'li'"
10854 * ["First li", "ne\nSecond li", "ne\n\nFourth li", "ne\nFifth li", "ne\n"]
10855 *
10856 * # Get-all separator.
10857 * $ cat t.txt | ruby -e "p readlines nil"
10858 * ["First line\nSecond line\n\nFourth line\nFifth line\n"]
10859 *
10860 * # Get-paragraph separator.
10861 * $ cat t.txt | ruby -e "p readlines ''"
10862 * ["First line\nSecond line\n\n", "Fourth line\nFifth line\n"]
10863 *
10864 * With only integer argument +limit+ given,
10865 * limits the number of bytes in the line;
10866 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
10867 *
10868 * $cat t.txt | ruby -e "p readlines 10"
10869 * ["First line", "\n", "Second lin", "e\n", "\n", "Fourth lin", "e\n", "Fifth line", "\n"]
10870 *
10871 * $cat t.txt | ruby -e "p readlines 11"
10872 * ["First line\n", "Second line", "\n", "\n", "Fourth line", "\n", "Fifth line\n"]
10873 *
10874 * $cat t.txt | ruby -e "p readlines 12"
10875 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10876 *
10877 * With arguments +sep+ and +limit+ given,
10878 * combines the two behaviors
10879 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
10880 *
10881 * Optional keyword argument +chomp+ specifies whether line separators
10882 * are to be omitted:
10883 *
10884 * $ cat t.txt | ruby -e "p readlines(chomp: true)"
10885 * ["First line", "Second line", "", "Fourth line", "Fifth line"]
10886 *
10887 * Optional keyword arguments +enc_opts+ specify encoding options;
10888 * see {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
10889 *
10890 */
10891
10892static VALUE
10893rb_f_readlines(int argc, VALUE *argv, VALUE recv)
10894{
10895 if (recv == argf) {
10896 return argf_readlines(argc, argv, argf);
10897 }
10898 return forward(argf, rb_intern("readlines"), argc, argv);
10899}
10900
10901/*
10902 * call-seq:
10903 * ARGF.readlines(sep = $/, chomp: false) -> array
10904 * ARGF.readlines(limit, chomp: false) -> array
10905 * ARGF.readlines(sep, limit, chomp: false) -> array
10906 *
10907 * ARGF.to_a(sep = $/, chomp: false) -> array
10908 * ARGF.to_a(limit, chomp: false) -> array
10909 * ARGF.to_a(sep, limit, chomp: false) -> array
10910 *
10911 * Reads each file in ARGF in its entirety, returning an Array containing
10912 * lines from the files. Lines are assumed to be separated by _sep_.
10913 *
10914 * lines = ARGF.readlines
10915 * lines[0] #=> "This is line one\n"
10916 *
10917 * See +IO.readlines+ for a full description of all options.
10918 */
10919static VALUE
10920argf_readlines(int argc, VALUE *argv, VALUE argf)
10921{
10922 long lineno = ARGF.lineno;
10923 VALUE lines, ary;
10924
10925 ary = rb_ary_new();
10926 while (next_argv()) {
10927 if (ARGF_GENERIC_INPUT_P()) {
10928 lines = forward_current(rb_intern("readlines"), argc, argv);
10929 }
10930 else {
10931 lines = rb_io_readlines(argc, argv, ARGF.current_file);
10932 argf_close(argf);
10933 }
10934 ARGF.next_p = 1;
10935 rb_ary_concat(ary, lines);
10936 ARGF.lineno = lineno + RARRAY_LEN(ary);
10937 ARGF.last_lineno = ARGF.lineno;
10938 }
10939 ARGF.init_p = 0;
10940 return ary;
10941}
10942
10943/*
10944 * call-seq:
10945 * `command` -> string
10946 *
10947 * Returns the <tt>$stdout</tt> output from running +command+ in a subshell;
10948 * sets global variable <tt>$?</tt> to the process status.
10949 *
10950 * This method has potential security vulnerabilities if called with untrusted input;
10951 * see {Command Injection}[rdoc-ref:security/command_injection.rdoc].
10952 *
10953 * Examples:
10954 *
10955 * $ `date` # => "Wed Apr 9 08:56:30 CDT 2003\n"
10956 * $ `echo oops && exit 99` # => "oops\n"
10957 * $ $? # => #<Process::Status: pid 17088 exit 99>
10958 * $ $?.exitstatus # => 99
10959 *
10960 * The built-in syntax <tt>%x{...}</tt> uses this method.
10961 *
10962 */
10963
10964static VALUE
10965rb_f_backquote(VALUE obj, VALUE str)
10966{
10967 VALUE port;
10968 VALUE result;
10969 rb_io_t *fptr;
10970
10971 StringValue(str);
10972 rb_last_status_clear();
10973 port = pipe_open_s(str, "r", FMODE_READABLE|DEFAULT_TEXTMODE, NULL);
10974 if (NIL_P(port)) return rb_str_new(0,0);
10975
10976 GetOpenFile(port, fptr);
10977 result = read_all(fptr, remain_size(fptr), Qnil);
10978 rb_io_close(port);
10979 rb_io_fptr_cleanup_all(fptr);
10980 RB_GC_GUARD(port);
10981
10982 return result;
10983}
10984
10985#ifdef HAVE_SYS_SELECT_H
10986#include <sys/select.h>
10987#endif
10988
10989static VALUE
10990select_internal(VALUE read, VALUE write, VALUE except, struct timeval *tp, rb_fdset_t *fds)
10991{
10992 VALUE res, list;
10993 rb_fdset_t *rp, *wp, *ep;
10994 rb_io_t *fptr;
10995 long i;
10996 int max = 0, n;
10997 int pending = 0;
10998 struct timeval timerec;
10999
11000 if (!NIL_P(read)) {
11001 Check_Type(read, T_ARRAY);
11002 for (i=0; i<RARRAY_LEN(read); i++) {
11003 GetOpenFile(rb_io_get_io(RARRAY_AREF(read, i)), fptr);
11004 rb_fd_set(fptr->fd, &fds[0]);
11005 if (READ_DATA_PENDING(fptr) || READ_CHAR_PENDING(fptr)) { /* check for buffered data */
11006 pending++;
11007 rb_fd_set(fptr->fd, &fds[3]);
11008 }
11009 if (max < fptr->fd) max = fptr->fd;
11010 }
11011 if (pending) { /* no blocking if there's buffered data */
11012 timerec.tv_sec = timerec.tv_usec = 0;
11013 tp = &timerec;
11014 }
11015 rp = &fds[0];
11016 }
11017 else
11018 rp = 0;
11019
11020 if (!NIL_P(write)) {
11021 Check_Type(write, T_ARRAY);
11022 for (i=0; i<RARRAY_LEN(write); i++) {
11023 VALUE write_io = GetWriteIO(rb_io_get_io(RARRAY_AREF(write, i)));
11024 GetOpenFile(write_io, fptr);
11025 rb_fd_set(fptr->fd, &fds[1]);
11026 if (max < fptr->fd) max = fptr->fd;
11027 }
11028 wp = &fds[1];
11029 }
11030 else
11031 wp = 0;
11032
11033 if (!NIL_P(except)) {
11034 Check_Type(except, T_ARRAY);
11035 for (i=0; i<RARRAY_LEN(except); i++) {
11036 VALUE io = rb_io_get_io(RARRAY_AREF(except, i));
11037 VALUE write_io = GetWriteIO(io);
11038 GetOpenFile(io, fptr);
11039 rb_fd_set(fptr->fd, &fds[2]);
11040 if (max < fptr->fd) max = fptr->fd;
11041 if (io != write_io) {
11042 GetOpenFile(write_io, fptr);
11043 rb_fd_set(fptr->fd, &fds[2]);
11044 if (max < fptr->fd) max = fptr->fd;
11045 }
11046 }
11047 ep = &fds[2];
11048 }
11049 else {
11050 ep = 0;
11051 }
11052
11053 max++;
11054
11055 n = rb_thread_fd_select(max, rp, wp, ep, tp);
11056 if (n < 0) {
11057 rb_sys_fail(0);
11058 }
11059 if (!pending && n == 0) return Qnil; /* returns nil on timeout */
11060
11061 res = rb_ary_new2(3);
11062 rb_ary_push(res, rp ? rb_ary_new_capa(RARRAY_LEN(read)) : rb_ary_new());
11063 rb_ary_push(res, wp ? rb_ary_new_capa(RARRAY_LEN(write)) : rb_ary_new());
11064 rb_ary_push(res, ep ? rb_ary_new_capa(RARRAY_LEN(except)) : rb_ary_new());
11065
11066 if (rp) {
11067 list = RARRAY_AREF(res, 0);
11068 for (i=0; i< RARRAY_LEN(read); i++) {
11069 VALUE obj = rb_ary_entry(read, i);
11070 VALUE io = rb_io_get_io(obj);
11071 GetOpenFile(io, fptr);
11072 if (rb_fd_isset(fptr->fd, &fds[0]) ||
11073 rb_fd_isset(fptr->fd, &fds[3])) {
11074 rb_ary_push(list, obj);
11075 }
11076 }
11077 }
11078
11079 if (wp) {
11080 list = RARRAY_AREF(res, 1);
11081 for (i=0; i< RARRAY_LEN(write); i++) {
11082 VALUE obj = rb_ary_entry(write, i);
11083 VALUE io = rb_io_get_io(obj);
11084 VALUE write_io = GetWriteIO(io);
11085 GetOpenFile(write_io, fptr);
11086 if (rb_fd_isset(fptr->fd, &fds[1])) {
11087 rb_ary_push(list, obj);
11088 }
11089 }
11090 }
11091
11092 if (ep) {
11093 list = RARRAY_AREF(res, 2);
11094 for (i=0; i< RARRAY_LEN(except); i++) {
11095 VALUE obj = rb_ary_entry(except, i);
11096 VALUE io = rb_io_get_io(obj);
11097 VALUE write_io = GetWriteIO(io);
11098 GetOpenFile(io, fptr);
11099 if (rb_fd_isset(fptr->fd, &fds[2])) {
11100 rb_ary_push(list, obj);
11101 }
11102 else if (io != write_io) {
11103 GetOpenFile(write_io, fptr);
11104 if (rb_fd_isset(fptr->fd, &fds[2])) {
11105 rb_ary_push(list, obj);
11106 }
11107 }
11108 }
11109 }
11110
11111 return res; /* returns an empty array on interrupt */
11112}
11113
11115 VALUE read, write, except;
11116 struct timeval *timeout;
11117 rb_fdset_t fdsets[4];
11118};
11119
11120static VALUE
11121select_call(VALUE arg)
11122{
11123 struct select_args *p = (struct select_args *)arg;
11124
11125 return select_internal(p->read, p->write, p->except, p->timeout, p->fdsets);
11126}
11127
11128static VALUE
11129select_end(VALUE arg)
11130{
11131 struct select_args *p = (struct select_args *)arg;
11132 int i;
11133
11134 for (i = 0; i < numberof(p->fdsets); ++i)
11135 rb_fd_term(&p->fdsets[i]);
11136 return Qnil;
11137}
11138
11139static VALUE sym_normal, sym_sequential, sym_random,
11140 sym_willneed, sym_dontneed, sym_noreuse;
11141
11142#ifdef HAVE_POSIX_FADVISE
11143struct io_advise_struct {
11144 int fd;
11145 int advice;
11146 rb_off_t offset;
11147 rb_off_t len;
11148};
11149
11150static VALUE
11151io_advise_internal(void *arg)
11152{
11153 struct io_advise_struct *ptr = arg;
11154 return posix_fadvise(ptr->fd, ptr->offset, ptr->len, ptr->advice);
11155}
11156
11157static VALUE
11158io_advise_sym_to_const(VALUE sym)
11159{
11160#ifdef POSIX_FADV_NORMAL
11161 if (sym == sym_normal)
11162 return INT2NUM(POSIX_FADV_NORMAL);
11163#endif
11164
11165#ifdef POSIX_FADV_RANDOM
11166 if (sym == sym_random)
11167 return INT2NUM(POSIX_FADV_RANDOM);
11168#endif
11169
11170#ifdef POSIX_FADV_SEQUENTIAL
11171 if (sym == sym_sequential)
11172 return INT2NUM(POSIX_FADV_SEQUENTIAL);
11173#endif
11174
11175#ifdef POSIX_FADV_WILLNEED
11176 if (sym == sym_willneed)
11177 return INT2NUM(POSIX_FADV_WILLNEED);
11178#endif
11179
11180#ifdef POSIX_FADV_DONTNEED
11181 if (sym == sym_dontneed)
11182 return INT2NUM(POSIX_FADV_DONTNEED);
11183#endif
11184
11185#ifdef POSIX_FADV_NOREUSE
11186 if (sym == sym_noreuse)
11187 return INT2NUM(POSIX_FADV_NOREUSE);
11188#endif
11189
11190 return Qnil;
11191}
11192
11193static VALUE
11194do_io_advise(rb_io_t *fptr, VALUE advice, rb_off_t offset, rb_off_t len)
11195{
11196 int rv;
11197 struct io_advise_struct ias;
11198 VALUE num_adv;
11199
11200 num_adv = io_advise_sym_to_const(advice);
11201
11202 /*
11203 * The platform doesn't support this hint. We don't raise exception, instead
11204 * silently ignore it. Because IO::advise is only hint.
11205 */
11206 if (NIL_P(num_adv))
11207 return Qnil;
11208
11209 ias.fd = fptr->fd;
11210 ias.advice = NUM2INT(num_adv);
11211 ias.offset = offset;
11212 ias.len = len;
11213
11214 rv = (int)rb_io_blocking_region(fptr, io_advise_internal, &ias);
11215 if (rv && rv != ENOSYS) {
11216 /* posix_fadvise(2) doesn't set errno. On success it returns 0; otherwise
11217 it returns the error code. */
11218 VALUE message = rb_sprintf("%"PRIsVALUE" "
11219 "(%"PRI_OFFT_PREFIX"d, "
11220 "%"PRI_OFFT_PREFIX"d, "
11221 "%"PRIsVALUE")",
11222 fptr->pathv, offset, len, advice);
11223 rb_syserr_fail_str(rv, message);
11224 }
11225
11226 return Qnil;
11227}
11228
11229#endif /* HAVE_POSIX_FADVISE */
11230
11231static void
11232advice_arg_check(VALUE advice)
11233{
11234 if (!SYMBOL_P(advice))
11235 rb_raise(rb_eTypeError, "advice must be a Symbol");
11236
11237 if (advice != sym_normal &&
11238 advice != sym_sequential &&
11239 advice != sym_random &&
11240 advice != sym_willneed &&
11241 advice != sym_dontneed &&
11242 advice != sym_noreuse) {
11243 rb_raise(rb_eNotImpError, "Unsupported advice: %+"PRIsVALUE, advice);
11244 }
11245}
11246
11247/*
11248 * call-seq:
11249 * advise(advice, offset = 0, len = 0) -> nil
11250 *
11251 * Invokes Posix system call
11252 * {posix_fadvise(2)}[https://man7.org/linux/man-pages/man2/posix_fadvise.2.html],
11253 * which announces an intention to access data from the current file
11254 * in a particular manner.
11255 *
11256 * The arguments and results are platform-dependent.
11257 *
11258 * The relevant data is specified by:
11259 *
11260 * - +offset+: The offset of the first byte of data.
11261 * - +len+: The number of bytes to be accessed;
11262 * if +len+ is zero, or is larger than the number of bytes remaining,
11263 * all remaining bytes will be accessed.
11264 *
11265 * Argument +advice+ is one of the following symbols:
11266 *
11267 * - +:normal+: The application has no advice to give
11268 * about its access pattern for the specified data.
11269 * If no advice is given for an open file, this is the default assumption.
11270 * - +:sequential+: The application expects to access the specified data sequentially
11271 * (with lower offsets read before higher ones).
11272 * - +:random+: The specified data will be accessed in random order.
11273 * - +:noreuse+: The specified data will be accessed only once.
11274 * - +:willneed+: The specified data will be accessed in the near future.
11275 * - +:dontneed+: The specified data will not be accessed in the near future.
11276 *
11277 * Not implemented on all platforms.
11278 *
11279 */
11280static VALUE
11281rb_io_advise(int argc, VALUE *argv, VALUE io)
11282{
11283 VALUE advice, offset, len;
11284 rb_off_t off, l;
11285 rb_io_t *fptr;
11286
11287 rb_scan_args(argc, argv, "12", &advice, &offset, &len);
11288 advice_arg_check(advice);
11289
11290 io = GetWriteIO(io);
11291 GetOpenFile(io, fptr);
11292
11293 off = NIL_P(offset) ? 0 : NUM2OFFT(offset);
11294 l = NIL_P(len) ? 0 : NUM2OFFT(len);
11295
11296#ifdef HAVE_POSIX_FADVISE
11297 return do_io_advise(fptr, advice, off, l);
11298#else
11299 ((void)off, (void)l); /* Ignore all hint */
11300 return Qnil;
11301#endif
11302}
11303
11304static int
11305is_pos_inf(VALUE x)
11306{
11307 double f;
11308 if (!RB_FLOAT_TYPE_P(x))
11309 return 0;
11310 f = RFLOAT_VALUE(x);
11311 return isinf(f) && 0 < f;
11312}
11313
11314/*
11315 * call-seq:
11316 * IO.select(read_ios, write_ios = [], error_ios = [], timeout = nil) -> array or nil
11317 *
11318 * Invokes system call {select(2)}[https://man7.org/linux/man-pages/man2/select.2.html],
11319 * which monitors multiple file descriptors,
11320 * waiting until one or more of the file descriptors
11321 * becomes ready for some class of I/O operation.
11322 *
11323 * Not implemented on all platforms.
11324 *
11325 * Each of the arguments +read_ios+, +write_ios+, and +error_ios+
11326 * is an array of IO objects.
11327 *
11328 * Argument +timeout+ is a numeric value (such as integer or float) timeout
11329 * interval in seconds.
11330 * +timeout+ can also be +nil+ or +Float::INFINITY+.
11331 * +nil+ and +Float::INFINITY+ means no timeout.
11332 *
11333 * The method monitors the \IO objects given in all three arrays,
11334 * waiting for some to be ready;
11335 * returns a 3-element array whose elements are:
11336 *
11337 * - An array of the objects in +read_ios+ that are ready for reading.
11338 * - An array of the objects in +write_ios+ that are ready for writing.
11339 * - An array of the objects in +error_ios+ have pending exceptions.
11340 *
11341 * If no object becomes ready within the given +timeout+, +nil+ is returned.
11342 *
11343 * \IO.select peeks the buffer of \IO objects for testing readability.
11344 * If the \IO buffer is not empty, \IO.select immediately notifies
11345 * readability. This "peek" only happens for \IO objects. It does not
11346 * happen for IO-like objects such as OpenSSL::SSL::SSLSocket.
11347 *
11348 * The best way to use \IO.select is invoking it after non-blocking
11349 * methods such as #read_nonblock, #write_nonblock, etc. The methods
11350 * raise an exception which is extended by IO::WaitReadable or
11351 * IO::WaitWritable. The modules notify how the caller should wait
11352 * with \IO.select. If IO::WaitReadable is raised, the caller should
11353 * wait for reading. If IO::WaitWritable is raised, the caller should
11354 * wait for writing.
11355 *
11356 * So, blocking read (#readpartial) can be emulated using
11357 * #read_nonblock and \IO.select as follows:
11358 *
11359 * begin
11360 * result = io_like.read_nonblock(maxlen)
11361 * rescue IO::WaitReadable
11362 * IO.select([io_like])
11363 * retry
11364 * rescue IO::WaitWritable
11365 * IO.select(nil, [io_like])
11366 * retry
11367 * end
11368 *
11369 * Especially, the combination of non-blocking methods and \IO.select is
11370 * preferred for IO like objects such as OpenSSL::SSL::SSLSocket. It
11371 * has #to_io method to return underlying IO object. IO.select calls
11372 * #to_io to obtain the file descriptor to wait.
11373 *
11374 * This means that readability notified by \IO.select doesn't mean
11375 * readability from OpenSSL::SSL::SSLSocket object.
11376 *
11377 * The most likely situation is that OpenSSL::SSL::SSLSocket buffers
11378 * some data. \IO.select doesn't see the buffer. So \IO.select can
11379 * block when OpenSSL::SSL::SSLSocket#readpartial doesn't block.
11380 *
11381 * However, several more complicated situations exist.
11382 *
11383 * SSL is a protocol which is sequence of records.
11384 * The record consists of multiple bytes.
11385 * So, the remote side of SSL sends a partial record, IO.select
11386 * notifies readability but OpenSSL::SSL::SSLSocket cannot decrypt a
11387 * byte and OpenSSL::SSL::SSLSocket#readpartial will block.
11388 *
11389 * Also, the remote side can request SSL renegotiation which forces
11390 * the local SSL engine to write some data.
11391 * This means OpenSSL::SSL::SSLSocket#readpartial may invoke #write
11392 * system call and it can block.
11393 * In such a situation, OpenSSL::SSL::SSLSocket#read_nonblock raises
11394 * IO::WaitWritable instead of blocking.
11395 * So, the caller should wait for ready for writability as above
11396 * example.
11397 *
11398 * The combination of non-blocking methods and \IO.select is also useful
11399 * for streams such as tty, pipe socket socket when multiple processes
11400 * read from a stream.
11401 *
11402 * Finally, Linux kernel developers don't guarantee that
11403 * readability of select(2) means readability of following read(2) even
11404 * for a single process;
11405 * see {select(2)}[https://man7.org/linux/man-pages/man2/select.2.html]
11406 *
11407 * Invoking \IO.select before IO#readpartial works well as usual.
11408 * However it is not the best way to use \IO.select.
11409 *
11410 * The writability notified by select(2) doesn't show
11411 * how many bytes are writable.
11412 * IO#write method blocks until given whole string is written.
11413 * So, <tt>IO#write(two or more bytes)</tt> can block after
11414 * writability is notified by \IO.select. IO#write_nonblock is required
11415 * to avoid the blocking.
11416 *
11417 * Blocking write (#write) can be emulated using #write_nonblock and
11418 * IO.select as follows: IO::WaitReadable should also be rescued for
11419 * SSL renegotiation in OpenSSL::SSL::SSLSocket.
11420 *
11421 * while 0 < string.bytesize
11422 * begin
11423 * written = io_like.write_nonblock(string)
11424 * rescue IO::WaitReadable
11425 * IO.select([io_like])
11426 * retry
11427 * rescue IO::WaitWritable
11428 * IO.select(nil, [io_like])
11429 * retry
11430 * end
11431 * string = string.byteslice(written..-1)
11432 * end
11433 *
11434 * Example:
11435 *
11436 * rp, wp = IO.pipe
11437 * mesg = "ping "
11438 * 100.times {
11439 * # IO.select follows IO#read. Not the best way to use IO.select.
11440 * rs, ws, = IO.select([rp], [wp])
11441 * if r = rs[0]
11442 * ret = r.read(5)
11443 * print ret
11444 * case ret
11445 * when /ping/
11446 * mesg = "pong\n"
11447 * when /pong/
11448 * mesg = "ping "
11449 * end
11450 * end
11451 * if w = ws[0]
11452 * w.write(mesg)
11453 * end
11454 * }
11455 *
11456 * Output:
11457 *
11458 * ping pong
11459 * ping pong
11460 * ping pong
11461 * (snipped)
11462 * ping
11463 *
11464 */
11465
11466static VALUE
11467rb_f_select(int argc, VALUE *argv, VALUE obj)
11468{
11469 VALUE scheduler = rb_fiber_scheduler_current();
11470 if (scheduler != Qnil) {
11471 // It's optionally supported.
11472 VALUE result = rb_fiber_scheduler_io_selectv(scheduler, argc, argv);
11473 if (!UNDEF_P(result)) return result;
11474 }
11475
11476 VALUE timeout;
11477 struct select_args args;
11478 struct timeval timerec;
11479 int i;
11480
11481 rb_scan_args(argc, argv, "13", &args.read, &args.write, &args.except, &timeout);
11482 if (NIL_P(timeout) || is_pos_inf(timeout)) {
11483 args.timeout = 0;
11484 }
11485 else {
11486 timerec = rb_time_interval(timeout);
11487 args.timeout = &timerec;
11488 }
11489
11490 for (i = 0; i < numberof(args.fdsets); ++i)
11491 rb_fd_init(&args.fdsets[i]);
11492
11493 return rb_ensure(select_call, (VALUE)&args, select_end, (VALUE)&args);
11494}
11495
11496#ifdef IOCTL_REQ_TYPE
11497 typedef IOCTL_REQ_TYPE ioctl_req_t;
11498#else
11499 typedef int ioctl_req_t;
11500# define NUM2IOCTLREQ(num) ((int)NUM2LONG(num))
11501#endif
11502
11503#ifdef HAVE_IOCTL
11504struct ioctl_arg {
11505 int fd;
11506 ioctl_req_t cmd;
11507 long narg;
11508};
11509
11510static VALUE
11511nogvl_ioctl(void *ptr)
11512{
11513 struct ioctl_arg *arg = ptr;
11514
11515 return (VALUE)ioctl(arg->fd, arg->cmd, arg->narg);
11516}
11517
11518static int
11519do_ioctl(struct rb_io *io, ioctl_req_t cmd, long narg)
11520{
11521 int retval;
11522 struct ioctl_arg arg;
11523
11524 arg.fd = io->fd;
11525 arg.cmd = cmd;
11526 arg.narg = narg;
11527
11528 retval = (int)rb_io_blocking_region(io, nogvl_ioctl, &arg);
11529
11530 return retval;
11531}
11532#endif
11533
11534#define DEFAULT_IOCTL_NARG_LEN (256)
11535
11536#if defined(__linux__) && defined(_IOC_SIZE)
11537static long
11538linux_iocparm_len(ioctl_req_t cmd)
11539{
11540 long len;
11541
11542 if ((cmd & 0xFFFF0000) == 0) {
11543 /* legacy and unstructured ioctl number. */
11544 return DEFAULT_IOCTL_NARG_LEN;
11545 }
11546
11547 len = _IOC_SIZE(cmd);
11548
11549 /* paranoia check for silly drivers which don't keep ioctl convention */
11550 if (len < DEFAULT_IOCTL_NARG_LEN)
11551 len = DEFAULT_IOCTL_NARG_LEN;
11552
11553 return len;
11554}
11555#endif
11556
11557#ifdef HAVE_IOCTL
11558static long
11559ioctl_narg_len(ioctl_req_t cmd)
11560{
11561 long len;
11562
11563#ifdef IOCPARM_MASK
11564#ifndef IOCPARM_LEN
11565#define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK)
11566#endif
11567#endif
11568#ifdef IOCPARM_LEN
11569 len = IOCPARM_LEN(cmd); /* on BSDish systems we're safe */
11570#elif defined(__linux__) && defined(_IOC_SIZE)
11571 len = linux_iocparm_len(cmd);
11572#else
11573 /* otherwise guess at what's safe */
11574 len = DEFAULT_IOCTL_NARG_LEN;
11575#endif
11576
11577 return len;
11578}
11579#endif
11580
11581#ifdef HAVE_FCNTL
11582#ifdef __linux__
11583typedef long fcntl_arg_t;
11584#else
11585/* posix */
11586typedef int fcntl_arg_t;
11587#endif
11588
11589static long
11590fcntl_narg_len(ioctl_req_t cmd)
11591{
11592 long len;
11593
11594 switch (cmd) {
11595#ifdef F_DUPFD
11596 case F_DUPFD:
11597 len = sizeof(fcntl_arg_t);
11598 break;
11599#endif
11600#ifdef F_DUP2FD /* bsd specific */
11601 case F_DUP2FD:
11602 len = sizeof(int);
11603 break;
11604#endif
11605#ifdef F_DUPFD_CLOEXEC /* linux specific */
11606 case F_DUPFD_CLOEXEC:
11607 len = sizeof(fcntl_arg_t);
11608 break;
11609#endif
11610#ifdef F_GETFD
11611 case F_GETFD:
11612 len = 1;
11613 break;
11614#endif
11615#ifdef F_SETFD
11616 case F_SETFD:
11617 len = sizeof(fcntl_arg_t);
11618 break;
11619#endif
11620#ifdef F_GETFL
11621 case F_GETFL:
11622 len = 1;
11623 break;
11624#endif
11625#ifdef F_SETFL
11626 case F_SETFL:
11627 len = sizeof(fcntl_arg_t);
11628 break;
11629#endif
11630#ifdef F_GETOWN
11631 case F_GETOWN:
11632 len = 1;
11633 break;
11634#endif
11635#ifdef F_SETOWN
11636 case F_SETOWN:
11637 len = sizeof(fcntl_arg_t);
11638 break;
11639#endif
11640#ifdef F_GETOWN_EX /* linux specific */
11641 case F_GETOWN_EX:
11642 len = sizeof(struct f_owner_ex);
11643 break;
11644#endif
11645#ifdef F_SETOWN_EX /* linux specific */
11646 case F_SETOWN_EX:
11647 len = sizeof(struct f_owner_ex);
11648 break;
11649#endif
11650#ifdef F_GETLK
11651 case F_GETLK:
11652 len = sizeof(struct flock);
11653 break;
11654#endif
11655#ifdef F_SETLK
11656 case F_SETLK:
11657 len = sizeof(struct flock);
11658 break;
11659#endif
11660#ifdef F_SETLKW
11661 case F_SETLKW:
11662 len = sizeof(struct flock);
11663 break;
11664#endif
11665#ifdef F_READAHEAD /* bsd specific */
11666 case F_READAHEAD:
11667 len = sizeof(int);
11668 break;
11669#endif
11670#ifdef F_RDAHEAD /* Darwin specific */
11671 case F_RDAHEAD:
11672 len = sizeof(int);
11673 break;
11674#endif
11675#ifdef F_GETSIG /* linux specific */
11676 case F_GETSIG:
11677 len = 1;
11678 break;
11679#endif
11680#ifdef F_SETSIG /* linux specific */
11681 case F_SETSIG:
11682 len = sizeof(fcntl_arg_t);
11683 break;
11684#endif
11685#ifdef F_GETLEASE /* linux specific */
11686 case F_GETLEASE:
11687 len = 1;
11688 break;
11689#endif
11690#ifdef F_SETLEASE /* linux specific */
11691 case F_SETLEASE:
11692 len = sizeof(fcntl_arg_t);
11693 break;
11694#endif
11695#ifdef F_NOTIFY /* linux specific */
11696 case F_NOTIFY:
11697 len = sizeof(fcntl_arg_t);
11698 break;
11699#endif
11700
11701 default:
11702 len = 256;
11703 break;
11704 }
11705
11706 return len;
11707}
11708#else /* HAVE_FCNTL */
11709static long
11710fcntl_narg_len(ioctl_req_t cmd)
11711{
11712 return 0;
11713}
11714#endif /* HAVE_FCNTL */
11715
11716#define NARG_SENTINEL 17
11717
11718static long
11719setup_narg(ioctl_req_t cmd, VALUE *argp, long (*narg_len)(ioctl_req_t))
11720{
11721 long narg = 0;
11722 VALUE arg = *argp;
11723
11724 if (!RTEST(arg)) {
11725 narg = 0;
11726 }
11727 else if (FIXNUM_P(arg)) {
11728 narg = FIX2LONG(arg);
11729 }
11730 else if (arg == Qtrue) {
11731 narg = 1;
11732 }
11733 else {
11734 VALUE tmp = rb_check_string_type(arg);
11735
11736 if (NIL_P(tmp)) {
11737 narg = NUM2LONG(arg);
11738 }
11739 else {
11740 char *ptr;
11741 long len, slen;
11742
11743 *argp = arg = tmp;
11744 len = narg_len(cmd);
11745 rb_str_modify(arg);
11746
11747 slen = RSTRING_LEN(arg);
11748 /* expand for data + sentinel. */
11749 if (slen < len+1) {
11750 rb_str_resize(arg, len+1);
11751 MEMZERO(RSTRING_PTR(arg)+slen, char, len-slen);
11752 slen = len+1;
11753 }
11754 /* a little sanity check here */
11755 ptr = RSTRING_PTR(arg);
11756 ptr[slen - 1] = NARG_SENTINEL;
11757 narg = (long)(SIGNED_VALUE)ptr;
11758 }
11759 }
11760
11761 return narg;
11762}
11763
11764static VALUE
11765finish_narg(int retval, VALUE arg, const rb_io_t *fptr)
11766{
11767 if (retval < 0) rb_sys_fail_path(fptr->pathv);
11768 if (RB_TYPE_P(arg, T_STRING)) {
11769 char *ptr;
11770 long slen;
11771 RSTRING_GETMEM(arg, ptr, slen);
11772 if (ptr[slen-1] != NARG_SENTINEL)
11773 rb_raise(rb_eArgError, "return value overflowed string");
11774 ptr[slen-1] = '\0';
11775 }
11776
11777 return INT2NUM(retval);
11778}
11779
11780#ifdef HAVE_IOCTL
11781static VALUE
11782rb_ioctl(VALUE io, VALUE req, VALUE arg)
11783{
11784 ioctl_req_t cmd = NUM2IOCTLREQ(req);
11785 rb_io_t *fptr;
11786 long narg;
11787 int retval;
11788
11789 narg = setup_narg(cmd, &arg, ioctl_narg_len);
11790 GetOpenFile(io, fptr);
11791 retval = do_ioctl(fptr, cmd, narg);
11792 return finish_narg(retval, arg, fptr);
11793}
11794
11795/*
11796 * call-seq:
11797 * ioctl(integer_cmd, argument) -> integer
11798 *
11799 * Invokes Posix system call {ioctl(2)}[https://man7.org/linux/man-pages/man2/ioctl.2.html],
11800 * which issues a low-level command to an I/O device.
11801 *
11802 * Issues a low-level command to an I/O device.
11803 * The arguments and returned value are platform-dependent.
11804 * The effect of the call is platform-dependent.
11805 *
11806 * If argument +argument+ is an integer, it is passed directly;
11807 * if it is a string, it is interpreted as a binary sequence of bytes.
11808 *
11809 * Not implemented on all platforms.
11810 *
11811 */
11812
11813static VALUE
11814rb_io_ioctl(int argc, VALUE *argv, VALUE io)
11815{
11816 VALUE req, arg;
11817
11818 rb_scan_args(argc, argv, "11", &req, &arg);
11819 return rb_ioctl(io, req, arg);
11820}
11821#else
11822#define rb_io_ioctl rb_f_notimplement
11823#endif
11824
11825#ifdef HAVE_FCNTL
11826struct fcntl_arg {
11827 int fd;
11828 int cmd;
11829 long narg;
11830};
11831
11832static VALUE
11833nogvl_fcntl(void *ptr)
11834{
11835 struct fcntl_arg *arg = ptr;
11836
11837#if defined(F_DUPFD)
11838 if (arg->cmd == F_DUPFD)
11839 return (VALUE)rb_cloexec_fcntl_dupfd(arg->fd, (int)arg->narg);
11840#endif
11841 return (VALUE)fcntl(arg->fd, arg->cmd, arg->narg);
11842}
11843
11844static int
11845do_fcntl(struct rb_io *io, int cmd, long narg)
11846{
11847 int retval;
11848 struct fcntl_arg arg;
11849
11850 arg.fd = io->fd;
11851 arg.cmd = cmd;
11852 arg.narg = narg;
11853
11854 retval = (int)rb_io_blocking_region(io, nogvl_fcntl, &arg);
11855 if (retval != -1) {
11856 switch (cmd) {
11857#if defined(F_DUPFD)
11858 case F_DUPFD:
11859#endif
11860#if defined(F_DUPFD_CLOEXEC)
11861 case F_DUPFD_CLOEXEC:
11862#endif
11863 rb_update_max_fd(retval);
11864 }
11865 }
11866
11867 return retval;
11868}
11869
11870static VALUE
11871rb_fcntl(VALUE io, VALUE req, VALUE arg)
11872{
11873 int cmd = NUM2INT(req);
11874 rb_io_t *fptr;
11875 long narg;
11876 int retval;
11877
11878 narg = setup_narg(cmd, &arg, fcntl_narg_len);
11879 GetOpenFile(io, fptr);
11880 retval = do_fcntl(fptr, cmd, narg);
11881 return finish_narg(retval, arg, fptr);
11882}
11883
11884/*
11885 * call-seq:
11886 * fcntl(integer_cmd, argument) -> integer
11887 *
11888 * Invokes Posix system call {fcntl(2)}[https://man7.org/linux/man-pages/man2/fcntl.2.html],
11889 * which provides a mechanism for issuing low-level commands to control or query
11890 * a file-oriented I/O stream. Arguments and results are platform
11891 * dependent.
11892 *
11893 * If +argument+ is a number, its value is passed directly;
11894 * if it is a string, it is interpreted as a binary sequence of bytes.
11895 * (Array#pack might be a useful way to build this string.)
11896 *
11897 * Not implemented on all platforms.
11898 *
11899 */
11900
11901static VALUE
11902rb_io_fcntl(int argc, VALUE *argv, VALUE io)
11903{
11904 VALUE req, arg;
11905
11906 rb_scan_args(argc, argv, "11", &req, &arg);
11907 return rb_fcntl(io, req, arg);
11908}
11909#else
11910#define rb_io_fcntl rb_f_notimplement
11911#endif
11912
11913#if defined(HAVE_SYSCALL) || defined(HAVE___SYSCALL)
11914/*
11915 * call-seq:
11916 * syscall(integer_callno, *arguments) -> integer
11917 *
11918 * Invokes Posix system call {syscall(2)}[https://man7.org/linux/man-pages/man2/syscall.2.html],
11919 * which calls a specified function.
11920 *
11921 * Calls the operating system function identified by +integer_callno+;
11922 * returns the result of the function or raises SystemCallError if it failed.
11923 * The effect of the call is platform-dependent.
11924 * The arguments and returned value are platform-dependent.
11925 *
11926 * For each of +arguments+: if it is an integer, it is passed directly;
11927 * if it is a string, it is interpreted as a binary sequence of bytes.
11928 * There may be as many as nine such arguments.
11929 *
11930 * Arguments +integer_callno+ and +argument+, as well as the returned value,
11931 * are platform-dependent.
11932 *
11933 * Note: Method +syscall+ is essentially unsafe and unportable.
11934 * The DL (Fiddle) library is preferred for safer and a bit
11935 * more portable programming.
11936 *
11937 * Not implemented on all platforms.
11938 *
11939 */
11940
11941static VALUE
11942rb_f_syscall(int argc, VALUE *argv, VALUE _)
11943{
11944 VALUE arg[8];
11945#if SIZEOF_VOIDP == 8 && defined(HAVE___SYSCALL) && SIZEOF_INT != 8 /* mainly *BSD */
11946# define SYSCALL __syscall
11947# define NUM2SYSCALLID(x) NUM2LONG(x)
11948# define RETVAL2NUM(x) LONG2NUM(x)
11949# if SIZEOF_LONG == 8
11950 long num, retval = -1;
11951# elif SIZEOF_LONG_LONG == 8
11952 long long num, retval = -1;
11953# else
11954# error ---->> it is asserted that __syscall takes the first argument and returns retval in 64bit signed integer. <<----
11955# endif
11956#elif defined(__linux__)
11957# define SYSCALL syscall
11958# define NUM2SYSCALLID(x) NUM2LONG(x)
11959# define RETVAL2NUM(x) LONG2NUM(x)
11960 /*
11961 * Linux man page says, syscall(2) function prototype is below.
11962 *
11963 * int syscall(int number, ...);
11964 *
11965 * But, it's incorrect. Actual one takes and returned long. (see unistd.h)
11966 */
11967 long num, retval = -1;
11968#else
11969# define SYSCALL syscall
11970# define NUM2SYSCALLID(x) NUM2INT(x)
11971# define RETVAL2NUM(x) INT2NUM(x)
11972 int num, retval = -1;
11973#endif
11974 int i;
11975
11976 if (RTEST(ruby_verbose)) {
11978 "We plan to remove a syscall function at future release. DL(Fiddle) provides safer alternative.");
11979 }
11980
11981 if (argc == 0)
11982 rb_raise(rb_eArgError, "too few arguments for syscall");
11983 if (argc > numberof(arg))
11984 rb_raise(rb_eArgError, "too many arguments for syscall");
11985 num = NUM2SYSCALLID(argv[0]); ++argv;
11986 for (i = argc - 1; i--; ) {
11987 VALUE v = rb_check_string_type(argv[i]);
11988
11989 if (!NIL_P(v)) {
11990 StringValue(v);
11991 rb_str_modify(v);
11992 arg[i] = (VALUE)StringValueCStr(v);
11993 }
11994 else {
11995 arg[i] = (VALUE)NUM2LONG(argv[i]);
11996 }
11997 }
11998
11999 switch (argc) {
12000 case 1:
12001 retval = SYSCALL(num);
12002 break;
12003 case 2:
12004 retval = SYSCALL(num, arg[0]);
12005 break;
12006 case 3:
12007 retval = SYSCALL(num, arg[0],arg[1]);
12008 break;
12009 case 4:
12010 retval = SYSCALL(num, arg[0],arg[1],arg[2]);
12011 break;
12012 case 5:
12013 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3]);
12014 break;
12015 case 6:
12016 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4]);
12017 break;
12018 case 7:
12019 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5]);
12020 break;
12021 case 8:
12022 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6]);
12023 break;
12024 }
12025
12026 if (retval == -1)
12027 rb_sys_fail(0);
12028 return RETVAL2NUM(retval);
12029#undef SYSCALL
12030#undef NUM2SYSCALLID
12031#undef RETVAL2NUM
12032}
12033#else
12034#define rb_f_syscall rb_f_notimplement
12035#endif
12036
12037static VALUE
12038io_new_instance(VALUE args)
12039{
12040 return rb_class_new_instance(2, (VALUE*)args+1, *(VALUE*)args);
12041}
12042
12043static rb_encoding *
12044find_encoding(VALUE v)
12045{
12046 rb_encoding *enc = rb_find_encoding(v);
12047 if (!enc) rb_warn("Unsupported encoding %"PRIsVALUE" ignored", v);
12048 return enc;
12049}
12050
12051static void
12052io_encoding_set(rb_io_t *fptr, VALUE v1, VALUE v2, VALUE opt)
12053{
12054 rb_encoding *enc, *enc2;
12055 int ecflags = fptr->encs.ecflags;
12056 VALUE ecopts, tmp;
12057
12058 if (!NIL_P(v2)) {
12059 enc2 = find_encoding(v1);
12060 tmp = rb_check_string_type(v2);
12061 if (!NIL_P(tmp)) {
12062 if (RSTRING_LEN(tmp) == 1 && RSTRING_PTR(tmp)[0] == '-') {
12063 /* Special case - "-" => no transcoding */
12064 enc = enc2;
12065 enc2 = NULL;
12066 }
12067 else
12068 enc = find_encoding(v2);
12069 if (enc == enc2) {
12070 /* Special case - "-" => no transcoding */
12071 enc2 = NULL;
12072 }
12073 }
12074 else {
12075 enc = find_encoding(v2);
12076 if (enc == enc2) {
12077 /* Special case - "-" => no transcoding */
12078 enc2 = NULL;
12079 }
12080 }
12081 if (enc2 == rb_ascii8bit_encoding()) {
12082 /* If external is ASCII-8BIT, no transcoding */
12083 enc = enc2;
12084 enc2 = NULL;
12085 }
12086 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
12087 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
12088 }
12089 else {
12090 if (NIL_P(v1)) {
12091 /* Set to default encodings */
12092 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
12093 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
12094 ecopts = Qnil;
12095 }
12096 else {
12097 tmp = rb_check_string_type(v1);
12098 if (!NIL_P(tmp) && rb_enc_asciicompat(enc = rb_enc_get(tmp))) {
12099 parse_mode_enc(RSTRING_PTR(tmp), enc, &enc, &enc2, NULL);
12100 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
12101 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
12102 }
12103 else {
12104 rb_io_ext_int_to_encs(find_encoding(v1), NULL, &enc, &enc2, 0);
12105 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
12106 ecopts = Qnil;
12107 }
12108 }
12109 }
12110 validate_enc_binmode(&fptr->mode, ecflags, enc, enc2);
12111 fptr->encs.enc = enc;
12112 fptr->encs.enc2 = enc2;
12113 fptr->encs.ecflags = ecflags;
12114 fptr->encs.ecopts = ecopts;
12115 clear_codeconv(fptr);
12116
12117}
12118
12120 rb_io_t *fptr;
12121 VALUE v1;
12122 VALUE v2;
12123 VALUE opt;
12124};
12125
12126static VALUE
12127io_encoding_set_v(VALUE v)
12128{
12129 struct io_encoding_set_args *arg = (struct io_encoding_set_args *)v;
12130 io_encoding_set(arg->fptr, arg->v1, arg->v2, arg->opt);
12131 return Qnil;
12132}
12133
12134static VALUE
12135pipe_pair_close(VALUE rw)
12136{
12137 VALUE *rwp = (VALUE *)rw;
12138 return rb_ensure(io_close, rwp[0], io_close, rwp[1]);
12139}
12140
12141/*
12142 * call-seq:
12143 * IO.pipe(**opts) -> [read_io, write_io]
12144 * IO.pipe(enc, **opts) -> [read_io, write_io]
12145 * IO.pipe(ext_enc, int_enc, **opts) -> [read_io, write_io]
12146 * IO.pipe(**opts) {|read_io, write_io| ...} -> object
12147 * IO.pipe(enc, **opts) {|read_io, write_io| ...} -> object
12148 * IO.pipe(ext_enc, int_enc, **opts) {|read_io, write_io| ...} -> object
12149 *
12150 * Creates a pair of pipe endpoints, +read_io+ and +write_io+,
12151 * connected to each other.
12152 *
12153 * If argument +enc_string+ is given, it must be a string containing one of:
12154 *
12155 * - The name of the encoding to be used as the external encoding.
12156 * - The colon-separated names of two encodings to be used as the external
12157 * and internal encodings.
12158 *
12159 * If argument +int_enc+ is given, it must be an Encoding object
12160 * or encoding name string that specifies the internal encoding to be used;
12161 * if argument +ext_enc+ is also given, it must be an Encoding object
12162 * or encoding name string that specifies the external encoding to be used.
12163 *
12164 * The string read from +read_io+ is tagged with the external encoding;
12165 * if an internal encoding is also specified, the string is converted
12166 * to, and tagged with, that encoding.
12167 *
12168 * If any encoding is specified,
12169 * optional hash arguments specify the conversion option.
12170 *
12171 * Optional keyword arguments +opts+ specify:
12172 *
12173 * - {Open Options}[rdoc-ref:IO@Open+Options].
12174 * - {Encoding Options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12175 *
12176 * With no block given, returns the two endpoints in an array:
12177 *
12178 * IO.pipe # => [#<IO:fd 4>, #<IO:fd 5>]
12179 *
12180 * With a block given, calls the block with the two endpoints;
12181 * closes both endpoints and returns the value of the block:
12182 *
12183 * IO.pipe {|read_io, write_io| p read_io; p write_io }
12184 *
12185 * Output:
12186 *
12187 * #<IO:fd 6>
12188 * #<IO:fd 7>
12189 *
12190 * Not available on all platforms.
12191 *
12192 * In the example below, the two processes close the ends of the pipe
12193 * that they are not using. This is not just a cosmetic nicety. The
12194 * read end of a pipe will not generate an end of file condition if
12195 * there are any writers with the pipe still open. In the case of the
12196 * parent process, the <tt>rd.read</tt> will never return if it
12197 * does not first issue a <tt>wr.close</tt>:
12198 *
12199 * rd, wr = IO.pipe
12200 *
12201 * if fork
12202 * wr.close
12203 * puts "Parent got: <#{rd.read}>"
12204 * rd.close
12205 * Process.wait
12206 * else
12207 * rd.close
12208 * puts 'Sending message to parent'
12209 * wr.write "Hi Dad"
12210 * wr.close
12211 * end
12212 *
12213 * <em>produces:</em>
12214 *
12215 * Sending message to parent
12216 * Parent got: <Hi Dad>
12217 *
12218 */
12219
12220static VALUE
12221rb_io_s_pipe(int argc, VALUE *argv, VALUE klass)
12222{
12223 int pipes[2], state;
12224 VALUE r, w, args[3], v1, v2;
12225 VALUE opt;
12226 rb_io_t *fptr, *fptr2;
12227 struct io_encoding_set_args ies_args;
12228 enum rb_io_mode fmode = 0;
12229 VALUE ret;
12230
12231 argc = rb_scan_args(argc, argv, "02:", &v1, &v2, &opt);
12232 if (rb_pipe(pipes) < 0)
12233 rb_sys_fail(0);
12234
12235 args[0] = klass;
12236 args[1] = INT2NUM(pipes[0]);
12237 args[2] = INT2FIX(O_RDONLY);
12238 r = rb_protect(io_new_instance, (VALUE)args, &state);
12239 if (state) {
12240 close(pipes[0]);
12241 close(pipes[1]);
12242 rb_jump_tag(state);
12243 }
12244 GetOpenFile(r, fptr);
12245
12246 ies_args.fptr = fptr;
12247 ies_args.v1 = v1;
12248 ies_args.v2 = v2;
12249 ies_args.opt = opt;
12250 rb_protect(io_encoding_set_v, (VALUE)&ies_args, &state);
12251 if (state) {
12252 close(pipes[1]);
12253 io_close(r);
12254 rb_jump_tag(state);
12255 }
12256
12257 args[1] = INT2NUM(pipes[1]);
12258 args[2] = INT2FIX(O_WRONLY);
12259 w = rb_protect(io_new_instance, (VALUE)args, &state);
12260 if (state) {
12261 close(pipes[1]);
12262 if (!NIL_P(r)) rb_io_close(r);
12263 rb_jump_tag(state);
12264 }
12265 GetOpenFile(w, fptr2);
12266 rb_io_synchronized(fptr2);
12267
12268 extract_binmode(opt, &fmode);
12269
12270 if ((fmode & FMODE_BINMODE) && NIL_P(v1)) {
12273 }
12274
12275#if DEFAULT_TEXTMODE
12276 if ((fptr->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
12277 fptr->mode &= ~FMODE_TEXTMODE;
12278 setmode(fptr->fd, O_BINARY);
12279 }
12280#if RUBY_CRLF_ENVIRONMENT
12283 }
12284#endif
12285#endif
12286 fptr->mode |= fmode;
12287#if DEFAULT_TEXTMODE
12288 if ((fptr2->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
12289 fptr2->mode &= ~FMODE_TEXTMODE;
12290 setmode(fptr2->fd, O_BINARY);
12291 }
12292#endif
12293 fptr2->mode |= fmode;
12294
12295 ret = rb_assoc_new(r, w);
12296 if (rb_block_given_p()) {
12297 VALUE rw[2];
12298 rw[0] = r;
12299 rw[1] = w;
12300 return rb_ensure(rb_yield, ret, pipe_pair_close, (VALUE)rw);
12301 }
12302 return ret;
12303}
12304
12306 int argc;
12307 VALUE *argv;
12308 VALUE io;
12309};
12310
12311static void
12312open_key_args(VALUE klass, int argc, VALUE *argv, VALUE opt, struct foreach_arg *arg)
12313{
12314 VALUE path, v;
12315 VALUE vmode = Qnil, vperm = Qnil;
12316
12317 path = *argv++;
12318 argc--;
12319 FilePathValue(path);
12320 arg->io = 0;
12321 arg->argc = argc;
12322 arg->argv = argv;
12323 if (NIL_P(opt)) {
12324 vmode = INT2NUM(O_RDONLY);
12325 vperm = INT2FIX(0666);
12326 }
12327 else if (!NIL_P(v = rb_hash_aref(opt, sym_open_args))) {
12328 int n;
12329
12330 v = rb_to_array_type(v);
12331 n = RARRAY_LENINT(v);
12332 rb_check_arity(n, 0, 3); /* rb_io_open */
12333 rb_scan_args_kw(RB_SCAN_ARGS_LAST_HASH_KEYWORDS, n, RARRAY_CONST_PTR(v), "02:", &vmode, &vperm, &opt);
12334 }
12335 arg->io = rb_io_open(klass, path, vmode, vperm, opt);
12336}
12337
12338static VALUE
12339io_s_foreach(VALUE v)
12340{
12341 struct getline_arg *arg = (void *)v;
12342 VALUE str;
12343
12344 if (arg->limit == 0)
12345 rb_raise(rb_eArgError, "invalid limit: 0 for foreach");
12346 while (!NIL_P(str = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, arg->io))) {
12347 rb_lastline_set(str);
12348 rb_yield(str);
12349 }
12351 return Qnil;
12352}
12353
12354/*
12355 * call-seq:
12356 * IO.foreach(path, sep = $/, **opts) {|line| block } -> nil
12357 * IO.foreach(path, limit, **opts) {|line| block } -> nil
12358 * IO.foreach(path, sep, limit, **opts) {|line| block } -> nil
12359 * IO.foreach(...) -> an_enumerator
12360 *
12361 * Calls the block with each successive line read from the stream.
12362 *
12363 * The first argument must be a string that is the path to a file.
12364 *
12365 * With only argument +path+ given, parses lines from the file at the given +path+,
12366 * as determined by the default line separator,
12367 * and calls the block with each successive line:
12368 *
12369 * File.foreach('t.txt') {|line| p line }
12370 *
12371 * Output: the same as above.
12372 *
12373 * For both forms, command and path, the remaining arguments are the same.
12374 *
12375 * With argument +sep+ given, parses lines as determined by that line separator
12376 * (see {Line Separator}[rdoc-ref:IO@Line+Separator]):
12377 *
12378 * File.foreach('t.txt', 'li') {|line| p line }
12379 *
12380 * Output:
12381 *
12382 * "First li"
12383 * "ne\nSecond li"
12384 * "ne\n\nThird li"
12385 * "ne\nFourth li"
12386 * "ne\n"
12387 *
12388 * Each paragraph:
12389 *
12390 * File.foreach('t.txt', '') {|paragraph| p paragraph }
12391 *
12392 * Output:
12393 *
12394 * "First line\nSecond line\n\n"
12395 * "Third line\nFourth line\n"
12396 *
12397 * With argument +limit+ given, parses lines as determined by the default
12398 * line separator and the given line-length limit
12399 * (see {Line Separator}[rdoc-ref:IO@Line+Separator] and {Line Limit}[rdoc-ref:IO@Line+Limit]):
12400 *
12401 * File.foreach('t.txt', 7) {|line| p line }
12402 *
12403 * Output:
12404 *
12405 * "First l"
12406 * "ine\n"
12407 * "Second "
12408 * "line\n"
12409 * "\n"
12410 * "Third l"
12411 * "ine\n"
12412 * "Fourth l"
12413 * "line\n"
12414 *
12415 * With arguments +sep+ and +limit+ given,
12416 * combines the two behaviors
12417 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
12418 *
12419 * Optional keyword arguments +opts+ specify:
12420 *
12421 * - {Open Options}[rdoc-ref:IO@Open+Options].
12422 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12423 * - {Line Input Options}[rdoc-ref:IO@Line+Input+Options].
12424 *
12425 * Returns an Enumerator if no block is given.
12426 *
12427 */
12428
12429static VALUE
12430rb_io_s_foreach(int argc, VALUE *argv, VALUE self)
12431{
12432 VALUE opt;
12433 int orig_argc = argc;
12434 struct foreach_arg arg;
12435 struct getline_arg garg;
12436
12437 argc = rb_scan_args(argc, argv, "12:", NULL, NULL, NULL, &opt);
12438 RETURN_ENUMERATOR(self, orig_argc, argv);
12439 extract_getline_args(argc-1, argv+1, &garg);
12440 open_key_args(self, argc, argv, opt, &arg);
12441 if (NIL_P(arg.io)) return Qnil;
12442 extract_getline_opts(opt, &garg);
12443 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12444 return rb_ensure(io_s_foreach, (VALUE)&garg, rb_io_close, arg.io);
12445}
12446
12447static VALUE
12448io_s_readlines(VALUE v)
12449{
12450 struct getline_arg *arg = (void *)v;
12451 return io_readlines(arg, arg->io);
12452}
12453
12454/*
12455 * call-seq:
12456 * IO.readlines(path, sep = $/, **opts) -> array
12457 * IO.readlines(path, limit, **opts) -> array
12458 * IO.readlines(path, sep, limit, **opts) -> array
12459 *
12460 * Returns an array of all lines read from the stream.
12461 *
12462 * The first argument must be a string that is the path to a file.
12463 *
12464 * With only argument +path+ given, parses lines from the file at the given +path+,
12465 * as determined by the default line separator,
12466 * and returns those lines in an array:
12467 *
12468 * IO.readlines('t.txt')
12469 * # => ["First line\n", "Second line\n", "\n", "Third line\n", "Fourth line\n"]
12470 *
12471 * With argument +sep+ given, parses lines as determined by that line separator
12472 * (see {Line Separator}[rdoc-ref:IO@Line+Separator]):
12473 *
12474 * # Ordinary separator.
12475 * IO.readlines('t.txt', 'li')
12476 * # =>["First li", "ne\nSecond li", "ne\n\nThird li", "ne\nFourth li", "ne\n"]
12477 * # Get-paragraphs separator.
12478 * IO.readlines('t.txt', '')
12479 * # => ["First line\nSecond line\n\n", "Third line\nFourth line\n"]
12480 * # Get-all separator.
12481 * IO.readlines('t.txt', nil)
12482 * # => ["First line\nSecond line\n\nThird line\nFourth line\n"]
12483 *
12484 * With argument +limit+ given, parses lines as determined by the default
12485 * line separator and the given line-length limit
12486 * (see {Line Separator}[rdoc-ref:IO@Line+Separator] and {Line Limit}[rdoc-ref:IO@Line+Limit]:
12487 *
12488 * IO.readlines('t.txt', 7)
12489 * # => ["First l", "ine\n", "Second ", "line\n", "\n", "Third l", "ine\n", "Fourth ", "line\n"]
12490 *
12491 * With arguments +sep+ and +limit+ given,
12492 * combines the two behaviors
12493 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
12494 *
12495 * Optional keyword arguments +opts+ specify:
12496 *
12497 * - {Open Options}[rdoc-ref:IO@Open+Options].
12498 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12499 * - {Line Input Options}[rdoc-ref:IO@Line+Input+Options].
12500 *
12501 */
12502
12503static VALUE
12504rb_io_s_readlines(int argc, VALUE *argv, VALUE io)
12505{
12506 VALUE opt;
12507 struct foreach_arg arg;
12508 struct getline_arg garg;
12509
12510 argc = rb_scan_args(argc, argv, "12:", NULL, NULL, NULL, &opt);
12511 extract_getline_args(argc-1, argv+1, &garg);
12512 open_key_args(io, argc, argv, opt, &arg);
12513 if (NIL_P(arg.io)) return Qnil;
12514 extract_getline_opts(opt, &garg);
12515 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12516 return rb_ensure(io_s_readlines, (VALUE)&garg, rb_io_close, arg.io);
12517}
12518
12519static VALUE
12520io_s_read(VALUE v)
12521{
12522 struct foreach_arg *arg = (void *)v;
12523 return io_read(arg->argc, arg->argv, arg->io);
12524}
12525
12526struct seek_arg {
12527 VALUE io;
12528 VALUE offset;
12529 int mode;
12530};
12531
12532static VALUE
12533seek_before_access(VALUE argp)
12534{
12535 struct seek_arg *arg = (struct seek_arg *)argp;
12536 rb_io_binmode(arg->io);
12537 return rb_io_seek(arg->io, arg->offset, arg->mode);
12538}
12539
12540/*
12541 * call-seq:
12542 * IO.read(path, length = nil, offset = 0, **opts) -> string or nil
12543 *
12544 * Opens the stream, reads and returns some or all of its content,
12545 * and closes the stream; returns +nil+ if no bytes were read.
12546 *
12547 * The first argument must be a string that is the path to a file.
12548 *
12549 * With only argument +path+ given, reads in text mode and returns the entire content
12550 * of the file at the given path:
12551 *
12552 * File.read('t.txt')
12553 * # => "First line\nSecond line\n\nFourth line\nFifth line\n"
12554 * File.read('t.ja')
12555 * # => "こんにちは"
12556 * File.read('t.dat')
12557 * # => "\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"
12558 *
12559 * On Windows, text mode can terminate reading and leave bytes in the file
12560 * unread when encountering certain special bytes. Consider using
12561 * IO.binread if all bytes in the file should be read.
12562 *
12563 * With argument +length+, returns +length+ bytes if available:
12564 *
12565 * File.read('t.txt', 7)
12566 * # => "First l"
12567 * File.read('t.ja', 7)
12568 * # => "\xE3\x81\x93\xE3\x82\x93\xE3"
12569 * File.read('t.dat', 7)
12570 * # => "\xFE\xFF\x99\x90\x99\x91\x99"
12571 *
12572 * Returns all bytes if +length+ is larger than the files size:
12573 *
12574 * File.read('t.txt', 700)
12575 * # => "First line\r\nSecond line\r\n\r\nFourth line\r\nFifth line\r\n"
12576 * File.read('t.ja', 700)
12577 * # => "\xE3\x81\x93\xE3\x82\x93\xE3\x81\xAB\xE3\x81\xA1\xE3\x81\xAF"
12578 * File.read('t.dat', 700)
12579 * # => "\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"
12580 *
12581 * With arguments +length+ and +offset+, returns +length+ bytes
12582 * if available, beginning at the given +offset+:
12583 *
12584 * File.read('t.txt', 10, 2)
12585 * # => "rst line\r\n"
12586 * File.read('t.ja', 10, 2)
12587 * # => "\x93\xE3\x82\x93\xE3\x81\xAB\xE3\x81\xA1"
12588 * File.read('t.dat', 10, 2)
12589 * # => "\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"
12590 *
12591 * Returns +nil+ if +offset+ is past the end of the stream:
12592 *
12593 * File.read('t.txt', 10, 200)
12594 * # => nil
12595 *
12596 * Optional keyword arguments +opts+ specify:
12597 *
12598 * - {Open Options}[rdoc-ref:IO@Open+Options].
12599 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12600 *
12601 */
12602
12603static VALUE
12604rb_io_s_read(int argc, VALUE *argv, VALUE io)
12605{
12606 VALUE opt, offset;
12607 long off;
12608 struct foreach_arg arg;
12609
12610 argc = rb_scan_args(argc, argv, "13:", NULL, NULL, &offset, NULL, &opt);
12611 if (!NIL_P(offset) && (off = NUM2LONG(offset)) < 0) {
12612 rb_raise(rb_eArgError, "negative offset %ld given", off);
12613 }
12614 open_key_args(io, argc, argv, opt, &arg);
12615 if (NIL_P(arg.io)) return Qnil;
12616 if (!NIL_P(offset)) {
12617 struct seek_arg sarg;
12618 int state = 0;
12619 sarg.io = arg.io;
12620 sarg.offset = offset;
12621 sarg.mode = SEEK_SET;
12622 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12623 if (state) {
12624 rb_io_close(arg.io);
12625 rb_jump_tag(state);
12626 }
12627 if (arg.argc == 2) arg.argc = 1;
12628 }
12629 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
12630}
12631
12632/*
12633 * call-seq:
12634 * IO.binread(path, length = nil, offset = 0) -> string or nil
12635 *
12636 * Behaves like IO.read, except that the stream is opened in binary mode
12637 * with ASCII-8BIT encoding.
12638 *
12639 */
12640
12641static VALUE
12642rb_io_s_binread(int argc, VALUE *argv, VALUE io)
12643{
12644 VALUE offset;
12645 struct foreach_arg arg;
12646 enum rb_io_mode fmode = FMODE_READABLE|FMODE_BINMODE;
12647 enum {
12648 oflags = O_RDONLY
12649#ifdef O_BINARY
12650 |O_BINARY
12651#endif
12652 };
12653 struct rb_io_encoding convconfig = {NULL, NULL, 0, Qnil};
12654
12655 rb_scan_args(argc, argv, "12", NULL, NULL, &offset);
12656 FilePathValue(argv[0]);
12657 convconfig.enc = rb_ascii8bit_encoding();
12658 arg.io = rb_io_open_generic(io, argv[0], oflags, fmode, &convconfig, 0);
12659 if (NIL_P(arg.io)) return Qnil;
12660 arg.argv = argv+1;
12661 arg.argc = (argc > 1) ? 1 : 0;
12662 if (!NIL_P(offset)) {
12663 struct seek_arg sarg;
12664 int state = 0;
12665 sarg.io = arg.io;
12666 sarg.offset = offset;
12667 sarg.mode = SEEK_SET;
12668 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12669 if (state) {
12670 rb_io_close(arg.io);
12671 rb_jump_tag(state);
12672 }
12673 }
12674 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
12675}
12676
12677static VALUE
12678io_s_write0(VALUE v)
12679{
12680 struct write_arg *arg = (void *)v;
12681 return io_write(arg->io,arg->str,arg->nosync);
12682}
12683
12684static VALUE
12685io_s_write(int argc, VALUE *argv, VALUE klass, int binary)
12686{
12687 VALUE string, offset, opt;
12688 struct foreach_arg arg;
12689 struct write_arg warg;
12690
12691 rb_scan_args(argc, argv, "21:", NULL, &string, &offset, &opt);
12692
12693 if (NIL_P(opt)) opt = rb_hash_new();
12694 else opt = rb_hash_dup(opt);
12695
12696
12697 if (NIL_P(rb_hash_aref(opt,sym_mode))) {
12698 int mode = O_WRONLY|O_CREAT;
12699#ifdef O_BINARY
12700 if (binary) mode |= O_BINARY;
12701#endif
12702 if (NIL_P(offset)) mode |= O_TRUNC;
12703 rb_hash_aset(opt,sym_mode,INT2NUM(mode));
12704 }
12705 open_key_args(klass, argc, argv, opt, &arg);
12706
12707#ifndef O_BINARY
12708 if (binary) rb_io_binmode_m(arg.io);
12709#endif
12710
12711 if (NIL_P(arg.io)) return Qnil;
12712 if (!NIL_P(offset)) {
12713 struct seek_arg sarg;
12714 int state = 0;
12715 sarg.io = arg.io;
12716 sarg.offset = offset;
12717 sarg.mode = SEEK_SET;
12718 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12719 if (state) {
12720 rb_io_close(arg.io);
12721 rb_jump_tag(state);
12722 }
12723 }
12724
12725 warg.io = arg.io;
12726 warg.str = string;
12727 warg.nosync = 0;
12728
12729 return rb_ensure(io_s_write0, (VALUE)&warg, rb_io_close, arg.io);
12730}
12731
12732/*
12733 * call-seq:
12734 * IO.write(path, data, offset = 0, **opts) -> nonnegative_integer
12735 *
12736 * Opens the stream, writes the given +data+ to it,
12737 * and closes the stream; returns the number of bytes written.
12738 *
12739 * The first argument must be a string that is the path to a file.
12740 *
12741 * With only arguments +path+ and +data+ given,
12742 * writes the given data to the file at that path:
12743 *
12744 * path = 't.tmp'
12745 * File.write(path, "First line\nSecond line\n\nFourth line\nFifth line\n") # => 47
12746 * File.write(path, 'こんにちは') # => 15
12747 * File.write(path, "\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94") # => 12
12748 *
12749 * When +offset+ is zero (the default), the entire file content is overwritten:
12750 *
12751 * File.read(path) # => "\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"
12752 * File.write(path, 'foo')
12753 * File.read(path) # => "foo"
12754 *
12755 * When +offset+ in within the file content, the file content is partly overwritten,
12756 * beginning at byte +offset+:
12757 *
12758 * File.write(path, "First line\nSecond line\n\nFourth line\nFifth line\n")
12759 * File.write(path, 'LINE', 6)
12760 * File.read(path) # => "First LINE\nSecond line\n\nFourth line\nFifth line\n"
12761 *
12762 * When the file contains multi-byte characters,
12763 * the effect of writing may disturb some characters:
12764 *
12765 * File.write(path, "こんにちは")
12766 * File.write(path, 'FOO', 3) # Replace one 3-byte character.
12767 * File.read(path) # => "こFOOにちは"
12768 * File.write(path, 'BAR', 7) # Replace bytes in two different 3-byte characters.
12769 * File.read(path) # => "こFOO\xE3BAR\x81\xA1は"
12770 *
12771 * If +offset+ is outside the file content,
12772 * the file is padded with null characters <tt>"\u0000"</tt>:
12773 *
12774 * File.write(path, "First line\nSecond line\n\nFourth line\nFifth line\n")
12775 * File.write(path, 'FOO', 55)
12776 * File.read(path)
12777 * # => "First line\nSecond line\n\nFourth line\nFifth line\n\u0000\u0000\u0000FOO"
12778 *
12779 * Optional keyword arguments +opts+ specify:
12780 *
12781 * - {Open Options}[rdoc-ref:IO@Open+Options].
12782 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12783 *
12784 */
12785
12786static VALUE
12787rb_io_s_write(int argc, VALUE *argv, VALUE io)
12788{
12789 return io_s_write(argc, argv, io, 0);
12790}
12791
12792/*
12793 * call-seq:
12794 * IO.binwrite(path, string, offset = 0, **opts) -> integer
12795 *
12796 * Behaves like IO.write, except that the stream is opened in binary mode
12797 * with ASCII-8BIT encoding.
12798 *
12799 */
12800
12801static VALUE
12802rb_io_s_binwrite(int argc, VALUE *argv, VALUE io)
12803{
12804 return io_s_write(argc, argv, io, 1);
12805}
12806
12808 VALUE src;
12809 VALUE dst;
12810 rb_off_t copy_length; /* (rb_off_t)-1 if not specified */
12811 rb_off_t src_offset; /* (rb_off_t)-1 if not specified */
12812
12813 rb_io_t *src_fptr;
12814 rb_io_t *dst_fptr;
12815 unsigned close_src : 1;
12816 unsigned close_dst : 1;
12817 int error_no;
12818 rb_off_t total;
12819 const char *syserr;
12820 const char *notimp;
12821 VALUE th;
12822 struct stat src_stat;
12823 struct stat dst_stat;
12824#ifdef HAVE_FCOPYFILE
12825 copyfile_state_t copyfile_state;
12826#endif
12827};
12828
12829static void *
12830exec_interrupts(void *arg)
12831{
12832 VALUE th = (VALUE)arg;
12833 rb_thread_execute_interrupts(th);
12834 return NULL;
12835}
12836
12837/*
12838 * returns TRUE if the preceding system call was interrupted
12839 * so we can continue. If the thread was interrupted, we
12840 * reacquire the GVL to execute interrupts before continuing.
12841 */
12842static int
12843maygvl_copy_stream_continue_p(int has_gvl, struct copy_stream_struct *stp)
12844{
12845 switch (errno) {
12846 case EINTR:
12847#if defined(ERESTART)
12848 case ERESTART:
12849#endif
12850 if (rb_thread_interrupted(stp->th)) {
12851 if (has_gvl)
12852 rb_thread_execute_interrupts(stp->th);
12853 else
12854 rb_thread_call_with_gvl(exec_interrupts, (void *)stp->th);
12855 }
12856 return TRUE;
12857 }
12858 return FALSE;
12859}
12860
12862 VALUE scheduler;
12863
12864 rb_io_t *fptr;
12865 short events;
12866
12867 VALUE result;
12868};
12869
12870static void *
12871fiber_scheduler_wait_for(void * _arguments)
12872{
12873 struct fiber_scheduler_wait_for_arguments *arguments = (struct fiber_scheduler_wait_for_arguments *)_arguments;
12874
12875 arguments->result = rb_fiber_scheduler_io_wait(arguments->scheduler, arguments->fptr->self, INT2NUM(arguments->events), RUBY_IO_TIMEOUT_DEFAULT);
12876
12877 return NULL;
12878}
12879
12880#if USE_POLL
12881# define IOWAIT_SYSCALL "poll"
12882STATIC_ASSERT(pollin_expected, POLLIN == RB_WAITFD_IN);
12883STATIC_ASSERT(pollout_expected, POLLOUT == RB_WAITFD_OUT);
12884static int
12885nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout)
12886{
12888 if (scheduler != Qnil) {
12889 struct fiber_scheduler_wait_for_arguments args = {.scheduler = scheduler, .fptr = fptr, .events = events};
12890 rb_thread_call_with_gvl(fiber_scheduler_wait_for, &args);
12891 return RTEST(args.result);
12892 }
12893
12894 int fd = fptr->fd;
12895 if (fd == -1) return 0;
12896
12897 struct pollfd fds;
12898
12899 fds.fd = fd;
12900 fds.events = events;
12901
12902 int timeout_milliseconds = -1;
12903
12904 if (timeout) {
12905 timeout_milliseconds = (int)(timeout->tv_sec * 1000) + (int)(timeout->tv_usec / 1000);
12906 }
12907
12908 return poll(&fds, 1, timeout_milliseconds);
12909}
12910#else /* !USE_POLL */
12911# define IOWAIT_SYSCALL "select"
12912static int
12913nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout)
12914{
12916 if (scheduler != Qnil) {
12917 struct fiber_scheduler_wait_for_arguments args = {.scheduler = scheduler, .fptr = fptr, .events = events};
12918 rb_thread_call_with_gvl(fiber_scheduler_wait_for, &args);
12919 return RTEST(args.result);
12920 }
12921
12922 int fd = fptr->fd;
12923
12924 if (fd == -1) {
12925 errno = EBADF;
12926 return -1;
12927 }
12928
12929 rb_fdset_t fds;
12930 int ret;
12931
12932 rb_fd_init(&fds);
12933 rb_fd_set(fd, &fds);
12934
12935 switch (events) {
12936 case RB_WAITFD_IN:
12937 ret = rb_fd_select(fd + 1, &fds, 0, 0, timeout);
12938 break;
12939 case RB_WAITFD_OUT:
12940 ret = rb_fd_select(fd + 1, 0, &fds, 0, timeout);
12941 break;
12942 default:
12943 VM_UNREACHABLE(nogvl_wait_for);
12944 }
12945
12946 rb_fd_term(&fds);
12947
12948 // On timeout, this returns 0.
12949 return ret;
12950}
12951#endif /* !USE_POLL */
12952
12953static int
12954maygvl_copy_stream_wait_read(int has_gvl, struct copy_stream_struct *stp)
12955{
12956 int ret;
12957
12958 do {
12959 if (has_gvl) {
12961 }
12962 else {
12963 ret = nogvl_wait_for(stp->th, stp->src_fptr, RB_WAITFD_IN, NULL);
12964 }
12965 } while (ret < 0 && maygvl_copy_stream_continue_p(has_gvl, stp));
12966
12967 if (ret < 0) {
12968 stp->syserr = IOWAIT_SYSCALL;
12969 stp->error_no = errno;
12970 return ret;
12971 }
12972 return 0;
12973}
12974
12975static int
12976nogvl_copy_stream_wait_write(struct copy_stream_struct *stp)
12977{
12978 int ret;
12979
12980 do {
12981 ret = nogvl_wait_for(stp->th, stp->dst_fptr, RB_WAITFD_OUT, NULL);
12982 } while (ret < 0 && maygvl_copy_stream_continue_p(0, stp));
12983
12984 if (ret < 0) {
12985 stp->syserr = IOWAIT_SYSCALL;
12986 stp->error_no = errno;
12987 return ret;
12988 }
12989 return 0;
12990}
12991
12992#ifdef USE_COPY_FILE_RANGE
12993
12994static ssize_t
12995simple_copy_file_range(int in_fd, rb_off_t *in_offset, int out_fd, rb_off_t *out_offset, size_t count, unsigned int flags)
12996{
12997#ifdef HAVE_COPY_FILE_RANGE
12998 return copy_file_range(in_fd, in_offset, out_fd, out_offset, count, flags);
12999#else
13000 return syscall(__NR_copy_file_range, in_fd, in_offset, out_fd, out_offset, count, flags);
13001#endif
13002}
13003
13004static int
13005nogvl_copy_file_range(struct copy_stream_struct *stp)
13006{
13007 ssize_t ss;
13008 rb_off_t src_size;
13009 rb_off_t copy_length, src_offset, *src_offset_ptr;
13010
13011 if (!S_ISREG(stp->src_stat.st_mode))
13012 return 0;
13013
13014 src_size = stp->src_stat.st_size;
13015 src_offset = stp->src_offset;
13016 if (src_offset >= (rb_off_t)0) {
13017 src_offset_ptr = &src_offset;
13018 }
13019 else {
13020 src_offset_ptr = NULL; /* if src_offset_ptr is NULL, then bytes are read from in_fd starting from the file offset */
13021 }
13022
13023 copy_length = stp->copy_length;
13024 if (copy_length < (rb_off_t)0) {
13025 if (src_offset < (rb_off_t)0) {
13026 rb_off_t current_offset;
13027 errno = 0;
13028 current_offset = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
13029 if (current_offset < (rb_off_t)0 && errno) {
13030 stp->syserr = "lseek";
13031 stp->error_no = errno;
13032 return (int)current_offset;
13033 }
13034 copy_length = src_size - current_offset;
13035 }
13036 else {
13037 copy_length = src_size - src_offset;
13038 }
13039 }
13040
13041 retry_copy_file_range:
13042# if SIZEOF_OFF_T > SIZEOF_SIZE_T
13043 /* we are limited by the 32-bit ssize_t return value on 32-bit */
13044 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
13045# else
13046 ss = (ssize_t)copy_length;
13047# endif
13048 ss = simple_copy_file_range(stp->src_fptr->fd, src_offset_ptr, stp->dst_fptr->fd, NULL, ss, 0);
13049 if (0 < ss) {
13050 stp->total += ss;
13051 copy_length -= ss;
13052 if (0 < copy_length) {
13053 goto retry_copy_file_range;
13054 }
13055 }
13056 if (ss < 0) {
13057 if (maygvl_copy_stream_continue_p(0, stp)) {
13058 goto retry_copy_file_range;
13059 }
13060 switch (errno) {
13061 case EINVAL:
13062 case EPERM: /* copy_file_range(2) doesn't exist (may happen in
13063 docker container) */
13064#ifdef ENOSYS
13065 case ENOSYS:
13066#endif
13067#ifdef EXDEV
13068 case EXDEV: /* in_fd and out_fd are not on the same filesystem */
13069#endif
13070 return 0;
13071 case EAGAIN:
13072#if EWOULDBLOCK != EAGAIN
13073 case EWOULDBLOCK:
13074#endif
13075 {
13076 int ret = nogvl_copy_stream_wait_write(stp);
13077 if (ret < 0) return ret;
13078 }
13079 goto retry_copy_file_range;
13080 case EBADF:
13081 {
13082 int e = errno;
13083 int flags = fcntl(stp->dst_fptr->fd, F_GETFL);
13084
13085 if (flags != -1 && flags & O_APPEND) {
13086 return 0;
13087 }
13088 errno = e;
13089 }
13090 }
13091 stp->syserr = "copy_file_range";
13092 stp->error_no = errno;
13093 return (int)ss;
13094 }
13095 return 1;
13096}
13097#endif
13098
13099#ifdef HAVE_FCOPYFILE
13100static int
13101nogvl_fcopyfile(struct copy_stream_struct *stp)
13102{
13103 rb_off_t cur, ss = 0;
13104 const rb_off_t src_offset = stp->src_offset;
13105 int ret;
13106
13107 if (stp->copy_length >= (rb_off_t)0) {
13108 /* copy_length can't be specified in fcopyfile(3) */
13109 return 0;
13110 }
13111
13112 if (!S_ISREG(stp->src_stat.st_mode))
13113 return 0;
13114
13115 if (!S_ISREG(stp->dst_stat.st_mode))
13116 return 0;
13117 if (lseek(stp->dst_fptr->fd, 0, SEEK_CUR) > (rb_off_t)0) /* if dst IO was already written */
13118 return 0;
13119 if (fcntl(stp->dst_fptr->fd, F_GETFL) & O_APPEND) {
13120 /* fcopyfile(3) appends src IO to dst IO and then truncates
13121 * dst IO to src IO's original size. */
13122 rb_off_t end = lseek(stp->dst_fptr->fd, 0, SEEK_END);
13123 lseek(stp->dst_fptr->fd, 0, SEEK_SET);
13124 if (end > (rb_off_t)0) return 0;
13125 }
13126
13127 if (src_offset > (rb_off_t)0) {
13128 rb_off_t r;
13129
13130 /* get current offset */
13131 errno = 0;
13132 cur = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
13133 if (cur < (rb_off_t)0 && errno) {
13134 stp->error_no = errno;
13135 return 1;
13136 }
13137
13138 errno = 0;
13139 r = lseek(stp->src_fptr->fd, src_offset, SEEK_SET);
13140 if (r < (rb_off_t)0 && errno) {
13141 stp->error_no = errno;
13142 return 1;
13143 }
13144 }
13145
13146 stp->copyfile_state = copyfile_state_alloc(); /* this will be freed by copy_stream_finalize() */
13147 ret = fcopyfile(stp->src_fptr->fd, stp->dst_fptr->fd, stp->copyfile_state, COPYFILE_DATA);
13148 copyfile_state_get(stp->copyfile_state, COPYFILE_STATE_COPIED, &ss); /* get copied bytes */
13149
13150 if (ret == 0) { /* success */
13151 stp->total = ss;
13152 if (src_offset > (rb_off_t)0) {
13153 rb_off_t r;
13154 errno = 0;
13155 /* reset offset */
13156 r = lseek(stp->src_fptr->fd, cur, SEEK_SET);
13157 if (r < (rb_off_t)0 && errno) {
13158 stp->error_no = errno;
13159 return 1;
13160 }
13161 }
13162 }
13163 else {
13164 switch (errno) {
13165 case ENOTSUP:
13166 case EPERM:
13167 case EINVAL:
13168 return 0;
13169 }
13170 stp->syserr = "fcopyfile";
13171 stp->error_no = errno;
13172 return (int)ret;
13173 }
13174 return 1;
13175}
13176#endif
13177
13178#ifdef HAVE_SENDFILE
13179
13180# ifdef __linux__
13181# define USE_SENDFILE
13182
13183# ifdef HAVE_SYS_SENDFILE_H
13184# include <sys/sendfile.h>
13185# endif
13186
13187static ssize_t
13188simple_sendfile(int out_fd, int in_fd, rb_off_t *offset, rb_off_t count)
13189{
13190 return sendfile(out_fd, in_fd, offset, (size_t)count);
13191}
13192
13193# elif 0 /* defined(__FreeBSD__) || defined(__DragonFly__) */ || defined(__APPLE__)
13194/* This runs on FreeBSD8.1 r30210, but sendfiles blocks its execution
13195 * without cpuset -l 0.
13196 */
13197# define USE_SENDFILE
13198
13199static ssize_t
13200simple_sendfile(int out_fd, int in_fd, rb_off_t *offset, rb_off_t count)
13201{
13202 int r;
13203 rb_off_t pos = offset ? *offset : lseek(in_fd, 0, SEEK_CUR);
13204 rb_off_t sbytes;
13205# ifdef __APPLE__
13206 r = sendfile(in_fd, out_fd, pos, &count, NULL, 0);
13207 sbytes = count;
13208# else
13209 r = sendfile(in_fd, out_fd, pos, (size_t)count, NULL, &sbytes, 0);
13210# endif
13211 if (r != 0 && sbytes == 0) return r;
13212 if (offset) {
13213 *offset += sbytes;
13214 }
13215 else {
13216 lseek(in_fd, sbytes, SEEK_CUR);
13217 }
13218 return (ssize_t)sbytes;
13219}
13220
13221# endif
13222
13223#endif
13224
13225#ifdef USE_SENDFILE
13226static int
13227nogvl_copy_stream_sendfile(struct copy_stream_struct *stp)
13228{
13229 ssize_t ss;
13230 rb_off_t src_size;
13231 rb_off_t copy_length;
13232 rb_off_t src_offset;
13233 int use_pread;
13234
13235 if (!S_ISREG(stp->src_stat.st_mode))
13236 return 0;
13237
13238 src_size = stp->src_stat.st_size;
13239#ifndef __linux__
13240 if ((stp->dst_stat.st_mode & S_IFMT) != S_IFSOCK)
13241 return 0;
13242#endif
13243
13244 src_offset = stp->src_offset;
13245 use_pread = src_offset >= (rb_off_t)0;
13246
13247 copy_length = stp->copy_length;
13248 if (copy_length < (rb_off_t)0) {
13249 if (use_pread)
13250 copy_length = src_size - src_offset;
13251 else {
13252 rb_off_t cur;
13253 errno = 0;
13254 cur = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
13255 if (cur < (rb_off_t)0 && errno) {
13256 stp->syserr = "lseek";
13257 stp->error_no = errno;
13258 return (int)cur;
13259 }
13260 copy_length = src_size - cur;
13261 }
13262 }
13263
13264 retry_sendfile:
13265# if SIZEOF_OFF_T > SIZEOF_SIZE_T
13266 /* we are limited by the 32-bit ssize_t return value on 32-bit */
13267 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
13268# else
13269 ss = (ssize_t)copy_length;
13270# endif
13271 if (use_pread) {
13272 ss = simple_sendfile(stp->dst_fptr->fd, stp->src_fptr->fd, &src_offset, ss);
13273 }
13274 else {
13275 ss = simple_sendfile(stp->dst_fptr->fd, stp->src_fptr->fd, NULL, ss);
13276 }
13277 if (0 < ss) {
13278 stp->total += ss;
13279 copy_length -= ss;
13280 if (0 < copy_length) {
13281 goto retry_sendfile;
13282 }
13283 }
13284 if (ss < 0) {
13285 if (maygvl_copy_stream_continue_p(0, stp))
13286 goto retry_sendfile;
13287 switch (errno) {
13288 case EINVAL:
13289#ifdef ENOSYS
13290 case ENOSYS:
13291#endif
13292#ifdef EOPNOTSUP
13293 /* some RedHat kernels may return EOPNOTSUP on an NFS mount.
13294 see also: [Feature #16965] */
13295 case EOPNOTSUP:
13296#endif
13297 return 0;
13298 case EAGAIN:
13299#if EWOULDBLOCK != EAGAIN
13300 case EWOULDBLOCK:
13301#endif
13302 {
13303 int ret;
13304#ifndef __linux__
13305 /*
13306 * Linux requires stp->src_fptr->fd to be a mmap-able (regular) file,
13307 * select() reports regular files to always be "ready", so
13308 * there is no need to select() on it.
13309 * Other OSes may have the same limitation for sendfile() which
13310 * allow us to bypass maygvl_copy_stream_wait_read()...
13311 */
13312 ret = maygvl_copy_stream_wait_read(0, stp);
13313 if (ret < 0) return ret;
13314#endif
13315 ret = nogvl_copy_stream_wait_write(stp);
13316 if (ret < 0) return ret;
13317 }
13318 goto retry_sendfile;
13319 }
13320 stp->syserr = "sendfile";
13321 stp->error_no = errno;
13322 return (int)ss;
13323 }
13324 return 1;
13325}
13326#endif
13327
13328static ssize_t
13329maygvl_read(int has_gvl, rb_io_t *fptr, void *buf, size_t count)
13330{
13331 if (has_gvl)
13332 return rb_io_read_memory(fptr, buf, count);
13333 else
13334 return read(fptr->fd, buf, count);
13335}
13336
13337static ssize_t
13338maygvl_copy_stream_read(int has_gvl, struct copy_stream_struct *stp, char *buf, size_t len, rb_off_t offset)
13339{
13340 ssize_t ss;
13341 retry_read:
13342 if (offset < (rb_off_t)0) {
13343 ss = maygvl_read(has_gvl, stp->src_fptr, buf, len);
13344 }
13345 else {
13346 ss = pread(stp->src_fptr->fd, buf, len, offset);
13347 }
13348 if (ss == 0) {
13349 return 0;
13350 }
13351 if (ss < 0) {
13352 if (maygvl_copy_stream_continue_p(has_gvl, stp))
13353 goto retry_read;
13354 switch (errno) {
13355 case EAGAIN:
13356#if EWOULDBLOCK != EAGAIN
13357 case EWOULDBLOCK:
13358#endif
13359 {
13360 int ret = maygvl_copy_stream_wait_read(has_gvl, stp);
13361 if (ret < 0) return ret;
13362 }
13363 goto retry_read;
13364#ifdef ENOSYS
13365 case ENOSYS:
13366 stp->notimp = "pread";
13367 return ss;
13368#endif
13369 }
13370 stp->syserr = offset < (rb_off_t)0 ? "read" : "pread";
13371 stp->error_no = errno;
13372 }
13373 return ss;
13374}
13375
13376static int
13377nogvl_copy_stream_write(struct copy_stream_struct *stp, char *buf, size_t len)
13378{
13379 ssize_t ss;
13380 int off = 0;
13381 while (len) {
13382 ss = write(stp->dst_fptr->fd, buf+off, len);
13383 if (ss < 0) {
13384 if (maygvl_copy_stream_continue_p(0, stp))
13385 continue;
13386 if (io_again_p(errno)) {
13387 int ret = nogvl_copy_stream_wait_write(stp);
13388 if (ret < 0) return ret;
13389 continue;
13390 }
13391 stp->syserr = "write";
13392 stp->error_no = errno;
13393 return (int)ss;
13394 }
13395 off += (int)ss;
13396 len -= (int)ss;
13397 stp->total += ss;
13398 }
13399 return 0;
13400}
13401
13402static void
13403nogvl_copy_stream_read_write(struct copy_stream_struct *stp)
13404{
13405 char buf[1024*16];
13406 size_t len;
13407 ssize_t ss;
13408 int ret;
13409 rb_off_t copy_length;
13410 rb_off_t src_offset;
13411 int use_eof;
13412 int use_pread;
13413
13414 copy_length = stp->copy_length;
13415 use_eof = copy_length < (rb_off_t)0;
13416 src_offset = stp->src_offset;
13417 use_pread = src_offset >= (rb_off_t)0;
13418
13419 if (use_pread && stp->close_src) {
13420 rb_off_t r;
13421 errno = 0;
13422 r = lseek(stp->src_fptr->fd, src_offset, SEEK_SET);
13423 if (r < (rb_off_t)0 && errno) {
13424 stp->syserr = "lseek";
13425 stp->error_no = errno;
13426 return;
13427 }
13428 src_offset = (rb_off_t)-1;
13429 use_pread = 0;
13430 }
13431
13432 while (use_eof || 0 < copy_length) {
13433 if (!use_eof && copy_length < (rb_off_t)sizeof(buf)) {
13434 len = (size_t)copy_length;
13435 }
13436 else {
13437 len = sizeof(buf);
13438 }
13439 if (use_pread) {
13440 ss = maygvl_copy_stream_read(0, stp, buf, len, src_offset);
13441 if (0 < ss)
13442 src_offset += ss;
13443 }
13444 else {
13445 ss = maygvl_copy_stream_read(0, stp, buf, len, (rb_off_t)-1);
13446 }
13447 if (ss <= 0) /* EOF or error */
13448 return;
13449
13450 ret = nogvl_copy_stream_write(stp, buf, ss);
13451 if (ret < 0)
13452 return;
13453
13454 if (!use_eof)
13455 copy_length -= ss;
13456 }
13457}
13458
13459static void *
13460nogvl_copy_stream_func(void *arg)
13461{
13462 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13463#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13464 int ret;
13465#endif
13466
13467#ifdef USE_COPY_FILE_RANGE
13468 ret = nogvl_copy_file_range(stp);
13469 if (ret != 0)
13470 goto finish; /* error or success */
13471#endif
13472
13473#ifdef HAVE_FCOPYFILE
13474 ret = nogvl_fcopyfile(stp);
13475 if (ret != 0)
13476 goto finish; /* error or success */
13477#endif
13478
13479#ifdef USE_SENDFILE
13480 ret = nogvl_copy_stream_sendfile(stp);
13481 if (ret != 0)
13482 goto finish; /* error or success */
13483#endif
13484
13485 nogvl_copy_stream_read_write(stp);
13486
13487#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13488 finish:
13489#endif
13490 return 0;
13491}
13492
13493static VALUE
13494copy_stream_fallback_body(VALUE arg)
13495{
13496 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13497 const int buflen = 16*1024;
13498 VALUE n;
13499 VALUE buf = rb_str_buf_new(buflen);
13500 rb_off_t rest = stp->copy_length;
13501 rb_off_t off = stp->src_offset;
13502 ID read_method = id_readpartial;
13503
13504 if (!stp->src_fptr) {
13505 if (!rb_respond_to(stp->src, read_method)) {
13506 read_method = id_read;
13507 }
13508 }
13509
13510 while (1) {
13511 long numwrote;
13512 long l;
13513 rb_str_make_independent(buf);
13514 if (stp->copy_length < (rb_off_t)0) {
13515 l = buflen;
13516 }
13517 else {
13518 if (rest == 0) {
13519 rb_str_resize(buf, 0);
13520 break;
13521 }
13522 l = buflen < rest ? buflen : (long)rest;
13523 }
13524 if (!stp->src_fptr) {
13525 VALUE rc = rb_funcall(stp->src, read_method, 2, INT2FIX(l), buf);
13526
13527 if (read_method == id_read && NIL_P(rc))
13528 break;
13529 }
13530 else {
13531 ssize_t ss;
13532 rb_str_resize(buf, buflen);
13533 ss = maygvl_copy_stream_read(1, stp, RSTRING_PTR(buf), l, off);
13534 rb_str_resize(buf, ss > 0 ? ss : 0);
13535 if (ss < 0)
13536 return Qnil;
13537 if (ss == 0)
13538 rb_eof_error();
13539 if (off >= (rb_off_t)0)
13540 off += ss;
13541 }
13542 n = rb_io_write(stp->dst, buf);
13543 numwrote = NUM2LONG(n);
13544 stp->total += numwrote;
13545 rest -= numwrote;
13546 if (read_method == id_read && RSTRING_LEN(buf) == 0) {
13547 break;
13548 }
13549 }
13550
13551 return Qnil;
13552}
13553
13554static VALUE
13555copy_stream_fallback(struct copy_stream_struct *stp)
13556{
13557 if (!stp->src_fptr && stp->src_offset >= (rb_off_t)0) {
13558 rb_raise(rb_eArgError, "cannot specify src_offset for non-IO");
13559 }
13560 rb_rescue2(copy_stream_fallback_body, (VALUE)stp,
13561 (VALUE (*) (VALUE, VALUE))0, (VALUE)0,
13562 rb_eEOFError, (VALUE)0);
13563 return Qnil;
13564}
13565
13566static VALUE
13567copy_stream_body(VALUE arg)
13568{
13569 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13570 VALUE src_io = stp->src, dst_io = stp->dst;
13571 const int common_oflags = 0
13572#ifdef O_NOCTTY
13573 | O_NOCTTY
13574#endif
13575 ;
13576
13577 stp->th = rb_thread_current();
13578
13579 stp->total = 0;
13580
13581 if (src_io == argf ||
13582 !(RB_TYPE_P(src_io, T_FILE) ||
13583 RB_TYPE_P(src_io, T_STRING) ||
13584 rb_respond_to(src_io, rb_intern("to_path")))) {
13585 stp->src_fptr = NULL;
13586 }
13587 else {
13588 int stat_ret;
13589 VALUE tmp_io = rb_io_check_io(src_io);
13590 if (!NIL_P(tmp_io)) {
13591 src_io = tmp_io;
13592 }
13593 else if (!RB_TYPE_P(src_io, T_FILE)) {
13594 VALUE args[2];
13595 FilePathValue(src_io);
13596 args[0] = src_io;
13597 args[1] = INT2NUM(O_RDONLY|common_oflags);
13598 src_io = rb_class_new_instance(2, args, rb_cFile);
13599 stp->src = src_io;
13600 stp->close_src = 1;
13601 }
13602 RB_IO_POINTER(src_io, stp->src_fptr);
13603 rb_io_check_byte_readable(stp->src_fptr);
13604
13605 stat_ret = fstat(stp->src_fptr->fd, &stp->src_stat);
13606 if (stat_ret < 0) {
13607 stp->syserr = "fstat";
13608 stp->error_no = errno;
13609 return Qnil;
13610 }
13611 }
13612
13613 if (dst_io == argf ||
13614 !(RB_TYPE_P(dst_io, T_FILE) ||
13615 RB_TYPE_P(dst_io, T_STRING) ||
13616 rb_respond_to(dst_io, rb_intern("to_path")))) {
13617 stp->dst_fptr = NULL;
13618 }
13619 else {
13620 int stat_ret;
13621 VALUE tmp_io = rb_io_check_io(dst_io);
13622 if (!NIL_P(tmp_io)) {
13623 dst_io = GetWriteIO(tmp_io);
13624 }
13625 else if (!RB_TYPE_P(dst_io, T_FILE)) {
13626 VALUE args[3];
13627 FilePathValue(dst_io);
13628 args[0] = dst_io;
13629 args[1] = INT2NUM(O_WRONLY|O_CREAT|O_TRUNC|common_oflags);
13630 args[2] = INT2FIX(0666);
13631 dst_io = rb_class_new_instance(3, args, rb_cFile);
13632 stp->dst = dst_io;
13633 stp->close_dst = 1;
13634 }
13635 else {
13636 dst_io = GetWriteIO(dst_io);
13637 stp->dst = dst_io;
13638 }
13639 RB_IO_POINTER(dst_io, stp->dst_fptr);
13640 rb_io_check_writable(stp->dst_fptr);
13641
13642 stat_ret = fstat(stp->dst_fptr->fd, &stp->dst_stat);
13643 if (stat_ret < 0) {
13644 stp->syserr = "fstat";
13645 stp->error_no = errno;
13646 return Qnil;
13647 }
13648 }
13649
13650#ifdef O_BINARY
13651 if (stp->src_fptr)
13652 SET_BINARY_MODE_WITH_SEEK_CUR(stp->src_fptr);
13653#endif
13654 if (stp->dst_fptr)
13655 io_ascii8bit_binmode(stp->dst_fptr);
13656
13657 if (stp->src_offset < (rb_off_t)0 && stp->src_fptr && stp->src_fptr->rbuf.len) {
13658 size_t len = stp->src_fptr->rbuf.len;
13659 VALUE str;
13660 if (stp->copy_length >= (rb_off_t)0 && stp->copy_length < (rb_off_t)len) {
13661 len = (size_t)stp->copy_length;
13662 }
13663 str = rb_str_buf_new(len);
13664 rb_str_resize(str,len);
13665 read_buffered_data(RSTRING_PTR(str), len, stp->src_fptr);
13666 if (stp->dst_fptr) { /* IO or filename */
13667 if (io_binwrite(RSTRING_PTR(str), RSTRING_LEN(str), stp->dst_fptr, 0) < 0)
13668 rb_sys_fail_on_write(stp->dst_fptr);
13669 }
13670 else /* others such as StringIO */
13671 rb_io_write(dst_io, str);
13672 rb_str_resize(str, 0);
13673 stp->total += len;
13674 if (stp->copy_length >= (rb_off_t)0)
13675 stp->copy_length -= len;
13676 }
13677
13678 if (stp->dst_fptr && io_fflush(stp->dst_fptr) < 0) {
13679 rb_raise(rb_eIOError, "flush failed");
13680 }
13681
13682 if (stp->copy_length == 0)
13683 return Qnil;
13684
13685 if (stp->src_fptr == NULL || stp->dst_fptr == NULL) {
13686 return copy_stream_fallback(stp);
13687 }
13688
13689 IO_WITHOUT_GVL(nogvl_copy_stream_func, stp);
13690 return Qnil;
13691}
13692
13693static VALUE
13694copy_stream_finalize(VALUE arg)
13695{
13696 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13697
13698#ifdef HAVE_FCOPYFILE
13699 if (stp->copyfile_state) {
13700 copyfile_state_free(stp->copyfile_state);
13701 }
13702#endif
13703
13704 if (stp->close_src) {
13705 rb_io_close_m(stp->src);
13706 }
13707 if (stp->close_dst) {
13708 rb_io_close_m(stp->dst);
13709 }
13710 if (stp->syserr) {
13711 rb_syserr_fail(stp->error_no, stp->syserr);
13712 }
13713 if (stp->notimp) {
13714 rb_raise(rb_eNotImpError, "%s() not implemented", stp->notimp);
13715 }
13716 return Qnil;
13717}
13718
13719/*
13720 * call-seq:
13721 * IO.copy_stream(src, dst, src_length = nil, src_offset = 0) -> integer
13722 *
13723 * Copies from the given +src+ to the given +dst+,
13724 * returning the number of bytes copied.
13725 *
13726 * - The given +src+ must be one of the following:
13727 *
13728 * - The path to a readable file, from which source data is to be read.
13729 * - An \IO-like object, opened for reading and capable of responding
13730 * to method +:readpartial+ or method +:read+.
13731 *
13732 * - The given +dst+ must be one of the following:
13733 *
13734 * - The path to a writable file, to which data is to be written.
13735 * - An \IO-like object, opened for writing and capable of responding
13736 * to method +:write+.
13737 *
13738 * The examples here use file <tt>t.txt</tt> as source:
13739 *
13740 * File.read('t.txt')
13741 * # => "First line\nSecond line\n\nThird line\nFourth line\n"
13742 * File.read('t.txt').size # => 47
13743 *
13744 * If only arguments +src+ and +dst+ are given,
13745 * the entire source stream is copied:
13746 *
13747 * # Paths.
13748 * IO.copy_stream('t.txt', 't.tmp') # => 47
13749 *
13750 * # IOs (recall that a File is also an IO).
13751 * src_io = File.open('t.txt', 'r') # => #<File:t.txt>
13752 * dst_io = File.open('t.tmp', 'w') # => #<File:t.tmp>
13753 * IO.copy_stream(src_io, dst_io) # => 47
13754 * src_io.close
13755 * dst_io.close
13756 *
13757 * With argument +src_length+ a non-negative integer,
13758 * no more than that many bytes are copied:
13759 *
13760 * IO.copy_stream('t.txt', 't.tmp', 10) # => 10
13761 * File.read('t.tmp') # => "First line"
13762 *
13763 * With argument +src_offset+ also given,
13764 * the source stream is read beginning at that offset:
13765 *
13766 * IO.copy_stream('t.txt', 't.tmp', 11, 11) # => 11
13767 * IO.read('t.tmp') # => "Second line"
13768 *
13769 */
13770static VALUE
13771rb_io_s_copy_stream(int argc, VALUE *argv, VALUE io)
13772{
13773 VALUE src, dst, length, src_offset;
13774 struct copy_stream_struct st;
13775
13776 MEMZERO(&st, struct copy_stream_struct, 1);
13777
13778 rb_scan_args(argc, argv, "22", &src, &dst, &length, &src_offset);
13779
13780 st.src = src;
13781 st.dst = dst;
13782
13783 st.src_fptr = NULL;
13784 st.dst_fptr = NULL;
13785
13786 if (NIL_P(length))
13787 st.copy_length = (rb_off_t)-1;
13788 else
13789 st.copy_length = NUM2OFFT(length);
13790
13791 if (NIL_P(src_offset))
13792 st.src_offset = (rb_off_t)-1;
13793 else
13794 st.src_offset = NUM2OFFT(src_offset);
13795
13796 rb_ensure(copy_stream_body, (VALUE)&st, copy_stream_finalize, (VALUE)&st);
13797
13798 return OFFT2NUM(st.total);
13799}
13800
13801/*
13802 * call-seq:
13803 * external_encoding -> encoding or nil
13804 *
13805 * Returns the Encoding object that represents the encoding of the stream,
13806 * or +nil+ if the stream is in write mode and no encoding is specified.
13807 *
13808 * See {Encodings}[rdoc-ref:File@Encodings].
13809 *
13810 */
13811
13812static VALUE
13813rb_io_external_encoding(VALUE io)
13814{
13815 rb_io_t *fptr = RFILE(rb_io_taint_check(io))->fptr;
13816
13817 if (fptr->encs.enc2) {
13818 return rb_enc_from_encoding(fptr->encs.enc2);
13819 }
13820 if (fptr->mode & FMODE_WRITABLE) {
13821 if (fptr->encs.enc)
13822 return rb_enc_from_encoding(fptr->encs.enc);
13823 return Qnil;
13824 }
13825 return rb_enc_from_encoding(io_read_encoding(fptr));
13826}
13827
13828/*
13829 * call-seq:
13830 * internal_encoding -> encoding or nil
13831 *
13832 * Returns the Encoding object that represents the encoding of the internal string,
13833 * if conversion is specified,
13834 * or +nil+ otherwise.
13835 *
13836 * See {Encodings}[rdoc-ref:File@Encodings].
13837 *
13838 */
13839
13840static VALUE
13841rb_io_internal_encoding(VALUE io)
13842{
13843 rb_io_t *fptr = RFILE(rb_io_taint_check(io))->fptr;
13844
13845 if (!fptr->encs.enc2) return Qnil;
13846 return rb_enc_from_encoding(io_read_encoding(fptr));
13847}
13848
13849/*
13850 * call-seq:
13851 * set_encoding(ext_enc) -> self
13852 * set_encoding(ext_enc, int_enc, **enc_opts) -> self
13853 * set_encoding('ext_enc:int_enc', **enc_opts) -> self
13854 *
13855 * See {Encodings}[rdoc-ref:File@Encodings].
13856 *
13857 * Argument +ext_enc+, if given, must be an Encoding object
13858 * or a String with the encoding name;
13859 * it is assigned as the encoding for the stream.
13860 *
13861 * Argument +int_enc+, if given, must be an Encoding object
13862 * or a String with the encoding name;
13863 * it is assigned as the encoding for the internal string.
13864 *
13865 * Argument <tt>'ext_enc:int_enc'</tt>, if given, is a string
13866 * containing two colon-separated encoding names;
13867 * corresponding Encoding objects are assigned as the external
13868 * and internal encodings for the stream.
13869 *
13870 * If the external encoding of a string is binary/ASCII-8BIT,
13871 * the internal encoding of the string is set to nil, since no
13872 * transcoding is needed.
13873 *
13874 * Optional keyword arguments +enc_opts+ specify
13875 * {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
13876 *
13877 */
13878
13879static VALUE
13880rb_io_set_encoding(int argc, VALUE *argv, VALUE io)
13881{
13882 rb_io_t *fptr;
13883 VALUE v1, v2, opt;
13884
13885 if (!RB_TYPE_P(io, T_FILE)) {
13886 return forward(io, id_set_encoding, argc, argv);
13887 }
13888
13889 argc = rb_scan_args(argc, argv, "11:", &v1, &v2, &opt);
13890 GetOpenFile(io, fptr);
13891 io_encoding_set(fptr, v1, v2, opt);
13892 return io;
13893}
13894
13895void
13896rb_stdio_set_default_encoding(void)
13897{
13898 VALUE val = Qnil;
13899
13900#ifdef _WIN32
13901 if (isatty(fileno(stdin))) {
13902 rb_encoding *external = rb_locale_encoding();
13903 rb_encoding *internal = rb_default_internal_encoding();
13904 if (!internal) internal = rb_default_external_encoding();
13905 io_encoding_set(RFILE(rb_stdin)->fptr,
13906 rb_enc_from_encoding(external),
13907 rb_enc_from_encoding(internal),
13908 Qnil);
13909 }
13910 else
13911#endif
13912 rb_io_set_encoding(1, &val, rb_stdin);
13913 rb_io_set_encoding(1, &val, rb_stdout);
13914 rb_io_set_encoding(1, &val, rb_stderr);
13915}
13916
13917static inline int
13918global_argf_p(VALUE arg)
13919{
13920 return arg == argf;
13921}
13922
13923typedef VALUE (*argf_encoding_func)(VALUE io);
13924
13925static VALUE
13926argf_encoding(VALUE argf, argf_encoding_func func)
13927{
13928 if (!RTEST(ARGF.current_file)) {
13929 return rb_enc_default_external();
13930 }
13931 return func(rb_io_check_io(ARGF.current_file));
13932}
13933
13934/*
13935 * call-seq:
13936 * ARGF.external_encoding -> encoding
13937 *
13938 * Returns the external encoding for files read from ARGF as an Encoding
13939 * object. The external encoding is the encoding of the text as stored in a
13940 * file. Contrast with ARGF.internal_encoding, which is the encoding used to
13941 * represent this text within Ruby.
13942 *
13943 * To set the external encoding use ARGF.set_encoding.
13944 *
13945 * For example:
13946 *
13947 * ARGF.external_encoding #=> #<Encoding:UTF-8>
13948 *
13949 */
13950static VALUE
13951argf_external_encoding(VALUE argf)
13952{
13953 return argf_encoding(argf, rb_io_external_encoding);
13954}
13955
13956/*
13957 * call-seq:
13958 * ARGF.internal_encoding -> encoding
13959 *
13960 * Returns the internal encoding for strings read from ARGF as an
13961 * Encoding object.
13962 *
13963 * If ARGF.set_encoding has been called with two encoding names, the second
13964 * is returned. Otherwise, if +Encoding.default_external+ has been set, that
13965 * value is returned. Failing that, if a default external encoding was
13966 * specified on the command-line, that value is used. If the encoding is
13967 * unknown, +nil+ is returned.
13968 */
13969static VALUE
13970argf_internal_encoding(VALUE argf)
13971{
13972 return argf_encoding(argf, rb_io_internal_encoding);
13973}
13974
13975/*
13976 * call-seq:
13977 * ARGF.set_encoding(ext_enc) -> ARGF
13978 * ARGF.set_encoding("ext_enc:int_enc") -> ARGF
13979 * ARGF.set_encoding(ext_enc, int_enc) -> ARGF
13980 * ARGF.set_encoding("ext_enc:int_enc", opt) -> ARGF
13981 * ARGF.set_encoding(ext_enc, int_enc, opt) -> ARGF
13982 *
13983 * If single argument is specified, strings read from ARGF are tagged with
13984 * the encoding specified.
13985 *
13986 * If two encoding names separated by a colon are given, e.g. "ascii:utf-8",
13987 * the read string is converted from the first encoding (external encoding)
13988 * to the second encoding (internal encoding), then tagged with the second
13989 * encoding.
13990 *
13991 * If two arguments are specified, they must be encoding objects or encoding
13992 * names. Again, the first specifies the external encoding; the second
13993 * specifies the internal encoding.
13994 *
13995 * If the external encoding and the internal encoding are specified, the
13996 * optional Hash argument can be used to adjust the conversion process. The
13997 * structure of this hash is explained in the String#encode documentation.
13998 *
13999 * For example:
14000 *
14001 * ARGF.set_encoding('ascii') # Tag the input as US-ASCII text
14002 * ARGF.set_encoding(Encoding::UTF_8) # Tag the input as UTF-8 text
14003 * ARGF.set_encoding('utf-8','ascii') # Transcode the input from US-ASCII
14004 * # to UTF-8.
14005 */
14006static VALUE
14007argf_set_encoding(int argc, VALUE *argv, VALUE argf)
14008{
14009 rb_io_t *fptr;
14010
14011 if (!next_argv()) {
14012 rb_raise(rb_eArgError, "no stream to set encoding");
14013 }
14014 rb_io_set_encoding(argc, argv, ARGF.current_file);
14015 GetOpenFile(ARGF.current_file, fptr);
14016 ARGF.encs = fptr->encs;
14017 RB_OBJ_WRITTEN(argf, Qundef, ARGF.encs.ecopts);
14018 return argf;
14019}
14020
14021/*
14022 * call-seq:
14023 * ARGF.tell -> Integer
14024 * ARGF.pos -> Integer
14025 *
14026 * Returns the current offset (in bytes) of the current file in ARGF.
14027 *
14028 * ARGF.pos #=> 0
14029 * ARGF.gets #=> "This is line one\n"
14030 * ARGF.pos #=> 17
14031 *
14032 */
14033static VALUE
14034argf_tell(VALUE argf)
14035{
14036 if (!next_argv()) {
14037 rb_raise(rb_eArgError, "no stream to tell");
14038 }
14039 ARGF_FORWARD(0, 0);
14040 return rb_io_tell(ARGF.current_file);
14041}
14042
14043/*
14044 * call-seq:
14045 * ARGF.seek(amount, whence=IO::SEEK_SET) -> 0
14046 *
14047 * Seeks to offset _amount_ (an Integer) in the ARGF stream according to
14048 * the value of _whence_. See IO#seek for further details.
14049 */
14050static VALUE
14051argf_seek_m(int argc, VALUE *argv, VALUE argf)
14052{
14053 if (!next_argv()) {
14054 rb_raise(rb_eArgError, "no stream to seek");
14055 }
14056 ARGF_FORWARD(argc, argv);
14057 return rb_io_seek_m(argc, argv, ARGF.current_file);
14058}
14059
14060/*
14061 * call-seq:
14062 * ARGF.pos = position -> Integer
14063 *
14064 * Seeks to the position given by _position_ (in bytes) in ARGF.
14065 *
14066 * For example:
14067 *
14068 * ARGF.pos = 17
14069 * ARGF.gets #=> "This is line two\n"
14070 */
14071static VALUE
14072argf_set_pos(VALUE argf, VALUE offset)
14073{
14074 if (!next_argv()) {
14075 rb_raise(rb_eArgError, "no stream to set position");
14076 }
14077 ARGF_FORWARD(1, &offset);
14078 return rb_io_set_pos(ARGF.current_file, offset);
14079}
14080
14081/*
14082 * call-seq:
14083 * ARGF.rewind -> 0
14084 *
14085 * Positions the current file to the beginning of input, resetting
14086 * ARGF.lineno to zero.
14087 *
14088 * ARGF.readline #=> "This is line one\n"
14089 * ARGF.rewind #=> 0
14090 * ARGF.lineno #=> 0
14091 * ARGF.readline #=> "This is line one\n"
14092 */
14093static VALUE
14094argf_rewind(VALUE argf)
14095{
14096 VALUE ret;
14097 int old_lineno;
14098
14099 if (!next_argv()) {
14100 rb_raise(rb_eArgError, "no stream to rewind");
14101 }
14102 ARGF_FORWARD(0, 0);
14103 old_lineno = RFILE(ARGF.current_file)->fptr->lineno;
14104 ret = rb_io_rewind(ARGF.current_file);
14105 if (!global_argf_p(argf)) {
14106 ARGF.last_lineno = ARGF.lineno -= old_lineno;
14107 }
14108 return ret;
14109}
14110
14111/*
14112 * call-seq:
14113 * ARGF.fileno -> integer
14114 * ARGF.to_i -> integer
14115 *
14116 * Returns an integer representing the numeric file descriptor for
14117 * the current file. Raises an ArgumentError if there isn't a current file.
14118 *
14119 * ARGF.fileno #=> 3
14120 */
14121static VALUE
14122argf_fileno(VALUE argf)
14123{
14124 if (!next_argv()) {
14125 rb_raise(rb_eArgError, "no stream");
14126 }
14127 ARGF_FORWARD(0, 0);
14128 return rb_io_fileno(ARGF.current_file);
14129}
14130
14131/*
14132 * call-seq:
14133 * ARGF.to_io -> IO
14134 *
14135 * Returns an IO object representing the current file. This will be a
14136 * File object unless the current file is a stream such as STDIN.
14137 *
14138 * For example:
14139 *
14140 * ARGF.to_io #=> #<File:glark.txt>
14141 * ARGF.to_io #=> #<IO:<STDIN>>
14142 */
14143static VALUE
14144argf_to_io(VALUE argf)
14145{
14146 next_argv();
14147 ARGF_FORWARD(0, 0);
14148 return ARGF.current_file;
14149}
14150
14151/*
14152 * call-seq:
14153 * ARGF.eof? -> true or false
14154 * ARGF.eof -> true or false
14155 *
14156 * Returns true if the current file in ARGF is at end of file, i.e. it has
14157 * no data to read. The stream must be opened for reading or an IOError
14158 * will be raised.
14159 *
14160 * $ echo "eof" | ruby argf.rb
14161 *
14162 * ARGF.eof? #=> false
14163 * 3.times { ARGF.readchar }
14164 * ARGF.eof? #=> false
14165 * ARGF.readchar #=> "\n"
14166 * ARGF.eof? #=> true
14167 */
14168
14169static VALUE
14170argf_eof(VALUE argf)
14171{
14172 next_argv();
14173 if (RTEST(ARGF.current_file)) {
14174 if (ARGF.init_p == 0) return Qtrue;
14175 next_argv();
14176 ARGF_FORWARD(0, 0);
14177 if (rb_io_eof(ARGF.current_file)) {
14178 return Qtrue;
14179 }
14180 }
14181 return Qfalse;
14182}
14183
14184/*
14185 * call-seq:
14186 * ARGF.read([length [, outbuf]]) -> string, outbuf, or nil
14187 *
14188 * Reads _length_ bytes from ARGF. The files named on the command line
14189 * are concatenated and treated as a single file by this method, so when
14190 * called without arguments the contents of this pseudo file are returned in
14191 * their entirety.
14192 *
14193 * _length_ must be a non-negative integer or +nil+.
14194 *
14195 * If _length_ is a positive integer, +read+ tries to read
14196 * _length_ bytes without any conversion (binary mode).
14197 * It returns +nil+ if an EOF is encountered before anything can be read.
14198 * Fewer than _length_ bytes are returned if an EOF is encountered during
14199 * the read.
14200 * In the case of an integer _length_, the resulting string is always
14201 * in ASCII-8BIT encoding.
14202 *
14203 * If _length_ is omitted or is +nil+, it reads until EOF
14204 * and the encoding conversion is applied, if applicable.
14205 * A string is returned even if EOF is encountered before any data is read.
14206 *
14207 * If _length_ is zero, it returns an empty string (<code>""</code>).
14208 *
14209 * If the optional _outbuf_ argument is present,
14210 * it must reference a String, which will receive the data.
14211 * The _outbuf_ will contain only the received data after the method call
14212 * even if it is not empty at the beginning.
14213 *
14214 * For example:
14215 *
14216 * $ echo "small" > small.txt
14217 * $ echo "large" > large.txt
14218 * $ ./glark.rb small.txt large.txt
14219 *
14220 * ARGF.read #=> "small\nlarge"
14221 * ARGF.read(200) #=> "small\nlarge"
14222 * ARGF.read(2) #=> "sm"
14223 * ARGF.read(0) #=> ""
14224 *
14225 * Note that this method behaves like the fread() function in C.
14226 * This means it retries to invoke read(2) system calls to read data
14227 * with the specified length.
14228 * If you need the behavior like a single read(2) system call,
14229 * consider ARGF#readpartial or ARGF#read_nonblock.
14230 */
14231
14232static VALUE
14233argf_read(int argc, VALUE *argv, VALUE argf)
14234{
14235 VALUE tmp, str, length;
14236 long len = 0;
14237
14238 rb_scan_args(argc, argv, "02", &length, &str);
14239 if (!NIL_P(length)) {
14240 len = NUM2LONG(argv[0]);
14241 }
14242 if (!NIL_P(str)) {
14243 StringValue(str);
14244 rb_str_resize(str,0);
14245 argv[1] = Qnil;
14246 }
14247
14248 retry:
14249 if (!next_argv()) {
14250 return str;
14251 }
14252 if (ARGF_GENERIC_INPUT_P()) {
14253 tmp = argf_forward(argc, argv, argf);
14254 }
14255 else {
14256 tmp = io_read(argc, argv, ARGF.current_file);
14257 }
14258 if (NIL_P(str)) str = tmp;
14259 else if (!NIL_P(tmp)) rb_str_append(str, tmp);
14260 if (NIL_P(tmp) || NIL_P(length)) {
14261 if (ARGF.next_p != -1) {
14262 argf_close(argf);
14263 ARGF.next_p = 1;
14264 goto retry;
14265 }
14266 }
14267 else if (argc >= 1) {
14268 long slen = RSTRING_LEN(str);
14269 if (slen < len) {
14270 argv[0] = LONG2NUM(len - slen);
14271 goto retry;
14272 }
14273 }
14274 return str;
14275}
14276
14278 int argc;
14279 VALUE *argv;
14280 VALUE argf;
14281};
14282
14283static VALUE
14284argf_forward_call(VALUE arg)
14285{
14286 struct argf_call_arg *p = (struct argf_call_arg *)arg;
14287 argf_forward(p->argc, p->argv, p->argf);
14288 return Qnil;
14289}
14290
14291static VALUE argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts,
14292 int nonblock);
14293
14294/*
14295 * call-seq:
14296 * ARGF.readpartial(maxlen) -> string
14297 * ARGF.readpartial(maxlen, outbuf) -> outbuf
14298 *
14299 * Reads at most _maxlen_ bytes from the ARGF stream.
14300 *
14301 * If the optional _outbuf_ argument is present,
14302 * it must reference a String, which will receive the data.
14303 * The _outbuf_ will contain only the received data after the method call
14304 * even if it is not empty at the beginning.
14305 *
14306 * It raises EOFError on end of ARGF stream.
14307 * Since ARGF stream is a concatenation of multiple files,
14308 * internally EOF is occur for each file.
14309 * ARGF.readpartial returns empty strings for EOFs except the last one and
14310 * raises EOFError for the last one.
14311 *
14312 */
14313
14314static VALUE
14315argf_readpartial(int argc, VALUE *argv, VALUE argf)
14316{
14317 return argf_getpartial(argc, argv, argf, Qnil, 0);
14318}
14319
14320/*
14321 * call-seq:
14322 * ARGF.read_nonblock(maxlen[, options]) -> string
14323 * ARGF.read_nonblock(maxlen, outbuf[, options]) -> outbuf
14324 *
14325 * Reads at most _maxlen_ bytes from the ARGF stream in non-blocking mode.
14326 */
14327
14328static VALUE
14329argf_read_nonblock(int argc, VALUE *argv, VALUE argf)
14330{
14331 VALUE opts;
14332
14333 rb_scan_args(argc, argv, "11:", NULL, NULL, &opts);
14334
14335 if (!NIL_P(opts))
14336 argc--;
14337
14338 return argf_getpartial(argc, argv, argf, opts, 1);
14339}
14340
14341static VALUE
14342argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts, int nonblock)
14343{
14344 VALUE tmp, str, length;
14345 int no_exception;
14346
14347 rb_scan_args(argc, argv, "11", &length, &str);
14348 if (!NIL_P(str)) {
14349 StringValue(str);
14350 argv[1] = str;
14351 }
14352 no_exception = no_exception_p(opts);
14353
14354 if (!next_argv()) {
14355 if (!NIL_P(str)) {
14356 rb_str_resize(str, 0);
14357 }
14358 rb_eof_error();
14359 }
14360 if (ARGF_GENERIC_INPUT_P()) {
14361 VALUE (*const rescue_does_nothing)(VALUE, VALUE) = 0;
14362 struct argf_call_arg arg;
14363 arg.argc = argc;
14364 arg.argv = argv;
14365 arg.argf = argf;
14366 tmp = rb_rescue2(argf_forward_call, (VALUE)&arg,
14367 rescue_does_nothing, Qnil, rb_eEOFError, (VALUE)0);
14368 }
14369 else {
14370 tmp = io_getpartial(argc, argv, ARGF.current_file, no_exception, nonblock);
14371 }
14372 if (NIL_P(tmp)) {
14373 if (ARGF.next_p == -1) {
14374 return io_nonblock_eof(no_exception);
14375 }
14376 argf_close(argf);
14377 ARGF.next_p = 1;
14378 if (RARRAY_LEN(ARGF.argv) == 0) {
14379 return io_nonblock_eof(no_exception);
14380 }
14381 if (NIL_P(str))
14382 str = rb_str_new(NULL, 0);
14383 return str;
14384 }
14385 return tmp;
14386}
14387
14388/*
14389 * call-seq:
14390 * ARGF.getc -> String or nil
14391 *
14392 * Reads the next character from ARGF and returns it as a String. Returns
14393 * +nil+ at the end of the stream.
14394 *
14395 * ARGF treats the files named on the command line as a single file created
14396 * by concatenating their contents. After returning the last character of the
14397 * first file, it returns the first character of the second file, and so on.
14398 *
14399 * For example:
14400 *
14401 * $ echo "foo" > file
14402 * $ ruby argf.rb file
14403 *
14404 * ARGF.getc #=> "f"
14405 * ARGF.getc #=> "o"
14406 * ARGF.getc #=> "o"
14407 * ARGF.getc #=> "\n"
14408 * ARGF.getc #=> nil
14409 * ARGF.getc #=> nil
14410 */
14411static VALUE
14412argf_getc(VALUE argf)
14413{
14414 VALUE ch;
14415
14416 retry:
14417 if (!next_argv()) return Qnil;
14418 if (ARGF_GENERIC_INPUT_P()) {
14419 ch = forward_current(rb_intern("getc"), 0, 0);
14420 }
14421 else {
14422 ch = rb_io_getc(ARGF.current_file);
14423 }
14424 if (NIL_P(ch) && ARGF.next_p != -1) {
14425 argf_close(argf);
14426 ARGF.next_p = 1;
14427 goto retry;
14428 }
14429
14430 return ch;
14431}
14432
14433/*
14434 * call-seq:
14435 * ARGF.getbyte -> Integer or nil
14436 *
14437 * Gets the next 8-bit byte (0..255) from ARGF. Returns +nil+ if called at
14438 * the end of the stream.
14439 *
14440 * For example:
14441 *
14442 * $ echo "foo" > file
14443 * $ ruby argf.rb file
14444 *
14445 * ARGF.getbyte #=> 102
14446 * ARGF.getbyte #=> 111
14447 * ARGF.getbyte #=> 111
14448 * ARGF.getbyte #=> 10
14449 * ARGF.getbyte #=> nil
14450 */
14451static VALUE
14452argf_getbyte(VALUE argf)
14453{
14454 VALUE ch;
14455
14456 retry:
14457 if (!next_argv()) return Qnil;
14458 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
14459 ch = forward_current(rb_intern("getbyte"), 0, 0);
14460 }
14461 else {
14462 ch = rb_io_getbyte(ARGF.current_file);
14463 }
14464 if (NIL_P(ch) && ARGF.next_p != -1) {
14465 argf_close(argf);
14466 ARGF.next_p = 1;
14467 goto retry;
14468 }
14469
14470 return ch;
14471}
14472
14473/*
14474 * call-seq:
14475 * ARGF.readchar -> String or nil
14476 *
14477 * Reads the next character from ARGF and returns it as a String. Raises
14478 * an EOFError after the last character of the last file has been read.
14479 *
14480 * For example:
14481 *
14482 * $ echo "foo" > file
14483 * $ ruby argf.rb file
14484 *
14485 * ARGF.readchar #=> "f"
14486 * ARGF.readchar #=> "o"
14487 * ARGF.readchar #=> "o"
14488 * ARGF.readchar #=> "\n"
14489 * ARGF.readchar #=> end of file reached (EOFError)
14490 */
14491static VALUE
14492argf_readchar(VALUE argf)
14493{
14494 VALUE ch;
14495
14496 retry:
14497 if (!next_argv()) rb_eof_error();
14498 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
14499 ch = forward_current(rb_intern("getc"), 0, 0);
14500 }
14501 else {
14502 ch = rb_io_getc(ARGF.current_file);
14503 }
14504 if (NIL_P(ch) && ARGF.next_p != -1) {
14505 argf_close(argf);
14506 ARGF.next_p = 1;
14507 goto retry;
14508 }
14509
14510 return ch;
14511}
14512
14513/*
14514 * call-seq:
14515 * ARGF.readbyte -> Integer
14516 *
14517 * Reads the next 8-bit byte from ARGF and returns it as an Integer. Raises
14518 * an EOFError after the last byte of the last file has been read.
14519 *
14520 * For example:
14521 *
14522 * $ echo "foo" > file
14523 * $ ruby argf.rb file
14524 *
14525 * ARGF.readbyte #=> 102
14526 * ARGF.readbyte #=> 111
14527 * ARGF.readbyte #=> 111
14528 * ARGF.readbyte #=> 10
14529 * ARGF.readbyte #=> end of file reached (EOFError)
14530 */
14531static VALUE
14532argf_readbyte(VALUE argf)
14533{
14534 VALUE c;
14535
14536 NEXT_ARGF_FORWARD(0, 0);
14537 c = argf_getbyte(argf);
14538 if (NIL_P(c)) {
14539 rb_eof_error();
14540 }
14541 return c;
14542}
14543
14544#define FOREACH_ARGF() while (next_argv())
14545
14546static VALUE
14547argf_block_call_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
14548{
14549 const VALUE current = ARGF.current_file;
14550 rb_yield_values2(argc, argv);
14551 if (ARGF.init_p == -1 || current != ARGF.current_file) {
14553 }
14554 return Qnil;
14555}
14556
14557#define ARGF_block_call(mid, argc, argv, func, argf) \
14558 rb_block_call_kw(ARGF.current_file, mid, argc, argv, \
14559 func, argf, rb_keyword_given_p())
14560
14561static void
14562argf_block_call(ID mid, int argc, VALUE *argv, VALUE argf)
14563{
14564 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_i, argf);
14565 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14566}
14567
14568static VALUE
14569argf_block_call_line_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
14570{
14571 if (!global_argf_p(argf)) {
14572 ARGF.last_lineno = ++ARGF.lineno;
14573 }
14574 return argf_block_call_i(i, argf, argc, argv, blockarg);
14575}
14576
14577static void
14578argf_block_call_line(ID mid, int argc, VALUE *argv, VALUE argf)
14579{
14580 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_line_i, argf);
14581 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14582}
14583
14584/*
14585 * call-seq:
14586 * ARGF.each(sep=$/) {|line| block } -> ARGF
14587 * ARGF.each(sep=$/, limit) {|line| block } -> ARGF
14588 * ARGF.each(...) -> an_enumerator
14589 *
14590 * ARGF.each_line(sep=$/) {|line| block } -> ARGF
14591 * ARGF.each_line(sep=$/, limit) {|line| block } -> ARGF
14592 * ARGF.each_line(...) -> an_enumerator
14593 *
14594 * Returns an enumerator which iterates over each line (separated by _sep_,
14595 * which defaults to your platform's newline character) of each file in
14596 * +ARGV+. If a block is supplied, each line in turn will be yielded to the
14597 * block, otherwise an enumerator is returned.
14598 * The optional _limit_ argument is an Integer specifying the maximum
14599 * length of each line; longer lines will be split according to this limit.
14600 *
14601 * This method allows you to treat the files supplied on the command line as
14602 * a single file consisting of the concatenation of each named file. After
14603 * the last line of the first file has been returned, the first line of the
14604 * second file is returned. The ARGF.filename and ARGF.lineno methods can be
14605 * used to determine the filename of the current line and line number of the
14606 * whole input, respectively.
14607 *
14608 * For example, the following code prints out each line of each named file
14609 * prefixed with its line number, displaying the filename once per file:
14610 *
14611 * ARGF.each_line do |line|
14612 * puts ARGF.filename if ARGF.file.lineno == 1
14613 * puts "#{ARGF.file.lineno}: #{line}"
14614 * end
14615 *
14616 * While the following code prints only the first file's name at first, and
14617 * the contents with line number counted through all named files.
14618 *
14619 * ARGF.each_line do |line|
14620 * puts ARGF.filename if ARGF.lineno == 1
14621 * puts "#{ARGF.lineno}: #{line}"
14622 * end
14623 */
14624static VALUE
14625argf_each_line(int argc, VALUE *argv, VALUE argf)
14626{
14627 RETURN_ENUMERATOR(argf, argc, argv);
14628 FOREACH_ARGF() {
14629 argf_block_call_line(rb_intern("each_line"), argc, argv, argf);
14630 }
14631 return argf;
14632}
14633
14634/*
14635 * call-seq:
14636 * ARGF.each_byte {|byte| block } -> ARGF
14637 * ARGF.each_byte -> an_enumerator
14638 *
14639 * Iterates over each byte of each file in +ARGV+.
14640 * A byte is returned as an Integer in the range 0..255.
14641 *
14642 * This method allows you to treat the files supplied on the command line as
14643 * a single file consisting of the concatenation of each named file. After
14644 * the last byte of the first file has been returned, the first byte of the
14645 * second file is returned. The ARGF.filename method can be used to
14646 * determine the filename of the current byte.
14647 *
14648 * If no block is given, an enumerator is returned instead.
14649 *
14650 * For example:
14651 *
14652 * ARGF.bytes.to_a #=> [35, 32, ... 95, 10]
14653 *
14654 */
14655static VALUE
14656argf_each_byte(VALUE argf)
14657{
14658 RETURN_ENUMERATOR(argf, 0, 0);
14659 FOREACH_ARGF() {
14660 argf_block_call(rb_intern("each_byte"), 0, 0, argf);
14661 }
14662 return argf;
14663}
14664
14665/*
14666 * call-seq:
14667 * ARGF.each_char {|char| block } -> ARGF
14668 * ARGF.each_char -> an_enumerator
14669 *
14670 * Iterates over each character of each file in ARGF.
14671 *
14672 * This method allows you to treat the files supplied on the command line as
14673 * a single file consisting of the concatenation of each named file. After
14674 * the last character of the first file has been returned, the first
14675 * character of the second file is returned. The ARGF.filename method can
14676 * be used to determine the name of the file in which the current character
14677 * appears.
14678 *
14679 * If no block is given, an enumerator is returned instead.
14680 */
14681static VALUE
14682argf_each_char(VALUE argf)
14683{
14684 RETURN_ENUMERATOR(argf, 0, 0);
14685 FOREACH_ARGF() {
14686 argf_block_call(rb_intern("each_char"), 0, 0, argf);
14687 }
14688 return argf;
14689}
14690
14691/*
14692 * call-seq:
14693 * ARGF.each_codepoint {|codepoint| block } -> ARGF
14694 * ARGF.each_codepoint -> an_enumerator
14695 *
14696 * Iterates over each codepoint of each file in ARGF.
14697 *
14698 * This method allows you to treat the files supplied on the command line as
14699 * a single file consisting of the concatenation of each named file. After
14700 * the last codepoint of the first file has been returned, the first
14701 * codepoint of the second file is returned. The ARGF.filename method can
14702 * be used to determine the name of the file in which the current codepoint
14703 * appears.
14704 *
14705 * If no block is given, an enumerator is returned instead.
14706 */
14707static VALUE
14708argf_each_codepoint(VALUE argf)
14709{
14710 RETURN_ENUMERATOR(argf, 0, 0);
14711 FOREACH_ARGF() {
14712 argf_block_call(rb_intern("each_codepoint"), 0, 0, argf);
14713 }
14714 return argf;
14715}
14716
14717/*
14718 * call-seq:
14719 * ARGF.filename -> String
14720 * ARGF.path -> String
14721 *
14722 * Returns the current filename. "-" is returned when the current file is
14723 * STDIN.
14724 *
14725 * For example:
14726 *
14727 * $ echo "foo" > foo
14728 * $ echo "bar" > bar
14729 * $ echo "glark" > glark
14730 *
14731 * $ ruby argf.rb foo bar glark
14732 *
14733 * ARGF.filename #=> "foo"
14734 * ARGF.read(5) #=> "foo\nb"
14735 * ARGF.filename #=> "bar"
14736 * ARGF.skip
14737 * ARGF.filename #=> "glark"
14738 */
14739static VALUE
14740argf_filename(VALUE argf)
14741{
14742 next_argv();
14743 return ARGF.filename;
14744}
14745
14746static VALUE
14747argf_filename_getter(ID id, VALUE *var)
14748{
14749 return argf_filename(*var);
14750}
14751
14752/*
14753 * call-seq:
14754 * ARGF.file -> IO or File object
14755 *
14756 * Returns the current file as an IO or File object.
14757 * <code>$stdin</code> is returned when the current file is STDIN.
14758 *
14759 * For example:
14760 *
14761 * $ echo "foo" > foo
14762 * $ echo "bar" > bar
14763 *
14764 * $ ruby argf.rb foo bar
14765 *
14766 * ARGF.file #=> #<File:foo>
14767 * ARGF.read(5) #=> "foo\nb"
14768 * ARGF.file #=> #<File:bar>
14769 */
14770static VALUE
14771argf_file(VALUE argf)
14772{
14773 next_argv();
14774 return ARGF.current_file;
14775}
14776
14777/*
14778 * call-seq:
14779 * ARGF.binmode -> ARGF
14780 *
14781 * Puts ARGF into binary mode. Once a stream is in binary mode, it cannot
14782 * be reset to non-binary mode. This option has the following effects:
14783 *
14784 * * Newline conversion is disabled.
14785 * * Encoding conversion is disabled.
14786 * * Content is treated as ASCII-8BIT.
14787 */
14788static VALUE
14789argf_binmode_m(VALUE argf)
14790{
14791 ARGF.binmode = 1;
14792 next_argv();
14793 ARGF_FORWARD(0, 0);
14794 rb_io_ascii8bit_binmode(ARGF.current_file);
14795 return argf;
14796}
14797
14798/*
14799 * call-seq:
14800 * ARGF.binmode? -> true or false
14801 *
14802 * Returns true if ARGF is being read in binary mode; false otherwise.
14803 * To enable binary mode use ARGF.binmode.
14804 *
14805 * For example:
14806 *
14807 * ARGF.binmode? #=> false
14808 * ARGF.binmode
14809 * ARGF.binmode? #=> true
14810 */
14811static VALUE
14812argf_binmode_p(VALUE argf)
14813{
14814 return RBOOL(ARGF.binmode);
14815}
14816
14817/*
14818 * call-seq:
14819 * ARGF.skip -> ARGF
14820 *
14821 * Sets the current file to the next file in ARGV. If there aren't any more
14822 * files it has no effect.
14823 *
14824 * For example:
14825 *
14826 * $ ruby argf.rb foo bar
14827 * ARGF.filename #=> "foo"
14828 * ARGF.skip
14829 * ARGF.filename #=> "bar"
14830 */
14831static VALUE
14832argf_skip(VALUE argf)
14833{
14834 if (ARGF.init_p && ARGF.next_p == 0) {
14835 argf_close(argf);
14836 ARGF.next_p = 1;
14837 }
14838 return argf;
14839}
14840
14841/*
14842 * call-seq:
14843 * ARGF.close -> ARGF
14844 *
14845 * Closes the current file and skips to the next file in ARGV. If there are
14846 * no more files to open, just closes the current file. STDIN will not be
14847 * closed.
14848 *
14849 * For example:
14850 *
14851 * $ ruby argf.rb foo bar
14852 *
14853 * ARGF.filename #=> "foo"
14854 * ARGF.close
14855 * ARGF.filename #=> "bar"
14856 * ARGF.close
14857 */
14858static VALUE
14859argf_close_m(VALUE argf)
14860{
14861 next_argv();
14862 argf_close(argf);
14863 if (ARGF.next_p != -1) {
14864 ARGF.next_p = 1;
14865 }
14866 ARGF.lineno = 0;
14867 return argf;
14868}
14869
14870/*
14871 * call-seq:
14872 * ARGF.closed? -> true or false
14873 *
14874 * Returns _true_ if the current file has been closed; _false_ otherwise. Use
14875 * ARGF.close to actually close the current file.
14876 */
14877static VALUE
14878argf_closed(VALUE argf)
14879{
14880 next_argv();
14881 ARGF_FORWARD(0, 0);
14882 return rb_io_closed_p(ARGF.current_file);
14883}
14884
14885/*
14886 * call-seq:
14887 * ARGF.to_s -> String
14888 *
14889 * Returns "ARGF".
14890 */
14891static VALUE
14892argf_to_s(VALUE argf)
14893{
14894 return rb_str_new2("ARGF");
14895}
14896
14897/*
14898 * call-seq:
14899 * ARGF.inplace_mode -> String
14900 *
14901 * Returns the file extension appended to the names of backup copies of
14902 * modified files under in-place edit mode. This value can be set using
14903 * ARGF.inplace_mode= or passing the +-i+ switch to the Ruby binary.
14904 */
14905static VALUE
14906argf_inplace_mode_get(VALUE argf)
14907{
14908 if (!ARGF.inplace) return Qnil;
14909 if (NIL_P(ARGF.inplace)) return rb_str_new(0, 0);
14910 return rb_str_dup(ARGF.inplace);
14911}
14912
14913static VALUE
14914opt_i_get(ID id, VALUE *var)
14915{
14916 return argf_inplace_mode_get(*var);
14917}
14918
14919/*
14920 * call-seq:
14921 * ARGF.inplace_mode = ext -> ARGF
14922 *
14923 * Sets the filename extension for in-place editing mode to the given String.
14924 * The backup copy of each file being edited has this value appended to its
14925 * filename.
14926 *
14927 * For example:
14928 *
14929 * $ ruby argf.rb file.txt
14930 *
14931 * ARGF.inplace_mode = '.bak'
14932 * ARGF.each_line do |line|
14933 * print line.sub("foo","bar")
14934 * end
14935 *
14936 * First, _file.txt.bak_ is created as a backup copy of _file.txt_.
14937 * Then, each line of _file.txt_ has the first occurrence of "foo" replaced with
14938 * "bar".
14939 */
14940static VALUE
14941argf_inplace_mode_set(VALUE argf, VALUE val)
14942{
14943 if (!RTEST(val)) {
14944 ARGF.inplace = Qfalse;
14945 }
14946 else if (StringValueCStr(val), !RSTRING_LEN(val)) {
14947 ARGF.inplace = Qnil;
14948 }
14949 else {
14950 ARGF_SET(inplace, rb_str_new_frozen(val));
14951 }
14952 return argf;
14953}
14954
14955static void
14956opt_i_set(VALUE val, ID id, VALUE *var)
14957{
14958 argf_inplace_mode_set(*var, val);
14959}
14960
14961void
14962ruby_set_inplace_mode(const char *suffix)
14963{
14964 ARGF_SET(inplace, !suffix ? Qfalse : !*suffix ? Qnil : rb_str_new(suffix, strlen(suffix)));
14965}
14966
14967/*
14968 * call-seq:
14969 * ARGF.argv -> ARGV
14970 *
14971 * Returns the +ARGV+ array, which contains the arguments passed to your
14972 * script, one per element.
14973 *
14974 * For example:
14975 *
14976 * $ ruby argf.rb -v glark.txt
14977 *
14978 * ARGF.argv #=> ["-v", "glark.txt"]
14979 *
14980 */
14981static VALUE
14982argf_argv(VALUE argf)
14983{
14984 return ARGF.argv;
14985}
14986
14987static VALUE
14988argf_argv_getter(ID id, VALUE *var)
14989{
14990 return argf_argv(*var);
14991}
14992
14993VALUE
14995{
14996 return ARGF.argv;
14997}
14998
14999/*
15000 * call-seq:
15001 * ARGF.to_write_io -> io
15002 *
15003 * Returns IO instance tied to _ARGF_ for writing if inplace mode is
15004 * enabled.
15005 */
15006static VALUE
15007argf_write_io(VALUE argf)
15008{
15009 if (!RTEST(ARGF.current_file)) {
15010 rb_raise(rb_eIOError, "not opened for writing");
15011 }
15012 return GetWriteIO(ARGF.current_file);
15013}
15014
15015/*
15016 * call-seq:
15017 * ARGF.write(*objects) -> integer
15018 *
15019 * Writes each of the given +objects+ if inplace mode.
15020 */
15021static VALUE
15022argf_write(int argc, VALUE *argv, VALUE argf)
15023{
15024 return rb_io_writev(argf_write_io(argf), argc, argv);
15025}
15026
15027void
15028rb_readwrite_sys_fail(enum rb_io_wait_readwrite waiting, const char *mesg)
15029{
15030 rb_readwrite_syserr_fail(waiting, errno, mesg);
15031}
15032
15033void
15034rb_readwrite_syserr_fail(enum rb_io_wait_readwrite waiting, int n, const char *mesg)
15035{
15036 VALUE arg, c = Qnil;
15037 arg = mesg ? rb_str_new2(mesg) : Qnil;
15038 switch (waiting) {
15039 case RB_IO_WAIT_WRITABLE:
15040 switch (n) {
15041 case EAGAIN:
15042 c = rb_eEAGAINWaitWritable;
15043 break;
15044#if EAGAIN != EWOULDBLOCK
15045 case EWOULDBLOCK:
15046 c = rb_eEWOULDBLOCKWaitWritable;
15047 break;
15048#endif
15049 case EINPROGRESS:
15050 c = rb_eEINPROGRESSWaitWritable;
15051 break;
15052 default:
15054 }
15055 break;
15056 case RB_IO_WAIT_READABLE:
15057 switch (n) {
15058 case EAGAIN:
15059 c = rb_eEAGAINWaitReadable;
15060 break;
15061#if EAGAIN != EWOULDBLOCK
15062 case EWOULDBLOCK:
15063 c = rb_eEWOULDBLOCKWaitReadable;
15064 break;
15065#endif
15066 case EINPROGRESS:
15067 c = rb_eEINPROGRESSWaitReadable;
15068 break;
15069 default:
15071 }
15072 break;
15073 default:
15074 rb_bug("invalid read/write type passed to rb_readwrite_sys_fail: %d", waiting);
15075 }
15077}
15078
15079static VALUE
15080get_LAST_READ_LINE(ID _x, VALUE *_y)
15081{
15082 return rb_lastline_get();
15083}
15084
15085static void
15086set_LAST_READ_LINE(VALUE val, ID _x, VALUE *_y)
15087{
15088 rb_lastline_set(val);
15089}
15090
15091/*
15092 * Document-class: IOError
15093 *
15094 * Raised when an IO operation fails.
15095 *
15096 * File.open("/etc/hosts") {|f| f << "example"}
15097 * #=> IOError: not opened for writing
15098 *
15099 * File.open("/etc/hosts") {|f| f.close; f.read }
15100 * #=> IOError: closed stream
15101 *
15102 * Note that some IO failures raise <code>SystemCallError</code>s
15103 * and these are not subclasses of IOError:
15104 *
15105 * File.open("does/not/exist")
15106 * #=> Errno::ENOENT: No such file or directory - does/not/exist
15107 */
15108
15109/*
15110 * Document-class: EOFError
15111 *
15112 * Raised by some IO operations when reaching the end of file. Many IO
15113 * methods exist in two forms,
15114 *
15115 * one that returns +nil+ when the end of file is reached, the other
15116 * raises EOFError.
15117 *
15118 * EOFError is a subclass of IOError.
15119 *
15120 * file = File.open("/etc/hosts")
15121 * file.read
15122 * file.gets #=> nil
15123 * file.readline #=> EOFError: end of file reached
15124 * file.close
15125 */
15126
15127/*
15128 * Document-class: ARGF
15129 *
15130 * == \ARGF and +ARGV+
15131 *
15132 * The \ARGF object works with the array at global variable +ARGV+
15133 * to make <tt>$stdin</tt> and file streams available in the Ruby program:
15134 *
15135 * - **ARGV** may be thought of as the <b>argument vector</b> array.
15136 *
15137 * Initially, it contains the command-line arguments and options
15138 * that are passed to the Ruby program;
15139 * the program can modify that array as it likes.
15140 *
15141 * - **ARGF** may be thought of as the <b>argument files</b> object.
15142 *
15143 * It can access file streams and/or the <tt>$stdin</tt> stream,
15144 * based on what it finds in +ARGV+.
15145 * This provides a convenient way for the command line
15146 * to specify streams for a Ruby program to read.
15147 *
15148 * == Reading
15149 *
15150 * \ARGF may read from _source_ streams,
15151 * which at any particular time are determined by the content of +ARGV+.
15152 *
15153 * === Simplest Case
15154 *
15155 * When the <i>very first</i> \ARGF read occurs with an empty +ARGV+ (<tt>[]</tt>),
15156 * the source is <tt>$stdin</tt>:
15157 *
15158 * - \File +t.rb+:
15159 *
15160 * p ['ARGV', ARGV]
15161 * p ['ARGF.read', ARGF.read]
15162 *
15163 * - Commands and outputs
15164 * (see below for the content of files +foo.txt+ and +bar.txt+):
15165 *
15166 * $ echo "Open the pod bay doors, Hal." | ruby t.rb
15167 * ["ARGV", []]
15168 * ["ARGF.read", "Open the pod bay doors, Hal.\n"]
15169 *
15170 * $ cat foo.txt bar.txt | ruby t.rb
15171 * ["ARGV", []]
15172 * ["ARGF.read", "Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"]
15173 *
15174 * === About the Examples
15175 *
15176 * Many examples here assume the existence of files +foo.txt+ and +bar.txt+:
15177 *
15178 * $ cat foo.txt
15179 * Foo 0
15180 * Foo 1
15181 * $ cat bar.txt
15182 * Bar 0
15183 * Bar 1
15184 * Bar 2
15185 * Bar 3
15186 *
15187 * === Sources in +ARGV+
15188 *
15189 * For any \ARGF read _except_ the {simplest case}[rdoc-ref:ARGF@Simplest+Case]
15190 * (that is, _except_ for the <i>very first</i> \ARGF read with an empty +ARGV+),
15191 * the sources are found in +ARGV+.
15192 *
15193 * \ARGF assumes that each element in array +ARGV+ is a potential source,
15194 * and is one of:
15195 *
15196 * - The string path to a file that may be opened as a stream.
15197 * - The character <tt>'-'</tt>, meaning stream <tt>$stdin</tt>.
15198 *
15199 * Each element that is _not_ one of these
15200 * should be removed from +ARGV+ before \ARGF accesses that source.
15201 *
15202 * In the following example:
15203 *
15204 * - Filepaths +foo.txt+ and +bar.txt+ may be retained as potential sources.
15205 * - Options <tt>--xyzzy</tt> and <tt>--mojo</tt> should be removed.
15206 *
15207 * Example:
15208 *
15209 * - \File +t.rb+:
15210 *
15211 * # Print arguments (and options, if any) found on command line.
15212 * p ['ARGV', ARGV]
15213 *
15214 * - Command and output:
15215 *
15216 * $ ruby t.rb --xyzzy --mojo foo.txt bar.txt
15217 * ["ARGV", ["--xyzzy", "--mojo", "foo.txt", "bar.txt"]]
15218 *
15219 * \ARGF's stream access considers the elements of +ARGV+, left to right:
15220 *
15221 * - \File +t.rb+:
15222 *
15223 * p "ARGV: #{ARGV}"
15224 * p "Read: #{ARGF.read}" # Read everything from all specified streams.
15225 *
15226 * - Command and output:
15227 *
15228 * $ ruby t.rb foo.txt bar.txt
15229 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
15230 * "Read: Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"
15231 *
15232 * Because the value at +ARGV+ is an ordinary array,
15233 * you can manipulate it to control which sources \ARGF considers:
15234 *
15235 * - If you remove an element from +ARGV+, \ARGF will not consider the corresponding source.
15236 * - If you add an element to +ARGV+, \ARGF will consider the corresponding source.
15237 *
15238 * Each element in +ARGV+ is removed when its corresponding source is accessed;
15239 * when all sources have been accessed, the array is empty:
15240 *
15241 * - \File +t.rb+:
15242 *
15243 * until ARGV.empty? && ARGF.eof?
15244 * p "ARGV: #{ARGV}"
15245 * p "Line: #{ARGF.readline}" # Read each line from each specified stream.
15246 * end
15247 *
15248 * - Command and output:
15249 *
15250 * $ ruby t.rb foo.txt bar.txt
15251 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
15252 * "Line: Foo 0\n"
15253 * "ARGV: [\"bar.txt\"]"
15254 * "Line: Foo 1\n"
15255 * "ARGV: [\"bar.txt\"]"
15256 * "Line: Bar 0\n"
15257 * "ARGV: []"
15258 * "Line: Bar 1\n"
15259 * "ARGV: []"
15260 * "Line: Bar 2\n"
15261 * "ARGV: []"
15262 * "Line: Bar 3\n"
15263 *
15264 * ==== Filepaths in +ARGV+
15265 *
15266 * The +ARGV+ array may contain filepaths the specify sources for \ARGF reading.
15267 *
15268 * This program prints what it reads from files at the paths specified
15269 * on the command line:
15270 *
15271 * - \File +t.rb+:
15272 *
15273 * p ['ARGV', ARGV]
15274 * # Read and print all content from the specified sources.
15275 * p ['ARGF.read', ARGF.read]
15276 *
15277 * - Command and output:
15278 *
15279 * $ ruby t.rb foo.txt bar.txt
15280 * ["ARGV", [foo.txt, bar.txt]
15281 * ["ARGF.read", "Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"]
15282 *
15283 * ==== Specifying <tt>$stdin</tt> in +ARGV+
15284 *
15285 * To specify stream <tt>$stdin</tt> in +ARGV+, us the character <tt>'-'</tt>:
15286 *
15287 * - \File +t.rb+:
15288 *
15289 * p ['ARGV', ARGV]
15290 * p ['ARGF.read', ARGF.read]
15291 *
15292 * - Command and output:
15293 *
15294 * $ echo "Open the pod bay doors, Hal." | ruby t.rb -
15295 * ["ARGV", ["-"]]
15296 * ["ARGF.read", "Open the pod bay doors, Hal.\n"]
15297 *
15298 * When no character <tt>'-'</tt> is given, stream <tt>$stdin</tt> is ignored.
15299 *
15300 * - Command and output:
15301 *
15302 * $ echo "Open the pod bay doors, Hal." | ruby t.rb foo.txt bar.txt
15303 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
15304 * "Read: Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"
15305 *
15306 * ==== Mixtures and Repetitions in +ARGV+
15307 *
15308 * For an \ARGF reader, +ARGV+ may contain any mixture of filepaths
15309 * and character <tt>'-'</tt>, including repetitions.
15310 *
15311 * ==== Modifications to +ARGV+
15312 *
15313 * The running Ruby program may make any modifications to the +ARGV+ array;
15314 * the current value of +ARGV+ affects \ARGF reading.
15315 *
15316 * ==== Empty +ARGV+
15317 *
15318 * For an empty +ARGV+, an \ARGF read method either returns +nil+
15319 * or raises an exception, depending on the specific method.
15320 *
15321 * === More Read Methods
15322 *
15323 * As seen above, method ARGF#read reads the content of all sources
15324 * into a single string.
15325 * Other \ARGF methods provide other ways to access that content;
15326 * these include:
15327 *
15328 * - Byte access: #each_byte, #getbyte, #readbyte.
15329 * - Character access: #each_char, #getc, #readchar.
15330 * - Codepoint access: #each_codepoint.
15331 * - Line access: #each_line, #gets, #readline, #readlines.
15332 * - Source access: #read, #read_nonblock, #readpartial.
15333 *
15334 * === About \Enumerable
15335 *
15336 * \ARGF includes module Enumerable.
15337 * Virtually all methods in \Enumerable call method <tt>#each</tt> in the including class.
15338 *
15339 * <b>Note well</b>: In \ARGF, method #each returns data from the _sources_,
15340 * _not_ from +ARGV+;
15341 * therefore, for example, <tt>ARGF#entries</tt> returns an array of lines from the sources,
15342 * not an array of the strings from +ARGV+:
15343 *
15344 * - \File +t.rb+:
15345 *
15346 * p ['ARGV', ARGV]
15347 * p ['ARGF.entries', ARGF.entries]
15348 *
15349 * - Command and output:
15350 *
15351 * $ ruby t.rb foo.txt bar.txt
15352 * ["ARGV", ["foo.txt", "bar.txt"]]
15353 * ["ARGF.entries", ["Foo 0\n", "Foo 1\n", "Bar 0\n", "Bar 1\n", "Bar 2\n", "Bar 3\n"]]
15354 *
15355 * == Writing
15356 *
15357 * If <i>inplace mode</i> is in effect,
15358 * \ARGF may write to target streams,
15359 * which at any particular time are determined by the content of ARGV.
15360 *
15361 * Methods about inplace mode:
15362 *
15363 * - #inplace_mode
15364 * - #inplace_mode=
15365 * - #to_write_io
15366 *
15367 * Methods for writing:
15368 *
15369 * - #print
15370 * - #printf
15371 * - #putc
15372 * - #puts
15373 * - #write
15374 *
15375 */
15376
15377/*
15378 * An instance of class \IO (commonly called a _stream_)
15379 * represents an input/output stream in the underlying operating system.
15380 * Class \IO is the basis for input and output in Ruby.
15381 *
15382 * Class File is the only class in the Ruby core that is a subclass of \IO.
15383 * Some classes in the Ruby standard library are also subclasses of \IO;
15384 * these include TCPSocket and UDPSocket.
15385 *
15386 * The global constant ARGF (also accessible as <tt>$<</tt>)
15387 * provides an IO-like stream that allows access to all file paths
15388 * found in ARGV (or found in STDIN if ARGV is empty).
15389 * ARGF is not itself a subclass of \IO.
15390 *
15391 * Class StringIO provides an IO-like stream that handles a String.
15392 * StringIO is not itself a subclass of \IO.
15393 *
15394 * Important objects based on \IO include:
15395 *
15396 * - $stdin.
15397 * - $stdout.
15398 * - $stderr.
15399 * - Instances of class File.
15400 *
15401 * An instance of \IO may be created using:
15402 *
15403 * - IO.new: returns a new \IO object for the given integer file descriptor.
15404 * - IO.open: passes a new \IO object to the given block.
15405 * - IO.popen: returns a new \IO object that is connected to the $stdin and $stdout
15406 * of a newly-launched subprocess.
15407 * - Kernel#open: Returns a new \IO object connected to a given source:
15408 * stream, file, or subprocess.
15409 *
15410 * Like a File stream, an \IO stream has:
15411 *
15412 * - A read/write mode, which may be read-only, write-only, or read/write;
15413 * see {Read/Write Mode}[rdoc-ref:File@ReadWrite+Mode].
15414 * - A data mode, which may be text-only or binary;
15415 * see {Data Mode}[rdoc-ref:File@Data+Mode].
15416 * - Internal and external encodings;
15417 * see {Encodings}[rdoc-ref:File@Encodings].
15418 *
15419 * And like other \IO streams, it has:
15420 *
15421 * - A position, which determines where in the stream the next
15422 * read or write is to occur;
15423 * see {Position}[rdoc-ref:IO@Position].
15424 * - A line number, which is a special, line-oriented, "position"
15425 * (different from the position mentioned above);
15426 * see {Line Number}[rdoc-ref:IO@Line+Number].
15427 *
15428 * == Extension <tt>io/console</tt>
15429 *
15430 * Extension <tt>io/console</tt> provides numerous methods
15431 * for interacting with the console;
15432 * requiring it adds numerous methods to class \IO.
15433 *
15434 * == Example Files
15435 *
15436 * Many examples here use these variables:
15437 *
15438 * :include: doc/examples/files.rdoc
15439 *
15440 * == Open Options
15441 *
15442 * A number of \IO methods accept optional keyword arguments
15443 * that determine how a new stream is to be opened:
15444 *
15445 * - +:mode+: Stream mode.
15446 * - +:flags+: Integer file open flags;
15447 * If +mode+ is also given, the two are bitwise-ORed.
15448 * - +:external_encoding+: External encoding for the stream.
15449 * - +:internal_encoding+: Internal encoding for the stream.
15450 * <tt>'-'</tt> is a synonym for the default internal encoding.
15451 * If the value is +nil+ no conversion occurs.
15452 * - +:encoding+: Specifies external and internal encodings as <tt>'extern:intern'</tt>.
15453 * - +:textmode+: If a truthy value, specifies the mode as text-only, binary otherwise.
15454 * - +:binmode+: If a truthy value, specifies the mode as binary, text-only otherwise.
15455 * - +:autoclose+: If a truthy value, specifies that the +fd+ will close
15456 * when the stream closes; otherwise it remains open.
15457 * - +:path+: If a string value is provided, it is used in #inspect and is available as
15458 * #path method.
15459 *
15460 * Also available are the options offered in String#encode,
15461 * which may control conversion between external and internal encoding.
15462 *
15463 * == Basic \IO
15464 *
15465 * You can perform basic stream \IO with these methods,
15466 * which typically operate on multi-byte strings:
15467 *
15468 * - IO#read: Reads and returns some or all of the remaining bytes from the stream.
15469 * - IO#write: Writes zero or more strings to the stream;
15470 * each given object that is not already a string is converted via +to_s+.
15471 *
15472 * === Position
15473 *
15474 * An \IO stream has a nonnegative integer _position_,
15475 * which is the byte offset at which the next read or write is to occur.
15476 * A new stream has position zero (and line number zero);
15477 * method +rewind+ resets the position (and line number) to zero.
15478 *
15479 * These methods discard {buffers}[rdoc-ref:IO@Buffering] and the
15480 * Encoding::Converter instances used for that \IO.
15481 *
15482 * The relevant methods:
15483 *
15484 * - IO#tell (aliased as +#pos+): Returns the current position (in bytes) in the stream.
15485 * - IO#pos=: Sets the position of the stream to a given integer +new_position+ (in bytes).
15486 * - IO#seek: Sets the position of the stream to a given integer +offset+ (in bytes),
15487 * relative to a given position +whence+
15488 * (indicating the beginning, end, or current position).
15489 * - IO#rewind: Positions the stream at the beginning (also resetting the line number).
15490 *
15491 * === Open and Closed Streams
15492 *
15493 * A new \IO stream may be open for reading, open for writing, or both.
15494 *
15495 * A stream is automatically closed when claimed by the garbage collector.
15496 *
15497 * Attempted reading or writing on a closed stream raises an exception.
15498 *
15499 * The relevant methods:
15500 *
15501 * - IO#close: Closes the stream for both reading and writing.
15502 * - IO#close_read: Closes the stream for reading.
15503 * - IO#close_write: Closes the stream for writing.
15504 * - IO#closed?: Returns whether the stream is closed.
15505 *
15506 * === End-of-Stream
15507 *
15508 * You can query whether a stream is positioned at its end:
15509 *
15510 * - IO#eof? (also aliased as +#eof+): Returns whether the stream is at end-of-stream.
15511 *
15512 * You can reposition to end-of-stream by using method IO#seek:
15513 *
15514 * f = File.new('t.txt')
15515 * f.eof? # => false
15516 * f.seek(0, :END)
15517 * f.eof? # => true
15518 * f.close
15519 *
15520 * Or by reading all stream content (which is slower than using IO#seek):
15521 *
15522 * f.rewind
15523 * f.eof? # => false
15524 * f.read # => "First line\nSecond line\n\nFourth line\nFifth line\n"
15525 * f.eof? # => true
15526 *
15527 * == Line \IO
15528 *
15529 * Class \IO supports line-oriented
15530 * {input}[rdoc-ref:IO@Line+Input] and {output}[rdoc-ref:IO@Line+Output]
15531 *
15532 * === Line Input
15533 *
15534 * Class \IO supports line-oriented input for
15535 * {files}[rdoc-ref:IO@File+Line+Input] and {IO streams}[rdoc-ref:IO@Stream+Line+Input].
15536 *
15537 * ==== Line Input Options
15538 *
15539 * Optional keyword argument +chomp+ (default: +false+)
15540 * specifies whether line separators are to be excluded from the result of a read.
15541 *
15542 * ==== \File Line Input
15543 *
15544 * You can read lines from a file using these methods:
15545 *
15546 * - IO.foreach: Reads each line and passes it to the given block.
15547 * - IO.readlines: Reads and returns all lines in an array.
15548 *
15549 * For each of these methods:
15550 *
15551 * - You can specify {open options}[rdoc-ref:IO@Open+Options].
15552 * - Line parsing depends on the effective <i>line separator</i>;
15553 * see {Line Separator}[rdoc-ref:IO@Line+Separator].
15554 * - The length of each returned line depends on the effective <i>line limit</i>;
15555 * see {Line Limit}[rdoc-ref:IO@Line+Limit].
15556 *
15557 * ==== Stream Line Input
15558 *
15559 * You can read lines from an \IO stream using these methods:
15560 *
15561 * - IO#each_line: Reads each remaining line, passing it to the given block.
15562 * - IO#gets: Returns the next line.
15563 * - IO#readline: Like #gets, but raises an exception at end-of-stream.
15564 * - IO#readlines: Returns all remaining lines in an array.
15565 *
15566 * For each of these methods:
15567 *
15568 * - Reading may begin mid-line,
15569 * depending on the stream's _position_;
15570 * see {Position}[rdoc-ref:IO@Position].
15571 * - Line parsing depends on the effective <i>line separator</i>;
15572 * see {Line Separator}[rdoc-ref:IO@Line+Separator].
15573 * - The length of each returned line depends on the effective <i>line limit</i>;
15574 * see {Line Limit}[rdoc-ref:IO@Line+Limit].
15575 *
15576 * ===== Line Separator
15577 *
15578 * Each of the {line input methods}[rdoc-ref:IO@Line+Input] uses a <i>line separator</i>:
15579 * the string that determines what is considered a line;
15580 * it is sometimes called the <i>input record separator</i>.
15581 *
15582 * The default line separator is taken from global variable <tt>$/</tt>,
15583 * whose initial value is <tt>"\n"</tt>.
15584 *
15585 * Generally, the line to be read next is all data
15586 * from the current {position}[rdoc-ref:IO@Position]
15587 * to the next line separator
15588 * (but see {Special Line Separator Values}[rdoc-ref:IO@Special+Line+Separator+Values]):
15589 *
15590 * f = File.new('t.txt')
15591 * # Method gets with no sep argument returns the next line, according to $/.
15592 * f.gets # => "First line\n"
15593 * f.gets # => "Second line\n"
15594 * f.gets # => "\n"
15595 * f.gets # => "Fourth line\n"
15596 * f.gets # => "Fifth line\n"
15597 * f.close
15598 *
15599 * You can use a different line separator by passing argument +sep+:
15600 *
15601 * f = File.new('t.txt')
15602 * f.gets('l') # => "First l"
15603 * f.gets('li') # => "ine\nSecond li"
15604 * f.gets('lin') # => "ne\n\nFourth lin"
15605 * f.gets # => "e\n"
15606 * f.close
15607 *
15608 * Or by setting global variable <tt>$/</tt>:
15609 *
15610 * f = File.new('t.txt')
15611 * $/ = 'l'
15612 * f.gets # => "First l"
15613 * f.gets # => "ine\nSecond l"
15614 * f.gets # => "ine\n\nFourth l"
15615 * f.close
15616 *
15617 * ===== Special Line Separator Values
15618 *
15619 * Each of the {line input methods}[rdoc-ref:IO@Line+Input]
15620 * accepts two special values for parameter +sep+:
15621 *
15622 * - +nil+: The entire stream is to be read ("slurped") into a single string:
15623 *
15624 * f = File.new('t.txt')
15625 * f.gets(nil) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
15626 * f.close
15627 *
15628 * - <tt>''</tt> (the empty string): The next "paragraph" is to be read
15629 * (paragraphs being separated by two consecutive line separators):
15630 *
15631 * f = File.new('t.txt')
15632 * f.gets('') # => "First line\nSecond line\n\n"
15633 * f.gets('') # => "Fourth line\nFifth line\n"
15634 * f.close
15635 *
15636 * ===== Line Limit
15637 *
15638 * Each of the {line input methods}[rdoc-ref:IO@Line+Input]
15639 * uses an integer <i>line limit</i>,
15640 * which restricts the number of bytes that may be returned.
15641 * (A multi-byte character will not be split, and so a returned line may be slightly longer
15642 * than the limit).
15643 *
15644 * The default limit value is <tt>-1</tt>;
15645 * any negative limit value means that there is no limit.
15646 *
15647 * If there is no limit, the line is determined only by +sep+.
15648 *
15649 * # Text with 1-byte characters.
15650 * File.open('t.txt') {|f| f.gets(1) } # => "F"
15651 * File.open('t.txt') {|f| f.gets(2) } # => "Fi"
15652 * File.open('t.txt') {|f| f.gets(3) } # => "Fir"
15653 * File.open('t.txt') {|f| f.gets(4) } # => "Firs"
15654 * # No more than one line.
15655 * File.open('t.txt') {|f| f.gets(10) } # => "First line"
15656 * File.open('t.txt') {|f| f.gets(11) } # => "First line\n"
15657 * File.open('t.txt') {|f| f.gets(12) } # => "First line\n"
15658 *
15659 * # Text with 3-byte characters, which will not be split.
15660 * File.read('t.ja') # => "こんにちは"
15661 * File.open('t.ja') {|f| f.gets(1).size } # => 1
15662 * File.open('t.ja') {|f| f.gets(2).size } # => 1
15663 * File.open('t.ja') {|f| f.gets(3).size } # => 1
15664 * File.open('t.ja') {|f| f.gets(4).size } # => 2
15665 * File.open('t.ja') {|f| f.gets(5).size } # => 2
15666 *
15667 * ===== Line Separator and Line Limit
15668 *
15669 * With arguments +sep+ and +limit+ given, combines the two behaviors:
15670 *
15671 * - Returns the next line as determined by line separator +sep+.
15672 * - But returns no more bytes than are allowed by the limit +limit+.
15673 *
15674 * Example:
15675 *
15676 * File.open('t.txt') {|f| f.gets('li', 20) } # => "First li"
15677 * File.open('t.txt') {|f| f.gets('li', 2) } # => "Fi"
15678 *
15679 * ===== Line Number
15680 *
15681 * A readable \IO stream has a non-negative integer <i>line number</i>:
15682 *
15683 * - IO#lineno: Returns the line number.
15684 * - IO#lineno=: Resets and returns the line number.
15685 *
15686 * Unless modified by a call to method IO#lineno=,
15687 * the line number is the number of lines read
15688 * by certain line-oriented methods,
15689 * according to the effective {line separator}[rdoc-ref:IO@Line+Separator]:
15690 *
15691 * - IO.foreach: Increments the line number on each call to the block.
15692 * - IO#each_line: Increments the line number on each call to the block.
15693 * - IO#gets: Increments the line number.
15694 * - IO#readline: Increments the line number.
15695 * - IO#readlines: Increments the line number for each line read.
15696 *
15697 * A new stream is initially has line number zero (and position zero);
15698 * method +rewind+ resets the line number (and position) to zero:
15699 *
15700 * f = File.new('t.txt')
15701 * f.lineno # => 0
15702 * f.gets # => "First line\n"
15703 * f.lineno # => 1
15704 * f.rewind
15705 * f.lineno # => 0
15706 * f.close
15707 *
15708 * Reading lines from a stream usually changes its line number:
15709 *
15710 * f = File.new('t.txt', 'r')
15711 * f.lineno # => 0
15712 * f.readline # => "This is line one.\n"
15713 * f.lineno # => 1
15714 * f.readline # => "This is the second line.\n"
15715 * f.lineno # => 2
15716 * f.readline # => "Here's the third line.\n"
15717 * f.lineno # => 3
15718 * f.eof? # => true
15719 * f.close
15720 *
15721 * Iterating over lines in a stream usually changes its line number:
15722 *
15723 * File.open('t.txt') do |f|
15724 * f.each_line do |line|
15725 * p "position=#{f.pos} eof?=#{f.eof?} lineno=#{f.lineno}"
15726 * end
15727 * end
15728 *
15729 * Output:
15730 *
15731 * "position=11 eof?=false lineno=1"
15732 * "position=23 eof?=false lineno=2"
15733 * "position=24 eof?=false lineno=3"
15734 * "position=36 eof?=false lineno=4"
15735 * "position=47 eof?=true lineno=5"
15736 *
15737 * Unlike the stream's {position}[rdoc-ref:IO@Position],
15738 * the line number does not affect where the next read or write will occur:
15739 *
15740 * f = File.new('t.txt')
15741 * f.lineno = 1000
15742 * f.lineno # => 1000
15743 * f.gets # => "First line\n"
15744 * f.lineno # => 1001
15745 * f.close
15746 *
15747 * Associated with the line number is the global variable <tt>$.</tt>:
15748 *
15749 * - When a stream is opened, <tt>$.</tt> is not set;
15750 * its value is left over from previous activity in the process:
15751 *
15752 * $. = 41
15753 * f = File.new('t.txt')
15754 * $. = 41
15755 * # => 41
15756 * f.close
15757 *
15758 * - When a stream is read, <tt>$.</tt> is set to the line number for that stream:
15759 *
15760 * f0 = File.new('t.txt')
15761 * f1 = File.new('t.dat')
15762 * f0.readlines # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
15763 * $. # => 5
15764 * f1.readlines # => ["\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"]
15765 * $. # => 1
15766 * f0.close
15767 * f1.close
15768 *
15769 * - Methods IO#rewind and IO#seek do not affect <tt>$.</tt>:
15770 *
15771 * f = File.new('t.txt')
15772 * f.readlines # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
15773 * $. # => 5
15774 * f.rewind
15775 * f.seek(0, :SET)
15776 * $. # => 5
15777 * f.close
15778 *
15779 * === Line Output
15780 *
15781 * You can write to an \IO stream line-by-line using this method:
15782 *
15783 * - IO#puts: Writes objects to the stream.
15784 *
15785 * == Character \IO
15786 *
15787 * You can process an \IO stream character-by-character using these methods:
15788 *
15789 * - IO#getc: Reads and returns the next character from the stream.
15790 * - IO#readchar: Like #getc, but raises an exception at end-of-stream.
15791 * - IO#ungetc: Pushes back ("unshifts") a character or integer onto the stream.
15792 * - IO#putc: Writes a character to the stream.
15793 * - IO#each_char: Reads each remaining character in the stream,
15794 * passing the character to the given block.
15795 *
15796 * == Byte \IO
15797 *
15798 * You can process an \IO stream byte-by-byte using these methods:
15799 *
15800 * - IO#getbyte: Returns the next 8-bit byte as an integer in range 0..255.
15801 * - IO#readbyte: Like #getbyte, but raises an exception if at end-of-stream.
15802 * - IO#ungetbyte: Pushes back ("unshifts") a byte back onto the stream.
15803 * - IO#each_byte: Reads each remaining byte in the stream,
15804 * passing the byte to the given block.
15805 *
15806 * == Codepoint \IO
15807 *
15808 * You can process an \IO stream codepoint-by-codepoint:
15809 *
15810 * - IO#each_codepoint: Reads each remaining codepoint, passing it to the given block.
15811 *
15812 * == What's Here
15813 *
15814 * First, what's elsewhere. Class \IO:
15815 *
15816 * - Inherits from {class Object}[rdoc-ref:Object@Whats+Here].
15817 * - Includes {module Enumerable}[rdoc-ref:Enumerable@Whats+Here],
15818 * which provides dozens of additional methods.
15819 *
15820 * Here, class \IO provides methods that are useful for:
15821 *
15822 * - {Creating}[rdoc-ref:IO@Creating]
15823 * - {Reading}[rdoc-ref:IO@Reading]
15824 * - {Writing}[rdoc-ref:IO@Writing]
15825 * - {Positioning}[rdoc-ref:IO@Positioning]
15826 * - {Iterating}[rdoc-ref:IO@Iterating]
15827 * - {Settings}[rdoc-ref:IO@Settings]
15828 * - {Querying}[rdoc-ref:IO@Querying]
15829 * - {Buffering}[rdoc-ref:IO@Buffering]
15830 * - {Low-Level Access}[rdoc-ref:IO@Low-Level+Access]
15831 * - {Other}[rdoc-ref:IO@Other]
15832 *
15833 * === Creating
15834 *
15835 * - ::new (aliased as ::for_fd): Creates and returns a new \IO object for the given
15836 * integer file descriptor.
15837 * - ::open: Creates a new \IO object.
15838 * - ::pipe: Creates a connected pair of reader and writer \IO objects.
15839 * - ::popen: Creates an \IO object to interact with a subprocess.
15840 * - ::select: Selects which given \IO instances are ready for reading,
15841 * writing, or have pending exceptions.
15842 *
15843 * === Reading
15844 *
15845 * - ::binread: Returns a binary string with all or a subset of bytes
15846 * from the given file.
15847 * - ::read: Returns a string with all or a subset of bytes from the given file.
15848 * - ::readlines: Returns an array of strings, which are the lines from the given file.
15849 * - #getbyte: Returns the next 8-bit byte read from +self+ as an integer.
15850 * - #getc: Returns the next character read from +self+ as a string.
15851 * - #gets: Returns the line read from +self+.
15852 * - #pread: Returns all or the next _n_ bytes read from +self+,
15853 * not updating the receiver's offset.
15854 * - #read: Returns all remaining or the next _n_ bytes read from +self+
15855 * for a given _n_.
15856 * - #read_nonblock: the next _n_ bytes read from +self+ for a given _n_,
15857 * in non-block mode.
15858 * - #readbyte: Returns the next byte read from +self+;
15859 * same as #getbyte, but raises an exception on end-of-stream.
15860 * - #readchar: Returns the next character read from +self+;
15861 * same as #getc, but raises an exception on end-of-stream.
15862 * - #readline: Returns the next line read from +self+;
15863 * same as #getline, but raises an exception of end-of-stream.
15864 * - #readlines: Returns an array of all lines read read from +self+.
15865 * - #readpartial: Returns up to the given number of bytes from +self+.
15866 *
15867 * === Writing
15868 *
15869 * - ::binwrite: Writes the given string to the file at the given filepath,
15870 * in binary mode.
15871 * - ::write: Writes the given string to +self+.
15872 * - #<<: Appends the given string to +self+.
15873 * - #print: Prints last read line or given objects to +self+.
15874 * - #printf: Writes to +self+ based on the given format string and objects.
15875 * - #putc: Writes a character to +self+.
15876 * - #puts: Writes lines to +self+, making sure line ends with a newline.
15877 * - #pwrite: Writes the given string at the given offset,
15878 * not updating the receiver's offset.
15879 * - #write: Writes one or more given strings to +self+.
15880 * - #write_nonblock: Writes one or more given strings to +self+ in non-blocking mode.
15881 *
15882 * === Positioning
15883 *
15884 * - #lineno: Returns the current line number in +self+.
15885 * - #lineno=: Sets the line number is +self+.
15886 * - #pos (aliased as #tell): Returns the current byte offset in +self+.
15887 * - #pos=: Sets the byte offset in +self+.
15888 * - #reopen: Reassociates +self+ with a new or existing \IO stream.
15889 * - #rewind: Positions +self+ to the beginning of input.
15890 * - #seek: Sets the offset for +self+ relative to given position.
15891 *
15892 * === Iterating
15893 *
15894 * - ::foreach: Yields each line of given file to the block.
15895 * - #each (aliased as #each_line): Calls the given block
15896 * with each successive line in +self+.
15897 * - #each_byte: Calls the given block with each successive byte in +self+
15898 * as an integer.
15899 * - #each_char: Calls the given block with each successive character in +self+
15900 * as a string.
15901 * - #each_codepoint: Calls the given block with each successive codepoint in +self+
15902 * as an integer.
15903 *
15904 * === Settings
15905 *
15906 * - #autoclose=: Sets whether +self+ auto-closes.
15907 * - #binmode: Sets +self+ to binary mode.
15908 * - #close: Closes +self+.
15909 * - #close_on_exec=: Sets the close-on-exec flag.
15910 * - #close_read: Closes +self+ for reading.
15911 * - #close_write: Closes +self+ for writing.
15912 * - #set_encoding: Sets the encoding for +self+.
15913 * - #set_encoding_by_bom: Sets the encoding for +self+, based on its
15914 * Unicode byte-order-mark.
15915 * - #sync=: Sets the sync-mode to the given value.
15916 *
15917 * === Querying
15918 *
15919 * - #autoclose?: Returns whether +self+ auto-closes.
15920 * - #binmode?: Returns whether +self+ is in binary mode.
15921 * - #close_on_exec?: Returns the close-on-exec flag for +self+.
15922 * - #closed?: Returns whether +self+ is closed.
15923 * - #eof? (aliased as #eof): Returns whether +self+ is at end-of-stream.
15924 * - #external_encoding: Returns the external encoding object for +self+.
15925 * - #fileno (aliased as #to_i): Returns the integer file descriptor for +self+
15926 * - #internal_encoding: Returns the internal encoding object for +self+.
15927 * - #pid: Returns the process ID of a child process associated with +self+,
15928 * if +self+ was created by ::popen.
15929 * - #stat: Returns the File::Stat object containing status information for +self+.
15930 * - #sync: Returns whether +self+ is in sync-mode.
15931 * - #tty? (aliased as #isatty): Returns whether +self+ is a terminal.
15932 *
15933 * === Buffering
15934 *
15935 * - #fdatasync: Immediately writes all buffered data in +self+ to disk.
15936 * - #flush: Flushes any buffered data within +self+ to the underlying
15937 * operating system.
15938 * - #fsync: Immediately writes all buffered data and attributes in +self+ to disk.
15939 * - #ungetbyte: Prepends buffer for +self+ with given integer byte or string.
15940 * - #ungetc: Prepends buffer for +self+ with given string.
15941 *
15942 * === Low-Level Access
15943 *
15944 * - ::sysopen: Opens the file given by its path,
15945 * returning the integer file descriptor.
15946 * - #advise: Announces the intention to access data from +self+ in a specific way.
15947 * - #fcntl: Passes a low-level command to the file specified
15948 * by the given file descriptor.
15949 * - #ioctl: Passes a low-level command to the device specified
15950 * by the given file descriptor.
15951 * - #sysread: Returns up to the next _n_ bytes read from self using a low-level read.
15952 * - #sysseek: Sets the offset for +self+.
15953 * - #syswrite: Writes the given string to +self+ using a low-level write.
15954 *
15955 * === Other
15956 *
15957 * - ::copy_stream: Copies data from a source to a destination,
15958 * each of which is a filepath or an \IO-like object.
15959 * - ::try_convert: Returns a new \IO object resulting from converting
15960 * the given object.
15961 * - #inspect: Returns the string representation of +self+.
15962 *
15963 */
15964
15965void
15966Init_IO(void)
15967{
15968 VALUE rb_cARGF;
15969#ifdef __CYGWIN__
15970#include <sys/cygwin.h>
15971 static struct __cygwin_perfile pf[] =
15972 {
15973 {"", O_RDONLY | O_BINARY},
15974 {"", O_WRONLY | O_BINARY},
15975 {"", O_RDWR | O_BINARY},
15976 {"", O_APPEND | O_BINARY},
15977 {NULL, 0}
15978 };
15979 cygwin_internal(CW_PERFILE, pf);
15980#endif
15981
15982 rb_eIOError = rb_define_class("IOError", rb_eStandardError);
15983 rb_eEOFError = rb_define_class("EOFError", rb_eIOError);
15984
15985 id_write = rb_intern_const("write");
15986 id_read = rb_intern_const("read");
15987 id_flush = rb_intern_const("flush");
15988 id_readpartial = rb_intern_const("readpartial");
15989 id_set_encoding = rb_intern_const("set_encoding");
15990 id_fileno = rb_intern_const("fileno");
15991
15992 rb_define_global_function("syscall", rb_f_syscall, -1);
15993
15994 rb_define_global_function("open", rb_f_open, -1);
15995 rb_define_global_function("printf", rb_f_printf, -1);
15996 rb_define_global_function("print", rb_f_print, -1);
15997 rb_define_global_function("putc", rb_f_putc, 1);
15998 rb_define_global_function("puts", rb_f_puts, -1);
15999 rb_define_global_function("gets", rb_f_gets, -1);
16000 rb_define_global_function("readline", rb_f_readline, -1);
16001 rb_define_global_function("select", rb_f_select, -1);
16002
16003 rb_define_global_function("readlines", rb_f_readlines, -1);
16004
16005 rb_define_global_function("`", rb_f_backquote, 1);
16006
16007 rb_define_global_function("p", rb_f_p, -1);
16008 rb_define_method(rb_mKernel, "display", rb_obj_display, -1);
16009
16010 rb_cIO = rb_define_class("IO", rb_cObject);
16012
16013 /* Can be raised by IO operations when IO#timeout= is set. */
16014 rb_eIOTimeoutError = rb_define_class_under(rb_cIO, "TimeoutError", rb_eIOError);
16015
16016 /* Readable event mask for IO#wait. */
16017 rb_define_const(rb_cIO, "READABLE", INT2NUM(RUBY_IO_READABLE));
16018 /* Writable event mask for IO#wait. */
16019 rb_define_const(rb_cIO, "WRITABLE", INT2NUM(RUBY_IO_WRITABLE));
16020 /* Priority event mask for IO#wait. */
16021 rb_define_const(rb_cIO, "PRIORITY", INT2NUM(RUBY_IO_PRIORITY));
16022
16023 /* exception to wait for reading. see IO.select. */
16024 rb_mWaitReadable = rb_define_module_under(rb_cIO, "WaitReadable");
16025 /* exception to wait for writing. see IO.select. */
16026 rb_mWaitWritable = rb_define_module_under(rb_cIO, "WaitWritable");
16027 /* exception to wait for reading by EAGAIN. see IO.select. */
16028 rb_eEAGAINWaitReadable = rb_define_class_under(rb_cIO, "EAGAINWaitReadable", rb_eEAGAIN);
16029 rb_include_module(rb_eEAGAINWaitReadable, rb_mWaitReadable);
16030 /* exception to wait for writing by EAGAIN. see IO.select. */
16031 rb_eEAGAINWaitWritable = rb_define_class_under(rb_cIO, "EAGAINWaitWritable", rb_eEAGAIN);
16032 rb_include_module(rb_eEAGAINWaitWritable, rb_mWaitWritable);
16033#if EAGAIN == EWOULDBLOCK
16034 /* same as IO::EAGAINWaitReadable */
16035 rb_define_const(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEAGAINWaitReadable);
16036 /* same as IO::EAGAINWaitWritable */
16037 rb_define_const(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEAGAINWaitWritable);
16038#else
16039 /* exception to wait for reading by EWOULDBLOCK. see IO.select. */
16040 rb_eEWOULDBLOCKWaitReadable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEWOULDBLOCK);
16041 rb_include_module(rb_eEWOULDBLOCKWaitReadable, rb_mWaitReadable);
16042 /* exception to wait for writing by EWOULDBLOCK. see IO.select. */
16043 rb_eEWOULDBLOCKWaitWritable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEWOULDBLOCK);
16044 rb_include_module(rb_eEWOULDBLOCKWaitWritable, rb_mWaitWritable);
16045#endif
16046 /* exception to wait for reading by EINPROGRESS. see IO.select. */
16047 rb_eEINPROGRESSWaitReadable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitReadable", rb_eEINPROGRESS);
16048 rb_include_module(rb_eEINPROGRESSWaitReadable, rb_mWaitReadable);
16049 /* exception to wait for writing by EINPROGRESS. see IO.select. */
16050 rb_eEINPROGRESSWaitWritable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitWritable", rb_eEINPROGRESS);
16051 rb_include_module(rb_eEINPROGRESSWaitWritable, rb_mWaitWritable);
16052
16053#if 0
16054 /* This is necessary only for forcing rdoc handle File::open */
16055 rb_define_singleton_method(rb_cFile, "open", rb_io_s_open, -1);
16056#endif
16057
16058 rb_define_alloc_func(rb_cIO, io_alloc);
16059 rb_define_singleton_method(rb_cIO, "new", rb_io_s_new, -1);
16060 rb_define_singleton_method(rb_cIO, "open", rb_io_s_open, -1);
16061 rb_define_singleton_method(rb_cIO, "sysopen", rb_io_s_sysopen, -1);
16062 rb_define_singleton_method(rb_cIO, "for_fd", rb_io_s_for_fd, -1);
16063 rb_define_singleton_method(rb_cIO, "popen", rb_io_s_popen, -1);
16064 rb_define_singleton_method(rb_cIO, "foreach", rb_io_s_foreach, -1);
16065 rb_define_singleton_method(rb_cIO, "readlines", rb_io_s_readlines, -1);
16066 rb_define_singleton_method(rb_cIO, "read", rb_io_s_read, -1);
16067 rb_define_singleton_method(rb_cIO, "binread", rb_io_s_binread, -1);
16068 rb_define_singleton_method(rb_cIO, "write", rb_io_s_write, -1);
16069 rb_define_singleton_method(rb_cIO, "binwrite", rb_io_s_binwrite, -1);
16070 rb_define_singleton_method(rb_cIO, "select", rb_f_select, -1);
16071 rb_define_singleton_method(rb_cIO, "pipe", rb_io_s_pipe, -1);
16072 rb_define_singleton_method(rb_cIO, "try_convert", rb_io_s_try_convert, 1);
16073 rb_define_singleton_method(rb_cIO, "copy_stream", rb_io_s_copy_stream, -1);
16074
16075 rb_define_method(rb_cIO, "initialize", rb_io_initialize, -1);
16076
16078 rb_define_hooked_variable("$,", &rb_output_fs, 0, rb_deprecated_str_setter);
16079
16080 rb_default_rs = rb_fstring_lit("\n"); /* avoid modifying RS_default */
16081 rb_vm_register_global_object(rb_default_rs);
16082 rb_rs = rb_default_rs;
16084 rb_define_hooked_variable("$/", &rb_rs, 0, deprecated_rs_setter);
16085 rb_gvar_ractor_local("$/"); // not local but ractor safe
16086 rb_define_hooked_variable("$-0", &rb_rs, 0, deprecated_rs_setter);
16087 rb_gvar_ractor_local("$-0"); // not local but ractor safe
16088 rb_define_hooked_variable("$\\", &rb_output_rs, 0, rb_deprecated_str_setter);
16089
16090 rb_define_virtual_variable("$_", get_LAST_READ_LINE, set_LAST_READ_LINE);
16091 rb_gvar_ractor_local("$_");
16092 rb_gvar_box_dynamic("$_");
16093
16094 rb_define_method(rb_cIO, "initialize_copy", rb_io_init_copy, 1);
16095 rb_define_method(rb_cIO, "reopen", rb_io_reopen, -1);
16096
16097 rb_define_method(rb_cIO, "print", rb_io_print, -1);
16098 rb_define_method(rb_cIO, "putc", rb_io_putc, 1);
16099 rb_define_method(rb_cIO, "puts", rb_io_puts, -1);
16100 rb_define_method(rb_cIO, "printf", rb_io_printf, -1);
16101
16102 rb_define_method(rb_cIO, "each", rb_io_each_line, -1);
16103 rb_define_method(rb_cIO, "each_line", rb_io_each_line, -1);
16104 rb_define_method(rb_cIO, "each_byte", rb_io_each_byte, 0);
16105 rb_define_method(rb_cIO, "each_char", rb_io_each_char, 0);
16106 rb_define_method(rb_cIO, "each_codepoint", rb_io_each_codepoint, 0);
16107
16108 rb_define_method(rb_cIO, "syswrite", rb_io_syswrite, 1);
16109 rb_define_method(rb_cIO, "sysread", rb_io_sysread, -1);
16110
16111 rb_define_method(rb_cIO, "pread", rb_io_pread, -1);
16112 rb_define_method(rb_cIO, "pwrite", rb_io_pwrite, 2);
16113
16114 rb_define_method(rb_cIO, "fileno", rb_io_fileno, 0);
16115 rb_define_alias(rb_cIO, "to_i", "fileno");
16116 rb_define_method(rb_cIO, "to_io", rb_io_to_io, 0);
16117
16118 rb_define_method(rb_cIO, "timeout", rb_io_timeout, 0);
16119 rb_define_method(rb_cIO, "timeout=", rb_io_set_timeout, 1);
16120
16121 rb_define_method(rb_cIO, "fsync", rb_io_fsync, 0);
16122 rb_define_method(rb_cIO, "fdatasync", rb_io_fdatasync, 0);
16123 rb_define_method(rb_cIO, "sync", rb_io_sync, 0);
16124 rb_define_method(rb_cIO, "sync=", rb_io_set_sync, 1);
16125
16126 rb_define_method(rb_cIO, "lineno", rb_io_lineno, 0);
16127 rb_define_method(rb_cIO, "lineno=", rb_io_set_lineno, 1);
16128
16129 rb_define_method(rb_cIO, "readlines", rb_io_readlines, -1);
16130
16131 rb_define_method(rb_cIO, "readpartial", io_readpartial, -1);
16132 rb_define_method(rb_cIO, "read", io_read, -1);
16133 rb_define_method(rb_cIO, "write", io_write_m, -1);
16134 rb_define_method(rb_cIO, "gets", rb_io_gets_m, -1);
16135 rb_define_method(rb_cIO, "getc", rb_io_getc, 0);
16136 rb_define_method(rb_cIO, "getbyte", rb_io_getbyte, 0);
16137 rb_define_method(rb_cIO, "readchar", rb_io_readchar, 0);
16138 rb_define_method(rb_cIO, "readbyte", rb_io_readbyte, 0);
16139 rb_define_method(rb_cIO, "ungetbyte",rb_io_ungetbyte, 1);
16140 rb_define_method(rb_cIO, "ungetc",rb_io_ungetc, 1);
16142 rb_define_method(rb_cIO, "flush", rb_io_flush, 0);
16143 rb_define_method(rb_cIO, "tell", rb_io_tell, 0);
16144 rb_define_method(rb_cIO, "seek", rb_io_seek_m, -1);
16145 /* Set I/O position from the beginning */
16146 rb_define_const(rb_cIO, "SEEK_SET", INT2FIX(SEEK_SET));
16147 /* Set I/O position from the current position */
16148 rb_define_const(rb_cIO, "SEEK_CUR", INT2FIX(SEEK_CUR));
16149 /* Set I/O position from the end */
16150 rb_define_const(rb_cIO, "SEEK_END", INT2FIX(SEEK_END));
16151#ifdef SEEK_DATA
16152 /* Set I/O position to the next location containing data */
16153 rb_define_const(rb_cIO, "SEEK_DATA", INT2FIX(SEEK_DATA));
16154#endif
16155#ifdef SEEK_HOLE
16156 /* Set I/O position to the next hole */
16157 rb_define_const(rb_cIO, "SEEK_HOLE", INT2FIX(SEEK_HOLE));
16158#endif
16159 rb_define_method(rb_cIO, "rewind", rb_io_rewind, 0);
16160 rb_define_method(rb_cIO, "pos", rb_io_tell, 0);
16161 rb_define_method(rb_cIO, "pos=", rb_io_set_pos, 1);
16162 rb_define_method(rb_cIO, "eof", rb_io_eof, 0);
16163 rb_define_method(rb_cIO, "eof?", rb_io_eof, 0);
16164
16165 rb_define_method(rb_cIO, "close_on_exec?", rb_io_close_on_exec_p, 0);
16166 rb_define_method(rb_cIO, "close_on_exec=", rb_io_set_close_on_exec, 1);
16167
16168 rb_define_method(rb_cIO, "close", rb_io_close_m, 0);
16169 rb_define_method(rb_cIO, "closed?", rb_io_closed_p, 0);
16170 rb_define_method(rb_cIO, "close_read", rb_io_close_read, 0);
16171 rb_define_method(rb_cIO, "close_write", rb_io_close_write, 0);
16172
16173 rb_define_method(rb_cIO, "isatty", rb_io_isatty, 0);
16174 rb_define_method(rb_cIO, "tty?", rb_io_isatty, 0);
16175 rb_define_method(rb_cIO, "binmode", rb_io_binmode_m, 0);
16176 rb_define_method(rb_cIO, "binmode?", rb_io_binmode_p, 0);
16177 rb_define_method(rb_cIO, "sysseek", rb_io_sysseek, -1);
16178 rb_define_method(rb_cIO, "advise", rb_io_advise, -1);
16179
16180 rb_define_method(rb_cIO, "ioctl", rb_io_ioctl, -1);
16181 rb_define_method(rb_cIO, "fcntl", rb_io_fcntl, -1);
16182 rb_define_method(rb_cIO, "pid", rb_io_pid, 0);
16183
16184 rb_define_method(rb_cIO, "path", rb_io_path, 0);
16185 rb_define_method(rb_cIO, "to_path", rb_io_path, 0);
16186
16187 rb_define_method(rb_cIO, "inspect", rb_io_inspect, 0);
16188
16189 rb_define_method(rb_cIO, "external_encoding", rb_io_external_encoding, 0);
16190 rb_define_method(rb_cIO, "internal_encoding", rb_io_internal_encoding, 0);
16191 rb_define_method(rb_cIO, "set_encoding", rb_io_set_encoding, -1);
16192 rb_define_method(rb_cIO, "set_encoding_by_bom", rb_io_set_encoding_by_bom, 0);
16193
16194 rb_define_method(rb_cIO, "autoclose?", rb_io_autoclose_p, 0);
16195 rb_define_method(rb_cIO, "autoclose=", rb_io_set_autoclose, 1);
16196
16197 rb_define_method(rb_cIO, "wait", io_wait, -1);
16198
16199 rb_define_method(rb_cIO, "wait_readable", io_wait_readable, -1);
16200 rb_define_method(rb_cIO, "wait_writable", io_wait_writable, -1);
16201 rb_define_method(rb_cIO, "wait_priority", io_wait_priority, -1);
16202
16203 rb_define_virtual_variable("$stdin", stdin_getter, stdin_setter);
16204 rb_define_virtual_variable("$stdout", stdout_getter, stdout_setter);
16205 rb_define_virtual_variable("$>", stdout_getter, stdout_setter);
16206 rb_define_virtual_variable("$stderr", stderr_getter, stderr_setter);
16207
16208 rb_gvar_ractor_local("$stdin");
16209 rb_gvar_ractor_local("$stdout");
16210 rb_gvar_ractor_local("$>");
16211 rb_gvar_ractor_local("$stderr");
16212
16213 rb_gvar_box_dynamic("$stdin");
16214 rb_gvar_box_dynamic("$stdout");
16215 rb_gvar_box_dynamic("$>");
16216 rb_gvar_box_dynamic("$stderr");
16217
16219 rb_stdin = rb_io_prep_stdin();
16221 rb_stdout = rb_io_prep_stdout();
16223 rb_stderr = rb_io_prep_stderr();
16224
16225 orig_stdout = rb_stdout;
16226 orig_stderr = rb_stderr;
16227
16228 /* Holds the original stdin */
16230 /* Holds the original stdout */
16232 /* Holds the original stderr */
16234
16235#if 0
16236 /* Hack to get rdoc to regard ARGF as a class: */
16237 rb_cARGF = rb_define_class("ARGF", rb_cObject);
16238#endif
16239
16240 rb_cARGF = rb_class_new(rb_cObject);
16241 rb_set_class_path(rb_cARGF, rb_cObject, "ARGF.class");
16242 rb_define_alloc_func(rb_cARGF, argf_alloc);
16243
16245
16246 rb_define_method(rb_cARGF, "initialize", argf_initialize, -2);
16247 rb_define_method(rb_cARGF, "initialize_copy", argf_initialize_copy, 1);
16248 rb_define_method(rb_cARGF, "to_s", argf_to_s, 0);
16249 rb_define_alias(rb_cARGF, "inspect", "to_s");
16250 rb_define_method(rb_cARGF, "argv", argf_argv, 0);
16251
16252 rb_define_method(rb_cARGF, "fileno", argf_fileno, 0);
16253 rb_define_method(rb_cARGF, "to_i", argf_fileno, 0);
16254 rb_define_method(rb_cARGF, "to_io", argf_to_io, 0);
16255 rb_define_method(rb_cARGF, "to_write_io", argf_write_io, 0);
16256 rb_define_method(rb_cARGF, "each", argf_each_line, -1);
16257 rb_define_method(rb_cARGF, "each_line", argf_each_line, -1);
16258 rb_define_method(rb_cARGF, "each_byte", argf_each_byte, 0);
16259 rb_define_method(rb_cARGF, "each_char", argf_each_char, 0);
16260 rb_define_method(rb_cARGF, "each_codepoint", argf_each_codepoint, 0);
16261
16262 rb_define_method(rb_cARGF, "read", argf_read, -1);
16263 rb_define_method(rb_cARGF, "readpartial", argf_readpartial, -1);
16264 rb_define_method(rb_cARGF, "read_nonblock", argf_read_nonblock, -1);
16265 rb_define_method(rb_cARGF, "readlines", argf_readlines, -1);
16266 rb_define_method(rb_cARGF, "to_a", argf_readlines, -1);
16267 rb_define_method(rb_cARGF, "gets", argf_gets, -1);
16268 rb_define_method(rb_cARGF, "readline", argf_readline, -1);
16269 rb_define_method(rb_cARGF, "getc", argf_getc, 0);
16270 rb_define_method(rb_cARGF, "getbyte", argf_getbyte, 0);
16271 rb_define_method(rb_cARGF, "readchar", argf_readchar, 0);
16272 rb_define_method(rb_cARGF, "readbyte", argf_readbyte, 0);
16273 rb_define_method(rb_cARGF, "tell", argf_tell, 0);
16274 rb_define_method(rb_cARGF, "seek", argf_seek_m, -1);
16275 rb_define_method(rb_cARGF, "rewind", argf_rewind, 0);
16276 rb_define_method(rb_cARGF, "pos", argf_tell, 0);
16277 rb_define_method(rb_cARGF, "pos=", argf_set_pos, 1);
16278 rb_define_method(rb_cARGF, "eof", argf_eof, 0);
16279 rb_define_method(rb_cARGF, "eof?", argf_eof, 0);
16280 rb_define_method(rb_cARGF, "binmode", argf_binmode_m, 0);
16281 rb_define_method(rb_cARGF, "binmode?", argf_binmode_p, 0);
16282
16283 rb_define_method(rb_cARGF, "write", argf_write, -1);
16284 rb_define_method(rb_cARGF, "print", rb_io_print, -1);
16285 rb_define_method(rb_cARGF, "putc", rb_io_putc, 1);
16286 rb_define_method(rb_cARGF, "puts", rb_io_puts, -1);
16287 rb_define_method(rb_cARGF, "printf", rb_io_printf, -1);
16288
16289 rb_define_method(rb_cARGF, "filename", argf_filename, 0);
16290 rb_define_method(rb_cARGF, "path", argf_filename, 0);
16291 rb_define_method(rb_cARGF, "file", argf_file, 0);
16292 rb_define_method(rb_cARGF, "skip", argf_skip, 0);
16293 rb_define_method(rb_cARGF, "close", argf_close_m, 0);
16294 rb_define_method(rb_cARGF, "closed?", argf_closed, 0);
16295
16296 rb_define_method(rb_cARGF, "lineno", argf_lineno, 0);
16297 rb_define_method(rb_cARGF, "lineno=", argf_set_lineno, 1);
16298
16299 rb_define_method(rb_cARGF, "inplace_mode", argf_inplace_mode_get, 0);
16300 rb_define_method(rb_cARGF, "inplace_mode=", argf_inplace_mode_set, 1);
16301
16302 rb_define_method(rb_cARGF, "external_encoding", argf_external_encoding, 0);
16303 rb_define_method(rb_cARGF, "internal_encoding", argf_internal_encoding, 0);
16304 rb_define_method(rb_cARGF, "set_encoding", argf_set_encoding, -1);
16305
16306 argf = rb_class_new_instance(0, 0, rb_cARGF);
16307
16309 /*
16310 * ARGF is a stream designed for use in scripts that process files given
16311 * as command-line arguments or passed in via STDIN.
16312 *
16313 * See ARGF (the class) for more details.
16314 */
16316
16317 rb_define_hooked_variable("$.", &argf, argf_lineno_getter, argf_lineno_setter);
16318 rb_define_hooked_variable("$FILENAME", &argf, argf_filename_getter, rb_gvar_readonly_setter);
16319 ARGF_SET(filename, rb_str_new2("-"));
16320
16321 rb_define_hooked_variable("$-i", &argf, opt_i_get, opt_i_set);
16322 rb_gvar_ractor_local("$-i");
16323
16324 rb_define_hooked_variable("$*", &argf, argf_argv_getter, rb_gvar_readonly_setter);
16325
16326#if defined (_WIN32) || defined(__CYGWIN__)
16327 atexit(pipe_atexit);
16328#endif
16329
16330 Init_File();
16331
16332 rb_define_method(rb_cFile, "initialize", rb_file_initialize, -1);
16333
16334 sym_mode = ID2SYM(rb_intern_const("mode"));
16335 sym_perm = ID2SYM(rb_intern_const("perm"));
16336 sym_flags = ID2SYM(rb_intern_const("flags"));
16337 sym_extenc = ID2SYM(rb_intern_const("external_encoding"));
16338 sym_intenc = ID2SYM(rb_intern_const("internal_encoding"));
16339 sym_encoding = ID2SYM(rb_id_encoding());
16340 sym_open_args = ID2SYM(rb_intern_const("open_args"));
16341 sym_textmode = ID2SYM(rb_intern_const("textmode"));
16342 sym_binmode = ID2SYM(rb_intern_const("binmode"));
16343 sym_autoclose = ID2SYM(rb_intern_const("autoclose"));
16344 sym_normal = ID2SYM(rb_intern_const("normal"));
16345 sym_sequential = ID2SYM(rb_intern_const("sequential"));
16346 sym_random = ID2SYM(rb_intern_const("random"));
16347 sym_willneed = ID2SYM(rb_intern_const("willneed"));
16348 sym_dontneed = ID2SYM(rb_intern_const("dontneed"));
16349 sym_noreuse = ID2SYM(rb_intern_const("noreuse"));
16350 sym_SET = ID2SYM(rb_intern_const("SET"));
16351 sym_CUR = ID2SYM(rb_intern_const("CUR"));
16352 sym_END = ID2SYM(rb_intern_const("END"));
16353#ifdef SEEK_DATA
16354 sym_DATA = ID2SYM(rb_intern_const("DATA"));
16355#endif
16356#ifdef SEEK_HOLE
16357 sym_HOLE = ID2SYM(rb_intern_const("HOLE"));
16358#endif
16359 sym_wait_readable = ID2SYM(rb_intern_const("wait_readable"));
16360 sym_wait_writable = ID2SYM(rb_intern_const("wait_writable"));
16361}
16362
16363static void init_builtin_io(void);
16364#define Init_builtin_io init_builtin_io
16365#include "io.rbinc"
16366#undef Init_builtin_io
16367
16368void
16369Init_builtin_io(void)
16370{
16371 init_builtin_io();
16372
16373 /* Init_IO is called earlier than `loaded_features` is initialized */
16374 rb_provide("io/wait.rb");
16375 rb_provide("io/wait.so");
16376}
#define RUBY_ASSERT(...)
Asserts that the given expression is truthy if and only if RUBY_DEBUG is truthy.
Definition assert.h:219
std::atomic< unsigned > rb_atomic_t
Type that is eligible for atomic operations.
Definition atomic.h:69
unsigned long ruby_strtoul(const char *str, char **endptr, int base)
Our own locale-insensitive version of strtoul(3).
Definition util.c:113
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
#define rb_define_singleton_method(klass, mid, func, arity)
Defines klass.mid.
#define rb_define_global_function(mid, func, arity)
Defines rb_mKernel #mid.
void rb_include_module(VALUE klass, VALUE module)
Includes a module to a class.
Definition class.c:1769
VALUE rb_class_new(VALUE super)
Creates a new, anonymous class.
Definition class.c:853
void rb_define_alias(VALUE klass, const char *name1, const char *name2)
Defines an alias of a method.
Definition class.c:3094
int rb_scan_args_kw(int kw_flag, int argc, const VALUE *argv, const char *fmt,...)
Identical to rb_scan_args(), except it also accepts kw_splat.
Definition class.c:3397
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Retrieves argument from argc and argv to given VALUE references according to the format string.
Definition class.c:3384
int rb_block_given_p(void)
Determines if the current method is given a block.
Definition eval.c:1035
int rb_get_kwargs(VALUE keyword_hash, const ID *table, int required, int optional, VALUE *values)
Keyword argument deconstructor.
Definition class.c:3173
#define ECONV_AFTER_OUTPUT
Old name of RUBY_ECONV_AFTER_OUTPUT.
Definition transcode.h:555
#define rb_str_new2
Old name of rb_str_new_cstr.
Definition string.h:1700
#define TYPE(_)
Old name of rb_type.
Definition value_type.h:108
#define RB_INTEGER_TYPE_P
Old name of rb_integer_type_p.
Definition value_type.h:87
#define ENC_CODERANGE_7BIT
Old name of RUBY_ENC_CODERANGE_7BIT.
Definition coderange.h:180
#define T_FILE
Old name of RUBY_T_FILE.
Definition value_type.h:62
#define ENC_CODERANGE_VALID
Old name of RUBY_ENC_CODERANGE_VALID.
Definition coderange.h:181
#define ECONV_UNIVERSAL_NEWLINE_DECORATOR
Old name of RUBY_ECONV_UNIVERSAL_NEWLINE_DECORATOR.
Definition transcode.h:532
#define REALLOC_N
Old name of RB_REALLOC_N.
Definition memory.h:403
#define OBJ_INIT_COPY(obj, orig)
Old name of RB_OBJ_INIT_COPY.
Definition object.h:41
#define ALLOC
Old name of RB_ALLOC.
Definition memory.h:400
#define RFLOAT_VALUE
Old name of rb_float_value.
Definition double.h:28
#define T_STRING
Old name of RUBY_T_STRING.
Definition value_type.h:78
#define Qundef
Old name of RUBY_Qundef.
#define INT2FIX
Old name of RB_INT2FIX.
Definition long.h:48
#define rb_str_cat2
Old name of rb_str_cat_cstr.
Definition string.h:1708
#define T_NIL
Old name of RUBY_T_NIL.
Definition value_type.h:72
#define UNREACHABLE
Old name of RBIMPL_UNREACHABLE.
Definition assume.h:28
#define ID2SYM
Old name of RB_ID2SYM.
Definition symbol.h:44
#define T_BIGNUM
Old name of RUBY_T_BIGNUM.
Definition value_type.h:57
#define OBJ_FREEZE
Old name of RB_OBJ_FREEZE.
Definition fl_type.h:131
#define T_FIXNUM
Old name of RUBY_T_FIXNUM.
Definition value_type.h:63
#define UNREACHABLE_RETURN
Old name of RBIMPL_UNREACHABLE_RETURN.
Definition assume.h:29
#define FIX2UINT
Old name of RB_FIX2UINT.
Definition int.h:42
#define SSIZET2NUM
Old name of RB_SSIZE2NUM.
Definition size_t.h:64
#define ZALLOC
Old name of RB_ZALLOC.
Definition memory.h:402
#define CLASS_OF
Old name of rb_class_of.
Definition globals.h:205
#define rb_ary_new4
Old name of rb_ary_new_from_values.
Definition array.h:659
#define ENCODING_MAXNAMELEN
Old name of RUBY_ENCODING_MAXNAMELEN.
Definition encoding.h:111
#define MBCLEN_NEEDMORE_LEN(ret)
Old name of ONIGENC_MBCLEN_NEEDMORE_LEN.
Definition encoding.h:520
#define ENCODING_GET(obj)
Old name of RB_ENCODING_GET.
Definition encoding.h:109
#define LONG2FIX
Old name of RB_INT2FIX.
Definition long.h:49
#define NUM2UINT
Old name of RB_NUM2UINT.
Definition int.h:45
#define ALLOC_N
Old name of RB_ALLOC_N.
Definition memory.h:399
#define MBCLEN_CHARFOUND_LEN(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_LEN.
Definition encoding.h:517
#define LONG2NUM
Old name of RB_LONG2NUM.
Definition long.h:50
#define rb_exc_new3
Old name of rb_exc_new_str.
Definition error.h:38
#define STRNCASECMP
Old name of st_locale_insensitive_strncasecmp.
Definition ctype.h:103
#define MBCLEN_INVALID_P(ret)
Old name of ONIGENC_MBCLEN_INVALID_P.
Definition encoding.h:518
#define ISASCII
Old name of rb_isascii.
Definition ctype.h:85
#define ECONV_STATEFUL_DECORATOR_MASK
Old name of RUBY_ECONV_STATEFUL_DECORATOR_MASK.
Definition transcode.h:538
#define Qtrue
Old name of RUBY_Qtrue.
#define MBCLEN_NEEDMORE_P(ret)
Old name of ONIGENC_MBCLEN_NEEDMORE_P.
Definition encoding.h:519
#define ECONV_PARTIAL_INPUT
Old name of RUBY_ECONV_PARTIAL_INPUT.
Definition transcode.h:554
#define NUM2INT
Old name of RB_NUM2INT.
Definition int.h:44
#define ECONV_ERROR_HANDLER_MASK
Old name of RUBY_ECONV_ERROR_HANDLER_MASK.
Definition transcode.h:522
#define INT2NUM
Old name of RB_INT2NUM.
Definition int.h:43
#define Qnil
Old name of RUBY_Qnil.
#define Qfalse
Old name of RUBY_Qfalse.
#define FIX2LONG
Old name of RB_FIX2LONG.
Definition long.h:46
#define ENC_CODERANGE_BROKEN
Old name of RUBY_ENC_CODERANGE_BROKEN.
Definition coderange.h:182
#define T_ARRAY
Old name of RUBY_T_ARRAY.
Definition value_type.h:56
#define NIL_P
Old name of RB_NIL_P.
#define ALLOCV_N
Old name of RB_ALLOCV_N.
Definition memory.h:405
#define MBCLEN_CHARFOUND_P(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_P.
Definition encoding.h:516
#define NUM2CHR
Old name of RB_NUM2CHR.
Definition char.h:33
#define NUM2LONG
Old name of RB_NUM2LONG.
Definition long.h:51
#define UINT2NUM
Old name of RB_UINT2NUM.
Definition int.h:46
#define FIXNUM_P
Old name of RB_FIXNUM_P.
#define ECONV_NEWLINE_DECORATOR_MASK
Old name of RUBY_ECONV_NEWLINE_DECORATOR_MASK.
Definition transcode.h:529
#define CONST_ID
Old name of RUBY_CONST_ID.
Definition symbol.h:47
#define rb_ary_new2
Old name of rb_ary_new_capa.
Definition array.h:657
#define NUM2SIZET
Old name of RB_NUM2SIZE.
Definition size_t.h:61
#define ENC_CODERANGE_SET(obj, cr)
Old name of RB_ENC_CODERANGE_SET.
Definition coderange.h:186
#define rb_str_new4
Old name of rb_str_new_frozen.
Definition string.h:1702
#define ALLOCV_END
Old name of RB_ALLOCV_END.
Definition memory.h:406
#define SYMBOL_P
Old name of RB_SYMBOL_P.
Definition value_type.h:88
#define ECONV_DEFAULT_NEWLINE_DECORATOR
Old name of RUBY_ECONV_DEFAULT_NEWLINE_DECORATOR.
Definition transcode.h:540
void rb_category_warn(rb_warning_category_t category, const char *fmt,...)
Identical to rb_category_warning(), except it reports unless $VERBOSE is nil.
Definition error.c:478
void rb_category_warning(rb_warning_category_t category, const char *fmt,...)
Identical to rb_warning(), except it takes additional "category" parameter.
Definition error.c:510
VALUE rb_eNotImpError
NotImplementedError exception.
Definition error.c:1483
void rb_exc_raise(VALUE mesg)
Raises an exception in the current thread.
Definition eval.c:678
void rb_syserr_fail(int e, const char *mesg)
Raises appropriate exception that represents a C errno.
Definition error.c:4084
void rb_readwrite_syserr_fail(enum rb_io_wait_readwrite waiting, int n, const char *mesg)
Identical to rb_readwrite_sys_fail(), except it does not depend on C global variable errno.
Definition io.c:15034
VALUE rb_eIOError
IOError exception.
Definition io.c:189
VALUE rb_eStandardError
StandardError exception.
Definition error.c:1470
void rb_mod_syserr_fail_str(VALUE mod, int e, VALUE mesg)
Identical to rb_mod_syserr_fail(), except it takes the message in Ruby's String instead of C's.
Definition error.c:4174
void rb_syserr_fail_str(int e, VALUE mesg)
Identical to rb_syserr_fail(), except it takes the message in Ruby's String instead of C's.
Definition error.c:4090
#define ruby_verbose
This variable controls whether the interpreter is in debug mode.
Definition error.h:476
VALUE rb_eTypeError
TypeError exception.
Definition error.c:1473
VALUE rb_eEOFError
EOFError exception.
Definition io.c:188
void rb_readwrite_sys_fail(enum rb_io_wait_readwrite waiting, const char *mesg)
Raises appropriate exception using the parameters.
Definition io.c:15028
void rb_iter_break_value(VALUE val)
Identical to rb_iter_break(), except it additionally takes the "value" of this breakage.
Definition vm.c:2387
rb_io_wait_readwrite
for rb_readwrite_sys_fail first argument
Definition error.h:73
VALUE rb_eRuntimeError
RuntimeError exception.
Definition error.c:1471
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports unless $VERBOSE is nil.
Definition error.c:468
VALUE rb_eSystemCallError
SystemCallError exception.
Definition error.c:1493
@ RB_WARN_CATEGORY_DEPRECATED
Warning is for deprecated features.
Definition error.h:48
VALUE rb_mKernel
Kernel module.
Definition object.c:59
VALUE rb_check_to_int(VALUE val)
Identical to rb_check_to_integer(), except it uses #to_int for conversion.
Definition object.c:3334
VALUE rb_cObject
Object class.
Definition object.c:60
VALUE rb_any_to_s(VALUE obj)
Generates a textual representation of the given object.
Definition object.c:658
VALUE rb_obj_alloc(VALUE klass)
Allocates an instance of the given class.
Definition object.c:2252
VALUE rb_class_new_instance(int argc, const VALUE *argv, VALUE klass)
Allocates, then initialises an instance of the given class.
Definition object.c:2293
VALUE rb_cIO
IO class.
Definition io.c:187
VALUE rb_class_new_instance_kw(int argc, const VALUE *argv, VALUE klass, int kw_splat)
Identical to rb_class_new_instance(), except you can specify how to handle the last element of the gi...
Definition object.c:2281
VALUE rb_mEnumerable
Enumerable module.
Definition enum.c:28
VALUE rb_stdin
STDIN constant.
Definition io.c:203
VALUE rb_stderr
STDERR constant.
Definition io.c:203
VALUE rb_obj_class(VALUE obj)
Queries the class of an object.
Definition object.c:234
VALUE rb_obj_dup(VALUE obj)
Duplicates the given object.
Definition object.c:556
VALUE rb_inspect(VALUE obj)
Generates a human-readable textual representation of the given object.
Definition object.c:669
VALUE rb_mWaitReadable
IO::WaitReadable module.
Definition io.c:191
VALUE rb_mWaitWritable
IO::WaitReadable module.
Definition io.c:192
VALUE rb_obj_freeze(VALUE obj)
Same as RB_OBJ_FREEZE(), but returns the given object.
Definition object.c:1309
VALUE rb_check_to_integer(VALUE val, const char *mid)
Identical to rb_check_convert_type(), except the return value type is fixed to rb_cInteger.
Definition object.c:3315
VALUE rb_cFile
File class.
Definition file.c:175
VALUE rb_stdout
STDOUT constant.
Definition io.c:203
VALUE rb_to_int(VALUE val)
Identical to rb_check_to_int(), except it raises in case of conversion mismatch.
Definition object.c:3328
#define RB_OBJ_WRITTEN(old, oldv, young)
Identical to RB_OBJ_WRITE(), except it doesn't write any values, but only a WB declaration.
Definition gc.h:504
#define RB_OBJ_WRITE(old, slot, young)
Declaration of a "back" pointer.
Definition gc.h:492
Scheduler APIs.
VALUE rb_fiber_scheduler_current(void)
Identical to rb_fiber_scheduler_get(), except it also returns RUBY_Qnil in case of a blocking fiber.
Definition scheduler.c:581
VALUE rb_fiber_scheduler_make_timeout(struct timeval *timeout)
Converts the passed timeout to an expression that rb_fiber_scheduler_block() etc.
Definition scheduler.c:632
VALUE rb_fiber_scheduler_io_wait_readable(VALUE scheduler, VALUE io)
Non-blocking wait until the passed IO is ready for reading.
Definition scheduler.c:866
VALUE rb_fiber_scheduler_io_wait(VALUE scheduler, VALUE io, VALUE events, VALUE timeout)
Non-blocking version of rb_io_wait().
Definition scheduler.c:856
static ssize_t rb_fiber_scheduler_io_result_apply(VALUE result)
Apply an io result to the local thread, returning the value of the original system call that created ...
Definition scheduler.h:74
VALUE rb_fiber_scheduler_io_pread_memory(VALUE scheduler, VALUE io, rb_off_t from, void *base, size_t size)
Non-blocking pread from the passed IO using a native buffer.
Definition scheduler.c:1127
VALUE rb_fiber_scheduler_io_selectv(VALUE scheduler, int argc, VALUE *argv)
Non-blocking version of IO.select, argv variant.
Definition scheduler.c:896
VALUE rb_fiber_scheduler_io_read_memory(VALUE scheduler, VALUE io, void *base, size_t size)
Non-blocking read from the passed IO using a native buffer.
Definition scheduler.c:1079
VALUE rb_fiber_scheduler_current_for_thread(VALUE thread)
Identical to rb_fiber_scheduler_current(), except it queries for that of the passed thread value inst...
Definition scheduler.c:589
VALUE rb_fiber_scheduler_io_pwrite_memory(VALUE scheduler, VALUE io, rb_off_t from, const void *base, size_t size)
Non-blocking pwrite to the passed IO using a native buffer.
Definition scheduler.c:1152
VALUE rb_fiber_scheduler_current_for_threadptr(struct rb_thread_struct *thread)
Identical to rb_fiber_scheduler_current_for_thread(), except it expects a threadptr instead of a thre...
Definition scheduler.c:594
VALUE rb_fiber_scheduler_io_wait_writable(VALUE scheduler, VALUE io)
Non-blocking wait until the passed IO is ready for writing.
Definition scheduler.c:872
VALUE rb_fiber_scheduler_io_close(VALUE scheduler, VALUE io)
Non-blocking close the given IO.
Definition scheduler.c:1177
VALUE rb_fiber_scheduler_io_write_memory(VALUE scheduler, VALUE io, const void *base, size_t size)
Non-blocking write to the passed IO using a native buffer.
Definition scheduler.c:1103
static unsigned int rb_enc_codepoint(const char *p, const char *e, rb_encoding *enc)
Queries the code point of character pointed by the passed pointer.
Definition encoding.h:571
static int rb_enc_mbmaxlen(rb_encoding *enc)
Queries the maximum number of bytes that the passed encoding needs to represent a character.
Definition encoding.h:447
VALUE rb_str_conv_enc(VALUE str, rb_encoding *from, rb_encoding *to)
Encoding conversion main routine.
Definition string.c:1379
VALUE rb_enc_uint_chr(unsigned int code, rb_encoding *enc)
Encodes the passed code point into a series of bytes.
Definition numeric.c:3946
long rb_str_coderange_scan_restartable(const char *str, const char *end, rb_encoding *enc, int *cr)
Scans the passed string until it finds something odd.
Definition string.c:844
int rb_econv_prepare_options(VALUE opthash, VALUE *ecopts, int ecflags)
Identical to rb_econv_prepare_opts(), except it additionally takes the initial value of flags.
Definition transcode.c:2679
VALUE rb_econv_open_exc(const char *senc, const char *denc, int ecflags)
Creates a rb_eConverterNotFoundError exception object (but does not raise).
Definition transcode.c:2126
rb_econv_result_t rb_econv_convert(rb_econv_t *ec, const unsigned char **source_buffer_ptr, const unsigned char *source_buffer_end, unsigned char **destination_buffer_ptr, unsigned char *destination_buffer_end, int flags)
Converts a string from an encoding to another.
Definition transcode.c:1487
rb_econv_result_t
return value of rb_econv_convert()
Definition transcode.h:30
@ econv_incomplete_input
The conversion stopped in middle of reading a character, possibly due to a partial read of a socket e...
Definition transcode.h:69
@ econv_finished
The conversion stopped after converting everything.
Definition transcode.h:57
@ econv_undefined_conversion
The conversion stopped when it found a character in the input which cannot be representable in the ou...
Definition transcode.h:41
@ econv_source_buffer_empty
The conversion stopped because there is no input.
Definition transcode.h:51
@ econv_destination_buffer_full
The conversion stopped because there is no destination.
Definition transcode.h:46
@ econv_invalid_byte_sequence
The conversion stopped when it found an invalid sequence.
Definition transcode.h:35
int rb_econv_putbackable(rb_econv_t *ec)
Queries if rb_econv_putback() makes sense, i.e.
Definition transcode.c:1783
const char * rb_econv_asciicompat_encoding(const char *encname)
Queries the passed encoding's corresponding ASCII compatible encoding.
Definition transcode.c:1827
VALUE rb_econv_str_convert(rb_econv_t *ec, VALUE src, int flags)
Identical to rb_econv_convert(), except it takes Ruby's string instead of C's pointer.
Definition transcode.c:1962
rb_econv_t * rb_econv_open_opts(const char *source_encoding, const char *destination_encoding, int ecflags, VALUE ecopts)
Identical to rb_econv_open(), except it additionally takes a hash of optional strings.
Definition transcode.c:2730
void rb_econv_binmode(rb_econv_t *ec)
This badly named function does not set the destination encoding to binary, but instead just nullifies...
Definition transcode.c:2025
VALUE rb_str_encode(VALUE str, VALUE to, int ecflags, VALUE ecopts)
Converts the contents of the passed string from its encoding to the passed one.
Definition transcode.c:2993
VALUE rb_econv_make_exception(rb_econv_t *ec)
This function makes sense right after rb_econv_convert() returns.
Definition transcode.c:4359
void rb_econv_check_error(rb_econv_t *ec)
This is a rb_econv_make_exception() + rb_exc_raise() combo.
Definition transcode.c:4365
void rb_econv_close(rb_econv_t *ec)
Destructs a converter.
Definition transcode.c:1744
void rb_econv_putback(rb_econv_t *ec, unsigned char *p, int n)
Puts back the bytes.
Definition transcode.c:1794
VALUE rb_funcall(VALUE recv, ID mid, int n,...)
Calls a method.
Definition vm_eval.c:1123
VALUE rb_funcallv_kw(VALUE recv, ID mid, int argc, const VALUE *argv, int kw_splat)
Identical to rb_funcallv(), except you can specify how to handle the last element of the given array.
Definition vm_eval.c:1090
VALUE rb_funcallv(VALUE recv, ID mid, int argc, const VALUE *argv)
Identical to rb_funcall(), except it takes the method arguments as a C array.
Definition vm_eval.c:1081
Defines RBIMPL_HAS_BUILTIN.
VALUE rb_ary_concat(VALUE lhs, VALUE rhs)
Destructively appends the contents of latter into the end of former.
VALUE rb_ary_shift(VALUE ary)
Destructively deletes an element from the beginning of the passed array and returns what was deleted.
VALUE rb_check_array_type(VALUE obj)
Try converting an object to its array representation using its to_ary method, if any.
VALUE rb_ary_new(void)
Allocates a new, empty array.
VALUE rb_ary_new_capa(long capa)
Identical to rb_ary_new(), except it additionally specifies how many rooms of objects it should alloc...
VALUE rb_ary_push(VALUE ary, VALUE elem)
Special case of rb_ary_cat() that it adds only one element.
VALUE rb_ary_entry(VALUE ary, long off)
Queries an element of an array.
VALUE rb_assoc_new(VALUE car, VALUE cdr)
Identical to rb_ary_new_from_values(), except it expects exactly two parameters.
#define RETURN_ENUMERATOR(obj, argc, argv)
Identical to RETURN_SIZED_ENUMERATOR(), except its size is unknown.
Definition enumerator.h:242
static int rb_check_arity(int argc, int min, int max)
Ensures that the passed integer is in the passed range.
Definition error.h:284
VALUE rb_io_printf(int argc, const VALUE *argv, VALUE io)
This is a rb_f_sprintf() + rb_io_write() combo.
Definition io.c:8914
VALUE rb_io_gets(VALUE io)
Reads a "line" from the given IO.
Definition io.c:4599
int rb_cloexec_pipe(int fildes[2])
Opens a pipe with closing on exec.
Definition io.c:511
VALUE rb_io_print(int argc, const VALUE *argv, VALUE io)
Iterates over the passed array to apply rb_io_write() individually.
Definition io.c:9047
VALUE rb_io_addstr(VALUE io, VALUE str)
Identical to rb_io_write(), except it always returns the passed IO.
Definition io.c:2479
void rb_write_error(const char *str)
Writes the given error message to somewhere applicable.
Definition io.c:9476
VALUE rb_io_ungetbyte(VALUE io, VALUE b)
Identical to rb_io_ungetc(), except it doesn't take the encoding of the passed IO into account.
Definition io.c:5471
VALUE rb_io_getbyte(VALUE io)
Reads a byte from the given IO.
Definition io.c:5376
int rb_cloexec_dup2(int oldfd, int newfd)
Identical to rb_cloexec_dup(), except you can specify the destination file descriptor.
Definition io.c:409
VALUE rb_io_fdopen(int fd, int flags, const char *path)
Creates an IO instance whose backend is the given file descriptor.
Definition io.c:9657
void rb_update_max_fd(int fd)
Informs the interpreter that the passed fd can be the max.
Definition io.c:283
int rb_cloexec_open(const char *pathname, int flags, mode_t mode)
Opens a file that closes on exec.
Definition io.c:363
VALUE rb_output_rs
The record separator character for outputs, or the $\.
Definition io.c:208
VALUE rb_io_eof(VALUE io)
Queries if the passed IO is at the end of file.
Definition io.c:2821
void rb_write_error2(const char *str, long len)
Identical to rb_write_error(), except it additionally takes the message's length.
Definition io.c:9456
void rb_close_before_exec(int lowfd, int maxhint, VALUE noclose_fds)
Closes everything.
int rb_reserved_fd_p(int fd)
Queries if the given FD is reserved or not.
void rb_fd_fix_cloexec(int fd)
Sets or clears the close-on-exec flag of the passed file descriptor to the desired state.
Definition io.c:333
VALUE rb_io_ascii8bit_binmode(VALUE io)
Forces no conversions be applied to the passed IO.
Definition io.c:6714
VALUE rb_io_binmode(VALUE io)
Sets the binmode.
Definition io.c:6668
VALUE rb_io_ungetc(VALUE io, VALUE c)
"Unget"s a string.
Definition io.c:5535
int rb_pipe(int *pipes)
This is an rb_cloexec_pipe() + rb_update_max_fd() combo.
Definition io.c:7715
VALUE rb_gets(void)
Much like rb_io_gets(), but it reads from the mysterious ARGF object.
Definition io.c:10745
int rb_cloexec_fcntl_dupfd(int fd, int minfd)
Duplicates a file descriptor with closing on exec.
Definition io.c:517
VALUE rb_output_fs
The field separator character for outputs, or the $,.
Definition io.c:206
VALUE rb_file_open_str(VALUE fname, const char *fmode)
Identical to rb_file_open(), except it takes the pathname as a Ruby's string instead of C's.
Definition io.c:7599
int rb_cloexec_dup(int oldfd)
Identical to rb_cloexec_fcntl_dupfd(), except it implies minfd is 3.
Definition io.c:402
VALUE rb_file_open(const char *fname, const char *fmode)
Opens a file located at the given path.
Definition io.c:7606
VALUE rb_io_close(VALUE io)
Closes the IO.
Definition io.c:6071
VALUE rb_default_rs
This is the default value of rb_rs, i.e.
Definition io.c:209
void rb_provide(const char *feature)
Declares that the given feature is already provided by someone else.
Definition load.c:710
void rb_lastline_set(VALUE str)
Updates $_.
Definition vm.c:2149
VALUE rb_lastline_get(void)
Queries the last line, or the $_.
Definition vm.c:2143
int rb_obj_method_arity(VALUE obj, ID mid)
Identical to rb_mod_method_arity(), except it searches for singleton methods rather than instance met...
Definition proc.c:3761
rb_pid_t rb_waitpid(rb_pid_t pid, int *status, int flags)
Waits for a process, with releasing GVL.
Definition process.c:1161
void rb_last_status_set(int status, rb_pid_t pid)
Sets the "last status", or the $?.
Definition process.c:676
VALUE rb_str_append(VALUE dst, VALUE src)
Identical to rb_str_buf_append(), except it converts the right hand side before concatenating.
Definition string.c:3913
#define rb_str_new(str, len)
Allocates an instance of rb_cString.
Definition string.h:1523
#define rb_str_buf_cat
Just another name of rb_str_cat.
Definition string.h:1706
#define rb_usascii_str_new(str, len)
Identical to rb_str_new, except it generates a string of "US ASCII" encoding.
Definition string.h:1557
size_t rb_str_capacity(VALUE str)
Queries the capacity of the given string.
Definition string.c:1023
VALUE rb_str_new_frozen(VALUE str)
Creates a frozen copy of the string, if necessary.
Definition string.c:1555
VALUE rb_str_dup(VALUE str)
Duplicates a string.
Definition string.c:2038
VALUE rb_str_cat(VALUE dst, const char *src, long srclen)
Destructively appends the passed contents to the string.
Definition string.c:3681
VALUE rb_str_locktmp(VALUE str)
Obtains a "temporary lock" of the string.
VALUE rb_str_no_gvl_safe_acquire(VALUE orig)
Creates a frozen copy of orig that guarantees the RSTRING_PTR is safe to use in operations that relea...
Definition string.c:1584
VALUE rb_str_equal(VALUE str1, VALUE str2)
Equality of two strings.
Definition string.c:4383
void rb_str_no_gvl_safe_release(VALUE orig, VALUE tmp)
Releases a string created from rb_str_no_gvl_safe_acquire.
Definition string.c:1627
void rb_str_set_len(VALUE str, long len)
Overwrites the length of the string.
Definition string.c:3500
VALUE rb_str_buf_cat_ascii(VALUE dst, const char *src)
Identical to rb_str_cat_cstr(), except it additionally assumes the source string be a NUL terminated ...
Definition string.c:3855
VALUE rb_check_string_type(VALUE obj)
Try converting an object to its stringised representation using its to_str method,...
Definition string.c:3047
VALUE rb_str_substr(VALUE str, long beg, long len)
This is the implementation of two-argumented String#slice.
Definition string.c:3363
VALUE rb_str_unlocktmp(VALUE str)
Releases a lock formerly obtained by rb_str_locktmp().
Definition string.c:3482
void rb_str_modify_expand(VALUE str, long capa)
Identical to rb_str_modify(), except it additionally expands the capacity of the receiver.
Definition string.c:2816
VALUE rb_str_buf_new(long capa)
Allocates a "string buffer".
Definition string.c:1769
#define rb_str_new_cstr(str)
Identical to rb_str_new, except it assumes the passed pointer is a pointer to a C string.
Definition string.h:1539
VALUE rb_obj_as_string(VALUE obj)
Try converting an object to its stringised representation using its to_s method, if any.
Definition string.c:1902
int rb_thread_interrupted(VALUE thval)
Checks if the thread's execution was recently interrupted.
Definition thread.c:1662
VALUE rb_mutex_new(void)
Creates a mutex.
int rb_thread_fd_writable(int fd)
Identical to rb_thread_wait_fd(), except it blocks the current thread until the given file descriptor...
Definition io.c:1719
VALUE rb_exec_recursive(VALUE(*f)(VALUE g, VALUE h, int r), VALUE g, VALUE h)
"Recursion" API entry point.
VALUE rb_mutex_synchronize(VALUE mutex, VALUE(*func)(VALUE arg), VALUE arg)
Obtains the lock, runs the passed function, and releases the lock when it completes.
void rb_thread_check_ints(void)
Checks for interrupts.
Definition thread.c:1645
VALUE rb_thread_current(void)
Obtains the "current" thread.
Definition thread.c:3480
int rb_thread_wait_fd(int fd)
Blocks the current thread until the given file descriptor is ready to be read.
Definition io.c:1713
void rb_thread_sleep(int sec)
Blocks for the given period of time.
Definition thread.c:1668
struct timeval rb_time_interval(VALUE num)
Creates a "time interval".
Definition time.c:2984
void rb_set_class_path(VALUE klass, VALUE space, const char *name)
Names a class.
Definition variable.c:459
VALUE rb_ivar_set(VALUE obj, ID name, VALUE val)
Identical to rb_iv_set(), except it accepts the name as an ID instead of a C string.
Definition variable.c:2141
VALUE rb_class_name(VALUE obj)
Queries the name of the given object's class.
Definition variable.c:518
int rb_respond_to(VALUE obj, ID mid)
Queries if the object responds to the method.
Definition vm_method.c:3693
int rb_method_basic_definition_p(VALUE klass, ID mid)
Well... Let us hesitate from describing what a "basic definition" is.
Definition vm_method.c:3571
VALUE rb_check_funcall(VALUE recv, ID mid, int argc, const VALUE *argv)
Identical to rb_funcallv(), except it returns RUBY_Qundef instead of raising rb_eNoMethodError.
Definition vm_eval.c:691
void rb_define_alloc_func(VALUE klass, rb_alloc_func_t func)
Sets the allocator function of a class.
static ID rb_intern_const(const char *str)
This is a "tiny optimisation" over rb_intern().
Definition symbol.h:285
#define RB_ID2SYM
Just another name of rb_id2sym.
Definition symbol.h:42
void rb_define_global_const(const char *name, VALUE val)
Identical to rb_define_const(), except it defines that of "global", i.e.
Definition variable.c:4095
void rb_define_readonly_variable(const char *name, const VALUE *var)
Identical to rb_define_variable(), except it does not allow Ruby programs to assign values to such gl...
Definition variable.c:890
rb_gvar_setter_t rb_gvar_readonly_setter
This function just raises rb_eNameError.
Definition variable.h:135
#define FMODE_READABLE
The IO is opened for reading.
Definition io.h:162
enum rb_io_mode rb_io_modestr_fmode(const char *modestr)
Maps a file mode string (that rb_file_open() takes) into a mixture of FMODE_ flags.
Definition io.c:6800
VALUE rb_io_get_io(VALUE io)
Identical to rb_io_check_io(), except it raises exceptions on conversion failures.
Definition io.c:869
VALUE rb_io_timeout(VALUE io)
Get the timeout associated with the specified io object.
Definition io.c:915
VALUE rb_io_taint_check(VALUE obj)
Definition io.c:839
void rb_io_read_check(rb_io_t *fptr)
Blocks until there is a pending read in the passed IO.
Definition io.c:1153
int rb_io_modestr_oflags(const char *modestr)
Identical to rb_io_modestr_fmode(), except it returns a mixture of O_ flags.
Definition io.c:6933
#define FMODE_SETENC_BY_BOM
This flag amends the encoding of the IO so that the BOM of the contents of the IO takes effect.
Definition io.h:260
rb_io_event
Type of events that an IO can wait.
Definition io.h:96
@ RUBY_IO_READABLE
IO::READABLE
Definition io.h:97
@ RUBY_IO_PRIORITY
IO::PRIORITY
Definition io.h:99
@ RUBY_IO_WRITABLE
IO::WRITABLE
Definition io.h:98
#define FMODE_READWRITE
The IO is opened for both read/write.
Definition io.h:168
#define FMODE_EXTERNAL
This flag means that an IO object is wrapping an "external" file descriptor, which is owned by someth...
Definition io.h:252
#define GetOpenFile
This is an old name of RB_IO_POINTER.
Definition io.h:442
void rb_io_check_byte_readable(rb_io_t *fptr)
Asserts that an IO is opened for byte-based reading.
Definition io.c:1099
#define FMODE_TTY
The IO is a TTY.
Definition io.h:192
#define FMODE_CREATE
The IO is opened for creating.
Definition io.h:215
void rb_io_check_readable(rb_io_t *fptr)
Just another name of rb_io_check_byte_readable.
Definition io.c:1108
int rb_wait_for_single_fd(int fd, int events, struct timeval *tv)
Blocks until the passed file descriptor is ready for the passed events.
Definition io.c:1705
FILE * rb_fdopen(int fd, const char *modestr)
Identical to rb_io_stdio_file(), except it takes file descriptors instead of Ruby's IO.
Definition io.c:7416
int rb_io_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding **enc2_p, enum rb_io_mode *fmode_p)
This function breaks down the option hash that IO#initialize takes into components.
Definition io.c:7082
int rb_io_descriptor(VALUE io)
Returns an integer representing the numeric file descriptor for io.
Definition io.c:3020
#define FMODE_WRITABLE
The IO is opened for writing.
Definition io.h:165
FILE * rb_io_stdio_file(rb_io_t *fptr)
Finds or creates a stdio's file structure from a Ruby's one.
Definition io.c:9703
#define FMODE_APPEND
The IO is opened for appending.
Definition io.h:207
#define MakeOpenFile
This is an old name of RB_IO_OPEN.
Definition io.h:465
#define FMODE_DUPLEX
Ruby eventually detects that the IO is bidirectional.
Definition io.h:200
#define FMODE_BINMODE
The IO is in "binary mode".
Definition io.h:179
int rb_io_maybe_wait_readable(int error, VALUE io, VALUE timeout)
Blocks until the passed IO is ready for reading, if that makes sense for the passed errno.
Definition io.c:1772
int capa
Designed capacity of the buffer.
Definition io.h:11
#define RB_IO_POINTER(obj, fp)
Queries the underlying IO pointer.
Definition io.h:436
VALUE rb_io_maybe_wait(int error, VALUE io, VALUE events, VALUE timeout)
Identical to rb_io_wait() except it additionally takes previous errno.
Definition io.c:1725
VALUE rb_eIOTimeoutError
Indicates that a timeout has occurred while performing an IO operation.
Definition io.c:190
char * ptr
Pointer to the underlying memory region, of at least capa bytes.
Definition io.h:2
#define FMODE_SYNC
The IO is in "sync mode".
Definition io.h:186
int off
Offset inside of ptr.
Definition io.h:5
VALUE rb_io_path(VALUE io)
Returns the path for the given IO.
Definition io.c:3099
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)
This function can be seen as an extended version of rb_io_extract_encoding_option() that not only con...
Definition io.c:7207
void rb_io_check_initialized(rb_io_t *fptr)
Asserts that the passed IO is initialised.
Definition io.c:846
#define FMODE_EXCL
This flag amends the effect of FMODE_CREATE, so that if there already is a file at the given path the...
Definition io.h:223
#define FMODE_TEXTMODE
The IO is in "text mode".
Definition io.h:243
int rb_io_fptr_finalize(rb_io_t *fptr)
Destroys the given IO.
Definition io.c:5982
VALUE rb_io_check_io(VALUE io)
Try converting an object to its IO representation using its to_io method, if any.
Definition io.c:875
VALUE rb_io_closed_p(VALUE io)
Returns whether or not the underlying IO is closed.
Definition io.c:6179
VALUE rb_io_set_timeout(VALUE io, VALUE timeout)
Set the timeout associated with the specified io object.
Definition io.c:944
ssize_t rb_io_bufwrite(VALUE io, const void *buf, size_t size)
Buffered write to the passed IO.
Definition io.c:2136
void rb_io_check_char_readable(rb_io_t *fptr)
Asserts that an IO is opened for character-based reading.
Definition io.c:1080
#define FMODE_TRUNC
This flag amends the effect of FMODE_CREATE, so that if there already is a file at the given path it ...
Definition io.h:229
VALUE rb_io_get_write_io(VALUE io)
Queries the tied IO for writing.
Definition io.c:881
void rb_io_set_nonblock(rb_io_t *fptr)
Instructs the OS to put its internal file structure into "nonblocking mode".
Definition io.c:3586
int rb_io_wait_writable(int fd)
Blocks until the passed file descriptor gets writable.
Definition io.c:1661
VALUE rb_io_open_descriptor(VALUE klass, int descriptor, int mode, VALUE path, VALUE timeout, struct rb_io_encoding *encoding)
Allocate a new IO object, with the given file descriptor.
Definition io.c:9569
VALUE rb_io_set_write_io(VALUE io, VALUE w)
Assigns the tied IO for writing.
Definition io.c:892
void rb_io_check_writable(rb_io_t *fptr)
Asserts that an IO is opened for writing.
Definition io.c:1132
int rb_io_maybe_wait_writable(int error, VALUE io, VALUE timeout)
Blocks until the passed IO is ready for writing, if that makes sense for the passed errno.
Definition io.c:1787
void rb_io_check_closed(rb_io_t *fptr)
This badly named function asserts that the passed IO is open.
Definition io.c:854
int rb_io_wait_readable(int fd)
Blocks until the passed file descriptor gets readable.
Definition io.c:1626
void rb_io_synchronized(rb_io_t *fptr)
Sets FMODE_SYNC.
Definition io.c:7707
VALUE rb_io_wait(VALUE io, VALUE events, VALUE timeout)
Blocks until the passed IO is ready for the passed events.
Definition io.c:1566
int len
Length of the buffer.
Definition io.h:8
VALUE rb_ractor_stdin(void)
Queries the standard input of the current Ractor that is calling this function.
Definition ractor.c:1455
void rb_ractor_stderr_set(VALUE io)
Assigns an IO to the standard error of the Ractor that is calling this function.
Definition ractor.c:1524
void rb_ractor_stdout_set(VALUE io)
Assigns an IO to the standard output of the Ractor that is calling this function.
Definition ractor.c:1512
void rb_ractor_stdin_set(VALUE io)
Assigns an IO to the standard input of the Ractor that is calling this function.
Definition ractor.c:1500
void * rb_thread_call_with_gvl(void *(*func)(void *), void *data1)
(Re-)acquires the GVL.
Definition thread.c:2319
#define RB_NUM2INT
Just another name of rb_num2int_inline.
Definition int.h:38
#define RB_INT2NUM
Just another name of rb_int2num_inline.
Definition int.h:37
VALUE rb_f_sprintf(int argc, const VALUE *argv)
Identical to rb_str_format(), except how the arguments are arranged.
Definition sprintf.c:232
#define RB_BLOCK_CALL_FUNC_ARGLIST(yielded_arg, callback_arg)
Shim for block function parameters.
Definition iterator.h:58
VALUE rb_yield_values2(int n, const VALUE *argv)
Identical to rb_yield_values(), except it takes the parameters as a C array instead of variadic argum...
Definition vm_eval.c:1423
VALUE rb_yield(VALUE val)
Yields the block.
Definition vm_eval.c:1378
void rb_fd_term(rb_fdset_t *f)
Destroys the rb_fdset_t, releasing any memory and resources it used.
#define MEMZERO(p, type, n)
Handy macro to erase a region of memory.
Definition memory.h:360
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
Definition memory.h:167
#define MEMMOVE(p1, p2, type, n)
Handy macro to call memmove.
Definition memory.h:384
#define NUM2MODET
Converts a C's mode_t into an instance of rb_cInteger.
Definition mode_t.h:28
void rb_define_hooked_variable(const char *q, VALUE *w, type *e, void_type *r)
Define a function-backended global variable.
void rb_define_virtual_variable(const char *q, type *w, void_type *e)
Define a function-backended global variable.
VALUE rb_rescue2(type *q, VALUE w, type *e, VALUE r,...)
An equivalent of rescue clause.
VALUE rb_ensure(type *q, VALUE w, type *e, VALUE r)
An equivalent of ensure clause.
#define PRI_OFFT_PREFIX
A rb_sprintf() format prefix to be used for an off_t parameter.
Definition off_t.h:55
#define OFFT2NUM
Converts a C's off_t into an instance of rb_cInteger.
Definition off_t.h:33
#define NUM2OFFT
Converts an instance of rb_cNumeric into C's off_t.
Definition off_t.h:44
#define PIDT2NUM
Converts a C's pid_t into an instance of rb_cInteger.
Definition pid_t.h:28
#define rb_fd_isset
Queries if the given fd is in the rb_fdset_t.
Definition posix.h:60
#define rb_fd_select
Waits for multiple file descriptors at once.
Definition posix.h:66
#define rb_fd_init
Initialises the :given :rb_fdset_t.
Definition posix.h:63
#define rb_fd_set
Sets the given fd to the rb_fdset_t.
Definition posix.h:54
#define RARRAY_LEN
Just another name of rb_array_len.
Definition rarray.h:50
static int RARRAY_LENINT(VALUE ary)
Identical to rb_array_len(), except it differs for the return type.
Definition rarray.h:280
#define RARRAY_AREF(a, i)
Definition rarray.h:402
#define RARRAY_CONST_PTR
Just another name of rb_array_const_ptr.
Definition rarray.h:51
#define RFILE(obj)
Convenient casting macro.
Definition rfile.h:50
#define StringValue(v)
Ensures that the parameter object is a String.
Definition rstring.h:66
static char * RSTRING_END(VALUE str)
Queries the end of the contents pointer of the string.
Definition rstring.h:409
#define RSTRING_GETMEM(str, ptrvar, lenvar)
Convenient macro to obtain the contents and length at once.
Definition rstring.h:450
#define StringValueCStr(v)
Identical to StringValuePtr, except it additionally checks for the contents for viability as a C stri...
Definition rstring.h:89
#define RUBY_TYPED_DEFAULT_FREE
This is a value you can set to rb_data_type_struct::dfree.
Definition rtypeddata.h:81
#define TypedData_Make_Struct(klass, type, data_type, sval)
Identical to TypedData_Wrap_Struct, except it allocates a new data region internally instead of takin...
Definition rtypeddata.h:604
VALUE rb_get_argv(void)
Queries the arguments passed to the current process that you can access from Ruby as ARGV.
Definition io.c:14994
void rb_p(VALUE obj)
Inspects an object.
Definition io.c:9355
#define FilePathValue(v)
Ensures that the parameter object is a path.
Definition ruby.h:90
#define errno
Ractor-aware version of errno.
Definition ruby.h:388
#define RB_SCAN_ARGS_LAST_HASH_KEYWORDS
Treat a final argument as keywords if it is a hash, and not as keywords otherwise.
Definition scan_args.h:59
#define RB_PASS_CALLED_KEYWORDS
Pass keywords if current method is called with keywords, useful for argument delegation.
Definition scan_args.h:78
int rb_thread_fd_select(int nfds, rb_fdset_t *rfds, rb_fdset_t *wfds, rb_fdset_t *efds, struct timeval *timeout)
Waits for multiple file descriptors at once.
Definition thread.c:4853
static bool RB_TEST(VALUE obj)
Emulates Ruby's "if" statement.
@ RUBY_Qfalse
#define RTEST
This is an old name of RB_TEST.
#define _(args)
This was a transition path from K&R to ANSI.
Definition stdarg.h:35
C99 shim for <stdbool.h>
Ruby's File and IO.
Definition rfile.h:35
Definition io.c:238
Definition win32.h:196
This is the struct that holds necessary info for a struct.
Definition rtypeddata.h:242
The data structure which wraps the fd_set bitmap used by select(2).
Definition largesize.h:71
Decomposed encoding flags (e.g.
Definition io.h:134
int ecflags
Flags.
Definition io.h:144
VALUE ecopts
Flags as Ruby hash.
Definition io.h:152
rb_encoding * enc2
External encoding.
Definition io.h:138
rb_encoding * enc
Internal encoding.
Definition io.h:136
IO buffers.
Definition io.h:109
char * ptr
Pointer to the underlying memory region, of at least capa bytes.
Definition io.h:112
int off
Offset inside of ptr.
Definition io.h:115
int len
Length of the buffer.
Definition io.h:118
int capa
Designed capacity of the buffer.
Definition io.h:121
Ruby's IO, metadata and buffers.
Definition io.h:295
rb_io_buffer_t wbuf
Write buffer.
Definition io.h:330
enum rb_io_mode mode
mode flags: FMODE_XXXs
Definition io.h:310
void(* finalize)(struct rb_io *, int)
finalize proc
Definition io.h:326
rb_econv_t * readconv
Encoding converter used when reading from this IO.
Definition io.h:352
rb_econv_t * writeconv
Encoding converter used when writing to this IO.
Definition io.h:363
struct rb_io_encoding encs
Decomposed encoding flags.
Definition io.h:348
VALUE self
The IO's Ruby level counterpart.
Definition io.h:298
VALUE write_lock
This is a Ruby level mutex.
Definition io.h:400
VALUE timeout
The timeout associated with this IO when performing blocking operations.
Definition io.h:406
FILE * stdio_file
stdio ptr for read/write, if available.
Definition io.h:302
VALUE writeconv_pre_ecopts
Value of ::rb_io_t::rb_io_enc_t::ecopts stored right before initialising rb_io_t::writeconv.
Definition io.h:390
VALUE tied_io_for_writing
Duplex IO object, if set.
Definition io.h:345
int writeconv_initialized
Whether rb_io_t::writeconv is already set up.
Definition io.h:376
int fd
file descriptor.
Definition io.h:306
rb_io_buffer_t rbuf
(Byte) read buffer.
Definition io.h:337
int lineno
number of lines read
Definition io.h:318
struct ccan_list_head blocking_operations
Threads that are performing a blocking operation without the GVL using this IO.
Definition io.h:134
VALUE writeconv_asciicompat
This is, when set, an instance of rb_cString which holds the "common" encoding.
Definition io.h:372
rb_io_buffer_t cbuf
rb_io_ungetc() destination.
Definition io.h:359
rb_pid_t pid
child's pid (for pipes)
Definition io.h:314
int writeconv_pre_ecflags
Value of ::rb_io_t::rb_io_enc_t::ecflags stored right before initialising rb_io_t::writeconv.
Definition io.h:383
VALUE pathv
pathname for file
Definition io.h:322
intptr_t SIGNED_VALUE
A signed integer type that has the same width with VALUE.
Definition value.h:63
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
Definition value.h:52
uintptr_t VALUE
Type that represents a Ruby object.
Definition value.h:40
static bool RB_FLOAT_TYPE_P(VALUE obj)
Queries if the object is an instance of rb_cFloat.
Definition value_type.h:264
static bool RB_SYMBOL_P(VALUE obj)
Queries if the object is an instance of rb_cSymbol.
Definition value_type.h:307
static void Check_Type(VALUE v, enum ruby_value_type t)
Identical to RB_TYPE_P(), except it raises exceptions on predication failure.
Definition value_type.h:425
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.
Definition value_type.h:376
#define RBIMPL_WARNING_IGNORED(flag)
Suppresses a warning.
#define RBIMPL_WARNING_PUSH()
Pushes compiler warning state.
#define RBIMPL_WARNING_POP()
Pops compiler warning state.