Ruby 4.1.0dev (2026-09-27 revision f6ff9e7d02e46360f8930b280a3dd921cccbda29)
io.c (f6ff9e7d02e46360f8930b280a3dd921cccbda29)
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#ifdef __QNXNTO__
60#include <unix.h>
61#endif
62
63#include <sys/types.h>
64#ifdef HAVE_SYS_IOCTL_H
65#include <sys/ioctl.h>
66#endif
67#if defined(HAVE_FCNTL_H)
68#include <fcntl.h>
69#elif defined(HAVE_SYS_FCNTL_H)
70#include <sys/fcntl.h>
71#endif
72
73#ifdef HAVE_SYS_TIME_H
74# include <sys/time.h>
75#endif
76
77#include <sys/stat.h>
78
79#if defined(HAVE_SYS_PARAM_H) || defined(__HIUX_MPP__)
80# include <sys/param.h>
81#endif
82
83#if !defined NOFILE
84# define NOFILE 64
85#endif
86
87#ifdef HAVE_UNISTD_H
88#include <unistd.h>
89#endif
90
91#ifdef HAVE_SYSCALL_H
92#include <syscall.h>
93#elif defined HAVE_SYS_SYSCALL_H
94#include <sys/syscall.h>
95#endif
96
97#ifdef HAVE_SYS_UIO_H
98#include <sys/uio.h>
99#endif
100
101#ifdef HAVE_SYS_WAIT_H
102# include <sys/wait.h> /* for WNOHANG on BSD */
103#endif
104
105#ifdef HAVE_COPYFILE_H
106# include <copyfile.h>
107
108# ifndef COPYFILE_STATE_COPIED
109/*
110 * Some OSes (e.g., OSX < 10.6) implement fcopyfile() but not
111 * COPYFILE_STATE_COPIED. Since the only use of the former here
112 * requires the latter, we disable the former when the latter is undefined.
113 */
114# undef HAVE_FCOPYFILE
115# endif
116
117#endif
118
119#if defined __APPLE__
120# include <AvailabilityMacros.h>
121#endif
122
124#include "ccan/list/list.h"
125#include "dln.h"
126#include "encindex.h"
127#include "id.h"
128#include "internal.h"
129#include "internal/class.h"
130#include "internal/encoding.h"
131#include "internal/error.h"
132#include "internal/inits.h"
133#include "internal/io.h"
134#include "internal/numeric.h"
135#include "internal/object.h"
136#include "internal/process.h"
137#include "internal/thread.h"
138#include "internal/transcode.h"
139#include "internal/variable.h"
140#include "ruby/io.h"
141#include "ruby/io/buffer.h"
142#include "ruby/missing.h"
143#include "ruby/thread.h"
144#include "ruby/util.h"
145#include "ruby_atomic.h"
146#include "ruby/ractor.h"
147
148#if !USE_POLL
149# include "vm_core.h"
150#endif
151
152#include "builtin.h"
153
154#ifndef O_ACCMODE
155#define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR)
156#endif
157
158#ifndef PIPE_BUF
159# ifdef _POSIX_PIPE_BUF
160# define PIPE_BUF _POSIX_PIPE_BUF
161# else
162# define PIPE_BUF 512 /* is this ok? */
163# endif
164#endif
165
166#ifndef EWOULDBLOCK
167# define EWOULDBLOCK EAGAIN
168#endif
169
170#if defined(HAVE___SYSCALL) && (defined(__APPLE__) || defined(__OpenBSD__))
171/* Mac OS X and OpenBSD have __syscall but don't define it in headers */
172off_t __syscall(quad_t number, ...);
173#endif
174
175#define IO_RBUF_CAPA_MIN 8192
176#define IO_CBUF_CAPA_MIN (128*1024)
177#define IO_RBUF_CAPA_FOR(fptr) (NEED_READCONV(fptr) ? IO_CBUF_CAPA_MIN : IO_RBUF_CAPA_MIN)
178#define IO_WBUF_CAPA_MIN 8192
179
180#define IO_MAX_BUFFER_GROWTH 8 * 1024 * 1024 // 8MB
181
182/* define system APIs */
183#ifdef _WIN32
184#undef open
185#define open rb_w32_uopen
186#undef rename
187#define rename(f, t) rb_w32_urename((f), (t))
188#include "win32/file.h"
189#endif
190
197
198static VALUE rb_eEAGAINWaitReadable;
199static VALUE rb_eEAGAINWaitWritable;
200#if EAGAIN != EWOULDBLOCK
201static VALUE rb_eEWOULDBLOCKWaitReadable;
202static VALUE rb_eEWOULDBLOCKWaitWritable;
203#endif
204static VALUE rb_eEINPROGRESSWaitWritable;
205static VALUE rb_eEINPROGRESSWaitReadable;
206
208static VALUE orig_stdout, orig_stderr;
209
211VALUE rb_rs;
214
215static VALUE argf;
216
217static ID id_write, id_read, id_flush, id_readpartial, id_set_encoding, id_fileno;
218static VALUE sym_mode, sym_perm, sym_flags, sym_extenc, sym_intenc, sym_encoding, sym_open_args;
219static VALUE sym_textmode, sym_binmode, sym_autoclose;
220static VALUE sym_SET, sym_CUR, sym_END;
221static VALUE sym_wait_readable, sym_wait_writable;
222#ifdef SEEK_DATA
223static VALUE sym_DATA;
224#endif
225#ifdef SEEK_HOLE
226static VALUE sym_HOLE;
227#endif
228
229static VALUE prep_io(int fd, enum rb_io_mode fmode, VALUE klass, const char *path);
230
231VALUE
232rb_io_blocking_region_wait(struct rb_io *io, rb_blocking_function_t *function, void *argument, enum rb_io_event events)
233{
234 return rb_thread_io_blocking_call(io, function, argument, events);
235}
236
237VALUE rb_io_blocking_region(struct rb_io *io, rb_blocking_function_t *function, void *argument)
238{
239 return rb_io_blocking_region_wait(io, function, argument, 0);
240}
241
242struct argf {
243 VALUE filename, current_file;
244 long last_lineno; /* $. */
245 long lineno;
246 VALUE argv;
247 VALUE inplace;
248 struct rb_io_encoding encs;
249 int8_t init_p, next_p, binmode;
250};
251
252
253#if defined(__APPLE__) && \
254 (!defined(MAC_OS_VERSION_27_0) || (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_VERSION_27_0))
255
256# if __has_attribute(availability) && __has_warning("-Wunguarded-availability-new")
257
259RBIMPL_WARNING_IGNORED(-Wunguarded-availability-new)
260
261# ifdef HAVE_DUP3
262static inline int (*rb_dup3(void))(int, int, int) {return &dup3;}
263# define dup3 rb_dup3()
264# endif
265
266# ifdef HAVE_PIPE2
267static inline int (*rb_pipe2(void))(int [2], int) {return &pipe2;}
268# define pipe2 rb_pipe2()
269# endif
270
272
273# else /* __API_AVAILABLE macro does nothing on gcc */
274
275# ifdef HAVE_DUP3
276__attribute__((weak)) int dup3(int, int, int);
277# endif
278# ifdef HAVE_PIPE2
279__attribute__((weak)) int pipe2(int [2], int);
280# endif
281
282# endif
283#endif /* __APPLE__ && < MAC_OS_X_VERSION_27_0 */
284
285static rb_atomic_t max_file_descriptor = NOFILE;
286void
288{
289 rb_atomic_t afd = (rb_atomic_t)fd;
290 rb_atomic_t max_fd = max_file_descriptor;
291 int err;
292
293 if (fd < 0 || afd <= max_fd)
294 return;
295
296#if defined(HAVE_FCNTL) && defined(F_GETFL)
297 err = fcntl(fd, F_GETFL) == -1;
298#else
299 {
300 struct stat buf;
301 err = fstat(fd, &buf) != 0;
302 }
303#endif
304 if (err && errno == EBADF) {
305 rb_bug("rb_update_max_fd: invalid fd (%d) given.", fd);
306 }
307
308 while (max_fd < afd) {
309 max_fd = ATOMIC_CAS(max_file_descriptor, max_fd, afd);
310 }
311}
312
313void
314rb_maygvl_fd_fix_cloexec(int fd)
315{
316 /* MinGW don't have F_GETFD and FD_CLOEXEC. [ruby-core:40281] */
317#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
318 int flags, flags2, ret;
319 flags = fcntl(fd, F_GETFD); /* should not fail except EBADF. */
320 if (flags == -1) {
321 rb_bug("rb_maygvl_fd_fix_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(errno));
322 }
323 if (fd <= 2)
324 flags2 = flags & ~FD_CLOEXEC; /* Clear CLOEXEC for standard file descriptors: 0, 1, 2. */
325 else
326 flags2 = flags | FD_CLOEXEC; /* Set CLOEXEC for non-standard file descriptors: 3, 4, 5, ... */
327 if (flags != flags2) {
328 ret = fcntl(fd, F_SETFD, flags2);
329 if (ret != 0) {
330 rb_bug("rb_maygvl_fd_fix_cloexec: fcntl(%d, F_SETFD, %d) failed: %s", fd, flags2, strerror(errno));
331 }
332 }
333#endif
334}
335
336void
338{
339 rb_maygvl_fd_fix_cloexec(fd);
341}
342
343/* this is only called once */
344static int
345rb_fix_detect_o_cloexec(int fd)
346{
347#if defined(O_CLOEXEC) && defined(F_GETFD)
348 int flags = fcntl(fd, F_GETFD);
349
350 if (flags == -1)
351 rb_bug("rb_fix_detect_o_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(errno));
352
353 if (flags & FD_CLOEXEC)
354 return 1;
355#endif /* fall through if O_CLOEXEC does not work: */
356 rb_maygvl_fd_fix_cloexec(fd);
357 return 0;
358}
359
360static inline bool
361io_again_p(int e)
362{
363 return (e == EWOULDBLOCK) || (e == EAGAIN);
364}
365
366int
367rb_cloexec_open(const char *pathname, int flags, mode_t mode)
368{
369 int ret;
370 static int o_cloexec_state = -1; /* <0: unknown, 0: ignored, >0: working */
371
372 static const int retry_interval = 0;
373 static const int retry_max_count = 10000;
374
375 int retry_count = 0;
376
377#ifdef O_CLOEXEC
378 /* O_CLOEXEC is available since Linux 2.6.23. Linux 2.6.18 silently ignore it. */
379 flags |= O_CLOEXEC;
380#elif defined O_NOINHERIT
381 flags |= O_NOINHERIT;
382#endif
383
384 while ((ret = open(pathname, flags, mode)) == -1) {
385 int e = errno;
386 if (!io_again_p(e)) break;
387 if (retry_count++ >= retry_max_count) break;
388
389 sleep(retry_interval);
390 }
391
392 if (ret < 0) return ret;
393 if (ret <= 2 || o_cloexec_state == 0) {
394 rb_maygvl_fd_fix_cloexec(ret);
395 }
396 else if (o_cloexec_state > 0) {
397 return ret;
398 }
399 else {
400 o_cloexec_state = rb_fix_detect_o_cloexec(ret);
401 }
402 return ret;
403}
404
405int
407{
408 /* Don't allocate standard file descriptors: 0, 1, 2 */
409 return rb_cloexec_fcntl_dupfd(oldfd, 3);
410}
411
412int
413rb_cloexec_dup2(int oldfd, int newfd)
414{
415 int ret;
416
417 /* When oldfd == newfd, dup2 succeeds but dup3 fails with EINVAL.
418 * rb_cloexec_dup2 succeeds as dup2. */
419 if (oldfd == newfd) {
420 ret = newfd;
421 }
422 else {
423#if defined(HAVE_DUP3) && defined(O_CLOEXEC)
424# if defined(__APPLE__)
425# define try_dup3 (dup3 != NULL)
426# define abandon_dup3() true
427# else
428 static bool try_dup3 = true;
429# define abandon_dup3() (errno != ENOSYS || !!(try_dup3 = false))
430# endif
431 if (newfd <= 2) {
432 /* pass stdin, stdout and stderr to children */
433 }
434 else if (try_dup3) {
435 ret = dup3(oldfd, newfd, O_CLOEXEC);
436 /* dup3 is available since:
437 * - Linux 2.6.27, glibc 2.9
438 * - macOS 27.0
439 */
440 if (ret != -1)
441 return ret;
442 if (abandon_dup3()) return ret;
443 }
444#endif
445 ret = dup2(oldfd, newfd);
446 if (ret < 0) return ret;
447 }
448 rb_maygvl_fd_fix_cloexec(ret);
449 return ret;
450}
451
452static int
453rb_fd_set_nonblock(int fd)
454{
455#ifdef _WIN32
456 return rb_w32_set_nonblock(fd);
457#elif defined(F_GETFL)
458 int oflags = fcntl(fd, F_GETFL);
459
460 if (oflags == -1)
461 return -1;
462 if (oflags & O_NONBLOCK)
463 return 0;
464 oflags |= O_NONBLOCK;
465 return fcntl(fd, F_SETFL, oflags);
466#endif
467 return 0;
468}
469
470static inline int
471cloexec_pipe(int descriptors[2], int flags, bool force_cloexec)
472{
473 int result = -1;
474#ifdef HAVE_PIPE2
475# if defined(__APPLE__)
476# define try_pipe2 (pipe2 != NULL)
477# define abandon_pipe2() true
478# else
479 static bool try_pipe2 = true;
480# define abandon_pipe2() (errno != ENOSYS || !!(try_pipe2 = false))
481# endif
482 if (try_pipe2) {
483 result = pipe2(descriptors, O_CLOEXEC | flags);
484 if (result == 0) return result;
485 if (abandon_pipe2()) return result;
486 }
487#endif
488 if (result < 0 && (result = pipe(descriptors)) < 0)
489 return result;
490
491#ifdef __CYGWIN__
492 if (result == 0 && descriptors[1] == -1) {
493 close(descriptors[0]);
494 descriptors[0] = -1;
495 errno = ENFILE;
496 return -1;
497 }
498#endif
499
500 if (!force_cloexec) return result;
501
502 /* no pipe2 or fallenback to dup */
503 rb_maygvl_fd_fix_cloexec(descriptors[0]);
504 rb_maygvl_fd_fix_cloexec(descriptors[1]);
505
506#ifndef _WIN32
507 rb_fd_set_nonblock(descriptors[0]);
508 rb_fd_set_nonblock(descriptors[1]);
509#endif
510
511 return result;
512}
513
514int
515rb_cloexec_pipe(int descriptors[2])
516{
517 return cloexec_pipe(descriptors, O_NONBLOCK, true);
518}
519
520int
521rb_cloexec_fcntl_dupfd(int fd, int minfd)
522{
523 int ret;
524
525#if defined(HAVE_FCNTL) && defined(F_DUPFD_CLOEXEC) && defined(F_DUPFD)
526 static int try_dupfd_cloexec = 1;
527 if (try_dupfd_cloexec) {
528 ret = fcntl(fd, F_DUPFD_CLOEXEC, minfd);
529 if (ret != -1) {
530 if (ret <= 2)
531 rb_maygvl_fd_fix_cloexec(ret);
532 return ret;
533 }
534 /* F_DUPFD_CLOEXEC is available since Linux 2.6.24. Linux 2.6.18 fails with EINVAL */
535 if (errno == EINVAL) {
536 ret = fcntl(fd, F_DUPFD, minfd);
537 if (ret != -1) {
538 try_dupfd_cloexec = 0;
539 }
540 }
541 }
542 else {
543 ret = fcntl(fd, F_DUPFD, minfd);
544 }
545#elif defined(HAVE_FCNTL) && defined(F_DUPFD)
546 ret = fcntl(fd, F_DUPFD, minfd);
547#else
548 ret = dup(fd);
549 if (ret >= 0 && ret < minfd) {
550 const int prev_fd = ret;
551 ret = rb_cloexec_fcntl_dupfd(fd, minfd);
552 close(prev_fd);
553 }
554 return ret;
555#endif
556 if (ret < 0) return ret;
557 rb_maygvl_fd_fix_cloexec(ret);
558 return ret;
559}
560
561#define argf_of(obj) (*(struct argf *)DATA_PTR(obj))
562#define ARGF argf_of(argf)
563#define ARGF_SET(field, value) RB_OBJ_WRITE(argf, &ARGF.field, value)
564
565#define GetWriteIO(io) rb_io_get_write_io(io)
566
567#define READ_DATA_PENDING(fptr) ((fptr)->rbuf.len)
568#define READ_DATA_PENDING_COUNT(fptr) ((fptr)->rbuf.len)
569#define READ_DATA_PENDING_PTR(fptr) ((fptr)->rbuf.ptr+(fptr)->rbuf.off)
570#define READ_DATA_BUFFERED(fptr) READ_DATA_PENDING(fptr)
571
572#define READ_CHAR_PENDING(fptr) ((fptr)->cbuf.len)
573#define READ_CHAR_PENDING_COUNT(fptr) ((fptr)->cbuf.len)
574#define READ_CHAR_PENDING_PTR(fptr) ((fptr)->cbuf.ptr+(fptr)->cbuf.off)
575
576#if defined(_WIN32)
577#define WAIT_FD_IN_WIN32(fptr) \
578 (rb_w32_io_cancelable_p((fptr)->fd) ? Qnil : rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), RUBY_IO_TIMEOUT_DEFAULT))
579#else
580#define WAIT_FD_IN_WIN32(fptr)
581#endif
582
583#define READ_CHECK(fptr) do {\
584 if (!READ_DATA_PENDING(fptr)) {\
585 WAIT_FD_IN_WIN32(fptr);\
586 rb_io_check_closed(fptr);\
587 }\
588} while(0)
589
590#ifndef S_ISSOCK
591# ifdef _S_ISSOCK
592# define S_ISSOCK(m) _S_ISSOCK(m)
593# else
594# ifdef _S_IFSOCK
595# define S_ISSOCK(m) (((m) & S_IFMT) == _S_IFSOCK)
596# else
597# ifdef S_IFSOCK
598# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
599# endif
600# endif
601# endif
602#endif
603
604static int io_fflush(rb_io_t *);
605static rb_io_t *flush_before_seek(rb_io_t *fptr, bool discard_rbuf);
606static void clear_readconv(rb_io_t *fptr);
607static void clear_codeconv(rb_io_t *fptr);
608
609#define FMODE_SIGNAL_ON_EPIPE (1<<17)
610
611#define fptr_signal_on_epipe(fptr) \
612 (((fptr)->mode & FMODE_SIGNAL_ON_EPIPE) != 0)
613
614#define fptr_set_signal_on_epipe(fptr, flag) \
615 ((flag) ? \
616 (fptr)->mode |= FMODE_SIGNAL_ON_EPIPE : \
617 (fptr)->mode &= ~FMODE_SIGNAL_ON_EPIPE)
618
619extern ID ruby_static_id_signo;
620
621NORETURN(static void rb_sys_fail_on_write(rb_io_t *fptr));
622static void
623rb_sys_fail_on_write(rb_io_t *fptr)
624{
625 int e = errno;
626 VALUE errinfo = rb_syserr_new_path(e, (fptr)->pathv);
627#if defined EPIPE
628 if (fptr_signal_on_epipe(fptr) && (e == EPIPE)) {
629 const VALUE sig =
630# if defined SIGPIPE
631 INT2FIX(SIGPIPE) - INT2FIX(0) +
632# endif
633 INT2FIX(0);
634 rb_ivar_set(errinfo, ruby_static_id_signo, sig);
635 }
636#endif
637 rb_exc_raise(errinfo);
638}
639
640#define NEED_NEWLINE_DECORATOR_ON_READ(fptr) ((fptr)->mode & FMODE_TEXTMODE)
641#define NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) ((fptr)->mode & FMODE_TEXTMODE)
642#if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)
643# define RUBY_CRLF_ENVIRONMENT 1
644#else
645# define RUBY_CRLF_ENVIRONMENT 0
646#endif
647
648#if RUBY_CRLF_ENVIRONMENT
649/* Windows */
650# define DEFAULT_TEXTMODE FMODE_TEXTMODE
651# define TEXTMODE_NEWLINE_DECORATOR_ON_WRITE ECONV_CRLF_NEWLINE_DECORATOR
652/*
653 * CRLF newline is set as default newline decorator.
654 * If only CRLF newline conversion is needed, we use binary IO process
655 * with OS's text mode for IO performance improvement.
656 * If encoding conversion is needed or a user sets text mode, we use encoding
657 * conversion IO process and universal newline decorator by default.
658 */
659#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || (fptr)->encs.ecflags & ~ECONV_CRLF_NEWLINE_DECORATOR)
660#define WRITECONV_MASK ( \
661 (ECONV_DECORATOR_MASK & ~ECONV_CRLF_NEWLINE_DECORATOR)|\
662 ECONV_STATEFUL_DECORATOR_MASK|\
663 0)
664#define NEED_WRITECONV(fptr) ( \
665 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
666 ((fptr)->encs.ecflags & WRITECONV_MASK) || \
667 0)
668#define SET_BINARY_MODE(fptr) setmode((fptr)->fd, O_BINARY)
669
670#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) do {\
671 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {\
672 if (((fptr)->mode & FMODE_READABLE) &&\
673 !((fptr)->encs.ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {\
674 setmode((fptr)->fd, O_BINARY);\
675 }\
676 else {\
677 setmode((fptr)->fd, O_TEXT);\
678 }\
679 }\
680} while(0)
681
682#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) do {\
683 if ((enc2) && ((ecflags) & ECONV_DEFAULT_NEWLINE_DECORATOR)) {\
684 (ecflags) |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;\
685 }\
686} while(0)
687
688/*
689 * IO unread with taking care of removed '\r' in text mode.
690 */
691static void
692io_unread(rb_io_t *fptr, bool discard_rbuf)
693{
694 rb_off_t r, pos;
695 ssize_t read_size;
696 long i;
697 long newlines = 0;
698 long extra_max;
699 char *p;
700 char *buf;
701
702 rb_io_check_closed(fptr);
703 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX) {
704 return;
705 }
706
707 errno = 0;
708 if (!rb_w32_fd_is_text(fptr->fd)) {
709 r = lseek(fptr->fd, -fptr->rbuf.len, SEEK_CUR);
710 if (r < 0 && errno) {
711 if (errno == ESPIPE)
712 fptr->mode |= FMODE_DUPLEX;
713 if (!discard_rbuf) return;
714 }
715
716 goto end;
717 }
718
719 pos = lseek(fptr->fd, 0, SEEK_CUR);
720 if (pos < 0 && errno) {
721 if (errno == ESPIPE)
722 fptr->mode |= FMODE_DUPLEX;
723 if (!discard_rbuf) goto end;
724 }
725
726 /* add extra offset for removed '\r' in rbuf */
727 extra_max = (long)(pos - fptr->rbuf.len);
728 p = fptr->rbuf.ptr + fptr->rbuf.off;
729
730 /* if the end of rbuf is '\r', rbuf doesn't have '\r' within rbuf.len */
731 if (*(fptr->rbuf.ptr + fptr->rbuf.capa - 1) == '\r') {
732 newlines++;
733 }
734
735 for (i = 0; i < fptr->rbuf.len; i++) {
736 if (*p == '\n') newlines++;
737 if (extra_max == newlines) break;
738 p++;
739 }
740
741 buf = ALLOC_N(char, fptr->rbuf.len + newlines);
742 while (newlines >= 0) {
743 r = lseek(fptr->fd, pos - fptr->rbuf.len - newlines, SEEK_SET);
744 if (newlines == 0) break;
745 if (r < 0) {
746 newlines--;
747 continue;
748 }
749 read_size = _read(fptr->fd, buf, fptr->rbuf.len + newlines);
750 if (read_size < 0) {
751 int e = errno;
752 free(buf);
753 rb_syserr_fail_path(e, fptr->pathv);
754 }
755 if (read_size == fptr->rbuf.len) {
756 lseek(fptr->fd, r, SEEK_SET);
757 break;
758 }
759 else {
760 newlines--;
761 }
762 }
763 free(buf);
764 end:
765 fptr->rbuf.off = 0;
766 fptr->rbuf.len = 0;
767 clear_codeconv(fptr);
768 return;
769}
770
771/*
772 * We use io_seek to back cursor position when changing mode from text to binary,
773 * but stdin and pipe cannot seek back. Stdin and pipe read should use encoding
774 * conversion for working properly with mode change.
775 *
776 * Return previous translation mode.
777 */
778static inline int
779set_binary_mode_with_seek_cur(rb_io_t *fptr)
780{
781 if (!rb_w32_fd_is_text(fptr->fd)) return O_BINARY;
782
783 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX) {
784 return setmode(fptr->fd, O_BINARY);
785 }
786 flush_before_seek(fptr, false);
787 return setmode(fptr->fd, O_BINARY);
788}
789#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) set_binary_mode_with_seek_cur(fptr)
790
791#else
792/* Unix */
793# define DEFAULT_TEXTMODE 0
794#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || NEED_NEWLINE_DECORATOR_ON_READ(fptr))
795#define NEED_WRITECONV(fptr) ( \
796 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
797 NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) || \
798 ((fptr)->encs.ecflags & (ECONV_DECORATOR_MASK|ECONV_STATEFUL_DECORATOR_MASK)) || \
799 0)
800#define SET_BINARY_MODE(fptr) (void)(fptr)
801#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) (void)(fptr)
802#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) ((void)(enc2), (void)(ecflags))
803#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) (void)(fptr)
804#endif
805
806#if !defined HAVE_SHUTDOWN && !defined shutdown
807#define shutdown(a,b) 0
808#endif
809
810#if defined(_WIN32)
811#define is_socket(fd, path) rb_w32_is_socket(fd)
812#elif !defined(S_ISSOCK)
813#define is_socket(fd, path) 0
814#else
815static int
816is_socket(int fd, VALUE path)
817{
818 struct stat sbuf;
819 if (fstat(fd, &sbuf) < 0)
820 rb_sys_fail_path(path);
821 return S_ISSOCK(sbuf.st_mode);
822}
823#endif
824
825static const char closed_stream[] = "closed stream";
826
827static void
828io_fd_check_closed(int fd)
829{
830 if (fd < 0) {
831 rb_thread_check_ints(); /* check for ruby_error_stream_closed */
832 rb_raise(rb_eIOError, closed_stream);
833 }
834}
835
836void
837rb_eof_error(void)
838{
839 rb_raise(rb_eEOFError, "end of file reached");
840}
841
842VALUE
844{
845 rb_check_frozen(io);
846 return io;
847}
848
849void
851{
852 if (!fptr) {
853 rb_raise(rb_eIOError, "uninitialized stream");
854 }
855}
856
857void
859{
861 io_fd_check_closed(fptr->fd);
862}
863
864static rb_io_t *
865rb_io_get_fptr(VALUE io)
866{
867 rb_io_t *fptr = RFILE(io)->fptr;
869 return fptr;
870}
871
872VALUE
874{
875 return rb_convert_type_with_id(io, T_FILE, "IO", idTo_io);
876}
877
878VALUE
880{
881 return rb_check_convert_type_with_id(io, T_FILE, "IO", idTo_io);
882}
883
884VALUE
886{
887 VALUE write_io;
888 write_io = rb_io_get_fptr(io)->tied_io_for_writing;
889 if (write_io) {
890 return write_io;
891 }
892 return io;
893}
894
895VALUE
897{
898 VALUE write_io;
899 rb_io_t *fptr = rb_io_get_fptr(io);
900 if (!RTEST(w)) {
901 w = 0;
902 }
903 else {
904 GetWriteIO(w);
905 }
906 write_io = fptr->tied_io_for_writing;
907 fptr->tied_io_for_writing = w;
908 return write_io ? write_io : Qnil;
909}
910
911/*
912 * call-seq:
913 * timeout -> duration or nil
914 *
915 * Get the internal timeout duration or nil if it was not set.
916 *
917 */
918VALUE
920{
921 rb_io_t *fptr = rb_io_get_fptr(self);
922
923 return fptr->timeout;
924}
925
926/*
927 * call-seq:
928 * timeout = duration -> duration
929 * timeout = nil -> nil
930 *
931 * Sets the internal timeout to the specified duration or nil. The timeout
932 * applies to all blocking operations where possible.
933 *
934 * When the operation performs longer than the timeout set, IO::TimeoutError
935 * is raised.
936 *
937 * This affects the following methods (but is not limited to): #gets, #puts,
938 * #read, #write, #wait_readable and #wait_writable. This also affects
939 * blocking socket operations like Socket#accept and Socket#connect.
940 *
941 * Some operations like File#open and IO#close are not affected by the
942 * timeout. A timeout during a write operation may leave the IO in an
943 * inconsistent state, e.g. data was partially written. Generally speaking, a
944 * timeout is a last ditch effort to prevent an application from hanging on
945 * slow I/O operations, such as those that occur during a slowloris attack.
946 */
947VALUE
949{
950 // Validate it:
951 if (RTEST(timeout)) {
952 rb_time_interval(timeout);
953 }
954
955 rb_io_t *fptr = rb_io_get_fptr(self);
956
957 RB_OBJ_WRITE(self, &fptr->timeout, timeout);
958
959 return self;
960}
961
962/*
963 * call-seq:
964 * IO.try_convert(object) -> new_io or nil
965 *
966 * Attempts to convert +object+ into an \IO object via method +to_io+;
967 * returns the new \IO object if successful, or +nil+ otherwise:
968 *
969 * IO.try_convert(STDOUT) # => #<IO:<STDOUT>>
970 * IO.try_convert(ARGF) # => #<IO:<STDIN>>
971 * IO.try_convert('STDOUT') # => nil
972 *
973 */
974static VALUE
975rb_io_s_try_convert(VALUE dummy, VALUE io)
976{
977 return rb_io_check_io(io);
978}
979
980#if !RUBY_CRLF_ENVIRONMENT
981static void
982io_unread(rb_io_t *fptr, bool discard_rbuf)
983{
984 rb_off_t r;
985 rb_io_check_closed(fptr);
986 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX)
987 return;
988 /* xxx: target position may be negative if buffer is filled by ungetc */
989 errno = 0;
990 r = lseek(fptr->fd, -fptr->rbuf.len, SEEK_CUR);
991 if (r < 0 && errno) {
992 if (errno == ESPIPE)
993 fptr->mode |= FMODE_DUPLEX;
994 if (!discard_rbuf) return;
995 }
996 fptr->rbuf.off = 0;
997 fptr->rbuf.len = 0;
998 clear_codeconv(fptr);
999 return;
1000}
1001#endif
1002
1003static rb_encoding *io_input_encoding(rb_io_t *fptr);
1004
1005static void
1006io_ungetbyte(VALUE str, rb_io_t *fptr)
1007{
1008 long len = RSTRING_LEN(str);
1009
1010 if (fptr->rbuf.ptr == NULL) {
1011 const int min_capa = IO_RBUF_CAPA_FOR(fptr);
1012 fptr->rbuf.off = 0;
1013 fptr->rbuf.len = 0;
1014#if SIZEOF_LONG > SIZEOF_INT
1015 if (len > INT_MAX)
1016 rb_raise(rb_eIOError, "ungetbyte failed");
1017#endif
1018 if (len > min_capa)
1019 fptr->rbuf.capa = (int)len;
1020 else
1021 fptr->rbuf.capa = min_capa;
1022 fptr->rbuf.ptr = ALLOC_N(char, fptr->rbuf.capa);
1023 }
1024 if (fptr->rbuf.capa < len + fptr->rbuf.len) {
1025 rb_raise(rb_eIOError, "ungetbyte failed");
1026 }
1027 if (fptr->rbuf.off < len) {
1028 MEMMOVE(fptr->rbuf.ptr+fptr->rbuf.capa-fptr->rbuf.len,
1029 fptr->rbuf.ptr+fptr->rbuf.off,
1030 char, fptr->rbuf.len);
1031 fptr->rbuf.off = fptr->rbuf.capa-fptr->rbuf.len;
1032 }
1033 fptr->rbuf.off-=(int)len;
1034 fptr->rbuf.len+=(int)len;
1035 MEMMOVE(fptr->rbuf.ptr+fptr->rbuf.off, RSTRING_PTR(str), char, len);
1036}
1037
1038static void
1039io_restore_read_buffer(VALUE str, rb_io_t *fptr)
1040{
1041 long len = RSTRING_LEN(str);
1042
1043 if (len > INT_MAX - fptr->rbuf.len) {
1044 rb_raise(rb_eIOError, "read buffer too large");
1045 }
1046 if (fptr->rbuf.ptr == NULL || fptr->rbuf.capa >= len + fptr->rbuf.len) {
1047 io_ungetbyte(str, fptr);
1048 }
1049 else {
1050 int pending = fptr->rbuf.len;
1051 int capa = (int)len + pending;
1052 char *ptr = ALLOC_N(char, capa);
1053
1054 MEMMOVE(ptr, RSTRING_PTR(str), char, len);
1055 MEMMOVE(ptr + len, fptr->rbuf.ptr + fptr->rbuf.off, char, pending);
1056 ruby_xfree(fptr->rbuf.ptr);
1057 fptr->rbuf.ptr = ptr;
1058 fptr->rbuf.off = 0;
1059 fptr->rbuf.len = capa;
1060 fptr->rbuf.capa = capa;
1061 }
1062}
1063
1064static rb_io_t *
1065flush_before_seek(rb_io_t *fptr, bool discard_rbuf)
1066{
1067 if (io_fflush(fptr) < 0)
1068 rb_sys_fail_on_write(fptr);
1069 io_unread(fptr, discard_rbuf);
1070 errno = 0;
1071 return fptr;
1072}
1073
1074#define io_seek(fptr, ofs, whence) (errno = 0, lseek(flush_before_seek(fptr, true)->fd, (ofs), (whence)))
1075#define io_tell(fptr) lseek(flush_before_seek(fptr, false)->fd, 0, SEEK_CUR)
1076
1077#ifndef SEEK_CUR
1078# define SEEK_SET 0
1079# define SEEK_CUR 1
1080# define SEEK_END 2
1081#endif
1082
1083void
1085{
1086 rb_io_check_closed(fptr);
1087 if (!(fptr->mode & FMODE_READABLE)) {
1088 rb_raise(rb_eIOError, "not opened for reading");
1089 }
1090 if (fptr->wbuf.len) {
1091 if (io_fflush(fptr) < 0)
1092 rb_sys_fail_on_write(fptr);
1093 }
1094 if (fptr->tied_io_for_writing) {
1095 rb_io_t *wfptr;
1096 GetOpenFile(fptr->tied_io_for_writing, wfptr);
1097 if (io_fflush(wfptr) < 0)
1098 rb_sys_fail_on_write(wfptr);
1099 }
1100}
1101
1102void
1104{
1106 if (READ_CHAR_PENDING(fptr)) {
1107 rb_raise(rb_eIOError, "byte oriented read for character buffered IO");
1108 }
1109}
1110
1111void
1116
1117static rb_encoding*
1118io_read_encoding(rb_io_t *fptr)
1119{
1120 if (fptr->encs.enc) {
1121 return fptr->encs.enc;
1122 }
1123 return rb_default_external_encoding();
1124}
1125
1126static rb_encoding*
1127io_input_encoding(rb_io_t *fptr)
1128{
1129 if (fptr->encs.enc2) {
1130 return fptr->encs.enc2;
1131 }
1132 return io_read_encoding(fptr);
1133}
1134
1135void
1137{
1138 rb_io_check_closed(fptr);
1139 if (!(fptr->mode & FMODE_WRITABLE)) {
1140 rb_raise(rb_eIOError, "not opened for writing");
1141 }
1142 if (fptr->rbuf.len) {
1143 io_unread(fptr, true);
1144 }
1145}
1146
1147int
1148rb_io_read_pending(rb_io_t *fptr)
1149{
1150 /* This function is used for bytes and chars. Confusing. */
1151 if (READ_CHAR_PENDING(fptr))
1152 return 1; /* should raise? */
1153 return READ_DATA_PENDING(fptr);
1154}
1155
1156void
1158{
1159 if (!READ_DATA_PENDING(fptr)) {
1160 rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), RUBY_IO_TIMEOUT_DEFAULT);
1161 }
1162 return;
1163}
1164
1165int
1166rb_gc_for_fd(int err)
1167{
1168 if (err == EMFILE || err == ENFILE || err == ENOMEM) {
1169 rb_gc();
1170 return 1;
1171 }
1172 return 0;
1173}
1174
1175/* try `expr` upto twice while it returns false and `errno`
1176 * is to GC. Each `errno`s are available as `first_errno` and
1177 * `retried_errno` respectively */
1178#define TRY_WITH_GC(expr) \
1179 for (int first_errno, retried_errno = 0, retried = 0; \
1180 (!retried && \
1181 !(expr) && \
1182 (!rb_gc_for_fd(first_errno = errno) || !(expr)) && \
1183 (retried_errno = errno, 1)); \
1184 (void)retried_errno, retried = 1)
1185
1186static int
1187ruby_dup(int orig)
1188{
1189 int fd = -1;
1190
1191 TRY_WITH_GC((fd = rb_cloexec_dup(orig)) >= 0) {
1192 rb_syserr_fail(first_errno, 0);
1193 }
1194 rb_update_max_fd(fd);
1195 return fd;
1196}
1197
1198static VALUE
1199io_alloc(VALUE klass)
1200{
1201 UNPROTECTED_NEWOBJ_OF(io, struct RFile, klass, T_FILE, sizeof(struct RFile));
1202
1203 io->fptr = 0;
1204
1205 return (VALUE)io;
1206}
1207
1208#ifndef S_ISREG
1209# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
1210#endif
1211
1213 VALUE th;
1214 rb_io_t *fptr;
1215 int nonblock;
1216 int fd;
1217
1218 void *buf;
1219 size_t capa;
1220 struct timeval *timeout;
1221};
1222
1224 VALUE th;
1225 rb_io_t *fptr;
1226 int nonblock;
1227 int fd;
1228
1229 const void *buf;
1230 size_t capa;
1231 struct timeval *timeout;
1232};
1233
1234#ifdef HAVE_WRITEV
1235struct io_internal_writev_struct {
1236 VALUE th;
1237 rb_io_t *fptr;
1238 int nonblock;
1239 int fd;
1240
1241 int iovcnt;
1242 const struct iovec *iov;
1243 struct timeval *timeout;
1244};
1245#endif
1246
1247static int nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout);
1248
1254static inline int
1255io_internal_wait(VALUE thread, rb_io_t *fptr, int error, int events, struct timeval *timeout)
1256{
1257 if (!timeout && rb_thread_mn_schedulable(thread)) {
1258 RUBY_ASSERT(errno == EWOULDBLOCK || errno == EAGAIN);
1259 return -1;
1260 }
1261
1262 int ready = nogvl_wait_for(thread, fptr, events, timeout);
1263
1264 if (ready > 0) {
1265 return ready;
1266 }
1267 else if (ready == 0) {
1268 errno = ETIMEDOUT;
1269 return -1;
1270 }
1271
1272 // If there was an error BEFORE we started waiting, return it:
1273 if (error) {
1274 errno = error;
1275 return -1;
1276 }
1277 else {
1278 // Otherwise, whatever error was generated by `nogvl_wait_for` is the one we want:
1279 return ready;
1280 }
1281}
1282
1283static VALUE
1284internal_read_func(void *ptr)
1285{
1286 struct io_internal_read_struct *iis = ptr;
1287 ssize_t result;
1288
1289 if (iis->timeout && !iis->nonblock) {
1290 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_IN, iis->timeout) == -1) {
1291 return -1;
1292 }
1293 }
1294
1295 retry:
1296 result = read(iis->fd, iis->buf, iis->capa);
1297
1298 if (result < 0 && !iis->nonblock) {
1299 if (io_again_p(errno)) {
1300 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_IN, iis->timeout) == -1) {
1301 return -1;
1302 }
1303 else {
1304 goto retry;
1305 }
1306 }
1307 }
1308
1309 return result;
1310}
1311
1312#if defined __APPLE__
1313# define do_write_retry(code) do {result = code;} while (result == -1 && errno == EPROTOTYPE)
1314#else
1315# define do_write_retry(code) result = code
1316#endif
1317
1318static VALUE
1319internal_write_func(void *ptr)
1320{
1321 struct io_internal_write_struct *iis = ptr;
1322 ssize_t result;
1323
1324 if (iis->timeout && !iis->nonblock) {
1325 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1326 return -1;
1327 }
1328 }
1329
1330 retry:
1331 do_write_retry(write(iis->fd, iis->buf, iis->capa));
1332
1333 if (result < 0 && !iis->nonblock) {
1334 int e = errno;
1335 if (io_again_p(e)) {
1336 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1337 return -1;
1338 }
1339 else {
1340 goto retry;
1341 }
1342 }
1343 }
1344
1345 return result;
1346}
1347
1348#ifdef HAVE_WRITEV
1349static VALUE
1350internal_writev_func(void *ptr)
1351{
1352 struct io_internal_writev_struct *iis = ptr;
1353 ssize_t result;
1354
1355 if (iis->timeout && !iis->nonblock) {
1356 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1357 return -1;
1358 }
1359 }
1360
1361 retry:
1362 do_write_retry(writev(iis->fd, iis->iov, iis->iovcnt));
1363
1364 if (result < 0 && !iis->nonblock) {
1365 if (io_again_p(errno)) {
1366 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1367 return -1;
1368 }
1369 else {
1370 goto retry;
1371 }
1372 }
1373 }
1374
1375 return result;
1376}
1377#endif
1378
1379static ssize_t
1380rb_io_read_memory(rb_io_t *fptr, void *buf, size_t count)
1381{
1382 rb_thread_t *th = GET_THREAD();
1384 if (scheduler != Qnil) {
1385 VALUE result = rb_fiber_scheduler_io_read_memory(scheduler, fptr->self, buf, count);
1386
1387 if (!UNDEF_P(result)) {
1389 }
1390 }
1391
1392 struct io_internal_read_struct iis = {
1393 .th = th->self,
1394 .fptr = fptr,
1395 .nonblock = 0,
1396 .fd = fptr->fd,
1397
1398 .buf = buf,
1399 .capa = count,
1400 .timeout = NULL,
1401 };
1402
1403 struct timeval timeout_storage;
1404
1405 if (fptr->timeout != Qnil) {
1406 timeout_storage = rb_time_interval(fptr->timeout);
1407 iis.timeout = &timeout_storage;
1408 }
1409
1410 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_read_func, &iis, RUBY_IO_READABLE);
1411}
1412
1413static ssize_t
1414rb_io_write_memory(rb_io_t *fptr, const void *buf, size_t count)
1415{
1416 rb_thread_t *th = GET_THREAD();
1418 if (scheduler != Qnil) {
1419 VALUE result = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, buf, count);
1420
1421 if (!UNDEF_P(result)) {
1423 }
1424 }
1425
1426 struct io_internal_write_struct iis = {
1427 .th = th->self,
1428 .fptr = fptr,
1429 .nonblock = 0,
1430 .fd = fptr->fd,
1431
1432 .buf = buf,
1433 .capa = count,
1434 .timeout = NULL
1435 };
1436
1437 struct timeval timeout_storage;
1438
1439 if (fptr->timeout != Qnil) {
1440 timeout_storage = rb_time_interval(fptr->timeout);
1441 iis.timeout = &timeout_storage;
1442 }
1443
1444 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_write_func, &iis, RUBY_IO_WRITABLE);
1445}
1446
1447#ifdef HAVE_WRITEV
1448static ssize_t
1449rb_writev_internal(rb_io_t *fptr, const struct iovec *iov, int iovcnt)
1450{
1451 if (!iovcnt) return 0;
1452
1453 rb_thread_t *th = GET_THREAD();
1454
1456 if (scheduler != Qnil) {
1457 // This path assumes at least one `iov`:
1458 VALUE result = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, iov[0].iov_base, iov[0].iov_len);
1459
1460 if (!UNDEF_P(result)) {
1462 }
1463 }
1464
1465 struct io_internal_writev_struct iis = {
1466 .th = th->self,
1467 .fptr = fptr,
1468 .nonblock = 0,
1469 .fd = fptr->fd,
1470
1471 .iov = iov,
1472 .iovcnt = iovcnt,
1473 .timeout = NULL
1474 };
1475
1476 struct timeval timeout_storage;
1477
1478 if (fptr->timeout != Qnil) {
1479 timeout_storage = rb_time_interval(fptr->timeout);
1480 iis.timeout = &timeout_storage;
1481 }
1482
1483 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_writev_func, &iis, RUBY_IO_WRITABLE);
1484}
1485#endif
1486
1487static VALUE
1488io_flush_buffer_sync(void *arg)
1489{
1490 rb_io_t *fptr = arg;
1491 long l = fptr->wbuf.len;
1492 ssize_t r = write(fptr->fd, fptr->wbuf.ptr+fptr->wbuf.off, (size_t)l);
1493
1494 if (fptr->wbuf.len <= r) {
1495 fptr->wbuf.off = 0;
1496 fptr->wbuf.len = 0;
1497 return 0;
1498 }
1499
1500 if (0 <= r) {
1501 fptr->wbuf.off += (int)r;
1502 fptr->wbuf.len -= (int)r;
1503 errno = EAGAIN;
1504 }
1505
1506 return (VALUE)-1;
1507}
1508
1509static inline VALUE
1510io_flush_buffer_fiber_scheduler(VALUE scheduler, rb_io_t *fptr)
1511{
1512 VALUE ret = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, fptr->wbuf.ptr+fptr->wbuf.off, fptr->wbuf.len);
1513 if (!UNDEF_P(ret)) {
1514 ssize_t result = rb_fiber_scheduler_io_result_apply(ret);
1515 if (result > 0) {
1516 fptr->wbuf.off += result;
1517 fptr->wbuf.len -= result;
1518 }
1519 return result >= 0 ? (VALUE)0 : (VALUE)-1;
1520 }
1521 return ret;
1522}
1523
1524static VALUE
1525io_flush_buffer_async(VALUE arg)
1526{
1527 rb_io_t *fptr = (rb_io_t *)arg;
1528
1529 VALUE scheduler = rb_fiber_scheduler_current();
1530 if (scheduler != Qnil) {
1531 VALUE result = io_flush_buffer_fiber_scheduler(scheduler, fptr);
1532 if (!UNDEF_P(result)) {
1533 return result;
1534 }
1535 }
1536
1537 return rb_io_blocking_region_wait(fptr, io_flush_buffer_sync, fptr, RUBY_IO_WRITABLE);
1538}
1539
1540static inline int
1541io_flush_buffer(rb_io_t *fptr)
1542{
1543 if (!NIL_P(fptr->write_lock) && rb_mutex_owned_p(fptr->write_lock)) {
1544 return (int)io_flush_buffer_async((VALUE)fptr);
1545 }
1546 else {
1547 return (int)rb_mutex_synchronize(fptr->write_lock, io_flush_buffer_async, (VALUE)fptr);
1548 }
1549}
1550
1551static int
1552io_fflush(rb_io_t *fptr)
1553{
1554 rb_io_check_closed(fptr);
1555
1556 if (fptr->wbuf.len == 0)
1557 return 0;
1558
1559 while (fptr->wbuf.len > 0 && io_flush_buffer(fptr) != 0) {
1560 if (!rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT))
1561 return -1;
1562
1563 rb_io_check_closed(fptr);
1564 }
1565
1566 return 0;
1567}
1568
1569VALUE
1570rb_io_wait(VALUE io, VALUE events, VALUE timeout)
1571{
1572 rb_thread_t *th = GET_THREAD();
1574
1575 if (scheduler != Qnil) {
1576 return rb_fiber_scheduler_io_wait(scheduler, io, events, timeout);
1577 }
1578
1579 rb_io_t * fptr = NULL;
1580 RB_IO_POINTER(io, fptr);
1581
1582 struct timeval tv_storage;
1583 struct timeval *tv = NULL;
1584
1585 if (NIL_OR_UNDEF_P(timeout)) {
1586 timeout = fptr->timeout;
1587 }
1588
1589 if (timeout != Qnil) {
1590 tv_storage = rb_time_interval(timeout);
1591 tv = &tv_storage;
1592 }
1593
1594 int ready = rb_thread_io_wait(th, fptr, RB_NUM2INT(events), tv);
1595
1596 if (ready < 0) {
1597 rb_sys_fail(0);
1598 }
1599
1600 // Not sure if this is necessary:
1601 rb_io_check_closed(fptr);
1602
1603 if (ready) {
1604 return RB_INT2NUM(ready);
1605 }
1606 else {
1607 return Qfalse;
1608 }
1609}
1610
1611static VALUE
1612io_from_fd(int fd)
1613{
1614 return prep_io(fd, FMODE_EXTERNAL, rb_cIO, NULL);
1615}
1616
1617static int
1618io_wait_for_single_fd(int fd, int events, struct timeval *timeout, rb_thread_t *th, VALUE scheduler)
1619{
1620 if (scheduler != Qnil) {
1621 return RTEST(
1622 rb_fiber_scheduler_io_wait(scheduler, io_from_fd(fd), RB_INT2NUM(events), rb_fiber_scheduler_make_timeout(timeout))
1623 );
1624 }
1625
1626 return rb_thread_wait_for_single_fd(th, fd, events, timeout);
1627}
1628
1629int
1631{
1632 io_fd_check_closed(f);
1633
1634 rb_thread_t *th = GET_THREAD();
1636
1637 switch (errno) {
1638 case EINTR:
1639#if defined(ERESTART)
1640 case ERESTART:
1641#endif
1643 return TRUE;
1644
1645 case EAGAIN:
1646#if EWOULDBLOCK != EAGAIN
1647 case EWOULDBLOCK:
1648#endif
1649 if (scheduler != Qnil) {
1650 return RTEST(
1651 rb_fiber_scheduler_io_wait_readable(scheduler, io_from_fd(f))
1652 );
1653 }
1654 else {
1655 io_wait_for_single_fd(f, RUBY_IO_READABLE, NULL, th, scheduler);
1656 }
1657 return TRUE;
1658
1659 default:
1660 return FALSE;
1661 }
1662}
1663
1664int
1666{
1667 io_fd_check_closed(f);
1668
1669 rb_thread_t *th = GET_THREAD();
1671
1672 switch (errno) {
1673 case EINTR:
1674#if defined(ERESTART)
1675 case ERESTART:
1676#endif
1677 /*
1678 * In old Linux, several special files under /proc and /sys don't handle
1679 * select properly. Thus we need avoid to call if don't use O_NONBLOCK.
1680 * Otherwise, we face nasty hang up. Sigh.
1681 * e.g. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1682 * https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1683 * In EINTR case, we only need to call RUBY_VM_CHECK_INTS_BLOCKING().
1684 * Then rb_thread_check_ints() is enough.
1685 */
1687 return TRUE;
1688
1689 case EAGAIN:
1690#if EWOULDBLOCK != EAGAIN
1691 case EWOULDBLOCK:
1692#endif
1693 if (scheduler != Qnil) {
1694 return RTEST(
1695 rb_fiber_scheduler_io_wait_writable(scheduler, io_from_fd(f))
1696 );
1697 }
1698 else {
1699 io_wait_for_single_fd(f, RUBY_IO_WRITABLE, NULL, th, scheduler);
1700 }
1701 return TRUE;
1702
1703 default:
1704 return FALSE;
1705 }
1706}
1707
1708int
1709rb_wait_for_single_fd(int fd, int events, struct timeval *timeout)
1710{
1711 rb_thread_t *th = GET_THREAD();
1713 return io_wait_for_single_fd(fd, events, timeout, th, scheduler);
1714}
1715
1716int
1718{
1719 return rb_wait_for_single_fd(fd, RUBY_IO_READABLE, NULL);
1720}
1721
1722int
1724{
1725 return rb_wait_for_single_fd(fd, RUBY_IO_WRITABLE, NULL);
1726}
1727
1728VALUE
1729rb_io_maybe_wait(int error, VALUE io, VALUE events, VALUE timeout)
1730{
1731 // fptr->fd can be set to -1 at any time by another thread when the GVL is
1732 // released. Many code, e.g. `io_bufread` didn't check this correctly and
1733 // instead relies on `read(-1) -> -1` which causes this code path. We then
1734 // check here whether the IO was in fact closed. Probably it's better to
1735 // check that `fptr->fd != -1` before using it in syscall.
1736 rb_io_check_closed(RFILE(io)->fptr);
1737
1738 switch (error) {
1739 // In old Linux, several special files under /proc and /sys don't handle
1740 // select properly. Thus we need avoid to call if don't use O_NONBLOCK.
1741 // Otherwise, we face nasty hang up. Sigh.
1742 // e.g. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1743 // https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1744 // In EINTR case, we only need to call RUBY_VM_CHECK_INTS_BLOCKING().
1745 // Then rb_thread_check_ints() is enough.
1746 case EINTR:
1747#if defined(ERESTART)
1748 case ERESTART:
1749#endif
1750 // We might have pending interrupts since the previous syscall was interrupted:
1752
1753 // The operation was interrupted, so retry it immediately:
1754 return events;
1755
1756 case EAGAIN:
1757#if EWOULDBLOCK != EAGAIN
1758 case EWOULDBLOCK:
1759#endif
1760 // The operation would block, so wait for the specified events:
1761 return rb_io_wait(io, events, timeout);
1762
1763 default:
1764 // Non-specific error, no event is ready:
1765 return Qnil;
1766 }
1767}
1768
1769int
1771{
1772 VALUE result = rb_io_maybe_wait(error, io, RB_INT2NUM(RUBY_IO_READABLE), timeout);
1773
1774 if (RTEST(result)) {
1775 return RB_NUM2INT(result);
1776 }
1777 else if (result == RUBY_Qfalse) {
1778 rb_raise(rb_eIOTimeoutError, "Timed out waiting for IO to become readable!");
1779 }
1780
1781 return 0;
1782}
1783
1784int
1786{
1787 VALUE result = rb_io_maybe_wait(error, io, RB_INT2NUM(RUBY_IO_WRITABLE), timeout);
1788
1789 if (RTEST(result)) {
1790 return RB_NUM2INT(result);
1791 }
1792 else if (result == RUBY_Qfalse) {
1793 rb_raise(rb_eIOTimeoutError, "Timed out waiting for IO to become writable!");
1794 }
1795
1796 return 0;
1797}
1798
1799static void
1800make_writeconv(rb_io_t *fptr)
1801{
1802 if (!fptr->writeconv_initialized) {
1803 const char *senc, *denc;
1804 rb_encoding *enc;
1805 int ecflags;
1806 VALUE ecopts;
1807
1808 fptr->writeconv_initialized = 1;
1809
1810 ecflags = fptr->encs.ecflags & ~ECONV_NEWLINE_DECORATOR_READ_MASK;
1811 ecopts = fptr->encs.ecopts;
1812
1813 if (!fptr->encs.enc || (rb_is_ascii8bit_enc(fptr->encs.enc) && !fptr->encs.enc2)) {
1814 /* no encoding conversion */
1815 fptr->writeconv_pre_ecflags = 0;
1816 fptr->writeconv_pre_ecopts = Qnil;
1817 fptr->writeconv = rb_econv_open_opts("", "", ecflags, ecopts);
1818 if (!fptr->writeconv)
1819 rb_exc_raise(rb_econv_open_exc("", "", ecflags));
1821 }
1822 else {
1823 enc = fptr->encs.enc2 ? fptr->encs.enc2 : fptr->encs.enc;
1824 senc = rb_econv_asciicompat_encoding(rb_enc_name(enc));
1825 if (!senc && !(fptr->encs.ecflags & ECONV_STATEFUL_DECORATOR_MASK)) {
1826 /* single conversion */
1827 fptr->writeconv_pre_ecflags = ecflags;
1828 fptr->writeconv_pre_ecopts = ecopts;
1829 fptr->writeconv = NULL;
1831 }
1832 else {
1833 /* double conversion */
1834 fptr->writeconv_pre_ecflags = ecflags & ~ECONV_STATEFUL_DECORATOR_MASK;
1835 fptr->writeconv_pre_ecopts = ecopts;
1836 if (senc) {
1837 denc = rb_enc_name(enc);
1838 fptr->writeconv_asciicompat = rb_str_new2(senc);
1839 }
1840 else {
1841 senc = denc = "";
1842 fptr->writeconv_asciicompat = rb_str_new2(rb_enc_name(enc));
1843 }
1845 ecopts = fptr->encs.ecopts;
1846 fptr->writeconv = rb_econv_open_opts(senc, denc, ecflags, ecopts);
1847 if (!fptr->writeconv)
1848 rb_exc_raise(rb_econv_open_exc(senc, denc, ecflags));
1849 }
1850 }
1851 }
1852}
1853
1854/* writing functions */
1856 rb_io_t *fptr;
1857 const char *ptr;
1858 long length;
1859};
1860
1862 VALUE io;
1863 VALUE str;
1864 int nosync;
1865};
1866
1867#ifdef HAVE_WRITEV
1868static ssize_t
1869io_binwrite_string_internal(rb_io_t *fptr, const char *ptr, long length)
1870{
1871 if (fptr->wbuf.len) {
1872 struct iovec iov[2];
1873
1874 iov[0].iov_base = fptr->wbuf.ptr+fptr->wbuf.off;
1875 iov[0].iov_len = fptr->wbuf.len;
1876 iov[1].iov_base = (void*)ptr;
1877 iov[1].iov_len = length;
1878
1879 ssize_t result = rb_writev_internal(fptr, iov, 2);
1880
1881 if (result < 0)
1882 return result;
1883
1884 if (result >= fptr->wbuf.len) {
1885 // We wrote more than the internal buffer:
1886 result -= fptr->wbuf.len;
1887 fptr->wbuf.off = 0;
1888 fptr->wbuf.len = 0;
1889 }
1890 else {
1891 // We only wrote less data than the internal buffer:
1892 fptr->wbuf.off += (int)result;
1893 fptr->wbuf.len -= (int)result;
1894
1895 result = 0;
1896 }
1897
1898 return result;
1899 }
1900 else {
1901 return rb_io_write_memory(fptr, ptr, length);
1902 }
1903}
1904#else
1905static ssize_t
1906io_binwrite_string_internal(rb_io_t *fptr, const char *ptr, long length)
1907{
1908 long remaining = length;
1909
1910 if (fptr->wbuf.len) {
1911 if (fptr->wbuf.len+length <= fptr->wbuf.capa) {
1912 if (fptr->wbuf.capa < fptr->wbuf.off+fptr->wbuf.len+length) {
1913 MEMMOVE(fptr->wbuf.ptr, fptr->wbuf.ptr+fptr->wbuf.off, char, fptr->wbuf.len);
1914 fptr->wbuf.off = 0;
1915 }
1916
1917 MEMMOVE(fptr->wbuf.ptr+fptr->wbuf.off+fptr->wbuf.len, ptr, char, length);
1918 fptr->wbuf.len += (int)length;
1919
1920 // We copied the entire incoming data to the internal buffer:
1921 remaining = 0;
1922 }
1923
1924 // Flush the internal buffer:
1925 if (io_fflush(fptr) < 0) {
1926 return -1;
1927 }
1928
1929 // If all the data was buffered, we are done:
1930 if (remaining == 0) {
1931 return length;
1932 }
1933 }
1934
1935 // Otherwise, we should write the data directly:
1936 return rb_io_write_memory(fptr, ptr, length);
1937}
1938#endif
1939
1940static VALUE
1941io_binwrite_string(VALUE arg)
1942{
1943 struct binwrite_arg *p = (struct binwrite_arg *)arg;
1944
1945 const char *ptr = p->ptr;
1946 size_t remaining = p->length;
1947
1948 while (remaining) {
1949 // Write as much as possible:
1950 ssize_t result = io_binwrite_string_internal(p->fptr, ptr, remaining);
1951
1952 if (result == 0) {
1953 // If only the internal buffer is written, result will be zero [bytes of given data written]. This means we
1954 // should try again immediately.
1955 }
1956 else if (result > 0) {
1957 if ((size_t)result == remaining) break;
1958 ptr += result;
1959 remaining -= result;
1960 }
1961 // Wait for it to become writable:
1962 else if (rb_io_maybe_wait_writable(errno, p->fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
1963 rb_io_check_closed(p->fptr);
1964 }
1965 else {
1966 // The error was unrelated to waiting for it to become writable, so we fail:
1967 return -1;
1968 }
1969 }
1970
1971 return p->length;
1972}
1973
1974inline static void
1975io_allocate_write_buffer(rb_io_t *fptr, int sync)
1976{
1977 if (fptr->wbuf.ptr == NULL && !(sync && (fptr->mode & FMODE_SYNC))) {
1978 fptr->wbuf.off = 0;
1979 fptr->wbuf.len = 0;
1980 fptr->wbuf.capa = IO_WBUF_CAPA_MIN;
1981 fptr->wbuf.ptr = ALLOC_N(char, fptr->wbuf.capa);
1982 }
1983
1984 if (NIL_P(fptr->write_lock)) {
1985 fptr->write_lock = rb_mutex_new();
1986 rb_mutex_allow_trap(fptr->write_lock, 1);
1987 }
1988}
1989
1990static inline int
1991io_binwrite_requires_flush_write(rb_io_t *fptr, long len, int nosync)
1992{
1993 // If the requested operation was synchronous and the output mode is synchronous or a TTY:
1994 if (!nosync && (fptr->mode & (FMODE_SYNC|FMODE_TTY)))
1995 return 1;
1996
1997 // If the amount of data we want to write exceeds the internal buffer:
1998 if (fptr->wbuf.ptr && fptr->wbuf.capa <= fptr->wbuf.len + len)
1999 return 1;
2000
2001 // Otherwise, we can append to the internal buffer:
2002 return 0;
2003}
2004
2005static long
2006io_binwrite(const char *ptr, long len, rb_io_t *fptr, int nosync)
2007{
2008 if (len <= 0) return len;
2009
2010 // Don't write anything if current thread has a pending interrupt:
2012
2013 io_allocate_write_buffer(fptr, !nosync);
2014
2015 if (io_binwrite_requires_flush_write(fptr, len, nosync)) {
2016 struct binwrite_arg arg;
2017
2018 arg.fptr = fptr;
2019 arg.ptr = ptr;
2020 arg.length = len;
2021
2022 if (!NIL_P(fptr->write_lock)) {
2023 return rb_mutex_synchronize(fptr->write_lock, io_binwrite_string, (VALUE)&arg);
2024 }
2025 else {
2026 return io_binwrite_string((VALUE)&arg);
2027 }
2028 }
2029 else {
2030 if (fptr->wbuf.off) {
2031 if (fptr->wbuf.len)
2032 MEMMOVE(fptr->wbuf.ptr, fptr->wbuf.ptr+fptr->wbuf.off, char, fptr->wbuf.len);
2033 fptr->wbuf.off = 0;
2034 }
2035
2036 MEMMOVE(fptr->wbuf.ptr+fptr->wbuf.off+fptr->wbuf.len, ptr, char, len);
2037 fptr->wbuf.len += (int)len;
2038
2039 return len;
2040 }
2041}
2042
2043# define MODE_BTMODE(a,b,c) ((fmode & FMODE_BINMODE) ? (b) : \
2044 (fmode & FMODE_TEXTMODE) ? (c) : (a))
2045
2046#define MODE_BTXMODE(a, b, c, d, e, f) ((fmode & FMODE_EXCL) ? \
2047 MODE_BTMODE(d, e, f) : \
2048 MODE_BTMODE(a, b, c))
2049
2050static VALUE
2051do_writeconv(VALUE str, rb_io_t *fptr, int *converted)
2052{
2053 if (NEED_WRITECONV(fptr)) {
2054 VALUE common_encoding = Qnil;
2055 SET_BINARY_MODE(fptr);
2056
2057 make_writeconv(fptr);
2058
2059 if (fptr->writeconv) {
2060#define fmode (fptr->mode)
2061 if (!NIL_P(fptr->writeconv_asciicompat))
2062 common_encoding = fptr->writeconv_asciicompat;
2063 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1) && !rb_enc_asciicompat(rb_enc_get(str))) {
2064 rb_raise(rb_eArgError, "ASCII incompatible string written for text mode IO without encoding conversion: %s",
2065 rb_enc_name(rb_enc_get(str)));
2066 }
2067#undef fmode
2068 }
2069 else {
2070 if (fptr->encs.enc2)
2071 common_encoding = rb_enc_from_encoding(fptr->encs.enc2);
2072 else if (fptr->encs.enc != rb_ascii8bit_encoding())
2073 common_encoding = rb_enc_from_encoding(fptr->encs.enc);
2074 }
2075
2076 if (!NIL_P(common_encoding)) {
2077 str = rb_str_encode(str, common_encoding,
2079 *converted = 1;
2080 }
2081
2082 if (fptr->writeconv) {
2084 *converted = 1;
2085 }
2086 }
2087#if RUBY_CRLF_ENVIRONMENT
2088#define fmode (fptr->mode)
2089 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1)) {
2090 if ((fptr->mode & FMODE_READABLE) &&
2092 setmode(fptr->fd, O_BINARY);
2093 }
2094 else {
2095 setmode(fptr->fd, O_TEXT);
2096 }
2097 if (!rb_enc_asciicompat(rb_enc_get(str))) {
2098 rb_raise(rb_eArgError, "ASCII incompatible string written for text mode IO without encoding conversion: %s",
2099 rb_enc_name(rb_enc_get(str)));
2100 }
2101 }
2102#undef fmode
2103#endif
2104 return str;
2105}
2106
2107static long
2108io_fwrite(VALUE str, rb_io_t *fptr, int nosync)
2109{
2110 int converted = 0;
2111 VALUE tmp;
2112 long n, len;
2113 const char *ptr;
2114
2115#ifdef _WIN32
2116 if (fptr->mode & FMODE_TTY) {
2117 if (rb_w32_write_console(str, fptr->fd) > 0) return RSTRING_LEN(str);
2118 }
2119#endif
2120
2121 str = do_writeconv(str, fptr, &converted);
2122 if (converted)
2123 OBJ_FREEZE(str);
2124
2125 tmp = rb_str_tmp_frozen_no_embed_acquire(str);
2126 RSTRING_GETMEM(tmp, ptr, len);
2127 n = io_binwrite(ptr, len, fptr, nosync);
2128 rb_str_tmp_frozen_release(str, tmp);
2129
2130 return n;
2131}
2132
2133ssize_t
2134rb_io_bufwrite(VALUE io, const void *buf, size_t size)
2135{
2136 rb_io_t *fptr;
2137
2138 GetOpenFile(io, fptr);
2140 return (ssize_t)io_binwrite(buf, (long)size, fptr, 0);
2141}
2142
2143static VALUE
2144io_write(VALUE io, VALUE str, int nosync)
2145{
2146 rb_io_t *fptr;
2147 long n;
2148 VALUE tmp;
2149
2150 io = GetWriteIO(io);
2151 str = rb_obj_as_string(str);
2152 tmp = rb_io_check_io(io);
2153
2154 if (NIL_P(tmp)) {
2155 /* port is not IO, call write method for it. */
2156 return rb_funcall(io, id_write, 1, str);
2157 }
2158
2159 io = tmp;
2160 if (RSTRING_LEN(str) == 0) return INT2FIX(0);
2161
2162 GetOpenFile(io, fptr);
2164
2165 n = io_fwrite(str, fptr, nosync);
2166 if (n < 0L) rb_sys_fail_on_write(fptr);
2167
2168 return LONG2FIX(n);
2169}
2170
2171#ifdef HAVE_WRITEV
2172struct binwritev_arg {
2173 rb_io_t *fptr;
2174 struct iovec *iov;
2175 int iovcnt;
2176 size_t total;
2177};
2178
2179static VALUE
2180io_binwritev_internal(VALUE arg)
2181{
2182 struct binwritev_arg *p = (struct binwritev_arg *)arg;
2183
2184 size_t remaining = p->total;
2185 size_t offset = 0;
2186
2187 rb_io_t *fptr = p->fptr;
2188 struct iovec *iov = p->iov;
2189 int iovcnt = p->iovcnt;
2190
2191 while (remaining) {
2192 long result = rb_writev_internal(fptr, iov, iovcnt);
2193
2194 if (result >= 0) {
2195 offset += result;
2196 if (fptr->wbuf.ptr && fptr->wbuf.len) {
2197 if (offset < (size_t)fptr->wbuf.len) {
2198 fptr->wbuf.off += result;
2199 fptr->wbuf.len -= result;
2200 }
2201 else {
2202 offset -= (size_t)fptr->wbuf.len;
2203 fptr->wbuf.off = 0;
2204 fptr->wbuf.len = 0;
2205 }
2206 }
2207
2208 if (offset == p->total) {
2209 return p->total;
2210 }
2211
2212 while (result >= (ssize_t)iov->iov_len) {
2213 /* iovcnt > 0 */
2214 result -= iov->iov_len;
2215 iov->iov_len = 0;
2216 iov++;
2217
2218 if (!--iovcnt) {
2219 // I don't believe this code path can ever occur.
2220 return offset;
2221 }
2222 }
2223
2224 iov->iov_base = (char *)iov->iov_base + result;
2225 iov->iov_len -= result;
2226 }
2227 else if (rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
2228 rb_io_check_closed(fptr);
2229 }
2230 else {
2231 return -1;
2232 }
2233 }
2234
2235 return offset;
2236}
2237
2238static long
2239io_binwritev(struct iovec *iov, int iovcnt, rb_io_t *fptr)
2240{
2241 // Don't write anything if current thread has a pending interrupt:
2243
2244 if (iovcnt == 0) return 0;
2245
2246 size_t total = 0;
2247 for (int i = 1; i < iovcnt; i++) total += iov[i].iov_len;
2248
2249 io_allocate_write_buffer(fptr, 1);
2250
2251 if (fptr->wbuf.ptr && fptr->wbuf.len) {
2252 // The end of the buffered data:
2253 size_t offset = fptr->wbuf.off + fptr->wbuf.len;
2254
2255 if (offset + total <= (size_t)fptr->wbuf.capa) {
2256 for (int i = 1; i < iovcnt; i++) {
2257 memcpy(fptr->wbuf.ptr+offset, iov[i].iov_base, iov[i].iov_len);
2258 offset += iov[i].iov_len;
2259 }
2260
2261 fptr->wbuf.len += total;
2262
2263 /* io_binwritev is only reached in sync/TTY mode (it is called only
2264 * from io_fwritev, which io_writev uses only when FMODE_SYNC or
2265 * FMODE_TTY is set), so the coalesced data must be flushed
2266 * immediately rather than left in the buffer until the next flush
2267 * or close. Otherwise a multi-argument write with many arguments
2268 * would not be observably atomic under sync. */
2269 if (io_fflush(fptr) < 0) return -1;
2270
2271 return total;
2272 }
2273 else {
2274 iov[0].iov_base = fptr->wbuf.ptr + fptr->wbuf.off;
2275 iov[0].iov_len = fptr->wbuf.len;
2276 }
2277 }
2278 else {
2279 // The first iov is reserved for the internal buffer, and it's empty.
2280 iov++;
2281
2282 if (!--iovcnt) {
2283 // If there are no other io vectors we are done.
2284 return 0;
2285 }
2286 }
2287
2288 struct binwritev_arg arg;
2289 arg.fptr = fptr;
2290 arg.iov = iov;
2291 arg.iovcnt = iovcnt;
2292 arg.total = total;
2293
2294 if (!NIL_P(fptr->write_lock)) {
2295 return rb_mutex_synchronize(fptr->write_lock, io_binwritev_internal, (VALUE)&arg);
2296 }
2297 else {
2298 return io_binwritev_internal((VALUE)&arg);
2299 }
2300}
2301
2302static long
2303io_fwritev(int argc, const VALUE *argv, rb_io_t *fptr)
2304{
2305 int i, converted, iovcnt = argc + 1;
2306 long n;
2307 VALUE v1, v2, str, tmp, *tmp_array;
2308 struct iovec *iov;
2309
2310 iov = ALLOCV_N(struct iovec, v1, iovcnt);
2311 tmp_array = ALLOCV_N(VALUE, v2, argc);
2312
2313 for (i = 0; i < argc; i++) {
2314 str = rb_obj_as_string(argv[i]);
2315 converted = 0;
2316 str = do_writeconv(str, fptr, &converted);
2317
2318 if (converted)
2319 OBJ_FREEZE(str);
2320
2321 tmp = rb_str_tmp_frozen_acquire(str);
2322 tmp_array[i] = tmp;
2323
2324 /* iov[0] is reserved for buffer of fptr */
2325 iov[i+1].iov_base = RSTRING_PTR(tmp);
2326 iov[i+1].iov_len = RSTRING_LEN(tmp);
2327 }
2328
2329 n = io_binwritev(iov, iovcnt, fptr);
2330 if (v1) ALLOCV_END(v1);
2331
2332 for (i = 0; i < argc; i++) {
2333 rb_str_tmp_frozen_release(argv[i], tmp_array[i]);
2334 }
2335
2336 if (v2) ALLOCV_END(v2);
2337
2338 return n;
2339}
2340
2341static int
2342iovcnt_ok(int iovcnt)
2343{
2344#ifdef IOV_MAX
2345 return iovcnt < IOV_MAX;
2346#else /* GNU/Hurd has writev, but no IOV_MAX */
2347 return 1;
2348#endif
2349}
2350#endif /* HAVE_WRITEV */
2351
2352static VALUE
2353io_writev(int argc, const VALUE *argv, VALUE io)
2354{
2355 rb_io_t *fptr;
2356 long n;
2357 VALUE tmp, total = INT2FIX(0);
2358 int i, cnt = 1;
2359
2360 io = GetWriteIO(io);
2361 tmp = rb_io_check_io(io);
2362
2363 if (NIL_P(tmp)) {
2364 /* port is not IO, call write method for it. */
2365 return rb_funcallv(io, id_write, argc, argv);
2366 }
2367
2368 io = tmp;
2369
2370 GetOpenFile(io, fptr);
2372
2373 for (i = 0; i < argc; i += cnt) {
2374#ifdef HAVE_WRITEV
2375 if ((fptr->mode & (FMODE_SYNC|FMODE_TTY)) && iovcnt_ok(cnt = argc - i)) {
2376 n = io_fwritev(cnt, &argv[i], fptr);
2377 }
2378 else
2379#endif
2380 {
2381 cnt = 1;
2382 /* sync at last item */
2383 n = io_fwrite(rb_obj_as_string(argv[i]), fptr, (i < argc-1));
2384 }
2385
2386 if (n < 0L)
2387 rb_sys_fail_on_write(fptr);
2388
2389 total = rb_fix_plus(LONG2FIX(n), total);
2390 }
2391
2392 return total;
2393}
2394
2395/*
2396 * call-seq:
2397 * write(*objects) -> integer
2398 *
2399 * Writes each of the given +objects+ to +self+,
2400 * which must be opened for writing
2401 * (see {Access Modes}[rdoc-ref:File@Access+Modes]);
2402 * returns the total number bytes written;
2403 * each of +objects+ that is not a string is converted via method +to_s+:
2404 *
2405 * $stdout.write('Hello', ', ', 'World!', "\n") # => 14
2406 * $stdout.write('foo', :bar, 2, "\n") # => 8
2407 *
2408 * Output:
2409 *
2410 * Hello, World!
2411 * foobar2
2412 *
2413 * Related: IO#read.
2414 */
2415
2416static VALUE
2417io_write_m(int argc, VALUE *argv, VALUE io)
2418{
2419 if (argc != 1) {
2420 return io_writev(argc, argv, io);
2421 }
2422 else {
2423 VALUE str = argv[0];
2424 return io_write(io, str, 0);
2425 }
2426}
2427
2428VALUE
2429rb_io_write(VALUE io, VALUE str)
2430{
2431 return rb_funcallv(io, id_write, 1, &str);
2432}
2433
2434static VALUE
2435rb_io_writev(VALUE io, int argc, const VALUE *argv)
2436{
2437 if (argc > 1 && rb_obj_method_arity(io, id_write) == 1) {
2438 if (io != rb_ractor_stderr() && RTEST(ruby_verbose)) {
2439 VALUE klass = CLASS_OF(io);
2440 char sep = RCLASS_SINGLETON_P(klass) ? (klass = io, '.') : '#';
2442 RB_WARN_CATEGORY_DEPRECATED, "%+"PRIsVALUE"%c""write is outdated interface"
2443 " which accepts just one argument",
2444 klass, sep
2445 );
2446 }
2447
2448 do rb_io_write(io, *argv++); while (--argc);
2449
2450 return Qnil;
2451 }
2452
2453 return rb_funcallv(io, id_write, argc, argv);
2454}
2455
2456/*
2457 * call-seq:
2458 * self << object -> self
2459 *
2460 * Writes the given +object+ to +self+,
2461 * which must be opened for writing (see {Access Modes}[rdoc-ref:File@Access+Modes]);
2462 * returns +self+;
2463 * if +object+ is not a string, it is converted via method +to_s+:
2464 *
2465 * $stdout << 'Hello' << ', ' << 'World!' << "\n"
2466 * $stdout << 'foo' << :bar << 2 << "\n"
2467 *
2468 * Output:
2469 *
2470 * Hello, World!
2471 * foobar2
2472 *
2473 */
2474
2475
2476VALUE
2478{
2479 rb_io_write(io, str);
2480 return io;
2481}
2482
2483#ifdef HAVE_FSYNC
2484static VALUE
2485nogvl_fsync(void *ptr)
2486{
2487 rb_io_t *fptr = ptr;
2488
2489#ifdef _WIN32
2490 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->fd)) != FILE_TYPE_DISK)
2491 return 0;
2492#endif
2493 return (VALUE)fsync(fptr->fd);
2494}
2495#endif
2496
2497VALUE
2498rb_io_flush_raw(VALUE io, int sync)
2499{
2500 rb_io_t *fptr;
2501
2502 if (!RB_TYPE_P(io, T_FILE)) {
2503 return rb_funcall(io, id_flush, 0);
2504 }
2505
2506 io = GetWriteIO(io);
2507 GetOpenFile(io, fptr);
2508
2509 if (fptr->mode & FMODE_WRITABLE) {
2510 if (io_fflush(fptr) < 0)
2511 rb_sys_fail_on_write(fptr);
2512 }
2513 if (fptr->mode & FMODE_READABLE) {
2514 io_unread(fptr, true);
2515 }
2516
2517 return io;
2518}
2519
2520/*
2521 * call-seq:
2522 * flush -> self
2523 *
2524 * Flushes data buffered in +self+ to the operating system
2525 * (but does not necessarily flush data buffered in the operating system):
2526 *
2527 * $stdout.print 'no newline' # Not necessarily flushed.
2528 * $stdout.flush # Flushed.
2529 *
2530 */
2531
2532VALUE
2533rb_io_flush(VALUE io)
2534{
2535 return rb_io_flush_raw(io, 1);
2536}
2537
2538/*
2539 * call-seq:
2540 * tell -> integer
2541 *
2542 * Returns the current position (in bytes) in +self+
2543 * (see {Position}[rdoc-ref:IO@Position]):
2544 *
2545 * f = File.open('t.txt')
2546 * f.tell # => 0
2547 * f.gets # => "First line\n"
2548 * f.tell # => 12
2549 * f.close
2550 *
2551 * Related: IO#pos=, IO#seek.
2552 */
2553
2554static VALUE
2555rb_io_tell(VALUE io)
2556{
2557 rb_io_t *fptr;
2558 rb_off_t pos;
2559
2560 GetOpenFile(io, fptr);
2561 pos = io_tell(fptr);
2562 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2563 pos -= fptr->rbuf.len;
2564 return OFFT2NUM(pos);
2565}
2566
2567static VALUE
2568rb_io_seek(VALUE io, VALUE offset, int whence)
2569{
2570 rb_io_t *fptr;
2571 rb_off_t pos;
2572
2573 pos = NUM2OFFT(offset);
2574 GetOpenFile(io, fptr);
2575 pos = io_seek(fptr, pos, whence);
2576 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2577 if (fptr->readconv) clear_readconv(fptr);
2578
2579 return INT2FIX(0);
2580}
2581
2582static int
2583interpret_seek_whence(VALUE vwhence)
2584{
2585 if (vwhence == sym_SET)
2586 return SEEK_SET;
2587 if (vwhence == sym_CUR)
2588 return SEEK_CUR;
2589 if (vwhence == sym_END)
2590 return SEEK_END;
2591#ifdef SEEK_DATA
2592 if (vwhence == sym_DATA)
2593 return SEEK_DATA;
2594#endif
2595#ifdef SEEK_HOLE
2596 if (vwhence == sym_HOLE)
2597 return SEEK_HOLE;
2598#endif
2599 return NUM2INT(vwhence);
2600}
2601
2602/*
2603 * call-seq:
2604 * seek(offset, whence = IO::SEEK_SET) -> 0
2605 *
2606 * Seeks to the position given by integer +offset+
2607 * (see {Position}[rdoc-ref:IO@Position])
2608 * and constant +whence+, which is one of:
2609 *
2610 * - +:CUR+ or <tt>IO::SEEK_CUR</tt>:
2611 * Repositions the stream to its current position plus the given +offset+:
2612 *
2613 * f = File.open('t.txt')
2614 * f.tell # => 0
2615 * f.seek(20, :CUR) # => 0
2616 * f.tell # => 20
2617 * f.seek(-10, :CUR) # => 0
2618 * f.tell # => 10
2619 * f.close
2620 *
2621 * - +:END+ or <tt>IO::SEEK_END</tt>:
2622 * Repositions the stream to its end plus the given +offset+:
2623 *
2624 * f = File.open('t.txt')
2625 * f.tell # => 0
2626 * f.seek(0, :END) # => 0 # Repositions to stream end.
2627 * f.tell # => 52
2628 * f.seek(-20, :END) # => 0
2629 * f.tell # => 32
2630 * f.seek(-40, :END) # => 0
2631 * f.tell # => 12
2632 * f.close
2633 *
2634 * - +:SET+ or <tt>IO::SEEK_SET</tt>:
2635 * Repositions the stream to the given +offset+:
2636 *
2637 * f = File.open('t.txt')
2638 * f.tell # => 0
2639 * f.seek(20, :SET) # => 0
2640 * f.tell # => 20
2641 * f.seek(40, :SET) # => 0
2642 * f.tell # => 40
2643 * f.close
2644 *
2645 * Related: IO#pos=, IO#tell.
2646 *
2647 */
2648
2649static VALUE
2650rb_io_seek_m(int argc, VALUE *argv, VALUE io)
2651{
2652 VALUE offset, ptrname;
2653 int whence = SEEK_SET;
2654
2655 if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
2656 whence = interpret_seek_whence(ptrname);
2657 }
2658
2659 return rb_io_seek(io, offset, whence);
2660}
2661
2662/*
2663 * call-seq:
2664 * pos = new_position -> new_position
2665 *
2666 * Seeks to the given +new_position+ (in bytes);
2667 * see {Position}[rdoc-ref:IO@Position]:
2668 *
2669 * f = File.open('t.txt')
2670 * f.tell # => 0
2671 * f.pos = 20 # => 20
2672 * f.tell # => 20
2673 * f.close
2674 *
2675 * Related: IO#seek, IO#tell.
2676 *
2677 */
2678
2679static VALUE
2680rb_io_set_pos(VALUE io, VALUE offset)
2681{
2682 rb_io_t *fptr;
2683 rb_off_t pos;
2684
2685 pos = NUM2OFFT(offset);
2686 GetOpenFile(io, fptr);
2687 pos = io_seek(fptr, pos, SEEK_SET);
2688 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2689 if (fptr->readconv) clear_readconv(fptr);
2690
2691 return OFFT2NUM(pos);
2692}
2693
2694/*
2695 * call-seq:
2696 * rewind -> 0
2697 *
2698 * Repositions the stream to its beginning,
2699 * setting both the position and the line number to zero;
2700 * see {Position}[rdoc-ref:IO@Position]
2701 * and {Line Number}[rdoc-ref:IO@Line+Number]:
2702 *
2703 * f = File.open('t.txt')
2704 * f.tell # => 0
2705 * f.lineno # => 0
2706 * f.gets # => "First line\n"
2707 * f.tell # => 12
2708 * f.lineno # => 1
2709 * f.rewind # => 0
2710 * f.tell # => 0
2711 * f.lineno # => 0
2712 * f.close
2713 *
2714 * Note that this method cannot be used with streams such as pipes, ttys, and sockets.
2715 *
2716 */
2717
2718static VALUE
2719rb_io_rewind(VALUE io)
2720{
2721 rb_io_t *fptr;
2722
2723 GetOpenFile(io, fptr);
2724 if (io_seek(fptr, 0L, 0) < 0 && errno) rb_sys_fail_path(fptr->pathv);
2725 if (io == ARGF.current_file) {
2726 ARGF.lineno -= fptr->lineno;
2727 }
2728 fptr->lineno = 0;
2729 if (fptr->readconv) {
2730 clear_readconv(fptr);
2731 }
2732
2733 return INT2FIX(0);
2734}
2735
2736static int
2737fptr_wait_readable(rb_io_t *fptr)
2738{
2739 int result = rb_io_maybe_wait_readable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT);
2740
2741 if (result)
2742 rb_io_check_closed(fptr);
2743
2744 return result;
2745}
2746
2747static int
2748io_fillbuf(rb_io_t *fptr)
2749{
2750 ssize_t r;
2751
2752 if (fptr->rbuf.ptr == NULL) {
2753 fptr->rbuf.off = 0;
2754 fptr->rbuf.len = 0;
2755 fptr->rbuf.capa = IO_RBUF_CAPA_FOR(fptr);
2756 fptr->rbuf.ptr = ALLOC_N(char, fptr->rbuf.capa);
2757 }
2758 if (fptr->rbuf.len == 0) {
2759 retry:
2760 r = rb_io_read_memory(fptr, fptr->rbuf.ptr, fptr->rbuf.capa);
2761
2762 if (r < 0) {
2763 if (fptr_wait_readable(fptr))
2764 goto retry;
2765
2766 int e = errno;
2767 VALUE path = rb_sprintf("fd:%d ", fptr->fd);
2768 if (!NIL_P(fptr->pathv)) {
2769 rb_str_append(path, fptr->pathv);
2770 }
2771
2772 rb_syserr_fail_path(e, path);
2773 }
2774 if (r > 0) rb_io_check_closed(fptr);
2775 fptr->rbuf.off = 0;
2776 fptr->rbuf.len = (int)r; /* r should be <= rbuf_capa */
2777 if (r == 0)
2778 return -1; /* EOF */
2779 }
2780 return 0;
2781}
2782
2783/*
2784 * call-seq:
2785 * eof -> true or false
2786 *
2787 * Returns +true+ if the stream is positioned at its end, +false+ otherwise;
2788 * see {Position}[rdoc-ref:IO@Position]:
2789 *
2790 * f = File.open('t.txt')
2791 * f.eof # => false
2792 * f.seek(0, :END) # => 0
2793 * f.eof # => true
2794 * f.close
2795 *
2796 * Raises an exception unless the stream is opened for reading;
2797 * see {Mode}[rdoc-ref:File@Access+Modes].
2798 *
2799 * If +self+ is a stream such as pipe or socket, this method
2800 * blocks until the other end sends some data or closes it:
2801 *
2802 * r, w = IO.pipe
2803 * Thread.new { sleep 1; w.close }
2804 * r.eof? # => true # After 1-second wait.
2805 *
2806 * r, w = IO.pipe
2807 * Thread.new { sleep 1; w.puts "a" }
2808 * r.eof? # => false # After 1-second wait.
2809 *
2810 * r, w = IO.pipe
2811 * r.eof? # blocks forever
2812 *
2813 * Note that this method reads data to the input byte buffer. So
2814 * IO#sysread may not behave as you intend with IO#eof?, unless you
2815 * call IO#rewind first (which is not available for some streams).
2816 */
2817
2818VALUE
2820{
2821 rb_io_t *fptr;
2822
2823 GetOpenFile(io, fptr);
2825
2826 if (READ_CHAR_PENDING(fptr)) return Qfalse;
2827 if (READ_DATA_PENDING(fptr)) return Qfalse;
2828 READ_CHECK(fptr);
2829#if RUBY_CRLF_ENVIRONMENT
2830 if (!NEED_READCONV(fptr) && NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
2831 return RBOOL(eof(fptr->fd));
2832 }
2833#endif
2834 return RBOOL(io_fillbuf(fptr) < 0);
2835}
2836
2837/*
2838 * call-seq:
2839 * sync -> true or false
2840 *
2841 * Returns the current sync mode of the stream.
2842 * When sync mode is true, all output is immediately flushed to the underlying
2843 * operating system and is not buffered by Ruby internally. See also #fsync.
2844 *
2845 * f = File.open('t.tmp', 'w')
2846 * f.sync # => false
2847 * f.sync = true
2848 * f.sync # => true
2849 * f.close
2850 *
2851 */
2852
2853static VALUE
2854rb_io_sync(VALUE io)
2855{
2856 rb_io_t *fptr;
2857
2858 io = GetWriteIO(io);
2859 GetOpenFile(io, fptr);
2860 return RBOOL(fptr->mode & FMODE_SYNC);
2861}
2862
2863#ifdef HAVE_FSYNC
2864
2865/*
2866 * call-seq:
2867 * sync = boolean -> boolean
2868 *
2869 * Sets the _sync_ _mode_ for the stream to the given value;
2870 * returns the given value.
2871 *
2872 * Values for the sync mode:
2873 *
2874 * - +true+: All output is immediately flushed to the
2875 * underlying operating system and is not buffered internally.
2876 * - +false+: Output may be buffered internally.
2877 *
2878 * Example;
2879 *
2880 * f = File.open('t.tmp', 'w')
2881 * f.sync # => false
2882 * f.sync = true
2883 * f.sync # => true
2884 * f.close
2885 *
2886 * Related: IO#fsync.
2887 *
2888 */
2889
2890static VALUE
2891rb_io_set_sync(VALUE io, VALUE sync)
2892{
2893 rb_io_t *fptr;
2894
2895 io = GetWriteIO(io);
2896 GetOpenFile(io, fptr);
2897 if (RTEST(sync)) {
2898 fptr->mode |= FMODE_SYNC;
2899 }
2900 else {
2901 fptr->mode &= ~FMODE_SYNC;
2902 }
2903 return sync;
2904}
2905
2906/*
2907 * call-seq:
2908 * fsync -> 0
2909 *
2910 * Immediately writes to disk all data buffered in the stream,
2911 * via the operating system's <tt>fsync(2)</tt>.
2912
2913 * Note this difference:
2914 *
2915 * - IO#sync=: Ensures that data is flushed from the stream's internal buffers,
2916 * but does not guarantee that the operating system actually writes the data to disk.
2917 * - IO#fsync: Ensures both that data is flushed from internal buffers,
2918 * and that data is written to disk.
2919 *
2920 * Raises an exception if the operating system does not support <tt>fsync(2)</tt>.
2921 *
2922 */
2923
2924static VALUE
2925rb_io_fsync(VALUE io)
2926{
2927 rb_io_t *fptr;
2928
2929 io = GetWriteIO(io);
2930 GetOpenFile(io, fptr);
2931
2932 if (io_fflush(fptr) < 0)
2933 rb_sys_fail_on_write(fptr);
2934
2935 if ((int)rb_io_blocking_region(fptr, nogvl_fsync, fptr))
2936 rb_sys_fail_path(fptr->pathv);
2937
2938 return INT2FIX(0);
2939}
2940#else
2941# define rb_io_fsync rb_f_notimplement
2942# define rb_io_sync rb_f_notimplement
2943static VALUE
2944rb_io_set_sync(VALUE io, VALUE sync)
2945{
2946 rb_notimplement();
2948}
2949#endif
2950
2951#ifdef HAVE_FDATASYNC
2952static VALUE
2953nogvl_fdatasync(void *ptr)
2954{
2955 rb_io_t *fptr = ptr;
2956
2957 return (VALUE)fdatasync(fptr->fd);
2958}
2959
2960/*
2961 * call-seq:
2962 * fdatasync -> 0
2963 *
2964 * Immediately writes to disk all data buffered in the stream,
2965 * via the operating system's: <tt>fdatasync(2)</tt>, if supported,
2966 * otherwise via <tt>fsync(2)</tt>, if supported;
2967 * otherwise raises an exception.
2968 *
2969 */
2970
2971static VALUE
2972rb_io_fdatasync(VALUE io)
2973{
2974 rb_io_t *fptr;
2975
2976 io = GetWriteIO(io);
2977 GetOpenFile(io, fptr);
2978
2979 if (io_fflush(fptr) < 0)
2980 rb_sys_fail_on_write(fptr);
2981
2982 if ((int)rb_io_blocking_region(fptr, nogvl_fdatasync, fptr) == 0)
2983 return INT2FIX(0);
2984
2985 /* fall back */
2986 return rb_io_fsync(io);
2987}
2988#else
2989#define rb_io_fdatasync rb_io_fsync
2990#endif
2991
2992/*
2993 * call-seq:
2994 * fileno -> integer
2995 *
2996 * Returns the integer file descriptor for the stream:
2997 *
2998 * $stdin.fileno # => 0
2999 * $stdout.fileno # => 1
3000 * $stderr.fileno # => 2
3001 * File.open('t.txt').fileno # => 10
3002 * f.close
3003 *
3004 */
3005
3006static VALUE
3007rb_io_fileno(VALUE io)
3008{
3009 rb_io_t *fptr = RFILE(io)->fptr;
3010 int fd;
3011
3012 rb_io_check_closed(fptr);
3013 fd = fptr->fd;
3014 return INT2FIX(fd);
3015}
3016
3017int
3019{
3020 if (RB_TYPE_P(io, T_FILE)) {
3021 rb_io_t *fptr = RFILE(io)->fptr;
3022 rb_io_check_closed(fptr);
3023 return fptr->fd;
3024 }
3025 else {
3026 VALUE fileno = rb_check_funcall(io, id_fileno, 0, NULL);
3027 if (!UNDEF_P(fileno)) {
3028 return RB_NUM2INT(fileno);
3029 }
3030 }
3031
3032 rb_raise(rb_eTypeError, "expected IO or #fileno, %"PRIsVALUE" given", rb_obj_class(io));
3033
3035}
3036
3037int
3038rb_io_mode(VALUE io)
3039{
3040 rb_io_t *fptr;
3041 GetOpenFile(io, fptr);
3042 return fptr->mode;
3043}
3044
3045/*
3046 * call-seq:
3047 * pid -> integer or nil
3048 *
3049 * Returns the process ID of a child process associated with the stream,
3050 * which will have been set by IO#popen, or +nil+ if the stream was not
3051 * created by IO#popen:
3052 *
3053 * pipe = IO.popen("-")
3054 * if pipe
3055 * $stderr.puts "In parent, child pid is #{pipe.pid}"
3056 * else
3057 * $stderr.puts "In child, pid is #{$$}"
3058 * end
3059 *
3060 * Output:
3061 *
3062 * In child, pid is 26209
3063 * In parent, child pid is 26209
3064 *
3065 */
3066
3067static VALUE
3068rb_io_pid(VALUE io)
3069{
3070 rb_io_t *fptr;
3071
3072 GetOpenFile(io, fptr);
3073 if (!fptr->pid)
3074 return Qnil;
3075 return PIDT2NUM(fptr->pid);
3076}
3077
3078/*
3079 * :markup: markdown
3080 *
3081 * call-seq:
3082 * path -> string or nil
3083 *
3084 * Returns the string path associated with `self`,
3085 * or `nil` if there is no associated path:
3086 *
3087 * ```ruby
3088 * path = 'doc/maintainers.md'
3089 * fd = File.open(path).fileno # => 6
3090 * IO.new(fd, path: path).path # => "doc/maintainers.md"
3091 * IO.new(fd).path # => nil
3092 * ```
3093 *
3094 */
3095
3096VALUE
3098{
3099 rb_io_t *fptr = RFILE(io)->fptr;
3100
3101 if (!fptr)
3102 return Qnil;
3103
3104 return rb_obj_dup(fptr->pathv);
3105}
3106
3107/*
3108 * call-seq:
3109 * inspect -> string
3110 *
3111 * Returns a string representation of +self+:
3112 *
3113 * f = File.open('t.txt')
3114 * f.inspect # => "#<File:t.txt>"
3115 * f.close
3116 *
3117 */
3118
3119static VALUE
3120rb_io_inspect(VALUE obj)
3121{
3122 rb_io_t *fptr;
3123 VALUE result;
3124 static const char closed[] = " (closed)";
3125
3126 fptr = RFILE(obj)->fptr;
3127 if (!fptr) return rb_any_to_s(obj);
3128 result = rb_str_new_cstr("#<");
3129 rb_str_append(result, rb_class_name(CLASS_OF(obj)));
3130 rb_str_cat2(result, ":");
3131 if (NIL_P(fptr->pathv)) {
3132 if (fptr->fd < 0) {
3133 rb_str_cat(result, closed+1, strlen(closed)-1);
3134 }
3135 else {
3136 rb_str_catf(result, "fd %d", fptr->fd);
3137 }
3138 }
3139 else {
3140 rb_str_append(result, fptr->pathv);
3141 if (fptr->fd < 0) {
3142 rb_str_cat(result, closed, strlen(closed));
3143 }
3144 }
3145 return rb_str_cat2(result, ">");
3146}
3147
3148/*
3149 * call-seq:
3150 * to_io -> self
3151 *
3152 * Returns +self+.
3153 *
3154 */
3155
3156static VALUE
3157rb_io_to_io(VALUE io)
3158{
3159 return io;
3160}
3161
3162/* reading functions */
3163static long
3164read_buffered_data(char *ptr, long len, rb_io_t *fptr)
3165{
3166 int n;
3167
3168 n = READ_DATA_PENDING_COUNT(fptr);
3169 if (n <= 0) return 0;
3170 if (n > len) n = (int)len;
3171 MEMMOVE(ptr, fptr->rbuf.ptr+fptr->rbuf.off, char, n);
3172 fptr->rbuf.off += n;
3173 fptr->rbuf.len -= n;
3174 return n;
3175}
3176
3177static long
3178io_bufread(char *ptr, long len, rb_io_t *fptr, long *read_len)
3179{
3180 long offset = 0;
3181 long n = len;
3182 long c;
3183
3184 *read_len = 0;
3185 if (READ_DATA_PENDING(fptr) == 0) {
3186 while (n > 0) {
3187 again:
3188 rb_io_check_closed(fptr);
3189 c = rb_io_read_memory(fptr, ptr+offset, n);
3190 if (c == 0) break;
3191 if (c < 0) {
3192 if (fptr_wait_readable(fptr))
3193 goto again;
3194 return -1;
3195 }
3196 offset += c;
3197 *read_len = offset;
3198 if ((n -= c) <= 0) break;
3199 }
3200 return len - n;
3201 }
3202
3203 while (n > 0) {
3204 c = read_buffered_data(ptr+offset, n, fptr);
3205 if (c > 0) {
3206 offset += c;
3207 *read_len = offset;
3208 if ((n -= c) <= 0) break;
3209 }
3210 rb_io_check_closed(fptr);
3211 if (io_fillbuf(fptr) < 0) {
3212 break;
3213 }
3214 }
3215 return len - n;
3216}
3217
3218static int io_setstrbuf(VALUE *str, long len);
3219
3221 char *str_ptr;
3222 long offset;
3223 long len;
3224 long read_len;
3225 rb_io_t *fptr;
3226};
3227
3228static VALUE
3229bufread_body(VALUE arg)
3230{
3231 struct bufread_arg *p = (struct bufread_arg *)arg;
3232 p->len = io_bufread(p->str_ptr + p->offset, p->len, p->fptr, &p->read_len);
3233 return Qundef;
3234}
3235
3236static VALUE
3237bufread_timeout(VALUE arg, VALUE error)
3238{
3239 struct bufread_arg *p = (struct bufread_arg *)arg;
3240
3241 if (p->offset + p->read_len > 0) {
3242 VALUE str = rb_str_new(p->str_ptr, p->offset + p->read_len);
3243 io_restore_read_buffer(str, p->fptr);
3244 }
3245 rb_exc_raise(error);
3247}
3248
3249static VALUE
3250bufread_call(VALUE arg)
3251{
3252 struct bufread_arg *p = (struct bufread_arg *)arg;
3253
3254 if (NIL_P(p->fptr->timeout)) {
3255 return bufread_body(arg);
3256 }
3257 return rb_rescue2(bufread_body, arg, bufread_timeout, arg,
3258 rb_eIOTimeoutError, (VALUE)0);
3259}
3260
3261static long
3262io_fread(VALUE str, long offset, long size, rb_io_t *fptr)
3263{
3264 long len;
3265 struct bufread_arg arg;
3266
3267 io_setstrbuf(&str, offset + size);
3268 arg.str_ptr = RSTRING_PTR(str);
3269 arg.offset = offset;
3270 arg.len = size;
3271 arg.read_len = 0;
3272 arg.fptr = fptr;
3273 rb_str_locktmp_ensure(str, bufread_call, (VALUE)&arg);
3274 len = arg.len;
3275 if (len < 0) rb_sys_fail_path(fptr->pathv);
3276 return len;
3277}
3278
3279static long
3280remain_size(rb_io_t *fptr)
3281{
3282 struct stat st;
3283 rb_off_t siz = READ_DATA_PENDING_COUNT(fptr);
3284 rb_off_t pos;
3285
3286 if (fstat(fptr->fd, &st) == 0 && S_ISREG(st.st_mode)
3287#if defined(__HAIKU__)
3288 && (st.st_dev > 3)
3289#endif
3290 )
3291 {
3292 if (io_fflush(fptr) < 0)
3293 rb_sys_fail_on_write(fptr);
3294 pos = lseek(fptr->fd, 0, SEEK_CUR);
3295 if (st.st_size >= pos && pos >= 0) {
3296 siz += st.st_size - pos;
3297 if (siz > LONG_MAX) {
3298 rb_raise(rb_eIOError, "file too big for single read");
3299 }
3300 }
3301 }
3302 else {
3303 siz += BUFSIZ;
3304 }
3305 return (long)siz;
3306}
3307
3308static VALUE
3309io_enc_str(VALUE str, rb_io_t *fptr)
3310{
3311 rb_enc_associate(str, io_read_encoding(fptr));
3312 return str;
3313}
3314
3315static void
3316make_readconv(rb_io_t *fptr, int size)
3317{
3318 if (!fptr->readconv) {
3319 int ecflags;
3320 VALUE ecopts;
3321 const char *sname, *dname;
3322 ecflags = fptr->encs.ecflags & ~ECONV_NEWLINE_DECORATOR_WRITE_MASK;
3323 ecopts = fptr->encs.ecopts;
3324 if (fptr->encs.enc2) {
3325 sname = rb_enc_name(fptr->encs.enc2);
3326 dname = rb_enc_name(io_read_encoding(fptr));
3327 }
3328 else {
3329 sname = dname = "";
3330 }
3331 fptr->readconv = rb_econv_open_opts(sname, dname, ecflags, ecopts);
3332 if (!fptr->readconv)
3333 rb_exc_raise(rb_econv_open_exc(sname, dname, ecflags));
3334 fptr->cbuf.off = 0;
3335 fptr->cbuf.len = 0;
3336 if (size < IO_CBUF_CAPA_MIN) size = IO_CBUF_CAPA_MIN;
3337 fptr->cbuf.capa = size;
3338 fptr->cbuf.ptr = ALLOC_N(char, fptr->cbuf.capa);
3339 }
3340}
3341
3342#define MORE_CHAR_SUSPENDED Qtrue
3343#define MORE_CHAR_FINISHED Qnil
3344static VALUE
3345fill_cbuf(rb_io_t *fptr, int ec_flags)
3346{
3347 const unsigned char *ss, *sp, *se;
3348 unsigned char *ds, *dp, *de;
3350 int putbackable;
3351 int cbuf_len0;
3352 VALUE exc;
3353
3354 ec_flags |= ECONV_PARTIAL_INPUT;
3355
3356 if (fptr->cbuf.len == fptr->cbuf.capa)
3357 return MORE_CHAR_SUSPENDED; /* cbuf full */
3358 if (fptr->cbuf.len == 0)
3359 fptr->cbuf.off = 0;
3360 else if (fptr->cbuf.off + fptr->cbuf.len == fptr->cbuf.capa) {
3361 memmove(fptr->cbuf.ptr, fptr->cbuf.ptr+fptr->cbuf.off, fptr->cbuf.len);
3362 fptr->cbuf.off = 0;
3363 }
3364
3365 cbuf_len0 = fptr->cbuf.len;
3366
3367 while (1) {
3368 ss = sp = (const unsigned char *)fptr->rbuf.ptr + fptr->rbuf.off;
3369 se = sp + fptr->rbuf.len;
3370 ds = dp = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.off + fptr->cbuf.len;
3371 de = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.capa;
3372 res = rb_econv_convert(fptr->readconv, &sp, se, &dp, de, ec_flags);
3373 fptr->rbuf.off += (int)(sp - ss);
3374 fptr->rbuf.len -= (int)(sp - ss);
3375 fptr->cbuf.len += (int)(dp - ds);
3376
3377 putbackable = rb_econv_putbackable(fptr->readconv);
3378 if (putbackable) {
3379 rb_econv_putback(fptr->readconv, (unsigned char *)fptr->rbuf.ptr + fptr->rbuf.off - putbackable, putbackable);
3380 fptr->rbuf.off -= putbackable;
3381 fptr->rbuf.len += putbackable;
3382 }
3383
3384 exc = rb_econv_make_exception(fptr->readconv);
3385 if (!NIL_P(exc))
3386 return exc;
3387
3388 if (cbuf_len0 != fptr->cbuf.len)
3389 return MORE_CHAR_SUSPENDED;
3390
3391 if (res == econv_finished) {
3392 return MORE_CHAR_FINISHED;
3393 }
3394
3395 if (res == econv_source_buffer_empty) {
3396 if (fptr->rbuf.len == 0) {
3397 READ_CHECK(fptr);
3398 if (io_fillbuf(fptr) < 0) {
3399 if (!fptr->readconv) {
3400 return MORE_CHAR_FINISHED;
3401 }
3402 ds = dp = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.off + fptr->cbuf.len;
3403 de = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.capa;
3404 res = rb_econv_convert(fptr->readconv, NULL, NULL, &dp, de, 0);
3405 fptr->cbuf.len += (int)(dp - ds);
3407 break;
3408 }
3409 }
3410 }
3411 }
3412 if (cbuf_len0 != fptr->cbuf.len)
3413 return MORE_CHAR_SUSPENDED;
3414
3415 return MORE_CHAR_FINISHED;
3416}
3417
3418static VALUE
3419more_char(rb_io_t *fptr)
3420{
3421 VALUE v;
3422 v = fill_cbuf(fptr, ECONV_AFTER_OUTPUT);
3423 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED)
3424 rb_exc_raise(v);
3425 return v;
3426}
3427
3428static VALUE
3429io_shift_cbuf(rb_io_t *fptr, int len, VALUE *strp)
3430{
3431 VALUE str = Qnil;
3432 if (strp) {
3433 str = *strp;
3434 if (NIL_P(str)) {
3435 *strp = str = rb_str_new(fptr->cbuf.ptr+fptr->cbuf.off, len);
3436 }
3437 else {
3438 rb_str_cat(str, fptr->cbuf.ptr+fptr->cbuf.off, len);
3439 }
3440 rb_enc_associate(str, fptr->encs.enc);
3441 }
3442 fptr->cbuf.off += len;
3443 fptr->cbuf.len -= len;
3444 /* xxx: set coderange */
3445 if (fptr->cbuf.len == 0)
3446 fptr->cbuf.off = 0;
3447 else if (fptr->cbuf.capa/2 < fptr->cbuf.off) {
3448 memmove(fptr->cbuf.ptr, fptr->cbuf.ptr+fptr->cbuf.off, fptr->cbuf.len);
3449 fptr->cbuf.off = 0;
3450 }
3451 return str;
3452}
3453
3454static int
3455io_setstrbuf(VALUE *str, long len)
3456{
3457 if (NIL_P(*str)) {
3458 *str = rb_str_new(0, len);
3459 return TRUE;
3460 }
3461 else {
3462 VALUE s = StringValue(*str);
3463 rb_str_modify(s);
3464
3465 long clen = RSTRING_LEN(s);
3466 if (clen >= len) {
3467 return FALSE;
3468 }
3469 len -= clen;
3470 }
3471 if ((rb_str_capacity(*str) - (size_t)RSTRING_LEN(*str)) < (size_t)len) {
3473 }
3474 return FALSE;
3475}
3476
3477#define MAX_REALLOC_GAP 4096
3478static void
3479io_shrink_read_string(VALUE str, long n)
3480{
3481 if (rb_str_capacity(str) - n > MAX_REALLOC_GAP) {
3482 rb_str_resize(str, n);
3483 }
3484}
3485
3486static void
3487io_set_read_length(VALUE str, long n, int shrinkable)
3488{
3489 if (RSTRING_LEN(str) != n) {
3490 rb_str_modify(str);
3491 rb_str_set_len(str, n);
3492 if (shrinkable) io_shrink_read_string(str, n);
3493 }
3494}
3495
3496static VALUE
3497read_all(rb_io_t *fptr, long siz, VALUE str)
3498{
3499 long bytes;
3500 long n;
3501 long pos;
3502 rb_encoding *enc;
3503 int cr;
3504 int shrinkable;
3505
3506 if (NEED_READCONV(fptr)) {
3507 int first = !NIL_P(str);
3508 SET_BINARY_MODE(fptr);
3509 shrinkable = io_setstrbuf(&str,0);
3510 make_readconv(fptr, 0);
3511 while (1) {
3512 VALUE v;
3513 if (fptr->cbuf.len) {
3514 if (first) rb_str_set_len(str, first = 0);
3515 io_shift_cbuf(fptr, fptr->cbuf.len, &str);
3516 }
3517 v = fill_cbuf(fptr, 0);
3518 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED) {
3519 if (fptr->cbuf.len) {
3520 if (first) rb_str_set_len(str, first = 0);
3521 io_shift_cbuf(fptr, fptr->cbuf.len, &str);
3522 }
3523 rb_exc_raise(v);
3524 }
3525 if (v == MORE_CHAR_FINISHED) {
3526 clear_readconv(fptr);
3527 if (first) rb_str_set_len(str, first = 0);
3528 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3529 return io_enc_str(str, fptr);
3530 }
3531 }
3532 }
3533
3534 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3535 bytes = 0;
3536 pos = 0;
3537
3538 enc = io_read_encoding(fptr);
3539 cr = 0;
3540
3541 if (siz == 0) {
3542 siz = BUFSIZ;
3543 }
3544 else {
3545 // If `siz` is set, we got it from `stat(2)`.
3546 // We attempt to read one extra byte because:
3547 // - If the file was appended to since then, we'll continue reading.
3548 // - If the file is still the same length, we won't issue a second `io_fread`.
3549 siz++;
3550 }
3551 shrinkable = io_setstrbuf(&str, siz);
3552 for (;;) {
3553 READ_CHECK(fptr);
3554 n = io_fread(str, bytes, siz - bytes, fptr);
3555 if (n == 0 && bytes == 0) {
3556 rb_str_set_len(str, 0);
3557 break;
3558 }
3559 bytes += n;
3560 rb_str_set_len(str, bytes);
3561 if (cr != ENC_CODERANGE_BROKEN)
3562 pos += rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + bytes, enc, &cr);
3563 if (bytes < siz) break;
3564 siz += BUFSIZ;
3565
3566 size_t capa = rb_str_capacity(str);
3567 if (capa < (size_t)RSTRING_LEN(str) + BUFSIZ) {
3568 if (capa < BUFSIZ) {
3569 capa = BUFSIZ;
3570 }
3571 else if (capa > IO_MAX_BUFFER_GROWTH) {
3572 capa = IO_MAX_BUFFER_GROWTH;
3573 }
3575 }
3576 }
3577 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3578 str = io_enc_str(str, fptr);
3579 ENC_CODERANGE_SET(str, cr);
3580 return str;
3581}
3582
3583void
3585{
3586 if (rb_fd_set_nonblock(fptr->fd) != 0) {
3587 rb_sys_fail_path(fptr->pathv);
3588 }
3589}
3590
3591static VALUE
3592io_read_memory_call(VALUE arg)
3593{
3594 struct io_internal_read_struct *iis = (struct io_internal_read_struct *)arg;
3595
3596 VALUE scheduler = rb_fiber_scheduler_current();
3597 if (scheduler != Qnil) {
3598 VALUE result = rb_fiber_scheduler_io_read_memory(scheduler, iis->fptr->self, iis->buf, iis->capa);
3599
3600 if (!UNDEF_P(result)) {
3601 // This is actually returned as a pseudo-VALUE and later cast to a long:
3603 }
3604 }
3605
3606 if (iis->nonblock) {
3607 return rb_io_blocking_region(iis->fptr, internal_read_func, iis);
3608 }
3609 else {
3610 return rb_io_blocking_region_wait(iis->fptr, internal_read_func, iis, RUBY_IO_READABLE);
3611 }
3612}
3613
3614static long
3615io_read_memory_locktmp(VALUE str, struct io_internal_read_struct *iis)
3616{
3617 return (long)rb_str_locktmp_ensure(str, io_read_memory_call, (VALUE)iis);
3618}
3619
3620#define no_exception_p(opts) !rb_opts_exception_p((opts), TRUE)
3621
3622static VALUE
3623io_getpartial(int argc, VALUE *argv, VALUE io, int no_exception, int nonblock)
3624{
3625 rb_io_t *fptr;
3626 VALUE length, str;
3627 long n, len;
3628 struct io_internal_read_struct iis;
3629 int shrinkable;
3630
3631 rb_scan_args(argc, argv, "11", &length, &str);
3632
3633 if ((len = NUM2LONG(length)) < 0) {
3634 rb_raise(rb_eArgError, "negative length %ld given", len);
3635 }
3636
3637 shrinkable = io_setstrbuf(&str, len);
3638
3639 GetOpenFile(io, fptr);
3641
3642 if (len == 0) {
3643 io_set_read_length(str, 0, shrinkable);
3644 return str;
3645 }
3646
3647 if (!nonblock)
3648 READ_CHECK(fptr);
3649 n = read_buffered_data(RSTRING_PTR(str), len, fptr);
3650 if (n <= 0) {
3651 again:
3652 if (nonblock) {
3653 rb_io_set_nonblock(fptr);
3654 }
3655 io_setstrbuf(&str, len);
3656 iis.th = rb_thread_current();
3657 iis.fptr = fptr;
3658 iis.nonblock = nonblock;
3659 iis.fd = fptr->fd;
3660 iis.buf = RSTRING_PTR(str);
3661 iis.capa = len;
3662 iis.timeout = NULL;
3663 n = io_read_memory_locktmp(str, &iis);
3664 if (n < 0) {
3665 int e = errno;
3666 if (!nonblock && fptr_wait_readable(fptr))
3667 goto again;
3668 if (nonblock && (io_again_p(e))) {
3669 if (no_exception)
3670 return sym_wait_readable;
3671 else
3672 rb_readwrite_syserr_fail(RB_IO_WAIT_READABLE,
3673 e, "read would block");
3674 }
3675 rb_syserr_fail_path(e, fptr->pathv);
3676 }
3677 }
3678 io_set_read_length(str, n, shrinkable);
3679
3680 if (n == 0)
3681 return Qnil;
3682 else
3683 return str;
3684}
3685
3686/*
3687 * call-seq:
3688 * readpartial(maxlen) -> string
3689 * readpartial(maxlen, out_string) -> out_string
3690 *
3691 * Reads up to +maxlen+ bytes from the stream;
3692 * returns a string (either a new string or the given +out_string+).
3693 * Its encoding is:
3694 *
3695 * - The unchanged encoding of +out_string+, if +out_string+ is given.
3696 * - ASCII-8BIT, otherwise.
3697 *
3698 * - Contains +maxlen+ bytes from the stream, if available.
3699 * - Otherwise contains all available bytes, if any available.
3700 * - Is an empty string if +maxlen+ is zero.
3701 *
3702 * With the single non-negative integer argument +maxlen+ given,
3703 * returns a new string:
3704 *
3705 * f = File.new('t.txt')
3706 * f.readpartial(20) # => "First line\nSecond l"
3707 * f.readpartial(20) # => "ine\n\nFourth line\n"
3708 * f.readpartial(20) # => "Fifth line\n"
3709 * f.readpartial(20) # Raises EOFError.
3710 * f.close
3711 *
3712 * With both argument +maxlen+ and string argument +out_string+ given,
3713 * returns modified +out_string+:
3714 *
3715 * f = File.new('t.txt')
3716 * s = 'foo'
3717 * f.readpartial(20, s) # => "First line\nSecond l"
3718 * s = 'bar'
3719 * f.readpartial(0, s) # => ""
3720 * f.close
3721 *
3722 * This method is useful for a stream such as a pipe, a socket, or a tty.
3723 * It blocks only when no data is immediately available.
3724 * This means that it blocks only when _all_ of the following are true:
3725 *
3726 * - The byte buffer in the stream is empty.
3727 * - The content of the stream is empty.
3728 * - The stream is not at EOF.
3729 *
3730 * When blocked, the method waits for either more data or EOF on the stream:
3731 *
3732 * - If more data is read, the method returns the data.
3733 * - If EOF is reached, the method raises EOFError.
3734 *
3735 * When not blocked, the method responds immediately:
3736 *
3737 * - Returns data from the buffer if there is any.
3738 * - Otherwise returns data from the stream if there is any.
3739 * - Otherwise raises EOFError if the stream has reached EOF.
3740 *
3741 * Note that this method is similar to sysread. The differences are:
3742 *
3743 * - If the byte buffer is not empty, read from the byte buffer
3744 * instead of "sysread for buffered IO (IOError)".
3745 * - It doesn't cause Errno::EWOULDBLOCK and Errno::EINTR. When
3746 * readpartial meets EWOULDBLOCK and EINTR by read system call,
3747 * readpartial retries the system call.
3748 *
3749 * The latter means that readpartial is non-blocking-flag insensitive.
3750 * It blocks on the situation IO#sysread causes Errno::EWOULDBLOCK as
3751 * if the fd is blocking mode.
3752 *
3753 * Examples:
3754 *
3755 * # # Returned Buffer Content Pipe Content
3756 * r, w = IO.pipe #
3757 * w << 'abc' # "" "abc".
3758 * r.readpartial(4096) # => "abc" "" ""
3759 * r.readpartial(4096) # (Blocks because buffer and pipe are empty.)
3760 *
3761 * # # Returned Buffer Content Pipe Content
3762 * r, w = IO.pipe #
3763 * w << 'abc' # "" "abc"
3764 * w.close # "" "abc" EOF
3765 * r.readpartial(4096) # => "abc" "" EOF
3766 * r.readpartial(4096) # raises EOFError
3767 *
3768 * # # Returned Buffer Content Pipe Content
3769 * r, w = IO.pipe #
3770 * w << "abc\ndef\n" # "" "abc\ndef\n"
3771 * r.gets # => "abc\n" "def\n" ""
3772 * w << "ghi\n" # "def\n" "ghi\n"
3773 * r.readpartial(4096) # => "def\n" "" "ghi\n"
3774 * r.readpartial(4096) # => "ghi\n" "" ""
3775 *
3776 */
3777
3778static VALUE
3779io_readpartial(int argc, VALUE *argv, VALUE io)
3780{
3781 VALUE ret;
3782
3783 ret = io_getpartial(argc, argv, io, Qnil, 0);
3784 if (NIL_P(ret))
3785 rb_eof_error();
3786 return ret;
3787}
3788
3789static VALUE
3790io_nonblock_eof(int no_exception)
3791{
3792 if (!no_exception) {
3793 rb_eof_error();
3794 }
3795 return Qnil;
3796}
3797
3798/* :nodoc: */
3799static VALUE
3800io_read_nonblock(rb_execution_context_t *ec, VALUE io, VALUE length, VALUE str, VALUE ex)
3801{
3802 rb_io_t *fptr;
3803 long n, len;
3804 struct io_internal_read_struct iis;
3805 int shrinkable;
3806
3807 if ((len = NUM2LONG(length)) < 0) {
3808 rb_raise(rb_eArgError, "negative length %ld given", len);
3809 }
3810
3811 shrinkable = io_setstrbuf(&str, len);
3812 rb_bool_expected(ex, "exception", TRUE);
3813
3814 GetOpenFile(io, fptr);
3816
3817 if (len == 0) {
3818 io_set_read_length(str, 0, shrinkable);
3819 return str;
3820 }
3821
3822 n = read_buffered_data(RSTRING_PTR(str), len, fptr);
3823 if (n <= 0) {
3824 rb_fd_set_nonblock(fptr->fd);
3825 shrinkable |= io_setstrbuf(&str, len);
3826 iis.fptr = fptr;
3827 iis.nonblock = 1;
3828 iis.fd = fptr->fd;
3829 iis.buf = RSTRING_PTR(str);
3830 iis.capa = len;
3831 iis.timeout = NULL;
3832 n = io_read_memory_locktmp(str, &iis);
3833 if (n < 0) {
3834 int e = errno;
3835 if (io_again_p(e)) {
3836 if (!ex) return sym_wait_readable;
3837 rb_readwrite_syserr_fail(RB_IO_WAIT_READABLE,
3838 e, "read would block");
3839 }
3840 rb_syserr_fail_path(e, fptr->pathv);
3841 }
3842 }
3843 io_set_read_length(str, n, shrinkable);
3844
3845 if (n == 0) {
3846 if (!ex) return Qnil;
3847 rb_eof_error();
3848 }
3849
3850 return str;
3851}
3852
3853/* :nodoc: */
3854static VALUE
3855io_write_nonblock(rb_execution_context_t *ec, VALUE io, VALUE str, VALUE ex)
3856{
3857 rb_io_t *fptr;
3858 long n;
3859
3860 if (!RB_TYPE_P(str, T_STRING))
3861 str = rb_obj_as_string(str);
3862 rb_bool_expected(ex, "exception", TRUE);
3863
3864 io = GetWriteIO(io);
3865 GetOpenFile(io, fptr);
3867
3868 if (io_fflush(fptr) < 0)
3869 rb_sys_fail_on_write(fptr);
3870
3871 rb_fd_set_nonblock(fptr->fd);
3872 n = write(fptr->fd, RSTRING_PTR(str), RSTRING_LEN(str));
3873 RB_GC_GUARD(str);
3874
3875 if (n < 0) {
3876 int e = errno;
3877 if (io_again_p(e)) {
3878 if (!ex) {
3879 return sym_wait_writable;
3880 }
3881 else {
3882 rb_readwrite_syserr_fail(RB_IO_WAIT_WRITABLE, e, "write would block");
3883 }
3884 }
3885 rb_syserr_fail_path(e, fptr->pathv);
3886 }
3887
3888 return LONG2FIX(n);
3889}
3890
3891/*
3892 * call-seq:
3893 * read(maxlen = nil, out_string = nil) -> new_string, out_string, or nil
3894 *
3895 * Reads bytes from the stream; the stream must be opened for reading
3896 * (see {Access Modes}[rdoc-ref:File@Access+Modes]):
3897 *
3898 * - If +maxlen+ is +nil+, reads all bytes using the stream's data mode.
3899 * - Otherwise reads up to +maxlen+ bytes in binary mode.
3900 *
3901 * Returns a string (either a new string or the given +out_string+)
3902 * containing the bytes read.
3903 * The encoding of the string depends on both +maxLen+ and +out_string+:
3904 *
3905 * - +maxlen+ is +nil+: uses internal encoding of +self+
3906 * (regardless of whether +out_string+ was given).
3907 * - +maxlen+ not +nil+:
3908 *
3909 * - +out_string+ given: encoding of +out_string+ not modified.
3910 * - +out_string+ not given: ASCII-8BIT is used.
3911 *
3912 * <b>Without Argument +out_string+</b>
3913 *
3914 * When argument +out_string+ is omitted,
3915 * the returned value is a new string:
3916 *
3917 * f = File.new('t.txt')
3918 * f.read
3919 * # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3920 * f.rewind
3921 * f.read(30) # => "First line\r\nSecond line\r\n\r\nFou"
3922 * f.read(30) # => "rth line\r\nFifth line\r\n"
3923 * f.read(30) # => nil
3924 * f.close
3925 *
3926 * If +maxlen+ is zero, returns an empty string.
3927 *
3928 * <b> With Argument +out_string+</b>
3929 *
3930 * When argument +out_string+ is given,
3931 * the returned value is +out_string+, whose content is replaced:
3932 *
3933 * f = File.new('t.txt')
3934 * s = 'foo' # => "foo"
3935 * f.read(nil, s) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3936 * s # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3937 * f.rewind
3938 * s = 'bar'
3939 * f.read(30, s) # => "First line\r\nSecond line\r\n\r\nFou"
3940 * s # => "First line\r\nSecond line\r\n\r\nFou"
3941 * s = 'baz'
3942 * f.read(30, s) # => "rth line\r\nFifth line\r\n"
3943 * s # => "rth line\r\nFifth line\r\n"
3944 * s = 'bat'
3945 * f.read(30, s) # => nil
3946 * s # => ""
3947 * f.close
3948 *
3949 * Note that this method behaves like the fread() function in C.
3950 * This means it retries to invoke read(2) system calls to read data
3951 * with the specified maxlen (or until EOF).
3952 *
3953 * This behavior is preserved even if the stream is in non-blocking mode.
3954 * (This method is non-blocking-flag insensitive as other methods.)
3955 *
3956 * If you need the behavior like a single read(2) system call,
3957 * consider #readpartial, #read_nonblock, and #sysread.
3958 *
3959 * Related: IO#write.
3960 */
3961
3962static VALUE
3963io_read(int argc, VALUE *argv, VALUE io)
3964{
3965 rb_io_t *fptr;
3966 long n, len;
3967 VALUE length, str;
3968 int shrinkable;
3969#if RUBY_CRLF_ENVIRONMENT
3970 int previous_mode;
3971#endif
3972
3973 rb_scan_args(argc, argv, "02", &length, &str);
3974
3975 if (NIL_P(length)) {
3976 GetOpenFile(io, fptr);
3978 return read_all(fptr, remain_size(fptr), str);
3979 }
3980 len = NUM2LONG(length);
3981 if (len < 0) {
3982 rb_raise(rb_eArgError, "negative length %ld given", len);
3983 }
3984
3985 shrinkable = io_setstrbuf(&str,len);
3986
3987 GetOpenFile(io, fptr);
3989 if (len == 0) {
3990 io_set_read_length(str, 0, shrinkable);
3991 return str;
3992 }
3993
3994 READ_CHECK(fptr);
3995#if RUBY_CRLF_ENVIRONMENT
3996 previous_mode = set_binary_mode_with_seek_cur(fptr);
3997#endif
3998 n = io_fread(str, 0, len, fptr);
3999 io_set_read_length(str, n, shrinkable);
4000#if RUBY_CRLF_ENVIRONMENT
4001 if (previous_mode == O_TEXT) {
4002 setmode(fptr->fd, O_TEXT);
4003 }
4004#endif
4005 if (n == 0) return Qnil;
4006
4007 return str;
4008}
4009
4010static void
4011rscheck(const char *rsptr, long rslen, VALUE rs)
4012{
4013 if (!rs) return;
4014 if (RSTRING_PTR(rs) != rsptr && RSTRING_LEN(rs) != rslen)
4015 rb_raise(rb_eRuntimeError, "rs modified");
4016}
4017
4018static const char *
4019search_delim(const char *p, long len, int delim, rb_encoding *enc)
4020{
4021 if (rb_enc_mbminlen(enc) == 1) {
4022 p = memchr(p, delim, len);
4023 if (p) return p + 1;
4024 }
4025 else {
4026 const char *end = p + len;
4027 while (p < end) {
4028 int r = rb_enc_precise_mbclen(p, end, enc);
4029 if (!MBCLEN_CHARFOUND_P(r)) {
4030 p += rb_enc_mbminlen(enc);
4031 continue;
4032 }
4033 int n = MBCLEN_CHARFOUND_LEN(r);
4034 if (rb_enc_mbc_to_codepoint(p, end, enc) == (unsigned int)delim) {
4035 return p + n;
4036 }
4037 p += n;
4038 }
4039 }
4040 return NULL;
4041}
4042
4043static int
4044read_raw_character(rb_io_t *fptr, rb_encoding *enc, char *buf)
4045{
4046 int n = 0;
4047 int r;
4048
4049 do {
4050 if (!READ_DATA_PENDING(fptr)) {
4051 READ_CHECK(fptr);
4052 if (io_fillbuf(fptr) < 0) break;
4053 }
4054 buf[n++] = *READ_DATA_PENDING_PTR(fptr);
4055 fptr->rbuf.off++;
4056 fptr->rbuf.len--;
4057 r = rb_enc_precise_mbclen(buf, buf + n, enc);
4058 } while (MBCLEN_NEEDMORE_P(r) && n < rb_enc_mbmaxlen(enc));
4059
4060 return n;
4061}
4062
4063static void
4064unread_raw_character(rb_io_t *fptr, const char *buf, int len)
4065{
4066 if (fptr->rbuf.capa - fptr->rbuf.len < len) {
4067 if (fptr->rbuf.capa > INT_MAX - len)
4068 rb_raise(rb_eIOError, "ungetbyte failed");
4069 fptr->rbuf.capa += len;
4070 REALLOC_N(fptr->rbuf.ptr, char, fptr->rbuf.capa);
4071 }
4072 io_ungetbyte(rb_str_new(buf, len), fptr);
4073}
4074
4075static const char *
4076search_wide_delim(const char *p, long len, const char *delim, int width)
4077{
4078 const char *e = p + len;
4079 int index = 0;
4080
4081 while (index < width && delim[index] == 0) index++;
4082 if (index == width) index = 0;
4083
4084 const char *candidate = p + index;
4085 while (candidate < e) {
4086 candidate = memchr(candidate, (unsigned char)delim[index], e - candidate);
4087 if (candidate == NULL) break;
4088 const char *start = candidate - index;
4089 if ((start - p) % width == 0 && start + width <= e &&
4090 memcmp(start, delim, width) == 0) {
4091 return start;
4092 }
4093 candidate++;
4094 }
4095 return NULL;
4096}
4097
4098static int
4099appendline(rb_io_t *fptr, int delim, VALUE *strp, long *lp, rb_encoding *enc)
4100{
4101 VALUE str = *strp;
4102 long limit = *lp;
4103
4104 if (NEED_READCONV(fptr)) {
4105 SET_BINARY_MODE(fptr);
4106 make_readconv(fptr, 0);
4107 do {
4108 const char *p, *e;
4109 int searchlen = READ_CHAR_PENDING_COUNT(fptr);
4110 if (searchlen) {
4111 p = READ_CHAR_PENDING_PTR(fptr);
4112 if (0 < limit && limit < searchlen)
4113 searchlen = (int)limit;
4114 e = search_delim(p, searchlen, delim, enc);
4115 if (e) {
4116 int len = (int)(e-p);
4117 if (NIL_P(str))
4118 *strp = str = rb_str_new(p, len);
4119 else
4120 rb_str_buf_cat(str, p, len);
4121 fptr->cbuf.off += len;
4122 fptr->cbuf.len -= len;
4123 limit -= len;
4124 *lp = limit;
4125 return delim;
4126 }
4127
4128 if (NIL_P(str))
4129 *strp = str = rb_str_new(p, searchlen);
4130 else
4131 rb_str_buf_cat(str, p, searchlen);
4132 fptr->cbuf.off += searchlen;
4133 fptr->cbuf.len -= searchlen;
4134 limit -= searchlen;
4135
4136 if (limit == 0) {
4137 *lp = limit;
4138 return (unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
4139 }
4140 }
4141 } while (more_char(fptr) != MORE_CHAR_FINISHED);
4142 clear_readconv(fptr);
4143 *lp = limit;
4144 return EOF;
4145 }
4146
4147 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4148 if (rb_enc_mbminlen(enc) != 1) {
4149 char buf[ONIGENC_CODE_TO_MBC_MAXLEN];
4150 int len;
4151
4152 if (limit < 0) {
4153 int width = rb_enc_mbminlen(enc);
4154 int delim_len = rb_enc_codelen(delim, enc);
4155
4156 if (delim_len == width) {
4157 rb_enc_mbcput(delim, buf, enc);
4158 for (;;) {
4159 if (!READ_DATA_PENDING(fptr)) {
4160 READ_CHECK(fptr);
4161 if (io_fillbuf(fptr) < 0) return EOF;
4162 }
4163 long pending = READ_DATA_PENDING_COUNT(fptr);
4164 long complete = pending - pending % width;
4165 const char *p = READ_DATA_PENDING_PTR(fptr);
4166 const char *q = complete ? search_wide_delim(p, complete, buf, width) : NULL;
4167 long take = q ? q - p + width : complete;
4168
4169 if (take > 0) {
4170 if (NIL_P(str))
4171 *strp = str = rb_str_buf_new(0);
4172 rb_str_buf_cat(str, p, take);
4173 fptr->rbuf.off += (int)take;
4174 fptr->rbuf.len -= (int)take;
4175 }
4176 if (q) return delim;
4177 if (complete == pending) continue;
4178
4179 len = read_raw_character(fptr, enc, buf);
4180 if (len == 0) return EOF;
4181 if (NIL_P(str))
4182 *strp = str = rb_str_buf_new(0);
4183 rb_str_buf_cat(str, buf, len);
4184 int r = rb_enc_precise_mbclen(buf, buf + len, enc);
4185 if (MBCLEN_CHARFOUND_P(r) &&
4186 rb_enc_mbc_to_codepoint(buf, buf + len, enc) == (unsigned int)delim)
4187 return delim;
4188 }
4189 }
4190 }
4191
4192 while ((len = read_raw_character(fptr, enc, buf)) > 0) {
4193 if (NIL_P(str))
4194 *strp = str = rb_str_buf_new(0);
4195 rb_str_buf_cat(str, buf, len);
4196 if (limit > 0) {
4197 if (len > limit) {
4198 *lp = 0;
4199 return (unsigned char)buf[len - 1];
4200 }
4201 *lp = limit -= len;
4202 }
4203 int r = rb_enc_precise_mbclen(buf, buf + len, enc);
4204 if (MBCLEN_CHARFOUND_P(r) &&
4205 rb_enc_mbc_to_codepoint(buf, buf + len, enc) == (unsigned int)delim)
4206 return delim;
4207 if (limit == 0)
4208 return (unsigned char)buf[len - 1];
4209 }
4210 *lp = limit;
4211 return EOF;
4212 }
4213 do {
4214 long pending = READ_DATA_PENDING_COUNT(fptr);
4215 if (pending > 0) {
4216 const char *p = READ_DATA_PENDING_PTR(fptr);
4217 const char *e;
4218 long last;
4219
4220 if (limit > 0 && pending > limit) pending = limit;
4221 e = search_delim(p, pending, delim, enc);
4222 if (e) pending = e - p;
4223 if (!NIL_P(str)) {
4224 last = RSTRING_LEN(str);
4225 rb_str_resize(str, last + pending);
4226 }
4227 else {
4228 last = 0;
4229 *strp = str = rb_str_buf_new(pending);
4230 rb_str_set_len(str, pending);
4231 }
4232 read_buffered_data(RSTRING_PTR(str) + last, pending, fptr); /* must not fail */
4233 limit -= pending;
4234 *lp = limit;
4235 if (e) return delim;
4236 if (limit == 0)
4237 return (unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
4238 }
4239 READ_CHECK(fptr);
4240 } while (io_fillbuf(fptr) >= 0);
4241 *lp = limit;
4242 return EOF;
4243}
4244
4245static inline int
4246swallow(rb_io_t *fptr, int term)
4247{
4248 if (NEED_READCONV(fptr)) {
4249 rb_encoding *enc = io_read_encoding(fptr);
4250 int needconv = rb_enc_mbminlen(enc) != 1;
4251 SET_BINARY_MODE(fptr);
4252 make_readconv(fptr, 0);
4253 do {
4254 size_t cnt;
4255 while ((cnt = READ_CHAR_PENDING_COUNT(fptr)) > 0) {
4256 const char *p = READ_CHAR_PENDING_PTR(fptr);
4257 int i;
4258 if (!needconv) {
4259 if (*p != term) return TRUE;
4260 i = (int)cnt;
4261 while (--i && *++p == term);
4262 }
4263 else {
4264 const char *e = p + cnt;
4265 if (rb_enc_ascget(p, e, &i, enc) != term) return TRUE;
4266 while ((p += i) < e && rb_enc_ascget(p, e, &i, enc) == term);
4267 i = (int)(e - p);
4268 }
4269 io_shift_cbuf(fptr, (int)cnt - i, NULL);
4270 }
4271 } while (more_char(fptr) != MORE_CHAR_FINISHED);
4272 return FALSE;
4273 }
4274
4275 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4276 rb_encoding *enc = io_read_encoding(fptr);
4277 int widechar = rb_enc_mbminlen(enc) != 1;
4278 if (widechar) {
4279 char buf[ONIGENC_CODE_TO_MBC_MAXLEN];
4280 int len;
4281
4282 while ((len = read_raw_character(fptr, enc, buf)) > 0) {
4283 if (rb_enc_ascget(buf, buf + len, NULL, enc) != term) {
4284 unread_raw_character(fptr, buf, len);
4285 return TRUE;
4286 }
4287 }
4288 return FALSE;
4289 }
4290 do {
4291 size_t cnt;
4292 while ((cnt = READ_DATA_PENDING_COUNT(fptr)) > 0) {
4293 char buf[1024];
4294 const char *p = READ_DATA_PENDING_PTR(fptr);
4295 int i;
4296 if (cnt > sizeof buf) cnt = sizeof buf;
4297 if (*p != term) return TRUE;
4298 i = (int)cnt;
4299 while (--i && *++p == term);
4300 if (!read_buffered_data(buf, cnt - i, fptr)) /* must not fail */
4301 rb_sys_fail_path(fptr->pathv);
4302 }
4303 READ_CHECK(fptr);
4304 } while (io_fillbuf(fptr) == 0);
4305 return FALSE;
4306}
4307
4308static VALUE
4309rb_io_getline_fast(rb_io_t *fptr, rb_encoding *enc, int chomp)
4310{
4311 VALUE str = Qnil;
4312 int len = 0;
4313 long pos = 0;
4314 int cr = 0;
4315
4316 do {
4317 int pending = READ_DATA_PENDING_COUNT(fptr);
4318
4319 if (pending > 0) {
4320 const char *p = READ_DATA_PENDING_PTR(fptr);
4321 const char *e;
4322 int chomplen = 0;
4323
4324 e = memchr(p, '\n', pending);
4325 if (e) {
4326 pending = (int)(e - p + 1);
4327 if (chomp) {
4328 chomplen = (pending > 1 && *(e-1) == '\r') + 1;
4329 }
4330 }
4331 if (NIL_P(str)) {
4332 str = rb_str_new(p, pending - chomplen);
4333 fptr->rbuf.off += pending;
4334 fptr->rbuf.len -= pending;
4335 }
4336 else {
4337 rb_str_resize(str, len + pending - chomplen);
4338 read_buffered_data(RSTRING_PTR(str)+len, pending - chomplen, fptr);
4339 fptr->rbuf.off += chomplen;
4340 fptr->rbuf.len -= chomplen;
4341 if (pending == 1 && chomplen == 1 && len > 0) {
4342 if (RSTRING_PTR(str)[len-1] == '\r') {
4343 rb_str_resize(str, --len);
4344 break;
4345 }
4346 }
4347 }
4348 len += pending - chomplen;
4349 if (cr != ENC_CODERANGE_BROKEN)
4350 pos += rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + len, enc, &cr);
4351 if (e) break;
4352 }
4353 READ_CHECK(fptr);
4354 } while (io_fillbuf(fptr) >= 0);
4355 if (NIL_P(str)) return Qnil;
4356
4357 str = io_enc_str(str, fptr);
4358 ENC_CODERANGE_SET(str, cr);
4359 fptr->lineno++;
4360
4361 return str;
4362}
4363
4365 VALUE io;
4366 VALUE rs;
4367 long limit;
4368 unsigned int chomp: 1;
4369};
4370
4371static void
4372extract_getline_opts(VALUE opts, struct getline_arg *args)
4373{
4374 int chomp = FALSE;
4375 if (!NIL_P(opts)) {
4376 static ID kwds[1];
4377 VALUE vchomp;
4378 if (!kwds[0]) {
4379 kwds[0] = rb_intern_const("chomp");
4380 }
4381 rb_get_kwargs(opts, kwds, 0, -2, &vchomp);
4382 chomp = (!UNDEF_P(vchomp)) && RTEST(vchomp);
4383 }
4384 args->chomp = chomp;
4385}
4386
4387static void
4388extract_getline_args(int argc, VALUE *argv, struct getline_arg *args)
4389{
4390 VALUE rs = rb_rs, lim = Qnil;
4391
4392 if (argc == 1) {
4393 VALUE tmp = Qnil;
4394
4395 if (NIL_P(argv[0]) || !NIL_P(tmp = rb_check_string_type(argv[0]))) {
4396 rs = tmp;
4397 }
4398 else {
4399 lim = argv[0];
4400 }
4401 }
4402 else if (2 <= argc) {
4403 rs = argv[0], lim = argv[1];
4404 if (!NIL_P(rs))
4405 StringValue(rs);
4406 }
4407 args->rs = rs;
4408 args->limit = NIL_P(lim) ? -1L : NUM2LONG(lim);
4409}
4410
4411static void
4412check_getline_args(VALUE *rsp, long *limit, VALUE io)
4413{
4414 rb_io_t *fptr;
4415 VALUE rs = *rsp;
4416
4417 if (!NIL_P(rs)) {
4418 rb_encoding *enc_rs, *enc_io;
4419
4420 GetOpenFile(io, fptr);
4421 enc_rs = rb_enc_get(rs);
4422 enc_io = io_read_encoding(fptr);
4423 if (enc_io != enc_rs &&
4424 (!is_ascii_string(rs) ||
4425 (RSTRING_LEN(rs) > 0 && !rb_enc_asciicompat(enc_io)))) {
4426 if (rs == rb_default_rs) {
4427 rs = rb_enc_str_new(0, 0, enc_io);
4428 rb_str_buf_cat_ascii(rs, "\n");
4429 *rsp = rs;
4430 }
4431 else {
4432 rb_raise(rb_eArgError, "encoding mismatch: %s IO with %s RS",
4433 rb_enc_name(enc_io),
4434 rb_enc_name(enc_rs));
4435 }
4436 }
4437 }
4438}
4439
4440static void
4441prepare_getline_args(int argc, VALUE *argv, struct getline_arg *args, VALUE io)
4442{
4443 VALUE opts;
4444 argc = rb_scan_args(argc, argv, "02:", NULL, NULL, &opts);
4445 extract_getline_args(argc, argv, args);
4446 extract_getline_opts(opts, args);
4447 check_getline_args(&args->rs, &args->limit, io);
4448}
4449
4450static VALUE
4451rb_io_getline_0(VALUE rs, long limit, int chomp, rb_io_t *fptr)
4452{
4453 VALUE str = Qnil;
4454 int nolimit = 0;
4455 rb_encoding *enc;
4456
4458 if (NIL_P(rs) && limit < 0) {
4459 str = read_all(fptr, 0, Qnil);
4460 if (RSTRING_LEN(str) == 0) return Qnil;
4461 }
4462 else if (limit == 0) {
4463 return rb_enc_str_new(0, 0, io_read_encoding(fptr));
4464 }
4465 else if (rs == rb_default_rs && limit < 0 && !NEED_READCONV(fptr) &&
4466 rb_enc_asciicompat(enc = io_read_encoding(fptr))) {
4467 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4468 return rb_io_getline_fast(fptr, enc, chomp);
4469 }
4470 else {
4471 int c, newline = -1;
4472 const char *rsptr = 0;
4473 long rslen = 0;
4474 int rspara = 0;
4475 int extra_limit = 16;
4476 int chomp_cr = chomp;
4477
4478 SET_BINARY_MODE(fptr);
4479 enc = io_read_encoding(fptr);
4480
4481 if (!NIL_P(rs)) {
4482 rslen = RSTRING_LEN(rs);
4483 if (rslen == 0) {
4484 rsptr = "\n\n";
4485 rslen = 2;
4486 rspara = 1;
4487 swallow(fptr, '\n');
4488 rs = 0;
4489 if (!rb_enc_asciicompat(enc)) {
4490 rs = rb_usascii_str_new(rsptr, rslen);
4491 rs = rb_str_conv_enc(rs, 0, enc);
4492 OBJ_FREEZE(rs);
4493 rsptr = RSTRING_PTR(rs);
4494 rslen = RSTRING_LEN(rs);
4495 }
4496 newline = '\n';
4497 }
4498 else if (rb_enc_mbminlen(enc) == 1) {
4499 rsptr = RSTRING_PTR(rs);
4500 newline = (unsigned char)rsptr[rslen - 1];
4501 }
4502 else {
4503 rs = rb_str_conv_enc(rs, 0, enc);
4504 rsptr = RSTRING_PTR(rs);
4505 const char *e = rsptr + rslen;
4506 const char *last = rb_enc_prev_char(rsptr, e, e, enc);
4507 int n;
4508 newline = rb_enc_codepoint_len(last, e, &n, enc);
4509 if (last + n != e) rb_raise(rb_eArgError, "broken separator");
4510 }
4511 chomp_cr = chomp && newline == '\n' && rslen == rb_enc_mbminlen(enc);
4512 }
4513
4514 /* MS - Optimization */
4515 while ((c = appendline(fptr, newline, &str, &limit, enc)) != EOF) {
4516 const char *s, *p, *pp, *e;
4517
4518 if (c == newline && RSTRING_LEN(str) >= rslen) {
4519 s = RSTRING_PTR(str);
4520 e = RSTRING_END(str);
4521 p = e - rslen;
4522 if (at_char_boundary(s, p, e, enc)) {
4523 if (!rspara) rscheck(rsptr, rslen, rs);
4524 if (memcmp(p, rsptr, rslen) == 0) {
4525 if (chomp) {
4526 if (chomp_cr && p > s && *(p-1) == '\r') --p;
4527 rb_str_set_len(str, p - s);
4528 }
4529 break;
4530 }
4531 }
4532 }
4533 if (limit == 0) {
4534 s = RSTRING_PTR(str);
4535 p = RSTRING_END(str);
4536 pp = rb_enc_prev_char(s, p, p, enc);
4537 if (extra_limit && pp &&
4538 MBCLEN_NEEDMORE_P(rb_enc_precise_mbclen(pp, p, enc))) {
4539 /* relax the limit while incomplete character.
4540 * extra_limit limits the relax length */
4541 limit = 1;
4542 extra_limit--;
4543 }
4544 else {
4545 nolimit = 1;
4546 break;
4547 }
4548 }
4549 }
4550
4551 if (rspara && c != EOF)
4552 swallow(fptr, '\n');
4553 if (!NIL_P(str))
4554 str = io_enc_str(str, fptr);
4555 }
4556
4557 if (!NIL_P(str) && !nolimit) {
4558 fptr->lineno++;
4559 }
4560
4561 return str;
4562}
4563
4564static VALUE
4565rb_io_getline_1(VALUE rs, long limit, int chomp, VALUE io)
4566{
4567 rb_io_t *fptr;
4568 int old_lineno, new_lineno;
4569 VALUE str;
4570
4571 GetOpenFile(io, fptr);
4572 old_lineno = fptr->lineno;
4573 str = rb_io_getline_0(rs, limit, chomp, fptr);
4574 if (!NIL_P(str) && (new_lineno = fptr->lineno) != old_lineno) {
4575 if (io == ARGF.current_file) {
4576 ARGF.lineno += new_lineno - old_lineno;
4577 ARGF.last_lineno = ARGF.lineno;
4578 }
4579 else {
4580 ARGF.last_lineno = new_lineno;
4581 }
4582 }
4583
4584 return str;
4585}
4586
4587static VALUE
4588rb_io_getline(int argc, VALUE *argv, VALUE io)
4589{
4590 struct getline_arg args;
4591
4592 prepare_getline_args(argc, argv, &args, io);
4593 return rb_io_getline_1(args.rs, args.limit, args.chomp, io);
4594}
4595
4596VALUE
4598{
4599 return rb_io_getline_1(rb_default_rs, -1, FALSE, io);
4600}
4601
4602VALUE
4603rb_io_gets_limit_internal(VALUE io, long limit)
4604{
4605 rb_io_t *fptr;
4606 GetOpenFile(io, fptr);
4607 return rb_io_getline_0(rb_default_rs, limit, FALSE, fptr);
4608}
4609
4610VALUE
4611rb_io_gets_internal(VALUE io)
4612{
4613 return rb_io_gets_limit_internal(io, -1);
4614}
4615
4616/*
4617 * call-seq:
4618 * gets(sep = $/, chomp: false) -> string or nil
4619 * gets(limit, chomp: false) -> string or nil
4620 * gets(sep, limit, chomp: false) -> string or nil
4621 *
4622 * Reads and returns a line from the stream;
4623 * assigns the return value to <tt>$_</tt>.
4624 * See {Line IO}[rdoc-ref:IO@Line+IO].
4625 *
4626 * With no arguments given, returns the next line
4627 * as determined by line separator <tt>$/</tt>, or +nil+ if none:
4628 *
4629 * f = File.open('t.txt')
4630 * f.gets # => "First line\n"
4631 * $_ # => "First line\n"
4632 * f.gets # => "\n"
4633 * f.gets # => "Fourth line\n"
4634 * f.gets # => "Fifth line\n"
4635 * f.gets # => nil
4636 * f.close
4637 *
4638 * With only string argument +sep+ given,
4639 * returns the next line as determined by line separator +sep+,
4640 * or +nil+ if none;
4641 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4642 *
4643 * f = File.new('t.txt')
4644 * f.gets('l') # => "First l"
4645 * f.gets('li') # => "ine\nSecond li"
4646 * f.gets('lin') # => "ne\n\nFourth lin"
4647 * f.gets # => "e\n"
4648 * f.close
4649 *
4650 * The two special values for +sep+ are honored:
4651 *
4652 * f = File.new('t.txt')
4653 * # Get all.
4654 * f.gets(nil) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
4655 * f.rewind
4656 * # Get paragraph (up to two line separators).
4657 * f.gets('') # => "First line\nSecond line\n\n"
4658 * f.close
4659 *
4660 * With only integer argument +limit+ given,
4661 * limits the number of bytes in the line;
4662 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4663 *
4664 * # No more than one line.
4665 * File.open('t.txt') {|f| f.gets(10) } # => "First line"
4666 * File.open('t.txt') {|f| f.gets(11) } # => "First line\n"
4667 * File.open('t.txt') {|f| f.gets(12) } # => "First line\n"
4668 *
4669 * With arguments +sep+ and +limit+ given,
4670 * combines the two behaviors
4671 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
4672 *
4673 * Optional keyword argument +chomp+ specifies whether line separators
4674 * are to be omitted:
4675 *
4676 * f = File.open('t.txt')
4677 * # Chomp the lines.
4678 * f.gets(chomp: true) # => "First line"
4679 * f.gets(chomp: true) # => "Second line"
4680 * f.gets(chomp: true) # => ""
4681 * f.gets(chomp: true) # => "Fourth line"
4682 * f.gets(chomp: true) # => "Fifth line"
4683 * f.gets(chomp: true) # => nil
4684 * f.close
4685 *
4686 */
4687
4688static VALUE
4689rb_io_gets_m(int argc, VALUE *argv, VALUE io)
4690{
4691 VALUE str;
4692
4693 str = rb_io_getline(argc, argv, io);
4694 rb_lastline_set(str);
4695
4696 return str;
4697}
4698
4699/*
4700 * call-seq:
4701 * lineno -> integer
4702 *
4703 * Returns the current line number for the stream;
4704 * see {Line Number}[rdoc-ref:IO@Line+Number].
4705 *
4706 */
4707
4708static VALUE
4709rb_io_lineno(VALUE io)
4710{
4711 rb_io_t *fptr;
4712
4713 GetOpenFile(io, fptr);
4715 return INT2NUM(fptr->lineno);
4716}
4717
4718/*
4719 * call-seq:
4720 * lineno = integer -> integer
4721 *
4722 * Sets and returns the line number for the stream;
4723 * see {Line Number}[rdoc-ref:IO@Line+Number].
4724 *
4725 */
4726
4727static VALUE
4728rb_io_set_lineno(VALUE io, VALUE lineno)
4729{
4730 rb_io_t *fptr;
4731
4732 GetOpenFile(io, fptr);
4734 fptr->lineno = NUM2INT(lineno);
4735 return lineno;
4736}
4737
4738/* :nodoc: */
4739static VALUE
4740io_readline(rb_execution_context_t *ec, VALUE io, VALUE sep, VALUE lim, VALUE chomp)
4741{
4742 long limit = -1;
4743 if (NIL_P(lim)) {
4744 VALUE tmp = Qnil;
4745 // If sep is specified, but it's not a string and not nil, then assume
4746 // it's the limit (it should be an integer)
4747 if (!NIL_P(sep) && NIL_P(tmp = rb_check_string_type(sep))) {
4748 // If the user has specified a non-nil / non-string value
4749 // for the separator, we assume it's the limit and set the
4750 // separator to default: rb_rs.
4751 lim = sep;
4752 limit = NUM2LONG(lim);
4753 sep = rb_rs;
4754 }
4755 else {
4756 sep = tmp;
4757 }
4758 }
4759 else {
4760 if (!NIL_P(sep)) StringValue(sep);
4761 limit = NUM2LONG(lim);
4762 }
4763
4764 check_getline_args(&sep, &limit, io);
4765
4766 VALUE line = rb_io_getline_1(sep, limit, RTEST(chomp), io);
4767 rb_lastline_set_up(line, 1);
4768
4769 if (NIL_P(line)) {
4770 rb_eof_error();
4771 }
4772 return line;
4773}
4774
4775static VALUE io_readlines(const struct getline_arg *arg, VALUE io);
4776
4777/*
4778 * call-seq:
4779 * readlines(sep = $/, chomp: false) -> array
4780 * readlines(limit, chomp: false) -> array
4781 * readlines(sep, limit, chomp: false) -> array
4782 *
4783 * Reads and returns all remaining line from the stream;
4784 * does not modify <tt>$_</tt>.
4785 * See {Line IO}[rdoc-ref:IO@Line+IO].
4786 *
4787 * With no arguments given, returns lines
4788 * as determined by line separator <tt>$/</tt>, or +nil+ if none:
4789 *
4790 * f = File.new('t.txt')
4791 * f.readlines
4792 * # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
4793 * f.readlines # => []
4794 * f.close
4795 *
4796 * With only string argument +sep+ given,
4797 * returns lines as determined by line separator +sep+,
4798 * or +nil+ if none;
4799 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4800 *
4801 * f = File.new('t.txt')
4802 * f.readlines('li')
4803 * # => ["First li", "ne\nSecond li", "ne\n\nFourth li", "ne\nFifth li", "ne\n"]
4804 * f.close
4805 *
4806 * The two special values for +sep+ are honored:
4807 *
4808 * f = File.new('t.txt')
4809 * # Get all into one string.
4810 * f.readlines(nil)
4811 * # => ["First line\nSecond line\n\nFourth line\nFifth line\n"]
4812 * # Get paragraphs (up to two line separators).
4813 * f.rewind
4814 * f.readlines('')
4815 * # => ["First line\nSecond line\n\n", "Fourth line\nFifth line\n"]
4816 * f.close
4817 *
4818 * With only integer argument +limit+ given,
4819 * limits the number of bytes in each line;
4820 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4821 *
4822 * f = File.new('t.txt')
4823 * f.readlines(8)
4824 * # => ["First li", "ne\n", "Second l", "ine\n", "\n", "Fourth l", "ine\n", "Fifth li", "ne\n"]
4825 * f.close
4826 *
4827 * With arguments +sep+ and +limit+ given,
4828 * combines the two behaviors
4829 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
4830 *
4831 * Optional keyword argument +chomp+ specifies whether line separators
4832 * are to be omitted:
4833 *
4834 * f = File.new('t.txt')
4835 * f.readlines(chomp: true)
4836 * # => ["First line", "Second line", "", "Fourth line", "Fifth line"]
4837 * f.close
4838 *
4839 */
4840
4841static VALUE
4842rb_io_readlines(int argc, VALUE *argv, VALUE io)
4843{
4844 struct getline_arg args;
4845
4846 prepare_getline_args(argc, argv, &args, io);
4847 return io_readlines(&args, io);
4848}
4849
4850static VALUE
4851io_readlines(const struct getline_arg *arg, VALUE io)
4852{
4853 VALUE line, ary;
4854
4855 if (arg->limit == 0)
4856 rb_raise(rb_eArgError, "invalid limit: 0 for readlines");
4857 ary = rb_ary_new();
4858 while (!NIL_P(line = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, io))) {
4859 rb_ary_push(ary, line);
4860 }
4861 return ary;
4862}
4863
4864/*
4865 * call-seq:
4866 * each_line(sep = $/, chomp: false) {|line| ... } -> self
4867 * each_line(limit, chomp: false) {|line| ... } -> self
4868 * each_line(sep, limit, chomp: false) {|line| ... } -> self
4869 * each_line -> enumerator
4870 *
4871 * Calls the block with each remaining line read from the stream;
4872 * returns +self+.
4873 * Does nothing if already at end-of-stream;
4874 * See {Line IO}[rdoc-ref:IO@Line+IO].
4875 *
4876 * With no arguments given, reads lines
4877 * as determined by line separator <tt>$/</tt>:
4878 *
4879 * f = File.new('t.txt')
4880 * f.each_line {|line| p line }
4881 * f.each_line {|line| fail 'Cannot happen' }
4882 * f.close
4883 *
4884 * Output:
4885 *
4886 * "First line\n"
4887 * "Second line\n"
4888 * "\n"
4889 * "Fourth line\n"
4890 * "Fifth line\n"
4891 *
4892 * With only string argument +sep+ given,
4893 * reads lines as determined by line separator +sep+;
4894 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4895 *
4896 * f = File.new('t.txt')
4897 * f.each_line('li') {|line| p line }
4898 * f.close
4899 *
4900 * Output:
4901 *
4902 * "First li"
4903 * "ne\nSecond li"
4904 * "ne\n\nFourth li"
4905 * "ne\nFifth li"
4906 * "ne\n"
4907 *
4908 * The two special values for +sep+ are honored:
4909 *
4910 * f = File.new('t.txt')
4911 * # Get all into one string.
4912 * f.each_line(nil) {|line| p line }
4913 * f.close
4914 *
4915 * Output:
4916 *
4917 * "First line\nSecond line\n\nFourth line\nFifth line\n"
4918 *
4919 * f.rewind
4920 * # Get paragraphs (up to two line separators).
4921 * f.each_line('') {|line| p line }
4922 *
4923 * Output:
4924 *
4925 * "First line\nSecond line\n\n"
4926 * "Fourth line\nFifth line\n"
4927 *
4928 * With only integer argument +limit+ given,
4929 * limits the number of bytes in each line;
4930 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4931 *
4932 * f = File.new('t.txt')
4933 * f.each_line(8) {|line| p line }
4934 * f.close
4935 *
4936 * Output:
4937 *
4938 * "First li"
4939 * "ne\n"
4940 * "Second l"
4941 * "ine\n"
4942 * "\n"
4943 * "Fourth l"
4944 * "ine\n"
4945 * "Fifth li"
4946 * "ne\n"
4947 *
4948 * With arguments +sep+ and +limit+ given,
4949 * combines the two behaviors
4950 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
4951 *
4952 * Optional keyword argument +chomp+ specifies whether line separators
4953 * are to be omitted:
4954 *
4955 * f = File.new('t.txt')
4956 * f.each_line(chomp: true) {|line| p line }
4957 * f.close
4958 *
4959 * Output:
4960 *
4961 * "First line"
4962 * "Second line"
4963 * ""
4964 * "Fourth line"
4965 * "Fifth line"
4966 *
4967 * Returns an Enumerator if no block is given.
4968 */
4969
4970static VALUE
4971rb_io_each_line(int argc, VALUE *argv, VALUE io)
4972{
4973 VALUE str;
4974 struct getline_arg args;
4975
4976 RETURN_ENUMERATOR(io, argc, argv);
4977 prepare_getline_args(argc, argv, &args, io);
4978 if (args.limit == 0)
4979 rb_raise(rb_eArgError, "invalid limit: 0 for each_line");
4980 while (!NIL_P(str = rb_io_getline_1(args.rs, args.limit, args.chomp, io))) {
4981 rb_yield(str);
4982 }
4983 return io;
4984}
4985
4986/*
4987 * call-seq:
4988 * each_byte {|byte| ... } -> self
4989 * each_byte -> enumerator
4990 *
4991 * Calls the given block with each byte (0..255) in the stream; returns +self+.
4992 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
4993 *
4994 * File.read('t.ja') # => "こんにちは"
4995 * f = File.new('t.ja')
4996 * a = []
4997 * f.each_byte {|b| a << b }
4998 * a # => [227, 129, 147, 227, 130, 147, 227, 129, 171, 227, 129, 161, 227, 129, 175]
4999 * f.close
5000 *
5001 * Returns an Enumerator if no block is given.
5002 *
5003 * Related: IO#each_char, IO#each_codepoint.
5004 *
5005 */
5006
5007static VALUE
5008rb_io_each_byte(VALUE io)
5009{
5010 rb_io_t *fptr;
5011
5012 RETURN_ENUMERATOR(io, 0, 0);
5013 GetOpenFile(io, fptr);
5014
5015 do {
5016 while (fptr->rbuf.len > 0) {
5017 char *p = fptr->rbuf.ptr + fptr->rbuf.off++;
5018 fptr->rbuf.len--;
5019 rb_yield(INT2FIX(*p & 0xff));
5021 errno = 0;
5022 }
5023 READ_CHECK(fptr);
5024 } while (io_fillbuf(fptr) >= 0);
5025 return io;
5026}
5027
5028static VALUE
5029io_getc(rb_io_t *fptr, rb_encoding *enc)
5030{
5031 int r, n, cr = 0;
5032 VALUE str;
5033
5034 if (NEED_READCONV(fptr)) {
5035 rb_encoding *read_enc = io_read_encoding(fptr);
5036
5037 str = Qnil;
5038 SET_BINARY_MODE(fptr);
5039 make_readconv(fptr, 0);
5040
5041 while (1) {
5042 if (fptr->cbuf.len) {
5043 r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
5044 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
5045 read_enc);
5046 if (!MBCLEN_NEEDMORE_P(r))
5047 break;
5048 if (fptr->cbuf.len == fptr->cbuf.capa) {
5049 rb_raise(rb_eIOError, "too long character");
5050 }
5051 }
5052
5053 if (more_char(fptr) == MORE_CHAR_FINISHED) {
5054 if (fptr->cbuf.len == 0) {
5055 clear_readconv(fptr);
5056 return Qnil;
5057 }
5058 /* return an unit of an incomplete character just before EOF */
5059 str = rb_enc_str_new(fptr->cbuf.ptr+fptr->cbuf.off, 1, read_enc);
5060 fptr->cbuf.off += 1;
5061 fptr->cbuf.len -= 1;
5062 if (fptr->cbuf.len == 0) clear_readconv(fptr);
5064 return str;
5065 }
5066 }
5067 if (MBCLEN_INVALID_P(r)) {
5068 r = rb_enc_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
5069 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
5070 read_enc);
5071 io_shift_cbuf(fptr, r, &str);
5073 }
5074 else {
5075 io_shift_cbuf(fptr, MBCLEN_CHARFOUND_LEN(r), &str);
5077 if (MBCLEN_CHARFOUND_LEN(r) == 1 && rb_enc_asciicompat(read_enc) &&
5078 ISASCII(RSTRING_PTR(str)[0])) {
5079 cr = ENC_CODERANGE_7BIT;
5080 }
5081 }
5082 str = io_enc_str(str, fptr);
5083 ENC_CODERANGE_SET(str, cr);
5084 return str;
5085 }
5086
5087 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
5088 if (io_fillbuf(fptr) < 0) {
5089 return Qnil;
5090 }
5091 if (rb_enc_asciicompat(enc) && ISASCII(fptr->rbuf.ptr[fptr->rbuf.off])) {
5092 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, 1);
5093 fptr->rbuf.off += 1;
5094 fptr->rbuf.len -= 1;
5095 cr = ENC_CODERANGE_7BIT;
5096 }
5097 else {
5098 r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off, fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
5099 if (MBCLEN_CHARFOUND_P(r) &&
5100 (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
5101 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, n);
5102 fptr->rbuf.off += n;
5103 fptr->rbuf.len -= n;
5105 }
5106 else if (MBCLEN_NEEDMORE_P(r)) {
5107 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, fptr->rbuf.len);
5108 fptr->rbuf.len = 0;
5109 getc_needmore:
5110 if (io_fillbuf(fptr) != -1) {
5111 rb_str_cat(str, fptr->rbuf.ptr+fptr->rbuf.off, 1);
5112 fptr->rbuf.off++;
5113 fptr->rbuf.len--;
5114 r = rb_enc_precise_mbclen(RSTRING_PTR(str), RSTRING_PTR(str)+RSTRING_LEN(str), enc);
5115 if (MBCLEN_NEEDMORE_P(r)) {
5116 goto getc_needmore;
5117 }
5118 else if (MBCLEN_CHARFOUND_P(r)) {
5120 }
5121 }
5122 }
5123 else {
5124 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, 1);
5125 fptr->rbuf.off++;
5126 fptr->rbuf.len--;
5127 }
5128 }
5129 if (!cr) cr = ENC_CODERANGE_BROKEN;
5130 str = io_enc_str(str, fptr);
5131 ENC_CODERANGE_SET(str, cr);
5132 return str;
5133}
5134
5135/*
5136 * call-seq:
5137 * each_char {|c| ... } -> self
5138 * each_char -> enumerator
5139 *
5140 * Calls the given block with each character in the stream; returns +self+.
5141 * See {Character IO}[rdoc-ref:IO@Character+IO].
5142 *
5143 * File.read('t.ja') # => "こんにちは"
5144 * f = File.new('t.ja')
5145 * a = []
5146 * f.each_char {|c| a << c.ord }
5147 * a # => [12371, 12435, 12395, 12385, 12399]
5148 * f.close
5149 *
5150 * Returns an Enumerator if no block is given.
5151 *
5152 * Related: IO#each_byte, IO#each_codepoint.
5153 *
5154 */
5155
5156static VALUE
5157rb_io_each_char(VALUE io)
5158{
5159 rb_io_t *fptr;
5160 rb_encoding *enc;
5161 VALUE c;
5162
5163 RETURN_ENUMERATOR(io, 0, 0);
5164 GetOpenFile(io, fptr);
5166
5167 enc = io_input_encoding(fptr);
5168 READ_CHECK(fptr);
5169 while (!NIL_P(c = io_getc(fptr, enc))) {
5170 rb_yield(c);
5171 }
5172 return io;
5173}
5174
5175/*
5176 * call-seq:
5177 * each_codepoint {|c| ... } -> self
5178 * each_codepoint -> enumerator
5179 *
5180 * Calls the given block with each codepoint in the stream; returns +self+:
5181 *
5182 * File.read('t.ja') # => "こんにちは"
5183 * f = File.new('t.ja')
5184 * a = []
5185 * f.each_codepoint {|c| a << c }
5186 * a # => [12371, 12435, 12395, 12385, 12399]
5187 * f.close
5188 *
5189 * Returns an Enumerator if no block is given.
5190 *
5191 * Related: IO#each_byte, IO#each_char.
5192 *
5193 */
5194
5195static VALUE
5196rb_io_each_codepoint(VALUE io)
5197{
5198 rb_io_t *fptr;
5199 rb_encoding *enc;
5200 unsigned int c;
5201 int r, n;
5202
5203 RETURN_ENUMERATOR(io, 0, 0);
5204 GetOpenFile(io, fptr);
5206
5207 READ_CHECK(fptr);
5208 enc = io_read_encoding(fptr);
5209 if (NEED_READCONV(fptr)) {
5210 SET_BINARY_MODE(fptr);
5211 r = 1; /* no invalid char yet */
5212 for (;;) {
5213 make_readconv(fptr, 0);
5214 for (;;) {
5215 if (fptr->cbuf.len) {
5216 r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
5217 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
5218 enc);
5219 if (!MBCLEN_NEEDMORE_P(r))
5220 break;
5221 if (fptr->cbuf.len == fptr->cbuf.capa) {
5222 rb_raise(rb_eIOError, "too long character");
5223 }
5224 }
5225 if (more_char(fptr) == MORE_CHAR_FINISHED) {
5226 clear_readconv(fptr);
5227 if (!MBCLEN_CHARFOUND_P(r)) {
5228 goto invalid;
5229 }
5230 return io;
5231 }
5232 }
5233 if (MBCLEN_INVALID_P(r)) {
5234 goto invalid;
5235 }
5236 n = MBCLEN_CHARFOUND_LEN(r);
5237 c = rb_enc_codepoint(fptr->cbuf.ptr+fptr->cbuf.off,
5238 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
5239 enc);
5240 fptr->cbuf.off += n;
5241 fptr->cbuf.len -= n;
5242 rb_yield(UINT2NUM(c));
5244 }
5245 }
5246 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
5247 while (io_fillbuf(fptr) >= 0) {
5248 r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off,
5249 fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
5250 if (MBCLEN_CHARFOUND_P(r) &&
5251 (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
5252 c = rb_enc_codepoint(fptr->rbuf.ptr+fptr->rbuf.off,
5253 fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
5254 fptr->rbuf.off += n;
5255 fptr->rbuf.len -= n;
5256 rb_yield(UINT2NUM(c));
5257 }
5258 else if (MBCLEN_INVALID_P(r)) {
5259 goto invalid;
5260 }
5261 else if (MBCLEN_NEEDMORE_P(r)) {
5262 char cbuf[8], *p = cbuf;
5263 int more = MBCLEN_NEEDMORE_LEN(r);
5264 if (more > numberof(cbuf)) goto invalid;
5265 more += n = fptr->rbuf.len;
5266 if (more > numberof(cbuf)) goto invalid;
5267 while ((n = (int)read_buffered_data(p, more, fptr)) > 0 &&
5268 (p += n, (more -= n) > 0)) {
5269 if (io_fillbuf(fptr) < 0) goto invalid;
5270 if ((n = fptr->rbuf.len) > more) n = more;
5271 }
5272 r = rb_enc_precise_mbclen(cbuf, p, enc);
5273 if (!MBCLEN_CHARFOUND_P(r)) goto invalid;
5274 c = rb_enc_codepoint(cbuf, p, enc);
5275 rb_yield(UINT2NUM(c));
5276 }
5277 else {
5278 continue;
5279 }
5281 }
5282 return io;
5283
5284 invalid:
5285 rb_raise(rb_eArgError, "invalid byte sequence in %s", rb_enc_name(enc));
5287}
5288
5289/*
5290 * call-seq:
5291 * getc -> character or nil
5292 *
5293 * Reads and returns the next 1-character string from the stream;
5294 * returns +nil+ if already at end-of-stream.
5295 * See {Character IO}[rdoc-ref:IO@Character+IO].
5296 *
5297 * f = File.open('t.txt')
5298 * f.getc # => "F"
5299 * f.close
5300 * File.read('t.ja') # => "こんにちは"
5301 * f = File.open('t.ja')
5302 * f.getc.ord # => 12371
5303 * f.close
5304 *
5305 * Related: IO#readchar (may raise EOFError).
5306 *
5307 */
5308
5309static VALUE
5310rb_io_getc(VALUE io)
5311{
5312 rb_io_t *fptr;
5313 rb_encoding *enc;
5314
5315 GetOpenFile(io, fptr);
5317
5318 enc = io_input_encoding(fptr);
5319 READ_CHECK(fptr);
5320 return io_getc(fptr, enc);
5321}
5322
5323/*
5324 * call-seq:
5325 * readchar -> string
5326 *
5327 * Reads and returns the next 1-character string from the stream;
5328 * raises EOFError if already at end-of-stream.
5329 * See {Character IO}[rdoc-ref:IO@Character+IO].
5330 *
5331 * f = File.open('t.txt')
5332 * f.readchar # => "F"
5333 * f.close
5334 * File.read('t.ja') # => "こんにちは"
5335 * f = File.open('t.ja')
5336 * f.readchar.ord # => 12371
5337 * f.close
5338 *
5339 * Related: IO#getc (will not raise EOFError).
5340 *
5341 */
5342
5343static VALUE
5344rb_io_readchar(VALUE io)
5345{
5346 VALUE c = rb_io_getc(io);
5347
5348 if (NIL_P(c)) {
5349 rb_eof_error();
5350 }
5351 return c;
5352}
5353
5354/*
5355 * call-seq:
5356 * getbyte -> integer or nil
5357 *
5358 * Reads and returns the next byte (in range 0..255) from the stream;
5359 * returns +nil+ if already at end-of-stream.
5360 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5361 *
5362 * f = File.open('t.txt')
5363 * f.getbyte # => 70
5364 * f.close
5365 * File.read('t.ja') # => "こんにちは"
5366 * f = File.open('t.ja')
5367 * f.getbyte # => 227
5368 * f.close
5369 *
5370 * Related: IO#readbyte (may raise EOFError).
5371 */
5372
5373VALUE
5375{
5376 rb_io_t *fptr;
5377 int c;
5378
5379 GetOpenFile(io, fptr);
5381 READ_CHECK(fptr);
5382 VALUE r_stdout = rb_ractor_stdout();
5383 if (fptr->fd == 0 && (fptr->mode & FMODE_TTY) && RB_TYPE_P(r_stdout, T_FILE)) {
5384 rb_io_t *ofp;
5385 GetOpenFile(r_stdout, ofp);
5386 if (ofp->mode & FMODE_TTY) {
5387 rb_io_flush(r_stdout);
5388 }
5389 }
5390 if (io_fillbuf(fptr) < 0) {
5391 return Qnil;
5392 }
5393 fptr->rbuf.off++;
5394 fptr->rbuf.len--;
5395 c = (unsigned char)fptr->rbuf.ptr[fptr->rbuf.off-1];
5396 return INT2FIX(c & 0xff);
5397}
5398
5399/*
5400 * call-seq:
5401 * readbyte -> integer
5402 *
5403 * Reads and returns the next byte (in range 0..255) from the stream;
5404 * raises EOFError if already at end-of-stream.
5405 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5406 *
5407 * f = File.open('t.txt')
5408 * f.readbyte # => 70
5409 * f.close
5410 * File.read('t.ja') # => "こんにちは"
5411 * f = File.open('t.ja')
5412 * f.readbyte # => 227
5413 * f.close
5414 *
5415 * Related: IO#getbyte (will not raise EOFError).
5416 *
5417 */
5418
5419static VALUE
5420rb_io_readbyte(VALUE io)
5421{
5422 VALUE c = rb_io_getbyte(io);
5423
5424 if (NIL_P(c)) {
5425 rb_eof_error();
5426 }
5427 return c;
5428}
5429
5430/*
5431 * call-seq:
5432 * ungetbyte(integer) -> nil
5433 * ungetbyte(string) -> nil
5434 *
5435 * Pushes back ("unshifts") the given data onto the stream's buffer,
5436 * placing the data so that it is next to be read; returns +nil+.
5437 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5438 *
5439 * Note that:
5440 *
5441 * - Calling the method has no effect with unbuffered reads (such as IO#sysread).
5442 * - Calling #rewind on the stream discards the pushed-back data.
5443 *
5444 * When argument +integer+ is given, uses only its low-order byte:
5445 *
5446 * File.write('t.tmp', '012')
5447 * f = File.open('t.tmp')
5448 * f.ungetbyte(0x41) # => nil
5449 * f.read # => "A012"
5450 * f.rewind
5451 * f.ungetbyte(0x4243) # => nil
5452 * f.read # => "C012"
5453 * f.close
5454 *
5455 * When argument +string+ is given, uses all bytes:
5456 *
5457 * File.write('t.tmp', '012')
5458 * f = File.open('t.tmp')
5459 * f.ungetbyte('A') # => nil
5460 * f.read # => "A012"
5461 * f.rewind
5462 * f.ungetbyte('BCDE') # => nil
5463 * f.read # => "BCDE012"
5464 * f.close
5465 *
5466 */
5467
5468VALUE
5470{
5471 rb_io_t *fptr;
5472
5473 GetOpenFile(io, fptr);
5475 switch (TYPE(b)) {
5476 case T_NIL:
5477 return Qnil;
5478 case T_FIXNUM:
5479 case T_BIGNUM: ;
5480 VALUE v = rb_int_modulo(b, INT2FIX(256));
5481 unsigned char c = NUM2INT(v) & 0xFF;
5482 b = rb_str_new((const char *)&c, 1);
5483 break;
5484 default:
5485 StringValue(b);
5486 }
5487 io_ungetbyte(b, fptr);
5488 return Qnil;
5489}
5490
5491/*
5492 * call-seq:
5493 * ungetc(integer) -> nil
5494 * ungetc(string) -> nil
5495 *
5496 * Pushes back ("unshifts") the given data onto the stream's buffer,
5497 * placing the data so that it is next to be read; returns +nil+.
5498 * See {Character IO}[rdoc-ref:IO@Character+IO].
5499 *
5500 * Note that:
5501 *
5502 * - Calling the method has no effect with unbuffered reads (such as IO#sysread).
5503 * - Calling #rewind on the stream discards the pushed-back data.
5504 *
5505 * When argument +integer+ is given, interprets the integer as a character:
5506 *
5507 * File.write('t.tmp', '012')
5508 * f = File.open('t.tmp')
5509 * f.ungetc(0x41) # => nil
5510 * f.read # => "A012"
5511 * f.rewind
5512 * f.ungetc(0x0442) # => nil
5513 * f.getc.ord # => 1090
5514 * f.close
5515 *
5516 * When argument +string+ is given, uses all characters:
5517 *
5518 * File.write('t.tmp', '012')
5519 * f = File.open('t.tmp')
5520 * f.ungetc('A') # => nil
5521 * f.read # => "A012"
5522 * f.rewind
5523 * f.ungetc("\u0442\u0435\u0441\u0442") # => nil
5524 * f.getc.ord # => 1090
5525 * f.getc.ord # => 1077
5526 * f.getc.ord # => 1089
5527 * f.getc.ord # => 1090
5528 * f.close
5529 *
5530 */
5531
5532VALUE
5534{
5535 rb_io_t *fptr;
5536 long len;
5537
5538 GetOpenFile(io, fptr);
5540 if (FIXNUM_P(c)) {
5541 c = rb_enc_uint_chr(FIX2UINT(c), io_read_encoding(fptr));
5542 }
5543 else if (RB_BIGNUM_TYPE_P(c)) {
5544 c = rb_enc_uint_chr(NUM2UINT(c), io_read_encoding(fptr));
5545 }
5546 else {
5547 StringValue(c);
5548 }
5549 if (NEED_READCONV(fptr)) {
5550 SET_BINARY_MODE(fptr);
5551 len = RSTRING_LEN(c);
5552#if SIZEOF_LONG > SIZEOF_INT
5553 if (len > INT_MAX)
5554 rb_raise(rb_eIOError, "ungetc failed");
5555#endif
5556 make_readconv(fptr, (int)len);
5557 if (fptr->cbuf.capa - fptr->cbuf.len < len)
5558 rb_raise(rb_eIOError, "ungetc failed");
5559 if (fptr->cbuf.off < len) {
5560 MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.capa-fptr->cbuf.len,
5561 fptr->cbuf.ptr+fptr->cbuf.off,
5562 char, fptr->cbuf.len);
5563 fptr->cbuf.off = fptr->cbuf.capa-fptr->cbuf.len;
5564 }
5565 fptr->cbuf.off -= (int)len;
5566 fptr->cbuf.len += (int)len;
5567 MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.off, RSTRING_PTR(c), char, len);
5568 }
5569 else {
5570 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
5571 io_ungetbyte(c, fptr);
5572 }
5573 return Qnil;
5574}
5575
5576/*
5577 * call-seq:
5578 * isatty -> true or false
5579 *
5580 * Returns +true+ if the stream is associated with a terminal device (tty),
5581 * +false+ otherwise:
5582 *
5583 * f = File.new('t.txt').isatty #=> false
5584 * f.close
5585 * f = File.new('/dev/tty').isatty #=> true
5586 * f.close
5587 *
5588 */
5589
5590static VALUE
5591rb_io_isatty(VALUE io)
5592{
5593 rb_io_t *fptr;
5594
5595 GetOpenFile(io, fptr);
5596 return RBOOL(isatty(fptr->fd) != 0);
5597}
5598
5599#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5600/*
5601 * call-seq:
5602 * close_on_exec? -> true or false
5603 *
5604 * Returns +true+ if the stream will be closed on exec, +false+ otherwise:
5605 *
5606 * f = File.open('t.txt')
5607 * f.close_on_exec? # => true
5608 * f.close_on_exec = false
5609 * f.close_on_exec? # => false
5610 * f.close
5611 *
5612 */
5613
5614static VALUE
5615rb_io_close_on_exec_p(VALUE io)
5616{
5617 rb_io_t *fptr;
5618 VALUE write_io;
5619 int fd, ret;
5620
5621 write_io = GetWriteIO(io);
5622 if (io != write_io) {
5623 GetOpenFile(write_io, fptr);
5624 if (fptr && 0 <= (fd = fptr->fd)) {
5625 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5626 if (!(ret & FD_CLOEXEC)) return Qfalse;
5627 }
5628 }
5629
5630 GetOpenFile(io, fptr);
5631 if (fptr && 0 <= (fd = fptr->fd)) {
5632 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5633 if (!(ret & FD_CLOEXEC)) return Qfalse;
5634 }
5635 return Qtrue;
5636}
5637#else
5638#define rb_io_close_on_exec_p rb_f_notimplement
5639#endif
5640
5641#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5642/*
5643 * call-seq:
5644 * self.close_on_exec = bool -> true or false
5645 *
5646 * Sets a close-on-exec flag.
5647 *
5648 * f = File.open(File::NULL)
5649 * f.close_on_exec = true
5650 * system("cat", "/proc/self/fd/#{f.fileno}") # cat: /proc/self/fd/3: No such file or directory
5651 * f.closed? #=> false
5652 *
5653 * Ruby sets close-on-exec flags of all file descriptors by default
5654 * since Ruby 2.0.0.
5655 * So you don't need to set by yourself.
5656 * Also, unsetting a close-on-exec flag can cause file descriptor leak
5657 * if another thread use fork() and exec() (via system() method for example).
5658 * If you really needs file descriptor inheritance to child process,
5659 * use spawn()'s argument such as fd=>fd.
5660 */
5661
5662static VALUE
5663rb_io_set_close_on_exec(VALUE io, VALUE arg)
5664{
5665 int flag = RTEST(arg) ? FD_CLOEXEC : 0;
5666 rb_io_t *fptr;
5667 VALUE write_io;
5668 int fd, ret;
5669
5670 write_io = GetWriteIO(io);
5671 if (io != write_io) {
5672 GetOpenFile(write_io, fptr);
5673 if (fptr && 0 <= (fd = fptr->fd)) {
5674 if ((ret = fcntl(fptr->fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5675 if ((ret & FD_CLOEXEC) != flag) {
5676 ret = (ret & ~FD_CLOEXEC) | flag;
5677 ret = fcntl(fd, F_SETFD, ret);
5678 if (ret != 0) rb_sys_fail_path(fptr->pathv);
5679 }
5680 }
5681
5682 }
5683
5684 GetOpenFile(io, fptr);
5685 if (fptr && 0 <= (fd = fptr->fd)) {
5686 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5687 if ((ret & FD_CLOEXEC) != flag) {
5688 ret = (ret & ~FD_CLOEXEC) | flag;
5689 ret = fcntl(fd, F_SETFD, ret);
5690 if (ret != 0) rb_sys_fail_path(fptr->pathv);
5691 }
5692 }
5693 return Qnil;
5694}
5695#else
5696#define rb_io_set_close_on_exec rb_f_notimplement
5697#endif
5698
5699#define RUBY_IO_EXTERNAL_P(f) ((f)->mode & FMODE_EXTERNAL)
5700#define PREP_STDIO_NAME(f) (RSTRING_PTR((f)->pathv))
5701
5702static VALUE
5703finish_writeconv(rb_io_t *fptr, int noalloc)
5704{
5705 unsigned char *ds, *dp, *de;
5707
5708 if (!fptr->wbuf.ptr) {
5709 unsigned char buf[1024];
5710
5712 while (res == econv_destination_buffer_full) {
5713 ds = dp = buf;
5714 de = buf + sizeof(buf);
5715 res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
5716 while (dp-ds) {
5717 size_t remaining = dp-ds;
5718 long result = rb_io_write_memory(fptr, ds, remaining);
5719
5720 if (result > 0) {
5721 ds += result;
5722 if ((size_t)result == remaining) break;
5723 }
5724 else if (rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
5725 if (fptr->fd < 0)
5726 return noalloc ? Qtrue : rb_exc_new3(rb_eIOError, rb_str_new_cstr(closed_stream));
5727 }
5728 else {
5729 return noalloc ? Qtrue : INT2NUM(errno);
5730 }
5731 }
5732 if (res == econv_invalid_byte_sequence ||
5733 res == econv_incomplete_input ||
5735 return noalloc ? Qtrue : rb_econv_make_exception(fptr->writeconv);
5736 }
5737 }
5738
5739 return Qnil;
5740 }
5741
5743 while (res == econv_destination_buffer_full) {
5744 if (fptr->wbuf.len == fptr->wbuf.capa) {
5745 if (io_fflush(fptr) < 0) {
5746 return noalloc ? Qtrue : INT2NUM(errno);
5747 }
5748 }
5749
5750 ds = dp = (unsigned char *)fptr->wbuf.ptr + fptr->wbuf.off + fptr->wbuf.len;
5751 de = (unsigned char *)fptr->wbuf.ptr + fptr->wbuf.capa;
5752 res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
5753 fptr->wbuf.len += (int)(dp - ds);
5754 if (res == econv_invalid_byte_sequence ||
5755 res == econv_incomplete_input ||
5757 return noalloc ? Qtrue : rb_econv_make_exception(fptr->writeconv);
5758 }
5759 }
5760 return Qnil;
5761}
5762
5764 rb_io_t *fptr;
5765 int noalloc;
5766};
5767
5768static VALUE
5769finish_writeconv_sync(VALUE arg)
5770{
5771 struct finish_writeconv_arg *p = (struct finish_writeconv_arg *)arg;
5772 return finish_writeconv(p->fptr, p->noalloc);
5773}
5774
5775static void*
5776nogvl_close(void *ptr)
5777{
5778 int *fd = ptr;
5779
5780 return (void*)(intptr_t)close(*fd);
5781}
5782
5783static int
5784maygvl_close(int fd, int keepgvl)
5785{
5786 if (keepgvl)
5787 return close(fd);
5788
5789 /*
5790 * close() may block for certain file types (NFS, SO_LINGER sockets,
5791 * inotify), so let other threads run.
5792 */
5793 return IO_WITHOUT_GVL_INT(nogvl_close, &fd);
5794}
5795
5796static void*
5797nogvl_fclose(void *ptr)
5798{
5799 FILE *file = ptr;
5800
5801 return (void*)(intptr_t)fclose(file);
5802}
5803
5804static int
5805maygvl_fclose(FILE *file, int keepgvl)
5806{
5807 if (keepgvl)
5808 return fclose(file);
5809
5810 return IO_WITHOUT_GVL_INT(nogvl_fclose, file);
5811}
5812
5813static void free_io_buffer(rb_io_buffer_t *buf);
5814
5815static void
5816fptr_finalize_flush(rb_io_t *fptr, int noraise, int keepgvl)
5817{
5818 VALUE error = Qnil;
5819 int fd = fptr->fd;
5820 FILE *stdio_file = fptr->stdio_file;
5821 int mode = fptr->mode;
5822
5823 if (fptr->writeconv) {
5824 if (!NIL_P(fptr->write_lock) && !noraise) {
5825 struct finish_writeconv_arg arg;
5826 arg.fptr = fptr;
5827 arg.noalloc = noraise;
5828 error = rb_mutex_synchronize(fptr->write_lock, finish_writeconv_sync, (VALUE)&arg);
5829 }
5830 else {
5831 error = finish_writeconv(fptr, noraise);
5832 }
5833 }
5834 /* Do not flush the write buffer on close when the stream is in sync
5835 * mode. In sync mode Ruby's write buffer is not authoritative (writes go
5836 * straight to the OS), so any bytes left in the buffer are the result of
5837 * writes made while sync was disabled. Setting sync = true is therefore a
5838 * way to abandon that pending output rather than replaying it on close,
5839 * which matters after an interrupted write where the amount actually
5840 * written is indeterminate. Call flush before enabling sync if the
5841 * buffered data should still be sent. */
5842 if (fptr->wbuf.len && !(fptr->mode & FMODE_SYNC)) {
5843 if (noraise) {
5844 io_flush_buffer_sync(fptr);
5845 }
5846 else {
5847 if (io_fflush(fptr) < 0 && NIL_P(error)) {
5848 error = INT2NUM(errno);
5849 }
5850 }
5851 }
5852
5853 int done = 0;
5854
5855 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2) {
5856 // Need to keep FILE objects of stdin, stdout and stderr, so we are done:
5857 done = 1;
5858 }
5859
5860 fptr->fd = -1;
5861 fptr->stdio_file = 0;
5863
5864 // Wait for blocking operations to ensure they do not hit EBADF:
5865 rb_thread_io_close_wait(fptr);
5866
5867 if (!done && stdio_file) {
5868 // stdio_file is deallocated anyway even if fclose failed.
5869 if ((maygvl_fclose(stdio_file, noraise) < 0) && NIL_P(error)) {
5870 if (!noraise) {
5871 error = INT2NUM(errno);
5872 }
5873 }
5874
5875 done = 1;
5876 }
5877
5878 VALUE scheduler = rb_fiber_scheduler_current();
5879 if (!done && fd >= 0 && scheduler != Qnil) {
5880 VALUE result = rb_fiber_scheduler_io_close(scheduler, RB_INT2NUM(fd));
5881
5882 if (!UNDEF_P(result)) {
5883 done = RTEST(result);
5884 }
5885 }
5886
5887 if (!done && fd >= 0) {
5888 // fptr->fd may be closed even if close fails. POSIX doesn't specify it.
5889 // We assumes it is closed.
5890
5891 keepgvl |= !(mode & FMODE_WRITABLE);
5892 keepgvl |= noraise;
5893 if ((maygvl_close(fd, keepgvl) < 0) && NIL_P(error)) {
5894 if (!noraise) {
5895 error = INT2NUM(errno);
5896 }
5897 }
5898
5899 done = 1;
5900 }
5901
5902 if (!NIL_P(error) && !noraise) {
5903 if (RB_INTEGER_TYPE_P(error))
5904 rb_syserr_fail_path(NUM2INT(error), fptr->pathv);
5905 else
5906 rb_exc_raise(error);
5907 }
5908}
5909
5910static void
5911fptr_finalize(rb_io_t *fptr, int noraise)
5912{
5913 fptr_finalize_flush(fptr, noraise, FALSE);
5914 free_io_buffer(&fptr->rbuf);
5915 free_io_buffer(&fptr->wbuf);
5916 clear_codeconv(fptr);
5917}
5918
5919static void
5920rb_io_fptr_cleanup(rb_io_t *fptr, int noraise)
5921{
5922 if (fptr->finalize) {
5923 (*fptr->finalize)(fptr, noraise);
5924 }
5925 else {
5926 fptr_finalize(fptr, noraise);
5927 }
5928}
5929
5930static void
5931free_io_buffer(rb_io_buffer_t *buf)
5932{
5933 if (buf->ptr) {
5934 ruby_xfree_sized(buf->ptr, (size_t)buf->capa);
5935 buf->ptr = NULL;
5936 }
5937 buf->off = buf->len = buf->capa = 0;
5938}
5939
5940static void
5941clear_readconv(rb_io_t *fptr)
5942{
5943 if (fptr->readconv) {
5944 rb_econv_close(fptr->readconv);
5945 fptr->readconv = NULL;
5946 }
5947 free_io_buffer(&fptr->cbuf);
5948}
5949
5950static void
5951clear_writeconv(rb_io_t *fptr)
5952{
5953 if (fptr->writeconv) {
5955 fptr->writeconv = NULL;
5956 }
5957 fptr->writeconv_initialized = 0;
5958}
5959
5960static void
5961clear_codeconv(rb_io_t *fptr)
5962{
5963 clear_readconv(fptr);
5964 clear_writeconv(fptr);
5965}
5966
5967static void
5968rb_io_fptr_cleanup_all(rb_io_t *fptr)
5969{
5970 fptr->pathv = Qnil;
5971 if (0 <= fptr->fd)
5972 rb_io_fptr_cleanup(fptr, TRUE);
5973 fptr->write_lock = Qnil;
5974 free_io_buffer(&fptr->rbuf);
5975 free_io_buffer(&fptr->wbuf);
5976 clear_codeconv(fptr);
5977}
5978
5979int
5981{
5982 if (!io) return 0;
5983 rb_io_fptr_cleanup_all(io);
5984 free(io);
5985
5986 return 1;
5987}
5988
5989bool
5990rb_io_fptr_finalize_closed(struct rb_io *io)
5991{
5992 if (!io) return true;
5993 if (io->fd >= 0) return false;
5995 return true;
5996}
5997
5998size_t
5999rb_io_memsize(const rb_io_t *io)
6000{
6001 size_t size = sizeof(rb_io_t);
6002 size += io->rbuf.capa;
6003 size += io->wbuf.capa;
6004 size += io->cbuf.capa;
6005 if (io->readconv) size += rb_econv_memsize(io->readconv);
6006 if (io->writeconv) size += rb_econv_memsize(io->writeconv);
6007
6008 struct rb_io_blocking_operation *blocking_operation = 0;
6009
6010 // 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.
6011 rb_serial_t fork_generation = GET_VM()->fork_gen;
6012 if (io->fork_generation == fork_generation) {
6013 ccan_list_for_each(&io->blocking_operations, blocking_operation, list) {
6014 size += sizeof(struct rb_io_blocking_operation);
6015 }
6016 }
6017
6018 return size;
6019}
6020
6021#ifdef _WIN32
6022/* keep GVL while closing to prevent crash on Windows */
6023# define KEEPGVL TRUE
6024#else
6025# define KEEPGVL FALSE
6026#endif
6027
6028static rb_io_t *
6029io_close_fptr(VALUE io)
6030{
6031 rb_io_t *fptr;
6032 VALUE write_io;
6033 rb_io_t *write_fptr;
6034
6035 write_io = GetWriteIO(io);
6036 if (io != write_io) {
6037 write_fptr = RFILE(write_io)->fptr;
6038 if (write_fptr && 0 <= write_fptr->fd) {
6039 rb_io_fptr_cleanup(write_fptr, TRUE);
6040 }
6041 }
6042
6043 fptr = RFILE(io)->fptr;
6044 if (!fptr) return 0;
6045 if (fptr->fd < 0) return 0;
6046
6047 // This guards against multiple threads closing the same IO object:
6048 if (rb_thread_io_close_interrupt(fptr)) {
6049 /* calls close(fptr->fd): */
6050 fptr_finalize_flush(fptr, FALSE, KEEPGVL);
6051 }
6052
6053 rb_io_fptr_cleanup(fptr, FALSE);
6054 return fptr;
6055}
6056
6057static void
6058fptr_waitpid(rb_io_t *fptr, int nohang)
6059{
6060 int status;
6061 if (fptr->pid) {
6062 rb_last_status_clear();
6063 rb_waitpid(fptr->pid, &status, nohang ? WNOHANG : 0);
6064 fptr->pid = 0;
6065 }
6066}
6067
6068VALUE
6070{
6071 rb_io_t *fptr = io_close_fptr(io);
6072 if (fptr) fptr_waitpid(fptr, 0);
6073 return Qnil;
6074}
6075
6076/*
6077 * call-seq:
6078 * close -> nil
6079 *
6080 * Closes the stream for both reading and writing
6081 * if open for either or both; returns +nil+.
6082 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
6083 *
6084 * If the stream is open for writing, flushes any buffered writes
6085 * to the operating system before closing.
6086 *
6087 * If the stream was opened by IO.popen, sets global variable <tt>$?</tt>
6088 * (child exit status).
6089 *
6090 * It is not an error to close an IO object that has already been closed.
6091 * It just returns nil.
6092 *
6093 * Example:
6094 *
6095 * IO.popen('ruby', 'r+') do |pipe|
6096 * puts pipe.closed?
6097 * pipe.close
6098 * puts $?
6099 * puts pipe.closed?
6100 * end
6101 *
6102 * Output:
6103 *
6104 * false
6105 * pid 13760 exit 0
6106 * true
6107 *
6108 * Related: IO#close_read, IO#close_write, IO#closed?.
6109 */
6110
6111static VALUE
6112rb_io_close_m(VALUE io)
6113{
6114 rb_io_t *fptr = rb_io_get_fptr(io);
6115 if (fptr->fd < 0) {
6116 return Qnil;
6117 }
6118 rb_io_close(io);
6119 return Qnil;
6120}
6121
6122static VALUE
6123io_call_close(VALUE io)
6124{
6125 rb_check_funcall(io, rb_intern("close"), 0, 0);
6126 return io;
6127}
6128
6129static VALUE
6130ignore_closed_stream(VALUE io, VALUE exc)
6131{
6132 enum {mesg_len = sizeof(closed_stream)-1};
6133 VALUE mesg = rb_attr_get(exc, idMesg);
6134 if (!RB_TYPE_P(mesg, T_STRING) ||
6135 RSTRING_LEN(mesg) != mesg_len ||
6136 memcmp(RSTRING_PTR(mesg), closed_stream, mesg_len)) {
6137 rb_exc_raise(exc);
6138 }
6139 return io;
6140}
6141
6142static VALUE
6143io_close(VALUE io)
6144{
6145 VALUE closed = rb_check_funcall(io, rb_intern("closed?"), 0, 0);
6146 if (!UNDEF_P(closed) && RTEST(closed)) return io;
6147 rb_rescue2(io_call_close, io, ignore_closed_stream, io,
6148 rb_eIOError, (VALUE)0);
6149 return io;
6150}
6151
6152/*
6153 * call-seq:
6154 * closed? -> true or false
6155 *
6156 * Returns +true+ if the stream is closed for both reading and writing,
6157 * +false+ otherwise.
6158 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
6159 *
6160 * IO.popen('ruby', 'r+') do |pipe|
6161 * puts pipe.closed?
6162 * pipe.close_read
6163 * puts pipe.closed?
6164 * pipe.close_write
6165 * puts pipe.closed?
6166 * end
6167 *
6168 * Output:
6169 *
6170 * false
6171 * false
6172 * true
6173 *
6174 * Related: IO#close_read, IO#close_write, IO#close.
6175 */
6176VALUE
6178{
6179 rb_io_t *fptr;
6180 VALUE write_io;
6181 rb_io_t *write_fptr;
6182
6183 write_io = GetWriteIO(io);
6184 if (io != write_io) {
6185 write_fptr = RFILE(write_io)->fptr;
6186 if (write_fptr && 0 <= write_fptr->fd) {
6187 return Qfalse;
6188 }
6189 }
6190
6191 fptr = rb_io_get_fptr(io);
6192 return RBOOL(0 > fptr->fd);
6193}
6194
6195/*
6196 * call-seq:
6197 * close_read -> nil
6198 *
6199 * Closes the stream for reading if open for reading;
6200 * returns +nil+.
6201 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
6202 *
6203 * If the stream was opened by IO.popen and is also closed for writing,
6204 * sets global variable <tt>$?</tt> (child exit status).
6205 *
6206 * Example:
6207 *
6208 * IO.popen('ruby', 'r+') do |pipe|
6209 * puts pipe.closed?
6210 * pipe.close_write
6211 * puts pipe.closed?
6212 * pipe.close_read
6213 * puts $?
6214 * puts pipe.closed?
6215 * end
6216 *
6217 * Output:
6218 *
6219 * false
6220 * false
6221 * pid 14748 exit 0
6222 * true
6223 *
6224 * Related: IO#close, IO#close_write, IO#closed?.
6225 */
6226
6227static VALUE
6228rb_io_close_read(VALUE io)
6229{
6230 rb_io_t *fptr;
6231 VALUE write_io;
6232
6233 fptr = rb_io_get_fptr(rb_io_taint_check(io));
6234 if (fptr->fd < 0) return Qnil;
6235 if (is_socket(fptr->fd, fptr->pathv)) {
6236#ifndef SHUT_RD
6237# define SHUT_RD 0
6238#endif
6239 if (shutdown(fptr->fd, SHUT_RD) < 0)
6240 rb_sys_fail_path(fptr->pathv);
6241 fptr->mode &= ~FMODE_READABLE;
6242 if (!(fptr->mode & FMODE_WRITABLE))
6243 return rb_io_close(io);
6244 return Qnil;
6245 }
6246
6247 write_io = GetWriteIO(io);
6248 if (io != write_io) {
6249 rb_io_t *wfptr;
6250 wfptr = rb_io_get_fptr(rb_io_taint_check(write_io));
6251 wfptr->pid = fptr->pid;
6252 fptr->pid = 0;
6253 RFILE(io)->fptr = wfptr;
6254 /* bind to write_io temporarily to get rid of memory/fd leak */
6255 fptr->tied_io_for_writing = 0;
6256 RFILE(write_io)->fptr = fptr;
6257 rb_io_fptr_cleanup(fptr, FALSE);
6258 /* should not finalize fptr because another thread may be reading it */
6259 return Qnil;
6260 }
6261
6262 if ((fptr->mode & (FMODE_DUPLEX|FMODE_WRITABLE)) == FMODE_WRITABLE) {
6263 rb_raise(rb_eIOError, "closing non-duplex IO for reading");
6264 }
6265 return rb_io_close(io);
6266}
6267
6268/*
6269 * call-seq:
6270 * close_write -> nil
6271 *
6272 * Closes the stream for writing if open for writing;
6273 * returns +nil+.
6274 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
6275 *
6276 * Flushes any buffered writes to the operating system before closing.
6277 *
6278 * If the stream was opened by IO.popen and is also closed for reading,
6279 * sets global variable <tt>$?</tt> (child exit status).
6280 *
6281 * IO.popen('ruby', 'r+') do |pipe|
6282 * puts pipe.closed?
6283 * pipe.close_read
6284 * puts pipe.closed?
6285 * pipe.close_write
6286 * puts $?
6287 * puts pipe.closed?
6288 * end
6289 *
6290 * Output:
6291 *
6292 * false
6293 * false
6294 * pid 15044 exit 0
6295 * true
6296 *
6297 * Related: IO#close, IO#close_read, IO#closed?.
6298 */
6299
6300static VALUE
6301rb_io_close_write(VALUE io)
6302{
6303 rb_io_t *fptr;
6304 VALUE write_io;
6305
6306 write_io = GetWriteIO(io);
6307 fptr = rb_io_get_fptr(rb_io_taint_check(write_io));
6308 if (fptr->fd < 0) return Qnil;
6309 if (is_socket(fptr->fd, fptr->pathv)) {
6310#ifndef SHUT_WR
6311# define SHUT_WR 1
6312#endif
6313 /* Flush any buffered data before shutting down the write side.
6314 * Otherwise the buffered bytes are silently dropped here, and a
6315 * subsequent #close would try to flush them into the now
6316 * shutdown(SHUT_WR) socket and fail with EPIPE. This matches the
6317 * behaviour of the non-socket path below, which flushes via
6318 * rb_io_close(). */
6319 if (fptr->mode & FMODE_WRITABLE) {
6320 if (io_fflush(fptr) < 0)
6321 rb_sys_fail_on_write(fptr);
6322 }
6323 if (shutdown(fptr->fd, SHUT_WR) < 0)
6324 rb_sys_fail_path(fptr->pathv);
6325 fptr->mode &= ~FMODE_WRITABLE;
6326 if (!(fptr->mode & FMODE_READABLE))
6327 return rb_io_close(write_io);
6328 return Qnil;
6329 }
6330
6331 if ((fptr->mode & (FMODE_DUPLEX|FMODE_READABLE)) == FMODE_READABLE) {
6332 rb_raise(rb_eIOError, "closing non-duplex IO for writing");
6333 }
6334
6335 if (io != write_io) {
6336 fptr = rb_io_get_fptr(rb_io_taint_check(io));
6337 fptr->tied_io_for_writing = 0;
6338 }
6339 rb_io_close(write_io);
6340 return Qnil;
6341}
6342
6343/*
6344 * call-seq:
6345 * sysseek(offset, whence = IO::SEEK_SET) -> integer
6346 *
6347 * Behaves like IO#seek, except that it:
6348 *
6349 * - Uses low-level system functions.
6350 * - Returns the new position.
6351 *
6352 */
6353
6354static VALUE
6355rb_io_sysseek(int argc, VALUE *argv, VALUE io)
6356{
6357 VALUE offset, ptrname;
6358 int whence = SEEK_SET;
6359 rb_io_t *fptr;
6360 rb_off_t pos;
6361
6362 if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
6363 whence = interpret_seek_whence(ptrname);
6364 }
6365 pos = NUM2OFFT(offset);
6366 GetOpenFile(io, fptr);
6367 if ((fptr->mode & FMODE_READABLE) &&
6368 (READ_DATA_BUFFERED(fptr) || READ_CHAR_PENDING(fptr))) {
6369 rb_raise(rb_eIOError, "sysseek for buffered IO");
6370 }
6371 if ((fptr->mode & FMODE_WRITABLE) && fptr->wbuf.len) {
6372 rb_warn("sysseek for buffered IO");
6373 }
6374 errno = 0;
6375 pos = lseek(fptr->fd, pos, whence);
6376 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
6377
6378 return OFFT2NUM(pos);
6379}
6380
6381/*
6382 * call-seq:
6383 * syswrite(object) -> integer
6384 *
6385 * Writes the given +object+ to self, which must be opened for writing (see Modes);
6386 * returns the number bytes written.
6387 * If +object+ is not a string is converted via method to_s:
6388 *
6389 * f = File.new('t.tmp', 'w')
6390 * f.syswrite('foo') # => 3
6391 * f.syswrite(30) # => 2
6392 * f.syswrite(:foo) # => 3
6393 * f.close
6394 *
6395 * This methods should not be used with other stream-writer methods.
6396 *
6397 */
6398
6399static VALUE
6400rb_io_syswrite(VALUE io, VALUE str)
6401{
6402 VALUE tmp;
6403 rb_io_t *fptr;
6404 long n, len;
6405 const char *ptr;
6406
6407 if (!RB_TYPE_P(str, T_STRING))
6408 str = rb_obj_as_string(str);
6409
6410 io = GetWriteIO(io);
6411 GetOpenFile(io, fptr);
6413
6414 if (fptr->wbuf.len) {
6415 rb_warn("syswrite for buffered IO");
6416 }
6417
6418 tmp = rb_str_tmp_frozen_acquire(str);
6419 RSTRING_GETMEM(tmp, ptr, len);
6420 n = rb_io_write_memory(fptr, ptr, len);
6421 if (n < 0) rb_sys_fail_path(fptr->pathv);
6422 rb_str_tmp_frozen_release(str, tmp);
6423
6424 return LONG2FIX(n);
6425}
6426
6427/*
6428 * call-seq:
6429 * sysread(maxlen) -> string
6430 * sysread(maxlen, out_string) -> string
6431 *
6432 * Behaves like IO#readpartial, except that it uses low-level system functions.
6433 *
6434 * This method should not be used with other stream-reader methods.
6435 *
6436 */
6437
6438static VALUE
6439rb_io_sysread(int argc, VALUE *argv, VALUE io)
6440{
6441 VALUE len, str;
6442 rb_io_t *fptr;
6443 long n, ilen;
6444 struct io_internal_read_struct iis;
6445 int shrinkable;
6446
6447 rb_scan_args(argc, argv, "11", &len, &str);
6448 ilen = NUM2LONG(len);
6449
6450 shrinkable = io_setstrbuf(&str, ilen);
6451 if (ilen == 0) return str;
6452
6453 GetOpenFile(io, fptr);
6455
6456 if (READ_DATA_BUFFERED(fptr)) {
6457 rb_raise(rb_eIOError, "sysread for buffered IO");
6458 }
6459
6460 rb_io_check_closed(fptr);
6461
6462 io_setstrbuf(&str, ilen);
6463 iis.th = rb_thread_current();
6464 iis.fptr = fptr;
6465 iis.nonblock = 0;
6466 iis.fd = fptr->fd;
6467 iis.buf = RSTRING_PTR(str);
6468 iis.capa = ilen;
6469 iis.timeout = NULL;
6470 n = io_read_memory_locktmp(str, &iis);
6471
6472 if (n < 0) {
6473 rb_sys_fail_path(fptr->pathv);
6474 }
6475
6476 io_set_read_length(str, n, shrinkable);
6477
6478 if (n == 0 && ilen > 0) {
6479 rb_eof_error();
6480 }
6481
6482 return str;
6483}
6484
6486 struct rb_io *io;
6487 int fd;
6488 void *buf;
6489 size_t count;
6490 rb_off_t offset;
6491};
6492
6493static VALUE
6494internal_pread_func(void *_arg)
6495{
6496 struct prdwr_internal_arg *arg = _arg;
6497
6498 return (VALUE)pread(arg->fd, arg->buf, arg->count, arg->offset);
6499}
6500
6501static VALUE
6502pread_internal_call(VALUE _arg)
6503{
6504 struct prdwr_internal_arg *arg = (struct prdwr_internal_arg *)_arg;
6505
6506 VALUE scheduler = rb_fiber_scheduler_current();
6507 if (scheduler != Qnil) {
6508 VALUE result = rb_fiber_scheduler_io_pread_memory(scheduler, arg->io->self, arg->offset, arg->buf, arg->count);
6509
6510 if (!UNDEF_P(result)) {
6512 }
6513 }
6514
6515 return rb_io_blocking_region_wait(arg->io, internal_pread_func, arg, RUBY_IO_READABLE);
6516}
6517
6518/*
6519 * call-seq:
6520 * pread(maxlen, offset) -> string
6521 * pread(maxlen, offset, out_string) -> string
6522 *
6523 * Behaves like IO#readpartial, except that it:
6524 *
6525 * - Reads at the given +offset+ (in bytes).
6526 * - Disregards, and does not modify, the stream's position
6527 * (see {Position}[rdoc-ref:IO@Position]).
6528 * - Bypasses any user space buffering in the stream.
6529 *
6530 * Because this method does not disturb the stream's state
6531 * (its position, in particular), +pread+ allows multiple threads and processes
6532 * to use the same \IO object for reading at various offsets.
6533 *
6534 * f = File.open('t.txt')
6535 * f.read # => "First line\nSecond line\n\nFourth line\nFifth line\n"
6536 * f.pos # => 52
6537 * # Read 12 bytes at offset 0.
6538 * f.pread(12, 0) # => "First line\n"
6539 * # Read 9 bytes at offset 8.
6540 * f.pread(9, 8) # => "ne\nSecon"
6541 * f.close
6542 *
6543 * Not available on some platforms.
6544 *
6545 */
6546static VALUE
6547rb_io_pread(int argc, VALUE *argv, VALUE io)
6548{
6549 VALUE len, offset, str;
6550 rb_io_t *fptr;
6551 ssize_t n;
6552 struct prdwr_internal_arg arg;
6553 int shrinkable;
6554
6555 rb_scan_args(argc, argv, "21", &len, &offset, &str);
6556 arg.count = NUM2SIZET(len);
6557 arg.offset = NUM2OFFT(offset);
6558
6559 shrinkable = io_setstrbuf(&str, (long)arg.count);
6560 if (arg.count == 0) return str;
6561 arg.buf = RSTRING_PTR(str);
6562
6563 GetOpenFile(io, fptr);
6565
6566 arg.io = fptr;
6567 arg.fd = fptr->fd;
6568 rb_io_check_closed(fptr);
6569
6570 rb_str_locktmp(str);
6571 n = (ssize_t)rb_ensure(pread_internal_call, (VALUE)&arg, rb_str_unlocktmp, str);
6572
6573 if (n < 0) {
6574 rb_sys_fail_path(fptr->pathv);
6575 }
6576 io_set_read_length(str, n, shrinkable);
6577 if (n == 0 && arg.count > 0) {
6578 rb_eof_error();
6579 }
6580
6581 return str;
6582}
6583
6584static VALUE
6585internal_pwrite_func(void *_arg)
6586{
6587 struct prdwr_internal_arg *arg = _arg;
6588
6589 return (VALUE)pwrite(arg->fd, arg->buf, arg->count, arg->offset);
6590}
6591
6592static VALUE
6593pwrite_internal_call(VALUE _arg)
6594{
6595 struct prdwr_internal_arg *arg = (struct prdwr_internal_arg *)_arg;
6596
6597 VALUE scheduler = rb_fiber_scheduler_current();
6598 if (scheduler != Qnil) {
6599 VALUE result = rb_fiber_scheduler_io_pwrite_memory(scheduler, arg->io->self, arg->offset, arg->buf, arg->count);
6600
6601 if (!UNDEF_P(result)) {
6603 }
6604 }
6605
6606 return rb_io_blocking_region_wait(arg->io, internal_pwrite_func, arg, RUBY_IO_WRITABLE);
6607}
6608
6609/*
6610 * call-seq:
6611 * pwrite(object, offset) -> integer
6612 *
6613 * Behaves like IO#write, except that it:
6614 *
6615 * - Writes at the given +offset+ (in bytes).
6616 * - Disregards, and does not modify, the stream's position
6617 * (see {Position}[rdoc-ref:IO@Position]).
6618 * - Bypasses any user space buffering in the stream.
6619 *
6620 * Because this method does not disturb the stream's state
6621 * (its position, in particular), +pwrite+ allows multiple threads and processes
6622 * to use the same \IO object for writing at various offsets.
6623 *
6624 * f = File.open('t.tmp', 'w+')
6625 * # Write 6 bytes at offset 3.
6626 * f.pwrite('ABCDEF', 3) # => 6
6627 * f.rewind
6628 * f.read # => "\u0000\u0000\u0000ABCDEF"
6629 * f.close
6630 *
6631 * Not available on some platforms.
6632 *
6633 */
6634static VALUE
6635rb_io_pwrite(VALUE io, VALUE str, VALUE offset)
6636{
6637 rb_io_t *fptr;
6638 ssize_t n;
6639 struct prdwr_internal_arg arg;
6640 VALUE tmp;
6641
6642 if (!RB_TYPE_P(str, T_STRING))
6643 str = rb_obj_as_string(str);
6644
6645 arg.offset = NUM2OFFT(offset);
6646
6647 io = GetWriteIO(io);
6648 GetOpenFile(io, fptr);
6650
6651 arg.io = fptr;
6652 arg.fd = fptr->fd;
6653
6654 tmp = rb_str_tmp_frozen_acquire(str);
6655 arg.buf = RSTRING_PTR(tmp);
6656 arg.count = (size_t)RSTRING_LEN(tmp);
6657
6658 n = (ssize_t)pwrite_internal_call((VALUE)&arg);
6659 if (n < 0) rb_sys_fail_path(fptr->pathv);
6660 rb_str_tmp_frozen_release(str, tmp);
6661
6662 return SSIZET2NUM(n);
6663}
6664
6665VALUE
6667{
6668 rb_io_t *fptr;
6669
6670 GetOpenFile(io, fptr);
6671 if (fptr->readconv)
6673 if (fptr->writeconv)
6675 fptr->mode |= FMODE_BINMODE;
6676 fptr->mode &= ~FMODE_TEXTMODE;
6677 fptr->writeconv_pre_ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
6678#ifdef O_BINARY
6679 if (!fptr->readconv) {
6680 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6681 }
6682 else {
6683 setmode(fptr->fd, O_BINARY);
6684 }
6685#endif
6686 return io;
6687}
6688
6689static void
6690io_ascii8bit_binmode(rb_io_t *fptr)
6691{
6692 if (fptr->readconv) {
6693 rb_econv_close(fptr->readconv);
6694 fptr->readconv = NULL;
6695 }
6696 if (fptr->writeconv) {
6698 fptr->writeconv = NULL;
6699 }
6700 fptr->mode |= FMODE_BINMODE;
6701 fptr->mode &= ~FMODE_TEXTMODE;
6702 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6703
6704 fptr->encs.enc = rb_ascii8bit_encoding();
6705 fptr->encs.enc2 = NULL;
6706 fptr->encs.ecflags = 0;
6707 fptr->encs.ecopts = Qnil;
6708 clear_codeconv(fptr);
6709}
6710
6711VALUE
6713{
6714 rb_io_t *fptr;
6715
6716 GetOpenFile(io, fptr);
6717 io_ascii8bit_binmode(fptr);
6718
6719 return io;
6720}
6721
6722/*
6723 * call-seq:
6724 * binmode -> self
6725 *
6726 * Sets the stream's data mode as binary
6727 * (see {Data Mode}[rdoc-ref:File@Data+Mode]).
6728 *
6729 * A stream's data mode may not be changed from binary to text.
6730 *
6731 */
6732
6733static VALUE
6734rb_io_binmode_m(VALUE io)
6735{
6736 VALUE write_io;
6737
6739
6740 write_io = GetWriteIO(io);
6741 if (write_io != io)
6742 rb_io_ascii8bit_binmode(write_io);
6743 return io;
6744}
6745
6746/*
6747 * call-seq:
6748 * binmode? -> true or false
6749 *
6750 * Returns +true+ if the stream is on binary mode, +false+ otherwise.
6751 * See {Data Mode}[rdoc-ref:File@Data+Mode].
6752 *
6753 */
6754static VALUE
6755rb_io_binmode_p(VALUE io)
6756{
6757 rb_io_t *fptr;
6758 GetOpenFile(io, fptr);
6759 return RBOOL(fptr->mode & FMODE_BINMODE);
6760}
6761
6762static const char*
6763rb_io_fmode_modestr(enum rb_io_mode fmode)
6764{
6765 if (fmode & FMODE_APPEND) {
6766 if ((fmode & FMODE_READWRITE) == FMODE_READWRITE) {
6767 return MODE_BTMODE("a+", "ab+", "at+");
6768 }
6769 return MODE_BTMODE("a", "ab", "at");
6770 }
6771 switch (fmode & FMODE_READWRITE) {
6772 default:
6773 rb_raise(rb_eArgError, "invalid access fmode 0x%x", fmode);
6774 case FMODE_READABLE:
6775 return MODE_BTMODE("r", "rb", "rt");
6776 case FMODE_WRITABLE:
6777 return MODE_BTXMODE("w", "wb", "wt", "wx", "wbx", "wtx");
6778 case FMODE_READWRITE:
6779 if (fmode & FMODE_CREATE) {
6780 return MODE_BTXMODE("w+", "wb+", "wt+", "w+x", "wb+x", "wt+x");
6781 }
6782 return MODE_BTMODE("r+", "rb+", "rt+");
6783 }
6784}
6785
6786static const char bom_prefix[] = "bom|";
6787static const char utf_prefix[] = "utf-";
6788enum {bom_prefix_len = (int)sizeof(bom_prefix) - 1};
6789enum {utf_prefix_len = (int)sizeof(utf_prefix) - 1};
6790
6791static int
6792io_encname_bom_p(const char *name, long len)
6793{
6794 return len > bom_prefix_len && STRNCASECMP(name, bom_prefix, bom_prefix_len) == 0;
6795}
6796
6797enum rb_io_mode
6798rb_io_modestr_fmode(const char *modestr)
6799{
6800 enum rb_io_mode fmode = 0;
6801 const char *m = modestr, *p = NULL;
6802
6803 switch (*m++) {
6804 case 'r':
6805 fmode |= FMODE_READABLE;
6806 break;
6807 case 'w':
6809 break;
6810 case 'a':
6812 break;
6813 default:
6814 goto error;
6815 }
6816
6817 while (*m) {
6818 switch (*m++) {
6819 case 'b':
6820 fmode |= FMODE_BINMODE;
6821 break;
6822 case 't':
6823 fmode |= FMODE_TEXTMODE;
6824 break;
6825 case '+':
6826 fmode |= FMODE_READWRITE;
6827 break;
6828 case 'x':
6829 if (modestr[0] != 'w')
6830 goto error;
6831 fmode |= FMODE_EXCL;
6832 break;
6833 default:
6834 goto error;
6835 case ':':
6836 p = strchr(m, ':');
6837 if (io_encname_bom_p(m, p ? (long)(p - m) : (long)strlen(m)))
6838 fmode |= FMODE_SETENC_BY_BOM;
6839 goto finished;
6840 }
6841 }
6842
6843 finished:
6844 if ((fmode & FMODE_BINMODE) && (fmode & FMODE_TEXTMODE))
6845 goto error;
6846
6847 return fmode;
6848
6849 error:
6850 rb_raise(rb_eArgError, "invalid access mode %s", modestr);
6852}
6853
6854int
6855rb_io_oflags_fmode(int oflags)
6856{
6857 enum rb_io_mode fmode = 0;
6858
6859 switch (oflags & O_ACCMODE) {
6860 case O_RDONLY:
6861 fmode = FMODE_READABLE;
6862 break;
6863 case O_WRONLY:
6864 fmode = FMODE_WRITABLE;
6865 break;
6866 case O_RDWR:
6867 fmode = FMODE_READWRITE;
6868 break;
6869 }
6870
6871 if (oflags & O_APPEND) {
6872 fmode |= FMODE_APPEND;
6873 }
6874 if (oflags & O_TRUNC) {
6875 fmode |= FMODE_TRUNC;
6876 }
6877 if (oflags & O_CREAT) {
6878 fmode |= FMODE_CREATE;
6879 }
6880 if (oflags & O_EXCL) {
6881 fmode |= FMODE_EXCL;
6882 }
6883#ifdef O_BINARY
6884 if (oflags & O_BINARY) {
6885 fmode |= FMODE_BINMODE;
6886 }
6887#endif
6888
6889 return fmode;
6890}
6891
6892static int
6893rb_io_fmode_oflags(enum rb_io_mode fmode)
6894{
6895 int oflags = 0;
6896
6897 switch (fmode & FMODE_READWRITE) {
6898 case FMODE_READABLE:
6899 oflags |= O_RDONLY;
6900 break;
6901 case FMODE_WRITABLE:
6902 oflags |= O_WRONLY;
6903 break;
6904 case FMODE_READWRITE:
6905 oflags |= O_RDWR;
6906 break;
6907 }
6908
6909 if (fmode & FMODE_APPEND) {
6910 oflags |= O_APPEND;
6911 }
6912 if (fmode & FMODE_TRUNC) {
6913 oflags |= O_TRUNC;
6914 }
6915 if (fmode & FMODE_CREATE) {
6916 oflags |= O_CREAT;
6917 }
6918 if (fmode & FMODE_EXCL) {
6919 oflags |= O_EXCL;
6920 }
6921#ifdef O_BINARY
6922 if (fmode & FMODE_BINMODE) {
6923 oflags |= O_BINARY;
6924 }
6925#endif
6926
6927 return oflags;
6928}
6929
6930int
6931rb_io_modestr_oflags(const char *modestr)
6932{
6933 return rb_io_fmode_oflags(rb_io_modestr_fmode(modestr));
6934}
6935
6936static const char*
6937rb_io_oflags_modestr(int oflags)
6938{
6939#ifdef O_BINARY
6940# define MODE_BINARY(a,b) ((oflags & O_BINARY) ? (b) : (a))
6941#else
6942# define MODE_BINARY(a,b) (a)
6943#endif
6944 int accmode;
6945 if (oflags & O_EXCL) {
6946 rb_raise(rb_eArgError, "exclusive access mode is not supported");
6947 }
6948 accmode = oflags & (O_RDONLY|O_WRONLY|O_RDWR);
6949 if (oflags & O_APPEND) {
6950 if (accmode == O_WRONLY) {
6951 return MODE_BINARY("a", "ab");
6952 }
6953 if (accmode == O_RDWR) {
6954 return MODE_BINARY("a+", "ab+");
6955 }
6956 }
6957 switch (accmode) {
6958 default:
6959 rb_raise(rb_eArgError, "invalid access oflags 0x%x", oflags);
6960 case O_RDONLY:
6961 return MODE_BINARY("r", "rb");
6962 case O_WRONLY:
6963 return MODE_BINARY("w", "wb");
6964 case O_RDWR:
6965 if (oflags & O_TRUNC) {
6966 return MODE_BINARY("w+", "wb+");
6967 }
6968 return MODE_BINARY("r+", "rb+");
6969 }
6970}
6971
6972/*
6973 * Convert external/internal encodings to enc/enc2
6974 * NULL => use default encoding
6975 * Qnil => no encoding specified (internal only)
6976 */
6977static void
6978rb_io_ext_int_to_encs(rb_encoding *ext, rb_encoding *intern, rb_encoding **enc, rb_encoding **enc2, enum rb_io_mode fmode)
6979{
6980 int default_ext = 0;
6981
6982 if (ext == NULL) {
6983 ext = rb_default_external_encoding();
6984 default_ext = 1;
6985 }
6986 if (rb_is_ascii8bit_enc(ext)) {
6987 /* If external is ASCII-8BIT, no transcoding */
6988 intern = NULL;
6989 }
6990 else if (intern == NULL) {
6991 intern = rb_default_internal_encoding();
6992 }
6993 if (intern == NULL || intern == (rb_encoding *)Qnil ||
6994 (!(fmode & FMODE_SETENC_BY_BOM) && (intern == ext))) {
6995 /* No internal encoding => use external + no transcoding */
6996 *enc = (default_ext && intern != ext) ? NULL : ext;
6997 *enc2 = NULL;
6998 }
6999 else {
7000 *enc = intern;
7001 *enc2 = ext;
7002 }
7003}
7004
7005static void
7006unsupported_encoding(const char *name, rb_encoding *enc)
7007{
7008 rb_enc_warn(enc, "Unsupported encoding %s ignored", name);
7009}
7010
7011static void
7012parse_mode_enc(const char *estr, rb_encoding *estr_enc,
7013 rb_encoding **enc_p, rb_encoding **enc2_p, enum rb_io_mode *fmode_p)
7014{
7015 const char *p;
7016 char encname[ENCODING_MAXNAMELEN+1];
7017 int idx, idx2;
7018 enum rb_io_mode fmode = fmode_p ? *fmode_p : 0;
7019 rb_encoding *ext_enc, *int_enc;
7020 long len;
7021
7022 /* parse estr as "enc" or "enc2:enc" or "enc:-" */
7023
7024 p = strrchr(estr, ':');
7025 len = p ? (p++ - estr) : (long)strlen(estr);
7026 if ((fmode & FMODE_SETENC_BY_BOM) || io_encname_bom_p(estr, len)) {
7027 estr += bom_prefix_len;
7028 len -= bom_prefix_len;
7029 if (!STRNCASECMP(estr, utf_prefix, utf_prefix_len)) {
7030 fmode |= FMODE_SETENC_BY_BOM;
7031 }
7032 else {
7033 rb_enc_warn(estr_enc, "BOM with non-UTF encoding %s is nonsense", estr);
7034 fmode &= ~FMODE_SETENC_BY_BOM;
7035 }
7036 }
7037 if (len == 0 || len > ENCODING_MAXNAMELEN) {
7038 idx = -1;
7039 }
7040 else {
7041 if (p) {
7042 memcpy(encname, estr, len);
7043 encname[len] = '\0';
7044 estr = encname;
7045 }
7046 idx = rb_enc_find_index(estr);
7047 }
7048 if (fmode_p) *fmode_p = fmode;
7049
7050 if (idx >= 0)
7051 ext_enc = rb_enc_from_index(idx);
7052 else {
7053 if (idx != -2)
7054 unsupported_encoding(estr, estr_enc);
7055 ext_enc = NULL;
7056 }
7057
7058 int_enc = NULL;
7059 if (p) {
7060 if (*p == '-' && *(p+1) == '\0') {
7061 /* Special case - "-" => no transcoding */
7062 int_enc = (rb_encoding *)Qnil;
7063 }
7064 else {
7065 idx2 = rb_enc_find_index(p);
7066 if (idx2 < 0)
7067 unsupported_encoding(p, estr_enc);
7068 else if (!(fmode & FMODE_SETENC_BY_BOM) && (idx2 == idx)) {
7069 int_enc = (rb_encoding *)Qnil;
7070 }
7071 else
7072 int_enc = rb_enc_from_index(idx2);
7073 }
7074 }
7075
7076 rb_io_ext_int_to_encs(ext_enc, int_enc, enc_p, enc2_p, fmode);
7077}
7078
7079int
7080rb_io_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding **enc2_p, enum rb_io_mode *fmode_p)
7081{
7082 VALUE encoding=Qnil, extenc=Qundef, intenc=Qundef, tmp;
7083 int extracted = 0;
7084 rb_encoding *extencoding = NULL;
7085 rb_encoding *intencoding = NULL;
7086
7087 if (!NIL_P(opt)) {
7088 VALUE v;
7089 v = rb_hash_lookup2(opt, sym_encoding, Qnil);
7090 if (v != Qnil) encoding = v;
7091 v = rb_hash_lookup2(opt, sym_extenc, Qundef);
7092 if (v != Qnil) extenc = v;
7093 v = rb_hash_lookup2(opt, sym_intenc, Qundef);
7094 if (!UNDEF_P(v)) intenc = v;
7095 }
7096 if ((!UNDEF_P(extenc) || !UNDEF_P(intenc)) && !NIL_P(encoding)) {
7097 if (!NIL_P(ruby_verbose)) {
7098 int idx = rb_to_encoding_index(encoding);
7099 if (idx >= 0) encoding = rb_enc_from_encoding(rb_enc_from_index(idx));
7100 rb_warn("Ignoring encoding parameter '%"PRIsVALUE"': %s_encoding is used",
7101 encoding, UNDEF_P(extenc) ? "internal" : "external");
7102 }
7103 encoding = Qnil;
7104 }
7105 if (!UNDEF_P(extenc) && !NIL_P(extenc)) {
7106 extencoding = rb_to_encoding(extenc);
7107 }
7108 if (!UNDEF_P(intenc)) {
7109 if (NIL_P(intenc)) {
7110 /* internal_encoding: nil => no transcoding */
7111 intencoding = (rb_encoding *)Qnil;
7112 }
7113 else if (!NIL_P(tmp = rb_check_string_type(intenc))) {
7114 char *p = StringValueCStr(tmp);
7115
7116 if (*p == '-' && *(p+1) == '\0') {
7117 /* Special case - "-" => no transcoding */
7118 intencoding = (rb_encoding *)Qnil;
7119 }
7120 else {
7121 intencoding = rb_to_encoding(intenc);
7122 }
7123 }
7124 else {
7125 intencoding = rb_to_encoding(intenc);
7126 }
7127 if (extencoding == intencoding) {
7128 intencoding = (rb_encoding *)Qnil;
7129 }
7130 }
7131 if (!NIL_P(encoding)) {
7132 extracted = 1;
7133 if (!NIL_P(tmp = rb_check_string_type(encoding))) {
7134 parse_mode_enc(StringValueCStr(tmp), rb_enc_get(tmp),
7135 enc_p, enc2_p, fmode_p);
7136 }
7137 else {
7138 rb_io_ext_int_to_encs(rb_to_encoding(encoding), NULL, enc_p, enc2_p, 0);
7139 }
7140 }
7141 else if (!UNDEF_P(extenc) || !UNDEF_P(intenc)) {
7142 extracted = 1;
7143 rb_io_ext_int_to_encs(extencoding, intencoding, enc_p, enc2_p, 0);
7144 }
7145 return extracted;
7146}
7147
7148static void
7149validate_enc_binmode(enum rb_io_mode *fmode_p, int ecflags, rb_encoding *enc, rb_encoding *enc2)
7150{
7151 enum rb_io_mode fmode = *fmode_p;
7152
7153 if ((fmode & FMODE_READABLE) &&
7154 !enc2 &&
7155 !(fmode & FMODE_BINMODE) &&
7156 !rb_enc_asciicompat(enc ? enc : rb_default_external_encoding()))
7157 rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
7158
7159 if ((fmode & FMODE_BINMODE) && (ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
7160 rb_raise(rb_eArgError, "newline decorator with binary mode");
7161 }
7162 if (!(fmode & FMODE_BINMODE) &&
7163 (DEFAULT_TEXTMODE || (ecflags & ECONV_NEWLINE_DECORATOR_MASK))) {
7164 fmode |= FMODE_TEXTMODE;
7165 *fmode_p = fmode;
7166 }
7167#if !DEFAULT_TEXTMODE
7168 else if (!(ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
7169 fmode &= ~FMODE_TEXTMODE;
7170 *fmode_p = fmode;
7171 }
7172#endif
7173}
7174
7175static void
7176extract_binmode(VALUE opthash, enum rb_io_mode *fmode)
7177{
7178 if (!NIL_P(opthash)) {
7179 VALUE v;
7180 v = rb_hash_aref(opthash, sym_textmode);
7181 if (!NIL_P(v)) {
7182 if (*fmode & FMODE_TEXTMODE)
7183 rb_raise(rb_eArgError, "textmode specified twice");
7184 if (*fmode & FMODE_BINMODE)
7185 rb_raise(rb_eArgError, "both textmode and binmode specified");
7186 if (RTEST(v))
7187 *fmode |= FMODE_TEXTMODE;
7188 }
7189 v = rb_hash_aref(opthash, sym_binmode);
7190 if (!NIL_P(v)) {
7191 if (*fmode & FMODE_BINMODE)
7192 rb_raise(rb_eArgError, "binmode specified twice");
7193 if (*fmode & FMODE_TEXTMODE)
7194 rb_raise(rb_eArgError, "both textmode and binmode specified");
7195 if (RTEST(v))
7196 *fmode |= FMODE_BINMODE;
7197 }
7198
7199 if ((*fmode & FMODE_BINMODE) && (*fmode & FMODE_TEXTMODE))
7200 rb_raise(rb_eArgError, "both textmode and binmode specified");
7201 }
7202}
7203
7204void
7205rb_io_extract_modeenc(VALUE *vmode_p, VALUE *vperm_p, VALUE opthash,
7206 int *oflags_p, enum rb_io_mode *fmode_p, struct rb_io_encoding *convconfig_p)
7207{
7208 VALUE vmode;
7209 int oflags;
7210 enum rb_io_mode fmode;
7211 rb_encoding *enc, *enc2;
7212 int ecflags;
7213 VALUE ecopts;
7214 int has_enc = 0, has_vmode = 0;
7215 VALUE intmode;
7216
7217 vmode = *vmode_p;
7218
7219 /* Set to defaults */
7220 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
7221
7222 vmode_handle:
7223 if (NIL_P(vmode)) {
7224 fmode = FMODE_READABLE;
7225 oflags = O_RDONLY;
7226 }
7227 else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int"))) {
7228 vmode = intmode;
7229 oflags = NUM2INT(intmode);
7230 fmode = rb_io_oflags_fmode(oflags);
7231 }
7232 else {
7233 const char *p;
7234
7235 StringValue(vmode);
7236 p = StringValueCStr(vmode);
7237 fmode = rb_io_modestr_fmode(p);
7238 oflags = rb_io_fmode_oflags(fmode);
7239 p = strchr(p, ':');
7240 if (p) {
7241 has_enc = 1;
7242 parse_mode_enc(p+1, rb_enc_get(vmode), &enc, &enc2, &fmode);
7243 }
7244 else {
7245 rb_encoding *e;
7246
7247 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
7248 rb_io_ext_int_to_encs(e, NULL, &enc, &enc2, fmode);
7249 }
7250 }
7251
7252 if (NIL_P(opthash)) {
7253 ecflags = (fmode & FMODE_READABLE) ?
7256#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7257 ecflags |= (fmode & FMODE_WRITABLE) ?
7258 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7259 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7260#endif
7261 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
7262 ecopts = Qnil;
7263 if (fmode & FMODE_BINMODE) {
7264#ifdef O_BINARY
7265 oflags |= O_BINARY;
7266#endif
7267 if (!has_enc)
7268 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
7269 }
7270#if DEFAULT_TEXTMODE
7271 else if (NIL_P(vmode)) {
7272 fmode |= DEFAULT_TEXTMODE;
7273 }
7274#endif
7275 }
7276 else {
7277 VALUE v;
7278 if (!has_vmode) {
7279 v = rb_hash_aref(opthash, sym_mode);
7280 if (!NIL_P(v)) {
7281 if (!NIL_P(vmode)) {
7282 rb_raise(rb_eArgError, "mode specified twice");
7283 }
7284 has_vmode = 1;
7285 vmode = v;
7286 goto vmode_handle;
7287 }
7288 }
7289 v = rb_hash_aref(opthash, sym_flags);
7290 if (!NIL_P(v)) {
7291 v = rb_to_int(v);
7292 oflags |= NUM2INT(v);
7293 vmode = INT2NUM(oflags);
7294 fmode = rb_io_oflags_fmode(oflags);
7295 }
7296 extract_binmode(opthash, &fmode);
7297 if (fmode & FMODE_BINMODE) {
7298#ifdef O_BINARY
7299 oflags |= O_BINARY;
7300#endif
7301 if (!has_enc)
7302 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
7303 }
7304#if DEFAULT_TEXTMODE
7305 else if (NIL_P(vmode)) {
7306 fmode |= DEFAULT_TEXTMODE;
7307 }
7308#endif
7309 v = rb_hash_aref(opthash, sym_perm);
7310 if (!NIL_P(v)) {
7311 if (vperm_p) {
7312 if (!NIL_P(*vperm_p)) {
7313 rb_raise(rb_eArgError, "perm specified twice");
7314 }
7315 *vperm_p = v;
7316 }
7317 else {
7318 /* perm no use, just ignore */
7319 }
7320 }
7321 ecflags = (fmode & FMODE_READABLE) ?
7324#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7325 ecflags |= (fmode & FMODE_WRITABLE) ?
7326 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7327 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7328#endif
7329
7330 if (rb_io_extract_encoding_option(opthash, &enc, &enc2, &fmode)) {
7331 if (has_enc) {
7332 rb_raise(rb_eArgError, "encoding specified twice");
7333 }
7334 }
7335 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
7336 ecflags = rb_econv_prepare_options(opthash, &ecopts, ecflags);
7337 }
7338
7339 validate_enc_binmode(&fmode, ecflags, enc, enc2);
7340
7341 *vmode_p = vmode;
7342
7343 *oflags_p = oflags;
7344 *fmode_p = fmode;
7345 convconfig_p->enc = enc;
7346 convconfig_p->enc2 = enc2;
7347 convconfig_p->ecflags = ecflags;
7348 convconfig_p->ecopts = ecopts;
7349}
7350
7352 VALUE fname;
7353 int oflags;
7354 mode_t perm;
7355};
7356
7357static void *
7358sysopen_func(void *ptr)
7359{
7360 const struct sysopen_struct *data = ptr;
7361 const char *fname = RSTRING_PTR(data->fname);
7362 return (void *)(VALUE)rb_cloexec_open(fname, data->oflags, data->perm);
7363}
7364
7365static inline int
7366rb_sysopen_internal(struct sysopen_struct *data)
7367{
7368 int fd;
7369 do {
7370 fd = IO_WITHOUT_GVL_INT(sysopen_func, data);
7371 } while (fd < 0 && errno == EINTR);
7372 if (0 <= fd)
7373 rb_update_max_fd(fd);
7374 return fd;
7375}
7376
7377static int
7378rb_sysopen(VALUE fname, int oflags, mode_t perm)
7379{
7380 int fd = -1;
7381 struct sysopen_struct data;
7382
7383 data.fname = rb_str_encode_ospath(fname);
7384 StringValueCStr(data.fname);
7385 data.oflags = oflags;
7386 data.perm = perm;
7387
7388 TRY_WITH_GC((fd = rb_sysopen_internal(&data)) >= 0) {
7389 rb_syserr_fail_path(first_errno, fname);
7390 }
7391 return fd;
7392}
7393
7394static inline FILE *
7395fdopen_internal(int fd, const char *modestr)
7396{
7397 FILE *file;
7398
7399#if defined(__sun)
7400 errno = 0;
7401#endif
7402 file = fdopen(fd, modestr);
7403 if (!file) {
7404#ifdef _WIN32
7405 if (errno == 0) errno = EINVAL;
7406#elif defined(__sun)
7407 if (errno == 0) errno = EMFILE;
7408#endif
7409 }
7410 return file;
7411}
7412
7413FILE *
7414rb_fdopen(int fd, const char *modestr)
7415{
7416 FILE *file = 0;
7417
7418 TRY_WITH_GC((file = fdopen_internal(fd, modestr)) != 0) {
7419 rb_syserr_fail(first_errno, 0);
7420 }
7421
7422 /* xxx: should be _IONBF? A buffer in FILE may have trouble. */
7423#ifdef USE_SETVBUF
7424 if (setvbuf(file, NULL, _IOFBF, 0) != 0)
7425 rb_warn("setvbuf() can't be honoured (fd=%d)", fd);
7426#endif
7427 return file;
7428}
7429
7430static int
7431io_check_tty(rb_io_t *fptr)
7432{
7433 int t = isatty(fptr->fd);
7434 if (t)
7435 fptr->mode |= FMODE_TTY|FMODE_DUPLEX;
7436 return t;
7437}
7438
7439static VALUE rb_io_internal_encoding(VALUE);
7440static void io_encoding_set(rb_io_t *, VALUE, VALUE, VALUE);
7441
7442static int
7443io_strip_bom(VALUE io)
7444{
7445 VALUE b1, b2, b3, b4;
7446 rb_io_t *fptr;
7447
7448 GetOpenFile(io, fptr);
7449 if (!(fptr->mode & FMODE_READABLE)) return 0;
7450 if (NIL_P(b1 = rb_io_getbyte(io))) return 0;
7451 switch (b1) {
7452 case INT2FIX(0xEF):
7453 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7454 if (b2 == INT2FIX(0xBB) && !NIL_P(b3 = rb_io_getbyte(io))) {
7455 if (b3 == INT2FIX(0xBF)) {
7456 return rb_utf8_encindex();
7457 }
7458 rb_io_ungetbyte(io, b3);
7459 }
7460 rb_io_ungetbyte(io, b2);
7461 break;
7462
7463 case INT2FIX(0xFE):
7464 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7465 if (b2 == INT2FIX(0xFF)) {
7466 return ENCINDEX_UTF_16BE;
7467 }
7468 rb_io_ungetbyte(io, b2);
7469 break;
7470
7471 case INT2FIX(0xFF):
7472 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7473 if (b2 == INT2FIX(0xFE)) {
7474 b3 = rb_io_getbyte(io);
7475 if (b3 == INT2FIX(0) && !NIL_P(b4 = rb_io_getbyte(io))) {
7476 if (b4 == INT2FIX(0)) {
7477 return ENCINDEX_UTF_32LE;
7478 }
7479 rb_io_ungetbyte(io, b4);
7480 }
7481 rb_io_ungetbyte(io, b3);
7482 return ENCINDEX_UTF_16LE;
7483 }
7484 rb_io_ungetbyte(io, b2);
7485 break;
7486
7487 case INT2FIX(0):
7488 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7489 if (b2 == INT2FIX(0) && !NIL_P(b3 = rb_io_getbyte(io))) {
7490 if (b3 == INT2FIX(0xFE) && !NIL_P(b4 = rb_io_getbyte(io))) {
7491 if (b4 == INT2FIX(0xFF)) {
7492 return ENCINDEX_UTF_32BE;
7493 }
7494 rb_io_ungetbyte(io, b4);
7495 }
7496 rb_io_ungetbyte(io, b3);
7497 }
7498 rb_io_ungetbyte(io, b2);
7499 break;
7500 }
7501 rb_io_ungetbyte(io, b1);
7502 return 0;
7503}
7504
7505static rb_encoding *
7506io_set_encoding_by_bom(VALUE io)
7507{
7508 int idx = io_strip_bom(io);
7509 rb_io_t *fptr;
7510 rb_encoding *extenc = NULL;
7511
7512 GetOpenFile(io, fptr);
7513 if (idx) {
7514 extenc = rb_enc_from_index(idx);
7515 io_encoding_set(fptr, rb_enc_from_encoding(extenc),
7516 rb_io_internal_encoding(io), Qnil);
7517 }
7518 else {
7519 fptr->encs.enc2 = NULL;
7520 }
7521 return extenc;
7522}
7523
7524static VALUE
7525rb_file_open_generic(VALUE io, VALUE filename, int oflags, enum rb_io_mode fmode,
7526 const struct rb_io_encoding *convconfig, mode_t perm)
7527{
7528 VALUE pathv;
7529 rb_io_t *fptr;
7530 struct rb_io_encoding cc;
7531 if (!convconfig) {
7532 /* Set to default encodings */
7533 rb_io_ext_int_to_encs(NULL, NULL, &cc.enc, &cc.enc2, fmode);
7534 cc.ecflags = 0;
7535 cc.ecopts = Qnil;
7536 convconfig = &cc;
7537 }
7538 validate_enc_binmode(&fmode, convconfig->ecflags,
7539 convconfig->enc, convconfig->enc2);
7540
7541 MakeOpenFile(io, fptr);
7542 fptr->mode = fmode;
7543 fptr->encs = *convconfig;
7544 pathv = rb_str_new_frozen(filename);
7545#ifdef O_TMPFILE
7546 if (!(oflags & O_TMPFILE)) {
7547 fptr->pathv = pathv;
7548 }
7549#else
7550 fptr->pathv = pathv;
7551#endif
7552 fptr->fd = rb_sysopen(pathv, oflags, perm);
7553 io_check_tty(fptr);
7554 if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
7555
7556 return io;
7557}
7558
7559static VALUE
7560rb_file_open_internal(VALUE io, VALUE filename, const char *modestr)
7561{
7562 enum rb_io_mode fmode = rb_io_modestr_fmode(modestr);
7563 const char *p = strchr(modestr, ':');
7564 struct rb_io_encoding convconfig;
7565
7566 if (p) {
7567 parse_mode_enc(p+1, rb_usascii_encoding(),
7568 &convconfig.enc, &convconfig.enc2, &fmode);
7569 }
7570 else {
7571 rb_encoding *e;
7572 /* Set to default encodings */
7573
7574 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
7575 rb_io_ext_int_to_encs(e, NULL, &convconfig.enc, &convconfig.enc2, fmode);
7576 }
7577
7578 convconfig.ecflags = (fmode & FMODE_READABLE) ?
7581#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7582 convconfig.ecflags |= (fmode & FMODE_WRITABLE) ?
7583 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7584 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7585#endif
7586 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.enc2, convconfig.ecflags);
7587 convconfig.ecopts = Qnil;
7588
7589 return rb_file_open_generic(io, filename,
7590 rb_io_fmode_oflags(fmode),
7591 fmode,
7592 &convconfig,
7593 0666);
7594}
7595
7596VALUE
7597rb_file_open_str(VALUE fname, const char *modestr)
7598{
7599 FilePathValue(fname);
7600 return rb_file_open_internal(io_alloc(rb_cFile), fname, modestr);
7601}
7602
7603VALUE
7604rb_file_open(const char *fname, const char *modestr)
7605{
7606 return rb_file_open_internal(io_alloc(rb_cFile), rb_str_new_cstr(fname), modestr);
7607}
7608
7609#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7610static struct pipe_list {
7611 rb_io_t *fptr;
7612 struct pipe_list *next;
7613} *pipe_list;
7614
7615static void
7616pipe_add_fptr(rb_io_t *fptr)
7617{
7618 struct pipe_list *list;
7619
7620 list = ALLOC(struct pipe_list);
7621 list->fptr = fptr;
7622 list->next = pipe_list;
7623 pipe_list = list;
7624}
7625
7626static void
7627pipe_del_fptr(rb_io_t *fptr)
7628{
7629 struct pipe_list **prev = &pipe_list;
7630 struct pipe_list *tmp;
7631
7632 while ((tmp = *prev) != 0) {
7633 if (tmp->fptr == fptr) {
7634 *prev = tmp->next;
7635 free(tmp);
7636 return;
7637 }
7638 prev = &tmp->next;
7639 }
7640}
7641
7642#if defined (_WIN32) || defined(__CYGWIN__)
7643static void
7644pipe_atexit(void)
7645{
7646 struct pipe_list *list = pipe_list;
7647 struct pipe_list *tmp;
7648
7649 while (list) {
7650 tmp = list->next;
7651 rb_io_fptr_finalize(list->fptr);
7652 list = tmp;
7653 }
7654}
7655#endif
7656
7657static void
7658pipe_finalize(rb_io_t *fptr, int noraise)
7659{
7660#if !defined(HAVE_WORKING_FORK) && !defined(_WIN32)
7661 int status = 0;
7662 if (fptr->stdio_file) {
7663 status = pclose(fptr->stdio_file);
7664 }
7665 fptr->fd = -1;
7666 fptr->stdio_file = 0;
7667 rb_last_status_set(status, fptr->pid);
7668#else
7669 fptr_finalize(fptr, noraise);
7670#endif
7671 pipe_del_fptr(fptr);
7672}
7673#endif
7674
7675static void
7676fptr_copy_finalizer(rb_io_t *fptr, const rb_io_t *orig)
7677{
7678#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7679 void (*const old_finalize)(struct rb_io*,int) = fptr->finalize;
7680
7681 if (old_finalize == orig->finalize) return;
7682#endif
7683
7684 fptr->finalize = orig->finalize;
7685
7686#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7687 if (old_finalize != pipe_finalize) {
7688 struct pipe_list *list;
7689 for (list = pipe_list; list; list = list->next) {
7690 if (list->fptr == fptr) break;
7691 }
7692 if (!list) pipe_add_fptr(fptr);
7693 }
7694 else {
7695 pipe_del_fptr(fptr);
7696 }
7697#endif
7698}
7699
7700void
7702{
7704 fptr->mode |= FMODE_SYNC;
7705}
7706
7707
7708int
7709rb_pipe(int *pipes)
7710{
7711 int ret;
7712 TRY_WITH_GC((ret = rb_cloexec_pipe(pipes)) >= 0);
7713 if (ret == 0) {
7714 rb_update_max_fd(pipes[0]);
7715 rb_update_max_fd(pipes[1]);
7716 }
7717 return ret;
7718}
7719
7720#ifdef _WIN32
7721#define spawnv(mode, cmd, args) rb_w32_uaspawn((mode), (cmd), (args))
7722#define spawn(mode, cmd) rb_w32_uspawn((mode), (cmd), 0)
7723#endif
7724
7725#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7726struct popen_arg {
7727 VALUE execarg_obj;
7728 struct rb_execarg *eargp;
7729 int modef;
7730 int pair[2];
7731 int write_pair[2];
7732};
7733#endif
7734
7735#ifdef HAVE_WORKING_FORK
7736# ifndef __EMSCRIPTEN__
7737static void
7738popen_redirect(struct popen_arg *p)
7739{
7740 if ((p->modef & FMODE_READABLE) && (p->modef & FMODE_WRITABLE)) {
7741 close(p->write_pair[1]);
7742 if (p->write_pair[0] != 0) {
7743 dup2(p->write_pair[0], 0);
7744 close(p->write_pair[0]);
7745 }
7746 close(p->pair[0]);
7747 if (p->pair[1] != 1) {
7748 dup2(p->pair[1], 1);
7749 close(p->pair[1]);
7750 }
7751 }
7752 else if (p->modef & FMODE_READABLE) {
7753 close(p->pair[0]);
7754 if (p->pair[1] != 1) {
7755 dup2(p->pair[1], 1);
7756 close(p->pair[1]);
7757 }
7758 }
7759 else {
7760 close(p->pair[1]);
7761 if (p->pair[0] != 0) {
7762 dup2(p->pair[0], 0);
7763 close(p->pair[0]);
7764 }
7765 }
7766}
7767# endif
7768
7769#if defined(__linux__)
7770/* Linux /proc/self/status contains a line: "FDSize:\t<nnn>\n"
7771 * Since /proc may not be available, linux_get_maxfd is just a hint.
7772 * This function, linux_get_maxfd, must be async-signal-safe.
7773 * I.e. opendir() is not usable.
7774 *
7775 * Note that memchr() and memcmp is *not* async-signal-safe in POSIX.
7776 * However they are easy to re-implement in async-signal-safe manner.
7777 * (Also note that there is missing/memcmp.c.)
7778 */
7779static int
7780linux_get_maxfd(void)
7781{
7782 int fd;
7783 char buf[4096], *p, *np, *e;
7784 ssize_t ss;
7785 fd = rb_cloexec_open("/proc/self/status", O_RDONLY|O_NOCTTY, 0);
7786 if (fd < 0) return fd;
7787 ss = read(fd, buf, sizeof(buf));
7788 if (ss < 0) goto err;
7789 p = buf;
7790 e = buf + ss;
7791 while ((int)sizeof("FDSize:\t0\n")-1 <= e-p &&
7792 (np = memchr(p, '\n', e-p)) != NULL) {
7793 if (memcmp(p, "FDSize:", sizeof("FDSize:")-1) == 0) {
7794 int fdsize;
7795 p += sizeof("FDSize:")-1;
7796 *np = '\0';
7797 fdsize = (int)ruby_strtoul(p, (char **)NULL, 10);
7798 close(fd);
7799 return fdsize;
7800 }
7801 p = np+1;
7802 }
7803 /* fall through */
7804
7805 err:
7806 close(fd);
7807 return (int)ss;
7808}
7809#endif
7810
7811/* This function should be async-signal-safe. */
7812void
7813rb_close_before_exec(int lowfd, int maxhint, VALUE noclose_fds)
7814{
7815#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
7816 int fd, ret;
7817 int max = (int)max_file_descriptor;
7818# ifdef F_MAXFD
7819 /* F_MAXFD is available since NetBSD 2.0. */
7820 ret = fcntl(0, F_MAXFD); /* async-signal-safe */
7821 if (ret != -1)
7822 maxhint = max = ret;
7823# elif defined(__linux__)
7824 ret = linux_get_maxfd();
7825 if (maxhint < ret)
7826 maxhint = ret;
7827 /* maxhint = max = ret; if (ret == -1) abort(); // test */
7828# endif
7829 if (max < maxhint)
7830 max = maxhint;
7831 for (fd = lowfd; fd <= max; fd++) {
7832 if (!NIL_P(noclose_fds) &&
7833 RTEST(rb_hash_lookup(noclose_fds, INT2FIX(fd)))) /* async-signal-safe */
7834 continue;
7835 ret = fcntl(fd, F_GETFD); /* async-signal-safe */
7836 if (ret != -1 && !(ret & FD_CLOEXEC)) {
7837 fcntl(fd, F_SETFD, ret|FD_CLOEXEC); /* async-signal-safe */
7838 }
7839# define CONTIGUOUS_CLOSED_FDS 20
7840 if (ret != -1) {
7841 if (max < fd + CONTIGUOUS_CLOSED_FDS)
7842 max = fd + CONTIGUOUS_CLOSED_FDS;
7843 }
7844 }
7845#endif
7846}
7847
7848# ifndef __EMSCRIPTEN__
7849static int
7850popen_exec(void *pp, char *errmsg, size_t errmsg_len)
7851{
7852 struct popen_arg *p = (struct popen_arg*)pp;
7853
7854 return rb_exec_async_signal_safe(p->eargp, errmsg, errmsg_len);
7855}
7856# endif
7857#endif
7858
7859#if (defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)) && !defined __EMSCRIPTEN__
7860static VALUE
7861rb_execarg_fixup_v(VALUE execarg_obj)
7862{
7863 rb_execarg_parent_start(execarg_obj);
7864 return Qnil;
7865}
7866#else
7867char *rb_execarg_commandline(const struct rb_execarg *eargp, VALUE *prog);
7868#endif
7869
7870#ifndef __EMSCRIPTEN__
7871static VALUE
7872pipe_open(VALUE execarg_obj, const char *modestr, enum rb_io_mode fmode,
7873 const struct rb_io_encoding *convconfig)
7874{
7875 struct rb_execarg *eargp = NIL_P(execarg_obj) ? NULL : rb_execarg_get(execarg_obj);
7876 VALUE prog = eargp ? (eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name) : Qfalse ;
7877 rb_pid_t pid = 0;
7878 rb_io_t *fptr;
7879 VALUE port;
7880 rb_io_t *write_fptr;
7881 VALUE write_port;
7882#if defined(HAVE_WORKING_FORK)
7883 int status;
7884 char errmsg[80] = { '\0' };
7885#endif
7886#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7887 int state;
7888 struct popen_arg arg;
7889#endif
7890 int e = 0;
7891#if defined(HAVE_SPAWNV)
7892# define DO_SPAWN(cmd, args) ((args) ? \
7893 spawnv(P_NOWAIT, (cmd), (args)) : \
7894 spawn(P_NOWAIT, (cmd)))
7895# if !defined(HAVE_WORKING_FORK)
7896 char **args = NULL;
7897# endif
7898#endif
7899#if !defined(HAVE_WORKING_FORK)
7900 struct rb_execarg sarg, *sargp = &sarg;
7901#endif
7902 FILE *fp = 0;
7903 int fd = -1;
7904 int write_fd = -1;
7905#if !defined(HAVE_WORKING_FORK)
7906 const char *cmd = 0;
7907
7908 if (prog)
7909 cmd = StringValueCStr(prog);
7910#endif
7911
7912#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7913 arg.execarg_obj = execarg_obj;
7914 arg.eargp = eargp;
7915 arg.modef = fmode;
7916 arg.pair[0] = arg.pair[1] = -1;
7917 arg.write_pair[0] = arg.write_pair[1] = -1;
7918# if !defined(HAVE_WORKING_FORK)
7919 if (eargp && !eargp->use_shell) {
7920 args = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
7921 }
7922# endif
7923 switch (fmode & (FMODE_READABLE|FMODE_WRITABLE)) {
7925 if (rb_pipe(arg.write_pair) < 0)
7926 rb_sys_fail_str(prog);
7927 if (rb_pipe(arg.pair) < 0) {
7928 e = errno;
7929 close(arg.write_pair[0]);
7930 close(arg.write_pair[1]);
7931 rb_syserr_fail_str(e, prog);
7932 }
7933 if (eargp) {
7934 rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.write_pair[0]));
7935 rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
7936 }
7937 break;
7938 case FMODE_READABLE:
7939 if (rb_pipe(arg.pair) < 0)
7940 rb_sys_fail_str(prog);
7941 if (eargp)
7942 rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
7943 break;
7944 case FMODE_WRITABLE:
7945 if (rb_pipe(arg.pair) < 0)
7946 rb_sys_fail_str(prog);
7947 if (eargp)
7948 rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.pair[0]));
7949 break;
7950 default:
7951 rb_sys_fail_str(prog);
7952 }
7953 if (!NIL_P(execarg_obj)) {
7954 rb_protect(rb_execarg_fixup_v, execarg_obj, &state);
7955 if (state) {
7956 if (0 <= arg.write_pair[0]) close(arg.write_pair[0]);
7957 if (0 <= arg.write_pair[1]) close(arg.write_pair[1]);
7958 if (0 <= arg.pair[0]) close(arg.pair[0]);
7959 if (0 <= arg.pair[1]) close(arg.pair[1]);
7960 rb_execarg_parent_end(execarg_obj);
7961 rb_jump_tag(state);
7962 }
7963
7964# if defined(HAVE_WORKING_FORK)
7965 pid = rb_fork_async_signal_safe(&status, popen_exec, &arg, arg.eargp->redirect_fds, errmsg, sizeof(errmsg));
7966# else
7967 rb_execarg_run_options(eargp, sargp, NULL, 0);
7968 while ((pid = DO_SPAWN(cmd, args)) < 0) {
7969 /* exec failed */
7970 switch (e = errno) {
7971 case EAGAIN:
7972# if EWOULDBLOCK != EAGAIN
7973 case EWOULDBLOCK:
7974# endif
7975 rb_thread_sleep(1);
7976 continue;
7977 }
7978 break;
7979 }
7980 if (eargp)
7981 rb_execarg_run_options(sargp, NULL, NULL, 0);
7982# endif
7983 rb_execarg_parent_end(execarg_obj);
7984 }
7985 else {
7986# if defined(HAVE_WORKING_FORK)
7987 pid = rb_call_proc__fork();
7988 if (pid == 0) { /* child */
7989 popen_redirect(&arg);
7990 rb_io_synchronized(RFILE(orig_stdout)->fptr);
7991 rb_io_synchronized(RFILE(orig_stderr)->fptr);
7992 return Qnil;
7993 }
7994# else
7995 rb_notimplement();
7996# endif
7997 }
7998
7999 /* parent */
8000 if (pid < 0) {
8001# if defined(HAVE_WORKING_FORK)
8002 e = errno;
8003# endif
8004 close(arg.pair[0]);
8005 close(arg.pair[1]);
8007 close(arg.write_pair[0]);
8008 close(arg.write_pair[1]);
8009 }
8010# if defined(HAVE_WORKING_FORK)
8011 if (errmsg[0])
8012 rb_syserr_fail(e, errmsg);
8013# endif
8014 rb_syserr_fail_str(e, prog);
8015 }
8016 if ((fmode & FMODE_READABLE) && (fmode & FMODE_WRITABLE)) {
8017 close(arg.pair[1]);
8018 fd = arg.pair[0];
8019 close(arg.write_pair[0]);
8020 write_fd = arg.write_pair[1];
8021 }
8022 else if (fmode & FMODE_READABLE) {
8023 close(arg.pair[1]);
8024 fd = arg.pair[0];
8025 }
8026 else {
8027 close(arg.pair[0]);
8028 fd = arg.pair[1];
8029 }
8030#else
8031 cmd = rb_execarg_commandline(eargp, &prog);
8032 if (!NIL_P(execarg_obj)) {
8033 rb_execarg_parent_start(execarg_obj);
8034 rb_execarg_run_options(eargp, sargp, NULL, 0);
8035 }
8036 fp = popen(cmd, modestr);
8037 e = errno;
8038 if (eargp) {
8039 rb_execarg_parent_end(execarg_obj);
8040 rb_execarg_run_options(sargp, NULL, NULL, 0);
8041 }
8042 if (!fp) rb_syserr_fail_path(e, prog);
8043 fd = fileno(fp);
8044#endif
8045
8046 port = io_alloc(rb_cIO);
8047 MakeOpenFile(port, fptr);
8048 fptr->fd = fd;
8049 fptr->stdio_file = fp;
8050 fptr->mode = fmode | FMODE_SYNC|FMODE_DUPLEX;
8051 if (convconfig) {
8052 fptr->encs = *convconfig;
8053#if RUBY_CRLF_ENVIRONMENT
8056 }
8057#endif
8058 }
8059 else {
8060 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
8062 }
8063#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
8064 if (NEED_NEWLINE_DECORATOR_ON_WRITE(fptr)) {
8065 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
8066 }
8067#endif
8068 }
8069 fptr->pid = pid;
8070
8071 if (0 <= write_fd) {
8072 write_port = io_alloc(rb_cIO);
8073 MakeOpenFile(write_port, write_fptr);
8074 write_fptr->fd = write_fd;
8075 write_fptr->mode = (fmode & ~FMODE_READABLE)| FMODE_SYNC|FMODE_DUPLEX;
8076 fptr->mode &= ~FMODE_WRITABLE;
8077 fptr->tied_io_for_writing = write_port;
8078 rb_ivar_set(port, rb_intern("@tied_io_for_writing"), write_port);
8079 }
8080
8081#if defined (__CYGWIN__) || !defined(HAVE_WORKING_FORK)
8082 fptr->finalize = pipe_finalize;
8083 pipe_add_fptr(fptr);
8084#endif
8085 return port;
8086}
8087#else
8088static VALUE
8089pipe_open(VALUE execarg_obj, const char *modestr, enum rb_io_mode fmode,
8090 const struct rb_io_encoding *convconfig)
8091{
8092 rb_raise(rb_eNotImpError, "popen() is not available");
8093}
8094#endif
8095
8096static int
8097is_popen_fork(VALUE prog)
8098{
8099 if (RSTRING_LEN(prog) == 1 && RSTRING_PTR(prog)[0] == '-') {
8100#if !defined(HAVE_WORKING_FORK)
8101 rb_raise(rb_eNotImpError,
8102 "fork() function is unimplemented on this machine");
8103#else
8104 return TRUE;
8105#endif
8106 }
8107 return FALSE;
8108}
8109
8110static VALUE
8111pipe_open_s(VALUE prog, const char *modestr, enum rb_io_mode fmode,
8112 const struct rb_io_encoding *convconfig)
8113{
8114 int argc = 1;
8115 VALUE *argv = &prog;
8116 VALUE execarg_obj = Qnil;
8117
8118 if (!is_popen_fork(prog))
8119 execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
8120 return pipe_open(execarg_obj, modestr, fmode, convconfig);
8121}
8122
8123static VALUE
8124pipe_close(VALUE io)
8125{
8126 rb_io_t *fptr = io_close_fptr(io);
8127 if (fptr) {
8128 fptr_waitpid(fptr, rb_thread_to_be_killed(rb_thread_current()));
8129 }
8130 return Qnil;
8131}
8132
8133static VALUE popen_finish(VALUE port, VALUE klass);
8134
8135/*
8136 * call-seq:
8137 * IO.popen(env = {}, cmd, mode = 'r', **opts) -> io
8138 * IO.popen(env = {}, cmd, mode = 'r', **opts) {|io| ... } -> object
8139 *
8140 * Executes the given command +cmd+ as a subprocess
8141 * whose $stdin and $stdout are connected to a new stream +io+.
8142 *
8143 * This method has potential security vulnerabilities if called with untrusted input;
8144 * see {Command Injection}[rdoc-ref:security/command_injection.rdoc].
8145 *
8146 * If no block is given, returns the new stream,
8147 * which depending on given +mode+ may be open for reading, writing, or both.
8148 * The stream should be explicitly closed (eventually) to avoid resource leaks.
8149 *
8150 * If a block is given, the stream is passed to the block
8151 * (again, open for reading, writing, or both);
8152 * when the block exits, the stream is closed,
8153 * the block's value is returned,
8154 * and the global variable <tt>$?</tt> is set to the child's exit status.
8155 *
8156 * Optional argument +mode+ may be any valid \IO mode.
8157 * See {Access Modes}[rdoc-ref:File@Access+Modes].
8158 *
8159 * Required argument +cmd+ determines which of the following occurs:
8160 *
8161 * - The process forks.
8162 * - A specified program runs in a shell.
8163 * - A specified program runs with specified arguments.
8164 * - A specified program runs with specified arguments and a specified +argv0+.
8165 *
8166 * Each of these is detailed below.
8167 *
8168 * The optional hash argument +env+ specifies name/value pairs that are to be added
8169 * to the environment variables for the subprocess:
8170 *
8171 * IO.popen({'FOO' => 'bar'}, 'ruby', 'r+') do |pipe|
8172 * pipe.puts 'puts ENV["FOO"]'
8173 * pipe.close_write
8174 * pipe.gets
8175 * end => "bar\n"
8176 *
8177 * Optional keyword arguments +opts+ specify:
8178 *
8179 * - {Open options}[rdoc-ref:IO@Open+Options].
8180 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
8181 * - Options for Kernel#spawn.
8182 *
8183 * <b>Forked Process</b>
8184 *
8185 * When argument +cmd+ is the 1-character string <tt>'-'</tt>, causes the process to fork:
8186 * IO.popen('-') do |pipe|
8187 * if pipe
8188 * $stderr.puts "In parent, child pid is #{pipe.pid}\n"
8189 * else
8190 * $stderr.puts "In child, pid is #{$$}\n"
8191 * end
8192 * end
8193 *
8194 * Output:
8195 *
8196 * In parent, child pid is 26253
8197 * In child, pid is 26253
8198 *
8199 * Note that this is not supported on all platforms.
8200 *
8201 * <b>Shell Subprocess</b>
8202 *
8203 * When argument +cmd+ is a single string (but not <tt>'-'</tt>),
8204 * the program named +cmd+ is run as a shell command:
8205 *
8206 * IO.popen('uname') do |pipe|
8207 * pipe.readlines
8208 * end
8209 *
8210 * Output:
8211 *
8212 * ["Linux\n"]
8213 *
8214 * Another example:
8215 *
8216 * IO.popen('/bin/sh', 'r+') do |pipe|
8217 * pipe.puts('ls')
8218 * pipe.close_write
8219 * $stderr.puts pipe.readlines.size
8220 * end
8221 *
8222 * Output:
8223 *
8224 * 213
8225 *
8226 * <b>Program Subprocess</b>
8227 *
8228 * When argument +cmd+ is an array of strings,
8229 * the program named <tt>cmd[0]</tt> is run with all elements of +cmd+ as its arguments:
8230 *
8231 * IO.popen(['du', '..', '.']) do |pipe|
8232 * $stderr.puts pipe.readlines.size
8233 * end
8234 *
8235 * Output:
8236 *
8237 * 1111
8238 *
8239 * <b>Program Subprocess with <tt>argv0</tt></b>
8240 *
8241 * When argument +cmd+ is an array whose first element is a 2-element string array
8242 * and whose remaining elements (if any) are strings:
8243 *
8244 * - <tt>cmd[0][0]</tt> (the first string in the nested array) is the name of a program that is run.
8245 * - <tt>cmd[0][1]</tt> (the second string in the nested array) is set as the program's <tt>argv[0]</tt>.
8246 * - <tt>cmd[1..-1]</tt> (the strings in the outer array) are the program's arguments.
8247 *
8248 * Example (sets <tt>$0</tt> to 'foo'):
8249 *
8250 * IO.popen([['/bin/sh', 'foo'], '-c', 'echo $0']).read # => "foo\n"
8251 *
8252 * <b>Some Special Examples</b>
8253 *
8254 * # Set IO encoding.
8255 * IO.popen("nkf -e filename", :external_encoding=>"EUC-JP") {|nkf_io|
8256 * euc_jp_string = nkf_io.read
8257 * }
8258 *
8259 * # Merge standard output and standard error using Kernel#spawn option. See Kernel#spawn.
8260 * IO.popen(["ls", "/", :err=>[:child, :out]]) do |io|
8261 * ls_result_with_error = io.read
8262 * end
8263 *
8264 * # Use mixture of spawn options and IO options.
8265 * IO.popen(["ls", "/"], :err=>[:child, :out]) do |io|
8266 * ls_result_with_error = io.read
8267 * end
8268 *
8269 * f = IO.popen("uname")
8270 * p f.readlines
8271 * f.close
8272 * puts "Parent is #{Process.pid}"
8273 * IO.popen("date") {|f| puts f.gets }
8274 * IO.popen("-") {|f| $stderr.puts "#{Process.pid} is here, f is #{f.inspect}"}
8275 * p $?
8276 * IO.popen(%w"sed -e s|^|<foo>| -e s&$&;zot;&", "r+") {|f|
8277 * f.puts "bar"; f.close_write; puts f.gets
8278 * }
8279 *
8280 * Output (from last section):
8281 *
8282 * ["Linux\n"]
8283 * Parent is 21346
8284 * Thu Jan 15 22:41:19 JST 2009
8285 * 21346 is here, f is #<IO:fd 3>
8286 * 21352 is here, f is nil
8287 * #<Process::Status: pid 21352 exit 0>
8288 * <foo>bar;zot;
8289 *
8290 * Raises exceptions that IO.pipe and Kernel.spawn raise.
8291 *
8292 */
8293
8294static VALUE
8295rb_io_s_popen(int argc, VALUE *argv, VALUE klass)
8296{
8297 VALUE pname, pmode = Qnil, opt = Qnil, env = Qnil;
8298
8299 if (argc > 1 && !NIL_P(opt = rb_check_hash_type(argv[argc-1]))) --argc;
8300 if (argc > 1 && !NIL_P(env = rb_check_hash_type(argv[0]))) --argc, ++argv;
8301 switch (argc) {
8302 case 2:
8303 pmode = argv[1];
8304 case 1:
8305 pname = argv[0];
8306 break;
8307 default:
8308 {
8309 int ex = !NIL_P(opt);
8310 rb_error_arity(argc + ex, 1 + ex, 2 + ex);
8311 }
8312 }
8313 return popen_finish(rb_io_popen(pname, pmode, env, opt), klass);
8314}
8315
8316VALUE
8317rb_io_popen(VALUE pname, VALUE pmode, VALUE env, VALUE opt)
8318{
8319 const char *modestr;
8320 VALUE tmp, execarg_obj = Qnil;
8321 int oflags;
8322 enum rb_io_mode fmode;
8323 struct rb_io_encoding convconfig;
8324
8325 tmp = rb_check_array_type(pname);
8326 if (!NIL_P(tmp)) {
8327 long len = RARRAY_LEN(tmp);
8328#if SIZEOF_LONG > SIZEOF_INT
8329 if (len > INT_MAX) {
8330 rb_raise(rb_eArgError, "too many arguments");
8331 }
8332#endif
8333 execarg_obj = rb_execarg_new((int)len, RARRAY_CONST_PTR(tmp), FALSE, FALSE);
8334 RB_GC_GUARD(tmp);
8335 }
8336 else {
8337 StringValue(pname);
8338 execarg_obj = Qnil;
8339 if (!is_popen_fork(pname))
8340 execarg_obj = rb_execarg_new(1, &pname, TRUE, FALSE);
8341 }
8342 if (!NIL_P(execarg_obj)) {
8343 if (!NIL_P(opt))
8344 opt = rb_execarg_extract_options(execarg_obj, opt);
8345 if (!NIL_P(env))
8346 rb_execarg_setenv(execarg_obj, env);
8347 }
8348 rb_io_extract_modeenc(&pmode, 0, opt, &oflags, &fmode, &convconfig);
8349 modestr = rb_io_oflags_modestr(oflags);
8350
8351 return pipe_open(execarg_obj, modestr, fmode, &convconfig);
8352}
8353
8354static VALUE
8355popen_finish(VALUE port, VALUE klass)
8356{
8357 if (NIL_P(port)) {
8358 /* child */
8359 if (rb_block_given_p()) {
8360 rb_protect(rb_yield, Qnil, NULL);
8361 rb_io_flush(rb_ractor_stdout());
8362 rb_io_flush(rb_ractor_stderr());
8363 _exit(EXIT_SUCCESS);
8364 }
8365 return Qnil;
8366 }
8367 RBASIC_SET_CLASS(port, klass);
8368 if (rb_block_given_p()) {
8369 return rb_ensure(rb_yield, port, pipe_close, port);
8370 }
8371 return port;
8372}
8373
8374#if defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)
8375struct popen_writer_arg {
8376 char *const *argv;
8377 struct popen_arg popen;
8378};
8379
8380static int
8381exec_popen_writer(void *arg, char *errmsg, size_t buflen)
8382{
8383 struct popen_writer_arg *pw = arg;
8384 pw->popen.modef = FMODE_WRITABLE;
8385 popen_redirect(&pw->popen);
8386 execv(pw->argv[0], pw->argv);
8387 strlcpy(errmsg, strerror(errno), buflen);
8388 return -1;
8389}
8390#endif
8391
8392FILE *
8393ruby_popen_writer(char *const *argv, rb_pid_t *pid)
8394{
8395#if (defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)) || defined(_WIN32)
8396# ifdef HAVE_WORKING_FORK
8397 struct popen_writer_arg pw;
8398 int *const write_pair = pw.popen.pair;
8399# else
8400 int write_pair[2];
8401# endif
8402
8403 *pid = -1;
8404 if (cloexec_pipe(write_pair, 0, false) == 0) {
8405# ifdef HAVE_WORKING_FORK
8406 pw.argv = argv;
8407 int status;
8408 char errmsg[80] = {'\0'};
8409 *pid = rb_fork_async_signal_safe(&status, exec_popen_writer, &pw, Qnil, errmsg, sizeof(errmsg));
8410# else
8411 *pid = rb_w32_uspawn_process(P_NOWAIT, argv[0], argv, write_pair[0], -1, -1, 0);
8412 const char *errmsg = (*pid < 0) ? strerror(errno) : NULL;
8413# endif
8414 close(write_pair[0]);
8415 if (*pid < 0) {
8416 close(write_pair[1]);
8417 fprintf(stderr, "ruby_popen_writer(%s): %s\n", argv[0], errmsg);
8418 }
8419 else {
8420 return fdopen(write_pair[1], "w");
8421 }
8422 }
8423#endif
8424 return NULL;
8425}
8426
8427static VALUE
8428rb_open_file(VALUE io, VALUE fname, VALUE vmode, VALUE vperm, VALUE opt)
8429{
8430 int oflags;
8431 enum rb_io_mode fmode;
8432 struct rb_io_encoding convconfig;
8433 mode_t perm;
8434
8435 FilePathValue(fname);
8436
8437 rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, &convconfig);
8438 perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
8439
8440 rb_file_open_generic(io, fname, oflags, fmode, &convconfig, perm);
8441
8442 return io;
8443}
8444
8445/*
8446 * Document-method: File::open
8447 *
8448 * :markup: markdown
8449 *
8450 * call-seq:
8451 * File.open(path, mode = 'r', permissions = 0666, **options) -> file
8452 * File.open(path, mode = 'r', permissions = 0666, **options) {|file| ... } -> object
8453 *
8454 * Creates a new \File object via File.new with the given arguments.
8455 *
8456 * With no block given, returns the \File object.
8457 *
8458 * With a block given, calls the block with the \File object,
8459 * closes the \File object, and returns the block's value:
8460 *
8461 * ```ruby
8462 * File.open('doc/maintainers.md') {|file| file.size } # => 14900
8463 * ```
8464 *
8465 * Note that the \File object is automatically closed
8466 * even if the block raises an exception.
8467 */
8468
8469/*
8470 * Document-method: IO::open
8471 *
8472 * :markup: markdown
8473 *
8474 * call-seq:
8475 * IO.open(fd, mode = 'r', **options) -> io
8476 * IO.open(fd, mode = 'r', **options) {|io| ... } -> object
8477 *
8478 * Creates a new \IO object via IO.new with the given arguments.
8479 *
8480 * With no block given, returns the \IO object.
8481 *
8482 * With a block given, calls the block with the \IO object,
8483 * closes the \IO object, and returns the block’s value:
8484 *
8485 * ```ruby
8486 * fd = File.sysopen('doc/maintainers.md') # => 6
8487 * IO.open(fd) {|io| io.read.size } # => 14897
8488 * ```
8489 */
8490
8491static VALUE
8492rb_io_s_open(int argc, VALUE *argv, VALUE klass)
8493{
8495
8496 if (rb_block_given_p()) {
8497 return rb_ensure(rb_yield, io, io_close, io);
8498 }
8499
8500 return io;
8501}
8502
8503/*
8504 * call-seq:
8505 * IO.sysopen(path, mode = 'r', perm = 0666) -> integer
8506 *
8507 * Opens the file at the given path with the given mode and permissions;
8508 * returns the integer file descriptor.
8509 *
8510 * If the file is to be readable, it must exist;
8511 * if the file is to be writable and does not exist,
8512 * it is created with the given permissions:
8513 *
8514 * File.write('t.tmp', '') # => 0
8515 * IO.sysopen('t.tmp') # => 8
8516 * IO.sysopen('t.tmp', 'w') # => 9
8517 *
8518 *
8519 */
8520
8521static VALUE
8522rb_io_s_sysopen(int argc, VALUE *argv, VALUE _)
8523{
8524 VALUE fname, vmode, vperm;
8525 VALUE intmode;
8526 int oflags, fd;
8527 mode_t perm;
8528
8529 rb_scan_args(argc, argv, "12", &fname, &vmode, &vperm);
8530 FilePathValue(fname);
8531
8532 if (NIL_P(vmode))
8533 oflags = O_RDONLY;
8534 else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int")))
8535 oflags = NUM2INT(intmode);
8536 else {
8537 StringValue(vmode);
8538 oflags = rb_io_modestr_oflags(StringValueCStr(vmode));
8539 }
8540 if (NIL_P(vperm)) perm = 0666;
8541 else perm = NUM2MODET(vperm);
8542
8543 RB_GC_GUARD(fname) = rb_str_new4(fname);
8544 fd = rb_sysopen(fname, oflags, perm);
8545 return INT2NUM(fd);
8546}
8547
8548/*
8549 * call-seq:
8550 * open(path, mode = 'r', perm = 0666, **opts) -> io or nil
8551 * open(path, mode = 'r', perm = 0666, **opts) {|io| ... } -> obj
8552 *
8553 * Creates an IO object connected to the given file.
8554 *
8555 * With no block given, file stream is returned:
8556 *
8557 * open('t.txt') # => #<File:t.txt>
8558 *
8559 * With a block given, calls the block with the open file stream,
8560 * then closes the stream:
8561 *
8562 * open('t.txt') {|f| p f } # => #<File:t.txt (closed)>
8563 *
8564 * Output:
8565 *
8566 * #<File:t.txt>
8567 *
8568 * See File.open for details.
8569 *
8570 */
8571
8572static VALUE
8573rb_f_open(int argc, VALUE *argv, VALUE _)
8574{
8575 ID to_open = 0;
8576 int redirect = FALSE;
8577
8578 if (argc >= 1) {
8579 CONST_ID(to_open, "to_open");
8580 if (rb_respond_to(argv[0], to_open)) {
8581 redirect = TRUE;
8582 }
8583 else {
8584 VALUE tmp = argv[0];
8585 FilePathValue(tmp);
8586 if (NIL_P(tmp)) {
8587 redirect = TRUE;
8588 }
8589 else {
8590 argv[0] = tmp;
8591 }
8592 }
8593 }
8594 if (redirect) {
8595 VALUE io = rb_funcallv_kw(argv[0], to_open, argc-1, argv+1, RB_PASS_CALLED_KEYWORDS);
8596
8597 if (rb_block_given_p()) {
8598 return rb_ensure(rb_yield, io, io_close, io);
8599 }
8600 return io;
8601 }
8602 return rb_io_s_open(argc, argv, rb_cFile);
8603}
8604
8605static VALUE
8606rb_io_open_generic(VALUE klass, VALUE filename, int oflags, enum rb_io_mode fmode,
8607 const struct rb_io_encoding *convconfig, mode_t perm)
8608{
8609 return rb_file_open_generic(io_alloc(klass), filename,
8610 oflags, fmode, convconfig, perm);
8611}
8612
8613static VALUE
8614rb_io_open(VALUE io, VALUE filename, VALUE vmode, VALUE vperm, VALUE opt)
8615{
8616 int oflags;
8617 enum rb_io_mode fmode;
8618 struct rb_io_encoding convconfig;
8619 mode_t perm;
8620
8621 rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, &convconfig);
8622 perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
8623 return rb_io_open_generic(io, filename, oflags, fmode, &convconfig, perm);
8624}
8625
8626static VALUE
8627io_reopen(VALUE io, VALUE nfile)
8628{
8629 rb_io_t *fptr, *orig;
8630 int fd, fd2;
8631 rb_off_t pos = 0;
8632
8633 nfile = rb_io_get_io(nfile);
8634 GetOpenFile(io, fptr);
8635 GetOpenFile(nfile, orig);
8636
8637 if (fptr == orig) return io;
8638 if (RUBY_IO_EXTERNAL_P(fptr)) {
8639 if ((fptr->stdio_file == stdin && !(orig->mode & FMODE_READABLE)) ||
8640 (fptr->stdio_file == stdout && !(orig->mode & FMODE_WRITABLE)) ||
8641 (fptr->stdio_file == stderr && !(orig->mode & FMODE_WRITABLE))) {
8642 rb_raise(rb_eArgError,
8643 "%s can't change access mode from \"%s\" to \"%s\"",
8644 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
8645 rb_io_fmode_modestr(orig->mode));
8646 }
8647 }
8648 flush_before_seek(fptr, true);
8649 /* in flush_before_seek, clear_codeconv called only if rbuf is filled */
8650 clear_codeconv(fptr);
8651 if (orig->mode & FMODE_READABLE) {
8652 pos = io_tell(orig);
8653 }
8654 if (orig->mode & FMODE_WRITABLE) {
8655 if (io_fflush(orig) < 0)
8656 rb_sys_fail_on_write(fptr);
8657 }
8658
8659 /* copy rb_io_t structure */
8660 fptr->mode = orig->mode | (fptr->mode & FMODE_EXTERNAL);
8661 fptr->encs = orig->encs;
8662 fptr->pid = orig->pid;
8663 fptr->lineno = orig->lineno;
8664 if (RTEST(orig->pathv)) fptr->pathv = orig->pathv;
8665 else if (!RUBY_IO_EXTERNAL_P(fptr)) fptr->pathv = Qnil;
8666 fptr_copy_finalizer(fptr, orig);
8667
8668 fd = fptr->fd;
8669 fd2 = orig->fd;
8670 if (fd != fd2) {
8671 // Interrupt all usage of the old file descriptor:
8672 rb_thread_io_close_interrupt(fptr);
8673 rb_thread_io_close_wait(fptr);
8674
8675 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2 || !fptr->stdio_file) {
8676 /* need to keep FILE objects of stdin, stdout and stderr */
8677 if (rb_cloexec_dup2(fd2, fd) < 0)
8678 rb_sys_fail_path(orig->pathv);
8679 rb_update_max_fd(fd);
8680 }
8681 else {
8682 fclose(fptr->stdio_file);
8683 fptr->stdio_file = 0;
8684 fptr->fd = -1;
8685 if (rb_cloexec_dup2(fd2, fd) < 0)
8686 rb_sys_fail_path(orig->pathv);
8687 rb_update_max_fd(fd);
8688 fptr->fd = fd;
8689 }
8690
8691 if ((orig->mode & FMODE_READABLE) && pos >= 0) {
8692 if (io_seek(fptr, pos, SEEK_SET) < 0 && errno) {
8693 rb_sys_fail_path(fptr->pathv);
8694 }
8695 if (io_seek(orig, pos, SEEK_SET) < 0 && errno) {
8696 rb_sys_fail_path(orig->pathv);
8697 }
8698 }
8699 }
8700
8701 if (fptr->mode & FMODE_BINMODE) {
8702 rb_io_binmode(io);
8703 }
8704
8705 RBASIC_SET_CLASS(io, rb_obj_class(nfile));
8706 return io;
8707}
8708
8709#ifdef _WIN32
8710int rb_freopen(VALUE fname, const char *mode, FILE *fp);
8711#else
8712static int
8713rb_freopen(VALUE fname, const char *mode, FILE *fp)
8714{
8715 if (!freopen(RSTRING_PTR(fname), mode, fp)) {
8716 RB_GC_GUARD(fname);
8717 return errno;
8718 }
8719 return 0;
8720}
8721#endif
8722
8723/*
8724 * call-seq:
8725 * reopen(other_io) -> self
8726 * reopen(path, mode = 'r', **opts) -> self
8727 *
8728 * Reassociates the stream with another stream,
8729 * which may be of a different class.
8730 * This method may be used to redirect an existing stream
8731 * to a new destination.
8732 *
8733 * With argument +other_io+ given, reassociates with that stream:
8734 *
8735 * # Redirect $stdin from a file.
8736 * f = File.open('t.txt')
8737 * $stdin.reopen(f)
8738 * f.close
8739 *
8740 * # Redirect $stdout to a file.
8741 * f = File.open('t.tmp', 'w')
8742 * $stdout.reopen(f)
8743 * f.close
8744 *
8745 * With argument +path+ given, reassociates with a new stream to that file path:
8746 *
8747 * $stdin.reopen('t.txt')
8748 * $stdout.reopen('t.tmp', 'w')
8749 *
8750 * Optional keyword arguments +opts+ specify:
8751 *
8752 * - {Open Options}[rdoc-ref:IO@Open+Options].
8753 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
8754 *
8755 */
8756
8757static VALUE
8758rb_io_reopen(int argc, VALUE *argv, VALUE file)
8759{
8760 VALUE fname, nmode, opt;
8761 int oflags;
8762 rb_io_t *fptr;
8763
8764 if (rb_scan_args(argc, argv, "11:", &fname, &nmode, &opt) == 1) {
8765 VALUE tmp = rb_io_check_io(fname);
8766 if (!NIL_P(tmp)) {
8767 return io_reopen(file, tmp);
8768 }
8769 }
8770
8771 FilePathValue(fname);
8772 rb_io_taint_check(file);
8773 fptr = RFILE(file)->fptr;
8774 if (!fptr) {
8775 fptr = RFILE(file)->fptr = ZALLOC(rb_io_t);
8776 }
8777
8778 if (!NIL_P(nmode) || !NIL_P(opt)) {
8779 enum rb_io_mode fmode;
8780 struct rb_io_encoding convconfig;
8781
8782 rb_io_extract_modeenc(&nmode, 0, opt, &oflags, &fmode, &convconfig);
8783 if (RUBY_IO_EXTERNAL_P(fptr) &&
8784 ((fptr->mode & FMODE_READWRITE) & (fmode & FMODE_READWRITE)) !=
8785 (fptr->mode & FMODE_READWRITE)) {
8786 rb_raise(rb_eArgError,
8787 "%s can't change access mode from \"%s\" to \"%s\"",
8788 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
8789 rb_io_fmode_modestr(fmode));
8790 }
8791 fptr->mode = fmode;
8792 fptr->encs = convconfig;
8793 }
8794 else {
8795 oflags = rb_io_fmode_oflags(fptr->mode);
8796 }
8797
8798 fptr->pathv = fname;
8799 if (fptr->fd < 0) {
8800 fptr->fd = rb_sysopen(fptr->pathv, oflags, 0666);
8801 fptr->stdio_file = 0;
8802 return file;
8803 }
8804
8805 if (fptr->mode & FMODE_WRITABLE) {
8806 if (io_fflush(fptr) < 0)
8807 rb_sys_fail_on_write(fptr);
8808 }
8809 fptr->rbuf.off = fptr->rbuf.len = 0;
8810 clear_codeconv(fptr);
8811
8812 if (fptr->stdio_file) {
8813 int e = rb_freopen(rb_str_encode_ospath(fptr->pathv),
8814 rb_io_oflags_modestr(oflags),
8815 fptr->stdio_file);
8816 if (e) rb_syserr_fail_path(e, fptr->pathv);
8817 fptr->fd = fileno(fptr->stdio_file);
8818 rb_fd_fix_cloexec(fptr->fd);
8819#ifdef USE_SETVBUF
8820 if (setvbuf(fptr->stdio_file, NULL, _IOFBF, 0) != 0)
8821 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8822#endif
8823 if (fptr->stdio_file == stderr) {
8824 if (setvbuf(fptr->stdio_file, NULL, _IONBF, BUFSIZ) != 0)
8825 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8826 }
8827 else if (fptr->stdio_file == stdout && isatty(fptr->fd)) {
8828 if (setvbuf(fptr->stdio_file, NULL, _IOLBF, BUFSIZ) != 0)
8829 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8830 }
8831 }
8832 else {
8833 int tmpfd = rb_sysopen(fptr->pathv, oflags, 0666);
8834 int err = 0;
8835 if (rb_cloexec_dup2(tmpfd, fptr->fd) < 0)
8836 err = errno;
8837 (void)close(tmpfd);
8838 if (err) {
8839 rb_syserr_fail_path(err, fptr->pathv);
8840 }
8841 }
8842
8843 return file;
8844}
8845
8846/* :nodoc: */
8847static VALUE
8848rb_io_init_copy(VALUE dest, VALUE io)
8849{
8850 rb_io_t *fptr, *orig;
8851 int fd;
8852 VALUE write_io;
8853 rb_off_t pos;
8854
8855 io = rb_io_get_io(io);
8856 if (!OBJ_INIT_COPY(dest, io)) return dest;
8857 GetOpenFile(io, orig);
8858 MakeOpenFile(dest, fptr);
8859
8860 rb_io_flush(io);
8861
8862 /* copy rb_io_t structure */
8863 fptr->mode = orig->mode & ~FMODE_EXTERNAL;
8864 fptr->encs = orig->encs;
8865 fptr->pid = orig->pid;
8866 fptr->lineno = orig->lineno;
8867 fptr->timeout = orig->timeout;
8868
8869 ccan_list_head_init(&fptr->blocking_operations);
8870 fptr->closing_ec = NULL;
8871 fptr->wakeup_mutex = Qnil;
8872 fptr->fork_generation = GET_VM()->fork_gen;
8873
8874 if (!NIL_P(orig->pathv)) fptr->pathv = orig->pathv;
8875 fptr_copy_finalizer(fptr, orig);
8876
8877 fd = ruby_dup(orig->fd);
8878 fptr->fd = fd;
8879 pos = io_tell(orig);
8880 if (0 <= pos)
8881 io_seek(fptr, pos, SEEK_SET);
8882 if (fptr->mode & FMODE_BINMODE) {
8883 rb_io_binmode(dest);
8884 }
8885
8886 write_io = GetWriteIO(io);
8887 if (io != write_io) {
8888 write_io = rb_obj_dup(write_io);
8889 fptr->tied_io_for_writing = write_io;
8890 rb_ivar_set(dest, rb_intern("@tied_io_for_writing"), write_io);
8891 }
8892
8893 return dest;
8894}
8895
8896/*
8897 * call-seq:
8898 * printf(format_string, *objects) -> nil
8899 *
8900 * Formats and writes +objects+ to the stream.
8901 *
8902 * For details on +format_string+, see
8903 * {Format Specifications}[rdoc-ref:language/format_specifications.rdoc].
8904 *
8905 */
8906
8907VALUE
8908rb_io_printf(int argc, const VALUE *argv, VALUE out)
8909{
8910 rb_io_write(out, rb_f_sprintf(argc, argv));
8911 return Qnil;
8912}
8913
8914/*
8915 * call-seq:
8916 * printf(format_string, *objects) -> nil
8917 * printf(io, format_string, *objects) -> nil
8918 *
8919 * Equivalent to:
8920 *
8921 * io.write(sprintf(format_string, *objects))
8922 *
8923 * For details on +format_string+, see
8924 * {Format Specifications}[rdoc-ref:language/format_specifications.rdoc].
8925 *
8926 * With the single argument +format_string+, formats +objects+ into the string,
8927 * then writes the formatted string to $stdout:
8928 *
8929 * printf('%4.4d %10s %2.2f', 24, 24, 24.0)
8930 *
8931 * Output (on $stdout):
8932 *
8933 * 0024 24 24.00#
8934 *
8935 * With arguments +io+ and +format_string+, formats +objects+ into the string,
8936 * then writes the formatted string to +io+:
8937 *
8938 * printf($stderr, '%4.4d %10s %2.2f', 24, 24, 24.0)
8939 *
8940 * Output (on $stderr):
8941 *
8942 * 0024 24 24.00# => nil
8943 *
8944 * With no arguments, does nothing.
8945 *
8946 */
8947
8948static VALUE
8949rb_f_printf(int argc, VALUE *argv, VALUE _)
8950{
8951 VALUE out;
8952
8953 if (argc == 0) return Qnil;
8954 if (RB_TYPE_P(argv[0], T_STRING)) {
8955 out = rb_ractor_stdout();
8956 }
8957 else {
8958 out = argv[0];
8959 argv++;
8960 argc--;
8961 }
8962 rb_io_write(out, rb_f_sprintf(argc, argv));
8963
8964 return Qnil;
8965}
8966
8967extern void rb_deprecated_str_setter(VALUE val, ID id, VALUE *var);
8968
8969static void
8970deprecated_rs_setter(VALUE val, ID id, VALUE *var)
8971{
8972 rb_deprecated_str_setter(val, id, &val);
8973 if (!NIL_P(val)) {
8974 if (rb_str_equal(val, rb_default_rs)) {
8975 val = rb_default_rs;
8976 }
8977 else {
8978 val = rb_str_frozen_bare_string(val);
8979 }
8980 }
8981 *var = val;
8982}
8983
8984/*
8985 * call-seq:
8986 * print(*objects) -> nil
8987 *
8988 * Writes the given objects to the stream; returns +nil+.
8989 * Appends the output record separator <tt>$OUTPUT_RECORD_SEPARATOR</tt>
8990 * (<tt>$\</tt>), if it is not +nil+.
8991 * See {Line IO}[rdoc-ref:IO@Line+IO].
8992 *
8993 * With argument +objects+ given, for each object:
8994 *
8995 * - Converts via its method +to_s+ if not a string.
8996 * - Writes to the stream.
8997 * - If not the last object, writes the output field separator
8998 * <tt>$OUTPUT_FIELD_SEPARATOR</tt> (<tt>$,</tt>) if it is not +nil+.
8999 *
9000 * With default separators:
9001 *
9002 * f = File.open('t.tmp', 'w+')
9003 * objects = [0, 0.0, Rational(0, 1), Complex(0, 0), :zero, 'zero']
9004 * p $OUTPUT_RECORD_SEPARATOR
9005 * p $OUTPUT_FIELD_SEPARATOR
9006 * f.print(*objects)
9007 * f.rewind
9008 * p f.read
9009 * f.close
9010 *
9011 * Output:
9012 *
9013 * nil
9014 * nil
9015 * "00.00/10+0izerozero"
9016 *
9017 * With specified separators:
9018 *
9019 * $\ = "\n"
9020 * $, = ','
9021 * f.rewind
9022 * f.print(*objects)
9023 * f.rewind
9024 * p f.read
9025 *
9026 * Output:
9027 *
9028 * "0,0.0,0/1,0+0i,zero,zero\n"
9029 *
9030 * With no argument given, writes the content of <tt>$_</tt>
9031 * (which is usually the most recent user input):
9032 *
9033 * f = File.open('t.tmp', 'w+')
9034 * gets # Sets $_ to the most recent user input.
9035 * f.print
9036 * f.close
9037 *
9038 */
9039
9040VALUE
9041rb_io_print(int argc, const VALUE *argv, VALUE out)
9042{
9043 int i;
9044 VALUE line;
9045
9046 /* if no argument given, print `$_' */
9047 if (argc == 0) {
9048 argc = 1;
9049 line = rb_lastline_get();
9050 argv = &line;
9051 }
9052 if (argc > 1 && !NIL_P(rb_output_fs)) {
9053 rb_category_warn(RB_WARN_CATEGORY_DEPRECATED, "$, is set to non-nil value");
9054 }
9055 for (i=0; i<argc; i++) {
9056 if (!NIL_P(rb_output_fs) && i>0) {
9057 rb_io_write(out, rb_output_fs);
9058 }
9059 rb_io_write(out, argv[i]);
9060 }
9061 if (argc > 0 && !NIL_P(rb_output_rs)) {
9062 rb_io_write(out, rb_output_rs);
9063 }
9064
9065 return Qnil;
9066}
9067
9068/*
9069 * call-seq:
9070 * print(*objects) -> nil
9071 *
9072 * Equivalent to <tt>$stdout.print(*objects)</tt>,
9073 * this method is the straightforward way to write to <tt>$stdout</tt>.
9074 *
9075 * Writes the given objects to <tt>$stdout</tt>; returns +nil+.
9076 * Appends the output record separator <tt>$OUTPUT_RECORD_SEPARATOR</tt>
9077 * (<tt>$\</tt>), if it is not +nil+.
9078 *
9079 * With argument +objects+ given, for each object:
9080 *
9081 * - Converts via its method +to_s+ if not a string.
9082 * - Writes to <tt>stdout</tt>.
9083 * - If not the last object, writes the output field separator
9084 * <tt>$OUTPUT_FIELD_SEPARATOR</tt> (<tt>$,</tt>) if it is not +nil+.
9085 *
9086 * With default separators:
9087 *
9088 * objects = [0, 0.0, Rational(0, 1), Complex(0, 0), :zero, 'zero']
9089 * $OUTPUT_RECORD_SEPARATOR
9090 * $OUTPUT_FIELD_SEPARATOR
9091 * print(*objects)
9092 *
9093 * Output:
9094 *
9095 * nil
9096 * nil
9097 * 00.00/10+0izerozero
9098 *
9099 * With specified separators:
9100 *
9101 * $OUTPUT_RECORD_SEPARATOR = "\n"
9102 * $OUTPUT_FIELD_SEPARATOR = ','
9103 * print(*objects)
9104 *
9105 * Output:
9106 *
9107 * 0,0.0,0/1,0+0i,zero,zero
9108 *
9109 * With no argument given, writes the content of <tt>$_</tt>
9110 * (which is usually the most recent user input):
9111 *
9112 * gets # Sets $_ to the most recent user input.
9113 * print # Prints $_.
9114 *
9115 */
9116
9117static VALUE
9118rb_f_print(int argc, const VALUE *argv, VALUE _)
9119{
9120 rb_io_print(argc, argv, rb_ractor_stdout());
9121 return Qnil;
9122}
9123
9124/*
9125 * call-seq:
9126 * putc(object) -> object
9127 *
9128 * Writes a character to the stream.
9129 * See {Character IO}[rdoc-ref:IO@Character+IO].
9130 *
9131 * If +object+ is numeric, converts to integer if necessary,
9132 * then writes the character whose code is the
9133 * least significant byte;
9134 * if +object+ is a string, writes the first character:
9135 *
9136 * $stdout.putc "A"
9137 * $stdout.putc 65
9138 *
9139 * Output:
9140 *
9141 * AA
9142 *
9143 */
9144
9145static VALUE
9146rb_io_putc(VALUE io, VALUE ch)
9147{
9148 VALUE str;
9149 if (RB_TYPE_P(ch, T_STRING)) {
9150 str = rb_str_substr(ch, 0, 1);
9151 }
9152 else {
9153 char c = NUM2CHR(ch);
9154 str = rb_str_new(&c, 1);
9155 }
9156 rb_io_write(io, str);
9157 return ch;
9158}
9159
9160#define forward(obj, id, argc, argv) \
9161 rb_funcallv_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
9162#define forward_public(obj, id, argc, argv) \
9163 rb_funcallv_public_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
9164#define forward_current(id, argc, argv) \
9165 forward_public(ARGF.current_file, id, argc, argv)
9166
9167/*
9168 * call-seq:
9169 * putc(int) -> int
9170 *
9171 * Equivalent to:
9172 *
9173 * $stdout.putc(int)
9174 *
9175 * See IO#putc for important information regarding multi-byte characters.
9176 *
9177 */
9178
9179static VALUE
9180rb_f_putc(VALUE recv, VALUE ch)
9181{
9182 VALUE r_stdout = rb_ractor_stdout();
9183 if (recv == r_stdout) {
9184 return rb_io_putc(recv, ch);
9185 }
9186 return forward(r_stdout, rb_intern("putc"), 1, &ch);
9187}
9188
9189
9190int
9191rb_str_end_with_asciichar(VALUE str, int c)
9192{
9193 long len = RSTRING_LEN(str);
9194 const char *ptr = RSTRING_PTR(str);
9195 rb_encoding *enc = rb_enc_from_index(ENCODING_GET(str));
9196 int n;
9197
9198 if (len == 0) return 0;
9199 if ((n = rb_enc_mbminlen(enc)) == 1) {
9200 return ptr[len - 1] == c;
9201 }
9202 return rb_enc_ascget(ptr + ((len - 1) / n) * n, ptr + len, &n, enc) == c;
9203}
9204
9205static VALUE
9206io_puts_ary(VALUE ary, VALUE out, int recur)
9207{
9208 VALUE tmp;
9209 long i;
9210
9211 if (recur) {
9212 tmp = rb_str_new2("[...]");
9213 rb_io_puts(1, &tmp, out);
9214 return Qtrue;
9215 }
9216 ary = rb_check_array_type(ary);
9217 if (NIL_P(ary)) return Qfalse;
9218 for (i=0; i<RARRAY_LEN(ary); i++) {
9219 tmp = RARRAY_AREF(ary, i);
9220 rb_io_puts(1, &tmp, out);
9221 }
9222 return Qtrue;
9223}
9224
9225/*
9226 * call-seq:
9227 * puts(*objects) -> nil
9228 *
9229 * Writes the given +objects+ to the stream, which must be open for writing;
9230 * returns +nil+.\
9231 * Writes a newline after each that does not already end with a newline sequence.
9232 * If called without arguments, writes a newline.
9233 * See {Line IO}[rdoc-ref:IO@Line+IO].
9234 *
9235 * Note that each added newline is the character <tt>"\n"</tt>,
9236 * not the output record separator (<tt>$\</tt>).
9237 *
9238 * Treatment for each object:
9239 *
9240 * - String: writes the string.
9241 * - Neither string nor array: writes <tt>object.to_s</tt>.
9242 * - Array: writes each element of the array; arrays may be nested.
9243 *
9244 * To keep these examples brief, we define this helper method:
9245 *
9246 * def show(*objects)
9247 * # Puts objects to file.
9248 * f = File.new('t.tmp', 'w+')
9249 * f.puts(objects)
9250 * # Return file content.
9251 * f.rewind
9252 * p f.read
9253 * f.close
9254 * end
9255 *
9256 * # Strings without newlines.
9257 * show('foo', 'bar', 'baz') # => "foo\nbar\nbaz\n"
9258 * # Strings, some with newlines.
9259 * show("foo\n", 'bar', "baz\n") # => "foo\nbar\nbaz\n"
9260 *
9261 * # Neither strings nor arrays:
9262 * show(0, 0.0, Rational(0, 1), Complex(9, 0), :zero)
9263 * # => "0\n0.0\n0/1\n9+0i\nzero\n"
9264 *
9265 * # Array of strings.
9266 * show(['foo', "bar\n", 'baz']) # => "foo\nbar\nbaz\n"
9267 * # Nested arrays.
9268 * show([[[0, 1], 2, 3], 4, 5]) # => "0\n1\n2\n3\n4\n5\n"
9269 *
9270 */
9271
9272VALUE
9273rb_io_puts(int argc, const VALUE *argv, VALUE out)
9274{
9275 VALUE line, args[2];
9276
9277 /* if no argument given, print newline. */
9278 if (argc == 0) {
9279 rb_io_write(out, rb_default_rs);
9280 return Qnil;
9281 }
9282 for (int i = 0; i < argc; i++) {
9283 // Convert the argument to a string:
9284 if (RB_TYPE_P(argv[i], T_STRING)) {
9285 line = argv[i];
9286 }
9287 else if (rb_exec_recursive(io_puts_ary, argv[i], out)) {
9288 continue;
9289 }
9290 else {
9291 line = rb_obj_as_string(argv[i]);
9292 }
9293
9294 // Write the line:
9295 int n = 0;
9296 if (RSTRING_LEN(line) == 0) {
9297 args[n++] = rb_default_rs;
9298 }
9299 else {
9300 args[n++] = line;
9301 if (!rb_str_end_with_asciichar(line, '\n')) {
9302 args[n++] = rb_default_rs;
9303 }
9304 }
9305
9306 rb_io_writev(out, n, args);
9307 }
9308
9309 return Qnil;
9310}
9311
9312/*
9313 * call-seq:
9314 * puts(*objects) -> nil
9315 *
9316 * Equivalent to
9317 *
9318 * $stdout.puts(objects)
9319 */
9320
9321static VALUE
9322rb_f_puts(int argc, VALUE *argv, VALUE recv)
9323{
9324 VALUE r_stdout = rb_ractor_stdout();
9325 if (recv == r_stdout) {
9326 return rb_io_puts(argc, argv, recv);
9327 }
9328 return forward(r_stdout, rb_intern("puts"), argc, argv);
9329}
9330
9331static VALUE
9332rb_p_write(VALUE str)
9333{
9334 VALUE args[2];
9335 args[0] = str;
9336 args[1] = rb_default_rs;
9337 VALUE r_stdout = rb_ractor_stdout();
9338 if (RB_TYPE_P(r_stdout, T_FILE) &&
9339 rb_method_basic_definition_p(CLASS_OF(r_stdout), id_write)) {
9340 io_writev(2, args, r_stdout);
9341 }
9342 else {
9343 rb_io_writev(r_stdout, 2, args);
9344 }
9345 return Qnil;
9346}
9347
9348void
9349rb_p(VALUE obj) /* for debug print within C code */
9350{
9351 rb_p_write(rb_obj_as_string(rb_inspect(obj)));
9352}
9353
9354static VALUE
9355rb_p_result(int argc, const VALUE *argv)
9356{
9357 VALUE ret = Qnil;
9358
9359 if (argc == 1) {
9360 ret = argv[0];
9361 }
9362 else if (argc > 1) {
9363 ret = rb_ary_new4(argc, argv);
9364 }
9365 VALUE r_stdout = rb_ractor_stdout();
9366 if (RB_TYPE_P(r_stdout, T_FILE)) {
9367 rb_uninterruptible(rb_io_flush, r_stdout);
9368 }
9369 return ret;
9370}
9371
9372/*
9373 * call-seq:
9374 * p(object) -> obj
9375 * p(*objects) -> array of objects
9376 * p -> nil
9377 *
9378 * For each object +obj+, executes:
9379 *
9380 * $stdout.write(obj.inspect, "\n")
9381 *
9382 * With one object given, returns the object;
9383 * with multiple objects given, returns an array containing the objects;
9384 * with no object given, returns +nil+.
9385 *
9386 * Examples:
9387 *
9388 * r = Range.new(0, 4)
9389 * p r # => 0..4
9390 * p [r, r, r] # => [0..4, 0..4, 0..4]
9391 * p # => nil
9392 *
9393 * Output:
9394 *
9395 * 0..4
9396 * [0..4, 0..4, 0..4]
9397 *
9398 * Kernel#p is designed for debugging purposes.
9399 * Ruby implementations may define Kernel#p to be uninterruptible
9400 * in whole or in part.
9401 * On CRuby, Kernel#p's writing of data is uninterruptible.
9402 */
9403
9404static VALUE
9405rb_f_p(int argc, VALUE *argv, VALUE self)
9406{
9407 int i;
9408 for (i=0; i<argc; i++) {
9409 VALUE inspected = rb_obj_as_string(rb_inspect(argv[i]));
9410 rb_uninterruptible(rb_p_write, inspected);
9411 }
9412 return rb_p_result(argc, argv);
9413}
9414
9415/*
9416 * call-seq:
9417 * display(port = $>) -> nil
9418 *
9419 * Writes +self+ on the given port:
9420 *
9421 * 1.display
9422 * "cat".display
9423 * [ 4, 5, 6 ].display
9424 * puts
9425 *
9426 * Output:
9427 *
9428 * 1cat[4, 5, 6]
9429 *
9430 */
9431
9432static VALUE
9433rb_obj_display(int argc, VALUE *argv, VALUE self)
9434{
9435 VALUE out;
9436
9437 out = (!rb_check_arity(argc, 0, 1) ? rb_ractor_stdout() : argv[0]);
9438 rb_io_write(out, self);
9439
9440 return Qnil;
9441}
9442
9443static int
9444rb_stderr_to_original_p(VALUE err)
9445{
9446 return (err == orig_stderr || RFILE(orig_stderr)->fptr->fd < 0);
9447}
9448
9449void
9450rb_write_error2(const char *mesg, long len)
9451{
9452 VALUE out = rb_ractor_stderr();
9453 if (rb_stderr_to_original_p(out)) {
9454#ifdef _WIN32
9455 if (isatty(fileno(stderr))) {
9456 if (rb_w32_write_console(rb_str_new(mesg, len), fileno(stderr)) > 0) return;
9457 }
9458#endif
9459 if (fwrite(mesg, sizeof(char), (size_t)len, stderr) < (size_t)len) {
9460 /* failed to write to stderr, what can we do? */
9461 return;
9462 }
9463 }
9464 else {
9465 rb_io_write(out, rb_str_new(mesg, len));
9466 }
9467}
9468
9469void
9470rb_write_error(const char *mesg)
9471{
9472 rb_write_error2(mesg, strlen(mesg));
9473}
9474
9475void
9476rb_write_error_str(VALUE mesg)
9477{
9478 VALUE out = rb_ractor_stderr();
9479 /* a stopgap measure for the time being */
9480 if (rb_stderr_to_original_p(out)) {
9481 size_t len = (size_t)RSTRING_LEN(mesg);
9482#ifdef _WIN32
9483 if (isatty(fileno(stderr))) {
9484 if (rb_w32_write_console(mesg, fileno(stderr)) > 0) return;
9485 }
9486#endif
9487 if (fwrite(RSTRING_PTR(mesg), sizeof(char), len, stderr) < len) {
9488 RB_GC_GUARD(mesg);
9489 return;
9490 }
9491 }
9492 else {
9493 /* may unlock GVL, and */
9494 rb_io_write(out, mesg);
9495 }
9496}
9497
9498int
9499rb_stderr_tty_p(void)
9500{
9501 if (rb_stderr_to_original_p(rb_ractor_stderr()))
9502 return isatty(fileno(stderr));
9503 return 0;
9504}
9505
9506static void
9507must_respond_to(ID mid, VALUE val, ID id)
9508{
9509 if (!rb_respond_to(val, mid)) {
9510 rb_raise(rb_eTypeError, "%"PRIsVALUE" must have %"PRIsVALUE" method, %"PRIsVALUE" given",
9511 rb_id2str(id), rb_id2str(mid),
9512 rb_obj_class(val));
9513 }
9514}
9515
9516static void
9517stdin_setter(VALUE val, ID id, VALUE *ptr)
9518{
9520}
9521
9522static VALUE
9523stdin_getter(ID id, VALUE *ptr)
9524{
9525 return rb_ractor_stdin();
9526}
9527
9528static void
9529stdout_setter(VALUE val, ID id, VALUE *ptr)
9530{
9531 must_respond_to(id_write, val, id);
9533}
9534
9535static VALUE
9536stdout_getter(ID id, VALUE *ptr)
9537{
9538 return rb_ractor_stdout();
9539}
9540
9541static void
9542stderr_setter(VALUE val, ID id, VALUE *ptr)
9543{
9544 must_respond_to(id_write, val, id);
9546}
9547
9548static VALUE
9549stderr_getter(ID id, VALUE *ptr)
9550{
9551 return rb_ractor_stderr();
9552}
9553
9554static VALUE
9555allocate_and_open_new_file(VALUE klass)
9556{
9557 VALUE self = io_alloc(klass);
9558 rb_io_make_open_file(self);
9559 return self;
9560}
9561
9562VALUE
9563rb_io_open_descriptor(VALUE klass, int descriptor, int mode, VALUE path, VALUE timeout, struct rb_io_encoding *encoding)
9564{
9565 int state;
9566 VALUE self = rb_protect(allocate_and_open_new_file, klass, &state);
9567 if (state) {
9568 /* if we raised an exception allocating an IO object, but the caller
9569 intended to transfer ownership of this FD to us, close the fd before
9570 raising the exception. Otherwise, we would leak a FD - the caller
9571 expects GC to close the file, but we never got around to assigning
9572 it to a rb_io. */
9573 if (!(mode & FMODE_EXTERNAL)) {
9574 maygvl_close(descriptor, 0);
9575 }
9576 rb_jump_tag(state);
9577 }
9578
9579
9580 rb_io_t *io = RFILE(self)->fptr;
9581 io->self = self;
9582 io->fd = descriptor;
9583 io->mode = mode;
9584
9585 /* At this point, Ruby fully owns the descriptor, and will close it when
9586 the IO gets GC'd (unless FMODE_EXTERNAL was set), no matter what happens
9587 in the rest of this method. */
9588
9589 if (NIL_P(path)) {
9590 io->pathv = Qnil;
9591 }
9592 else {
9593 StringValue(path);
9594 io->pathv = rb_str_new_frozen(path);
9595 }
9596
9597 io->timeout = timeout;
9598
9599 ccan_list_head_init(&io->blocking_operations);
9600 io->closing_ec = NULL;
9601 io->wakeup_mutex = Qnil;
9602 io->fork_generation = GET_VM()->fork_gen;
9603
9604 if (encoding) {
9605 io->encs = *encoding;
9606 }
9607
9608 rb_update_max_fd(descriptor);
9609
9610 return self;
9611}
9612
9613static VALUE
9614prep_io(int fd, enum rb_io_mode fmode, VALUE klass, const char *path)
9615{
9616 VALUE path_value = Qnil;
9617 rb_encoding *e;
9618 struct rb_io_encoding convconfig;
9619
9620 if (path) {
9621 path_value = rb_obj_freeze(rb_str_new_cstr(path));
9622 }
9623
9624 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
9625 rb_io_ext_int_to_encs(e, NULL, &convconfig.enc, &convconfig.enc2, fmode);
9626 convconfig.ecflags = (fmode & FMODE_READABLE) ?
9629#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9630 convconfig.ecflags |= (fmode & FMODE_WRITABLE) ?
9631 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
9632 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
9633#endif
9634 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.enc2, convconfig.ecflags);
9635 convconfig.ecopts = Qnil;
9636
9637 VALUE self = rb_io_open_descriptor(klass, fd, fmode, path_value, Qnil, &convconfig);
9638 rb_io_t*io = RFILE(self)->fptr;
9639
9640 if (!io_check_tty(io)) {
9641#ifdef __CYGWIN__
9642 io->mode |= FMODE_BINMODE;
9643 setmode(fd, O_BINARY);
9644#endif
9645 }
9646
9647 return self;
9648}
9649
9650VALUE
9651rb_io_fdopen(int fd, int oflags, const char *path)
9652{
9653 VALUE klass = rb_cIO;
9654
9655 if (path && strcmp(path, "-")) klass = rb_cFile;
9656 return prep_io(fd, rb_io_oflags_fmode(oflags), klass, path);
9657}
9658
9659static VALUE
9660prep_stdio(FILE *f, enum rb_io_mode fmode, VALUE klass, const char *path)
9661{
9662 rb_io_t *fptr;
9663 VALUE io = prep_io(fileno(f), fmode|FMODE_EXTERNAL|DEFAULT_TEXTMODE, klass, path);
9664
9665 GetOpenFile(io, fptr);
9667#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9668 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
9669 if (fmode & FMODE_READABLE) {
9671 }
9672#endif
9673 fptr->stdio_file = f;
9674
9675 return io;
9676}
9677
9678VALUE
9679rb_io_prep_stdin(void)
9680{
9681 return prep_stdio(stdin, FMODE_READABLE, rb_cIO, "<STDIN>");
9682}
9683
9684VALUE
9685rb_io_prep_stdout(void)
9686{
9687 return prep_stdio(stdout, FMODE_WRITABLE|FMODE_SIGNAL_ON_EPIPE, rb_cIO, "<STDOUT>");
9688}
9689
9690VALUE
9691rb_io_prep_stderr(void)
9692{
9693 return prep_stdio(stderr, FMODE_WRITABLE|FMODE_SYNC, rb_cIO, "<STDERR>");
9694}
9695
9696FILE *
9698{
9699 if (!fptr->stdio_file) {
9700 int oflags = rb_io_fmode_oflags(fptr->mode) & ~O_EXCL;
9701 fptr->stdio_file = rb_fdopen(fptr->fd, rb_io_oflags_modestr(oflags));
9702 }
9703 return fptr->stdio_file;
9704}
9705
9706static inline void
9707rb_io_buffer_init(struct rb_io_internal_buffer *buf)
9708{
9709 buf->ptr = NULL;
9710 buf->off = 0;
9711 buf->len = 0;
9712 buf->capa = 0;
9713}
9714
9715static inline rb_io_t *
9716rb_io_fptr_new(void)
9717{
9718 rb_io_t *fp = ALLOC(rb_io_t);
9719 fp->self = Qnil;
9720 fp->fd = -1;
9721 fp->stdio_file = NULL;
9722 fp->mode = 0;
9723 fp->pid = 0;
9724 fp->lineno = 0;
9725 fp->pathv = Qnil;
9726 fp->finalize = 0;
9727 rb_io_buffer_init(&fp->wbuf);
9728 rb_io_buffer_init(&fp->rbuf);
9729 rb_io_buffer_init(&fp->cbuf);
9730 fp->readconv = NULL;
9731 fp->writeconv = NULL;
9733 fp->writeconv_pre_ecflags = 0;
9735 fp->writeconv_initialized = 0;
9736 fp->tied_io_for_writing = 0;
9737 fp->encs.enc = NULL;
9738 fp->encs.enc2 = NULL;
9739 fp->encs.ecflags = 0;
9740 fp->encs.ecopts = Qnil;
9741 fp->write_lock = Qnil;
9742 fp->timeout = Qnil;
9743 ccan_list_head_init(&fp->blocking_operations);
9744 fp->closing_ec = NULL;
9745 fp->wakeup_mutex = Qnil;
9746 fp->fork_generation = GET_VM()->fork_gen;
9747 return fp;
9748}
9749
9750rb_io_t *
9751rb_io_make_open_file(VALUE obj)
9752{
9753 rb_io_t *fp = 0;
9754
9755 Check_Type(obj, T_FILE);
9756 if (RFILE(obj)->fptr) {
9757 rb_io_close(obj);
9758 rb_io_fptr_finalize(RFILE(obj)->fptr);
9759 RFILE(obj)->fptr = 0;
9760 }
9761 fp = rb_io_fptr_new();
9762 fp->self = obj;
9763 RFILE(obj)->fptr = fp;
9764 return fp;
9765}
9766
9767static VALUE io_initialize(VALUE io, VALUE fnum, VALUE vmode, VALUE opt);
9768
9769/*
9770 * call-seq:
9771 * IO.new(fd, mode = 'r', **opts) -> io
9772 *
9773 * Creates and returns a new \IO object (file stream) from a file descriptor.
9774 *
9775 * \IO.new may be useful for interaction with low-level libraries.
9776 * For higher-level interactions, it may be simpler to create
9777 * the file stream using File.open.
9778 *
9779 * Argument +fd+ must be a valid file descriptor (integer):
9780 *
9781 * path = 't.tmp'
9782 * fd = IO.sysopen(path) # => 3
9783 * IO.new(fd) # => #<IO:fd 3>
9784 *
9785 * The new \IO object does not inherit encoding
9786 * (because the integer file descriptor does not have an encoding):
9787 *
9788 * File.read('t.ja') # => "こんにちは"
9789 * fd = IO.sysopen('t.ja', 'rb')
9790 * io = IO.new(fd)
9791 * io.external_encoding # => #<Encoding:UTF-8> # Not ASCII-8BIT.
9792 *
9793 * Optional argument +mode+ (defaults to 'r') must specify a valid mode;
9794 * see {Access Modes}[rdoc-ref:File@Access+Modes]:
9795 *
9796 * IO.new(fd, 'w') # => #<IO:fd 3>
9797 * IO.new(fd, File::WRONLY) # => #<IO:fd 3>
9798 *
9799 * Optional keyword arguments +opts+ specify:
9800 *
9801 * - {Open Options}[rdoc-ref:IO@Open+Options].
9802 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
9803 *
9804 * Examples:
9805 *
9806 * IO.new(fd, internal_encoding: nil) # => #<IO:fd 3>
9807 * IO.new(fd, autoclose: true) # => #<IO:fd 3>
9808 *
9809 */
9810
9811static VALUE
9812rb_io_initialize(int argc, VALUE *argv, VALUE io)
9813{
9814 VALUE fnum, vmode;
9815 VALUE opt;
9816
9817 rb_scan_args(argc, argv, "11:", &fnum, &vmode, &opt);
9818 return io_initialize(io, fnum, vmode, opt);
9819}
9820
9821static VALUE
9822io_initialize(VALUE io, VALUE fnum, VALUE vmode, VALUE opt)
9823{
9824 rb_io_t *fp;
9825 int fd, oflags = O_RDONLY;
9826 enum rb_io_mode fmode;
9827 struct rb_io_encoding convconfig;
9828#if defined(HAVE_FCNTL) && defined(F_GETFL)
9829 int ofmode;
9830#else
9831 struct stat st;
9832#endif
9833
9834 rb_io_extract_modeenc(&vmode, 0, opt, &oflags, &fmode, &convconfig);
9835
9836 fd = NUM2INT(fnum);
9837 if (rb_reserved_fd_p(fd)) {
9838 rb_raise(rb_eArgError, "The given fd is not accessible because RubyVM reserves it");
9839 }
9840#if defined(HAVE_FCNTL) && defined(F_GETFL)
9841 oflags = fcntl(fd, F_GETFL);
9842 if (oflags == -1) rb_sys_fail(0);
9843#else
9844 if (fstat(fd, &st) < 0) rb_sys_fail(0);
9845#endif
9846 rb_update_max_fd(fd);
9847#if defined(HAVE_FCNTL) && defined(F_GETFL)
9848 ofmode = rb_io_oflags_fmode(oflags);
9849 if (NIL_P(vmode)) {
9850 fmode = ofmode;
9851 }
9852 else if ((~ofmode & fmode) & FMODE_READWRITE) {
9853 VALUE error = INT2FIX(EINVAL);
9855 }
9856#endif
9857 VALUE path = Qnil;
9858
9859 if (!NIL_P(opt)) {
9860 if (rb_hash_aref(opt, sym_autoclose) == Qfalse) {
9861 fmode |= FMODE_EXTERNAL;
9862 }
9863
9864 path = rb_hash_aref(opt, RB_ID2SYM(idPath));
9865 if (!NIL_P(path)) {
9866 StringValue(path);
9867 path = rb_str_new_frozen(path);
9868 }
9869 }
9870
9871 MakeOpenFile(io, fp);
9872 fp->self = io;
9873 fp->fd = fd;
9874 fp->mode = fmode;
9875 fp->encs = convconfig;
9876 fp->pathv = path;
9877 fp->timeout = Qnil;
9878 ccan_list_head_init(&fp->blocking_operations);
9879 fp->closing_ec = NULL;
9880 fp->wakeup_mutex = Qnil;
9881 fp->fork_generation = GET_VM()->fork_gen;
9882 clear_codeconv(fp);
9883 io_check_tty(fp);
9884 if (fileno(stdin) == fd)
9885 fp->stdio_file = stdin;
9886 else if (fileno(stdout) == fd)
9887 fp->stdio_file = stdout;
9888 else if (fileno(stderr) == fd)
9889 fp->stdio_file = stderr;
9890
9891 if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
9892 return io;
9893}
9894
9895/*
9896 * call-seq:
9897 * set_encoding_by_bom -> encoding or nil
9898 *
9899 * If the stream begins with a BOM
9900 * ({byte order marker}[https://en.wikipedia.org/wiki/Byte_order_mark]),
9901 * consumes the BOM and sets the external encoding accordingly;
9902 * returns the result encoding if found, or +nil+ otherwise:
9903 *
9904 * File.write('t.tmp', "\u{FEFF}abc")
9905 * io = File.open('t.tmp', 'rb')
9906 * io.set_encoding_by_bom # => #<Encoding:UTF-8>
9907 * io.close
9908 *
9909 * File.write('t.tmp', 'abc')
9910 * io = File.open('t.tmp', 'rb')
9911 * io.set_encoding_by_bom # => nil
9912 * io.close
9913 *
9914 * Raises an exception if the stream is not binmode
9915 * or its encoding has already been set.
9916 *
9917 */
9918
9919static VALUE
9920rb_io_set_encoding_by_bom(VALUE io)
9921{
9922 rb_io_t *fptr;
9923
9924 GetOpenFile(io, fptr);
9925 if (!(fptr->mode & FMODE_BINMODE)) {
9926 rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
9927 }
9928 if (fptr->encs.enc2) {
9929 rb_raise(rb_eArgError, "encoding conversion is set");
9930 }
9931 else if (fptr->encs.enc && fptr->encs.enc != rb_ascii8bit_encoding()) {
9932 rb_raise(rb_eArgError, "encoding is set to %s already",
9933 rb_enc_name(fptr->encs.enc));
9934 }
9935 if (!io_set_encoding_by_bom(io)) return Qnil;
9936 return rb_enc_from_encoding(fptr->encs.enc);
9937}
9938
9939/*
9940 * :markup: markdown
9941 *
9942 * call-seq:
9943 * File.new(path, mode = 'r', permissions = 0666, **options) -> file
9944 *
9945 * Opens the file as specified by the given arguments.
9946 * Creates and returns a new open \File object for that file;
9947 * the opened file is in non-synchronous mode.
9948 *
9949 * Argument `path` must the string path to an existing filesystem entry:
9950 *
9951 * ```ruby
9952 * file = File.new('doc/maintainers.md') # => #<File:doc/maintainers.md>
9953 * file.close # Clean up.
9954 * tty = File.new('/dev/tty') # => #<File:/dev/tty>
9955 * tty.close # Clean up.
9956 * ```
9957 *
9958 * Note that the caller is responsible for closing the file;
9959 * see File.open for automatic closing.
9960 *
9961 * Optional argument `mode` (defaults to `'r'`) must specify a valid mode;
9962 * see [Access Modes](rdoc-ref:File@Access+Modes):
9963 *
9964 * ```ruby
9965 * file = File.new('t.tmp', 'w') # => #<File:t.tmp>
9966 * file.close # Clean up.
9967 * file = File.new('t.tmp', File::RDONLY) # => #<File:t.tmp>
9968 * file.close # Clean up.
9969 * ```
9970 *
9971 * Optional argument `permissions` (defaults to `0666`) must specify valid permissions;
9972 * see [File Permissions](rdoc-ref:File@File+Permissions):
9973 *
9974 * ```ruby
9975 * file = File.new('t.tmp', 'w', 0644) # => #<File:t.tmp>
9976 * file.close # Clean up.
9977 * file = File.new('t.tmp', 'w', 0444) # => #<File:t.tmp>
9978 * file.close # Clean up.
9979 * ```
9980 *
9981 * Optional keyword arguments `options` specify:
9982 *
9983 * - [Open Options](rdoc-ref:IO@Open+Options).
9984 * - [Encoding options](rdoc-ref:encodings.rdoc@Encoding+Options).
9985 *
9986 */
9987
9988static VALUE
9989rb_file_initialize(int argc, VALUE *argv, VALUE io)
9990{
9991 if (RFILE(io)->fptr) {
9992 rb_raise(rb_eRuntimeError, "reinitializing File");
9993 }
9994 VALUE fname, vmode, vperm, opt;
9995 int posargc = rb_scan_args(argc, argv, "12:", &fname, &vmode, &vperm, &opt);
9996 if (posargc < 3) { /* perm is File only */
9997 VALUE fd = rb_check_to_int(fname);
9998
9999 if (!NIL_P(fd)) {
10000 return io_initialize(io, fd, vmode, opt);
10001 }
10002 }
10003 return rb_open_file(io, fname, vmode, vperm, opt);
10004}
10005
10006/* :nodoc: */
10007static VALUE
10008rb_io_s_new(int argc, VALUE *argv, VALUE klass)
10009{
10010 if (rb_block_given_p()) {
10011 VALUE cname = rb_obj_as_string(klass);
10012
10013 rb_warn("%"PRIsVALUE"::new() does not take block; use %"PRIsVALUE"::open() instead",
10014 cname, cname);
10015 }
10016 return rb_class_new_instance_kw(argc, argv, klass, RB_PASS_CALLED_KEYWORDS);
10017}
10018
10019
10020/*
10021 * call-seq:
10022 * IO.for_fd(fd, mode = 'r', **opts) -> io
10023 *
10024 * Synonym for IO.new.
10025 *
10026 */
10027
10028static VALUE
10029rb_io_s_for_fd(int argc, VALUE *argv, VALUE klass)
10030{
10031 VALUE io = rb_obj_alloc(klass);
10032 rb_io_initialize(argc, argv, io);
10033 return io;
10034}
10035
10036/*
10037 * call-seq:
10038 * ios.autoclose? -> true or false
10039 *
10040 * Returns +true+ if the underlying file descriptor of _ios_ will be
10041 * closed at its finalization or at calling #close, otherwise +false+.
10042 */
10043
10044static VALUE
10045rb_io_autoclose_p(VALUE io)
10046{
10047 rb_io_t *fptr = RFILE(io)->fptr;
10048 rb_io_check_closed(fptr);
10049 return RBOOL(!(fptr->mode & FMODE_EXTERNAL));
10050}
10051
10052/*
10053 * call-seq:
10054 * io.autoclose = bool -> true or false
10055 *
10056 * Sets auto-close flag.
10057 *
10058 * f = File.open(File::NULL)
10059 * IO.for_fd(f.fileno).close
10060 * f.gets # raises Errno::EBADF
10061 *
10062 * f = File.open(File::NULL)
10063 * g = IO.for_fd(f.fileno)
10064 * g.autoclose = false
10065 * g.close
10066 * f.gets # won't cause Errno::EBADF
10067 */
10068
10069static VALUE
10070rb_io_set_autoclose(VALUE io, VALUE autoclose)
10071{
10072 rb_io_t *fptr;
10073 GetOpenFile(io, fptr);
10074 if (!RTEST(autoclose))
10075 fptr->mode |= FMODE_EXTERNAL;
10076 else
10077 fptr->mode &= ~FMODE_EXTERNAL;
10078 return autoclose;
10079}
10080
10081static VALUE
10082io_wait_event(VALUE io, int event, VALUE timeout, int return_io)
10083{
10084 VALUE result = rb_io_wait(io, RB_INT2NUM(event), timeout);
10085
10086 if (!RB_TEST(result)) {
10087 return Qnil;
10088 }
10089
10090 int mask = RB_NUM2INT(result);
10091
10092 if (mask & event) {
10093 if (return_io)
10094 return io;
10095 else
10096 return result;
10097 }
10098 else {
10099 return Qfalse;
10100 }
10101}
10102
10103/*
10104 * call-seq:
10105 * io.wait_readable -> truthy or falsy
10106 * io.wait_readable(timeout) -> truthy or falsy
10107 *
10108 * Waits until IO is readable and returns a truthy value, or a falsy
10109 * value when times out. Returns a truthy value immediately when
10110 * buffered data is available.
10111 */
10112
10113static VALUE
10114io_wait_readable(int argc, VALUE *argv, VALUE io)
10115{
10116 rb_io_t *fptr;
10117
10118 RB_IO_POINTER(io, fptr);
10120
10121 if (rb_io_read_pending(fptr)) return Qtrue;
10122
10123 rb_check_arity(argc, 0, 1);
10124 VALUE timeout = (argc == 1 ? argv[0] : Qnil);
10125
10126 return io_wait_event(io, RUBY_IO_READABLE, timeout, 1);
10127}
10128
10129/*
10130 * call-seq:
10131 * io.wait_writable -> truthy or falsy
10132 * io.wait_writable(timeout) -> truthy or falsy
10133 *
10134 * Waits until IO is writable and returns a truthy value or a falsy
10135 * value when times out.
10136 */
10137static VALUE
10138io_wait_writable(int argc, VALUE *argv, VALUE io)
10139{
10140 rb_io_t *fptr;
10141
10142 RB_IO_POINTER(io, fptr);
10144
10145 rb_check_arity(argc, 0, 1);
10146 VALUE timeout = (argc == 1 ? argv[0] : Qnil);
10147
10148 return io_wait_event(io, RUBY_IO_WRITABLE, timeout, 1);
10149}
10150
10151/*
10152 * call-seq:
10153 * io.wait_priority -> truthy or falsy
10154 * io.wait_priority(timeout) -> truthy or falsy
10155 *
10156 * Waits until IO is priority and returns a truthy value or a falsy
10157 * value when times out. Priority data is sent and received using
10158 * the Socket::MSG_OOB flag and is typically limited to streams.
10159 */
10160static VALUE
10161io_wait_priority(int argc, VALUE *argv, VALUE io)
10162{
10163 rb_io_t *fptr = NULL;
10164
10165 RB_IO_POINTER(io, fptr);
10167
10168 if (rb_io_read_pending(fptr)) return Qtrue;
10169
10170 rb_check_arity(argc, 0, 1);
10171 VALUE timeout = argc == 1 ? argv[0] : Qnil;
10172
10173 return io_wait_event(io, RUBY_IO_PRIORITY, timeout, 1);
10174}
10175
10176static int
10177wait_mode_sym(VALUE mode)
10178{
10179 if (mode == ID2SYM(rb_intern("r"))) {
10180 return RB_WAITFD_IN;
10181 }
10182 if (mode == ID2SYM(rb_intern("read"))) {
10183 return RB_WAITFD_IN;
10184 }
10185 if (mode == ID2SYM(rb_intern("readable"))) {
10186 return RB_WAITFD_IN;
10187 }
10188 if (mode == ID2SYM(rb_intern("w"))) {
10189 return RB_WAITFD_OUT;
10190 }
10191 if (mode == ID2SYM(rb_intern("write"))) {
10192 return RB_WAITFD_OUT;
10193 }
10194 if (mode == ID2SYM(rb_intern("writable"))) {
10195 return RB_WAITFD_OUT;
10196 }
10197 if (mode == ID2SYM(rb_intern("rw"))) {
10198 return RB_WAITFD_IN|RB_WAITFD_OUT;
10199 }
10200 if (mode == ID2SYM(rb_intern("read_write"))) {
10201 return RB_WAITFD_IN|RB_WAITFD_OUT;
10202 }
10203 if (mode == ID2SYM(rb_intern("readable_writable"))) {
10204 return RB_WAITFD_IN|RB_WAITFD_OUT;
10205 }
10206
10207 rb_raise(rb_eArgError, "unsupported mode: %"PRIsVALUE, mode);
10208}
10209
10210static inline enum rb_io_event
10211io_event_from_value(VALUE value)
10212{
10213 int events = RB_NUM2INT(value);
10214
10215 if (events <= 0) rb_raise(rb_eArgError, "Events must be positive integer!");
10216
10217 return events;
10218}
10219
10220/*
10221 * call-seq:
10222 * io.wait(events, timeout) -> event mask, false or nil
10223 * io.wait(*event_symbols[, timeout]) -> self, true, or false
10224 *
10225 * Waits until the IO becomes ready for the specified events and returns the
10226 * subset of events that become ready, or a falsy value when times out.
10227 *
10228 * The events can be a bit mask of +IO::READABLE+, +IO::WRITABLE+ or
10229 * +IO::PRIORITY+.
10230 *
10231 * Returns an event mask (truthy value) immediately when buffered data is
10232 * available.
10233 *
10234 * The second form: if one or more event symbols (+:read+, +:write+, or
10235 * +:read_write+) are passed, the event mask is the bit OR of the bitmask
10236 * corresponding to those symbols. In this form, +timeout+ is optional, the
10237 * order of the arguments is arbitrary, and returns +io+ if any of the
10238 * events is ready.
10239 */
10240
10241static VALUE
10242io_wait(int argc, VALUE *argv, VALUE io)
10243{
10244 VALUE timeout = Qundef;
10245 enum rb_io_event events = 0;
10246 int return_io = 0;
10247
10248 if (argc != 2 || (RB_SYMBOL_P(argv[0]) || RB_SYMBOL_P(argv[1]))) {
10249 // We'd prefer to return the actual mask, but this form would return the io itself:
10250 return_io = 1;
10251
10252 // Slow/messy path:
10253 for (int i = 0; i < argc; i += 1) {
10254 if (RB_SYMBOL_P(argv[i])) {
10255 events |= wait_mode_sym(argv[i]);
10256 }
10257 else if (UNDEF_P(timeout)) {
10258 rb_time_interval(timeout = argv[i]);
10259 }
10260 else {
10261 rb_raise(rb_eArgError, "timeout given more than once");
10262 }
10263 }
10264
10265 if (UNDEF_P(timeout)) timeout = Qnil;
10266
10267 if (events == 0) {
10268 events = RUBY_IO_READABLE;
10269 }
10270 }
10271 else /* argc == 2 and neither are symbols */ {
10272 // This is the fast path:
10273 events = io_event_from_value(argv[0]);
10274 timeout = argv[1];
10275 }
10276
10277 if (events & RUBY_IO_READABLE) {
10278 rb_io_t *fptr = NULL;
10279 RB_IO_POINTER(io, fptr);
10280
10281 if (rb_io_read_pending(fptr)) {
10282 // This was the original behaviour:
10283 if (return_io) return Qtrue;
10284 // New behaviour always returns an event mask:
10285 else return RB_INT2NUM(RUBY_IO_READABLE);
10286 }
10287 }
10288
10289 return io_wait_event(io, events, timeout, return_io);
10290}
10291
10292static void
10293argf_mark_and_move(void *ptr)
10294{
10295 struct argf *p = ptr;
10296 rb_gc_mark_and_move(&p->filename);
10297 rb_gc_mark_and_move(&p->current_file);
10298 rb_gc_mark_and_move(&p->argv);
10299 rb_gc_mark_and_move(&p->inplace);
10300 rb_gc_mark_and_move(&p->encs.ecopts);
10301}
10302
10303static size_t
10304argf_memsize(const void *ptr)
10305{
10306 const struct argf *p = ptr;
10307 size_t size = sizeof(*p);
10308 return size;
10309}
10310
10311static const rb_data_type_t argf_type = {
10312 "ARGF",
10313 {argf_mark_and_move, RUBY_TYPED_DEFAULT_FREE, argf_memsize, argf_mark_and_move},
10314 0, 0, RUBY_TYPED_THREAD_SAFE_FREE | RUBY_TYPED_WB_PROTECTED
10315};
10316
10317static inline void
10318argf_init(VALUE argf, struct argf *p, VALUE v)
10319{
10320 p->filename = Qnil;
10321 p->current_file = Qnil;
10322 p->lineno = 0;
10323 RB_OBJ_WRITE(argf, &p->argv, v);
10324}
10325
10326static VALUE
10327argf_alloc(VALUE klass)
10328{
10329 struct argf *p;
10330 VALUE argf = TypedData_Make_Struct(klass, struct argf, &argf_type, p);
10331
10332 argf_init(argf, p, Qnil);
10333 return argf;
10334}
10335
10336#undef rb_argv
10337
10338/* :nodoc: */
10339static VALUE
10340argf_initialize(VALUE argf, VALUE argv)
10341{
10342 memset(&ARGF, 0, sizeof(ARGF));
10343 argf_init(argf, &ARGF, argv);
10344
10345 return argf;
10346}
10347
10348/* :nodoc: */
10349static VALUE
10350argf_initialize_copy(VALUE argf, VALUE orig)
10351{
10352 if (!OBJ_INIT_COPY(argf, orig)) return argf;
10353 ARGF = argf_of(orig);
10354 rb_gc_writebarrier_remember(argf);
10355 ARGF_SET(argv, rb_obj_dup(ARGF.argv));
10356 return argf;
10357}
10358
10359/*
10360 * call-seq:
10361 * ARGF.lineno = integer -> integer
10362 *
10363 * Sets the line number of ARGF as a whole to the given Integer.
10364 *
10365 * ARGF sets the line number automatically as you read data, so normally
10366 * you will not need to set it explicitly. To access the current line number
10367 * use ARGF.lineno.
10368 *
10369 * For example:
10370 *
10371 * ARGF.lineno #=> 0
10372 * ARGF.readline #=> "This is line 1\n"
10373 * ARGF.lineno #=> 1
10374 * ARGF.lineno = 0 #=> 0
10375 * ARGF.lineno #=> 0
10376 */
10377static VALUE
10378argf_set_lineno(VALUE argf, VALUE val)
10379{
10380 ARGF.lineno = NUM2INT(val);
10381 ARGF.last_lineno = ARGF.lineno;
10382 return val;
10383}
10384
10385/*
10386 * call-seq:
10387 * ARGF.lineno -> integer
10388 *
10389 * Returns the current line number of ARGF as a whole. This value
10390 * can be set manually with ARGF.lineno=.
10391 *
10392 * For example:
10393 *
10394 * ARGF.lineno #=> 0
10395 * ARGF.readline #=> "This is line 1\n"
10396 * ARGF.lineno #=> 1
10397 */
10398static VALUE
10399argf_lineno(VALUE argf)
10400{
10401 return INT2FIX(ARGF.lineno);
10402}
10403
10404static VALUE
10405argf_forward(int argc, VALUE *argv, VALUE argf)
10406{
10407 return forward_current(rb_frame_this_func(), argc, argv);
10408}
10409
10410#define next_argv() argf_next_argv(argf)
10411#define ARGF_GENERIC_INPUT_P() \
10412 (ARGF.current_file == rb_stdin && !RB_TYPE_P(ARGF.current_file, T_FILE))
10413#define ARGF_FORWARD(argc, argv) do {\
10414 if (ARGF_GENERIC_INPUT_P())\
10415 return argf_forward((argc), (argv), argf);\
10416} while (0)
10417#define NEXT_ARGF_FORWARD(argc, argv) do {\
10418 if (!next_argv()) return Qnil;\
10419 ARGF_FORWARD((argc), (argv));\
10420} while (0)
10421
10422static void
10423argf_close(VALUE argf)
10424{
10425 VALUE file = ARGF.current_file;
10426 if (file == rb_stdin) return;
10427 if (RB_TYPE_P(file, T_FILE)) {
10428 rb_io_set_write_io(file, Qnil);
10429 }
10430 io_close(file);
10431 ARGF.init_p = -1;
10432}
10433
10434static int
10435argf_next_argv(VALUE argf)
10436{
10437 char *fn;
10438 rb_io_t *fptr;
10439 int stdout_binmode = 0;
10440 enum rb_io_mode fmode;
10441
10442 VALUE r_stdout = rb_ractor_stdout();
10443
10444 if (RB_TYPE_P(r_stdout, T_FILE)) {
10445 GetOpenFile(r_stdout, fptr);
10446 if (fptr->mode & FMODE_BINMODE)
10447 stdout_binmode = 1;
10448 }
10449
10450 if (ARGF.init_p == 0) {
10451 if (!NIL_P(ARGF.argv) && RARRAY_LEN(ARGF.argv) > 0) {
10452 ARGF.next_p = 1;
10453 }
10454 else {
10455 ARGF.next_p = -1;
10456 }
10457 ARGF.init_p = 1;
10458 }
10459 else {
10460 if (NIL_P(ARGF.argv)) {
10461 ARGF.next_p = -1;
10462 }
10463 else if (ARGF.next_p == -1 && RARRAY_LEN(ARGF.argv) > 0) {
10464 ARGF.next_p = 1;
10465 }
10466 }
10467
10468 if (ARGF.next_p == 1) {
10469 if (ARGF.init_p == 1) argf_close(argf);
10470 retry:
10471 if (RARRAY_LEN(ARGF.argv) > 0) {
10472 VALUE filename = rb_ary_shift(ARGF.argv);
10473 FilePathValue(filename);
10474 ARGF_SET(filename, filename);
10475 filename = rb_str_encode_ospath(filename);
10476 fn = StringValueCStr(filename);
10477 if (RSTRING_LEN(filename) == 1 && fn[0] == '-') {
10478 ARGF_SET(current_file, rb_stdin);
10479 if (ARGF.inplace) {
10480 rb_warn("Can't do inplace edit for stdio; skipping");
10481 goto retry;
10482 }
10483 }
10484 else {
10485 VALUE write_io = Qnil;
10486 int fr = rb_sysopen(filename, O_RDONLY, 0);
10487
10488 if (ARGF.inplace) {
10489 struct stat st;
10490#ifndef NO_SAFE_RENAME
10491 struct stat st2;
10492#endif
10493 VALUE str;
10494 int fw;
10495
10496 if (RB_TYPE_P(r_stdout, T_FILE) && r_stdout != orig_stdout) {
10497 rb_io_close(r_stdout);
10498 }
10499 fstat(fr, &st);
10500 str = filename;
10501 if (!NIL_P(ARGF.inplace)) {
10502 VALUE suffix = ARGF.inplace;
10503 str = rb_str_dup(str);
10504 if (NIL_P(rb_str_cat_conv_enc_opts(str, RSTRING_LEN(str),
10505 RSTRING_PTR(suffix), RSTRING_LEN(suffix),
10506 rb_enc_get(suffix), 0, Qnil))) {
10507 rb_str_append(str, suffix);
10508 }
10509#ifdef NO_SAFE_RENAME
10510 (void)close(fr);
10511 (void)unlink(RSTRING_PTR(str));
10512 if (rename(fn, RSTRING_PTR(str)) < 0) {
10513 rb_warn("Can't rename %"PRIsVALUE" to %"PRIsVALUE": %s, skipping file",
10514 filename, str, strerror(errno));
10515 goto retry;
10516 }
10517 fr = rb_sysopen(str, O_RDONLY, 0);
10518#else
10519 if (rename(fn, RSTRING_PTR(str)) < 0) {
10520 rb_warn("Can't rename %"PRIsVALUE" to %"PRIsVALUE": %s, skipping file",
10521 filename, str, strerror(errno));
10522 close(fr);
10523 goto retry;
10524 }
10525#endif
10526 }
10527 else {
10528#ifdef NO_SAFE_RENAME
10529 rb_fatal("Can't do inplace edit without backup");
10530#else
10531 if (unlink(fn) < 0) {
10532 rb_warn("Can't remove %"PRIsVALUE": %s, skipping file",
10533 filename, strerror(errno));
10534 close(fr);
10535 goto retry;
10536 }
10537#endif
10538 }
10539 fw = rb_sysopen(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666);
10540#ifndef NO_SAFE_RENAME
10541 fstat(fw, &st2);
10542#ifdef HAVE_FCHMOD
10543 fchmod(fw, st.st_mode);
10544#else
10545 chmod(fn, st.st_mode);
10546#endif
10547 if (st.st_uid!=st2.st_uid || st.st_gid!=st2.st_gid) {
10548 int err;
10549#ifdef HAVE_FCHOWN
10550 err = fchown(fw, st.st_uid, st.st_gid);
10551#else
10552 err = chown(fn, st.st_uid, st.st_gid);
10553#endif
10554 if (err && getuid() == 0 && st2.st_uid == 0) {
10555 const char *wkfn = RSTRING_PTR(filename);
10556 rb_warn("Can't set owner/group of %"PRIsVALUE" to same as %"PRIsVALUE": %s, skipping file",
10557 filename, str, strerror(errno));
10558 (void)close(fr);
10559 (void)close(fw);
10560 (void)unlink(wkfn);
10561 goto retry;
10562 }
10563 }
10564#endif
10565 write_io = prep_io(fw, FMODE_WRITABLE, rb_cFile, fn);
10566 rb_ractor_stdout_set(write_io);
10567 if (stdout_binmode) rb_io_binmode(rb_stdout);
10568 }
10569 fmode = FMODE_READABLE;
10570 if (!ARGF.binmode) {
10571 fmode |= DEFAULT_TEXTMODE;
10572 }
10573 ARGF_SET(current_file, prep_io(fr, fmode, rb_cFile, fn));
10574 if (!NIL_P(write_io)) {
10575 rb_io_set_write_io(ARGF.current_file, write_io);
10576 }
10577 RB_GC_GUARD(filename);
10578 }
10579 if (ARGF.binmode) rb_io_ascii8bit_binmode(ARGF.current_file);
10580 GetOpenFile(ARGF.current_file, fptr);
10581 if (ARGF.encs.enc) {
10582 fptr->encs = ARGF.encs;
10583 clear_codeconv(fptr);
10584 }
10585 else {
10586 fptr->encs.ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
10587 if (!ARGF.binmode) {
10589#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
10590 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
10591#endif
10592 }
10593 }
10594 ARGF.next_p = 0;
10595 }
10596 else {
10597 ARGF.next_p = 1;
10598 return FALSE;
10599 }
10600 }
10601 else if (ARGF.next_p == -1) {
10602 ARGF_SET(current_file, rb_stdin);
10603 ARGF_SET(filename, rb_str_new2("-"));
10604 if (ARGF.inplace) {
10605 rb_warn("Can't do inplace edit for stdio");
10606 rb_ractor_stdout_set(orig_stdout);
10607 }
10608 }
10609 if (ARGF.init_p == -1) ARGF.init_p = 1;
10610 return TRUE;
10611}
10612
10613static VALUE
10614argf_getline(int argc, VALUE *argv, VALUE argf)
10615{
10616 VALUE line;
10617 long lineno = ARGF.lineno;
10618
10619 retry:
10620 if (!next_argv()) return Qnil;
10621 if (ARGF_GENERIC_INPUT_P()) {
10622 line = forward_current(idGets, argc, argv);
10623 }
10624 else {
10625 if (argc == 0 && rb_rs == rb_default_rs) {
10626 line = rb_io_gets(ARGF.current_file);
10627 }
10628 else {
10629 line = rb_io_getline(argc, argv, ARGF.current_file);
10630 }
10631 if (NIL_P(line) && ARGF.next_p != -1) {
10632 argf_close(argf);
10633 ARGF.next_p = 1;
10634 goto retry;
10635 }
10636 }
10637 if (!NIL_P(line)) {
10638 ARGF.lineno = ++lineno;
10639 ARGF.last_lineno = ARGF.lineno;
10640 }
10641 return line;
10642}
10643
10644static VALUE
10645argf_lineno_getter(ID id, VALUE *var)
10646{
10647 VALUE argf = *var;
10648 return INT2FIX(ARGF.last_lineno);
10649}
10650
10651static void
10652argf_lineno_setter(VALUE val, ID id, VALUE *var)
10653{
10654 VALUE argf = *var;
10655 int n = NUM2INT(val);
10656 ARGF.last_lineno = ARGF.lineno = n;
10657}
10658
10659void
10660rb_reset_argf_lineno(long n)
10661{
10662 ARGF.last_lineno = ARGF.lineno = n;
10663}
10664
10665static VALUE argf_gets(int, VALUE *, VALUE);
10666
10667/*
10668 * call-seq:
10669 * gets(sep=$/ [, getline_args]) -> string or nil
10670 * gets(limit [, getline_args]) -> string or nil
10671 * gets(sep, limit [, getline_args]) -> string or nil
10672 *
10673 * Returns (and assigns to <code>$_</code>) the next line from the list
10674 * of files in +ARGV+ (or <code>$*</code>), or from standard input if
10675 * no files are present on the command line. Returns +nil+ at end of
10676 * file. The optional argument specifies the record separator. The
10677 * separator is included with the contents of each record. A separator
10678 * of +nil+ reads the entire contents, and a zero-length separator
10679 * reads the input one paragraph at a time, where paragraphs are
10680 * divided by two consecutive newlines. If the first argument is an
10681 * integer, or optional second argument is given, the returning string
10682 * would not be longer than the given value in bytes. If multiple
10683 * filenames are present in +ARGV+, <code>gets(nil)</code> will read
10684 * the contents one file at a time.
10685 *
10686 * ARGV << "testfile"
10687 * print while gets
10688 *
10689 * <em>produces:</em>
10690 *
10691 * This is line one
10692 * This is line two
10693 * This is line three
10694 * And so on...
10695 *
10696 * The style of programming using <code>$_</code> as an implicit
10697 * parameter is gradually losing favor in the Ruby community.
10698 */
10699
10700static VALUE
10701rb_f_gets(int argc, VALUE *argv, VALUE recv)
10702{
10703 if (recv == argf) {
10704 return argf_gets(argc, argv, argf);
10705 }
10706 return forward(argf, idGets, argc, argv);
10707}
10708
10709/*
10710 * call-seq:
10711 * ARGF.gets(sep=$/ [, getline_args]) -> string or nil
10712 * ARGF.gets(limit [, getline_args]) -> string or nil
10713 * ARGF.gets(sep, limit [, getline_args]) -> string or nil
10714 *
10715 * Returns the next line from the current file in ARGF.
10716 *
10717 * By default lines are assumed to be separated by <code>$/</code>;
10718 * to use a different character as a separator, supply it as a String
10719 * for the _sep_ argument.
10720 *
10721 * The optional _limit_ argument specifies how many characters of each line
10722 * to return. By default all characters are returned.
10723 *
10724 * See IO.readlines for details about getline_args.
10725 *
10726 */
10727static VALUE
10728argf_gets(int argc, VALUE *argv, VALUE argf)
10729{
10730 VALUE line;
10731
10732 line = argf_getline(argc, argv, argf);
10733 rb_lastline_set(line);
10734
10735 return line;
10736}
10737
10738VALUE
10740{
10741 VALUE line;
10742
10743 if (rb_rs != rb_default_rs) {
10744 return rb_f_gets(0, 0, argf);
10745 }
10746
10747 retry:
10748 if (!next_argv()) return Qnil;
10749 line = rb_io_gets(ARGF.current_file);
10750 if (NIL_P(line) && ARGF.next_p != -1) {
10751 rb_io_close(ARGF.current_file);
10752 ARGF.next_p = 1;
10753 goto retry;
10754 }
10755 rb_lastline_set(line);
10756 if (!NIL_P(line)) {
10757 ARGF.lineno++;
10758 ARGF.last_lineno = ARGF.lineno;
10759 }
10760
10761 return line;
10762}
10763
10764static VALUE argf_readline(int, VALUE *, VALUE);
10765
10766/*
10767 * call-seq:
10768 * readline(sep = $/, chomp: false) -> string
10769 * readline(limit, chomp: false) -> string
10770 * readline(sep, limit, chomp: false) -> string
10771 *
10772 * Equivalent to method Kernel#gets, except that it raises an exception
10773 * if called at end-of-stream:
10774 *
10775 * $ cat t.txt | ruby -e "p readlines; readline"
10776 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10777 * in `readline': end of file reached (EOFError)
10778 *
10779 * Optional keyword argument +chomp+ specifies whether line separators
10780 * are to be omitted.
10781 */
10782
10783static VALUE
10784rb_f_readline(int argc, VALUE *argv, VALUE recv)
10785{
10786 if (recv == argf) {
10787 return argf_readline(argc, argv, argf);
10788 }
10789 return forward(argf, rb_intern("readline"), argc, argv);
10790}
10791
10792
10793/*
10794 * call-seq:
10795 * ARGF.readline(sep=$/) -> string
10796 * ARGF.readline(limit) -> string
10797 * ARGF.readline(sep, limit) -> string
10798 *
10799 * Returns the next line from the current file in ARGF.
10800 *
10801 * By default lines are assumed to be separated by <code>$/</code>;
10802 * to use a different character as a separator, supply it as a String
10803 * for the _sep_ argument.
10804 *
10805 * The optional _limit_ argument specifies how many characters of each line
10806 * to return. By default all characters are returned.
10807 *
10808 * An EOFError is raised at the end of the file.
10809 */
10810static VALUE
10811argf_readline(int argc, VALUE *argv, VALUE argf)
10812{
10813 VALUE line;
10814
10815 if (!next_argv()) rb_eof_error();
10816 ARGF_FORWARD(argc, argv);
10817 line = argf_gets(argc, argv, argf);
10818 if (NIL_P(line)) {
10819 rb_eof_error();
10820 }
10821
10822 return line;
10823}
10824
10825static VALUE argf_readlines(int, VALUE *, VALUE);
10826
10827/*
10828 * call-seq:
10829 * readlines(sep = $/, chomp: false, **enc_opts) -> array
10830 * readlines(limit, chomp: false, **enc_opts) -> array
10831 * readlines(sep, limit, chomp: false, **enc_opts) -> array
10832 *
10833 * Returns an array containing the lines returned by calling
10834 * Kernel#gets until the end-of-stream is reached;
10835 * (see {Line IO}[rdoc-ref:IO@Line+IO]).
10836 *
10837 * With only string argument +sep+ given,
10838 * returns the remaining lines as determined by line separator +sep+,
10839 * or +nil+ if none;
10840 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
10841 *
10842 * # Default separator.
10843 * $ cat t.txt | ruby -e "p readlines"
10844 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10845 *
10846 * # Specified separator.
10847 * $ cat t.txt | ruby -e "p readlines 'li'"
10848 * ["First li", "ne\nSecond li", "ne\n\nFourth li", "ne\nFifth li", "ne\n"]
10849 *
10850 * # Get-all separator.
10851 * $ cat t.txt | ruby -e "p readlines nil"
10852 * ["First line\nSecond line\n\nFourth line\nFifth line\n"]
10853 *
10854 * # Get-paragraph separator.
10855 * $ cat t.txt | ruby -e "p readlines ''"
10856 * ["First line\nSecond line\n\n", "Fourth line\nFifth line\n"]
10857 *
10858 * With only integer argument +limit+ given,
10859 * limits the number of bytes in the line;
10860 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
10861 *
10862 * $cat t.txt | ruby -e "p readlines 10"
10863 * ["First line", "\n", "Second lin", "e\n", "\n", "Fourth lin", "e\n", "Fifth line", "\n"]
10864 *
10865 * $cat t.txt | ruby -e "p readlines 11"
10866 * ["First line\n", "Second line", "\n", "\n", "Fourth line", "\n", "Fifth line\n"]
10867 *
10868 * $cat t.txt | ruby -e "p readlines 12"
10869 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10870 *
10871 * With arguments +sep+ and +limit+ given,
10872 * combines the two behaviors
10873 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
10874 *
10875 * Optional keyword argument +chomp+ specifies whether line separators
10876 * are to be omitted:
10877 *
10878 * $ cat t.txt | ruby -e "p readlines(chomp: true)"
10879 * ["First line", "Second line", "", "Fourth line", "Fifth line"]
10880 *
10881 * Optional keyword arguments +enc_opts+ specify encoding options;
10882 * see {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
10883 *
10884 */
10885
10886static VALUE
10887rb_f_readlines(int argc, VALUE *argv, VALUE recv)
10888{
10889 if (recv == argf) {
10890 return argf_readlines(argc, argv, argf);
10891 }
10892 return forward(argf, rb_intern("readlines"), argc, argv);
10893}
10894
10895/*
10896 * call-seq:
10897 * ARGF.readlines(sep = $/, chomp: false) -> array
10898 * ARGF.readlines(limit, chomp: false) -> array
10899 * ARGF.readlines(sep, limit, chomp: false) -> array
10900 *
10901 * ARGF.to_a(sep = $/, chomp: false) -> array
10902 * ARGF.to_a(limit, chomp: false) -> array
10903 * ARGF.to_a(sep, limit, chomp: false) -> array
10904 *
10905 * Reads each file in ARGF in its entirety, returning an Array containing
10906 * lines from the files. Lines are assumed to be separated by _sep_.
10907 *
10908 * lines = ARGF.readlines
10909 * lines[0] #=> "This is line one\n"
10910 *
10911 * See +IO.readlines+ for a full description of all options.
10912 */
10913static VALUE
10914argf_readlines(int argc, VALUE *argv, VALUE argf)
10915{
10916 long lineno = ARGF.lineno;
10917 VALUE lines, ary;
10918
10919 ary = rb_ary_new();
10920 while (next_argv()) {
10921 if (ARGF_GENERIC_INPUT_P()) {
10922 lines = forward_current(rb_intern("readlines"), argc, argv);
10923 }
10924 else {
10925 lines = rb_io_readlines(argc, argv, ARGF.current_file);
10926 argf_close(argf);
10927 }
10928 ARGF.next_p = 1;
10929 rb_ary_concat(ary, lines);
10930 ARGF.lineno = lineno + RARRAY_LEN(ary);
10931 ARGF.last_lineno = ARGF.lineno;
10932 }
10933 ARGF.init_p = 0;
10934 return ary;
10935}
10936
10937/*
10938 * call-seq:
10939 * `command` -> string
10940 *
10941 * Returns the <tt>$stdout</tt> output from running +command+ in a subshell;
10942 * sets global variable <tt>$?</tt> to the process status.
10943 *
10944 * This method has potential security vulnerabilities if called with untrusted input;
10945 * see {Command Injection}[rdoc-ref:security/command_injection.rdoc].
10946 *
10947 * Examples:
10948 *
10949 * $ `date` # => "Wed Apr 9 08:56:30 CDT 2003\n"
10950 * $ `echo oops && exit 99` # => "oops\n"
10951 * $ $? # => #<Process::Status: pid 17088 exit 99>
10952 * $ $?.exitstatus # => 99
10953 *
10954 * The built-in syntax <tt>%x{...}</tt> uses this method.
10955 *
10956 */
10957
10958static VALUE
10959rb_f_backquote(VALUE obj, VALUE str)
10960{
10961 VALUE port;
10962 VALUE result;
10963 rb_io_t *fptr;
10964
10965 StringValue(str);
10966 rb_last_status_clear();
10967 port = pipe_open_s(str, "r", FMODE_READABLE|DEFAULT_TEXTMODE, NULL);
10968 if (NIL_P(port)) return rb_str_new(0,0);
10969
10970 GetOpenFile(port, fptr);
10971 result = read_all(fptr, remain_size(fptr), Qnil);
10972 rb_io_close(port);
10973 rb_io_fptr_cleanup_all(fptr);
10974 RB_GC_GUARD(port);
10975
10976 return result;
10977}
10978
10979#ifdef HAVE_SYS_SELECT_H
10980#include <sys/select.h>
10981#endif
10982
10983static VALUE
10984select_internal(VALUE read, VALUE write, VALUE except, struct timeval *tp, rb_fdset_t *fds)
10985{
10986 VALUE res, list;
10987 rb_fdset_t *rp, *wp, *ep;
10988 rb_io_t *fptr;
10989 long i;
10990 int max = 0, n;
10991 int pending = 0;
10992 struct timeval timerec;
10993
10994 if (!NIL_P(read)) {
10995 Check_Type(read, T_ARRAY);
10996 for (i=0; i<RARRAY_LEN(read); i++) {
10997 GetOpenFile(rb_io_get_io(RARRAY_AREF(read, i)), fptr);
10998 rb_fd_set(fptr->fd, &fds[0]);
10999 if (READ_DATA_PENDING(fptr) || READ_CHAR_PENDING(fptr)) { /* check for buffered data */
11000 pending++;
11001 rb_fd_set(fptr->fd, &fds[3]);
11002 }
11003 if (max < fptr->fd) max = fptr->fd;
11004 }
11005 if (pending) { /* no blocking if there's buffered data */
11006 timerec.tv_sec = timerec.tv_usec = 0;
11007 tp = &timerec;
11008 }
11009 rp = &fds[0];
11010 }
11011 else
11012 rp = 0;
11013
11014 if (!NIL_P(write)) {
11015 Check_Type(write, T_ARRAY);
11016 for (i=0; i<RARRAY_LEN(write); i++) {
11017 VALUE write_io = GetWriteIO(rb_io_get_io(RARRAY_AREF(write, i)));
11018 GetOpenFile(write_io, fptr);
11019 rb_fd_set(fptr->fd, &fds[1]);
11020 if (max < fptr->fd) max = fptr->fd;
11021 }
11022 wp = &fds[1];
11023 }
11024 else
11025 wp = 0;
11026
11027 if (!NIL_P(except)) {
11028 Check_Type(except, T_ARRAY);
11029 for (i=0; i<RARRAY_LEN(except); i++) {
11030 VALUE io = rb_io_get_io(RARRAY_AREF(except, i));
11031 VALUE write_io = GetWriteIO(io);
11032 GetOpenFile(io, fptr);
11033 rb_fd_set(fptr->fd, &fds[2]);
11034 if (max < fptr->fd) max = fptr->fd;
11035 if (io != write_io) {
11036 GetOpenFile(write_io, fptr);
11037 rb_fd_set(fptr->fd, &fds[2]);
11038 if (max < fptr->fd) max = fptr->fd;
11039 }
11040 }
11041 ep = &fds[2];
11042 }
11043 else {
11044 ep = 0;
11045 }
11046
11047 max++;
11048
11049 n = rb_thread_fd_select(max, rp, wp, ep, tp);
11050 if (n < 0) {
11051 rb_sys_fail(0);
11052 }
11053 if (!pending && n == 0) return Qnil; /* returns nil on timeout */
11054
11055 res = rb_ary_new2(3);
11056 rb_ary_push(res, rp ? rb_ary_new_capa(RARRAY_LEN(read)) : rb_ary_new());
11057 rb_ary_push(res, wp ? rb_ary_new_capa(RARRAY_LEN(write)) : rb_ary_new());
11058 rb_ary_push(res, ep ? rb_ary_new_capa(RARRAY_LEN(except)) : rb_ary_new());
11059
11060 if (rp) {
11061 list = RARRAY_AREF(res, 0);
11062 for (i=0; i< RARRAY_LEN(read); i++) {
11063 VALUE obj = rb_ary_entry(read, i);
11064 VALUE io = rb_io_get_io(obj);
11065 GetOpenFile(io, fptr);
11066 if (rb_fd_isset(fptr->fd, &fds[0]) ||
11067 rb_fd_isset(fptr->fd, &fds[3])) {
11068 rb_ary_push(list, obj);
11069 }
11070 }
11071 }
11072
11073 if (wp) {
11074 list = RARRAY_AREF(res, 1);
11075 for (i=0; i< RARRAY_LEN(write); i++) {
11076 VALUE obj = rb_ary_entry(write, i);
11077 VALUE io = rb_io_get_io(obj);
11078 VALUE write_io = GetWriteIO(io);
11079 GetOpenFile(write_io, fptr);
11080 if (rb_fd_isset(fptr->fd, &fds[1])) {
11081 rb_ary_push(list, obj);
11082 }
11083 }
11084 }
11085
11086 if (ep) {
11087 list = RARRAY_AREF(res, 2);
11088 for (i=0; i< RARRAY_LEN(except); i++) {
11089 VALUE obj = rb_ary_entry(except, i);
11090 VALUE io = rb_io_get_io(obj);
11091 VALUE write_io = GetWriteIO(io);
11092 GetOpenFile(io, fptr);
11093 if (rb_fd_isset(fptr->fd, &fds[2])) {
11094 rb_ary_push(list, obj);
11095 }
11096 else if (io != write_io) {
11097 GetOpenFile(write_io, fptr);
11098 if (rb_fd_isset(fptr->fd, &fds[2])) {
11099 rb_ary_push(list, obj);
11100 }
11101 }
11102 }
11103 }
11104
11105 return res; /* returns an empty array on interrupt */
11106}
11107
11109 VALUE read, write, except;
11110 struct timeval *timeout;
11111 rb_fdset_t fdsets[4];
11112};
11113
11114static VALUE
11115select_call(VALUE arg)
11116{
11117 struct select_args *p = (struct select_args *)arg;
11118
11119 return select_internal(p->read, p->write, p->except, p->timeout, p->fdsets);
11120}
11121
11122static VALUE
11123select_end(VALUE arg)
11124{
11125 struct select_args *p = (struct select_args *)arg;
11126 int i;
11127
11128 for (i = 0; i < numberof(p->fdsets); ++i)
11129 rb_fd_term(&p->fdsets[i]);
11130 return Qnil;
11131}
11132
11133static VALUE sym_normal, sym_sequential, sym_random,
11134 sym_willneed, sym_dontneed, sym_noreuse;
11135
11136#ifdef HAVE_POSIX_FADVISE
11137struct io_advise_struct {
11138 int fd;
11139 int advice;
11140 rb_off_t offset;
11141 rb_off_t len;
11142};
11143
11144static VALUE
11145io_advise_internal(void *arg)
11146{
11147 struct io_advise_struct *ptr = arg;
11148 return posix_fadvise(ptr->fd, ptr->offset, ptr->len, ptr->advice);
11149}
11150
11151static VALUE
11152io_advise_sym_to_const(VALUE sym)
11153{
11154#ifdef POSIX_FADV_NORMAL
11155 if (sym == sym_normal)
11156 return INT2NUM(POSIX_FADV_NORMAL);
11157#endif
11158
11159#ifdef POSIX_FADV_RANDOM
11160 if (sym == sym_random)
11161 return INT2NUM(POSIX_FADV_RANDOM);
11162#endif
11163
11164#ifdef POSIX_FADV_SEQUENTIAL
11165 if (sym == sym_sequential)
11166 return INT2NUM(POSIX_FADV_SEQUENTIAL);
11167#endif
11168
11169#ifdef POSIX_FADV_WILLNEED
11170 if (sym == sym_willneed)
11171 return INT2NUM(POSIX_FADV_WILLNEED);
11172#endif
11173
11174#ifdef POSIX_FADV_DONTNEED
11175 if (sym == sym_dontneed)
11176 return INT2NUM(POSIX_FADV_DONTNEED);
11177#endif
11178
11179#ifdef POSIX_FADV_NOREUSE
11180 if (sym == sym_noreuse)
11181 return INT2NUM(POSIX_FADV_NOREUSE);
11182#endif
11183
11184 return Qnil;
11185}
11186
11187static VALUE
11188do_io_advise(rb_io_t *fptr, VALUE advice, rb_off_t offset, rb_off_t len)
11189{
11190 int rv;
11191 struct io_advise_struct ias;
11192 VALUE num_adv;
11193
11194 num_adv = io_advise_sym_to_const(advice);
11195
11196 /*
11197 * The platform doesn't support this hint. We don't raise exception, instead
11198 * silently ignore it. Because IO::advise is only hint.
11199 */
11200 if (NIL_P(num_adv))
11201 return Qnil;
11202
11203 ias.fd = fptr->fd;
11204 ias.advice = NUM2INT(num_adv);
11205 ias.offset = offset;
11206 ias.len = len;
11207
11208 rv = (int)rb_io_blocking_region(fptr, io_advise_internal, &ias);
11209 if (rv && rv != ENOSYS) {
11210 /* posix_fadvise(2) doesn't set errno. On success it returns 0; otherwise
11211 it returns the error code. */
11212 VALUE message = rb_sprintf("%"PRIsVALUE" "
11213 "(%"PRI_OFFT_PREFIX"d, "
11214 "%"PRI_OFFT_PREFIX"d, "
11215 "%"PRIsVALUE")",
11216 fptr->pathv, offset, len, advice);
11217 rb_syserr_fail_str(rv, message);
11218 }
11219
11220 return Qnil;
11221}
11222
11223#endif /* HAVE_POSIX_FADVISE */
11224
11225static void
11226advice_arg_check(VALUE advice)
11227{
11228 if (!SYMBOL_P(advice))
11229 rb_raise(rb_eTypeError, "advice must be a Symbol");
11230
11231 if (advice != sym_normal &&
11232 advice != sym_sequential &&
11233 advice != sym_random &&
11234 advice != sym_willneed &&
11235 advice != sym_dontneed &&
11236 advice != sym_noreuse) {
11237 rb_raise(rb_eNotImpError, "Unsupported advice: %+"PRIsVALUE, advice);
11238 }
11239}
11240
11241/*
11242 * call-seq:
11243 * advise(advice, offset = 0, len = 0) -> nil
11244 *
11245 * Invokes Posix system call
11246 * {posix_fadvise(2)}[https://man7.org/linux/man-pages/man2/posix_fadvise.2.html],
11247 * which announces an intention to access data from the current file
11248 * in a particular manner.
11249 *
11250 * The arguments and results are platform-dependent.
11251 *
11252 * The relevant data is specified by:
11253 *
11254 * - +offset+: The offset of the first byte of data.
11255 * - +len+: The number of bytes to be accessed;
11256 * if +len+ is zero, or is larger than the number of bytes remaining,
11257 * all remaining bytes will be accessed.
11258 *
11259 * Argument +advice+ is one of the following symbols:
11260 *
11261 * - +:normal+: The application has no advice to give
11262 * about its access pattern for the specified data.
11263 * If no advice is given for an open file, this is the default assumption.
11264 * - +:sequential+: The application expects to access the specified data sequentially
11265 * (with lower offsets read before higher ones).
11266 * - +:random+: The specified data will be accessed in random order.
11267 * - +:noreuse+: The specified data will be accessed only once.
11268 * - +:willneed+: The specified data will be accessed in the near future.
11269 * - +:dontneed+: The specified data will not be accessed in the near future.
11270 *
11271 * Not implemented on all platforms.
11272 *
11273 */
11274static VALUE
11275rb_io_advise(int argc, VALUE *argv, VALUE io)
11276{
11277 VALUE advice, offset, len;
11278 rb_off_t off, l;
11279 rb_io_t *fptr;
11280
11281 rb_scan_args(argc, argv, "12", &advice, &offset, &len);
11282 advice_arg_check(advice);
11283
11284 io = GetWriteIO(io);
11285 GetOpenFile(io, fptr);
11286
11287 off = NIL_P(offset) ? 0 : NUM2OFFT(offset);
11288 l = NIL_P(len) ? 0 : NUM2OFFT(len);
11289
11290#ifdef HAVE_POSIX_FADVISE
11291 return do_io_advise(fptr, advice, off, l);
11292#else
11293 ((void)off, (void)l); /* Ignore all hint */
11294 return Qnil;
11295#endif
11296}
11297
11298static int
11299is_pos_inf(VALUE x)
11300{
11301 double f;
11302 if (!RB_FLOAT_TYPE_P(x))
11303 return 0;
11304 f = RFLOAT_VALUE(x);
11305 return isinf(f) && 0 < f;
11306}
11307
11308/*
11309 * call-seq:
11310 * IO.select(read_ios, write_ios = [], error_ios = [], timeout = nil) -> array or nil
11311 *
11312 * Invokes system call {select(2)}[https://man7.org/linux/man-pages/man2/select.2.html],
11313 * which monitors multiple file descriptors,
11314 * waiting until one or more of the file descriptors
11315 * becomes ready for some class of I/O operation.
11316 *
11317 * Not implemented on all platforms.
11318 *
11319 * Each of the arguments +read_ios+, +write_ios+, and +error_ios+
11320 * is an array of IO objects.
11321 *
11322 * Argument +timeout+ is a numeric value (such as integer or float) timeout
11323 * interval in seconds.
11324 * +timeout+ can also be +nil+ or +Float::INFINITY+.
11325 * +nil+ and +Float::INFINITY+ means no timeout.
11326 *
11327 * The method monitors the \IO objects given in all three arrays,
11328 * waiting for some to be ready;
11329 * returns a 3-element array whose elements are:
11330 *
11331 * - An array of the objects in +read_ios+ that are ready for reading.
11332 * - An array of the objects in +write_ios+ that are ready for writing.
11333 * - An array of the objects in +error_ios+ have pending exceptions.
11334 *
11335 * If no object becomes ready within the given +timeout+, +nil+ is returned.
11336 *
11337 * \IO.select peeks the buffer of \IO objects for testing readability.
11338 * If the \IO buffer is not empty, \IO.select immediately notifies
11339 * readability. This "peek" only happens for \IO objects. It does not
11340 * happen for IO-like objects such as OpenSSL::SSL::SSLSocket.
11341 *
11342 * The best way to use \IO.select is invoking it after non-blocking
11343 * methods such as #read_nonblock, #write_nonblock, etc. The methods
11344 * raise an exception which is extended by IO::WaitReadable or
11345 * IO::WaitWritable. The modules notify how the caller should wait
11346 * with \IO.select. If IO::WaitReadable is raised, the caller should
11347 * wait for reading. If IO::WaitWritable is raised, the caller should
11348 * wait for writing.
11349 *
11350 * So, blocking read (#readpartial) can be emulated using
11351 * #read_nonblock and \IO.select as follows:
11352 *
11353 * begin
11354 * result = io_like.read_nonblock(maxlen)
11355 * rescue IO::WaitReadable
11356 * IO.select([io_like])
11357 * retry
11358 * rescue IO::WaitWritable
11359 * IO.select(nil, [io_like])
11360 * retry
11361 * end
11362 *
11363 * Especially, the combination of non-blocking methods and \IO.select is
11364 * preferred for IO like objects such as OpenSSL::SSL::SSLSocket. It
11365 * has #to_io method to return underlying IO object. IO.select calls
11366 * #to_io to obtain the file descriptor to wait.
11367 *
11368 * This means that readability notified by \IO.select doesn't mean
11369 * readability from OpenSSL::SSL::SSLSocket object.
11370 *
11371 * The most likely situation is that OpenSSL::SSL::SSLSocket buffers
11372 * some data. \IO.select doesn't see the buffer. So \IO.select can
11373 * block when OpenSSL::SSL::SSLSocket#readpartial doesn't block.
11374 *
11375 * However, several more complicated situations exist.
11376 *
11377 * SSL is a protocol which is sequence of records.
11378 * The record consists of multiple bytes.
11379 * So, the remote side of SSL sends a partial record, IO.select
11380 * notifies readability but OpenSSL::SSL::SSLSocket cannot decrypt a
11381 * byte and OpenSSL::SSL::SSLSocket#readpartial will block.
11382 *
11383 * Also, the remote side can request SSL renegotiation which forces
11384 * the local SSL engine to write some data.
11385 * This means OpenSSL::SSL::SSLSocket#readpartial may invoke #write
11386 * system call and it can block.
11387 * In such a situation, OpenSSL::SSL::SSLSocket#read_nonblock raises
11388 * IO::WaitWritable instead of blocking.
11389 * So, the caller should wait for ready for writability as above
11390 * example.
11391 *
11392 * The combination of non-blocking methods and \IO.select is also useful
11393 * for streams such as tty, pipe socket socket when multiple processes
11394 * read from a stream.
11395 *
11396 * Finally, Linux kernel developers don't guarantee that
11397 * readability of select(2) means readability of following read(2) even
11398 * for a single process;
11399 * see {select(2)}[https://man7.org/linux/man-pages/man2/select.2.html]
11400 *
11401 * Invoking \IO.select before IO#readpartial works well as usual.
11402 * However it is not the best way to use \IO.select.
11403 *
11404 * The writability notified by select(2) doesn't show
11405 * how many bytes are writable.
11406 * IO#write method blocks until given whole string is written.
11407 * So, <tt>IO#write(two or more bytes)</tt> can block after
11408 * writability is notified by \IO.select. IO#write_nonblock is required
11409 * to avoid the blocking.
11410 *
11411 * Blocking write (#write) can be emulated using #write_nonblock and
11412 * IO.select as follows: IO::WaitReadable should also be rescued for
11413 * SSL renegotiation in OpenSSL::SSL::SSLSocket.
11414 *
11415 * while 0 < string.bytesize
11416 * begin
11417 * written = io_like.write_nonblock(string)
11418 * rescue IO::WaitReadable
11419 * IO.select([io_like])
11420 * retry
11421 * rescue IO::WaitWritable
11422 * IO.select(nil, [io_like])
11423 * retry
11424 * end
11425 * string = string.byteslice(written..-1)
11426 * end
11427 *
11428 * Example:
11429 *
11430 * rp, wp = IO.pipe
11431 * mesg = "ping "
11432 * 100.times {
11433 * # IO.select follows IO#read. Not the best way to use IO.select.
11434 * rs, ws, = IO.select([rp], [wp])
11435 * if r = rs[0]
11436 * ret = r.read(5)
11437 * print ret
11438 * case ret
11439 * when /ping/
11440 * mesg = "pong\n"
11441 * when /pong/
11442 * mesg = "ping "
11443 * end
11444 * end
11445 * if w = ws[0]
11446 * w.write(mesg)
11447 * end
11448 * }
11449 *
11450 * Output:
11451 *
11452 * ping pong
11453 * ping pong
11454 * ping pong
11455 * (snipped)
11456 * ping
11457 *
11458 */
11459
11460static VALUE
11461rb_f_select(int argc, VALUE *argv, VALUE obj)
11462{
11463 VALUE scheduler = rb_fiber_scheduler_current();
11464 if (scheduler != Qnil) {
11465 // It's optionally supported.
11466 VALUE result = rb_fiber_scheduler_io_selectv(scheduler, argc, argv);
11467 if (!UNDEF_P(result)) return result;
11468 }
11469
11470 VALUE timeout;
11471 struct select_args args;
11472 struct timeval timerec;
11473 int i;
11474
11475 rb_scan_args(argc, argv, "13", &args.read, &args.write, &args.except, &timeout);
11476 if (NIL_P(timeout) || is_pos_inf(timeout)) {
11477 args.timeout = 0;
11478 }
11479 else {
11480 timerec = rb_time_interval(timeout);
11481 args.timeout = &timerec;
11482 }
11483
11484 for (i = 0; i < numberof(args.fdsets); ++i)
11485 rb_fd_init(&args.fdsets[i]);
11486
11487 return rb_ensure(select_call, (VALUE)&args, select_end, (VALUE)&args);
11488}
11489
11490#ifdef IOCTL_REQ_TYPE
11491 typedef IOCTL_REQ_TYPE ioctl_req_t;
11492#else
11493 typedef int ioctl_req_t;
11494# define NUM2IOCTLREQ(num) ((int)NUM2LONG(num))
11495#endif
11496
11497#ifdef HAVE_IOCTL
11498struct ioctl_arg {
11499 int fd;
11500 ioctl_req_t cmd;
11501 long narg;
11502};
11503
11504static VALUE
11505nogvl_ioctl(void *ptr)
11506{
11507 struct ioctl_arg *arg = ptr;
11508
11509 return (VALUE)ioctl(arg->fd, arg->cmd, arg->narg);
11510}
11511
11512static int
11513do_ioctl(struct rb_io *io, ioctl_req_t cmd, long narg)
11514{
11515 int retval;
11516 struct ioctl_arg arg;
11517
11518 arg.fd = io->fd;
11519 arg.cmd = cmd;
11520 arg.narg = narg;
11521
11522 retval = (int)rb_io_blocking_region(io, nogvl_ioctl, &arg);
11523
11524 return retval;
11525}
11526#endif
11527
11528#define DEFAULT_IOCTL_NARG_LEN (256)
11529
11530#if defined(__linux__) && defined(_IOC_SIZE)
11531static long
11532linux_iocparm_len(ioctl_req_t cmd)
11533{
11534 long len;
11535
11536 if ((cmd & 0xFFFF0000) == 0) {
11537 /* legacy and unstructured ioctl number. */
11538 return DEFAULT_IOCTL_NARG_LEN;
11539 }
11540
11541 len = _IOC_SIZE(cmd);
11542
11543 /* paranoia check for silly drivers which don't keep ioctl convention */
11544 if (len < DEFAULT_IOCTL_NARG_LEN)
11545 len = DEFAULT_IOCTL_NARG_LEN;
11546
11547 return len;
11548}
11549#endif
11550
11551#ifdef HAVE_IOCTL
11552static long
11553ioctl_narg_len(ioctl_req_t cmd)
11554{
11555 long len;
11556
11557#ifdef IOCPARM_MASK
11558#ifndef IOCPARM_LEN
11559#define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK)
11560#endif
11561#endif
11562#ifdef IOCPARM_LEN
11563 len = IOCPARM_LEN(cmd); /* on BSDish systems we're safe */
11564#elif defined(__linux__) && defined(_IOC_SIZE)
11565 len = linux_iocparm_len(cmd);
11566#else
11567 /* otherwise guess at what's safe */
11568 len = DEFAULT_IOCTL_NARG_LEN;
11569#endif
11570
11571 return len;
11572}
11573#endif
11574
11575#ifdef HAVE_FCNTL
11576#ifdef __linux__
11577typedef long fcntl_arg_t;
11578#else
11579/* posix */
11580typedef int fcntl_arg_t;
11581#endif
11582
11583static long
11584fcntl_narg_len(ioctl_req_t cmd)
11585{
11586 long len;
11587
11588 switch (cmd) {
11589#ifdef F_DUPFD
11590 case F_DUPFD:
11591 len = sizeof(fcntl_arg_t);
11592 break;
11593#endif
11594#ifdef F_DUP2FD /* bsd specific */
11595 case F_DUP2FD:
11596 len = sizeof(int);
11597 break;
11598#endif
11599#ifdef F_DUPFD_CLOEXEC /* linux specific */
11600 case F_DUPFD_CLOEXEC:
11601 len = sizeof(fcntl_arg_t);
11602 break;
11603#endif
11604#ifdef F_GETFD
11605 case F_GETFD:
11606 len = 1;
11607 break;
11608#endif
11609#ifdef F_SETFD
11610 case F_SETFD:
11611 len = sizeof(fcntl_arg_t);
11612 break;
11613#endif
11614#ifdef F_GETFL
11615 case F_GETFL:
11616 len = 1;
11617 break;
11618#endif
11619#ifdef F_SETFL
11620 case F_SETFL:
11621 len = sizeof(fcntl_arg_t);
11622 break;
11623#endif
11624#ifdef F_GETOWN
11625 case F_GETOWN:
11626 len = 1;
11627 break;
11628#endif
11629#ifdef F_SETOWN
11630 case F_SETOWN:
11631 len = sizeof(fcntl_arg_t);
11632 break;
11633#endif
11634#ifdef F_GETOWN_EX /* linux specific */
11635 case F_GETOWN_EX:
11636 len = sizeof(struct f_owner_ex);
11637 break;
11638#endif
11639#ifdef F_SETOWN_EX /* linux specific */
11640 case F_SETOWN_EX:
11641 len = sizeof(struct f_owner_ex);
11642 break;
11643#endif
11644#ifdef F_GETLK
11645 case F_GETLK:
11646 len = sizeof(struct flock);
11647 break;
11648#endif
11649#ifdef F_SETLK
11650 case F_SETLK:
11651 len = sizeof(struct flock);
11652 break;
11653#endif
11654#ifdef F_SETLKW
11655 case F_SETLKW:
11656 len = sizeof(struct flock);
11657 break;
11658#endif
11659#ifdef F_READAHEAD /* bsd specific */
11660 case F_READAHEAD:
11661 len = sizeof(int);
11662 break;
11663#endif
11664#ifdef F_RDAHEAD /* Darwin specific */
11665 case F_RDAHEAD:
11666 len = sizeof(int);
11667 break;
11668#endif
11669#ifdef F_GETSIG /* linux specific */
11670 case F_GETSIG:
11671 len = 1;
11672 break;
11673#endif
11674#ifdef F_SETSIG /* linux specific */
11675 case F_SETSIG:
11676 len = sizeof(fcntl_arg_t);
11677 break;
11678#endif
11679#ifdef F_GETLEASE /* linux specific */
11680 case F_GETLEASE:
11681 len = 1;
11682 break;
11683#endif
11684#ifdef F_SETLEASE /* linux specific */
11685 case F_SETLEASE:
11686 len = sizeof(fcntl_arg_t);
11687 break;
11688#endif
11689#ifdef F_NOTIFY /* linux specific */
11690 case F_NOTIFY:
11691 len = sizeof(fcntl_arg_t);
11692 break;
11693#endif
11694
11695 default:
11696 len = 256;
11697 break;
11698 }
11699
11700 return len;
11701}
11702#else /* HAVE_FCNTL */
11703static long
11704fcntl_narg_len(ioctl_req_t cmd)
11705{
11706 return 0;
11707}
11708#endif /* HAVE_FCNTL */
11709
11710#define NARG_SENTINEL 17
11711
11712static long
11713setup_narg(ioctl_req_t cmd, VALUE *argp, long (*narg_len)(ioctl_req_t))
11714{
11715 long narg = 0;
11716 VALUE arg = *argp;
11717
11718 if (!RTEST(arg)) {
11719 narg = 0;
11720 }
11721 else if (FIXNUM_P(arg)) {
11722 narg = FIX2LONG(arg);
11723 }
11724 else if (arg == Qtrue) {
11725 narg = 1;
11726 }
11727 else {
11728 VALUE tmp = rb_check_string_type(arg);
11729
11730 if (NIL_P(tmp)) {
11731 narg = NUM2LONG(arg);
11732 }
11733 else {
11734 char *ptr;
11735 long len, slen;
11736
11737 *argp = arg = tmp;
11738 len = narg_len(cmd);
11739 rb_str_modify(arg);
11740
11741 slen = RSTRING_LEN(arg);
11742 /* expand for data + sentinel. */
11743 if (slen < len+1) {
11744 rb_str_resize(arg, len+1);
11745 MEMZERO(RSTRING_PTR(arg)+slen, char, len-slen);
11746 slen = len+1;
11747 }
11748 /* a little sanity check here */
11749 ptr = RSTRING_PTR(arg);
11750 ptr[slen - 1] = NARG_SENTINEL;
11751 narg = (long)(SIGNED_VALUE)ptr;
11752 }
11753 }
11754
11755 return narg;
11756}
11757
11758static VALUE
11759finish_narg(int retval, VALUE arg, const rb_io_t *fptr)
11760{
11761 if (retval < 0) rb_sys_fail_path(fptr->pathv);
11762 if (RB_TYPE_P(arg, T_STRING)) {
11763 char *ptr;
11764 long slen;
11765 RSTRING_GETMEM(arg, ptr, slen);
11766 if (ptr[slen-1] != NARG_SENTINEL)
11767 rb_raise(rb_eArgError, "return value overflowed string");
11768 ptr[slen-1] = '\0';
11769 }
11770
11771 return INT2NUM(retval);
11772}
11773
11774#ifdef HAVE_IOCTL
11775static VALUE
11776rb_ioctl(VALUE io, VALUE req, VALUE arg)
11777{
11778 ioctl_req_t cmd = NUM2IOCTLREQ(req);
11779 rb_io_t *fptr;
11780 long narg;
11781 int retval;
11782
11783 narg = setup_narg(cmd, &arg, ioctl_narg_len);
11784 GetOpenFile(io, fptr);
11785 retval = do_ioctl(fptr, cmd, narg);
11786 return finish_narg(retval, arg, fptr);
11787}
11788
11789/*
11790 * call-seq:
11791 * ioctl(integer_cmd, argument) -> integer
11792 *
11793 * Invokes Posix system call {ioctl(2)}[https://man7.org/linux/man-pages/man2/ioctl.2.html],
11794 * which issues a low-level command to an I/O device.
11795 *
11796 * Issues a low-level command to an I/O device.
11797 * The arguments and returned value are platform-dependent.
11798 * The effect of the call is platform-dependent.
11799 *
11800 * If argument +argument+ is an integer, it is passed directly;
11801 * if it is a string, it is interpreted as a binary sequence of bytes.
11802 *
11803 * Not implemented on all platforms.
11804 *
11805 */
11806
11807static VALUE
11808rb_io_ioctl(int argc, VALUE *argv, VALUE io)
11809{
11810 VALUE req, arg;
11811
11812 rb_scan_args(argc, argv, "11", &req, &arg);
11813 return rb_ioctl(io, req, arg);
11814}
11815#else
11816#define rb_io_ioctl rb_f_notimplement
11817#endif
11818
11819#ifdef HAVE_FCNTL
11820struct fcntl_arg {
11821 int fd;
11822 int cmd;
11823 long narg;
11824};
11825
11826static VALUE
11827nogvl_fcntl(void *ptr)
11828{
11829 struct fcntl_arg *arg = ptr;
11830
11831#if defined(F_DUPFD)
11832 if (arg->cmd == F_DUPFD)
11833 return (VALUE)rb_cloexec_fcntl_dupfd(arg->fd, (int)arg->narg);
11834#endif
11835 return (VALUE)fcntl(arg->fd, arg->cmd, arg->narg);
11836}
11837
11838static int
11839do_fcntl(struct rb_io *io, int cmd, long narg)
11840{
11841 int retval;
11842 struct fcntl_arg arg;
11843
11844 arg.fd = io->fd;
11845 arg.cmd = cmd;
11846 arg.narg = narg;
11847
11848 retval = (int)rb_io_blocking_region(io, nogvl_fcntl, &arg);
11849 if (retval != -1) {
11850 switch (cmd) {
11851#if defined(F_DUPFD)
11852 case F_DUPFD:
11853#endif
11854#if defined(F_DUPFD_CLOEXEC)
11855 case F_DUPFD_CLOEXEC:
11856#endif
11857 rb_update_max_fd(retval);
11858 }
11859 }
11860
11861 return retval;
11862}
11863
11864static VALUE
11865rb_fcntl(VALUE io, VALUE req, VALUE arg)
11866{
11867 int cmd = NUM2INT(req);
11868 rb_io_t *fptr;
11869 long narg;
11870 int retval;
11871
11872 narg = setup_narg(cmd, &arg, fcntl_narg_len);
11873 GetOpenFile(io, fptr);
11874 retval = do_fcntl(fptr, cmd, narg);
11875 return finish_narg(retval, arg, fptr);
11876}
11877
11878/*
11879 * call-seq:
11880 * fcntl(integer_cmd, argument) -> integer
11881 *
11882 * Invokes Posix system call {fcntl(2)}[https://man7.org/linux/man-pages/man2/fcntl.2.html],
11883 * which provides a mechanism for issuing low-level commands to control or query
11884 * a file-oriented I/O stream. Arguments and results are platform
11885 * dependent.
11886 *
11887 * If +argument+ is a number, its value is passed directly;
11888 * if it is a string, it is interpreted as a binary sequence of bytes.
11889 * (Array#pack might be a useful way to build this string.)
11890 *
11891 * Not implemented on all platforms.
11892 *
11893 */
11894
11895static VALUE
11896rb_io_fcntl(int argc, VALUE *argv, VALUE io)
11897{
11898 VALUE req, arg;
11899
11900 rb_scan_args(argc, argv, "11", &req, &arg);
11901 return rb_fcntl(io, req, arg);
11902}
11903#else
11904#define rb_io_fcntl rb_f_notimplement
11905#endif
11906
11907#if defined(HAVE_SYSCALL) || defined(HAVE___SYSCALL)
11908/*
11909 * call-seq:
11910 * syscall(integer_callno, *arguments) -> integer
11911 *
11912 * Invokes Posix system call {syscall(2)}[https://man7.org/linux/man-pages/man2/syscall.2.html],
11913 * which calls a specified function.
11914 *
11915 * Calls the operating system function identified by +integer_callno+;
11916 * returns the result of the function or raises SystemCallError if it failed.
11917 * The effect of the call is platform-dependent.
11918 * The arguments and returned value are platform-dependent.
11919 *
11920 * For each of +arguments+: if it is an integer, it is passed directly;
11921 * if it is a string, it is interpreted as a binary sequence of bytes.
11922 * There may be as many as nine such arguments.
11923 *
11924 * Arguments +integer_callno+ and +argument+, as well as the returned value,
11925 * are platform-dependent.
11926 *
11927 * Note: Method +syscall+ is essentially unsafe and unportable.
11928 * The DL (Fiddle) library is preferred for safer and a bit
11929 * more portable programming.
11930 *
11931 * Not implemented on all platforms.
11932 *
11933 */
11934
11935static VALUE
11936rb_f_syscall(int argc, VALUE *argv, VALUE _)
11937{
11938 VALUE arg[8];
11939#if SIZEOF_VOIDP == 8 && defined(HAVE___SYSCALL) && SIZEOF_INT != 8 /* mainly *BSD */
11940# define SYSCALL __syscall
11941# define NUM2SYSCALLID(x) NUM2LONG(x)
11942# define RETVAL2NUM(x) LONG2NUM(x)
11943# if SIZEOF_LONG == 8
11944 long num, retval = -1;
11945# elif SIZEOF_LONG_LONG == 8
11946 long long num, retval = -1;
11947# else
11948# error ---->> it is asserted that __syscall takes the first argument and returns retval in 64bit signed integer. <<----
11949# endif
11950#elif defined(__linux__)
11951# define SYSCALL syscall
11952# define NUM2SYSCALLID(x) NUM2LONG(x)
11953# define RETVAL2NUM(x) LONG2NUM(x)
11954 /*
11955 * Linux man page says, syscall(2) function prototype is below.
11956 *
11957 * int syscall(int number, ...);
11958 *
11959 * But, it's incorrect. Actual one takes and returned long. (see unistd.h)
11960 */
11961 long num, retval = -1;
11962#else
11963# define SYSCALL syscall
11964# define NUM2SYSCALLID(x) NUM2INT(x)
11965# define RETVAL2NUM(x) INT2NUM(x)
11966 int num, retval = -1;
11967#endif
11968 int i;
11969
11970 if (RTEST(ruby_verbose)) {
11972 "We plan to remove a syscall function at future release. DL(Fiddle) provides safer alternative.");
11973 }
11974
11975 if (argc == 0)
11976 rb_raise(rb_eArgError, "too few arguments for syscall");
11977 if (argc > numberof(arg))
11978 rb_raise(rb_eArgError, "too many arguments for syscall");
11979 num = NUM2SYSCALLID(argv[0]); ++argv;
11980 for (i = argc - 1; i--; ) {
11981 VALUE v = rb_check_string_type(argv[i]);
11982
11983 if (!NIL_P(v)) {
11984 StringValue(v);
11985 rb_str_modify(v);
11986 arg[i] = (VALUE)StringValueCStr(v);
11987 }
11988 else {
11989 arg[i] = (VALUE)NUM2LONG(argv[i]);
11990 }
11991 }
11992
11993 switch (argc) {
11994 case 1:
11995 retval = SYSCALL(num);
11996 break;
11997 case 2:
11998 retval = SYSCALL(num, arg[0]);
11999 break;
12000 case 3:
12001 retval = SYSCALL(num, arg[0],arg[1]);
12002 break;
12003 case 4:
12004 retval = SYSCALL(num, arg[0],arg[1],arg[2]);
12005 break;
12006 case 5:
12007 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3]);
12008 break;
12009 case 6:
12010 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4]);
12011 break;
12012 case 7:
12013 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5]);
12014 break;
12015 case 8:
12016 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6]);
12017 break;
12018 }
12019
12020 if (retval == -1)
12021 rb_sys_fail(0);
12022 return RETVAL2NUM(retval);
12023#undef SYSCALL
12024#undef NUM2SYSCALLID
12025#undef RETVAL2NUM
12026}
12027#else
12028#define rb_f_syscall rb_f_notimplement
12029#endif
12030
12031static VALUE
12032io_new_instance(VALUE args)
12033{
12034 return rb_class_new_instance(2, (VALUE*)args+1, *(VALUE*)args);
12035}
12036
12037static rb_encoding *
12038find_encoding(VALUE v)
12039{
12040 rb_encoding *enc = rb_find_encoding(v);
12041 if (!enc) rb_warn("Unsupported encoding %"PRIsVALUE" ignored", v);
12042 return enc;
12043}
12044
12045static void
12046io_encoding_set(rb_io_t *fptr, VALUE v1, VALUE v2, VALUE opt)
12047{
12048 rb_encoding *enc, *enc2;
12049 int ecflags = fptr->encs.ecflags;
12050 VALUE ecopts, tmp;
12051
12052 if (!NIL_P(v2)) {
12053 enc2 = find_encoding(v1);
12054 tmp = rb_check_string_type(v2);
12055 if (!NIL_P(tmp)) {
12056 if (RSTRING_LEN(tmp) == 1 && RSTRING_PTR(tmp)[0] == '-') {
12057 /* Special case - "-" => no transcoding */
12058 enc = enc2;
12059 enc2 = NULL;
12060 }
12061 else
12062 enc = find_encoding(v2);
12063 if (enc == enc2) {
12064 /* Special case - "-" => no transcoding */
12065 enc2 = NULL;
12066 }
12067 }
12068 else {
12069 enc = find_encoding(v2);
12070 if (enc == enc2) {
12071 /* Special case - "-" => no transcoding */
12072 enc2 = NULL;
12073 }
12074 }
12075 if (enc2 == rb_ascii8bit_encoding()) {
12076 /* If external is ASCII-8BIT, no transcoding */
12077 enc = enc2;
12078 enc2 = NULL;
12079 }
12080 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
12081 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
12082 }
12083 else {
12084 if (NIL_P(v1)) {
12085 /* Set to default encodings */
12086 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
12087 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
12088 ecopts = Qnil;
12089 }
12090 else {
12091 tmp = rb_check_string_type(v1);
12092 if (!NIL_P(tmp) && rb_enc_asciicompat(enc = rb_enc_get(tmp))) {
12093 parse_mode_enc(RSTRING_PTR(tmp), enc, &enc, &enc2, NULL);
12094 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
12095 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
12096 }
12097 else {
12098 rb_io_ext_int_to_encs(find_encoding(v1), NULL, &enc, &enc2, 0);
12099 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
12100 ecopts = Qnil;
12101 }
12102 }
12103 }
12104 validate_enc_binmode(&fptr->mode, ecflags, enc, enc2);
12105 fptr->encs.enc = enc;
12106 fptr->encs.enc2 = enc2;
12107 fptr->encs.ecflags = ecflags;
12108 fptr->encs.ecopts = ecopts;
12109 clear_codeconv(fptr);
12110
12111}
12112
12114 rb_io_t *fptr;
12115 VALUE v1;
12116 VALUE v2;
12117 VALUE opt;
12118};
12119
12120static VALUE
12121io_encoding_set_v(VALUE v)
12122{
12123 struct io_encoding_set_args *arg = (struct io_encoding_set_args *)v;
12124 io_encoding_set(arg->fptr, arg->v1, arg->v2, arg->opt);
12125 return Qnil;
12126}
12127
12128static VALUE
12129pipe_pair_close(VALUE rw)
12130{
12131 VALUE *rwp = (VALUE *)rw;
12132 return rb_ensure(io_close, rwp[0], io_close, rwp[1]);
12133}
12134
12135/*
12136 * call-seq:
12137 * IO.pipe(**opts) -> [read_io, write_io]
12138 * IO.pipe(enc, **opts) -> [read_io, write_io]
12139 * IO.pipe(ext_enc, int_enc, **opts) -> [read_io, write_io]
12140 * IO.pipe(**opts) {|read_io, write_io| ...} -> object
12141 * IO.pipe(enc, **opts) {|read_io, write_io| ...} -> object
12142 * IO.pipe(ext_enc, int_enc, **opts) {|read_io, write_io| ...} -> object
12143 *
12144 * Creates a pair of pipe endpoints, +read_io+ and +write_io+,
12145 * connected to each other.
12146 *
12147 * If argument +enc_string+ is given, it must be a string containing one of:
12148 *
12149 * - The name of the encoding to be used as the external encoding.
12150 * - The colon-separated names of two encodings to be used as the external
12151 * and internal encodings.
12152 *
12153 * If argument +int_enc+ is given, it must be an Encoding object
12154 * or encoding name string that specifies the internal encoding to be used;
12155 * if argument +ext_enc+ is also given, it must be an Encoding object
12156 * or encoding name string that specifies the external encoding to be used.
12157 *
12158 * The string read from +read_io+ is tagged with the external encoding;
12159 * if an internal encoding is also specified, the string is converted
12160 * to, and tagged with, that encoding.
12161 *
12162 * If any encoding is specified,
12163 * optional hash arguments specify the conversion option.
12164 *
12165 * Optional keyword arguments +opts+ specify:
12166 *
12167 * - {Open Options}[rdoc-ref:IO@Open+Options].
12168 * - {Encoding Options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12169 *
12170 * With no block given, returns the two endpoints in an array:
12171 *
12172 * IO.pipe # => [#<IO:fd 4>, #<IO:fd 5>]
12173 *
12174 * With a block given, calls the block with the two endpoints;
12175 * closes both endpoints and returns the value of the block:
12176 *
12177 * IO.pipe {|read_io, write_io| p read_io; p write_io }
12178 *
12179 * Output:
12180 *
12181 * #<IO:fd 6>
12182 * #<IO:fd 7>
12183 *
12184 * Not available on all platforms.
12185 *
12186 * In the example below, the two processes close the ends of the pipe
12187 * that they are not using. This is not just a cosmetic nicety. The
12188 * read end of a pipe will not generate an end of file condition if
12189 * there are any writers with the pipe still open. In the case of the
12190 * parent process, the <tt>rd.read</tt> will never return if it
12191 * does not first issue a <tt>wr.close</tt>:
12192 *
12193 * rd, wr = IO.pipe
12194 *
12195 * if fork
12196 * wr.close
12197 * puts "Parent got: <#{rd.read}>"
12198 * rd.close
12199 * Process.wait
12200 * else
12201 * rd.close
12202 * puts 'Sending message to parent'
12203 * wr.write "Hi Dad"
12204 * wr.close
12205 * end
12206 *
12207 * <em>produces:</em>
12208 *
12209 * Sending message to parent
12210 * Parent got: <Hi Dad>
12211 *
12212 */
12213
12214static VALUE
12215rb_io_s_pipe(int argc, VALUE *argv, VALUE klass)
12216{
12217 int pipes[2], state;
12218 VALUE r, w, args[3], v1, v2;
12219 VALUE opt;
12220 rb_io_t *fptr, *fptr2;
12221 struct io_encoding_set_args ies_args;
12222 enum rb_io_mode fmode = 0;
12223 VALUE ret;
12224
12225 argc = rb_scan_args(argc, argv, "02:", &v1, &v2, &opt);
12226 if (rb_pipe(pipes) < 0)
12227 rb_sys_fail(0);
12228
12229 args[0] = klass;
12230 args[1] = INT2NUM(pipes[0]);
12231 args[2] = INT2FIX(O_RDONLY);
12232 r = rb_protect(io_new_instance, (VALUE)args, &state);
12233 if (state) {
12234 close(pipes[0]);
12235 close(pipes[1]);
12236 rb_jump_tag(state);
12237 }
12238 GetOpenFile(r, fptr);
12239
12240 ies_args.fptr = fptr;
12241 ies_args.v1 = v1;
12242 ies_args.v2 = v2;
12243 ies_args.opt = opt;
12244 rb_protect(io_encoding_set_v, (VALUE)&ies_args, &state);
12245 if (state) {
12246 close(pipes[1]);
12247 io_close(r);
12248 rb_jump_tag(state);
12249 }
12250
12251 args[1] = INT2NUM(pipes[1]);
12252 args[2] = INT2FIX(O_WRONLY);
12253 w = rb_protect(io_new_instance, (VALUE)args, &state);
12254 if (state) {
12255 close(pipes[1]);
12256 if (!NIL_P(r)) rb_io_close(r);
12257 rb_jump_tag(state);
12258 }
12259 GetOpenFile(w, fptr2);
12260 rb_io_synchronized(fptr2);
12261
12262 extract_binmode(opt, &fmode);
12263
12264 if ((fmode & FMODE_BINMODE) && NIL_P(v1)) {
12267 }
12268
12269#if DEFAULT_TEXTMODE
12270 if ((fptr->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
12271 fptr->mode &= ~FMODE_TEXTMODE;
12272 setmode(fptr->fd, O_BINARY);
12273 }
12274#if RUBY_CRLF_ENVIRONMENT
12277 }
12278#endif
12279#endif
12280 fptr->mode |= fmode;
12281#if DEFAULT_TEXTMODE
12282 if ((fptr2->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
12283 fptr2->mode &= ~FMODE_TEXTMODE;
12284 setmode(fptr2->fd, O_BINARY);
12285 }
12286#endif
12287 fptr2->mode |= fmode;
12288
12289 ret = rb_assoc_new(r, w);
12290 if (rb_block_given_p()) {
12291 VALUE rw[2];
12292 rw[0] = r;
12293 rw[1] = w;
12294 return rb_ensure(rb_yield, ret, pipe_pair_close, (VALUE)rw);
12295 }
12296 return ret;
12297}
12298
12300 int argc;
12301 VALUE *argv;
12302 VALUE io;
12303};
12304
12305static void
12306open_key_args(VALUE klass, int argc, VALUE *argv, VALUE opt, struct foreach_arg *arg)
12307{
12308 VALUE path, v;
12309 VALUE vmode = Qnil, vperm = Qnil;
12310
12311 path = *argv++;
12312 argc--;
12313 FilePathValue(path);
12314 arg->io = 0;
12315 arg->argc = argc;
12316 arg->argv = argv;
12317 if (NIL_P(opt)) {
12318 vmode = INT2NUM(O_RDONLY);
12319 vperm = INT2FIX(0666);
12320 }
12321 else if (!NIL_P(v = rb_hash_aref(opt, sym_open_args))) {
12322 int n;
12323
12324 v = rb_to_array_type(v);
12325 n = RARRAY_LENINT(v);
12326 rb_check_arity(n, 0, 3); /* rb_io_open */
12327 rb_scan_args_kw(RB_SCAN_ARGS_LAST_HASH_KEYWORDS, n, RARRAY_CONST_PTR(v), "02:", &vmode, &vperm, &opt);
12328 }
12329 arg->io = rb_io_open(klass, path, vmode, vperm, opt);
12330}
12331
12332static VALUE
12333io_s_foreach(VALUE v)
12334{
12335 struct getline_arg *arg = (void *)v;
12336 VALUE str;
12337
12338 if (arg->limit == 0)
12339 rb_raise(rb_eArgError, "invalid limit: 0 for foreach");
12340 while (!NIL_P(str = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, arg->io))) {
12341 rb_lastline_set(str);
12342 rb_yield(str);
12343 }
12345 return Qnil;
12346}
12347
12348/*
12349 * call-seq:
12350 * IO.foreach(path, sep = $/, **opts) {|line| block } -> nil
12351 * IO.foreach(path, limit, **opts) {|line| block } -> nil
12352 * IO.foreach(path, sep, limit, **opts) {|line| block } -> nil
12353 * IO.foreach(...) -> an_enumerator
12354 *
12355 * Calls the block with each successive line read from the stream.
12356 *
12357 * The first argument must be a string that is the path to a file.
12358 *
12359 * With only argument +path+ given, parses lines from the file at the given +path+,
12360 * as determined by the default line separator,
12361 * and calls the block with each successive line:
12362 *
12363 * File.foreach('t.txt') {|line| p line }
12364 *
12365 * Output: the same as above.
12366 *
12367 * For both forms, command and path, the remaining arguments are the same.
12368 *
12369 * With argument +sep+ given, parses lines as determined by that line separator
12370 * (see {Line Separator}[rdoc-ref:IO@Line+Separator]):
12371 *
12372 * File.foreach('t.txt', 'li') {|line| p line }
12373 *
12374 * Output:
12375 *
12376 * "First li"
12377 * "ne\nSecond li"
12378 * "ne\n\nThird li"
12379 * "ne\nFourth li"
12380 * "ne\n"
12381 *
12382 * Each paragraph:
12383 *
12384 * File.foreach('t.txt', '') {|paragraph| p paragraph }
12385 *
12386 * Output:
12387 *
12388 * "First line\nSecond line\n\n"
12389 * "Third line\nFourth line\n"
12390 *
12391 * With argument +limit+ given, parses lines as determined by the default
12392 * line separator and the given line-length limit
12393 * (see {Line Separator}[rdoc-ref:IO@Line+Separator] and {Line Limit}[rdoc-ref:IO@Line+Limit]):
12394 *
12395 * File.foreach('t.txt', 7) {|line| p line }
12396 *
12397 * Output:
12398 *
12399 * "First l"
12400 * "ine\n"
12401 * "Second "
12402 * "line\n"
12403 * "\n"
12404 * "Third l"
12405 * "ine\n"
12406 * "Fourth l"
12407 * "line\n"
12408 *
12409 * With arguments +sep+ and +limit+ given,
12410 * combines the two behaviors
12411 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
12412 *
12413 * Optional keyword arguments +opts+ specify:
12414 *
12415 * - {Open Options}[rdoc-ref:IO@Open+Options].
12416 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12417 * - {Line Input Options}[rdoc-ref:IO@Line+Input+Options].
12418 *
12419 * Returns an Enumerator if no block is given.
12420 *
12421 */
12422
12423static VALUE
12424rb_io_s_foreach(int argc, VALUE *argv, VALUE self)
12425{
12426 VALUE opt;
12427 int orig_argc = argc;
12428 struct foreach_arg arg;
12429 struct getline_arg garg;
12430
12431 argc = rb_scan_args(argc, argv, "12:", NULL, NULL, NULL, &opt);
12432 RETURN_ENUMERATOR(self, orig_argc, argv);
12433 extract_getline_args(argc-1, argv+1, &garg);
12434 open_key_args(self, argc, argv, opt, &arg);
12435 if (NIL_P(arg.io)) return Qnil;
12436 extract_getline_opts(opt, &garg);
12437 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12438 return rb_ensure(io_s_foreach, (VALUE)&garg, rb_io_close, arg.io);
12439}
12440
12441static VALUE
12442io_s_readlines(VALUE v)
12443{
12444 struct getline_arg *arg = (void *)v;
12445 return io_readlines(arg, arg->io);
12446}
12447
12448/*
12449 * call-seq:
12450 * IO.readlines(path, sep = $/, **opts) -> array
12451 * IO.readlines(path, limit, **opts) -> array
12452 * IO.readlines(path, sep, limit, **opts) -> array
12453 *
12454 * Returns an array of all lines read from the stream.
12455 *
12456 * The first argument must be a string that is the path to a file.
12457 *
12458 * With only argument +path+ given, parses lines from the file at the given +path+,
12459 * as determined by the default line separator,
12460 * and returns those lines in an array:
12461 *
12462 * IO.readlines('t.txt')
12463 * # => ["First line\n", "Second line\n", "\n", "Third line\n", "Fourth line\n"]
12464 *
12465 * With argument +sep+ given, parses lines as determined by that line separator
12466 * (see {Line Separator}[rdoc-ref:IO@Line+Separator]):
12467 *
12468 * # Ordinary separator.
12469 * IO.readlines('t.txt', 'li')
12470 * # =>["First li", "ne\nSecond li", "ne\n\nThird li", "ne\nFourth li", "ne\n"]
12471 * # Get-paragraphs separator.
12472 * IO.readlines('t.txt', '')
12473 * # => ["First line\nSecond line\n\n", "Third line\nFourth line\n"]
12474 * # Get-all separator.
12475 * IO.readlines('t.txt', nil)
12476 * # => ["First line\nSecond line\n\nThird line\nFourth line\n"]
12477 *
12478 * With argument +limit+ given, parses lines as determined by the default
12479 * line separator and the given line-length limit
12480 * (see {Line Separator}[rdoc-ref:IO@Line+Separator] and {Line Limit}[rdoc-ref:IO@Line+Limit]:
12481 *
12482 * IO.readlines('t.txt', 7)
12483 * # => ["First l", "ine\n", "Second ", "line\n", "\n", "Third l", "ine\n", "Fourth ", "line\n"]
12484 *
12485 * With arguments +sep+ and +limit+ given,
12486 * combines the two behaviors
12487 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
12488 *
12489 * Optional keyword arguments +opts+ specify:
12490 *
12491 * - {Open Options}[rdoc-ref:IO@Open+Options].
12492 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12493 * - {Line Input Options}[rdoc-ref:IO@Line+Input+Options].
12494 *
12495 */
12496
12497static VALUE
12498rb_io_s_readlines(int argc, VALUE *argv, VALUE io)
12499{
12500 VALUE opt;
12501 struct foreach_arg arg;
12502 struct getline_arg garg;
12503
12504 argc = rb_scan_args(argc, argv, "12:", NULL, NULL, NULL, &opt);
12505 extract_getline_args(argc-1, argv+1, &garg);
12506 open_key_args(io, argc, argv, opt, &arg);
12507 if (NIL_P(arg.io)) return Qnil;
12508 extract_getline_opts(opt, &garg);
12509 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12510 return rb_ensure(io_s_readlines, (VALUE)&garg, rb_io_close, arg.io);
12511}
12512
12513static VALUE
12514io_s_read(VALUE v)
12515{
12516 struct foreach_arg *arg = (void *)v;
12517 return io_read(arg->argc, arg->argv, arg->io);
12518}
12519
12520struct seek_arg {
12521 VALUE io;
12522 VALUE offset;
12523 int mode;
12524};
12525
12526static VALUE
12527seek_before_access(VALUE argp)
12528{
12529 struct seek_arg *arg = (struct seek_arg *)argp;
12530 rb_io_binmode(arg->io);
12531 return rb_io_seek(arg->io, arg->offset, arg->mode);
12532}
12533
12534/*
12535 * call-seq:
12536 * IO.read(path, length = nil, offset = 0, **opts) -> string or nil
12537 *
12538 * Opens the stream, reads and returns some or all of its content,
12539 * and closes the stream; returns +nil+ if no bytes were read.
12540 *
12541 * The first argument must be a string that is the path to a file.
12542 *
12543 * With only argument +path+ given, reads in text mode and returns the entire content
12544 * of the file at the given path:
12545 *
12546 * File.read('t.txt')
12547 * # => "First line\nSecond line\n\nFourth line\nFifth line\n"
12548 * File.read('t.ja')
12549 * # => "こんにちは"
12550 * File.read('t.dat')
12551 * # => "\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"
12552 *
12553 * On Windows, text mode can terminate reading and leave bytes in the file
12554 * unread when encountering certain special bytes. Consider using
12555 * IO.binread if all bytes in the file should be read.
12556 *
12557 * With argument +length+, returns +length+ bytes if available:
12558 *
12559 * File.read('t.txt', 7)
12560 * # => "First l"
12561 * File.read('t.ja', 7)
12562 * # => "\xE3\x81\x93\xE3\x82\x93\xE3"
12563 * File.read('t.dat', 7)
12564 * # => "\xFE\xFF\x99\x90\x99\x91\x99"
12565 *
12566 * Returns all bytes if +length+ is larger than the files size:
12567 *
12568 * File.read('t.txt', 700)
12569 * # => "First line\r\nSecond line\r\n\r\nFourth line\r\nFifth line\r\n"
12570 * File.read('t.ja', 700)
12571 * # => "\xE3\x81\x93\xE3\x82\x93\xE3\x81\xAB\xE3\x81\xA1\xE3\x81\xAF"
12572 * File.read('t.dat', 700)
12573 * # => "\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"
12574 *
12575 * With arguments +length+ and +offset+, returns +length+ bytes
12576 * if available, beginning at the given +offset+:
12577 *
12578 * File.read('t.txt', 10, 2)
12579 * # => "rst line\r\n"
12580 * File.read('t.ja', 10, 2)
12581 * # => "\x93\xE3\x82\x93\xE3\x81\xAB\xE3\x81\xA1"
12582 * File.read('t.dat', 10, 2)
12583 * # => "\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"
12584 *
12585 * Returns +nil+ if +offset+ is past the end of the stream:
12586 *
12587 * File.read('t.txt', 10, 200)
12588 * # => nil
12589 *
12590 * Optional keyword arguments +opts+ specify:
12591 *
12592 * - {Open Options}[rdoc-ref:IO@Open+Options].
12593 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12594 *
12595 */
12596
12597static VALUE
12598rb_io_s_read(int argc, VALUE *argv, VALUE io)
12599{
12600 VALUE opt, offset;
12601 long off;
12602 struct foreach_arg arg;
12603
12604 argc = rb_scan_args(argc, argv, "13:", NULL, NULL, &offset, NULL, &opt);
12605 if (!NIL_P(offset) && (off = NUM2LONG(offset)) < 0) {
12606 rb_raise(rb_eArgError, "negative offset %ld given", off);
12607 }
12608 open_key_args(io, argc, argv, opt, &arg);
12609 if (NIL_P(arg.io)) return Qnil;
12610 if (!NIL_P(offset)) {
12611 struct seek_arg sarg;
12612 int state = 0;
12613 sarg.io = arg.io;
12614 sarg.offset = offset;
12615 sarg.mode = SEEK_SET;
12616 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12617 if (state) {
12618 rb_io_close(arg.io);
12619 rb_jump_tag(state);
12620 }
12621 if (arg.argc == 2) arg.argc = 1;
12622 }
12623 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
12624}
12625
12626/*
12627 * call-seq:
12628 * IO.binread(path, length = nil, offset = 0) -> string or nil
12629 *
12630 * Behaves like IO.read, except that the stream is opened in binary mode
12631 * with ASCII-8BIT encoding.
12632 *
12633 */
12634
12635static VALUE
12636rb_io_s_binread(int argc, VALUE *argv, VALUE io)
12637{
12638 VALUE offset;
12639 struct foreach_arg arg;
12640 enum rb_io_mode fmode = FMODE_READABLE|FMODE_BINMODE;
12641 enum {
12642 oflags = O_RDONLY
12643#ifdef O_BINARY
12644 |O_BINARY
12645#endif
12646 };
12647 struct rb_io_encoding convconfig = {NULL, NULL, 0, Qnil};
12648
12649 rb_scan_args(argc, argv, "12", NULL, NULL, &offset);
12650 FilePathValue(argv[0]);
12651 convconfig.enc = rb_ascii8bit_encoding();
12652 arg.io = rb_io_open_generic(io, argv[0], oflags, fmode, &convconfig, 0);
12653 if (NIL_P(arg.io)) return Qnil;
12654 arg.argv = argv+1;
12655 arg.argc = (argc > 1) ? 1 : 0;
12656 if (!NIL_P(offset)) {
12657 struct seek_arg sarg;
12658 int state = 0;
12659 sarg.io = arg.io;
12660 sarg.offset = offset;
12661 sarg.mode = SEEK_SET;
12662 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12663 if (state) {
12664 rb_io_close(arg.io);
12665 rb_jump_tag(state);
12666 }
12667 }
12668 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
12669}
12670
12671static VALUE
12672io_s_write0(VALUE v)
12673{
12674 struct write_arg *arg = (void *)v;
12675 return io_write(arg->io,arg->str,arg->nosync);
12676}
12677
12678static VALUE
12679io_s_write(int argc, VALUE *argv, VALUE klass, int binary)
12680{
12681 VALUE string, offset, opt;
12682 struct foreach_arg arg;
12683 struct write_arg warg;
12684
12685 rb_scan_args(argc, argv, "21:", NULL, &string, &offset, &opt);
12686
12687 if (NIL_P(opt)) opt = rb_hash_new();
12688 else opt = rb_hash_dup(opt);
12689
12690
12691 if (NIL_P(rb_hash_aref(opt,sym_mode))) {
12692 int mode = O_WRONLY|O_CREAT;
12693#ifdef O_BINARY
12694 if (binary) mode |= O_BINARY;
12695#endif
12696 if (NIL_P(offset)) mode |= O_TRUNC;
12697 rb_hash_aset(opt,sym_mode,INT2NUM(mode));
12698 }
12699 open_key_args(klass, argc, argv, opt, &arg);
12700
12701#ifndef O_BINARY
12702 if (binary) rb_io_binmode_m(arg.io);
12703#endif
12704
12705 if (NIL_P(arg.io)) return Qnil;
12706 if (!NIL_P(offset)) {
12707 struct seek_arg sarg;
12708 int state = 0;
12709 sarg.io = arg.io;
12710 sarg.offset = offset;
12711 sarg.mode = SEEK_SET;
12712 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12713 if (state) {
12714 rb_io_close(arg.io);
12715 rb_jump_tag(state);
12716 }
12717 }
12718
12719 warg.io = arg.io;
12720 warg.str = string;
12721 warg.nosync = 0;
12722
12723 return rb_ensure(io_s_write0, (VALUE)&warg, rb_io_close, arg.io);
12724}
12725
12726/*
12727 * call-seq:
12728 * IO.write(path, data, offset = 0, **opts) -> nonnegative_integer
12729 *
12730 * Opens the stream, writes the given +data+ to it,
12731 * and closes the stream; returns the number of bytes written.
12732 *
12733 * The first argument must be a string that is the path to a file.
12734 *
12735 * With only arguments +path+ and +data+ given,
12736 * writes the given data to the file at that path:
12737 *
12738 * path = 't.tmp'
12739 * File.write(path, "First line\nSecond line\n\nFourth line\nFifth line\n") # => 47
12740 * File.write(path, 'こんにちは') # => 15
12741 * File.write(path, "\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94") # => 12
12742 *
12743 * When +offset+ is zero (the default), the entire file content is overwritten:
12744 *
12745 * File.read(path) # => "\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"
12746 * File.write(path, 'foo')
12747 * File.read(path) # => "foo"
12748 *
12749 * When +offset+ in within the file content, the file content is partly overwritten,
12750 * beginning at byte +offset+:
12751 *
12752 * File.write(path, "First line\nSecond line\n\nFourth line\nFifth line\n")
12753 * File.write(path, 'LINE', 6)
12754 * File.read(path) # => "First LINE\nSecond line\n\nFourth line\nFifth line\n"
12755 *
12756 * When the file contains multi-byte characters,
12757 * the effect of writing may disturb some characters:
12758 *
12759 * File.write(path, "こんにちは")
12760 * File.write(path, 'FOO', 3) # Replace one 3-byte character.
12761 * File.read(path) # => "こFOOにちは"
12762 * File.write(path, 'BAR', 7) # Replace bytes in two different 3-byte characters.
12763 * File.read(path) # => "こFOO\xE3BAR\x81\xA1は"
12764 *
12765 * If +offset+ is outside the file content,
12766 * the file is padded with null characters <tt>"\u0000"</tt>:
12767 *
12768 * File.write(path, "First line\nSecond line\n\nFourth line\nFifth line\n")
12769 * File.write(path, 'FOO', 55)
12770 * File.read(path)
12771 * # => "First line\nSecond line\n\nFourth line\nFifth line\n\u0000\u0000\u0000FOO"
12772 *
12773 * Optional keyword arguments +opts+ specify:
12774 *
12775 * - {Open Options}[rdoc-ref:IO@Open+Options].
12776 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12777 *
12778 */
12779
12780static VALUE
12781rb_io_s_write(int argc, VALUE *argv, VALUE io)
12782{
12783 return io_s_write(argc, argv, io, 0);
12784}
12785
12786/*
12787 * call-seq:
12788 * IO.binwrite(path, string, offset = 0, **opts) -> integer
12789 *
12790 * Behaves like IO.write, except that the stream is opened in binary mode
12791 * with ASCII-8BIT encoding.
12792 *
12793 */
12794
12795static VALUE
12796rb_io_s_binwrite(int argc, VALUE *argv, VALUE io)
12797{
12798 return io_s_write(argc, argv, io, 1);
12799}
12800
12802 VALUE src;
12803 VALUE dst;
12804 rb_off_t copy_length; /* (rb_off_t)-1 if not specified */
12805 rb_off_t src_offset; /* (rb_off_t)-1 if not specified */
12806
12807 rb_io_t *src_fptr;
12808 rb_io_t *dst_fptr;
12809 unsigned close_src : 1;
12810 unsigned close_dst : 1;
12811 int error_no;
12812 rb_off_t total;
12813 const char *syserr;
12814 const char *notimp;
12815 VALUE th;
12816 struct stat src_stat;
12817 struct stat dst_stat;
12818#ifdef HAVE_FCOPYFILE
12819 copyfile_state_t copyfile_state;
12820#endif
12821};
12822
12823static void *
12824exec_interrupts(void *arg)
12825{
12826 VALUE th = (VALUE)arg;
12827 rb_thread_execute_interrupts(th);
12828 return NULL;
12829}
12830
12831/*
12832 * returns TRUE if the preceding system call was interrupted
12833 * so we can continue. If the thread was interrupted, we
12834 * reacquire the GVL to execute interrupts before continuing.
12835 */
12836static int
12837maygvl_copy_stream_continue_p(int has_gvl, struct copy_stream_struct *stp)
12838{
12839 switch (errno) {
12840 case EINTR:
12841#if defined(ERESTART)
12842 case ERESTART:
12843#endif
12844 if (rb_thread_interrupted(stp->th)) {
12845 if (has_gvl)
12846 rb_thread_execute_interrupts(stp->th);
12847 else
12848 rb_thread_call_with_gvl(exec_interrupts, (void *)stp->th);
12849 }
12850 return TRUE;
12851 }
12852 return FALSE;
12853}
12854
12856 VALUE scheduler;
12857
12858 rb_io_t *fptr;
12859 short events;
12860
12861 VALUE result;
12862};
12863
12864static void *
12865fiber_scheduler_wait_for(void * _arguments)
12866{
12867 struct fiber_scheduler_wait_for_arguments *arguments = (struct fiber_scheduler_wait_for_arguments *)_arguments;
12868
12869 arguments->result = rb_fiber_scheduler_io_wait(arguments->scheduler, arguments->fptr->self, INT2NUM(arguments->events), RUBY_IO_TIMEOUT_DEFAULT);
12870
12871 return NULL;
12872}
12873
12874#if USE_POLL
12875# define IOWAIT_SYSCALL "poll"
12876STATIC_ASSERT(pollin_expected, POLLIN == RB_WAITFD_IN);
12877STATIC_ASSERT(pollout_expected, POLLOUT == RB_WAITFD_OUT);
12878static int
12879nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout)
12880{
12882 if (scheduler != Qnil) {
12883 struct fiber_scheduler_wait_for_arguments args = {.scheduler = scheduler, .fptr = fptr, .events = events};
12884 rb_thread_call_with_gvl(fiber_scheduler_wait_for, &args);
12885 return RTEST(args.result);
12886 }
12887
12888 int fd = fptr->fd;
12889 if (fd == -1) return 0;
12890
12891 struct pollfd fds;
12892
12893 fds.fd = fd;
12894 fds.events = events;
12895
12896 int timeout_milliseconds = -1;
12897
12898 if (timeout) {
12899 timeout_milliseconds = (int)(timeout->tv_sec * 1000) + (int)(timeout->tv_usec / 1000);
12900 }
12901
12902 return poll(&fds, 1, timeout_milliseconds);
12903}
12904#else /* !USE_POLL */
12905# define IOWAIT_SYSCALL "select"
12906static int
12907nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout)
12908{
12910 if (scheduler != Qnil) {
12911 struct fiber_scheduler_wait_for_arguments args = {.scheduler = scheduler, .fptr = fptr, .events = events};
12912 rb_thread_call_with_gvl(fiber_scheduler_wait_for, &args);
12913 return RTEST(args.result);
12914 }
12915
12916 int fd = fptr->fd;
12917
12918 if (fd == -1) {
12919 errno = EBADF;
12920 return -1;
12921 }
12922
12923 rb_fdset_t fds;
12924 int ret;
12925
12926 rb_fd_init(&fds);
12927 rb_fd_set(fd, &fds);
12928
12929 switch (events) {
12930 case RB_WAITFD_IN:
12931 ret = rb_fd_select(fd + 1, &fds, 0, 0, timeout);
12932 break;
12933 case RB_WAITFD_OUT:
12934 ret = rb_fd_select(fd + 1, 0, &fds, 0, timeout);
12935 break;
12936 default:
12937 VM_UNREACHABLE(nogvl_wait_for);
12938 }
12939
12940 rb_fd_term(&fds);
12941
12942 // On timeout, this returns 0.
12943 return ret;
12944}
12945#endif /* !USE_POLL */
12946
12947static int
12948maygvl_copy_stream_wait_read(int has_gvl, struct copy_stream_struct *stp)
12949{
12950 int ret;
12951
12952 do {
12953 if (has_gvl) {
12955 }
12956 else {
12957 ret = nogvl_wait_for(stp->th, stp->src_fptr, RB_WAITFD_IN, NULL);
12958 }
12959 } while (ret < 0 && maygvl_copy_stream_continue_p(has_gvl, stp));
12960
12961 if (ret < 0) {
12962 stp->syserr = IOWAIT_SYSCALL;
12963 stp->error_no = errno;
12964 return ret;
12965 }
12966 return 0;
12967}
12968
12969static int
12970nogvl_copy_stream_wait_write(struct copy_stream_struct *stp)
12971{
12972 int ret;
12973
12974 do {
12975 ret = nogvl_wait_for(stp->th, stp->dst_fptr, RB_WAITFD_OUT, NULL);
12976 } while (ret < 0 && maygvl_copy_stream_continue_p(0, stp));
12977
12978 if (ret < 0) {
12979 stp->syserr = IOWAIT_SYSCALL;
12980 stp->error_no = errno;
12981 return ret;
12982 }
12983 return 0;
12984}
12985
12986#ifdef USE_COPY_FILE_RANGE
12987
12988static ssize_t
12989simple_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)
12990{
12991#ifdef HAVE_COPY_FILE_RANGE
12992 return copy_file_range(in_fd, in_offset, out_fd, out_offset, count, flags);
12993#else
12994 return syscall(__NR_copy_file_range, in_fd, in_offset, out_fd, out_offset, count, flags);
12995#endif
12996}
12997
12998static int
12999nogvl_copy_file_range(struct copy_stream_struct *stp)
13000{
13001 ssize_t ss;
13002 rb_off_t src_size;
13003 rb_off_t copy_length, src_offset, *src_offset_ptr;
13004
13005 if (!S_ISREG(stp->src_stat.st_mode))
13006 return 0;
13007
13008 src_size = stp->src_stat.st_size;
13009 src_offset = stp->src_offset;
13010 if (src_offset >= (rb_off_t)0) {
13011 src_offset_ptr = &src_offset;
13012 }
13013 else {
13014 src_offset_ptr = NULL; /* if src_offset_ptr is NULL, then bytes are read from in_fd starting from the file offset */
13015 }
13016
13017 copy_length = stp->copy_length;
13018 if (copy_length < (rb_off_t)0) {
13019 if (src_offset < (rb_off_t)0) {
13020 rb_off_t current_offset;
13021 errno = 0;
13022 current_offset = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
13023 if (current_offset < (rb_off_t)0 && errno) {
13024 stp->syserr = "lseek";
13025 stp->error_no = errno;
13026 return (int)current_offset;
13027 }
13028 copy_length = src_size - current_offset;
13029 }
13030 else {
13031 copy_length = src_size - src_offset;
13032 }
13033 }
13034
13035 retry_copy_file_range:
13036# if SIZEOF_OFF_T > SIZEOF_SIZE_T
13037 /* we are limited by the 32-bit ssize_t return value on 32-bit */
13038 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
13039# else
13040 ss = (ssize_t)copy_length;
13041# endif
13042 ss = simple_copy_file_range(stp->src_fptr->fd, src_offset_ptr, stp->dst_fptr->fd, NULL, ss, 0);
13043 if (0 < ss) {
13044 stp->total += ss;
13045 copy_length -= ss;
13046 if (0 < copy_length) {
13047 goto retry_copy_file_range;
13048 }
13049 }
13050 if (ss < 0) {
13051 if (maygvl_copy_stream_continue_p(0, stp)) {
13052 goto retry_copy_file_range;
13053 }
13054 switch (errno) {
13055 case EINVAL:
13056 case EPERM: /* copy_file_range(2) doesn't exist (may happen in
13057 docker container) */
13058#ifdef ENOSYS
13059 case ENOSYS:
13060#endif
13061#ifdef EXDEV
13062 case EXDEV: /* in_fd and out_fd are not on the same filesystem */
13063#endif
13064 return 0;
13065 case EAGAIN:
13066#if EWOULDBLOCK != EAGAIN
13067 case EWOULDBLOCK:
13068#endif
13069 {
13070 int ret = nogvl_copy_stream_wait_write(stp);
13071 if (ret < 0) return ret;
13072 }
13073 goto retry_copy_file_range;
13074 case EBADF:
13075 {
13076 int e = errno;
13077 int flags = fcntl(stp->dst_fptr->fd, F_GETFL);
13078
13079 if (flags != -1 && flags & O_APPEND) {
13080 return 0;
13081 }
13082 errno = e;
13083 }
13084 }
13085 stp->syserr = "copy_file_range";
13086 stp->error_no = errno;
13087 return (int)ss;
13088 }
13089 return 1;
13090}
13091#endif
13092
13093#ifdef HAVE_FCOPYFILE
13094static int
13095nogvl_fcopyfile(struct copy_stream_struct *stp)
13096{
13097 rb_off_t cur, ss = 0;
13098 const rb_off_t src_offset = stp->src_offset;
13099 int ret;
13100
13101 if (stp->copy_length >= (rb_off_t)0) {
13102 /* copy_length can't be specified in fcopyfile(3) */
13103 return 0;
13104 }
13105
13106 if (!S_ISREG(stp->src_stat.st_mode))
13107 return 0;
13108
13109 if (!S_ISREG(stp->dst_stat.st_mode))
13110 return 0;
13111 if (lseek(stp->dst_fptr->fd, 0, SEEK_CUR) > (rb_off_t)0) /* if dst IO was already written */
13112 return 0;
13113 if (fcntl(stp->dst_fptr->fd, F_GETFL) & O_APPEND) {
13114 /* fcopyfile(3) appends src IO to dst IO and then truncates
13115 * dst IO to src IO's original size. */
13116 rb_off_t end = lseek(stp->dst_fptr->fd, 0, SEEK_END);
13117 lseek(stp->dst_fptr->fd, 0, SEEK_SET);
13118 if (end > (rb_off_t)0) return 0;
13119 }
13120
13121 if (src_offset > (rb_off_t)0) {
13122 rb_off_t r;
13123
13124 /* get current offset */
13125 errno = 0;
13126 cur = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
13127 if (cur < (rb_off_t)0 && errno) {
13128 stp->error_no = errno;
13129 return 1;
13130 }
13131
13132 errno = 0;
13133 r = lseek(stp->src_fptr->fd, src_offset, SEEK_SET);
13134 if (r < (rb_off_t)0 && errno) {
13135 stp->error_no = errno;
13136 return 1;
13137 }
13138 }
13139
13140 stp->copyfile_state = copyfile_state_alloc(); /* this will be freed by copy_stream_finalize() */
13141 ret = fcopyfile(stp->src_fptr->fd, stp->dst_fptr->fd, stp->copyfile_state, COPYFILE_DATA);
13142 copyfile_state_get(stp->copyfile_state, COPYFILE_STATE_COPIED, &ss); /* get copied bytes */
13143
13144 if (ret == 0) { /* success */
13145 stp->total = ss;
13146 if (src_offset > (rb_off_t)0) {
13147 rb_off_t r;
13148 errno = 0;
13149 /* reset offset */
13150 r = lseek(stp->src_fptr->fd, cur, SEEK_SET);
13151 if (r < (rb_off_t)0 && errno) {
13152 stp->error_no = errno;
13153 return 1;
13154 }
13155 }
13156 }
13157 else {
13158 switch (errno) {
13159 case ENOTSUP:
13160 case EPERM:
13161 case EINVAL:
13162 return 0;
13163 }
13164 stp->syserr = "fcopyfile";
13165 stp->error_no = errno;
13166 return (int)ret;
13167 }
13168 return 1;
13169}
13170#endif
13171
13172#ifdef HAVE_SENDFILE
13173
13174# ifdef __linux__
13175# define USE_SENDFILE
13176
13177# ifdef HAVE_SYS_SENDFILE_H
13178# include <sys/sendfile.h>
13179# endif
13180
13181static ssize_t
13182simple_sendfile(int out_fd, int in_fd, rb_off_t *offset, rb_off_t count)
13183{
13184 return sendfile(out_fd, in_fd, offset, (size_t)count);
13185}
13186
13187# elif 0 /* defined(__FreeBSD__) || defined(__DragonFly__) */ || defined(__APPLE__)
13188/* This runs on FreeBSD8.1 r30210, but sendfiles blocks its execution
13189 * without cpuset -l 0.
13190 */
13191# define USE_SENDFILE
13192
13193static ssize_t
13194simple_sendfile(int out_fd, int in_fd, rb_off_t *offset, rb_off_t count)
13195{
13196 int r;
13197 rb_off_t pos = offset ? *offset : lseek(in_fd, 0, SEEK_CUR);
13198 rb_off_t sbytes;
13199# ifdef __APPLE__
13200 r = sendfile(in_fd, out_fd, pos, &count, NULL, 0);
13201 sbytes = count;
13202# else
13203 r = sendfile(in_fd, out_fd, pos, (size_t)count, NULL, &sbytes, 0);
13204# endif
13205 if (r != 0 && sbytes == 0) return r;
13206 if (offset) {
13207 *offset += sbytes;
13208 }
13209 else {
13210 lseek(in_fd, sbytes, SEEK_CUR);
13211 }
13212 return (ssize_t)sbytes;
13213}
13214
13215# endif
13216
13217#endif
13218
13219#ifdef USE_SENDFILE
13220static int
13221nogvl_copy_stream_sendfile(struct copy_stream_struct *stp)
13222{
13223 ssize_t ss;
13224 rb_off_t src_size;
13225 rb_off_t copy_length;
13226 rb_off_t src_offset;
13227 int use_pread;
13228
13229 if (!S_ISREG(stp->src_stat.st_mode))
13230 return 0;
13231
13232 src_size = stp->src_stat.st_size;
13233#ifndef __linux__
13234 if ((stp->dst_stat.st_mode & S_IFMT) != S_IFSOCK)
13235 return 0;
13236#endif
13237
13238 src_offset = stp->src_offset;
13239 use_pread = src_offset >= (rb_off_t)0;
13240
13241 copy_length = stp->copy_length;
13242 if (copy_length < (rb_off_t)0) {
13243 if (use_pread)
13244 copy_length = src_size - src_offset;
13245 else {
13246 rb_off_t cur;
13247 errno = 0;
13248 cur = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
13249 if (cur < (rb_off_t)0 && errno) {
13250 stp->syserr = "lseek";
13251 stp->error_no = errno;
13252 return (int)cur;
13253 }
13254 copy_length = src_size - cur;
13255 }
13256 }
13257
13258 retry_sendfile:
13259# if SIZEOF_OFF_T > SIZEOF_SIZE_T
13260 /* we are limited by the 32-bit ssize_t return value on 32-bit */
13261 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
13262# else
13263 ss = (ssize_t)copy_length;
13264# endif
13265 if (use_pread) {
13266 ss = simple_sendfile(stp->dst_fptr->fd, stp->src_fptr->fd, &src_offset, ss);
13267 }
13268 else {
13269 ss = simple_sendfile(stp->dst_fptr->fd, stp->src_fptr->fd, NULL, ss);
13270 }
13271 if (0 < ss) {
13272 stp->total += ss;
13273 copy_length -= ss;
13274 if (0 < copy_length) {
13275 goto retry_sendfile;
13276 }
13277 }
13278 if (ss < 0) {
13279 if (maygvl_copy_stream_continue_p(0, stp))
13280 goto retry_sendfile;
13281 switch (errno) {
13282 case EINVAL:
13283#ifdef ENOSYS
13284 case ENOSYS:
13285#endif
13286#ifdef EOPNOTSUP
13287 /* some RedHat kernels may return EOPNOTSUP on an NFS mount.
13288 see also: [Feature #16965] */
13289 case EOPNOTSUP:
13290#endif
13291 return 0;
13292 case EAGAIN:
13293#if EWOULDBLOCK != EAGAIN
13294 case EWOULDBLOCK:
13295#endif
13296 {
13297 int ret;
13298#ifndef __linux__
13299 /*
13300 * Linux requires stp->src_fptr->fd to be a mmap-able (regular) file,
13301 * select() reports regular files to always be "ready", so
13302 * there is no need to select() on it.
13303 * Other OSes may have the same limitation for sendfile() which
13304 * allow us to bypass maygvl_copy_stream_wait_read()...
13305 */
13306 ret = maygvl_copy_stream_wait_read(0, stp);
13307 if (ret < 0) return ret;
13308#endif
13309 ret = nogvl_copy_stream_wait_write(stp);
13310 if (ret < 0) return ret;
13311 }
13312 goto retry_sendfile;
13313 }
13314 stp->syserr = "sendfile";
13315 stp->error_no = errno;
13316 return (int)ss;
13317 }
13318 return 1;
13319}
13320#endif
13321
13322static ssize_t
13323maygvl_read(int has_gvl, rb_io_t *fptr, void *buf, size_t count)
13324{
13325 if (has_gvl)
13326 return rb_io_read_memory(fptr, buf, count);
13327 else
13328 return read(fptr->fd, buf, count);
13329}
13330
13331static ssize_t
13332maygvl_copy_stream_read(int has_gvl, struct copy_stream_struct *stp, char *buf, size_t len, rb_off_t offset)
13333{
13334 ssize_t ss;
13335 retry_read:
13336 if (offset < (rb_off_t)0) {
13337 ss = maygvl_read(has_gvl, stp->src_fptr, buf, len);
13338 }
13339 else {
13340 ss = pread(stp->src_fptr->fd, buf, len, offset);
13341 }
13342 if (ss == 0) {
13343 return 0;
13344 }
13345 if (ss < 0) {
13346 if (maygvl_copy_stream_continue_p(has_gvl, stp))
13347 goto retry_read;
13348 switch (errno) {
13349 case EAGAIN:
13350#if EWOULDBLOCK != EAGAIN
13351 case EWOULDBLOCK:
13352#endif
13353 {
13354 int ret = maygvl_copy_stream_wait_read(has_gvl, stp);
13355 if (ret < 0) return ret;
13356 }
13357 goto retry_read;
13358#ifdef ENOSYS
13359 case ENOSYS:
13360 stp->notimp = "pread";
13361 return ss;
13362#endif
13363 }
13364 stp->syserr = offset < (rb_off_t)0 ? "read" : "pread";
13365 stp->error_no = errno;
13366 }
13367 return ss;
13368}
13369
13370static int
13371nogvl_copy_stream_write(struct copy_stream_struct *stp, char *buf, size_t len)
13372{
13373 ssize_t ss;
13374 int off = 0;
13375 while (len) {
13376 ss = write(stp->dst_fptr->fd, buf+off, len);
13377 if (ss < 0) {
13378 if (maygvl_copy_stream_continue_p(0, stp))
13379 continue;
13380 if (io_again_p(errno)) {
13381 int ret = nogvl_copy_stream_wait_write(stp);
13382 if (ret < 0) return ret;
13383 continue;
13384 }
13385 stp->syserr = "write";
13386 stp->error_no = errno;
13387 return (int)ss;
13388 }
13389 off += (int)ss;
13390 len -= (int)ss;
13391 stp->total += ss;
13392 }
13393 return 0;
13394}
13395
13396static void
13397nogvl_copy_stream_read_write(struct copy_stream_struct *stp)
13398{
13399 char buf[1024*16];
13400 size_t len;
13401 ssize_t ss;
13402 int ret;
13403 rb_off_t copy_length;
13404 rb_off_t src_offset;
13405 int use_eof;
13406 int use_pread;
13407
13408 copy_length = stp->copy_length;
13409 use_eof = copy_length < (rb_off_t)0;
13410 src_offset = stp->src_offset;
13411 use_pread = src_offset >= (rb_off_t)0;
13412
13413 if (use_pread && stp->close_src) {
13414 rb_off_t r;
13415 errno = 0;
13416 r = lseek(stp->src_fptr->fd, src_offset, SEEK_SET);
13417 if (r < (rb_off_t)0 && errno) {
13418 stp->syserr = "lseek";
13419 stp->error_no = errno;
13420 return;
13421 }
13422 src_offset = (rb_off_t)-1;
13423 use_pread = 0;
13424 }
13425
13426 while (use_eof || 0 < copy_length) {
13427 if (!use_eof && copy_length < (rb_off_t)sizeof(buf)) {
13428 len = (size_t)copy_length;
13429 }
13430 else {
13431 len = sizeof(buf);
13432 }
13433 if (use_pread) {
13434 ss = maygvl_copy_stream_read(0, stp, buf, len, src_offset);
13435 if (0 < ss)
13436 src_offset += ss;
13437 }
13438 else {
13439 ss = maygvl_copy_stream_read(0, stp, buf, len, (rb_off_t)-1);
13440 }
13441 if (ss <= 0) /* EOF or error */
13442 return;
13443
13444 ret = nogvl_copy_stream_write(stp, buf, ss);
13445 if (ret < 0)
13446 return;
13447
13448 if (!use_eof)
13449 copy_length -= ss;
13450 }
13451}
13452
13453static void *
13454nogvl_copy_stream_func(void *arg)
13455{
13456 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13457#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13458 int ret;
13459#endif
13460
13461#ifdef USE_COPY_FILE_RANGE
13462 ret = nogvl_copy_file_range(stp);
13463 if (ret != 0)
13464 goto finish; /* error or success */
13465#endif
13466
13467#ifdef HAVE_FCOPYFILE
13468 ret = nogvl_fcopyfile(stp);
13469 if (ret != 0)
13470 goto finish; /* error or success */
13471#endif
13472
13473#ifdef USE_SENDFILE
13474 ret = nogvl_copy_stream_sendfile(stp);
13475 if (ret != 0)
13476 goto finish; /* error or success */
13477#endif
13478
13479 nogvl_copy_stream_read_write(stp);
13480
13481#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13482 finish:
13483#endif
13484 return 0;
13485}
13486
13487static VALUE
13488copy_stream_fallback_body(VALUE arg)
13489{
13490 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13491 const int buflen = 16*1024;
13492 VALUE n;
13493 VALUE buf = rb_str_buf_new(buflen);
13494 rb_off_t rest = stp->copy_length;
13495 rb_off_t off = stp->src_offset;
13496 ID read_method = id_readpartial;
13497
13498 if (!stp->src_fptr) {
13499 if (!rb_respond_to(stp->src, read_method)) {
13500 read_method = id_read;
13501 }
13502 }
13503
13504 while (1) {
13505 long numwrote;
13506 long l;
13507 rb_str_make_independent(buf);
13508 if (stp->copy_length < (rb_off_t)0) {
13509 l = buflen;
13510 }
13511 else {
13512 if (rest == 0) {
13513 rb_str_resize(buf, 0);
13514 break;
13515 }
13516 l = buflen < rest ? buflen : (long)rest;
13517 }
13518 if (!stp->src_fptr) {
13519 VALUE rc = rb_funcall(stp->src, read_method, 2, INT2FIX(l), buf);
13520
13521 if (read_method == id_read && NIL_P(rc))
13522 break;
13523 }
13524 else {
13525 ssize_t ss;
13526 rb_str_resize(buf, buflen);
13527 ss = maygvl_copy_stream_read(1, stp, RSTRING_PTR(buf), l, off);
13528 rb_str_resize(buf, ss > 0 ? ss : 0);
13529 if (ss < 0)
13530 return Qnil;
13531 if (ss == 0)
13532 rb_eof_error();
13533 if (off >= (rb_off_t)0)
13534 off += ss;
13535 }
13536 n = rb_io_write(stp->dst, buf);
13537 numwrote = NUM2LONG(n);
13538 stp->total += numwrote;
13539 rest -= numwrote;
13540 if (read_method == id_read && RSTRING_LEN(buf) == 0) {
13541 break;
13542 }
13543 }
13544
13545 return Qnil;
13546}
13547
13548static VALUE
13549copy_stream_fallback(struct copy_stream_struct *stp)
13550{
13551 if (!stp->src_fptr && stp->src_offset >= (rb_off_t)0) {
13552 rb_raise(rb_eArgError, "cannot specify src_offset for non-IO");
13553 }
13554 rb_rescue2(copy_stream_fallback_body, (VALUE)stp,
13555 (VALUE (*) (VALUE, VALUE))0, (VALUE)0,
13556 rb_eEOFError, (VALUE)0);
13557 return Qnil;
13558}
13559
13560static VALUE
13561copy_stream_body(VALUE arg)
13562{
13563 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13564 VALUE src_io = stp->src, dst_io = stp->dst;
13565 const int common_oflags = 0
13566#ifdef O_NOCTTY
13567 | O_NOCTTY
13568#endif
13569 ;
13570
13571 stp->th = rb_thread_current();
13572
13573 stp->total = 0;
13574
13575 if (src_io == argf ||
13576 !(RB_TYPE_P(src_io, T_FILE) ||
13577 RB_TYPE_P(src_io, T_STRING) ||
13578 rb_respond_to(src_io, rb_intern("to_path")))) {
13579 stp->src_fptr = NULL;
13580 }
13581 else {
13582 int stat_ret;
13583 VALUE tmp_io = rb_io_check_io(src_io);
13584 if (!NIL_P(tmp_io)) {
13585 src_io = tmp_io;
13586 }
13587 else if (!RB_TYPE_P(src_io, T_FILE)) {
13588 VALUE args[2];
13589 FilePathValue(src_io);
13590 args[0] = src_io;
13591 args[1] = INT2NUM(O_RDONLY|common_oflags);
13592 src_io = rb_class_new_instance(2, args, rb_cFile);
13593 stp->src = src_io;
13594 stp->close_src = 1;
13595 }
13596 RB_IO_POINTER(src_io, stp->src_fptr);
13597 rb_io_check_byte_readable(stp->src_fptr);
13598
13599 stat_ret = fstat(stp->src_fptr->fd, &stp->src_stat);
13600 if (stat_ret < 0) {
13601 stp->syserr = "fstat";
13602 stp->error_no = errno;
13603 return Qnil;
13604 }
13605 }
13606
13607 if (dst_io == argf ||
13608 !(RB_TYPE_P(dst_io, T_FILE) ||
13609 RB_TYPE_P(dst_io, T_STRING) ||
13610 rb_respond_to(dst_io, rb_intern("to_path")))) {
13611 stp->dst_fptr = NULL;
13612 }
13613 else {
13614 int stat_ret;
13615 VALUE tmp_io = rb_io_check_io(dst_io);
13616 if (!NIL_P(tmp_io)) {
13617 dst_io = GetWriteIO(tmp_io);
13618 }
13619 else if (!RB_TYPE_P(dst_io, T_FILE)) {
13620 VALUE args[3];
13621 FilePathValue(dst_io);
13622 args[0] = dst_io;
13623 args[1] = INT2NUM(O_WRONLY|O_CREAT|O_TRUNC|common_oflags);
13624 args[2] = INT2FIX(0666);
13625 dst_io = rb_class_new_instance(3, args, rb_cFile);
13626 stp->dst = dst_io;
13627 stp->close_dst = 1;
13628 }
13629 else {
13630 dst_io = GetWriteIO(dst_io);
13631 stp->dst = dst_io;
13632 }
13633 RB_IO_POINTER(dst_io, stp->dst_fptr);
13634 rb_io_check_writable(stp->dst_fptr);
13635
13636 stat_ret = fstat(stp->dst_fptr->fd, &stp->dst_stat);
13637 if (stat_ret < 0) {
13638 stp->syserr = "fstat";
13639 stp->error_no = errno;
13640 return Qnil;
13641 }
13642 }
13643
13644#ifdef O_BINARY
13645 if (stp->src_fptr)
13646 SET_BINARY_MODE_WITH_SEEK_CUR(stp->src_fptr);
13647#endif
13648 if (stp->dst_fptr)
13649 io_ascii8bit_binmode(stp->dst_fptr);
13650
13651 if (stp->src_offset < (rb_off_t)0 && stp->src_fptr && stp->src_fptr->rbuf.len) {
13652 size_t len = stp->src_fptr->rbuf.len;
13653 VALUE str;
13654 if (stp->copy_length >= (rb_off_t)0 && stp->copy_length < (rb_off_t)len) {
13655 len = (size_t)stp->copy_length;
13656 }
13657 str = rb_str_buf_new(len);
13658 rb_str_resize(str,len);
13659 read_buffered_data(RSTRING_PTR(str), len, stp->src_fptr);
13660 if (stp->dst_fptr) { /* IO or filename */
13661 if (io_binwrite(RSTRING_PTR(str), RSTRING_LEN(str), stp->dst_fptr, 0) < 0)
13662 rb_sys_fail_on_write(stp->dst_fptr);
13663 }
13664 else /* others such as StringIO */
13665 rb_io_write(dst_io, str);
13666 rb_str_resize(str, 0);
13667 stp->total += len;
13668 if (stp->copy_length >= (rb_off_t)0)
13669 stp->copy_length -= len;
13670 }
13671
13672 if (stp->dst_fptr && io_fflush(stp->dst_fptr) < 0) {
13673 rb_raise(rb_eIOError, "flush failed");
13674 }
13675
13676 if (stp->copy_length == 0)
13677 return Qnil;
13678
13679 if (stp->src_fptr == NULL || stp->dst_fptr == NULL) {
13680 return copy_stream_fallback(stp);
13681 }
13682
13683 IO_WITHOUT_GVL(nogvl_copy_stream_func, stp);
13684 return Qnil;
13685}
13686
13687static VALUE
13688copy_stream_finalize(VALUE arg)
13689{
13690 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13691
13692#ifdef HAVE_FCOPYFILE
13693 if (stp->copyfile_state) {
13694 copyfile_state_free(stp->copyfile_state);
13695 }
13696#endif
13697
13698 if (stp->close_src) {
13699 rb_io_close_m(stp->src);
13700 }
13701 if (stp->close_dst) {
13702 rb_io_close_m(stp->dst);
13703 }
13704 if (stp->syserr) {
13705 rb_syserr_fail(stp->error_no, stp->syserr);
13706 }
13707 if (stp->notimp) {
13708 rb_raise(rb_eNotImpError, "%s() not implemented", stp->notimp);
13709 }
13710 return Qnil;
13711}
13712
13713/*
13714 * call-seq:
13715 * IO.copy_stream(src, dst, src_length = nil, src_offset = 0) -> integer
13716 *
13717 * Copies from the given +src+ to the given +dst+,
13718 * returning the number of bytes copied.
13719 *
13720 * - The given +src+ must be one of the following:
13721 *
13722 * - The path to a readable file, from which source data is to be read.
13723 * - An \IO-like object, opened for reading and capable of responding
13724 * to method +:readpartial+ or method +:read+.
13725 *
13726 * - The given +dst+ must be one of the following:
13727 *
13728 * - The path to a writable file, to which data is to be written.
13729 * - An \IO-like object, opened for writing and capable of responding
13730 * to method +:write+.
13731 *
13732 * The examples here use file <tt>t.txt</tt> as source:
13733 *
13734 * File.read('t.txt')
13735 * # => "First line\nSecond line\n\nThird line\nFourth line\n"
13736 * File.read('t.txt').size # => 47
13737 *
13738 * If only arguments +src+ and +dst+ are given,
13739 * the entire source stream is copied:
13740 *
13741 * # Paths.
13742 * IO.copy_stream('t.txt', 't.tmp') # => 47
13743 *
13744 * # IOs (recall that a File is also an IO).
13745 * src_io = File.open('t.txt', 'r') # => #<File:t.txt>
13746 * dst_io = File.open('t.tmp', 'w') # => #<File:t.tmp>
13747 * IO.copy_stream(src_io, dst_io) # => 47
13748 * src_io.close
13749 * dst_io.close
13750 *
13751 * With argument +src_length+ a non-negative integer,
13752 * no more than that many bytes are copied:
13753 *
13754 * IO.copy_stream('t.txt', 't.tmp', 10) # => 10
13755 * File.read('t.tmp') # => "First line"
13756 *
13757 * With argument +src_offset+ also given,
13758 * the source stream is read beginning at that offset:
13759 *
13760 * IO.copy_stream('t.txt', 't.tmp', 11, 11) # => 11
13761 * IO.read('t.tmp') # => "Second line"
13762 *
13763 */
13764static VALUE
13765rb_io_s_copy_stream(int argc, VALUE *argv, VALUE io)
13766{
13767 VALUE src, dst, length, src_offset;
13768 struct copy_stream_struct st;
13769
13770 MEMZERO(&st, struct copy_stream_struct, 1);
13771
13772 rb_scan_args(argc, argv, "22", &src, &dst, &length, &src_offset);
13773
13774 st.src = src;
13775 st.dst = dst;
13776
13777 st.src_fptr = NULL;
13778 st.dst_fptr = NULL;
13779
13780 if (NIL_P(length))
13781 st.copy_length = (rb_off_t)-1;
13782 else
13783 st.copy_length = NUM2OFFT(length);
13784
13785 if (NIL_P(src_offset))
13786 st.src_offset = (rb_off_t)-1;
13787 else
13788 st.src_offset = NUM2OFFT(src_offset);
13789
13790 rb_ensure(copy_stream_body, (VALUE)&st, copy_stream_finalize, (VALUE)&st);
13791
13792 return OFFT2NUM(st.total);
13793}
13794
13795/*
13796 * call-seq:
13797 * external_encoding -> encoding or nil
13798 *
13799 * Returns the Encoding object that represents the encoding of the stream,
13800 * or +nil+ if the stream is in write mode and no encoding is specified.
13801 *
13802 * See {Encodings}[rdoc-ref:File@Encodings].
13803 *
13804 */
13805
13806static VALUE
13807rb_io_external_encoding(VALUE io)
13808{
13809 rb_io_t *fptr = RFILE(rb_io_taint_check(io))->fptr;
13810
13811 if (fptr->encs.enc2) {
13812 return rb_enc_from_encoding(fptr->encs.enc2);
13813 }
13814 if (fptr->mode & FMODE_WRITABLE) {
13815 if (fptr->encs.enc)
13816 return rb_enc_from_encoding(fptr->encs.enc);
13817 return Qnil;
13818 }
13819 return rb_enc_from_encoding(io_read_encoding(fptr));
13820}
13821
13822/*
13823 * call-seq:
13824 * internal_encoding -> encoding or nil
13825 *
13826 * Returns the Encoding object that represents the encoding of the internal string,
13827 * if conversion is specified,
13828 * or +nil+ otherwise.
13829 *
13830 * See {Encodings}[rdoc-ref:File@Encodings].
13831 *
13832 */
13833
13834static VALUE
13835rb_io_internal_encoding(VALUE io)
13836{
13837 rb_io_t *fptr = RFILE(rb_io_taint_check(io))->fptr;
13838
13839 if (!fptr->encs.enc2) return Qnil;
13840 return rb_enc_from_encoding(io_read_encoding(fptr));
13841}
13842
13843/*
13844 * call-seq:
13845 * set_encoding(ext_enc) -> self
13846 * set_encoding(ext_enc, int_enc, **enc_opts) -> self
13847 * set_encoding('ext_enc:int_enc', **enc_opts) -> self
13848 *
13849 * See {Encodings}[rdoc-ref:File@Encodings].
13850 *
13851 * Argument +ext_enc+, if given, must be an Encoding object
13852 * or a String with the encoding name;
13853 * it is assigned as the encoding for the stream.
13854 *
13855 * Argument +int_enc+, if given, must be an Encoding object
13856 * or a String with the encoding name;
13857 * it is assigned as the encoding for the internal string.
13858 *
13859 * Argument <tt>'ext_enc:int_enc'</tt>, if given, is a string
13860 * containing two colon-separated encoding names;
13861 * corresponding Encoding objects are assigned as the external
13862 * and internal encodings for the stream.
13863 *
13864 * If the external encoding of a string is binary/ASCII-8BIT,
13865 * the internal encoding of the string is set to nil, since no
13866 * transcoding is needed.
13867 *
13868 * Optional keyword arguments +enc_opts+ specify
13869 * {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
13870 *
13871 */
13872
13873static VALUE
13874rb_io_set_encoding(int argc, VALUE *argv, VALUE io)
13875{
13876 rb_io_t *fptr;
13877 VALUE v1, v2, opt;
13878
13879 if (!RB_TYPE_P(io, T_FILE)) {
13880 return forward(io, id_set_encoding, argc, argv);
13881 }
13882
13883 argc = rb_scan_args(argc, argv, "11:", &v1, &v2, &opt);
13884 GetOpenFile(io, fptr);
13885 io_encoding_set(fptr, v1, v2, opt);
13886 return io;
13887}
13888
13889void
13890rb_stdio_set_default_encoding(void)
13891{
13892 VALUE val = Qnil;
13893
13894#ifdef _WIN32
13895 if (isatty(fileno(stdin))) {
13896 rb_encoding *external = rb_locale_encoding();
13897 rb_encoding *internal = rb_default_internal_encoding();
13898 if (!internal) internal = rb_default_external_encoding();
13899 io_encoding_set(RFILE(rb_stdin)->fptr,
13900 rb_enc_from_encoding(external),
13901 rb_enc_from_encoding(internal),
13902 Qnil);
13903 }
13904 else
13905#endif
13906 rb_io_set_encoding(1, &val, rb_stdin);
13907 rb_io_set_encoding(1, &val, rb_stdout);
13908 rb_io_set_encoding(1, &val, rb_stderr);
13909}
13910
13911static inline int
13912global_argf_p(VALUE arg)
13913{
13914 return arg == argf;
13915}
13916
13917typedef VALUE (*argf_encoding_func)(VALUE io);
13918
13919static VALUE
13920argf_encoding(VALUE argf, argf_encoding_func func)
13921{
13922 if (!RTEST(ARGF.current_file)) {
13923 return rb_enc_default_external();
13924 }
13925 return func(rb_io_check_io(ARGF.current_file));
13926}
13927
13928/*
13929 * call-seq:
13930 * ARGF.external_encoding -> encoding
13931 *
13932 * Returns the external encoding for files read from ARGF as an Encoding
13933 * object. The external encoding is the encoding of the text as stored in a
13934 * file. Contrast with ARGF.internal_encoding, which is the encoding used to
13935 * represent this text within Ruby.
13936 *
13937 * To set the external encoding use ARGF.set_encoding.
13938 *
13939 * For example:
13940 *
13941 * ARGF.external_encoding #=> #<Encoding:UTF-8>
13942 *
13943 */
13944static VALUE
13945argf_external_encoding(VALUE argf)
13946{
13947 return argf_encoding(argf, rb_io_external_encoding);
13948}
13949
13950/*
13951 * call-seq:
13952 * ARGF.internal_encoding -> encoding
13953 *
13954 * Returns the internal encoding for strings read from ARGF as an
13955 * Encoding object.
13956 *
13957 * If ARGF.set_encoding has been called with two encoding names, the second
13958 * is returned. Otherwise, if +Encoding.default_external+ has been set, that
13959 * value is returned. Failing that, if a default external encoding was
13960 * specified on the command-line, that value is used. If the encoding is
13961 * unknown, +nil+ is returned.
13962 */
13963static VALUE
13964argf_internal_encoding(VALUE argf)
13965{
13966 return argf_encoding(argf, rb_io_internal_encoding);
13967}
13968
13969/*
13970 * call-seq:
13971 * ARGF.set_encoding(ext_enc) -> ARGF
13972 * ARGF.set_encoding("ext_enc:int_enc") -> ARGF
13973 * ARGF.set_encoding(ext_enc, int_enc) -> ARGF
13974 * ARGF.set_encoding("ext_enc:int_enc", opt) -> ARGF
13975 * ARGF.set_encoding(ext_enc, int_enc, opt) -> ARGF
13976 *
13977 * If single argument is specified, strings read from ARGF are tagged with
13978 * the encoding specified.
13979 *
13980 * If two encoding names separated by a colon are given, e.g. "ascii:utf-8",
13981 * the read string is converted from the first encoding (external encoding)
13982 * to the second encoding (internal encoding), then tagged with the second
13983 * encoding.
13984 *
13985 * If two arguments are specified, they must be encoding objects or encoding
13986 * names. Again, the first specifies the external encoding; the second
13987 * specifies the internal encoding.
13988 *
13989 * If the external encoding and the internal encoding are specified, the
13990 * optional Hash argument can be used to adjust the conversion process. The
13991 * structure of this hash is explained in the String#encode documentation.
13992 *
13993 * For example:
13994 *
13995 * ARGF.set_encoding('ascii') # Tag the input as US-ASCII text
13996 * ARGF.set_encoding(Encoding::UTF_8) # Tag the input as UTF-8 text
13997 * ARGF.set_encoding('utf-8','ascii') # Transcode the input from US-ASCII
13998 * # to UTF-8.
13999 */
14000static VALUE
14001argf_set_encoding(int argc, VALUE *argv, VALUE argf)
14002{
14003 rb_io_t *fptr;
14004
14005 if (!next_argv()) {
14006 rb_raise(rb_eArgError, "no stream to set encoding");
14007 }
14008 rb_io_set_encoding(argc, argv, ARGF.current_file);
14009 GetOpenFile(ARGF.current_file, fptr);
14010 ARGF.encs = fptr->encs;
14011 RB_OBJ_WRITTEN(argf, Qundef, ARGF.encs.ecopts);
14012 return argf;
14013}
14014
14015/*
14016 * call-seq:
14017 * ARGF.tell -> Integer
14018 * ARGF.pos -> Integer
14019 *
14020 * Returns the current offset (in bytes) of the current file in ARGF.
14021 *
14022 * ARGF.pos #=> 0
14023 * ARGF.gets #=> "This is line one\n"
14024 * ARGF.pos #=> 17
14025 *
14026 */
14027static VALUE
14028argf_tell(VALUE argf)
14029{
14030 if (!next_argv()) {
14031 rb_raise(rb_eArgError, "no stream to tell");
14032 }
14033 ARGF_FORWARD(0, 0);
14034 return rb_io_tell(ARGF.current_file);
14035}
14036
14037/*
14038 * call-seq:
14039 * ARGF.seek(amount, whence=IO::SEEK_SET) -> 0
14040 *
14041 * Seeks to offset _amount_ (an Integer) in the ARGF stream according to
14042 * the value of _whence_. See IO#seek for further details.
14043 */
14044static VALUE
14045argf_seek_m(int argc, VALUE *argv, VALUE argf)
14046{
14047 if (!next_argv()) {
14048 rb_raise(rb_eArgError, "no stream to seek");
14049 }
14050 ARGF_FORWARD(argc, argv);
14051 return rb_io_seek_m(argc, argv, ARGF.current_file);
14052}
14053
14054/*
14055 * call-seq:
14056 * ARGF.pos = position -> Integer
14057 *
14058 * Seeks to the position given by _position_ (in bytes) in ARGF.
14059 *
14060 * For example:
14061 *
14062 * ARGF.pos = 17
14063 * ARGF.gets #=> "This is line two\n"
14064 */
14065static VALUE
14066argf_set_pos(VALUE argf, VALUE offset)
14067{
14068 if (!next_argv()) {
14069 rb_raise(rb_eArgError, "no stream to set position");
14070 }
14071 ARGF_FORWARD(1, &offset);
14072 return rb_io_set_pos(ARGF.current_file, offset);
14073}
14074
14075/*
14076 * call-seq:
14077 * ARGF.rewind -> 0
14078 *
14079 * Positions the current file to the beginning of input, resetting
14080 * ARGF.lineno to zero.
14081 *
14082 * ARGF.readline #=> "This is line one\n"
14083 * ARGF.rewind #=> 0
14084 * ARGF.lineno #=> 0
14085 * ARGF.readline #=> "This is line one\n"
14086 */
14087static VALUE
14088argf_rewind(VALUE argf)
14089{
14090 VALUE ret;
14091 int old_lineno;
14092
14093 if (!next_argv()) {
14094 rb_raise(rb_eArgError, "no stream to rewind");
14095 }
14096 ARGF_FORWARD(0, 0);
14097 old_lineno = RFILE(ARGF.current_file)->fptr->lineno;
14098 ret = rb_io_rewind(ARGF.current_file);
14099 if (!global_argf_p(argf)) {
14100 ARGF.last_lineno = ARGF.lineno -= old_lineno;
14101 }
14102 return ret;
14103}
14104
14105/*
14106 * call-seq:
14107 * ARGF.fileno -> integer
14108 * ARGF.to_i -> integer
14109 *
14110 * Returns an integer representing the numeric file descriptor for
14111 * the current file. Raises an ArgumentError if there isn't a current file.
14112 *
14113 * ARGF.fileno #=> 3
14114 */
14115static VALUE
14116argf_fileno(VALUE argf)
14117{
14118 if (!next_argv()) {
14119 rb_raise(rb_eArgError, "no stream");
14120 }
14121 ARGF_FORWARD(0, 0);
14122 return rb_io_fileno(ARGF.current_file);
14123}
14124
14125/*
14126 * call-seq:
14127 * ARGF.to_io -> IO
14128 *
14129 * Returns an IO object representing the current file. This will be a
14130 * File object unless the current file is a stream such as STDIN.
14131 *
14132 * For example:
14133 *
14134 * ARGF.to_io #=> #<File:glark.txt>
14135 * ARGF.to_io #=> #<IO:<STDIN>>
14136 */
14137static VALUE
14138argf_to_io(VALUE argf)
14139{
14140 next_argv();
14141 ARGF_FORWARD(0, 0);
14142 return ARGF.current_file;
14143}
14144
14145/*
14146 * call-seq:
14147 * ARGF.eof? -> true or false
14148 * ARGF.eof -> true or false
14149 *
14150 * Returns true if the current file in ARGF is at end of file, i.e. it has
14151 * no data to read. The stream must be opened for reading or an IOError
14152 * will be raised.
14153 *
14154 * $ echo "eof" | ruby argf.rb
14155 *
14156 * ARGF.eof? #=> false
14157 * 3.times { ARGF.readchar }
14158 * ARGF.eof? #=> false
14159 * ARGF.readchar #=> "\n"
14160 * ARGF.eof? #=> true
14161 */
14162
14163static VALUE
14164argf_eof(VALUE argf)
14165{
14166 next_argv();
14167 if (RTEST(ARGF.current_file)) {
14168 if (ARGF.init_p == 0) return Qtrue;
14169 next_argv();
14170 ARGF_FORWARD(0, 0);
14171 if (rb_io_eof(ARGF.current_file)) {
14172 return Qtrue;
14173 }
14174 }
14175 return Qfalse;
14176}
14177
14178/*
14179 * call-seq:
14180 * ARGF.read([length [, outbuf]]) -> string, outbuf, or nil
14181 *
14182 * Reads _length_ bytes from ARGF. The files named on the command line
14183 * are concatenated and treated as a single file by this method, so when
14184 * called without arguments the contents of this pseudo file are returned in
14185 * their entirety.
14186 *
14187 * _length_ must be a non-negative integer or +nil+.
14188 *
14189 * If _length_ is a positive integer, +read+ tries to read
14190 * _length_ bytes without any conversion (binary mode).
14191 * It returns +nil+ if an EOF is encountered before anything can be read.
14192 * Fewer than _length_ bytes are returned if an EOF is encountered during
14193 * the read.
14194 * In the case of an integer _length_, the resulting string is always
14195 * in ASCII-8BIT encoding.
14196 *
14197 * If _length_ is omitted or is +nil+, it reads until EOF
14198 * and the encoding conversion is applied, if applicable.
14199 * A string is returned even if EOF is encountered before any data is read.
14200 *
14201 * If _length_ is zero, it returns an empty string (<code>""</code>).
14202 *
14203 * If the optional _outbuf_ argument is present,
14204 * it must reference a String, which will receive the data.
14205 * The _outbuf_ will contain only the received data after the method call
14206 * even if it is not empty at the beginning.
14207 *
14208 * For example:
14209 *
14210 * $ echo "small" > small.txt
14211 * $ echo "large" > large.txt
14212 * $ ./glark.rb small.txt large.txt
14213 *
14214 * ARGF.read #=> "small\nlarge"
14215 * ARGF.read(200) #=> "small\nlarge"
14216 * ARGF.read(2) #=> "sm"
14217 * ARGF.read(0) #=> ""
14218 *
14219 * Note that this method behaves like the fread() function in C.
14220 * This means it retries to invoke read(2) system calls to read data
14221 * with the specified length.
14222 * If you need the behavior like a single read(2) system call,
14223 * consider ARGF#readpartial or ARGF#read_nonblock.
14224 */
14225
14226static VALUE
14227argf_read(int argc, VALUE *argv, VALUE argf)
14228{
14229 VALUE tmp, str, length;
14230 long len = 0;
14231
14232 rb_scan_args(argc, argv, "02", &length, &str);
14233 if (!NIL_P(length)) {
14234 len = NUM2LONG(argv[0]);
14235 }
14236 if (!NIL_P(str)) {
14237 StringValue(str);
14238 rb_str_resize(str,0);
14239 argv[1] = Qnil;
14240 }
14241
14242 retry:
14243 if (!next_argv()) {
14244 return str;
14245 }
14246 if (ARGF_GENERIC_INPUT_P()) {
14247 tmp = argf_forward(argc, argv, argf);
14248 }
14249 else {
14250 tmp = io_read(argc, argv, ARGF.current_file);
14251 }
14252 if (NIL_P(str)) str = tmp;
14253 else if (!NIL_P(tmp)) rb_str_append(str, tmp);
14254 if (NIL_P(tmp) || NIL_P(length)) {
14255 if (ARGF.next_p != -1) {
14256 argf_close(argf);
14257 ARGF.next_p = 1;
14258 goto retry;
14259 }
14260 }
14261 else if (argc >= 1) {
14262 long slen = RSTRING_LEN(str);
14263 if (slen < len) {
14264 argv[0] = LONG2NUM(len - slen);
14265 goto retry;
14266 }
14267 }
14268 return str;
14269}
14270
14272 int argc;
14273 VALUE *argv;
14274 VALUE argf;
14275};
14276
14277static VALUE
14278argf_forward_call(VALUE arg)
14279{
14280 struct argf_call_arg *p = (struct argf_call_arg *)arg;
14281 argf_forward(p->argc, p->argv, p->argf);
14282 return Qnil;
14283}
14284
14285static VALUE argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts,
14286 int nonblock);
14287
14288/*
14289 * call-seq:
14290 * ARGF.readpartial(maxlen) -> string
14291 * ARGF.readpartial(maxlen, outbuf) -> outbuf
14292 *
14293 * Reads at most _maxlen_ bytes from the ARGF stream.
14294 *
14295 * If the optional _outbuf_ argument is present,
14296 * it must reference a String, which will receive the data.
14297 * The _outbuf_ will contain only the received data after the method call
14298 * even if it is not empty at the beginning.
14299 *
14300 * It raises EOFError on end of ARGF stream.
14301 * Since ARGF stream is a concatenation of multiple files,
14302 * internally EOF is occur for each file.
14303 * ARGF.readpartial returns empty strings for EOFs except the last one and
14304 * raises EOFError for the last one.
14305 *
14306 */
14307
14308static VALUE
14309argf_readpartial(int argc, VALUE *argv, VALUE argf)
14310{
14311 return argf_getpartial(argc, argv, argf, Qnil, 0);
14312}
14313
14314/*
14315 * call-seq:
14316 * ARGF.read_nonblock(maxlen[, options]) -> string
14317 * ARGF.read_nonblock(maxlen, outbuf[, options]) -> outbuf
14318 *
14319 * Reads at most _maxlen_ bytes from the ARGF stream in non-blocking mode.
14320 */
14321
14322static VALUE
14323argf_read_nonblock(int argc, VALUE *argv, VALUE argf)
14324{
14325 VALUE opts;
14326
14327 rb_scan_args(argc, argv, "11:", NULL, NULL, &opts);
14328
14329 if (!NIL_P(opts))
14330 argc--;
14331
14332 return argf_getpartial(argc, argv, argf, opts, 1);
14333}
14334
14335static VALUE
14336argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts, int nonblock)
14337{
14338 VALUE tmp, str, length;
14339 int no_exception;
14340
14341 rb_scan_args(argc, argv, "11", &length, &str);
14342 if (!NIL_P(str)) {
14343 StringValue(str);
14344 argv[1] = str;
14345 }
14346 no_exception = no_exception_p(opts);
14347
14348 if (!next_argv()) {
14349 if (!NIL_P(str)) {
14350 rb_str_resize(str, 0);
14351 }
14352 rb_eof_error();
14353 }
14354 if (ARGF_GENERIC_INPUT_P()) {
14355 VALUE (*const rescue_does_nothing)(VALUE, VALUE) = 0;
14356 struct argf_call_arg arg;
14357 arg.argc = argc;
14358 arg.argv = argv;
14359 arg.argf = argf;
14360 tmp = rb_rescue2(argf_forward_call, (VALUE)&arg,
14361 rescue_does_nothing, Qnil, rb_eEOFError, (VALUE)0);
14362 }
14363 else {
14364 tmp = io_getpartial(argc, argv, ARGF.current_file, no_exception, nonblock);
14365 }
14366 if (NIL_P(tmp)) {
14367 if (ARGF.next_p == -1) {
14368 return io_nonblock_eof(no_exception);
14369 }
14370 argf_close(argf);
14371 ARGF.next_p = 1;
14372 if (RARRAY_LEN(ARGF.argv) == 0) {
14373 return io_nonblock_eof(no_exception);
14374 }
14375 if (NIL_P(str))
14376 str = rb_str_new(NULL, 0);
14377 return str;
14378 }
14379 return tmp;
14380}
14381
14382/*
14383 * call-seq:
14384 * ARGF.getc -> String or nil
14385 *
14386 * Reads the next character from ARGF and returns it as a String. Returns
14387 * +nil+ at the end of the stream.
14388 *
14389 * ARGF treats the files named on the command line as a single file created
14390 * by concatenating their contents. After returning the last character of the
14391 * first file, it returns the first character of the second file, and so on.
14392 *
14393 * For example:
14394 *
14395 * $ echo "foo" > file
14396 * $ ruby argf.rb file
14397 *
14398 * ARGF.getc #=> "f"
14399 * ARGF.getc #=> "o"
14400 * ARGF.getc #=> "o"
14401 * ARGF.getc #=> "\n"
14402 * ARGF.getc #=> nil
14403 * ARGF.getc #=> nil
14404 */
14405static VALUE
14406argf_getc(VALUE argf)
14407{
14408 VALUE ch;
14409
14410 retry:
14411 if (!next_argv()) return Qnil;
14412 if (ARGF_GENERIC_INPUT_P()) {
14413 ch = forward_current(rb_intern("getc"), 0, 0);
14414 }
14415 else {
14416 ch = rb_io_getc(ARGF.current_file);
14417 }
14418 if (NIL_P(ch) && ARGF.next_p != -1) {
14419 argf_close(argf);
14420 ARGF.next_p = 1;
14421 goto retry;
14422 }
14423
14424 return ch;
14425}
14426
14427/*
14428 * call-seq:
14429 * ARGF.getbyte -> Integer or nil
14430 *
14431 * Gets the next 8-bit byte (0..255) from ARGF. Returns +nil+ if called at
14432 * the end of the stream.
14433 *
14434 * For example:
14435 *
14436 * $ echo "foo" > file
14437 * $ ruby argf.rb file
14438 *
14439 * ARGF.getbyte #=> 102
14440 * ARGF.getbyte #=> 111
14441 * ARGF.getbyte #=> 111
14442 * ARGF.getbyte #=> 10
14443 * ARGF.getbyte #=> nil
14444 */
14445static VALUE
14446argf_getbyte(VALUE argf)
14447{
14448 VALUE ch;
14449
14450 retry:
14451 if (!next_argv()) return Qnil;
14452 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
14453 ch = forward_current(rb_intern("getbyte"), 0, 0);
14454 }
14455 else {
14456 ch = rb_io_getbyte(ARGF.current_file);
14457 }
14458 if (NIL_P(ch) && ARGF.next_p != -1) {
14459 argf_close(argf);
14460 ARGF.next_p = 1;
14461 goto retry;
14462 }
14463
14464 return ch;
14465}
14466
14467/*
14468 * call-seq:
14469 * ARGF.readchar -> String or nil
14470 *
14471 * Reads the next character from ARGF and returns it as a String. Raises
14472 * an EOFError after the last character of the last file has been read.
14473 *
14474 * For example:
14475 *
14476 * $ echo "foo" > file
14477 * $ ruby argf.rb file
14478 *
14479 * ARGF.readchar #=> "f"
14480 * ARGF.readchar #=> "o"
14481 * ARGF.readchar #=> "o"
14482 * ARGF.readchar #=> "\n"
14483 * ARGF.readchar #=> end of file reached (EOFError)
14484 */
14485static VALUE
14486argf_readchar(VALUE argf)
14487{
14488 VALUE ch;
14489
14490 retry:
14491 if (!next_argv()) rb_eof_error();
14492 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
14493 ch = forward_current(rb_intern("getc"), 0, 0);
14494 }
14495 else {
14496 ch = rb_io_getc(ARGF.current_file);
14497 }
14498 if (NIL_P(ch) && ARGF.next_p != -1) {
14499 argf_close(argf);
14500 ARGF.next_p = 1;
14501 goto retry;
14502 }
14503
14504 return ch;
14505}
14506
14507/*
14508 * call-seq:
14509 * ARGF.readbyte -> Integer
14510 *
14511 * Reads the next 8-bit byte from ARGF and returns it as an Integer. Raises
14512 * an EOFError after the last byte of the last file has been read.
14513 *
14514 * For example:
14515 *
14516 * $ echo "foo" > file
14517 * $ ruby argf.rb file
14518 *
14519 * ARGF.readbyte #=> 102
14520 * ARGF.readbyte #=> 111
14521 * ARGF.readbyte #=> 111
14522 * ARGF.readbyte #=> 10
14523 * ARGF.readbyte #=> end of file reached (EOFError)
14524 */
14525static VALUE
14526argf_readbyte(VALUE argf)
14527{
14528 VALUE c;
14529
14530 NEXT_ARGF_FORWARD(0, 0);
14531 c = argf_getbyte(argf);
14532 if (NIL_P(c)) {
14533 rb_eof_error();
14534 }
14535 return c;
14536}
14537
14538#define FOREACH_ARGF() while (next_argv())
14539
14540static VALUE
14541argf_block_call_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
14542{
14543 const VALUE current = ARGF.current_file;
14544 rb_yield_values2(argc, argv);
14545 if (ARGF.init_p == -1 || current != ARGF.current_file) {
14547 }
14548 return Qnil;
14549}
14550
14551#define ARGF_block_call(mid, argc, argv, func, argf) \
14552 rb_block_call_kw(ARGF.current_file, mid, argc, argv, \
14553 func, argf, rb_keyword_given_p())
14554
14555static void
14556argf_block_call(ID mid, int argc, VALUE *argv, VALUE argf)
14557{
14558 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_i, argf);
14559 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14560}
14561
14562static VALUE
14563argf_block_call_line_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
14564{
14565 if (!global_argf_p(argf)) {
14566 ARGF.last_lineno = ++ARGF.lineno;
14567 }
14568 return argf_block_call_i(i, argf, argc, argv, blockarg);
14569}
14570
14571static void
14572argf_block_call_line(ID mid, int argc, VALUE *argv, VALUE argf)
14573{
14574 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_line_i, argf);
14575 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14576}
14577
14578/*
14579 * call-seq:
14580 * ARGF.each(sep=$/) {|line| block } -> ARGF
14581 * ARGF.each(sep=$/, limit) {|line| block } -> ARGF
14582 * ARGF.each(...) -> an_enumerator
14583 *
14584 * ARGF.each_line(sep=$/) {|line| block } -> ARGF
14585 * ARGF.each_line(sep=$/, limit) {|line| block } -> ARGF
14586 * ARGF.each_line(...) -> an_enumerator
14587 *
14588 * Returns an enumerator which iterates over each line (separated by _sep_,
14589 * which defaults to your platform's newline character) of each file in
14590 * +ARGV+. If a block is supplied, each line in turn will be yielded to the
14591 * block, otherwise an enumerator is returned.
14592 * The optional _limit_ argument is an Integer specifying the maximum
14593 * length of each line; longer lines will be split according to this limit.
14594 *
14595 * This method allows you to treat the files supplied on the command line as
14596 * a single file consisting of the concatenation of each named file. After
14597 * the last line of the first file has been returned, the first line of the
14598 * second file is returned. The ARGF.filename and ARGF.lineno methods can be
14599 * used to determine the filename of the current line and line number of the
14600 * whole input, respectively.
14601 *
14602 * For example, the following code prints out each line of each named file
14603 * prefixed with its line number, displaying the filename once per file:
14604 *
14605 * ARGF.each_line do |line|
14606 * puts ARGF.filename if ARGF.file.lineno == 1
14607 * puts "#{ARGF.file.lineno}: #{line}"
14608 * end
14609 *
14610 * While the following code prints only the first file's name at first, and
14611 * the contents with line number counted through all named files.
14612 *
14613 * ARGF.each_line do |line|
14614 * puts ARGF.filename if ARGF.lineno == 1
14615 * puts "#{ARGF.lineno}: #{line}"
14616 * end
14617 */
14618static VALUE
14619argf_each_line(int argc, VALUE *argv, VALUE argf)
14620{
14621 RETURN_ENUMERATOR(argf, argc, argv);
14622 FOREACH_ARGF() {
14623 argf_block_call_line(rb_intern("each_line"), argc, argv, argf);
14624 }
14625 return argf;
14626}
14627
14628/*
14629 * call-seq:
14630 * ARGF.each_byte {|byte| block } -> ARGF
14631 * ARGF.each_byte -> an_enumerator
14632 *
14633 * Iterates over each byte of each file in +ARGV+.
14634 * A byte is returned as an Integer in the range 0..255.
14635 *
14636 * This method allows you to treat the files supplied on the command line as
14637 * a single file consisting of the concatenation of each named file. After
14638 * the last byte of the first file has been returned, the first byte of the
14639 * second file is returned. The ARGF.filename method can be used to
14640 * determine the filename of the current byte.
14641 *
14642 * If no block is given, an enumerator is returned instead.
14643 *
14644 * For example:
14645 *
14646 * ARGF.bytes.to_a #=> [35, 32, ... 95, 10]
14647 *
14648 */
14649static VALUE
14650argf_each_byte(VALUE argf)
14651{
14652 RETURN_ENUMERATOR(argf, 0, 0);
14653 FOREACH_ARGF() {
14654 argf_block_call(rb_intern("each_byte"), 0, 0, argf);
14655 }
14656 return argf;
14657}
14658
14659/*
14660 * call-seq:
14661 * ARGF.each_char {|char| block } -> ARGF
14662 * ARGF.each_char -> an_enumerator
14663 *
14664 * Iterates over each character of each file in ARGF.
14665 *
14666 * This method allows you to treat the files supplied on the command line as
14667 * a single file consisting of the concatenation of each named file. After
14668 * the last character of the first file has been returned, the first
14669 * character of the second file is returned. The ARGF.filename method can
14670 * be used to determine the name of the file in which the current character
14671 * appears.
14672 *
14673 * If no block is given, an enumerator is returned instead.
14674 */
14675static VALUE
14676argf_each_char(VALUE argf)
14677{
14678 RETURN_ENUMERATOR(argf, 0, 0);
14679 FOREACH_ARGF() {
14680 argf_block_call(rb_intern("each_char"), 0, 0, argf);
14681 }
14682 return argf;
14683}
14684
14685/*
14686 * call-seq:
14687 * ARGF.each_codepoint {|codepoint| block } -> ARGF
14688 * ARGF.each_codepoint -> an_enumerator
14689 *
14690 * Iterates over each codepoint of each file in ARGF.
14691 *
14692 * This method allows you to treat the files supplied on the command line as
14693 * a single file consisting of the concatenation of each named file. After
14694 * the last codepoint of the first file has been returned, the first
14695 * codepoint of the second file is returned. The ARGF.filename method can
14696 * be used to determine the name of the file in which the current codepoint
14697 * appears.
14698 *
14699 * If no block is given, an enumerator is returned instead.
14700 */
14701static VALUE
14702argf_each_codepoint(VALUE argf)
14703{
14704 RETURN_ENUMERATOR(argf, 0, 0);
14705 FOREACH_ARGF() {
14706 argf_block_call(rb_intern("each_codepoint"), 0, 0, argf);
14707 }
14708 return argf;
14709}
14710
14711/*
14712 * call-seq:
14713 * ARGF.filename -> String
14714 * ARGF.path -> String
14715 *
14716 * Returns the current filename. "-" is returned when the current file is
14717 * STDIN.
14718 *
14719 * For example:
14720 *
14721 * $ echo "foo" > foo
14722 * $ echo "bar" > bar
14723 * $ echo "glark" > glark
14724 *
14725 * $ ruby argf.rb foo bar glark
14726 *
14727 * ARGF.filename #=> "foo"
14728 * ARGF.read(5) #=> "foo\nb"
14729 * ARGF.filename #=> "bar"
14730 * ARGF.skip
14731 * ARGF.filename #=> "glark"
14732 */
14733static VALUE
14734argf_filename(VALUE argf)
14735{
14736 next_argv();
14737 return ARGF.filename;
14738}
14739
14740static VALUE
14741argf_filename_getter(ID id, VALUE *var)
14742{
14743 return argf_filename(*var);
14744}
14745
14746/*
14747 * call-seq:
14748 * ARGF.file -> IO or File object
14749 *
14750 * Returns the current file as an IO or File object.
14751 * <code>$stdin</code> is returned when the current file is STDIN.
14752 *
14753 * For example:
14754 *
14755 * $ echo "foo" > foo
14756 * $ echo "bar" > bar
14757 *
14758 * $ ruby argf.rb foo bar
14759 *
14760 * ARGF.file #=> #<File:foo>
14761 * ARGF.read(5) #=> "foo\nb"
14762 * ARGF.file #=> #<File:bar>
14763 */
14764static VALUE
14765argf_file(VALUE argf)
14766{
14767 next_argv();
14768 return ARGF.current_file;
14769}
14770
14771/*
14772 * call-seq:
14773 * ARGF.binmode -> ARGF
14774 *
14775 * Puts ARGF into binary mode. Once a stream is in binary mode, it cannot
14776 * be reset to non-binary mode. This option has the following effects:
14777 *
14778 * * Newline conversion is disabled.
14779 * * Encoding conversion is disabled.
14780 * * Content is treated as ASCII-8BIT.
14781 */
14782static VALUE
14783argf_binmode_m(VALUE argf)
14784{
14785 ARGF.binmode = 1;
14786 next_argv();
14787 ARGF_FORWARD(0, 0);
14788 rb_io_ascii8bit_binmode(ARGF.current_file);
14789 return argf;
14790}
14791
14792/*
14793 * call-seq:
14794 * ARGF.binmode? -> true or false
14795 *
14796 * Returns true if ARGF is being read in binary mode; false otherwise.
14797 * To enable binary mode use ARGF.binmode.
14798 *
14799 * For example:
14800 *
14801 * ARGF.binmode? #=> false
14802 * ARGF.binmode
14803 * ARGF.binmode? #=> true
14804 */
14805static VALUE
14806argf_binmode_p(VALUE argf)
14807{
14808 return RBOOL(ARGF.binmode);
14809}
14810
14811/*
14812 * call-seq:
14813 * ARGF.skip -> ARGF
14814 *
14815 * Sets the current file to the next file in ARGV. If there aren't any more
14816 * files it has no effect.
14817 *
14818 * For example:
14819 *
14820 * $ ruby argf.rb foo bar
14821 * ARGF.filename #=> "foo"
14822 * ARGF.skip
14823 * ARGF.filename #=> "bar"
14824 */
14825static VALUE
14826argf_skip(VALUE argf)
14827{
14828 if (ARGF.init_p && ARGF.next_p == 0) {
14829 argf_close(argf);
14830 ARGF.next_p = 1;
14831 }
14832 return argf;
14833}
14834
14835/*
14836 * call-seq:
14837 * ARGF.close -> ARGF
14838 *
14839 * Closes the current file and skips to the next file in ARGV. If there are
14840 * no more files to open, just closes the current file. STDIN will not be
14841 * closed.
14842 *
14843 * For example:
14844 *
14845 * $ ruby argf.rb foo bar
14846 *
14847 * ARGF.filename #=> "foo"
14848 * ARGF.close
14849 * ARGF.filename #=> "bar"
14850 * ARGF.close
14851 */
14852static VALUE
14853argf_close_m(VALUE argf)
14854{
14855 next_argv();
14856 argf_close(argf);
14857 if (ARGF.next_p != -1) {
14858 ARGF.next_p = 1;
14859 }
14860 ARGF.lineno = 0;
14861 return argf;
14862}
14863
14864/*
14865 * call-seq:
14866 * ARGF.closed? -> true or false
14867 *
14868 * Returns _true_ if the current file has been closed; _false_ otherwise. Use
14869 * ARGF.close to actually close the current file.
14870 */
14871static VALUE
14872argf_closed(VALUE argf)
14873{
14874 next_argv();
14875 ARGF_FORWARD(0, 0);
14876 return rb_io_closed_p(ARGF.current_file);
14877}
14878
14879/*
14880 * call-seq:
14881 * ARGF.to_s -> String
14882 *
14883 * Returns "ARGF".
14884 */
14885static VALUE
14886argf_to_s(VALUE argf)
14887{
14888 return rb_str_new2("ARGF");
14889}
14890
14891/*
14892 * call-seq:
14893 * ARGF.inplace_mode -> String
14894 *
14895 * Returns the file extension appended to the names of backup copies of
14896 * modified files under in-place edit mode. This value can be set using
14897 * ARGF.inplace_mode= or passing the +-i+ switch to the Ruby binary.
14898 */
14899static VALUE
14900argf_inplace_mode_get(VALUE argf)
14901{
14902 if (!ARGF.inplace) return Qnil;
14903 if (NIL_P(ARGF.inplace)) return rb_str_new(0, 0);
14904 return rb_str_dup(ARGF.inplace);
14905}
14906
14907static VALUE
14908opt_i_get(ID id, VALUE *var)
14909{
14910 return argf_inplace_mode_get(*var);
14911}
14912
14913/*
14914 * call-seq:
14915 * ARGF.inplace_mode = ext -> ARGF
14916 *
14917 * Sets the filename extension for in-place editing mode to the given String.
14918 * The backup copy of each file being edited has this value appended to its
14919 * filename.
14920 *
14921 * For example:
14922 *
14923 * $ ruby argf.rb file.txt
14924 *
14925 * ARGF.inplace_mode = '.bak'
14926 * ARGF.each_line do |line|
14927 * print line.sub("foo","bar")
14928 * end
14929 *
14930 * First, _file.txt.bak_ is created as a backup copy of _file.txt_.
14931 * Then, each line of _file.txt_ has the first occurrence of "foo" replaced with
14932 * "bar".
14933 */
14934static VALUE
14935argf_inplace_mode_set(VALUE argf, VALUE val)
14936{
14937 if (!RTEST(val)) {
14938 ARGF.inplace = Qfalse;
14939 }
14940 else if (StringValueCStr(val), !RSTRING_LEN(val)) {
14941 ARGF.inplace = Qnil;
14942 }
14943 else {
14944 ARGF_SET(inplace, rb_str_new_frozen(val));
14945 }
14946 return argf;
14947}
14948
14949static void
14950opt_i_set(VALUE val, ID id, VALUE *var)
14951{
14952 argf_inplace_mode_set(*var, val);
14953}
14954
14955void
14956ruby_set_inplace_mode(const char *suffix)
14957{
14958 ARGF_SET(inplace, !suffix ? Qfalse : !*suffix ? Qnil : rb_str_new(suffix, strlen(suffix)));
14959}
14960
14961/*
14962 * call-seq:
14963 * ARGF.argv -> ARGV
14964 *
14965 * Returns the +ARGV+ array, which contains the arguments passed to your
14966 * script, one per element.
14967 *
14968 * For example:
14969 *
14970 * $ ruby argf.rb -v glark.txt
14971 *
14972 * ARGF.argv #=> ["-v", "glark.txt"]
14973 *
14974 */
14975static VALUE
14976argf_argv(VALUE argf)
14977{
14978 return ARGF.argv;
14979}
14980
14981static VALUE
14982argf_argv_getter(ID id, VALUE *var)
14983{
14984 return argf_argv(*var);
14985}
14986
14987VALUE
14989{
14990 return ARGF.argv;
14991}
14992
14993/*
14994 * call-seq:
14995 * ARGF.to_write_io -> io
14996 *
14997 * Returns IO instance tied to _ARGF_ for writing if inplace mode is
14998 * enabled.
14999 */
15000static VALUE
15001argf_write_io(VALUE argf)
15002{
15003 if (!RTEST(ARGF.current_file)) {
15004 rb_raise(rb_eIOError, "not opened for writing");
15005 }
15006 return GetWriteIO(ARGF.current_file);
15007}
15008
15009/*
15010 * call-seq:
15011 * ARGF.write(*objects) -> integer
15012 *
15013 * Writes each of the given +objects+ if inplace mode.
15014 */
15015static VALUE
15016argf_write(int argc, VALUE *argv, VALUE argf)
15017{
15018 return rb_io_writev(argf_write_io(argf), argc, argv);
15019}
15020
15021void
15022rb_readwrite_sys_fail(enum rb_io_wait_readwrite waiting, const char *mesg)
15023{
15024 rb_readwrite_syserr_fail(waiting, errno, mesg);
15025}
15026
15027void
15028rb_readwrite_syserr_fail(enum rb_io_wait_readwrite waiting, int n, const char *mesg)
15029{
15030 VALUE arg, c = Qnil;
15031 arg = mesg ? rb_str_new2(mesg) : Qnil;
15032 switch (waiting) {
15033 case RB_IO_WAIT_WRITABLE:
15034 switch (n) {
15035 case EAGAIN:
15036 c = rb_eEAGAINWaitWritable;
15037 break;
15038#if EAGAIN != EWOULDBLOCK
15039 case EWOULDBLOCK:
15040 c = rb_eEWOULDBLOCKWaitWritable;
15041 break;
15042#endif
15043 case EINPROGRESS:
15044 c = rb_eEINPROGRESSWaitWritable;
15045 break;
15046 default:
15048 }
15049 break;
15050 case RB_IO_WAIT_READABLE:
15051 switch (n) {
15052 case EAGAIN:
15053 c = rb_eEAGAINWaitReadable;
15054 break;
15055#if EAGAIN != EWOULDBLOCK
15056 case EWOULDBLOCK:
15057 c = rb_eEWOULDBLOCKWaitReadable;
15058 break;
15059#endif
15060 case EINPROGRESS:
15061 c = rb_eEINPROGRESSWaitReadable;
15062 break;
15063 default:
15065 }
15066 break;
15067 default:
15068 rb_bug("invalid read/write type passed to rb_readwrite_sys_fail: %d", waiting);
15069 }
15071}
15072
15073static VALUE
15074get_LAST_READ_LINE(ID _x, VALUE *_y)
15075{
15076 return rb_lastline_get();
15077}
15078
15079static void
15080set_LAST_READ_LINE(VALUE val, ID _x, VALUE *_y)
15081{
15082 rb_lastline_set(val);
15083}
15084
15085/*
15086 * Document-class: IOError
15087 *
15088 * Raised when an IO operation fails.
15089 *
15090 * File.open("/etc/hosts") {|f| f << "example"}
15091 * #=> IOError: not opened for writing
15092 *
15093 * File.open("/etc/hosts") {|f| f.close; f.read }
15094 * #=> IOError: closed stream
15095 *
15096 * Note that some IO failures raise <code>SystemCallError</code>s
15097 * and these are not subclasses of IOError:
15098 *
15099 * File.open("does/not/exist")
15100 * #=> Errno::ENOENT: No such file or directory - does/not/exist
15101 */
15102
15103/*
15104 * Document-class: EOFError
15105 *
15106 * Raised by some IO operations when reaching the end of file. Many IO
15107 * methods exist in two forms,
15108 *
15109 * one that returns +nil+ when the end of file is reached, the other
15110 * raises EOFError.
15111 *
15112 * EOFError is a subclass of IOError.
15113 *
15114 * file = File.open("/etc/hosts")
15115 * file.read
15116 * file.gets #=> nil
15117 * file.readline #=> EOFError: end of file reached
15118 * file.close
15119 */
15120
15121/*
15122 * Document-class: ARGF
15123 *
15124 * == \ARGF and +ARGV+
15125 *
15126 * The \ARGF object works with the array at global variable +ARGV+
15127 * to make <tt>$stdin</tt> and file streams available in the Ruby program:
15128 *
15129 * - **ARGV** may be thought of as the <b>argument vector</b> array.
15130 *
15131 * Initially, it contains the command-line arguments and options
15132 * that are passed to the Ruby program;
15133 * the program can modify that array as it likes.
15134 *
15135 * - **ARGF** may be thought of as the <b>argument files</b> object.
15136 *
15137 * It can access file streams and/or the <tt>$stdin</tt> stream,
15138 * based on what it finds in +ARGV+.
15139 * This provides a convenient way for the command line
15140 * to specify streams for a Ruby program to read.
15141 *
15142 * == Reading
15143 *
15144 * \ARGF may read from _source_ streams,
15145 * which at any particular time are determined by the content of +ARGV+.
15146 *
15147 * === Simplest Case
15148 *
15149 * When the <i>very first</i> \ARGF read occurs with an empty +ARGV+ (<tt>[]</tt>),
15150 * the source is <tt>$stdin</tt>:
15151 *
15152 * - \File +t.rb+:
15153 *
15154 * p ['ARGV', ARGV]
15155 * p ['ARGF.read', ARGF.read]
15156 *
15157 * - Commands and outputs
15158 * (see below for the content of files +foo.txt+ and +bar.txt+):
15159 *
15160 * $ echo "Open the pod bay doors, Hal." | ruby t.rb
15161 * ["ARGV", []]
15162 * ["ARGF.read", "Open the pod bay doors, Hal.\n"]
15163 *
15164 * $ cat foo.txt bar.txt | ruby t.rb
15165 * ["ARGV", []]
15166 * ["ARGF.read", "Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"]
15167 *
15168 * === About the Examples
15169 *
15170 * Many examples here assume the existence of files +foo.txt+ and +bar.txt+:
15171 *
15172 * $ cat foo.txt
15173 * Foo 0
15174 * Foo 1
15175 * $ cat bar.txt
15176 * Bar 0
15177 * Bar 1
15178 * Bar 2
15179 * Bar 3
15180 *
15181 * === Sources in +ARGV+
15182 *
15183 * For any \ARGF read _except_ the {simplest case}[rdoc-ref:ARGF@Simplest+Case]
15184 * (that is, _except_ for the <i>very first</i> \ARGF read with an empty +ARGV+),
15185 * the sources are found in +ARGV+.
15186 *
15187 * \ARGF assumes that each element in array +ARGV+ is a potential source,
15188 * and is one of:
15189 *
15190 * - The string path to a file that may be opened as a stream.
15191 * - The character <tt>'-'</tt>, meaning stream <tt>$stdin</tt>.
15192 *
15193 * Each element that is _not_ one of these
15194 * should be removed from +ARGV+ before \ARGF accesses that source.
15195 *
15196 * In the following example:
15197 *
15198 * - Filepaths +foo.txt+ and +bar.txt+ may be retained as potential sources.
15199 * - Options <tt>--xyzzy</tt> and <tt>--mojo</tt> should be removed.
15200 *
15201 * Example:
15202 *
15203 * - \File +t.rb+:
15204 *
15205 * # Print arguments (and options, if any) found on command line.
15206 * p ['ARGV', ARGV]
15207 *
15208 * - Command and output:
15209 *
15210 * $ ruby t.rb --xyzzy --mojo foo.txt bar.txt
15211 * ["ARGV", ["--xyzzy", "--mojo", "foo.txt", "bar.txt"]]
15212 *
15213 * \ARGF's stream access considers the elements of +ARGV+, left to right:
15214 *
15215 * - \File +t.rb+:
15216 *
15217 * p "ARGV: #{ARGV}"
15218 * p "Read: #{ARGF.read}" # Read everything from all specified streams.
15219 *
15220 * - Command and output:
15221 *
15222 * $ ruby t.rb foo.txt bar.txt
15223 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
15224 * "Read: Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"
15225 *
15226 * Because the value at +ARGV+ is an ordinary array,
15227 * you can manipulate it to control which sources \ARGF considers:
15228 *
15229 * - If you remove an element from +ARGV+, \ARGF will not consider the corresponding source.
15230 * - If you add an element to +ARGV+, \ARGF will consider the corresponding source.
15231 *
15232 * Each element in +ARGV+ is removed when its corresponding source is accessed;
15233 * when all sources have been accessed, the array is empty:
15234 *
15235 * - \File +t.rb+:
15236 *
15237 * until ARGV.empty? && ARGF.eof?
15238 * p "ARGV: #{ARGV}"
15239 * p "Line: #{ARGF.readline}" # Read each line from each specified stream.
15240 * end
15241 *
15242 * - Command and output:
15243 *
15244 * $ ruby t.rb foo.txt bar.txt
15245 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
15246 * "Line: Foo 0\n"
15247 * "ARGV: [\"bar.txt\"]"
15248 * "Line: Foo 1\n"
15249 * "ARGV: [\"bar.txt\"]"
15250 * "Line: Bar 0\n"
15251 * "ARGV: []"
15252 * "Line: Bar 1\n"
15253 * "ARGV: []"
15254 * "Line: Bar 2\n"
15255 * "ARGV: []"
15256 * "Line: Bar 3\n"
15257 *
15258 * ==== Filepaths in +ARGV+
15259 *
15260 * The +ARGV+ array may contain filepaths the specify sources for \ARGF reading.
15261 *
15262 * This program prints what it reads from files at the paths specified
15263 * on the command line:
15264 *
15265 * - \File +t.rb+:
15266 *
15267 * p ['ARGV', ARGV]
15268 * # Read and print all content from the specified sources.
15269 * p ['ARGF.read', ARGF.read]
15270 *
15271 * - Command and output:
15272 *
15273 * $ ruby t.rb foo.txt bar.txt
15274 * ["ARGV", [foo.txt, bar.txt]
15275 * ["ARGF.read", "Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"]
15276 *
15277 * ==== Specifying <tt>$stdin</tt> in +ARGV+
15278 *
15279 * To specify stream <tt>$stdin</tt> in +ARGV+, us the character <tt>'-'</tt>:
15280 *
15281 * - \File +t.rb+:
15282 *
15283 * p ['ARGV', ARGV]
15284 * p ['ARGF.read', ARGF.read]
15285 *
15286 * - Command and output:
15287 *
15288 * $ echo "Open the pod bay doors, Hal." | ruby t.rb -
15289 * ["ARGV", ["-"]]
15290 * ["ARGF.read", "Open the pod bay doors, Hal.\n"]
15291 *
15292 * When no character <tt>'-'</tt> is given, stream <tt>$stdin</tt> is ignored.
15293 *
15294 * - Command and output:
15295 *
15296 * $ echo "Open the pod bay doors, Hal." | ruby t.rb foo.txt bar.txt
15297 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
15298 * "Read: Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"
15299 *
15300 * ==== Mixtures and Repetitions in +ARGV+
15301 *
15302 * For an \ARGF reader, +ARGV+ may contain any mixture of filepaths
15303 * and character <tt>'-'</tt>, including repetitions.
15304 *
15305 * ==== Modifications to +ARGV+
15306 *
15307 * The running Ruby program may make any modifications to the +ARGV+ array;
15308 * the current value of +ARGV+ affects \ARGF reading.
15309 *
15310 * ==== Empty +ARGV+
15311 *
15312 * For an empty +ARGV+, an \ARGF read method either returns +nil+
15313 * or raises an exception, depending on the specific method.
15314 *
15315 * === More Read Methods
15316 *
15317 * As seen above, method ARGF#read reads the content of all sources
15318 * into a single string.
15319 * Other \ARGF methods provide other ways to access that content;
15320 * these include:
15321 *
15322 * - Byte access: #each_byte, #getbyte, #readbyte.
15323 * - Character access: #each_char, #getc, #readchar.
15324 * - Codepoint access: #each_codepoint.
15325 * - Line access: #each_line, #gets, #readline, #readlines.
15326 * - Source access: #read, #read_nonblock, #readpartial.
15327 *
15328 * === About \Enumerable
15329 *
15330 * \ARGF includes module Enumerable.
15331 * Virtually all methods in \Enumerable call method <tt>#each</tt> in the including class.
15332 *
15333 * <b>Note well</b>: In \ARGF, method #each returns data from the _sources_,
15334 * _not_ from +ARGV+;
15335 * therefore, for example, <tt>ARGF#entries</tt> returns an array of lines from the sources,
15336 * not an array of the strings from +ARGV+:
15337 *
15338 * - \File +t.rb+:
15339 *
15340 * p ['ARGV', ARGV]
15341 * p ['ARGF.entries', ARGF.entries]
15342 *
15343 * - Command and output:
15344 *
15345 * $ ruby t.rb foo.txt bar.txt
15346 * ["ARGV", ["foo.txt", "bar.txt"]]
15347 * ["ARGF.entries", ["Foo 0\n", "Foo 1\n", "Bar 0\n", "Bar 1\n", "Bar 2\n", "Bar 3\n"]]
15348 *
15349 * == Writing
15350 *
15351 * If <i>inplace mode</i> is in effect,
15352 * \ARGF may write to target streams,
15353 * which at any particular time are determined by the content of ARGV.
15354 *
15355 * Methods about inplace mode:
15356 *
15357 * - #inplace_mode
15358 * - #inplace_mode=
15359 * - #to_write_io
15360 *
15361 * Methods for writing:
15362 *
15363 * - #print
15364 * - #printf
15365 * - #putc
15366 * - #puts
15367 * - #write
15368 *
15369 */
15370
15371/*
15372 * An instance of class \IO (commonly called a _stream_)
15373 * represents an input/output stream in the underlying operating system.
15374 * Class \IO is the basis for input and output in Ruby.
15375 *
15376 * Class File is the only class in the Ruby core that is a subclass of \IO.
15377 * Some classes in the Ruby standard library are also subclasses of \IO;
15378 * these include TCPSocket and UDPSocket.
15379 *
15380 * The global constant ARGF (also accessible as <tt>$<</tt>)
15381 * provides an IO-like stream that allows access to all file paths
15382 * found in ARGV (or found in STDIN if ARGV is empty).
15383 * ARGF is not itself a subclass of \IO.
15384 *
15385 * Class StringIO provides an IO-like stream that handles a String.
15386 * StringIO is not itself a subclass of \IO.
15387 *
15388 * Important objects based on \IO include:
15389 *
15390 * - $stdin.
15391 * - $stdout.
15392 * - $stderr.
15393 * - Instances of class File.
15394 *
15395 * An instance of \IO may be created using:
15396 *
15397 * - IO.new: returns a new \IO object for the given integer file descriptor.
15398 * - IO.open: passes a new \IO object to the given block.
15399 * - IO.popen: returns a new \IO object that is connected to the $stdin and $stdout
15400 * of a newly-launched subprocess.
15401 * - Kernel#open: Returns a new \IO object connected to a given source:
15402 * stream, file, or subprocess.
15403 *
15404 * Like a File stream, an \IO stream has:
15405 *
15406 * - A read/write mode, which may be read-only, write-only, or read/write;
15407 * see {Read/Write Mode}[rdoc-ref:File@ReadWrite+Mode].
15408 * - A data mode, which may be text-only or binary;
15409 * see {Data Mode}[rdoc-ref:File@Data+Mode].
15410 * - Internal and external encodings;
15411 * see {Encodings}[rdoc-ref:File@Encodings].
15412 *
15413 * And like other \IO streams, it has:
15414 *
15415 * - A position, which determines where in the stream the next
15416 * read or write is to occur;
15417 * see {Position}[rdoc-ref:IO@Position].
15418 * - A line number, which is a special, line-oriented, "position"
15419 * (different from the position mentioned above);
15420 * see {Line Number}[rdoc-ref:IO@Line+Number].
15421 *
15422 * == Extension <tt>io/console</tt>
15423 *
15424 * Extension <tt>io/console</tt> provides numerous methods
15425 * for interacting with the console;
15426 * requiring it adds numerous methods to class \IO.
15427 *
15428 * == Example Files
15429 *
15430 * Many examples here use these variables:
15431 *
15432 * :include: doc/examples/files.rdoc
15433 *
15434 * == Open Options
15435 *
15436 * A number of \IO methods accept optional keyword arguments
15437 * that determine how a new stream is to be opened:
15438 *
15439 * - +:mode+: Stream mode.
15440 * - +:flags+: Integer file open flags;
15441 * If +mode+ is also given, the two are bitwise-ORed.
15442 * - +:external_encoding+: External encoding for the stream.
15443 * - +:internal_encoding+: Internal encoding for the stream.
15444 * <tt>'-'</tt> is a synonym for the default internal encoding.
15445 * If the value is +nil+ no conversion occurs.
15446 * - +:encoding+: Specifies external and internal encodings as <tt>'extern:intern'</tt>.
15447 * - +:textmode+: If a truthy value, specifies the mode as text-only, binary otherwise.
15448 * - +:binmode+: If a truthy value, specifies the mode as binary, text-only otherwise.
15449 * - +:autoclose+: If a truthy value, specifies that the +fd+ will close
15450 * when the stream closes; otherwise it remains open.
15451 * - +:path+: If a string value is provided, it is used in #inspect and is available as
15452 * #path method.
15453 *
15454 * Also available are the options offered in String#encode,
15455 * which may control conversion between external and internal encoding.
15456 *
15457 * == Basic \IO
15458 *
15459 * You can perform basic stream \IO with these methods,
15460 * which typically operate on multi-byte strings:
15461 *
15462 * - IO#read: Reads and returns some or all of the remaining bytes from the stream.
15463 * - IO#write: Writes zero or more strings to the stream;
15464 * each given object that is not already a string is converted via +to_s+.
15465 *
15466 * === Position
15467 *
15468 * An \IO stream has a nonnegative integer _position_,
15469 * which is the byte offset at which the next read or write is to occur.
15470 * A new stream has position zero (and line number zero);
15471 * method +rewind+ resets the position (and line number) to zero.
15472 *
15473 * These methods discard {buffers}[rdoc-ref:IO@Buffering] and the
15474 * Encoding::Converter instances used for that \IO.
15475 *
15476 * The relevant methods:
15477 *
15478 * - IO#tell (aliased as +#pos+): Returns the current position (in bytes) in the stream.
15479 * - IO#pos=: Sets the position of the stream to a given integer +new_position+ (in bytes).
15480 * - IO#seek: Sets the position of the stream to a given integer +offset+ (in bytes),
15481 * relative to a given position +whence+
15482 * (indicating the beginning, end, or current position).
15483 * - IO#rewind: Positions the stream at the beginning (also resetting the line number).
15484 *
15485 * === Open and Closed Streams
15486 *
15487 * A new \IO stream may be open for reading, open for writing, or both.
15488 *
15489 * A stream is automatically closed when claimed by the garbage collector.
15490 *
15491 * Attempted reading or writing on a closed stream raises an exception.
15492 *
15493 * The relevant methods:
15494 *
15495 * - IO#close: Closes the stream for both reading and writing.
15496 * - IO#close_read: Closes the stream for reading.
15497 * - IO#close_write: Closes the stream for writing.
15498 * - IO#closed?: Returns whether the stream is closed.
15499 *
15500 * === End-of-Stream
15501 *
15502 * You can query whether a stream is positioned at its end:
15503 *
15504 * - IO#eof? (also aliased as +#eof+): Returns whether the stream is at end-of-stream.
15505 *
15506 * You can reposition to end-of-stream by using method IO#seek:
15507 *
15508 * f = File.new('t.txt')
15509 * f.eof? # => false
15510 * f.seek(0, :END)
15511 * f.eof? # => true
15512 * f.close
15513 *
15514 * Or by reading all stream content (which is slower than using IO#seek):
15515 *
15516 * f.rewind
15517 * f.eof? # => false
15518 * f.read # => "First line\nSecond line\n\nFourth line\nFifth line\n"
15519 * f.eof? # => true
15520 *
15521 * == Line \IO
15522 *
15523 * Class \IO supports line-oriented
15524 * {input}[rdoc-ref:IO@Line+Input] and {output}[rdoc-ref:IO@Line+Output]
15525 *
15526 * === Line Input
15527 *
15528 * Class \IO supports line-oriented input for
15529 * {files}[rdoc-ref:IO@File+Line+Input] and {IO streams}[rdoc-ref:IO@Stream+Line+Input].
15530 *
15531 * ==== Line Input Options
15532 *
15533 * Optional keyword argument +chomp+ (default: +false+)
15534 * specifies whether line separators are to be excluded from the result of a read.
15535 *
15536 * ==== \File Line Input
15537 *
15538 * You can read lines from a file using these methods:
15539 *
15540 * - IO.foreach: Reads each line and passes it to the given block.
15541 * - IO.readlines: Reads and returns all lines in an array.
15542 *
15543 * For each of these methods:
15544 *
15545 * - You can specify {open options}[rdoc-ref:IO@Open+Options].
15546 * - Line parsing depends on the effective <i>line separator</i>;
15547 * see {Line Separator}[rdoc-ref:IO@Line+Separator].
15548 * - The length of each returned line depends on the effective <i>line limit</i>;
15549 * see {Line Limit}[rdoc-ref:IO@Line+Limit].
15550 *
15551 * ==== Stream Line Input
15552 *
15553 * You can read lines from an \IO stream using these methods:
15554 *
15555 * - IO#each_line: Reads each remaining line, passing it to the given block.
15556 * - IO#gets: Returns the next line.
15557 * - IO#readline: Like #gets, but raises an exception at end-of-stream.
15558 * - IO#readlines: Returns all remaining lines in an array.
15559 *
15560 * For each of these methods:
15561 *
15562 * - Reading may begin mid-line,
15563 * depending on the stream's _position_;
15564 * see {Position}[rdoc-ref:IO@Position].
15565 * - Line parsing depends on the effective <i>line separator</i>;
15566 * see {Line Separator}[rdoc-ref:IO@Line+Separator].
15567 * - The length of each returned line depends on the effective <i>line limit</i>;
15568 * see {Line Limit}[rdoc-ref:IO@Line+Limit].
15569 *
15570 * ===== Line Separator
15571 *
15572 * Each of the {line input methods}[rdoc-ref:IO@Line+Input] uses a <i>line separator</i>:
15573 * the string that determines what is considered a line;
15574 * it is sometimes called the <i>input record separator</i>.
15575 *
15576 * The default line separator is taken from global variable <tt>$/</tt>,
15577 * whose initial value is <tt>"\n"</tt>.
15578 *
15579 * Generally, the line to be read next is all data
15580 * from the current {position}[rdoc-ref:IO@Position]
15581 * to the next line separator
15582 * (but see {Special Line Separator Values}[rdoc-ref:IO@Special+Line+Separator+Values]):
15583 *
15584 * f = File.new('t.txt')
15585 * # Method gets with no sep argument returns the next line, according to $/.
15586 * f.gets # => "First line\n"
15587 * f.gets # => "Second line\n"
15588 * f.gets # => "\n"
15589 * f.gets # => "Fourth line\n"
15590 * f.gets # => "Fifth line\n"
15591 * f.close
15592 *
15593 * You can use a different line separator by passing argument +sep+:
15594 *
15595 * f = File.new('t.txt')
15596 * f.gets('l') # => "First l"
15597 * f.gets('li') # => "ine\nSecond li"
15598 * f.gets('lin') # => "ne\n\nFourth lin"
15599 * f.gets # => "e\n"
15600 * f.close
15601 *
15602 * Or by setting global variable <tt>$/</tt>:
15603 *
15604 * f = File.new('t.txt')
15605 * $/ = 'l'
15606 * f.gets # => "First l"
15607 * f.gets # => "ine\nSecond l"
15608 * f.gets # => "ine\n\nFourth l"
15609 * f.close
15610 *
15611 * ===== Special Line Separator Values
15612 *
15613 * Each of the {line input methods}[rdoc-ref:IO@Line+Input]
15614 * accepts two special values for parameter +sep+:
15615 *
15616 * - +nil+: The entire stream is to be read ("slurped") into a single string:
15617 *
15618 * f = File.new('t.txt')
15619 * f.gets(nil) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
15620 * f.close
15621 *
15622 * - <tt>''</tt> (the empty string): The next "paragraph" is to be read
15623 * (paragraphs being separated by two consecutive line separators):
15624 *
15625 * f = File.new('t.txt')
15626 * f.gets('') # => "First line\nSecond line\n\n"
15627 * f.gets('') # => "Fourth line\nFifth line\n"
15628 * f.close
15629 *
15630 * ===== Line Limit
15631 *
15632 * Each of the {line input methods}[rdoc-ref:IO@Line+Input]
15633 * uses an integer <i>line limit</i>,
15634 * which restricts the number of bytes that may be returned.
15635 * (A multi-byte character will not be split, and so a returned line may be slightly longer
15636 * than the limit).
15637 *
15638 * The default limit value is <tt>-1</tt>;
15639 * any negative limit value means that there is no limit.
15640 *
15641 * If there is no limit, the line is determined only by +sep+.
15642 *
15643 * # Text with 1-byte characters.
15644 * File.open('t.txt') {|f| f.gets(1) } # => "F"
15645 * File.open('t.txt') {|f| f.gets(2) } # => "Fi"
15646 * File.open('t.txt') {|f| f.gets(3) } # => "Fir"
15647 * File.open('t.txt') {|f| f.gets(4) } # => "Firs"
15648 * # No more than one line.
15649 * File.open('t.txt') {|f| f.gets(10) } # => "First line"
15650 * File.open('t.txt') {|f| f.gets(11) } # => "First line\n"
15651 * File.open('t.txt') {|f| f.gets(12) } # => "First line\n"
15652 *
15653 * # Text with 3-byte characters, which will not be split.
15654 * File.read('t.ja') # => "こんにちは"
15655 * File.open('t.ja') {|f| f.gets(1).size } # => 1
15656 * File.open('t.ja') {|f| f.gets(2).size } # => 1
15657 * File.open('t.ja') {|f| f.gets(3).size } # => 1
15658 * File.open('t.ja') {|f| f.gets(4).size } # => 2
15659 * File.open('t.ja') {|f| f.gets(5).size } # => 2
15660 *
15661 * ===== Line Separator and Line Limit
15662 *
15663 * With arguments +sep+ and +limit+ given, combines the two behaviors:
15664 *
15665 * - Returns the next line as determined by line separator +sep+.
15666 * - But returns no more bytes than are allowed by the limit +limit+.
15667 *
15668 * Example:
15669 *
15670 * File.open('t.txt') {|f| f.gets('li', 20) } # => "First li"
15671 * File.open('t.txt') {|f| f.gets('li', 2) } # => "Fi"
15672 *
15673 * ===== Line Number
15674 *
15675 * A readable \IO stream has a non-negative integer <i>line number</i>:
15676 *
15677 * - IO#lineno: Returns the line number.
15678 * - IO#lineno=: Resets and returns the line number.
15679 *
15680 * Unless modified by a call to method IO#lineno=,
15681 * the line number is the number of lines read
15682 * by certain line-oriented methods,
15683 * according to the effective {line separator}[rdoc-ref:IO@Line+Separator]:
15684 *
15685 * - IO.foreach: Increments the line number on each call to the block.
15686 * - IO#each_line: Increments the line number on each call to the block.
15687 * - IO#gets: Increments the line number.
15688 * - IO#readline: Increments the line number.
15689 * - IO#readlines: Increments the line number for each line read.
15690 *
15691 * A new stream is initially has line number zero (and position zero);
15692 * method +rewind+ resets the line number (and position) to zero:
15693 *
15694 * f = File.new('t.txt')
15695 * f.lineno # => 0
15696 * f.gets # => "First line\n"
15697 * f.lineno # => 1
15698 * f.rewind
15699 * f.lineno # => 0
15700 * f.close
15701 *
15702 * Reading lines from a stream usually changes its line number:
15703 *
15704 * f = File.new('t.txt', 'r')
15705 * f.lineno # => 0
15706 * f.readline # => "This is line one.\n"
15707 * f.lineno # => 1
15708 * f.readline # => "This is the second line.\n"
15709 * f.lineno # => 2
15710 * f.readline # => "Here's the third line.\n"
15711 * f.lineno # => 3
15712 * f.eof? # => true
15713 * f.close
15714 *
15715 * Iterating over lines in a stream usually changes its line number:
15716 *
15717 * File.open('t.txt') do |f|
15718 * f.each_line do |line|
15719 * p "position=#{f.pos} eof?=#{f.eof?} lineno=#{f.lineno}"
15720 * end
15721 * end
15722 *
15723 * Output:
15724 *
15725 * "position=11 eof?=false lineno=1"
15726 * "position=23 eof?=false lineno=2"
15727 * "position=24 eof?=false lineno=3"
15728 * "position=36 eof?=false lineno=4"
15729 * "position=47 eof?=true lineno=5"
15730 *
15731 * Unlike the stream's {position}[rdoc-ref:IO@Position],
15732 * the line number does not affect where the next read or write will occur:
15733 *
15734 * f = File.new('t.txt')
15735 * f.lineno = 1000
15736 * f.lineno # => 1000
15737 * f.gets # => "First line\n"
15738 * f.lineno # => 1001
15739 * f.close
15740 *
15741 * Associated with the line number is the global variable <tt>$.</tt>:
15742 *
15743 * - When a stream is opened, <tt>$.</tt> is not set;
15744 * its value is left over from previous activity in the process:
15745 *
15746 * $. = 41
15747 * f = File.new('t.txt')
15748 * $. = 41
15749 * # => 41
15750 * f.close
15751 *
15752 * - When a stream is read, <tt>$.</tt> is set to the line number for that stream:
15753 *
15754 * f0 = File.new('t.txt')
15755 * f1 = File.new('t.dat')
15756 * f0.readlines # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
15757 * $. # => 5
15758 * f1.readlines # => ["\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"]
15759 * $. # => 1
15760 * f0.close
15761 * f1.close
15762 *
15763 * - Methods IO#rewind and IO#seek do not affect <tt>$.</tt>:
15764 *
15765 * f = File.new('t.txt')
15766 * f.readlines # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
15767 * $. # => 5
15768 * f.rewind
15769 * f.seek(0, :SET)
15770 * $. # => 5
15771 * f.close
15772 *
15773 * === Line Output
15774 *
15775 * You can write to an \IO stream line-by-line using this method:
15776 *
15777 * - IO#puts: Writes objects to the stream.
15778 *
15779 * == Character \IO
15780 *
15781 * You can process an \IO stream character-by-character using these methods:
15782 *
15783 * - IO#getc: Reads and returns the next character from the stream.
15784 * - IO#readchar: Like #getc, but raises an exception at end-of-stream.
15785 * - IO#ungetc: Pushes back ("unshifts") a character or integer onto the stream.
15786 * - IO#putc: Writes a character to the stream.
15787 * - IO#each_char: Reads each remaining character in the stream,
15788 * passing the character to the given block.
15789 *
15790 * == Byte \IO
15791 *
15792 * You can process an \IO stream byte-by-byte using these methods:
15793 *
15794 * - IO#getbyte: Returns the next 8-bit byte as an integer in range 0..255.
15795 * - IO#readbyte: Like #getbyte, but raises an exception if at end-of-stream.
15796 * - IO#ungetbyte: Pushes back ("unshifts") a byte back onto the stream.
15797 * - IO#each_byte: Reads each remaining byte in the stream,
15798 * passing the byte to the given block.
15799 *
15800 * == Codepoint \IO
15801 *
15802 * You can process an \IO stream codepoint-by-codepoint:
15803 *
15804 * - IO#each_codepoint: Reads each remaining codepoint, passing it to the given block.
15805 *
15806 * == What's Here
15807 *
15808 * First, what's elsewhere. Class \IO:
15809 *
15810 * - Inherits from {class Object}[rdoc-ref:Object@Whats+Here].
15811 * - Includes {module Enumerable}[rdoc-ref:Enumerable@Whats+Here],
15812 * which provides dozens of additional methods.
15813 *
15814 * Here, class \IO provides methods that are useful for:
15815 *
15816 * - {Creating}[rdoc-ref:IO@Creating]
15817 * - {Reading}[rdoc-ref:IO@Reading]
15818 * - {Writing}[rdoc-ref:IO@Writing]
15819 * - {Positioning}[rdoc-ref:IO@Positioning]
15820 * - {Iterating}[rdoc-ref:IO@Iterating]
15821 * - {Settings}[rdoc-ref:IO@Settings]
15822 * - {Querying}[rdoc-ref:IO@Querying]
15823 * - {Buffering}[rdoc-ref:IO@Buffering]
15824 * - {Low-Level Access}[rdoc-ref:IO@Low-Level+Access]
15825 * - {Other}[rdoc-ref:IO@Other]
15826 *
15827 * === Creating
15828 *
15829 * - ::new (aliased as ::for_fd): Creates and returns a new \IO object for the given
15830 * integer file descriptor.
15831 * - ::open: Creates a new \IO object.
15832 * - ::pipe: Creates a connected pair of reader and writer \IO objects.
15833 * - ::popen: Creates an \IO object to interact with a subprocess.
15834 * - ::select: Selects which given \IO instances are ready for reading,
15835 * writing, or have pending exceptions.
15836 *
15837 * === Reading
15838 *
15839 * - ::binread: Returns a binary string with all or a subset of bytes
15840 * from the given file.
15841 * - ::read: Returns a string with all or a subset of bytes from the given file.
15842 * - ::readlines: Returns an array of strings, which are the lines from the given file.
15843 * - #getbyte: Returns the next 8-bit byte read from +self+ as an integer.
15844 * - #getc: Returns the next character read from +self+ as a string.
15845 * - #gets: Returns the line read from +self+.
15846 * - #pread: Returns all or the next _n_ bytes read from +self+,
15847 * not updating the receiver's offset.
15848 * - #read: Returns all remaining or the next _n_ bytes read from +self+
15849 * for a given _n_.
15850 * - #read_nonblock: the next _n_ bytes read from +self+ for a given _n_,
15851 * in non-block mode.
15852 * - #readbyte: Returns the next byte read from +self+;
15853 * same as #getbyte, but raises an exception on end-of-stream.
15854 * - #readchar: Returns the next character read from +self+;
15855 * same as #getc, but raises an exception on end-of-stream.
15856 * - #readline: Returns the next line read from +self+;
15857 * same as #getline, but raises an exception of end-of-stream.
15858 * - #readlines: Returns an array of all lines read read from +self+.
15859 * - #readpartial: Returns up to the given number of bytes from +self+.
15860 *
15861 * === Writing
15862 *
15863 * - ::binwrite: Writes the given string to the file at the given filepath,
15864 * in binary mode.
15865 * - ::write: Writes the given string to +self+.
15866 * - #<<: Appends the given string to +self+.
15867 * - #print: Prints last read line or given objects to +self+.
15868 * - #printf: Writes to +self+ based on the given format string and objects.
15869 * - #putc: Writes a character to +self+.
15870 * - #puts: Writes lines to +self+, making sure line ends with a newline.
15871 * - #pwrite: Writes the given string at the given offset,
15872 * not updating the receiver's offset.
15873 * - #write: Writes one or more given strings to +self+.
15874 * - #write_nonblock: Writes one or more given strings to +self+ in non-blocking mode.
15875 *
15876 * === Positioning
15877 *
15878 * - #lineno: Returns the current line number in +self+.
15879 * - #lineno=: Sets the line number is +self+.
15880 * - #pos (aliased as #tell): Returns the current byte offset in +self+.
15881 * - #pos=: Sets the byte offset in +self+.
15882 * - #reopen: Reassociates +self+ with a new or existing \IO stream.
15883 * - #rewind: Positions +self+ to the beginning of input.
15884 * - #seek: Sets the offset for +self+ relative to given position.
15885 *
15886 * === Iterating
15887 *
15888 * - ::foreach: Yields each line of given file to the block.
15889 * - #each (aliased as #each_line): Calls the given block
15890 * with each successive line in +self+.
15891 * - #each_byte: Calls the given block with each successive byte in +self+
15892 * as an integer.
15893 * - #each_char: Calls the given block with each successive character in +self+
15894 * as a string.
15895 * - #each_codepoint: Calls the given block with each successive codepoint in +self+
15896 * as an integer.
15897 *
15898 * === Settings
15899 *
15900 * - #autoclose=: Sets whether +self+ auto-closes.
15901 * - #binmode: Sets +self+ to binary mode.
15902 * - #close: Closes +self+.
15903 * - #close_on_exec=: Sets the close-on-exec flag.
15904 * - #close_read: Closes +self+ for reading.
15905 * - #close_write: Closes +self+ for writing.
15906 * - #set_encoding: Sets the encoding for +self+.
15907 * - #set_encoding_by_bom: Sets the encoding for +self+, based on its
15908 * Unicode byte-order-mark.
15909 * - #sync=: Sets the sync-mode to the given value.
15910 *
15911 * === Querying
15912 *
15913 * - #autoclose?: Returns whether +self+ auto-closes.
15914 * - #binmode?: Returns whether +self+ is in binary mode.
15915 * - #close_on_exec?: Returns the close-on-exec flag for +self+.
15916 * - #closed?: Returns whether +self+ is closed.
15917 * - #eof? (aliased as #eof): Returns whether +self+ is at end-of-stream.
15918 * - #external_encoding: Returns the external encoding object for +self+.
15919 * - #fileno (aliased as #to_i): Returns the integer file descriptor for +self+
15920 * - #internal_encoding: Returns the internal encoding object for +self+.
15921 * - #pid: Returns the process ID of a child process associated with +self+,
15922 * if +self+ was created by ::popen.
15923 * - #stat: Returns the File::Stat object containing status information for +self+.
15924 * - #sync: Returns whether +self+ is in sync-mode.
15925 * - #tty? (aliased as #isatty): Returns whether +self+ is a terminal.
15926 *
15927 * === Buffering
15928 *
15929 * - #fdatasync: Immediately writes all buffered data in +self+ to disk.
15930 * - #flush: Flushes any buffered data within +self+ to the underlying
15931 * operating system.
15932 * - #fsync: Immediately writes all buffered data and attributes in +self+ to disk.
15933 * - #ungetbyte: Prepends buffer for +self+ with given integer byte or string.
15934 * - #ungetc: Prepends buffer for +self+ with given string.
15935 *
15936 * === Low-Level Access
15937 *
15938 * - ::sysopen: Opens the file given by its path,
15939 * returning the integer file descriptor.
15940 * - #advise: Announces the intention to access data from +self+ in a specific way.
15941 * - #fcntl: Passes a low-level command to the file specified
15942 * by the given file descriptor.
15943 * - #ioctl: Passes a low-level command to the device specified
15944 * by the given file descriptor.
15945 * - #sysread: Returns up to the next _n_ bytes read from self using a low-level read.
15946 * - #sysseek: Sets the offset for +self+.
15947 * - #syswrite: Writes the given string to +self+ using a low-level write.
15948 *
15949 * === Other
15950 *
15951 * - ::copy_stream: Copies data from a source to a destination,
15952 * each of which is a filepath or an \IO-like object.
15953 * - ::try_convert: Returns a new \IO object resulting from converting
15954 * the given object.
15955 * - #inspect: Returns the string representation of +self+.
15956 *
15957 */
15958
15959void
15960Init_IO(void)
15961{
15962 VALUE rb_cARGF;
15963#ifdef __CYGWIN__
15964#include <sys/cygwin.h>
15965 static struct __cygwin_perfile pf[] =
15966 {
15967 {"", O_RDONLY | O_BINARY},
15968 {"", O_WRONLY | O_BINARY},
15969 {"", O_RDWR | O_BINARY},
15970 {"", O_APPEND | O_BINARY},
15971 {NULL, 0}
15972 };
15973 cygwin_internal(CW_PERFILE, pf);
15974#endif
15975
15976 rb_eIOError = rb_define_class("IOError", rb_eStandardError);
15977 rb_eEOFError = rb_define_class("EOFError", rb_eIOError);
15978
15979 id_write = rb_intern_const("write");
15980 id_read = rb_intern_const("read");
15981 id_flush = rb_intern_const("flush");
15982 id_readpartial = rb_intern_const("readpartial");
15983 id_set_encoding = rb_intern_const("set_encoding");
15984 id_fileno = rb_intern_const("fileno");
15985
15986 rb_define_global_function("syscall", rb_f_syscall, -1);
15987
15988 rb_define_global_function("open", rb_f_open, -1);
15989 rb_define_global_function("printf", rb_f_printf, -1);
15990 rb_define_global_function("print", rb_f_print, -1);
15991 rb_define_global_function("putc", rb_f_putc, 1);
15992 rb_define_global_function("puts", rb_f_puts, -1);
15993 rb_define_global_function("gets", rb_f_gets, -1);
15994 rb_define_global_function("readline", rb_f_readline, -1);
15995 rb_define_global_function("select", rb_f_select, -1);
15996
15997 rb_define_global_function("readlines", rb_f_readlines, -1);
15998
15999 rb_define_global_function("`", rb_f_backquote, 1);
16000
16001 rb_define_global_function("p", rb_f_p, -1);
16002 rb_define_method(rb_mKernel, "display", rb_obj_display, -1);
16003
16004 rb_cIO = rb_define_class("IO", rb_cObject);
16006
16007 /* Can be raised by IO operations when IO#timeout= is set. */
16008 rb_eIOTimeoutError = rb_define_class_under(rb_cIO, "TimeoutError", rb_eIOError);
16009
16010 /* Readable event mask for IO#wait. */
16011 rb_define_const(rb_cIO, "READABLE", INT2NUM(RUBY_IO_READABLE));
16012 /* Writable event mask for IO#wait. */
16013 rb_define_const(rb_cIO, "WRITABLE", INT2NUM(RUBY_IO_WRITABLE));
16014 /* Priority event mask for IO#wait. */
16015 rb_define_const(rb_cIO, "PRIORITY", INT2NUM(RUBY_IO_PRIORITY));
16016
16017 /* exception to wait for reading. see IO.select. */
16018 rb_mWaitReadable = rb_define_module_under(rb_cIO, "WaitReadable");
16019 /* exception to wait for writing. see IO.select. */
16020 rb_mWaitWritable = rb_define_module_under(rb_cIO, "WaitWritable");
16021 /* exception to wait for reading by EAGAIN. see IO.select. */
16022 rb_eEAGAINWaitReadable = rb_define_class_under(rb_cIO, "EAGAINWaitReadable", rb_eEAGAIN);
16023 rb_include_module(rb_eEAGAINWaitReadable, rb_mWaitReadable);
16024 /* exception to wait for writing by EAGAIN. see IO.select. */
16025 rb_eEAGAINWaitWritable = rb_define_class_under(rb_cIO, "EAGAINWaitWritable", rb_eEAGAIN);
16026 rb_include_module(rb_eEAGAINWaitWritable, rb_mWaitWritable);
16027#if EAGAIN == EWOULDBLOCK
16028 /* same as IO::EAGAINWaitReadable */
16029 rb_define_const(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEAGAINWaitReadable);
16030 /* same as IO::EAGAINWaitWritable */
16031 rb_define_const(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEAGAINWaitWritable);
16032#else
16033 /* exception to wait for reading by EWOULDBLOCK. see IO.select. */
16034 rb_eEWOULDBLOCKWaitReadable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEWOULDBLOCK);
16035 rb_include_module(rb_eEWOULDBLOCKWaitReadable, rb_mWaitReadable);
16036 /* exception to wait for writing by EWOULDBLOCK. see IO.select. */
16037 rb_eEWOULDBLOCKWaitWritable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEWOULDBLOCK);
16038 rb_include_module(rb_eEWOULDBLOCKWaitWritable, rb_mWaitWritable);
16039#endif
16040 /* exception to wait for reading by EINPROGRESS. see IO.select. */
16041 rb_eEINPROGRESSWaitReadable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitReadable", rb_eEINPROGRESS);
16042 rb_include_module(rb_eEINPROGRESSWaitReadable, rb_mWaitReadable);
16043 /* exception to wait for writing by EINPROGRESS. see IO.select. */
16044 rb_eEINPROGRESSWaitWritable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitWritable", rb_eEINPROGRESS);
16045 rb_include_module(rb_eEINPROGRESSWaitWritable, rb_mWaitWritable);
16046
16047#if 0
16048 /* This is necessary only for forcing rdoc handle File::open */
16049 rb_define_singleton_method(rb_cFile, "open", rb_io_s_open, -1);
16050#endif
16051
16052 rb_define_alloc_func(rb_cIO, io_alloc);
16053 rb_define_singleton_method(rb_cIO, "new", rb_io_s_new, -1);
16054 rb_define_singleton_method(rb_cIO, "open", rb_io_s_open, -1);
16055 rb_define_singleton_method(rb_cIO, "sysopen", rb_io_s_sysopen, -1);
16056 rb_define_singleton_method(rb_cIO, "for_fd", rb_io_s_for_fd, -1);
16057 rb_define_singleton_method(rb_cIO, "popen", rb_io_s_popen, -1);
16058 rb_define_singleton_method(rb_cIO, "foreach", rb_io_s_foreach, -1);
16059 rb_define_singleton_method(rb_cIO, "readlines", rb_io_s_readlines, -1);
16060 rb_define_singleton_method(rb_cIO, "read", rb_io_s_read, -1);
16061 rb_define_singleton_method(rb_cIO, "binread", rb_io_s_binread, -1);
16062 rb_define_singleton_method(rb_cIO, "write", rb_io_s_write, -1);
16063 rb_define_singleton_method(rb_cIO, "binwrite", rb_io_s_binwrite, -1);
16064 rb_define_singleton_method(rb_cIO, "select", rb_f_select, -1);
16065 rb_define_singleton_method(rb_cIO, "pipe", rb_io_s_pipe, -1);
16066 rb_define_singleton_method(rb_cIO, "try_convert", rb_io_s_try_convert, 1);
16067 rb_define_singleton_method(rb_cIO, "copy_stream", rb_io_s_copy_stream, -1);
16068
16069 rb_define_method(rb_cIO, "initialize", rb_io_initialize, -1);
16070
16072 rb_define_hooked_variable("$,", &rb_output_fs, 0, rb_deprecated_str_setter);
16073
16074 rb_default_rs = rb_fstring_lit("\n"); /* avoid modifying RS_default */
16075 rb_vm_register_global_object(rb_default_rs);
16076 rb_rs = rb_default_rs;
16078 rb_define_hooked_variable("$/", &rb_rs, 0, deprecated_rs_setter);
16079 rb_gvar_ractor_local("$/"); // not local but ractor safe
16080 rb_define_hooked_variable("$-0", &rb_rs, 0, deprecated_rs_setter);
16081 rb_gvar_ractor_local("$-0"); // not local but ractor safe
16082 rb_define_hooked_variable("$\\", &rb_output_rs, 0, rb_deprecated_str_setter);
16083
16084 rb_define_virtual_variable("$_", get_LAST_READ_LINE, set_LAST_READ_LINE);
16085 rb_gvar_ractor_local("$_");
16086 rb_gvar_box_dynamic("$_");
16087
16088 rb_define_method(rb_cIO, "initialize_copy", rb_io_init_copy, 1);
16089 rb_define_method(rb_cIO, "reopen", rb_io_reopen, -1);
16090
16091 rb_define_method(rb_cIO, "print", rb_io_print, -1);
16092 rb_define_method(rb_cIO, "putc", rb_io_putc, 1);
16093 rb_define_method(rb_cIO, "puts", rb_io_puts, -1);
16094 rb_define_method(rb_cIO, "printf", rb_io_printf, -1);
16095
16096 rb_define_method(rb_cIO, "each", rb_io_each_line, -1);
16097 rb_define_method(rb_cIO, "each_line", rb_io_each_line, -1);
16098 rb_define_method(rb_cIO, "each_byte", rb_io_each_byte, 0);
16099 rb_define_method(rb_cIO, "each_char", rb_io_each_char, 0);
16100 rb_define_method(rb_cIO, "each_codepoint", rb_io_each_codepoint, 0);
16101
16102 rb_define_method(rb_cIO, "syswrite", rb_io_syswrite, 1);
16103 rb_define_method(rb_cIO, "sysread", rb_io_sysread, -1);
16104
16105 rb_define_method(rb_cIO, "pread", rb_io_pread, -1);
16106 rb_define_method(rb_cIO, "pwrite", rb_io_pwrite, 2);
16107
16108 rb_define_method(rb_cIO, "fileno", rb_io_fileno, 0);
16109 rb_define_alias(rb_cIO, "to_i", "fileno");
16110 rb_define_method(rb_cIO, "to_io", rb_io_to_io, 0);
16111
16112 rb_define_method(rb_cIO, "timeout", rb_io_timeout, 0);
16113 rb_define_method(rb_cIO, "timeout=", rb_io_set_timeout, 1);
16114
16115 rb_define_method(rb_cIO, "fsync", rb_io_fsync, 0);
16116 rb_define_method(rb_cIO, "fdatasync", rb_io_fdatasync, 0);
16117 rb_define_method(rb_cIO, "sync", rb_io_sync, 0);
16118 rb_define_method(rb_cIO, "sync=", rb_io_set_sync, 1);
16119
16120 rb_define_method(rb_cIO, "lineno", rb_io_lineno, 0);
16121 rb_define_method(rb_cIO, "lineno=", rb_io_set_lineno, 1);
16122
16123 rb_define_method(rb_cIO, "readlines", rb_io_readlines, -1);
16124
16125 rb_define_method(rb_cIO, "readpartial", io_readpartial, -1);
16126 rb_define_method(rb_cIO, "read", io_read, -1);
16127 rb_define_method(rb_cIO, "write", io_write_m, -1);
16128 rb_define_method(rb_cIO, "gets", rb_io_gets_m, -1);
16129 rb_define_method(rb_cIO, "getc", rb_io_getc, 0);
16130 rb_define_method(rb_cIO, "getbyte", rb_io_getbyte, 0);
16131 rb_define_method(rb_cIO, "readchar", rb_io_readchar, 0);
16132 rb_define_method(rb_cIO, "readbyte", rb_io_readbyte, 0);
16133 rb_define_method(rb_cIO, "ungetbyte",rb_io_ungetbyte, 1);
16134 rb_define_method(rb_cIO, "ungetc",rb_io_ungetc, 1);
16136 rb_define_method(rb_cIO, "flush", rb_io_flush, 0);
16137 rb_define_method(rb_cIO, "tell", rb_io_tell, 0);
16138 rb_define_method(rb_cIO, "seek", rb_io_seek_m, -1);
16139 /* Set I/O position from the beginning */
16140 rb_define_const(rb_cIO, "SEEK_SET", INT2FIX(SEEK_SET));
16141 /* Set I/O position from the current position */
16142 rb_define_const(rb_cIO, "SEEK_CUR", INT2FIX(SEEK_CUR));
16143 /* Set I/O position from the end */
16144 rb_define_const(rb_cIO, "SEEK_END", INT2FIX(SEEK_END));
16145#ifdef SEEK_DATA
16146 /* Set I/O position to the next location containing data */
16147 rb_define_const(rb_cIO, "SEEK_DATA", INT2FIX(SEEK_DATA));
16148#endif
16149#ifdef SEEK_HOLE
16150 /* Set I/O position to the next hole */
16151 rb_define_const(rb_cIO, "SEEK_HOLE", INT2FIX(SEEK_HOLE));
16152#endif
16153 rb_define_method(rb_cIO, "rewind", rb_io_rewind, 0);
16154 rb_define_method(rb_cIO, "pos", rb_io_tell, 0);
16155 rb_define_method(rb_cIO, "pos=", rb_io_set_pos, 1);
16156 rb_define_method(rb_cIO, "eof", rb_io_eof, 0);
16157 rb_define_method(rb_cIO, "eof?", rb_io_eof, 0);
16158
16159 rb_define_method(rb_cIO, "close_on_exec?", rb_io_close_on_exec_p, 0);
16160 rb_define_method(rb_cIO, "close_on_exec=", rb_io_set_close_on_exec, 1);
16161
16162 rb_define_method(rb_cIO, "close", rb_io_close_m, 0);
16163 rb_define_method(rb_cIO, "closed?", rb_io_closed_p, 0);
16164 rb_define_method(rb_cIO, "close_read", rb_io_close_read, 0);
16165 rb_define_method(rb_cIO, "close_write", rb_io_close_write, 0);
16166
16167 rb_define_method(rb_cIO, "isatty", rb_io_isatty, 0);
16168 rb_define_method(rb_cIO, "tty?", rb_io_isatty, 0);
16169 rb_define_method(rb_cIO, "binmode", rb_io_binmode_m, 0);
16170 rb_define_method(rb_cIO, "binmode?", rb_io_binmode_p, 0);
16171 rb_define_method(rb_cIO, "sysseek", rb_io_sysseek, -1);
16172 rb_define_method(rb_cIO, "advise", rb_io_advise, -1);
16173
16174 rb_define_method(rb_cIO, "ioctl", rb_io_ioctl, -1);
16175 rb_define_method(rb_cIO, "fcntl", rb_io_fcntl, -1);
16176 rb_define_method(rb_cIO, "pid", rb_io_pid, 0);
16177
16178 rb_define_method(rb_cIO, "path", rb_io_path, 0);
16179 rb_define_method(rb_cIO, "to_path", rb_io_path, 0);
16180
16181 rb_define_method(rb_cIO, "inspect", rb_io_inspect, 0);
16182
16183 rb_define_method(rb_cIO, "external_encoding", rb_io_external_encoding, 0);
16184 rb_define_method(rb_cIO, "internal_encoding", rb_io_internal_encoding, 0);
16185 rb_define_method(rb_cIO, "set_encoding", rb_io_set_encoding, -1);
16186 rb_define_method(rb_cIO, "set_encoding_by_bom", rb_io_set_encoding_by_bom, 0);
16187
16188 rb_define_method(rb_cIO, "autoclose?", rb_io_autoclose_p, 0);
16189 rb_define_method(rb_cIO, "autoclose=", rb_io_set_autoclose, 1);
16190
16191 rb_define_method(rb_cIO, "wait", io_wait, -1);
16192
16193 rb_define_method(rb_cIO, "wait_readable", io_wait_readable, -1);
16194 rb_define_method(rb_cIO, "wait_writable", io_wait_writable, -1);
16195 rb_define_method(rb_cIO, "wait_priority", io_wait_priority, -1);
16196
16197 rb_define_virtual_variable("$stdin", stdin_getter, stdin_setter);
16198 rb_define_virtual_variable("$stdout", stdout_getter, stdout_setter);
16199 rb_define_virtual_variable("$>", stdout_getter, stdout_setter);
16200 rb_define_virtual_variable("$stderr", stderr_getter, stderr_setter);
16201
16202 rb_gvar_ractor_local("$stdin");
16203 rb_gvar_ractor_local("$stdout");
16204 rb_gvar_ractor_local("$>");
16205 rb_gvar_ractor_local("$stderr");
16206
16207 rb_gvar_box_dynamic("$stdin");
16208 rb_gvar_box_dynamic("$stdout");
16209 rb_gvar_box_dynamic("$>");
16210 rb_gvar_box_dynamic("$stderr");
16211
16213 rb_stdin = rb_io_prep_stdin();
16215 rb_stdout = rb_io_prep_stdout();
16217 rb_stderr = rb_io_prep_stderr();
16218
16219 orig_stdout = rb_stdout;
16220 orig_stderr = rb_stderr;
16221
16222 /* Holds the original stdin */
16224 /* Holds the original stdout */
16226 /* Holds the original stderr */
16228
16229#if 0
16230 /* Hack to get rdoc to regard ARGF as a class: */
16231 rb_cARGF = rb_define_class("ARGF", rb_cObject);
16232#endif
16233
16234 rb_cARGF = rb_class_new(rb_cObject);
16235 rb_set_class_path(rb_cARGF, rb_cObject, "ARGF.class");
16236 rb_define_alloc_func(rb_cARGF, argf_alloc);
16237
16239
16240 rb_define_method(rb_cARGF, "initialize", argf_initialize, -2);
16241 rb_define_method(rb_cARGF, "initialize_copy", argf_initialize_copy, 1);
16242 rb_define_method(rb_cARGF, "to_s", argf_to_s, 0);
16243 rb_define_alias(rb_cARGF, "inspect", "to_s");
16244 rb_define_method(rb_cARGF, "argv", argf_argv, 0);
16245
16246 rb_define_method(rb_cARGF, "fileno", argf_fileno, 0);
16247 rb_define_method(rb_cARGF, "to_i", argf_fileno, 0);
16248 rb_define_method(rb_cARGF, "to_io", argf_to_io, 0);
16249 rb_define_method(rb_cARGF, "to_write_io", argf_write_io, 0);
16250 rb_define_method(rb_cARGF, "each", argf_each_line, -1);
16251 rb_define_method(rb_cARGF, "each_line", argf_each_line, -1);
16252 rb_define_method(rb_cARGF, "each_byte", argf_each_byte, 0);
16253 rb_define_method(rb_cARGF, "each_char", argf_each_char, 0);
16254 rb_define_method(rb_cARGF, "each_codepoint", argf_each_codepoint, 0);
16255
16256 rb_define_method(rb_cARGF, "read", argf_read, -1);
16257 rb_define_method(rb_cARGF, "readpartial", argf_readpartial, -1);
16258 rb_define_method(rb_cARGF, "read_nonblock", argf_read_nonblock, -1);
16259 rb_define_method(rb_cARGF, "readlines", argf_readlines, -1);
16260 rb_define_method(rb_cARGF, "to_a", argf_readlines, -1);
16261 rb_define_method(rb_cARGF, "gets", argf_gets, -1);
16262 rb_define_method(rb_cARGF, "readline", argf_readline, -1);
16263 rb_define_method(rb_cARGF, "getc", argf_getc, 0);
16264 rb_define_method(rb_cARGF, "getbyte", argf_getbyte, 0);
16265 rb_define_method(rb_cARGF, "readchar", argf_readchar, 0);
16266 rb_define_method(rb_cARGF, "readbyte", argf_readbyte, 0);
16267 rb_define_method(rb_cARGF, "tell", argf_tell, 0);
16268 rb_define_method(rb_cARGF, "seek", argf_seek_m, -1);
16269 rb_define_method(rb_cARGF, "rewind", argf_rewind, 0);
16270 rb_define_method(rb_cARGF, "pos", argf_tell, 0);
16271 rb_define_method(rb_cARGF, "pos=", argf_set_pos, 1);
16272 rb_define_method(rb_cARGF, "eof", argf_eof, 0);
16273 rb_define_method(rb_cARGF, "eof?", argf_eof, 0);
16274 rb_define_method(rb_cARGF, "binmode", argf_binmode_m, 0);
16275 rb_define_method(rb_cARGF, "binmode?", argf_binmode_p, 0);
16276
16277 rb_define_method(rb_cARGF, "write", argf_write, -1);
16278 rb_define_method(rb_cARGF, "print", rb_io_print, -1);
16279 rb_define_method(rb_cARGF, "putc", rb_io_putc, 1);
16280 rb_define_method(rb_cARGF, "puts", rb_io_puts, -1);
16281 rb_define_method(rb_cARGF, "printf", rb_io_printf, -1);
16282
16283 rb_define_method(rb_cARGF, "filename", argf_filename, 0);
16284 rb_define_method(rb_cARGF, "path", argf_filename, 0);
16285 rb_define_method(rb_cARGF, "file", argf_file, 0);
16286 rb_define_method(rb_cARGF, "skip", argf_skip, 0);
16287 rb_define_method(rb_cARGF, "close", argf_close_m, 0);
16288 rb_define_method(rb_cARGF, "closed?", argf_closed, 0);
16289
16290 rb_define_method(rb_cARGF, "lineno", argf_lineno, 0);
16291 rb_define_method(rb_cARGF, "lineno=", argf_set_lineno, 1);
16292
16293 rb_define_method(rb_cARGF, "inplace_mode", argf_inplace_mode_get, 0);
16294 rb_define_method(rb_cARGF, "inplace_mode=", argf_inplace_mode_set, 1);
16295
16296 rb_define_method(rb_cARGF, "external_encoding", argf_external_encoding, 0);
16297 rb_define_method(rb_cARGF, "internal_encoding", argf_internal_encoding, 0);
16298 rb_define_method(rb_cARGF, "set_encoding", argf_set_encoding, -1);
16299
16300 argf = rb_class_new_instance(0, 0, rb_cARGF);
16301
16303 /*
16304 * ARGF is a stream designed for use in scripts that process files given
16305 * as command-line arguments or passed in via STDIN.
16306 *
16307 * See ARGF (the class) for more details.
16308 */
16310
16311 rb_define_hooked_variable("$.", &argf, argf_lineno_getter, argf_lineno_setter);
16312 rb_define_hooked_variable("$FILENAME", &argf, argf_filename_getter, rb_gvar_readonly_setter);
16313 ARGF_SET(filename, rb_str_new2("-"));
16314
16315 rb_define_hooked_variable("$-i", &argf, opt_i_get, opt_i_set);
16316 rb_gvar_ractor_local("$-i");
16317
16318 rb_define_hooked_variable("$*", &argf, argf_argv_getter, rb_gvar_readonly_setter);
16319
16320#if defined (_WIN32) || defined(__CYGWIN__)
16321 atexit(pipe_atexit);
16322#endif
16323
16324 Init_File();
16325
16326 rb_define_method(rb_cFile, "initialize", rb_file_initialize, -1);
16327
16328 sym_mode = ID2SYM(rb_intern_const("mode"));
16329 sym_perm = ID2SYM(rb_intern_const("perm"));
16330 sym_flags = ID2SYM(rb_intern_const("flags"));
16331 sym_extenc = ID2SYM(rb_intern_const("external_encoding"));
16332 sym_intenc = ID2SYM(rb_intern_const("internal_encoding"));
16333 sym_encoding = ID2SYM(rb_id_encoding());
16334 sym_open_args = ID2SYM(rb_intern_const("open_args"));
16335 sym_textmode = ID2SYM(rb_intern_const("textmode"));
16336 sym_binmode = ID2SYM(rb_intern_const("binmode"));
16337 sym_autoclose = ID2SYM(rb_intern_const("autoclose"));
16338 sym_normal = ID2SYM(rb_intern_const("normal"));
16339 sym_sequential = ID2SYM(rb_intern_const("sequential"));
16340 sym_random = ID2SYM(rb_intern_const("random"));
16341 sym_willneed = ID2SYM(rb_intern_const("willneed"));
16342 sym_dontneed = ID2SYM(rb_intern_const("dontneed"));
16343 sym_noreuse = ID2SYM(rb_intern_const("noreuse"));
16344 sym_SET = ID2SYM(rb_intern_const("SET"));
16345 sym_CUR = ID2SYM(rb_intern_const("CUR"));
16346 sym_END = ID2SYM(rb_intern_const("END"));
16347#ifdef SEEK_DATA
16348 sym_DATA = ID2SYM(rb_intern_const("DATA"));
16349#endif
16350#ifdef SEEK_HOLE
16351 sym_HOLE = ID2SYM(rb_intern_const("HOLE"));
16352#endif
16353 sym_wait_readable = ID2SYM(rb_intern_const("wait_readable"));
16354 sym_wait_writable = ID2SYM(rb_intern_const("wait_writable"));
16355}
16356
16357static void init_builtin_io(void);
16358#define Init_builtin_io init_builtin_io
16359#include "io.rbinc"
16360#undef Init_builtin_io
16361
16362void
16363Init_builtin_io(void)
16364{
16365 init_builtin_io();
16366
16367 /* Init_IO is called earlier than `loaded_features` is initialized */
16368 rb_provide("io/wait.rb");
16369 rb_provide("io/wait.so");
16370}
#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:1676
#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:1684
#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:1678
#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:15028
VALUE rb_eIOError
IOError exception.
Definition io.c:193
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:192
void rb_readwrite_sys_fail(enum rb_io_wait_readwrite waiting, const char *mesg)
Raises appropriate exception using the parameters.
Definition io.c:15022
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:191
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:207
VALUE rb_stderr
STDERR constant.
Definition io.c:207
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:195
VALUE rb_mWaitWritable
IO::WaitReadable module.
Definition io.c:196
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:176
VALUE rb_stdout
STDOUT constant.
Definition io.c:207
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:8908
VALUE rb_io_gets(VALUE io)
Reads a "line" from the given IO.
Definition io.c:4597
int rb_cloexec_pipe(int fildes[2])
Opens a pipe with closing on exec.
Definition io.c:515
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:9041
VALUE rb_io_addstr(VALUE io, VALUE str)
Identical to rb_io_write(), except it always returns the passed IO.
Definition io.c:2477
void rb_write_error(const char *str)
Writes the given error message to somewhere applicable.
Definition io.c:9470
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:5469
VALUE rb_io_getbyte(VALUE io)
Reads a byte from the given IO.
Definition io.c:5374
int rb_cloexec_dup2(int oldfd, int newfd)
Identical to rb_cloexec_dup(), except you can specify the destination file descriptor.
Definition io.c:413
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:9651
void rb_update_max_fd(int fd)
Informs the interpreter that the passed fd can be the max.
Definition io.c:287
int rb_cloexec_open(const char *pathname, int flags, mode_t mode)
Opens a file that closes on exec.
Definition io.c:367
VALUE rb_output_rs
The record separator character for outputs, or the $\.
Definition io.c:212
VALUE rb_io_eof(VALUE io)
Queries if the passed IO is at the end of file.
Definition io.c:2819
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:9450
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:337
VALUE rb_io_ascii8bit_binmode(VALUE io)
Forces no conversions be applied to the passed IO.
Definition io.c:6712
VALUE rb_io_binmode(VALUE io)
Sets the binmode.
Definition io.c:6666
VALUE rb_io_ungetc(VALUE io, VALUE c)
"Unget"s a string.
Definition io.c:5533
int rb_pipe(int *pipes)
This is an rb_cloexec_pipe() + rb_update_max_fd() combo.
Definition io.c:7709
VALUE rb_gets(void)
Much like rb_io_gets(), but it reads from the mysterious ARGF object.
Definition io.c:10739
int rb_cloexec_fcntl_dupfd(int fd, int minfd)
Duplicates a file descriptor with closing on exec.
Definition io.c:521
VALUE rb_output_fs
The field separator character for outputs, or the $,.
Definition io.c:210
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:7597
int rb_cloexec_dup(int oldfd)
Identical to rb_cloexec_fcntl_dupfd(), except it implies minfd is 3.
Definition io.c:406
VALUE rb_file_open(const char *fname, const char *fmode)
Opens a file located at the given path.
Definition io.c:7604
VALUE rb_io_close(VALUE io)
Closes the IO.
Definition io.c:6069
VALUE rb_default_rs
This is the default value of rb_rs, i.e.
Definition io.c:213
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:3906
#define rb_str_new(str, len)
Allocates an instance of rb_cString.
Definition string.h:1499
#define rb_str_buf_cat
Just another name of rb_str_cat.
Definition string.h:1682
#define rb_usascii_str_new(str, len)
Identical to rb_str_new, except it generates a string of "US ASCII" encoding.
Definition string.h:1533
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:2031
VALUE rb_str_cat(VALUE dst, const char *src, long srclen)
Destructively appends the passed contents to the string.
Definition string.c:3674
VALUE rb_str_locktmp(VALUE str)
Obtains a "temporary lock" of the string.
VALUE rb_str_equal(VALUE str1, VALUE str2)
Equality of two strings.
Definition string.c:4376
void rb_str_set_len(VALUE str, long len)
Overwrites the length of the string.
Definition string.c:3493
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:3848
VALUE rb_check_string_type(VALUE obj)
Try converting an object to its stringised representation using its to_str method,...
Definition string.c:3040
VALUE rb_str_substr(VALUE str, long beg, long len)
This is the implementation of two-argumented String#slice.
Definition string.c:3356
VALUE rb_str_unlocktmp(VALUE str)
Releases a lock formerly obtained by rb_str_locktmp().
Definition string.c:3475
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:2809
VALUE rb_str_buf_new(long capa)
Allocates a "string buffer".
Definition string.c:1763
#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:1515
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:1895
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:1723
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:1717
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:3683
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:3561
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:6798
VALUE rb_io_get_io(VALUE io)
Identical to rb_io_check_io(), except it raises exceptions on conversion failures.
Definition io.c:873
VALUE rb_io_timeout(VALUE io)
Get the timeout associated with the specified io object.
Definition io.c:919
VALUE rb_io_taint_check(VALUE obj)
Definition io.c:843
void rb_io_read_check(rb_io_t *fptr)
Blocks until there is a pending read in the passed IO.
Definition io.c:1157
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:6931
#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:1103
#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:1112
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:1709
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:7414
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:7080
int rb_io_descriptor(VALUE io)
Returns an integer representing the numeric file descriptor for io.
Definition io.c:3018
#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:9697
#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:1770
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:1729
VALUE rb_eIOTimeoutError
Indicates that a timeout has occurred while performing an IO operation.
Definition io.c:194
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:3097
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:7205
void rb_io_check_initialized(rb_io_t *fptr)
Asserts that the passed IO is initialised.
Definition io.c:850
#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:5980
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:879
VALUE rb_io_closed_p(VALUE io)
Returns whether or not the underlying IO is closed.
Definition io.c:6177
VALUE rb_io_set_timeout(VALUE io, VALUE timeout)
Set the timeout associated with the specified io object.
Definition io.c:948
ssize_t rb_io_bufwrite(VALUE io, const void *buf, size_t size)
Buffered write to the passed IO.
Definition io.c:2134
void rb_io_check_char_readable(rb_io_t *fptr)
Asserts that an IO is opened for character-based reading.
Definition io.c:1084
#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:885
void rb_io_set_nonblock(rb_io_t *fptr)
Instructs the OS to put its internal file structure into "nonblocking mode".
Definition io.c:3584
int rb_io_wait_writable(int fd)
Blocks until the passed file descriptor gets writable.
Definition io.c:1665
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:9563
VALUE rb_io_set_write_io(VALUE io, VALUE w)
Assigns the tied IO for writing.
Definition io.c:896
void rb_io_check_writable(rb_io_t *fptr)
Asserts that an IO is opened for writing.
Definition io.c:1136
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:1785
void rb_io_check_closed(rb_io_t *fptr)
This badly named function asserts that the passed IO is open.
Definition io.c:858
int rb_io_wait_readable(int fd)
Blocks until the passed file descriptor gets readable.
Definition io.c:1630
void rb_io_synchronized(rb_io_t *fptr)
Sets FMODE_SYNC.
Definition io.c:7701
VALUE rb_io_wait(VALUE io, VALUE events, VALUE timeout)
Blocks until the passed IO is ready for the passed events.
Definition io.c:1570
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:1428
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:1497
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:1485
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:1473
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:14988
void rb_p(VALUE obj)
Inspects an object.
Definition io.c:9349
#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:242
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.