Ruby 4.1.0dev (2026-09-30 revision 5c128f545b7d16f3fc8405b811fc5a04dcd73d8f)
io.c (5c128f545b7d16f3fc8405b811fc5a04dcd73d8f)
1/**********************************************************************
2
3 io.c -
4
5 $Author$
6 created at: Fri Oct 15 18:08:59 JST 1993
7
8 Copyright (C) 1993-2007 Yukihiro Matsumoto
9 Copyright (C) 2000 Network Applied Communication Laboratory, Inc.
10 Copyright (C) 2000 Information-technology Promotion Agency, Japan
11
12**********************************************************************/
13
14#include "ruby/internal/config.h"
15
17#include "ruby/io/buffer.h"
18
19#include <ctype.h>
20#include <errno.h>
21#include <stddef.h>
22
23/* non-Linux poll may not work on all FDs */
24#if defined(HAVE_POLL)
25# if defined(__linux__)
26# define USE_POLL 1
27# endif
28# if defined(__FreeBSD_version) && __FreeBSD_version >= 1100000
29# define USE_POLL 1
30# endif
31#endif
32
33#ifndef USE_POLL
34# define USE_POLL 0
35#endif
36
37#undef free
38#define free(x) xfree(x)
39
40#ifdef __CYGWIN__
41#include <io.h>
42#endif
43
44#include <sys/types.h>
45#if defined HAVE_NET_SOCKET_H
46# include <net/socket.h>
47#elif defined HAVE_SYS_SOCKET_H
48# include <sys/socket.h>
49#endif
50
51#if defined(__CYGWIN__) || defined(_WIN32)
52# define NO_SAFE_RENAME
53#endif
54
55#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__sun) || defined(_nec_ews)
56# define USE_SETVBUF
57#endif
58
59#include <sys/types.h>
60#ifdef HAVE_SYS_IOCTL_H
61#include <sys/ioctl.h>
62#endif
63#if defined(HAVE_FCNTL_H)
64#include <fcntl.h>
65#elif defined(HAVE_SYS_FCNTL_H)
66#include <sys/fcntl.h>
67#endif
68
69#ifdef HAVE_SYS_TIME_H
70# include <sys/time.h>
71#endif
72
73#include <sys/stat.h>
74
75#if defined(HAVE_SYS_PARAM_H)
76# include <sys/param.h>
77#endif
78
79#if !defined NOFILE
80# define NOFILE 64
81#endif
82
83#ifdef HAVE_UNISTD_H
84#include <unistd.h>
85#endif
86
87#ifdef HAVE_SYSCALL_H
88#include <syscall.h>
89#elif defined HAVE_SYS_SYSCALL_H
90#include <sys/syscall.h>
91#endif
92
93#ifdef HAVE_SYS_UIO_H
94#include <sys/uio.h>
95#endif
96
97#ifdef HAVE_SYS_WAIT_H
98# include <sys/wait.h> /* for WNOHANG on BSD */
99#endif
100
101#ifdef HAVE_COPYFILE_H
102# include <copyfile.h>
103
104# ifndef COPYFILE_STATE_COPIED
105/*
106 * Some OSes (e.g., OSX < 10.6) implement fcopyfile() but not
107 * COPYFILE_STATE_COPIED. Since the only use of the former here
108 * requires the latter, we disable the former when the latter is undefined.
109 */
110# undef HAVE_FCOPYFILE
111# endif
112
113#endif
114
115#if defined __APPLE__
116# include <AvailabilityMacros.h>
117#endif
118
120#include "ccan/list/list.h"
121#include "dln.h"
122#include "encindex.h"
123#include "id.h"
124#include "internal.h"
125#include "internal/class.h"
126#include "internal/encoding.h"
127#include "internal/error.h"
128#include "internal/inits.h"
129#include "internal/io.h"
130#include "internal/numeric.h"
131#include "internal/object.h"
132#include "internal/process.h"
133#include "internal/thread.h"
134#include "internal/transcode.h"
135#include "internal/variable.h"
136#include "ruby/io.h"
137#include "ruby/io/buffer.h"
138#include "ruby/missing.h"
139#include "ruby/thread.h"
140#include "ruby/util.h"
141#include "ruby_atomic.h"
142#include "ruby/ractor.h"
143
144#if !USE_POLL
145# include "vm_core.h"
146#endif
147
148#include "builtin.h"
149
150#ifndef O_ACCMODE
151#define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR)
152#endif
153
154#ifndef PIPE_BUF
155# ifdef _POSIX_PIPE_BUF
156# define PIPE_BUF _POSIX_PIPE_BUF
157# else
158# define PIPE_BUF 512 /* is this ok? */
159# endif
160#endif
161
162#ifndef EWOULDBLOCK
163# define EWOULDBLOCK EAGAIN
164#endif
165
166#if defined(HAVE___SYSCALL) && (defined(__APPLE__) || defined(__OpenBSD__))
167/* Mac OS X and OpenBSD have __syscall but don't define it in headers */
168off_t __syscall(quad_t number, ...);
169#endif
170
171#define IO_RBUF_CAPA_MIN 8192
172#define IO_CBUF_CAPA_MIN (128*1024)
173#define IO_RBUF_CAPA_FOR(fptr) (NEED_READCONV(fptr) ? IO_CBUF_CAPA_MIN : IO_RBUF_CAPA_MIN)
174#define IO_WBUF_CAPA_MIN 8192
175
176#define IO_MAX_BUFFER_GROWTH 8 * 1024 * 1024 // 8MB
177
178/* define system APIs */
179#ifdef _WIN32
180#undef open
181#define open rb_w32_uopen
182#undef rename
183#define rename(f, t) rb_w32_urename((f), (t))
184#include "win32/file.h"
185#endif
186
193
194static VALUE rb_eEAGAINWaitReadable;
195static VALUE rb_eEAGAINWaitWritable;
196#if EAGAIN != EWOULDBLOCK
197static VALUE rb_eEWOULDBLOCKWaitReadable;
198static VALUE rb_eEWOULDBLOCKWaitWritable;
199#endif
200static VALUE rb_eEINPROGRESSWaitWritable;
201static VALUE rb_eEINPROGRESSWaitReadable;
202
204static VALUE orig_stdout, orig_stderr;
205
207VALUE rb_rs;
210
211static VALUE argf;
212
213static ID id_write, id_read, id_flush, id_readpartial, id_set_encoding, id_fileno;
214static VALUE sym_mode, sym_perm, sym_flags, sym_extenc, sym_intenc, sym_encoding, sym_open_args;
215static VALUE sym_textmode, sym_binmode, sym_autoclose;
216static VALUE sym_SET, sym_CUR, sym_END;
217static VALUE sym_wait_readable, sym_wait_writable;
218#ifdef SEEK_DATA
219static VALUE sym_DATA;
220#endif
221#ifdef SEEK_HOLE
222static VALUE sym_HOLE;
223#endif
224
225static VALUE prep_io(int fd, enum rb_io_mode fmode, VALUE klass, const char *path);
226
227VALUE
228rb_io_blocking_region_wait(struct rb_io *io, rb_blocking_function_t *function, void *argument, enum rb_io_event events)
229{
230 return rb_thread_io_blocking_call(io, function, argument, events);
231}
232
233VALUE rb_io_blocking_region(struct rb_io *io, rb_blocking_function_t *function, void *argument)
234{
235 return rb_io_blocking_region_wait(io, function, argument, 0);
236}
237
238struct argf {
239 VALUE filename, current_file;
240 long last_lineno; /* $. */
241 long lineno;
242 VALUE argv;
243 VALUE inplace;
244 struct rb_io_encoding encs;
245 int8_t init_p, next_p, binmode;
246};
247
248
249#if defined(__APPLE__) && \
250 (!defined(MAC_OS_VERSION_27_0) || (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_VERSION_27_0))
251
252# if __has_attribute(availability) && __has_warning("-Wunguarded-availability-new")
253
255RBIMPL_WARNING_IGNORED(-Wunguarded-availability-new)
256
257# ifdef HAVE_DUP3
258static inline int (*rb_dup3(void))(int, int, int) {return &dup3;}
259# define dup3 rb_dup3()
260# endif
261
262# ifdef HAVE_PIPE2
263static inline int (*rb_pipe2(void))(int [2], int) {return &pipe2;}
264# define pipe2 rb_pipe2()
265# endif
266
268
269# else /* __API_AVAILABLE macro does nothing on gcc */
270
271# ifdef HAVE_DUP3
272__attribute__((weak)) int dup3(int, int, int);
273# endif
274# ifdef HAVE_PIPE2
275__attribute__((weak)) int pipe2(int [2], int);
276# endif
277
278# endif
279#endif /* __APPLE__ && < MAC_OS_X_VERSION_27_0 */
280
281static rb_atomic_t max_file_descriptor = NOFILE;
282void
284{
285 rb_atomic_t afd = (rb_atomic_t)fd;
286 rb_atomic_t max_fd = max_file_descriptor;
287 int err;
288
289 if (fd < 0 || afd <= max_fd)
290 return;
291
292#if defined(HAVE_FCNTL) && defined(F_GETFL)
293 err = fcntl(fd, F_GETFL) == -1;
294#else
295 {
296 struct stat buf;
297 err = fstat(fd, &buf) != 0;
298 }
299#endif
300 if (err && errno == EBADF) {
301 rb_bug("rb_update_max_fd: invalid fd (%d) given.", fd);
302 }
303
304 while (max_fd < afd) {
305 max_fd = ATOMIC_CAS(max_file_descriptor, max_fd, afd);
306 }
307}
308
309void
310rb_maygvl_fd_fix_cloexec(int fd)
311{
312 /* MinGW don't have F_GETFD and FD_CLOEXEC. [ruby-core:40281] */
313#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
314 int flags, flags2, ret;
315 flags = fcntl(fd, F_GETFD); /* should not fail except EBADF. */
316 if (flags == -1) {
317 rb_bug("rb_maygvl_fd_fix_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(errno));
318 }
319 if (fd <= 2)
320 flags2 = flags & ~FD_CLOEXEC; /* Clear CLOEXEC for standard file descriptors: 0, 1, 2. */
321 else
322 flags2 = flags | FD_CLOEXEC; /* Set CLOEXEC for non-standard file descriptors: 3, 4, 5, ... */
323 if (flags != flags2) {
324 ret = fcntl(fd, F_SETFD, flags2);
325 if (ret != 0) {
326 rb_bug("rb_maygvl_fd_fix_cloexec: fcntl(%d, F_SETFD, %d) failed: %s", fd, flags2, strerror(errno));
327 }
328 }
329#endif
330}
331
332void
334{
335 rb_maygvl_fd_fix_cloexec(fd);
337}
338
339/* this is only called once */
340static int
341rb_fix_detect_o_cloexec(int fd)
342{
343#if defined(O_CLOEXEC) && defined(F_GETFD)
344 int flags = fcntl(fd, F_GETFD);
345
346 if (flags == -1)
347 rb_bug("rb_fix_detect_o_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(errno));
348
349 if (flags & FD_CLOEXEC)
350 return 1;
351#endif /* fall through if O_CLOEXEC does not work: */
352 rb_maygvl_fd_fix_cloexec(fd);
353 return 0;
354}
355
356static inline bool
357io_again_p(int e)
358{
359 return (e == EWOULDBLOCK) || (e == EAGAIN);
360}
361
362int
363rb_cloexec_open(const char *pathname, int flags, mode_t mode)
364{
365 int ret;
366 static int o_cloexec_state = -1; /* <0: unknown, 0: ignored, >0: working */
367
368 static const int retry_interval = 0;
369 static const int retry_max_count = 10000;
370
371 int retry_count = 0;
372
373#ifdef O_CLOEXEC
374 /* O_CLOEXEC is available since Linux 2.6.23. Linux 2.6.18 silently ignore it. */
375 flags |= O_CLOEXEC;
376#elif defined O_NOINHERIT
377 flags |= O_NOINHERIT;
378#endif
379
380 while ((ret = open(pathname, flags, mode)) == -1) {
381 int e = errno;
382 if (!io_again_p(e)) break;
383 if (retry_count++ >= retry_max_count) break;
384
385 sleep(retry_interval);
386 }
387
388 if (ret < 0) return ret;
389 if (ret <= 2 || o_cloexec_state == 0) {
390 rb_maygvl_fd_fix_cloexec(ret);
391 }
392 else if (o_cloexec_state > 0) {
393 return ret;
394 }
395 else {
396 o_cloexec_state = rb_fix_detect_o_cloexec(ret);
397 }
398 return ret;
399}
400
401int
403{
404 /* Don't allocate standard file descriptors: 0, 1, 2 */
405 return rb_cloexec_fcntl_dupfd(oldfd, 3);
406}
407
408int
409rb_cloexec_dup2(int oldfd, int newfd)
410{
411 int ret;
412
413 /* When oldfd == newfd, dup2 succeeds but dup3 fails with EINVAL.
414 * rb_cloexec_dup2 succeeds as dup2. */
415 if (oldfd == newfd) {
416 ret = newfd;
417 }
418 else {
419#if defined(HAVE_DUP3) && defined(O_CLOEXEC)
420# if defined(__APPLE__)
421# define try_dup3 (dup3 != NULL)
422# define abandon_dup3() true
423# else
424 static bool try_dup3 = true;
425# define abandon_dup3() (errno != ENOSYS || !!(try_dup3 = false))
426# endif
427 if (newfd <= 2) {
428 /* pass stdin, stdout and stderr to children */
429 }
430 else if (try_dup3) {
431 ret = dup3(oldfd, newfd, O_CLOEXEC);
432 /* dup3 is available since:
433 * - Linux 2.6.27, glibc 2.9
434 * - macOS 27.0
435 */
436 if (ret != -1)
437 return ret;
438 if (abandon_dup3()) return ret;
439 }
440#endif
441 ret = dup2(oldfd, newfd);
442 if (ret < 0) return ret;
443 }
444 rb_maygvl_fd_fix_cloexec(ret);
445 return ret;
446}
447
448static int
449rb_fd_set_nonblock(int fd)
450{
451#ifdef _WIN32
452 return rb_w32_set_nonblock(fd);
453#elif defined(F_GETFL)
454 int oflags = fcntl(fd, F_GETFL);
455
456 if (oflags == -1)
457 return -1;
458 if (oflags & O_NONBLOCK)
459 return 0;
460 oflags |= O_NONBLOCK;
461 return fcntl(fd, F_SETFL, oflags);
462#endif
463 return 0;
464}
465
466static inline int
467cloexec_pipe(int descriptors[2], int flags, bool force_cloexec)
468{
469 int result = -1;
470#ifdef HAVE_PIPE2
471# if defined(__APPLE__)
472# define try_pipe2 (pipe2 != NULL)
473# define abandon_pipe2() true
474# else
475 static bool try_pipe2 = true;
476# define abandon_pipe2() (errno != ENOSYS || !!(try_pipe2 = false))
477# endif
478 if (try_pipe2) {
479 result = pipe2(descriptors, O_CLOEXEC | flags);
480 if (result == 0) return result;
481 if (abandon_pipe2()) return result;
482 }
483#endif
484 if (result < 0 && (result = pipe(descriptors)) < 0)
485 return result;
486
487#ifdef __CYGWIN__
488 if (result == 0 && descriptors[1] == -1) {
489 close(descriptors[0]);
490 descriptors[0] = -1;
491 errno = ENFILE;
492 return -1;
493 }
494#endif
495
496 if (!force_cloexec) return result;
497
498 /* no pipe2 or fallenback to dup */
499 rb_maygvl_fd_fix_cloexec(descriptors[0]);
500 rb_maygvl_fd_fix_cloexec(descriptors[1]);
501
502#ifndef _WIN32
503 rb_fd_set_nonblock(descriptors[0]);
504 rb_fd_set_nonblock(descriptors[1]);
505#endif
506
507 return result;
508}
509
510int
511rb_cloexec_pipe(int descriptors[2])
512{
513 return cloexec_pipe(descriptors, O_NONBLOCK, true);
514}
515
516int
517rb_cloexec_fcntl_dupfd(int fd, int minfd)
518{
519 int ret;
520
521#if defined(HAVE_FCNTL) && defined(F_DUPFD_CLOEXEC) && defined(F_DUPFD)
522 static int try_dupfd_cloexec = 1;
523 if (try_dupfd_cloexec) {
524 ret = fcntl(fd, F_DUPFD_CLOEXEC, minfd);
525 if (ret != -1) {
526 if (ret <= 2)
527 rb_maygvl_fd_fix_cloexec(ret);
528 return ret;
529 }
530 /* F_DUPFD_CLOEXEC is available since Linux 2.6.24. Linux 2.6.18 fails with EINVAL */
531 if (errno == EINVAL) {
532 ret = fcntl(fd, F_DUPFD, minfd);
533 if (ret != -1) {
534 try_dupfd_cloexec = 0;
535 }
536 }
537 }
538 else {
539 ret = fcntl(fd, F_DUPFD, minfd);
540 }
541#elif defined(HAVE_FCNTL) && defined(F_DUPFD)
542 ret = fcntl(fd, F_DUPFD, minfd);
543#else
544 ret = dup(fd);
545 if (ret >= 0 && ret < minfd) {
546 const int prev_fd = ret;
547 ret = rb_cloexec_fcntl_dupfd(fd, minfd);
548 close(prev_fd);
549 }
550 return ret;
551#endif
552 if (ret < 0) return ret;
553 rb_maygvl_fd_fix_cloexec(ret);
554 return ret;
555}
556
557#define argf_of(obj) (*(struct argf *)DATA_PTR(obj))
558#define ARGF argf_of(argf)
559#define ARGF_SET(field, value) RB_OBJ_WRITE(argf, &ARGF.field, value)
560
561#define GetWriteIO(io) rb_io_get_write_io(io)
562
563#define READ_DATA_PENDING(fptr) ((fptr)->rbuf.len)
564#define READ_DATA_PENDING_COUNT(fptr) ((fptr)->rbuf.len)
565#define READ_DATA_PENDING_PTR(fptr) ((fptr)->rbuf.ptr+(fptr)->rbuf.off)
566#define READ_DATA_BUFFERED(fptr) READ_DATA_PENDING(fptr)
567
568#define READ_CHAR_PENDING(fptr) ((fptr)->cbuf.len)
569#define READ_CHAR_PENDING_COUNT(fptr) ((fptr)->cbuf.len)
570#define READ_CHAR_PENDING_PTR(fptr) ((fptr)->cbuf.ptr+(fptr)->cbuf.off)
571
572#if defined(_WIN32)
573#define WAIT_FD_IN_WIN32(fptr) \
574 (rb_w32_io_cancelable_p((fptr)->fd) ? Qnil : rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), RUBY_IO_TIMEOUT_DEFAULT))
575#else
576#define WAIT_FD_IN_WIN32(fptr)
577#endif
578
579#define READ_CHECK(fptr) do {\
580 if (!READ_DATA_PENDING(fptr)) {\
581 WAIT_FD_IN_WIN32(fptr);\
582 rb_io_check_closed(fptr);\
583 }\
584} while(0)
585
586#ifndef S_ISSOCK
587# ifdef _S_ISSOCK
588# define S_ISSOCK(m) _S_ISSOCK(m)
589# else
590# ifdef _S_IFSOCK
591# define S_ISSOCK(m) (((m) & S_IFMT) == _S_IFSOCK)
592# else
593# ifdef S_IFSOCK
594# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
595# endif
596# endif
597# endif
598#endif
599
600static int io_fflush(rb_io_t *);
601static rb_io_t *flush_before_seek(rb_io_t *fptr, bool discard_rbuf);
602static void clear_readconv(rb_io_t *fptr);
603static void clear_codeconv(rb_io_t *fptr);
604
605#define FMODE_SIGNAL_ON_EPIPE (1<<17)
606
607#define fptr_signal_on_epipe(fptr) \
608 (((fptr)->mode & FMODE_SIGNAL_ON_EPIPE) != 0)
609
610#define fptr_set_signal_on_epipe(fptr, flag) \
611 ((flag) ? \
612 (fptr)->mode |= FMODE_SIGNAL_ON_EPIPE : \
613 (fptr)->mode &= ~FMODE_SIGNAL_ON_EPIPE)
614
615extern ID ruby_static_id_signo;
616
617NORETURN(static void rb_sys_fail_on_write(rb_io_t *fptr));
618static void
619rb_sys_fail_on_write(rb_io_t *fptr)
620{
621 int e = errno;
622 VALUE errinfo = rb_syserr_new_path(e, (fptr)->pathv);
623#if defined EPIPE
624 if (fptr_signal_on_epipe(fptr) && (e == EPIPE)) {
625 const VALUE sig =
626# if defined SIGPIPE
627 INT2FIX(SIGPIPE) - INT2FIX(0) +
628# endif
629 INT2FIX(0);
630 rb_ivar_set(errinfo, ruby_static_id_signo, sig);
631 }
632#endif
633 rb_exc_raise(errinfo);
634}
635
636#define NEED_NEWLINE_DECORATOR_ON_READ(fptr) ((fptr)->mode & FMODE_TEXTMODE)
637#define NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) ((fptr)->mode & FMODE_TEXTMODE)
638#if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)
639# define RUBY_CRLF_ENVIRONMENT 1
640#else
641# define RUBY_CRLF_ENVIRONMENT 0
642#endif
643
644#if RUBY_CRLF_ENVIRONMENT
645/* Windows */
646# define DEFAULT_TEXTMODE FMODE_TEXTMODE
647# define TEXTMODE_NEWLINE_DECORATOR_ON_WRITE ECONV_CRLF_NEWLINE_DECORATOR
648/*
649 * CRLF newline is set as default newline decorator.
650 * If only CRLF newline conversion is needed, we use binary IO process
651 * with OS's text mode for IO performance improvement.
652 * If encoding conversion is needed or a user sets text mode, we use encoding
653 * conversion IO process and universal newline decorator by default.
654 */
655#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || (fptr)->encs.ecflags & ~ECONV_CRLF_NEWLINE_DECORATOR)
656#define WRITECONV_MASK ( \
657 (ECONV_DECORATOR_MASK & ~ECONV_CRLF_NEWLINE_DECORATOR)|\
658 ECONV_STATEFUL_DECORATOR_MASK|\
659 0)
660#define NEED_WRITECONV(fptr) ( \
661 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
662 ((fptr)->encs.ecflags & WRITECONV_MASK) || \
663 0)
664#define SET_BINARY_MODE(fptr) setmode((fptr)->fd, O_BINARY)
665
666#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) do {\
667 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {\
668 if (((fptr)->mode & FMODE_READABLE) &&\
669 !((fptr)->encs.ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {\
670 setmode((fptr)->fd, O_BINARY);\
671 }\
672 else {\
673 setmode((fptr)->fd, O_TEXT);\
674 }\
675 }\
676} while(0)
677
678#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) do {\
679 if ((enc2) && ((ecflags) & ECONV_DEFAULT_NEWLINE_DECORATOR)) {\
680 (ecflags) |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;\
681 }\
682} while(0)
683
684/*
685 * IO unread with taking care of removed '\r' in text mode.
686 */
687static void
688io_unread(rb_io_t *fptr, bool discard_rbuf)
689{
690 rb_off_t r, pos;
691 ssize_t read_size;
692 long i;
693 long newlines = 0;
694 long extra_max;
695 char *p;
696 char *buf;
697
698 rb_io_check_closed(fptr);
699 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX) {
700 return;
701 }
702
703 errno = 0;
704 if (!rb_w32_fd_is_text(fptr->fd)) {
705 r = lseek(fptr->fd, -fptr->rbuf.len, SEEK_CUR);
706 if (r < 0 && errno) {
707 if (errno == ESPIPE)
708 fptr->mode |= FMODE_DUPLEX;
709 if (!discard_rbuf) return;
710 }
711
712 goto end;
713 }
714
715 pos = lseek(fptr->fd, 0, SEEK_CUR);
716 if (pos < 0 && errno) {
717 if (errno == ESPIPE)
718 fptr->mode |= FMODE_DUPLEX;
719 if (!discard_rbuf) goto end;
720 }
721
722 /* add extra offset for removed '\r' in rbuf */
723 extra_max = (long)(pos - fptr->rbuf.len);
724 p = fptr->rbuf.ptr + fptr->rbuf.off;
725
726 /* if the end of rbuf is '\r', rbuf doesn't have '\r' within rbuf.len */
727 if (*(fptr->rbuf.ptr + fptr->rbuf.capa - 1) == '\r') {
728 newlines++;
729 }
730
731 for (i = 0; i < fptr->rbuf.len; i++) {
732 if (*p == '\n') newlines++;
733 if (extra_max == newlines) break;
734 p++;
735 }
736
737 buf = ALLOC_N(char, fptr->rbuf.len + newlines);
738 while (newlines >= 0) {
739 r = lseek(fptr->fd, pos - fptr->rbuf.len - newlines, SEEK_SET);
740 if (newlines == 0) break;
741 if (r < 0) {
742 newlines--;
743 continue;
744 }
745 read_size = _read(fptr->fd, buf, fptr->rbuf.len + newlines);
746 if (read_size < 0) {
747 int e = errno;
748 free(buf);
749 rb_syserr_fail_path(e, fptr->pathv);
750 }
751 if (read_size == fptr->rbuf.len) {
752 lseek(fptr->fd, r, SEEK_SET);
753 break;
754 }
755 else {
756 newlines--;
757 }
758 }
759 free(buf);
760 end:
761 fptr->rbuf.off = 0;
762 fptr->rbuf.len = 0;
763 clear_codeconv(fptr);
764 return;
765}
766
767/*
768 * We use io_seek to back cursor position when changing mode from text to binary,
769 * but stdin and pipe cannot seek back. Stdin and pipe read should use encoding
770 * conversion for working properly with mode change.
771 *
772 * Return previous translation mode.
773 */
774static inline int
775set_binary_mode_with_seek_cur(rb_io_t *fptr)
776{
777 if (!rb_w32_fd_is_text(fptr->fd)) return O_BINARY;
778
779 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX) {
780 return setmode(fptr->fd, O_BINARY);
781 }
782 flush_before_seek(fptr, false);
783 return setmode(fptr->fd, O_BINARY);
784}
785#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) set_binary_mode_with_seek_cur(fptr)
786
787#else
788/* Unix */
789# define DEFAULT_TEXTMODE 0
790#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || NEED_NEWLINE_DECORATOR_ON_READ(fptr))
791#define NEED_WRITECONV(fptr) ( \
792 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
793 NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) || \
794 ((fptr)->encs.ecflags & (ECONV_DECORATOR_MASK|ECONV_STATEFUL_DECORATOR_MASK)) || \
795 0)
796#define SET_BINARY_MODE(fptr) (void)(fptr)
797#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) (void)(fptr)
798#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) ((void)(enc2), (void)(ecflags))
799#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) (void)(fptr)
800#endif
801
802#if !defined HAVE_SHUTDOWN && !defined shutdown
803#define shutdown(a,b) 0
804#endif
805
806#if defined(_WIN32)
807#define is_socket(fd, path) rb_w32_is_socket(fd)
808#elif !defined(S_ISSOCK)
809#define is_socket(fd, path) 0
810#else
811static int
812is_socket(int fd, VALUE path)
813{
814 struct stat sbuf;
815 if (fstat(fd, &sbuf) < 0)
816 rb_sys_fail_path(path);
817 return S_ISSOCK(sbuf.st_mode);
818}
819#endif
820
821static const char closed_stream[] = "closed stream";
822
823static void
824io_fd_check_closed(int fd)
825{
826 if (fd < 0) {
827 rb_thread_check_ints(); /* check for ruby_error_stream_closed */
828 rb_raise(rb_eIOError, closed_stream);
829 }
830}
831
832void
833rb_eof_error(void)
834{
835 rb_raise(rb_eEOFError, "end of file reached");
836}
837
838VALUE
840{
841 rb_check_frozen(io);
842 return io;
843}
844
845void
847{
848 if (!fptr) {
849 rb_raise(rb_eIOError, "uninitialized stream");
850 }
851}
852
853void
855{
857 io_fd_check_closed(fptr->fd);
858}
859
860static rb_io_t *
861rb_io_get_fptr(VALUE io)
862{
863 rb_io_t *fptr = RFILE(io)->fptr;
865 return fptr;
866}
867
868VALUE
870{
871 return rb_convert_type_with_id(io, T_FILE, "IO", idTo_io);
872}
873
874VALUE
876{
877 return rb_check_convert_type_with_id(io, T_FILE, "IO", idTo_io);
878}
879
880VALUE
882{
883 VALUE write_io;
884 write_io = rb_io_get_fptr(io)->tied_io_for_writing;
885 if (write_io) {
886 return write_io;
887 }
888 return io;
889}
890
891VALUE
893{
894 VALUE write_io;
895 rb_io_t *fptr = rb_io_get_fptr(io);
896 if (!RTEST(w)) {
897 w = 0;
898 }
899 else {
900 GetWriteIO(w);
901 }
902 write_io = fptr->tied_io_for_writing;
903 fptr->tied_io_for_writing = w;
904 return write_io ? write_io : Qnil;
905}
906
907/*
908 * call-seq:
909 * timeout -> duration or nil
910 *
911 * Get the internal timeout duration or nil if it was not set.
912 *
913 */
914VALUE
916{
917 rb_io_t *fptr = rb_io_get_fptr(self);
918
919 return fptr->timeout;
920}
921
922/*
923 * call-seq:
924 * timeout = duration -> duration
925 * timeout = nil -> nil
926 *
927 * Sets the internal timeout to the specified duration or nil. The timeout
928 * applies to all blocking operations where possible.
929 *
930 * When the operation performs longer than the timeout set, IO::TimeoutError
931 * is raised.
932 *
933 * This affects the following methods (but is not limited to): #gets, #puts,
934 * #read, #write, #wait_readable and #wait_writable. This also affects
935 * blocking socket operations like Socket#accept and Socket#connect.
936 *
937 * Some operations like File#open and IO#close are not affected by the
938 * timeout. A timeout during a write operation may leave the IO in an
939 * inconsistent state, e.g. data was partially written. Generally speaking, a
940 * timeout is a last ditch effort to prevent an application from hanging on
941 * slow I/O operations, such as those that occur during a slowloris attack.
942 */
943VALUE
945{
946 // Validate it:
947 if (RTEST(timeout)) {
948 rb_time_interval(timeout);
949 }
950
951 rb_io_t *fptr = rb_io_get_fptr(self);
952
953 RB_OBJ_WRITE(self, &fptr->timeout, timeout);
954
955 return self;
956}
957
958/*
959 * call-seq:
960 * IO.try_convert(object) -> new_io or nil
961 *
962 * Attempts to convert +object+ into an \IO object via method +to_io+;
963 * returns the new \IO object if successful, or +nil+ otherwise:
964 *
965 * IO.try_convert(STDOUT) # => #<IO:<STDOUT>>
966 * IO.try_convert(ARGF) # => #<IO:<STDIN>>
967 * IO.try_convert('STDOUT') # => nil
968 *
969 */
970static VALUE
971rb_io_s_try_convert(VALUE dummy, VALUE io)
972{
973 return rb_io_check_io(io);
974}
975
976#if !RUBY_CRLF_ENVIRONMENT
977static void
978io_unread(rb_io_t *fptr, bool discard_rbuf)
979{
980 rb_off_t r;
981 rb_io_check_closed(fptr);
982 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX)
983 return;
984 /* xxx: target position may be negative if buffer is filled by ungetc */
985 errno = 0;
986 r = lseek(fptr->fd, -fptr->rbuf.len, SEEK_CUR);
987 if (r < 0 && errno) {
988 if (errno == ESPIPE)
989 fptr->mode |= FMODE_DUPLEX;
990 if (!discard_rbuf) return;
991 }
992 fptr->rbuf.off = 0;
993 fptr->rbuf.len = 0;
994 clear_codeconv(fptr);
995 return;
996}
997#endif
998
999static rb_encoding *io_input_encoding(rb_io_t *fptr);
1000
1001static void
1002io_ungetbyte(VALUE str, rb_io_t *fptr)
1003{
1004 long len = RSTRING_LEN(str);
1005
1006 if (fptr->rbuf.ptr == NULL) {
1007 const int min_capa = IO_RBUF_CAPA_FOR(fptr);
1008 fptr->rbuf.off = 0;
1009 fptr->rbuf.len = 0;
1010#if SIZEOF_LONG > SIZEOF_INT
1011 if (len > INT_MAX)
1012 rb_raise(rb_eIOError, "ungetbyte failed");
1013#endif
1014 if (len > min_capa)
1015 fptr->rbuf.capa = (int)len;
1016 else
1017 fptr->rbuf.capa = min_capa;
1018 fptr->rbuf.ptr = ALLOC_N(char, fptr->rbuf.capa);
1019 }
1020 if (fptr->rbuf.capa < len + fptr->rbuf.len) {
1021 rb_raise(rb_eIOError, "ungetbyte failed");
1022 }
1023 if (fptr->rbuf.off < len) {
1024 MEMMOVE(fptr->rbuf.ptr+fptr->rbuf.capa-fptr->rbuf.len,
1025 fptr->rbuf.ptr+fptr->rbuf.off,
1026 char, fptr->rbuf.len);
1027 fptr->rbuf.off = fptr->rbuf.capa-fptr->rbuf.len;
1028 }
1029 fptr->rbuf.off-=(int)len;
1030 fptr->rbuf.len+=(int)len;
1031 MEMMOVE(fptr->rbuf.ptr+fptr->rbuf.off, RSTRING_PTR(str), char, len);
1032}
1033
1034static void
1035io_restore_read_buffer(VALUE str, rb_io_t *fptr)
1036{
1037 long len = RSTRING_LEN(str);
1038
1039 if (len > INT_MAX - fptr->rbuf.len) {
1040 rb_raise(rb_eIOError, "read buffer too large");
1041 }
1042 if (fptr->rbuf.ptr == NULL || fptr->rbuf.capa >= len + fptr->rbuf.len) {
1043 io_ungetbyte(str, fptr);
1044 }
1045 else {
1046 int pending = fptr->rbuf.len;
1047 int capa = (int)len + pending;
1048 char *ptr = ALLOC_N(char, capa);
1049
1050 MEMMOVE(ptr, RSTRING_PTR(str), char, len);
1051 MEMMOVE(ptr + len, fptr->rbuf.ptr + fptr->rbuf.off, char, pending);
1052 ruby_xfree(fptr->rbuf.ptr);
1053 fptr->rbuf.ptr = ptr;
1054 fptr->rbuf.off = 0;
1055 fptr->rbuf.len = capa;
1056 fptr->rbuf.capa = capa;
1057 }
1058}
1059
1060static rb_io_t *
1061flush_before_seek(rb_io_t *fptr, bool discard_rbuf)
1062{
1063 if (io_fflush(fptr) < 0)
1064 rb_sys_fail_on_write(fptr);
1065 io_unread(fptr, discard_rbuf);
1066 errno = 0;
1067 return fptr;
1068}
1069
1070#define io_seek(fptr, ofs, whence) (errno = 0, lseek(flush_before_seek(fptr, true)->fd, (ofs), (whence)))
1071#define io_tell(fptr) lseek(flush_before_seek(fptr, false)->fd, 0, SEEK_CUR)
1072
1073#ifndef SEEK_CUR
1074# define SEEK_SET 0
1075# define SEEK_CUR 1
1076# define SEEK_END 2
1077#endif
1078
1079void
1081{
1082 rb_io_check_closed(fptr);
1083 if (!(fptr->mode & FMODE_READABLE)) {
1084 rb_raise(rb_eIOError, "not opened for reading");
1085 }
1086 if (fptr->wbuf.len) {
1087 if (io_fflush(fptr) < 0)
1088 rb_sys_fail_on_write(fptr);
1089 }
1090 if (fptr->tied_io_for_writing) {
1091 rb_io_t *wfptr;
1092 GetOpenFile(fptr->tied_io_for_writing, wfptr);
1093 if (io_fflush(wfptr) < 0)
1094 rb_sys_fail_on_write(wfptr);
1095 }
1096}
1097
1098void
1100{
1102 if (READ_CHAR_PENDING(fptr)) {
1103 rb_raise(rb_eIOError, "byte oriented read for character buffered IO");
1104 }
1105}
1106
1107void
1112
1113static rb_encoding*
1114io_read_encoding(rb_io_t *fptr)
1115{
1116 if (fptr->encs.enc) {
1117 return fptr->encs.enc;
1118 }
1119 return rb_default_external_encoding();
1120}
1121
1122static rb_encoding*
1123io_input_encoding(rb_io_t *fptr)
1124{
1125 if (fptr->encs.enc2) {
1126 return fptr->encs.enc2;
1127 }
1128 return io_read_encoding(fptr);
1129}
1130
1131void
1133{
1134 rb_io_check_closed(fptr);
1135 if (!(fptr->mode & FMODE_WRITABLE)) {
1136 rb_raise(rb_eIOError, "not opened for writing");
1137 }
1138 if (fptr->rbuf.len) {
1139 io_unread(fptr, true);
1140 }
1141}
1142
1143int
1144rb_io_read_pending(rb_io_t *fptr)
1145{
1146 /* This function is used for bytes and chars. Confusing. */
1147 if (READ_CHAR_PENDING(fptr))
1148 return 1; /* should raise? */
1149 return READ_DATA_PENDING(fptr);
1150}
1151
1152void
1154{
1155 if (!READ_DATA_PENDING(fptr)) {
1156 rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), RUBY_IO_TIMEOUT_DEFAULT);
1157 }
1158 return;
1159}
1160
1161int
1162rb_gc_for_fd(int err)
1163{
1164 if (err == EMFILE || err == ENFILE || err == ENOMEM) {
1165 rb_gc();
1166 return 1;
1167 }
1168 return 0;
1169}
1170
1171/* try `expr` upto twice while it returns false and `errno`
1172 * is to GC. Each `errno`s are available as `first_errno` and
1173 * `retried_errno` respectively */
1174#define TRY_WITH_GC(expr) \
1175 for (int first_errno, retried_errno = 0, retried = 0; \
1176 (!retried && \
1177 !(expr) && \
1178 (!rb_gc_for_fd(first_errno = errno) || !(expr)) && \
1179 (retried_errno = errno, 1)); \
1180 (void)retried_errno, retried = 1)
1181
1182static int
1183ruby_dup(int orig)
1184{
1185 int fd = -1;
1186
1187 TRY_WITH_GC((fd = rb_cloexec_dup(orig)) >= 0) {
1188 rb_syserr_fail(first_errno, 0);
1189 }
1190 rb_update_max_fd(fd);
1191 return fd;
1192}
1193
1194static VALUE
1195io_alloc(VALUE klass)
1196{
1197 UNPROTECTED_NEWOBJ_OF(io, struct RFile, klass, T_FILE, sizeof(struct RFile));
1198
1199 io->fptr = 0;
1200
1201 return (VALUE)io;
1202}
1203
1204#ifndef S_ISREG
1205# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
1206#endif
1207
1209 VALUE th;
1210 rb_io_t *fptr;
1211 int nonblock;
1212 int fd;
1213
1214 void *buf;
1215 size_t capa;
1216 struct timeval *timeout;
1217};
1218
1220 VALUE th;
1221 rb_io_t *fptr;
1222 int nonblock;
1223 int fd;
1224
1225 const void *buf;
1226 size_t capa;
1227 struct timeval *timeout;
1228};
1229
1230#ifdef HAVE_WRITEV
1231struct io_internal_writev_struct {
1232 VALUE th;
1233 rb_io_t *fptr;
1234 int nonblock;
1235 int fd;
1236
1237 int iovcnt;
1238 const struct iovec *iov;
1239 struct timeval *timeout;
1240};
1241#endif
1242
1243static int nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout);
1244
1250static inline int
1251io_internal_wait(VALUE thread, rb_io_t *fptr, int error, int events, struct timeval *timeout)
1252{
1253 if (!timeout && rb_thread_mn_schedulable(thread)) {
1254 RUBY_ASSERT(errno == EWOULDBLOCK || errno == EAGAIN);
1255 return -1;
1256 }
1257
1258 int ready = nogvl_wait_for(thread, fptr, events, timeout);
1259
1260 if (ready > 0) {
1261 return ready;
1262 }
1263 else if (ready == 0) {
1264 errno = ETIMEDOUT;
1265 return -1;
1266 }
1267
1268 // If there was an error BEFORE we started waiting, return it:
1269 if (error) {
1270 errno = error;
1271 return -1;
1272 }
1273 else {
1274 // Otherwise, whatever error was generated by `nogvl_wait_for` is the one we want:
1275 return ready;
1276 }
1277}
1278
1279static VALUE
1280internal_read_func(void *ptr)
1281{
1282 struct io_internal_read_struct *iis = ptr;
1283 ssize_t result;
1284
1285 if (iis->timeout && !iis->nonblock) {
1286 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_IN, iis->timeout) == -1) {
1287 return -1;
1288 }
1289 }
1290
1291 retry:
1292 result = read(iis->fd, iis->buf, iis->capa);
1293
1294 if (result < 0 && !iis->nonblock) {
1295 if (io_again_p(errno)) {
1296 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_IN, iis->timeout) == -1) {
1297 return -1;
1298 }
1299 else {
1300 goto retry;
1301 }
1302 }
1303 }
1304
1305 return result;
1306}
1307
1308#if defined __APPLE__
1309# define do_write_retry(code) do {result = code;} while (result == -1 && errno == EPROTOTYPE)
1310#else
1311# define do_write_retry(code) result = code
1312#endif
1313
1314static VALUE
1315internal_write_func(void *ptr)
1316{
1317 struct io_internal_write_struct *iis = ptr;
1318 ssize_t result;
1319
1320 if (iis->timeout && !iis->nonblock) {
1321 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1322 return -1;
1323 }
1324 }
1325
1326 retry:
1327 do_write_retry(write(iis->fd, iis->buf, iis->capa));
1328
1329 if (result < 0 && !iis->nonblock) {
1330 int e = errno;
1331 if (io_again_p(e)) {
1332 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1333 return -1;
1334 }
1335 else {
1336 goto retry;
1337 }
1338 }
1339 }
1340
1341 return result;
1342}
1343
1344#ifdef HAVE_WRITEV
1345static VALUE
1346internal_writev_func(void *ptr)
1347{
1348 struct io_internal_writev_struct *iis = ptr;
1349 ssize_t result;
1350
1351 if (iis->timeout && !iis->nonblock) {
1352 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1353 return -1;
1354 }
1355 }
1356
1357 retry:
1358 do_write_retry(writev(iis->fd, iis->iov, iis->iovcnt));
1359
1360 if (result < 0 && !iis->nonblock) {
1361 if (io_again_p(errno)) {
1362 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1363 return -1;
1364 }
1365 else {
1366 goto retry;
1367 }
1368 }
1369 }
1370
1371 return result;
1372}
1373#endif
1374
1375static ssize_t
1376rb_io_read_memory(rb_io_t *fptr, void *buf, size_t count)
1377{
1378 rb_thread_t *th = GET_THREAD();
1380 if (scheduler != Qnil) {
1381 VALUE result = rb_fiber_scheduler_io_read_memory(scheduler, fptr->self, buf, count);
1382
1383 if (!UNDEF_P(result)) {
1385 }
1386 }
1387
1388 struct io_internal_read_struct iis = {
1389 .th = th->self,
1390 .fptr = fptr,
1391 .nonblock = 0,
1392 .fd = fptr->fd,
1393
1394 .buf = buf,
1395 .capa = count,
1396 .timeout = NULL,
1397 };
1398
1399 struct timeval timeout_storage;
1400
1401 if (fptr->timeout != Qnil) {
1402 timeout_storage = rb_time_interval(fptr->timeout);
1403 iis.timeout = &timeout_storage;
1404 }
1405
1406 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_read_func, &iis, RUBY_IO_READABLE);
1407}
1408
1409static ssize_t
1410rb_io_write_memory(rb_io_t *fptr, const void *buf, size_t count)
1411{
1412 rb_thread_t *th = GET_THREAD();
1414 if (scheduler != Qnil) {
1415 VALUE result = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, buf, count);
1416
1417 if (!UNDEF_P(result)) {
1419 }
1420 }
1421
1422 struct io_internal_write_struct iis = {
1423 .th = th->self,
1424 .fptr = fptr,
1425 .nonblock = 0,
1426 .fd = fptr->fd,
1427
1428 .buf = buf,
1429 .capa = count,
1430 .timeout = NULL
1431 };
1432
1433 struct timeval timeout_storage;
1434
1435 if (fptr->timeout != Qnil) {
1436 timeout_storage = rb_time_interval(fptr->timeout);
1437 iis.timeout = &timeout_storage;
1438 }
1439
1440 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_write_func, &iis, RUBY_IO_WRITABLE);
1441}
1442
1443#ifdef HAVE_WRITEV
1444static ssize_t
1445rb_writev_internal(rb_io_t *fptr, const struct iovec *iov, int iovcnt)
1446{
1447 if (!iovcnt) return 0;
1448
1449 rb_thread_t *th = GET_THREAD();
1450
1452 if (scheduler != Qnil) {
1453 // This path assumes at least one `iov`:
1454 VALUE result = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, iov[0].iov_base, iov[0].iov_len);
1455
1456 if (!UNDEF_P(result)) {
1458 }
1459 }
1460
1461 struct io_internal_writev_struct iis = {
1462 .th = th->self,
1463 .fptr = fptr,
1464 .nonblock = 0,
1465 .fd = fptr->fd,
1466
1467 .iov = iov,
1468 .iovcnt = iovcnt,
1469 .timeout = NULL
1470 };
1471
1472 struct timeval timeout_storage;
1473
1474 if (fptr->timeout != Qnil) {
1475 timeout_storage = rb_time_interval(fptr->timeout);
1476 iis.timeout = &timeout_storage;
1477 }
1478
1479 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_writev_func, &iis, RUBY_IO_WRITABLE);
1480}
1481#endif
1482
1483static VALUE
1484io_flush_buffer_sync(void *arg)
1485{
1486 rb_io_t *fptr = arg;
1487 long l = fptr->wbuf.len;
1488 ssize_t r = write(fptr->fd, fptr->wbuf.ptr+fptr->wbuf.off, (size_t)l);
1489
1490 if (fptr->wbuf.len <= r) {
1491 fptr->wbuf.off = 0;
1492 fptr->wbuf.len = 0;
1493 return 0;
1494 }
1495
1496 if (0 <= r) {
1497 fptr->wbuf.off += (int)r;
1498 fptr->wbuf.len -= (int)r;
1499 errno = EAGAIN;
1500 }
1501
1502 return (VALUE)-1;
1503}
1504
1505static inline VALUE
1506io_flush_buffer_fiber_scheduler(VALUE scheduler, rb_io_t *fptr)
1507{
1508 VALUE ret = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, fptr->wbuf.ptr+fptr->wbuf.off, fptr->wbuf.len);
1509 if (!UNDEF_P(ret)) {
1510 ssize_t result = rb_fiber_scheduler_io_result_apply(ret);
1511 if (result > 0) {
1512 fptr->wbuf.off += result;
1513 fptr->wbuf.len -= result;
1514 }
1515 return result >= 0 ? (VALUE)0 : (VALUE)-1;
1516 }
1517 return ret;
1518}
1519
1520static VALUE
1521io_flush_buffer_async(VALUE arg)
1522{
1523 rb_io_t *fptr = (rb_io_t *)arg;
1524
1525 VALUE scheduler = rb_fiber_scheduler_current();
1526 if (scheduler != Qnil) {
1527 VALUE result = io_flush_buffer_fiber_scheduler(scheduler, fptr);
1528 if (!UNDEF_P(result)) {
1529 return result;
1530 }
1531 }
1532
1533 return rb_io_blocking_region_wait(fptr, io_flush_buffer_sync, fptr, RUBY_IO_WRITABLE);
1534}
1535
1536static inline int
1537io_flush_buffer(rb_io_t *fptr)
1538{
1539 if (!NIL_P(fptr->write_lock) && rb_mutex_owned_p(fptr->write_lock)) {
1540 return (int)io_flush_buffer_async((VALUE)fptr);
1541 }
1542 else {
1543 return (int)rb_mutex_synchronize(fptr->write_lock, io_flush_buffer_async, (VALUE)fptr);
1544 }
1545}
1546
1547static int
1548io_fflush(rb_io_t *fptr)
1549{
1550 rb_io_check_closed(fptr);
1551
1552 if (fptr->wbuf.len == 0)
1553 return 0;
1554
1555 while (fptr->wbuf.len > 0 && io_flush_buffer(fptr) != 0) {
1556 if (!rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT))
1557 return -1;
1558
1559 rb_io_check_closed(fptr);
1560 }
1561
1562 return 0;
1563}
1564
1565VALUE
1566rb_io_wait(VALUE io, VALUE events, VALUE timeout)
1567{
1568 rb_thread_t *th = GET_THREAD();
1570
1571 if (scheduler != Qnil) {
1572 return rb_fiber_scheduler_io_wait(scheduler, io, events, timeout);
1573 }
1574
1575 rb_io_t * fptr = NULL;
1576 RB_IO_POINTER(io, fptr);
1577
1578 struct timeval tv_storage;
1579 struct timeval *tv = NULL;
1580
1581 if (NIL_OR_UNDEF_P(timeout)) {
1582 timeout = fptr->timeout;
1583 }
1584
1585 if (timeout != Qnil) {
1586 tv_storage = rb_time_interval(timeout);
1587 tv = &tv_storage;
1588 }
1589
1590 int ready = rb_thread_io_wait(th, fptr, RB_NUM2INT(events), tv);
1591
1592 if (ready < 0) {
1593 rb_sys_fail(0);
1594 }
1595
1596 // Not sure if this is necessary:
1597 rb_io_check_closed(fptr);
1598
1599 if (ready) {
1600 return RB_INT2NUM(ready);
1601 }
1602 else {
1603 return Qfalse;
1604 }
1605}
1606
1607static VALUE
1608io_from_fd(int fd)
1609{
1610 return prep_io(fd, FMODE_EXTERNAL, rb_cIO, NULL);
1611}
1612
1613static int
1614io_wait_for_single_fd(int fd, int events, struct timeval *timeout, rb_thread_t *th, VALUE scheduler)
1615{
1616 if (scheduler != Qnil) {
1617 return RTEST(
1618 rb_fiber_scheduler_io_wait(scheduler, io_from_fd(fd), RB_INT2NUM(events), rb_fiber_scheduler_make_timeout(timeout))
1619 );
1620 }
1621
1622 return rb_thread_wait_for_single_fd(th, fd, events, timeout);
1623}
1624
1625int
1627{
1628 io_fd_check_closed(f);
1629
1630 rb_thread_t *th = GET_THREAD();
1632
1633 switch (errno) {
1634 case EINTR:
1635#if defined(ERESTART)
1636 case ERESTART:
1637#endif
1639 return TRUE;
1640
1641 case EAGAIN:
1642#if EWOULDBLOCK != EAGAIN
1643 case EWOULDBLOCK:
1644#endif
1645 if (scheduler != Qnil) {
1646 return RTEST(
1647 rb_fiber_scheduler_io_wait_readable(scheduler, io_from_fd(f))
1648 );
1649 }
1650 else {
1651 io_wait_for_single_fd(f, RUBY_IO_READABLE, NULL, th, scheduler);
1652 }
1653 return TRUE;
1654
1655 default:
1656 return FALSE;
1657 }
1658}
1659
1660int
1662{
1663 io_fd_check_closed(f);
1664
1665 rb_thread_t *th = GET_THREAD();
1667
1668 switch (errno) {
1669 case EINTR:
1670#if defined(ERESTART)
1671 case ERESTART:
1672#endif
1673 /*
1674 * In old Linux, several special files under /proc and /sys don't handle
1675 * select properly. Thus we need avoid to call if don't use O_NONBLOCK.
1676 * Otherwise, we face nasty hang up. Sigh.
1677 * e.g. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1678 * https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1679 * In EINTR case, we only need to call RUBY_VM_CHECK_INTS_BLOCKING().
1680 * Then rb_thread_check_ints() is enough.
1681 */
1683 return TRUE;
1684
1685 case EAGAIN:
1686#if EWOULDBLOCK != EAGAIN
1687 case EWOULDBLOCK:
1688#endif
1689 if (scheduler != Qnil) {
1690 return RTEST(
1691 rb_fiber_scheduler_io_wait_writable(scheduler, io_from_fd(f))
1692 );
1693 }
1694 else {
1695 io_wait_for_single_fd(f, RUBY_IO_WRITABLE, NULL, th, scheduler);
1696 }
1697 return TRUE;
1698
1699 default:
1700 return FALSE;
1701 }
1702}
1703
1704int
1705rb_wait_for_single_fd(int fd, int events, struct timeval *timeout)
1706{
1707 rb_thread_t *th = GET_THREAD();
1709 return io_wait_for_single_fd(fd, events, timeout, th, scheduler);
1710}
1711
1712int
1714{
1715 return rb_wait_for_single_fd(fd, RUBY_IO_READABLE, NULL);
1716}
1717
1718int
1720{
1721 return rb_wait_for_single_fd(fd, RUBY_IO_WRITABLE, NULL);
1722}
1723
1724VALUE
1725rb_io_maybe_wait(int error, VALUE io, VALUE events, VALUE timeout)
1726{
1727 // fptr->fd can be set to -1 at any time by another thread when the GVL is
1728 // released. Many code, e.g. `io_bufread` didn't check this correctly and
1729 // instead relies on `read(-1) -> -1` which causes this code path. We then
1730 // check here whether the IO was in fact closed. Probably it's better to
1731 // check that `fptr->fd != -1` before using it in syscall.
1732 rb_io_check_closed(RFILE(io)->fptr);
1733
1734 switch (error) {
1735 // In old Linux, several special files under /proc and /sys don't handle
1736 // select properly. Thus we need avoid to call if don't use O_NONBLOCK.
1737 // Otherwise, we face nasty hang up. Sigh.
1738 // e.g. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1739 // https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1740 // In EINTR case, we only need to call RUBY_VM_CHECK_INTS_BLOCKING().
1741 // Then rb_thread_check_ints() is enough.
1742 case EINTR:
1743#if defined(ERESTART)
1744 case ERESTART:
1745#endif
1746 // We might have pending interrupts since the previous syscall was interrupted:
1748
1749 // The operation was interrupted, so retry it immediately:
1750 return events;
1751
1752 case EAGAIN:
1753#if EWOULDBLOCK != EAGAIN
1754 case EWOULDBLOCK:
1755#endif
1756 {
1757 // The operation would block, so wait for the specified events:
1758 VALUE result = rb_io_wait(io, events, timeout);
1759 // The scheduler may change errno while waiting. Preserve the original
1760 // error in case no events are ready and the caller reports the failure.
1761 errno = error;
1762 return result;
1763 }
1764
1765 default:
1766 // Non-specific error, no event is ready:
1767 return Qnil;
1768 }
1769}
1770
1771int
1773{
1774 VALUE result = rb_io_maybe_wait(error, io, RB_INT2NUM(RUBY_IO_READABLE), timeout);
1775
1776 if (RTEST(result)) {
1777 return RB_NUM2INT(result);
1778 }
1779 else if (result == RUBY_Qfalse) {
1780 rb_raise(rb_eIOTimeoutError, "Timed out waiting for IO to become readable!");
1781 }
1782
1783 return 0;
1784}
1785
1786int
1788{
1789 VALUE result = rb_io_maybe_wait(error, io, RB_INT2NUM(RUBY_IO_WRITABLE), timeout);
1790
1791 if (RTEST(result)) {
1792 return RB_NUM2INT(result);
1793 }
1794 else if (result == RUBY_Qfalse) {
1795 rb_raise(rb_eIOTimeoutError, "Timed out waiting for IO to become writable!");
1796 }
1797
1798 return 0;
1799}
1800
1801static void
1802make_writeconv(rb_io_t *fptr)
1803{
1804 if (!fptr->writeconv_initialized) {
1805 const char *senc, *denc;
1806 rb_encoding *enc;
1807 int ecflags;
1808 VALUE ecopts;
1809
1810 fptr->writeconv_initialized = 1;
1811
1812 ecflags = fptr->encs.ecflags & ~ECONV_NEWLINE_DECORATOR_READ_MASK;
1813 ecopts = fptr->encs.ecopts;
1814
1815 if (!fptr->encs.enc || (rb_is_ascii8bit_enc(fptr->encs.enc) && !fptr->encs.enc2)) {
1816 /* no encoding conversion */
1817 fptr->writeconv_pre_ecflags = 0;
1818 fptr->writeconv_pre_ecopts = Qnil;
1819 fptr->writeconv = rb_econv_open_opts("", "", ecflags, ecopts);
1820 if (!fptr->writeconv)
1821 rb_exc_raise(rb_econv_open_exc("", "", ecflags));
1823 }
1824 else {
1825 enc = fptr->encs.enc2 ? fptr->encs.enc2 : fptr->encs.enc;
1826 senc = rb_econv_asciicompat_encoding(rb_enc_name(enc));
1827 if (!senc && !(fptr->encs.ecflags & ECONV_STATEFUL_DECORATOR_MASK)) {
1828 /* single conversion */
1829 fptr->writeconv_pre_ecflags = ecflags;
1830 fptr->writeconv_pre_ecopts = ecopts;
1831 fptr->writeconv = NULL;
1833 }
1834 else {
1835 /* double conversion */
1836 fptr->writeconv_pre_ecflags = ecflags & ~ECONV_STATEFUL_DECORATOR_MASK;
1837 fptr->writeconv_pre_ecopts = ecopts;
1838 if (senc) {
1839 denc = rb_enc_name(enc);
1840 fptr->writeconv_asciicompat = rb_str_new2(senc);
1841 }
1842 else {
1843 senc = denc = "";
1844 fptr->writeconv_asciicompat = rb_str_new2(rb_enc_name(enc));
1845 }
1847 ecopts = fptr->encs.ecopts;
1848 fptr->writeconv = rb_econv_open_opts(senc, denc, ecflags, ecopts);
1849 if (!fptr->writeconv)
1850 rb_exc_raise(rb_econv_open_exc(senc, denc, ecflags));
1851 }
1852 }
1853 }
1854}
1855
1856/* writing functions */
1858 rb_io_t *fptr;
1859 const char *ptr;
1860 long length;
1861};
1862
1864 VALUE io;
1865 VALUE str;
1866 int nosync;
1867};
1868
1869#ifdef HAVE_WRITEV
1870static ssize_t
1871io_binwrite_string_internal(rb_io_t *fptr, const char *ptr, long length)
1872{
1873 if (fptr->wbuf.len) {
1874 struct iovec iov[2];
1875
1876 iov[0].iov_base = fptr->wbuf.ptr+fptr->wbuf.off;
1877 iov[0].iov_len = fptr->wbuf.len;
1878 iov[1].iov_base = (void*)ptr;
1879 iov[1].iov_len = length;
1880
1881 ssize_t result = rb_writev_internal(fptr, iov, 2);
1882
1883 if (result < 0)
1884 return result;
1885
1886 if (result >= fptr->wbuf.len) {
1887 // We wrote more than the internal buffer:
1888 result -= fptr->wbuf.len;
1889 fptr->wbuf.off = 0;
1890 fptr->wbuf.len = 0;
1891 }
1892 else {
1893 // We only wrote less data than the internal buffer:
1894 fptr->wbuf.off += (int)result;
1895 fptr->wbuf.len -= (int)result;
1896
1897 result = 0;
1898 }
1899
1900 return result;
1901 }
1902 else {
1903 return rb_io_write_memory(fptr, ptr, length);
1904 }
1905}
1906#else
1907static ssize_t
1908io_binwrite_string_internal(rb_io_t *fptr, const char *ptr, long length)
1909{
1910 long remaining = length;
1911
1912 if (fptr->wbuf.len) {
1913 if (fptr->wbuf.len+length <= fptr->wbuf.capa) {
1914 if (fptr->wbuf.capa < fptr->wbuf.off+fptr->wbuf.len+length) {
1915 MEMMOVE(fptr->wbuf.ptr, fptr->wbuf.ptr+fptr->wbuf.off, char, fptr->wbuf.len);
1916 fptr->wbuf.off = 0;
1917 }
1918
1919 MEMMOVE(fptr->wbuf.ptr+fptr->wbuf.off+fptr->wbuf.len, ptr, char, length);
1920 fptr->wbuf.len += (int)length;
1921
1922 // We copied the entire incoming data to the internal buffer:
1923 remaining = 0;
1924 }
1925
1926 // Flush the internal buffer:
1927 if (io_fflush(fptr) < 0) {
1928 return -1;
1929 }
1930
1931 // If all the data was buffered, we are done:
1932 if (remaining == 0) {
1933 return length;
1934 }
1935 }
1936
1937 // Otherwise, we should write the data directly:
1938 return rb_io_write_memory(fptr, ptr, length);
1939}
1940#endif
1941
1942static VALUE
1943io_binwrite_string(VALUE arg)
1944{
1945 struct binwrite_arg *p = (struct binwrite_arg *)arg;
1946
1947 const char *ptr = p->ptr;
1948 size_t remaining = p->length;
1949
1950 while (remaining) {
1951 // Write as much as possible:
1952 ssize_t result = io_binwrite_string_internal(p->fptr, ptr, remaining);
1953
1954 if (result == 0) {
1955 // If only the internal buffer is written, result will be zero [bytes of given data written]. This means we
1956 // should try again immediately.
1957 }
1958 else if (result > 0) {
1959 if ((size_t)result == remaining) break;
1960 ptr += result;
1961 remaining -= result;
1962 }
1963 // Wait for it to become writable:
1964 else if (rb_io_maybe_wait_writable(errno, p->fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
1965 rb_io_check_closed(p->fptr);
1966 }
1967 else {
1968 // The error was unrelated to waiting for it to become writable, so we fail:
1969 return -1;
1970 }
1971 }
1972
1973 return p->length;
1974}
1975
1976inline static void
1977io_allocate_write_buffer(rb_io_t *fptr, int sync)
1978{
1979 if (fptr->wbuf.ptr == NULL && !(sync && (fptr->mode & FMODE_SYNC))) {
1980 fptr->wbuf.off = 0;
1981 fptr->wbuf.len = 0;
1982 fptr->wbuf.capa = IO_WBUF_CAPA_MIN;
1983 fptr->wbuf.ptr = ALLOC_N(char, fptr->wbuf.capa);
1984 }
1985
1986 if (NIL_P(fptr->write_lock)) {
1987 fptr->write_lock = rb_mutex_new();
1988 rb_mutex_allow_trap(fptr->write_lock, 1);
1989 }
1990}
1991
1992static inline int
1993io_binwrite_requires_flush_write(rb_io_t *fptr, long len, int nosync)
1994{
1995 // If the requested operation was synchronous and the output mode is synchronous or a TTY:
1996 if (!nosync && (fptr->mode & (FMODE_SYNC|FMODE_TTY)))
1997 return 1;
1998
1999 // If the amount of data we want to write exceeds the internal buffer:
2000 if (fptr->wbuf.ptr && fptr->wbuf.capa <= fptr->wbuf.len + len)
2001 return 1;
2002
2003 // Otherwise, we can append to the internal buffer:
2004 return 0;
2005}
2006
2007static long
2008io_binwrite(const char *ptr, long len, rb_io_t *fptr, int nosync)
2009{
2010 if (len <= 0) return len;
2011
2012 // Don't write anything if current thread has a pending interrupt:
2014
2015 io_allocate_write_buffer(fptr, !nosync);
2016
2017 if (io_binwrite_requires_flush_write(fptr, len, nosync)) {
2018 struct binwrite_arg arg;
2019
2020 arg.fptr = fptr;
2021 arg.ptr = ptr;
2022 arg.length = len;
2023
2024 if (!NIL_P(fptr->write_lock)) {
2025 return rb_mutex_synchronize(fptr->write_lock, io_binwrite_string, (VALUE)&arg);
2026 }
2027 else {
2028 return io_binwrite_string((VALUE)&arg);
2029 }
2030 }
2031 else {
2032 if (fptr->wbuf.off) {
2033 if (fptr->wbuf.len)
2034 MEMMOVE(fptr->wbuf.ptr, fptr->wbuf.ptr+fptr->wbuf.off, char, fptr->wbuf.len);
2035 fptr->wbuf.off = 0;
2036 }
2037
2038 MEMMOVE(fptr->wbuf.ptr+fptr->wbuf.off+fptr->wbuf.len, ptr, char, len);
2039 fptr->wbuf.len += (int)len;
2040
2041 return len;
2042 }
2043}
2044
2045# define MODE_BTMODE(a,b,c) ((fmode & FMODE_BINMODE) ? (b) : \
2046 (fmode & FMODE_TEXTMODE) ? (c) : (a))
2047
2048#define MODE_BTXMODE(a, b, c, d, e, f) ((fmode & FMODE_EXCL) ? \
2049 MODE_BTMODE(d, e, f) : \
2050 MODE_BTMODE(a, b, c))
2051
2052static VALUE
2053do_writeconv(VALUE str, rb_io_t *fptr, int *converted)
2054{
2055 if (NEED_WRITECONV(fptr)) {
2056 VALUE common_encoding = Qnil;
2057 SET_BINARY_MODE(fptr);
2058
2059 make_writeconv(fptr);
2060
2061 if (fptr->writeconv) {
2062#define fmode (fptr->mode)
2063 if (!NIL_P(fptr->writeconv_asciicompat))
2064 common_encoding = fptr->writeconv_asciicompat;
2065 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1) && !rb_enc_asciicompat(rb_enc_get(str))) {
2066 rb_raise(rb_eArgError, "ASCII incompatible string written for text mode IO without encoding conversion: %s",
2067 rb_enc_name(rb_enc_get(str)));
2068 }
2069#undef fmode
2070 }
2071 else {
2072 if (fptr->encs.enc2)
2073 common_encoding = rb_enc_from_encoding(fptr->encs.enc2);
2074 else if (fptr->encs.enc != rb_ascii8bit_encoding())
2075 common_encoding = rb_enc_from_encoding(fptr->encs.enc);
2076 }
2077
2078 if (!NIL_P(common_encoding)) {
2079 str = rb_str_encode(str, common_encoding,
2081 *converted = 1;
2082 }
2083
2084 if (fptr->writeconv) {
2086 *converted = 1;
2087 }
2088 }
2089#if RUBY_CRLF_ENVIRONMENT
2090#define fmode (fptr->mode)
2091 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1)) {
2092 if ((fptr->mode & FMODE_READABLE) &&
2094 setmode(fptr->fd, O_BINARY);
2095 }
2096 else {
2097 setmode(fptr->fd, O_TEXT);
2098 }
2099 if (!rb_enc_asciicompat(rb_enc_get(str))) {
2100 rb_raise(rb_eArgError, "ASCII incompatible string written for text mode IO without encoding conversion: %s",
2101 rb_enc_name(rb_enc_get(str)));
2102 }
2103 }
2104#undef fmode
2105#endif
2106 return str;
2107}
2108
2109static long
2110io_fwrite(VALUE str, rb_io_t *fptr, int nosync)
2111{
2112 int converted = 0;
2113 VALUE tmp;
2114 long n, len;
2115 const char *ptr;
2116
2117#ifdef _WIN32
2118 if (fptr->mode & FMODE_TTY) {
2119 if (rb_w32_write_console(str, fptr->fd) > 0) return RSTRING_LEN(str);
2120 }
2121#endif
2122
2123 str = do_writeconv(str, fptr, &converted);
2124 if (converted)
2125 OBJ_FREEZE(str);
2126
2127 tmp = rb_str_tmp_frozen_no_embed_acquire(str);
2128 RSTRING_GETMEM(tmp, ptr, len);
2129 n = io_binwrite(ptr, len, fptr, nosync);
2130 rb_str_tmp_frozen_release(str, tmp);
2131
2132 return n;
2133}
2134
2135ssize_t
2136rb_io_bufwrite(VALUE io, const void *buf, size_t size)
2137{
2138 rb_io_t *fptr;
2139
2140 GetOpenFile(io, fptr);
2142 return (ssize_t)io_binwrite(buf, (long)size, fptr, 0);
2143}
2144
2145static VALUE
2146io_write(VALUE io, VALUE str, int nosync)
2147{
2148 rb_io_t *fptr;
2149 long n;
2150 VALUE tmp;
2151
2152 io = GetWriteIO(io);
2153 str = rb_obj_as_string(str);
2154 tmp = rb_io_check_io(io);
2155
2156 if (NIL_P(tmp)) {
2157 /* port is not IO, call write method for it. */
2158 return rb_funcall(io, id_write, 1, str);
2159 }
2160
2161 io = tmp;
2162 if (RSTRING_LEN(str) == 0) return INT2FIX(0);
2163
2164 GetOpenFile(io, fptr);
2166
2167 n = io_fwrite(str, fptr, nosync);
2168 if (n < 0L) rb_sys_fail_on_write(fptr);
2169
2170 return LONG2FIX(n);
2171}
2172
2173#ifdef HAVE_WRITEV
2174struct binwritev_arg {
2175 rb_io_t *fptr;
2176 struct iovec *iov;
2177 int iovcnt;
2178 size_t total;
2179};
2180
2181static VALUE
2182io_binwritev_internal(VALUE arg)
2183{
2184 struct binwritev_arg *p = (struct binwritev_arg *)arg;
2185
2186 size_t remaining = p->total;
2187 size_t offset = 0;
2188
2189 rb_io_t *fptr = p->fptr;
2190 struct iovec *iov = p->iov;
2191 int iovcnt = p->iovcnt;
2192
2193 while (remaining) {
2194 long result = rb_writev_internal(fptr, iov, iovcnt);
2195
2196 if (result >= 0) {
2197 offset += result;
2198 if (fptr->wbuf.ptr && fptr->wbuf.len) {
2199 if (offset < (size_t)fptr->wbuf.len) {
2200 fptr->wbuf.off += result;
2201 fptr->wbuf.len -= result;
2202 }
2203 else {
2204 offset -= (size_t)fptr->wbuf.len;
2205 fptr->wbuf.off = 0;
2206 fptr->wbuf.len = 0;
2207 }
2208 }
2209
2210 if (offset == p->total) {
2211 return p->total;
2212 }
2213
2214 while (result >= (ssize_t)iov->iov_len) {
2215 /* iovcnt > 0 */
2216 result -= iov->iov_len;
2217 iov->iov_len = 0;
2218 iov++;
2219
2220 if (!--iovcnt) {
2221 // I don't believe this code path can ever occur.
2222 return offset;
2223 }
2224 }
2225
2226 iov->iov_base = (char *)iov->iov_base + result;
2227 iov->iov_len -= result;
2228 }
2229 else if (rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
2230 rb_io_check_closed(fptr);
2231 }
2232 else {
2233 return -1;
2234 }
2235 }
2236
2237 return offset;
2238}
2239
2240static long
2241io_binwritev(struct iovec *iov, int iovcnt, rb_io_t *fptr)
2242{
2243 // Don't write anything if current thread has a pending interrupt:
2245
2246 if (iovcnt == 0) return 0;
2247
2248 size_t total = 0;
2249 for (int i = 1; i < iovcnt; i++) total += iov[i].iov_len;
2250
2251 io_allocate_write_buffer(fptr, 1);
2252
2253 if (fptr->wbuf.ptr && fptr->wbuf.len) {
2254 // The end of the buffered data:
2255 size_t offset = fptr->wbuf.off + fptr->wbuf.len;
2256
2257 if (offset + total <= (size_t)fptr->wbuf.capa) {
2258 for (int i = 1; i < iovcnt; i++) {
2259 memcpy(fptr->wbuf.ptr+offset, iov[i].iov_base, iov[i].iov_len);
2260 offset += iov[i].iov_len;
2261 }
2262
2263 fptr->wbuf.len += total;
2264
2265 /* io_binwritev is only reached in sync/TTY mode (it is called only
2266 * from io_fwritev, which io_writev uses only when FMODE_SYNC or
2267 * FMODE_TTY is set), so the coalesced data must be flushed
2268 * immediately rather than left in the buffer until the next flush
2269 * or close. Otherwise a multi-argument write with many arguments
2270 * would not be observably atomic under sync. */
2271 if (io_fflush(fptr) < 0) return -1;
2272
2273 return total;
2274 }
2275 else {
2276 iov[0].iov_base = fptr->wbuf.ptr + fptr->wbuf.off;
2277 iov[0].iov_len = fptr->wbuf.len;
2278 }
2279 }
2280 else {
2281 // The first iov is reserved for the internal buffer, and it's empty.
2282 iov++;
2283
2284 if (!--iovcnt) {
2285 // If there are no other io vectors we are done.
2286 return 0;
2287 }
2288 }
2289
2290 struct binwritev_arg arg;
2291 arg.fptr = fptr;
2292 arg.iov = iov;
2293 arg.iovcnt = iovcnt;
2294 arg.total = total;
2295
2296 if (!NIL_P(fptr->write_lock)) {
2297 return rb_mutex_synchronize(fptr->write_lock, io_binwritev_internal, (VALUE)&arg);
2298 }
2299 else {
2300 return io_binwritev_internal((VALUE)&arg);
2301 }
2302}
2303
2304static long
2305io_fwritev(int argc, const VALUE *argv, rb_io_t *fptr)
2306{
2307 int i, converted, iovcnt = argc + 1;
2308 long n;
2309 VALUE v1, v2, str, tmp, *tmp_array;
2310 struct iovec *iov;
2311
2312 iov = ALLOCV_N(struct iovec, v1, iovcnt);
2313 tmp_array = ALLOCV_N(VALUE, v2, argc);
2314
2315 for (i = 0; i < argc; i++) {
2316 str = rb_obj_as_string(argv[i]);
2317 converted = 0;
2318 str = do_writeconv(str, fptr, &converted);
2319
2320 if (converted)
2321 OBJ_FREEZE(str);
2322
2323 tmp = rb_str_tmp_frozen_acquire(str);
2324 tmp_array[i] = tmp;
2325
2326 /* iov[0] is reserved for buffer of fptr */
2327 iov[i+1].iov_base = RSTRING_PTR(tmp);
2328 iov[i+1].iov_len = RSTRING_LEN(tmp);
2329 }
2330
2331 n = io_binwritev(iov, iovcnt, fptr);
2332 if (v1) ALLOCV_END(v1);
2333
2334 for (i = 0; i < argc; i++) {
2335 rb_str_tmp_frozen_release(argv[i], tmp_array[i]);
2336 }
2337
2338 if (v2) ALLOCV_END(v2);
2339
2340 return n;
2341}
2342
2343static int
2344iovcnt_ok(int iovcnt)
2345{
2346#ifdef IOV_MAX
2347 return iovcnt < IOV_MAX;
2348#else /* GNU/Hurd has writev, but no IOV_MAX */
2349 return 1;
2350#endif
2351}
2352#endif /* HAVE_WRITEV */
2353
2354static VALUE
2355io_writev(int argc, const VALUE *argv, VALUE io)
2356{
2357 rb_io_t *fptr;
2358 long n;
2359 VALUE tmp, total = INT2FIX(0);
2360 int i, cnt = 1;
2361
2362 io = GetWriteIO(io);
2363 tmp = rb_io_check_io(io);
2364
2365 if (NIL_P(tmp)) {
2366 /* port is not IO, call write method for it. */
2367 return rb_funcallv(io, id_write, argc, argv);
2368 }
2369
2370 io = tmp;
2371
2372 GetOpenFile(io, fptr);
2374
2375 for (i = 0; i < argc; i += cnt) {
2376#ifdef HAVE_WRITEV
2377 if ((fptr->mode & (FMODE_SYNC|FMODE_TTY)) && iovcnt_ok(cnt = argc - i)) {
2378 n = io_fwritev(cnt, &argv[i], fptr);
2379 }
2380 else
2381#endif
2382 {
2383 cnt = 1;
2384 /* sync at last item */
2385 n = io_fwrite(rb_obj_as_string(argv[i]), fptr, (i < argc-1));
2386 }
2387
2388 if (n < 0L)
2389 rb_sys_fail_on_write(fptr);
2390
2391 total = rb_fix_plus(LONG2FIX(n), total);
2392 }
2393
2394 return total;
2395}
2396
2397/*
2398 * call-seq:
2399 * write(*objects) -> integer
2400 *
2401 * Writes each of the given +objects+ to +self+,
2402 * which must be opened for writing
2403 * (see {Access Modes}[rdoc-ref:File@Access+Modes]);
2404 * returns the total number bytes written;
2405 * each of +objects+ that is not a string is converted via method +to_s+:
2406 *
2407 * $stdout.write('Hello', ', ', 'World!', "\n") # => 14
2408 * $stdout.write('foo', :bar, 2, "\n") # => 8
2409 *
2410 * Output:
2411 *
2412 * Hello, World!
2413 * foobar2
2414 *
2415 * Related: IO#read.
2416 */
2417
2418static VALUE
2419io_write_m(int argc, VALUE *argv, VALUE io)
2420{
2421 if (argc != 1) {
2422 return io_writev(argc, argv, io);
2423 }
2424 else {
2425 VALUE str = argv[0];
2426 return io_write(io, str, 0);
2427 }
2428}
2429
2430VALUE
2431rb_io_write(VALUE io, VALUE str)
2432{
2433 return rb_funcallv(io, id_write, 1, &str);
2434}
2435
2436static VALUE
2437rb_io_writev(VALUE io, int argc, const VALUE *argv)
2438{
2439 if (argc > 1 && rb_obj_method_arity(io, id_write) == 1) {
2440 if (io != rb_ractor_stderr() && RTEST(ruby_verbose)) {
2441 VALUE klass = CLASS_OF(io);
2442 char sep = RCLASS_SINGLETON_P(klass) ? (klass = io, '.') : '#';
2444 RB_WARN_CATEGORY_DEPRECATED, "%+"PRIsVALUE"%c""write is outdated interface"
2445 " which accepts just one argument",
2446 klass, sep
2447 );
2448 }
2449
2450 do rb_io_write(io, *argv++); while (--argc);
2451
2452 return Qnil;
2453 }
2454
2455 return rb_funcallv(io, id_write, argc, argv);
2456}
2457
2458/*
2459 * call-seq:
2460 * self << object -> self
2461 *
2462 * Writes the given +object+ to +self+,
2463 * which must be opened for writing (see {Access Modes}[rdoc-ref:File@Access+Modes]);
2464 * returns +self+;
2465 * if +object+ is not a string, it is converted via method +to_s+:
2466 *
2467 * $stdout << 'Hello' << ', ' << 'World!' << "\n"
2468 * $stdout << 'foo' << :bar << 2 << "\n"
2469 *
2470 * Output:
2471 *
2472 * Hello, World!
2473 * foobar2
2474 *
2475 */
2476
2477
2478VALUE
2480{
2481 rb_io_write(io, str);
2482 return io;
2483}
2484
2485#ifdef HAVE_FSYNC
2486static VALUE
2487nogvl_fsync(void *ptr)
2488{
2489 rb_io_t *fptr = ptr;
2490
2491#ifdef _WIN32
2492 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->fd)) != FILE_TYPE_DISK)
2493 return 0;
2494#endif
2495 return (VALUE)fsync(fptr->fd);
2496}
2497#endif
2498
2499VALUE
2500rb_io_flush_raw(VALUE io, int sync)
2501{
2502 rb_io_t *fptr;
2503
2504 if (!RB_TYPE_P(io, T_FILE)) {
2505 return rb_funcall(io, id_flush, 0);
2506 }
2507
2508 io = GetWriteIO(io);
2509 GetOpenFile(io, fptr);
2510
2511 if (fptr->mode & FMODE_WRITABLE) {
2512 if (io_fflush(fptr) < 0)
2513 rb_sys_fail_on_write(fptr);
2514 }
2515 if (fptr->mode & FMODE_READABLE) {
2516 io_unread(fptr, true);
2517 }
2518
2519 return io;
2520}
2521
2522/*
2523 * call-seq:
2524 * flush -> self
2525 *
2526 * Flushes data buffered in +self+ to the operating system
2527 * (but does not necessarily flush data buffered in the operating system):
2528 *
2529 * $stdout.print 'no newline' # Not necessarily flushed.
2530 * $stdout.flush # Flushed.
2531 *
2532 */
2533
2534VALUE
2535rb_io_flush(VALUE io)
2536{
2537 return rb_io_flush_raw(io, 1);
2538}
2539
2540/*
2541 * call-seq:
2542 * tell -> integer
2543 *
2544 * Returns the current position (in bytes) in +self+
2545 * (see {Position}[rdoc-ref:IO@Position]):
2546 *
2547 * f = File.open('t.txt')
2548 * f.tell # => 0
2549 * f.gets # => "First line\n"
2550 * f.tell # => 12
2551 * f.close
2552 *
2553 * Related: IO#pos=, IO#seek.
2554 */
2555
2556static VALUE
2557rb_io_tell(VALUE io)
2558{
2559 rb_io_t *fptr;
2560 rb_off_t pos;
2561
2562 GetOpenFile(io, fptr);
2563 pos = io_tell(fptr);
2564 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2565 pos -= fptr->rbuf.len;
2566 return OFFT2NUM(pos);
2567}
2568
2569static VALUE
2570rb_io_seek(VALUE io, VALUE offset, int whence)
2571{
2572 rb_io_t *fptr;
2573 rb_off_t pos;
2574
2575 pos = NUM2OFFT(offset);
2576 GetOpenFile(io, fptr);
2577 pos = io_seek(fptr, pos, whence);
2578 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2579 if (fptr->readconv) clear_readconv(fptr);
2580
2581 return INT2FIX(0);
2582}
2583
2584static int
2585interpret_seek_whence(VALUE vwhence)
2586{
2587 if (vwhence == sym_SET)
2588 return SEEK_SET;
2589 if (vwhence == sym_CUR)
2590 return SEEK_CUR;
2591 if (vwhence == sym_END)
2592 return SEEK_END;
2593#ifdef SEEK_DATA
2594 if (vwhence == sym_DATA)
2595 return SEEK_DATA;
2596#endif
2597#ifdef SEEK_HOLE
2598 if (vwhence == sym_HOLE)
2599 return SEEK_HOLE;
2600#endif
2601 return NUM2INT(vwhence);
2602}
2603
2604/*
2605 * call-seq:
2606 * seek(offset, whence = IO::SEEK_SET) -> 0
2607 *
2608 * Seeks to the position given by integer +offset+
2609 * (see {Position}[rdoc-ref:IO@Position])
2610 * and constant +whence+, which is one of:
2611 *
2612 * - +:CUR+ or <tt>IO::SEEK_CUR</tt>:
2613 * Repositions the stream to its current position plus the given +offset+:
2614 *
2615 * f = File.open('t.txt')
2616 * f.tell # => 0
2617 * f.seek(20, :CUR) # => 0
2618 * f.tell # => 20
2619 * f.seek(-10, :CUR) # => 0
2620 * f.tell # => 10
2621 * f.close
2622 *
2623 * - +:END+ or <tt>IO::SEEK_END</tt>:
2624 * Repositions the stream to its end plus the given +offset+:
2625 *
2626 * f = File.open('t.txt')
2627 * f.tell # => 0
2628 * f.seek(0, :END) # => 0 # Repositions to stream end.
2629 * f.tell # => 52
2630 * f.seek(-20, :END) # => 0
2631 * f.tell # => 32
2632 * f.seek(-40, :END) # => 0
2633 * f.tell # => 12
2634 * f.close
2635 *
2636 * - +:SET+ or <tt>IO::SEEK_SET</tt>:
2637 * Repositions the stream to the given +offset+:
2638 *
2639 * f = File.open('t.txt')
2640 * f.tell # => 0
2641 * f.seek(20, :SET) # => 0
2642 * f.tell # => 20
2643 * f.seek(40, :SET) # => 0
2644 * f.tell # => 40
2645 * f.close
2646 *
2647 * Related: IO#pos=, IO#tell.
2648 *
2649 */
2650
2651static VALUE
2652rb_io_seek_m(int argc, VALUE *argv, VALUE io)
2653{
2654 VALUE offset, ptrname;
2655 int whence = SEEK_SET;
2656
2657 if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
2658 whence = interpret_seek_whence(ptrname);
2659 }
2660
2661 return rb_io_seek(io, offset, whence);
2662}
2663
2664/*
2665 * call-seq:
2666 * pos = new_position -> new_position
2667 *
2668 * Seeks to the given +new_position+ (in bytes);
2669 * see {Position}[rdoc-ref:IO@Position]:
2670 *
2671 * f = File.open('t.txt')
2672 * f.tell # => 0
2673 * f.pos = 20 # => 20
2674 * f.tell # => 20
2675 * f.close
2676 *
2677 * Related: IO#seek, IO#tell.
2678 *
2679 */
2680
2681static VALUE
2682rb_io_set_pos(VALUE io, VALUE offset)
2683{
2684 rb_io_t *fptr;
2685 rb_off_t pos;
2686
2687 pos = NUM2OFFT(offset);
2688 GetOpenFile(io, fptr);
2689 pos = io_seek(fptr, pos, SEEK_SET);
2690 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2691 if (fptr->readconv) clear_readconv(fptr);
2692
2693 return OFFT2NUM(pos);
2694}
2695
2696/*
2697 * call-seq:
2698 * rewind -> 0
2699 *
2700 * Repositions the stream to its beginning,
2701 * setting both the position and the line number to zero;
2702 * see {Position}[rdoc-ref:IO@Position]
2703 * and {Line Number}[rdoc-ref:IO@Line+Number]:
2704 *
2705 * f = File.open('t.txt')
2706 * f.tell # => 0
2707 * f.lineno # => 0
2708 * f.gets # => "First line\n"
2709 * f.tell # => 12
2710 * f.lineno # => 1
2711 * f.rewind # => 0
2712 * f.tell # => 0
2713 * f.lineno # => 0
2714 * f.close
2715 *
2716 * Note that this method cannot be used with streams such as pipes, ttys, and sockets.
2717 *
2718 */
2719
2720static VALUE
2721rb_io_rewind(VALUE io)
2722{
2723 rb_io_t *fptr;
2724
2725 GetOpenFile(io, fptr);
2726 if (io_seek(fptr, 0L, 0) < 0 && errno) rb_sys_fail_path(fptr->pathv);
2727 if (io == ARGF.current_file) {
2728 ARGF.lineno -= fptr->lineno;
2729 }
2730 fptr->lineno = 0;
2731 if (fptr->readconv) {
2732 clear_readconv(fptr);
2733 }
2734
2735 return INT2FIX(0);
2736}
2737
2738static int
2739fptr_wait_readable(rb_io_t *fptr)
2740{
2741 int result = rb_io_maybe_wait_readable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT);
2742
2743 if (result)
2744 rb_io_check_closed(fptr);
2745
2746 return result;
2747}
2748
2749static int
2750io_fillbuf(rb_io_t *fptr)
2751{
2752 ssize_t r;
2753
2754 if (fptr->rbuf.ptr == NULL) {
2755 fptr->rbuf.off = 0;
2756 fptr->rbuf.len = 0;
2757 fptr->rbuf.capa = IO_RBUF_CAPA_FOR(fptr);
2758 fptr->rbuf.ptr = ALLOC_N(char, fptr->rbuf.capa);
2759 }
2760 if (fptr->rbuf.len == 0) {
2761 retry:
2762 r = rb_io_read_memory(fptr, fptr->rbuf.ptr, fptr->rbuf.capa);
2763
2764 if (r < 0) {
2765 if (fptr_wait_readable(fptr))
2766 goto retry;
2767
2768 int e = errno;
2769 VALUE path = rb_sprintf("fd:%d ", fptr->fd);
2770 if (!NIL_P(fptr->pathv)) {
2771 rb_str_append(path, fptr->pathv);
2772 }
2773
2774 rb_syserr_fail_path(e, path);
2775 }
2776 if (r > 0) rb_io_check_closed(fptr);
2777 fptr->rbuf.off = 0;
2778 fptr->rbuf.len = (int)r; /* r should be <= rbuf_capa */
2779 if (r == 0)
2780 return -1; /* EOF */
2781 }
2782 return 0;
2783}
2784
2785/*
2786 * call-seq:
2787 * eof -> true or false
2788 *
2789 * Returns +true+ if the stream is positioned at its end, +false+ otherwise;
2790 * see {Position}[rdoc-ref:IO@Position]:
2791 *
2792 * f = File.open('t.txt')
2793 * f.eof # => false
2794 * f.seek(0, :END) # => 0
2795 * f.eof # => true
2796 * f.close
2797 *
2798 * Raises an exception unless the stream is opened for reading;
2799 * see {Mode}[rdoc-ref:File@Access+Modes].
2800 *
2801 * If +self+ is a stream such as pipe or socket, this method
2802 * blocks until the other end sends some data or closes it:
2803 *
2804 * r, w = IO.pipe
2805 * Thread.new { sleep 1; w.close }
2806 * r.eof? # => true # After 1-second wait.
2807 *
2808 * r, w = IO.pipe
2809 * Thread.new { sleep 1; w.puts "a" }
2810 * r.eof? # => false # After 1-second wait.
2811 *
2812 * r, w = IO.pipe
2813 * r.eof? # blocks forever
2814 *
2815 * Note that this method reads data to the input byte buffer. So
2816 * IO#sysread may not behave as you intend with IO#eof?, unless you
2817 * call IO#rewind first (which is not available for some streams).
2818 */
2819
2820VALUE
2822{
2823 rb_io_t *fptr;
2824
2825 GetOpenFile(io, fptr);
2827
2828 if (READ_CHAR_PENDING(fptr)) return Qfalse;
2829 if (READ_DATA_PENDING(fptr)) return Qfalse;
2830 READ_CHECK(fptr);
2831#if RUBY_CRLF_ENVIRONMENT
2832 if (!NEED_READCONV(fptr) && NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
2833 return RBOOL(eof(fptr->fd));
2834 }
2835#endif
2836 return RBOOL(io_fillbuf(fptr) < 0);
2837}
2838
2839/*
2840 * call-seq:
2841 * sync -> true or false
2842 *
2843 * Returns the current sync mode of the stream.
2844 * When sync mode is true, all output is immediately flushed to the underlying
2845 * operating system and is not buffered by Ruby internally. See also #fsync.
2846 *
2847 * f = File.open('t.tmp', 'w')
2848 * f.sync # => false
2849 * f.sync = true
2850 * f.sync # => true
2851 * f.close
2852 *
2853 */
2854
2855static VALUE
2856rb_io_sync(VALUE io)
2857{
2858 rb_io_t *fptr;
2859
2860 io = GetWriteIO(io);
2861 GetOpenFile(io, fptr);
2862 return RBOOL(fptr->mode & FMODE_SYNC);
2863}
2864
2865#ifdef HAVE_FSYNC
2866
2867/*
2868 * call-seq:
2869 * sync = boolean -> boolean
2870 *
2871 * Sets the _sync_ _mode_ for the stream to the given value;
2872 * returns the given value.
2873 *
2874 * Values for the sync mode:
2875 *
2876 * - +true+: All output is immediately flushed to the
2877 * underlying operating system and is not buffered internally.
2878 * - +false+: Output may be buffered internally.
2879 *
2880 * Example;
2881 *
2882 * f = File.open('t.tmp', 'w')
2883 * f.sync # => false
2884 * f.sync = true
2885 * f.sync # => true
2886 * f.close
2887 *
2888 * Related: IO#fsync.
2889 *
2890 */
2891
2892static VALUE
2893rb_io_set_sync(VALUE io, VALUE sync)
2894{
2895 rb_io_t *fptr;
2896
2897 io = GetWriteIO(io);
2898 GetOpenFile(io, fptr);
2899 if (RTEST(sync)) {
2900 fptr->mode |= FMODE_SYNC;
2901 }
2902 else {
2903 fptr->mode &= ~FMODE_SYNC;
2904 }
2905 return sync;
2906}
2907
2908/*
2909 * call-seq:
2910 * fsync -> 0
2911 *
2912 * Immediately writes to disk all data buffered in the stream,
2913 * via the operating system's <tt>fsync(2)</tt>.
2914
2915 * Note this difference:
2916 *
2917 * - IO#sync=: Ensures that data is flushed from the stream's internal buffers,
2918 * but does not guarantee that the operating system actually writes the data to disk.
2919 * - IO#fsync: Ensures both that data is flushed from internal buffers,
2920 * and that data is written to disk.
2921 *
2922 * Raises an exception if the operating system does not support <tt>fsync(2)</tt>.
2923 *
2924 */
2925
2926static VALUE
2927rb_io_fsync(VALUE io)
2928{
2929 rb_io_t *fptr;
2930
2931 io = GetWriteIO(io);
2932 GetOpenFile(io, fptr);
2933
2934 if (io_fflush(fptr) < 0)
2935 rb_sys_fail_on_write(fptr);
2936
2937 if ((int)rb_io_blocking_region(fptr, nogvl_fsync, fptr))
2938 rb_sys_fail_path(fptr->pathv);
2939
2940 return INT2FIX(0);
2941}
2942#else
2943# define rb_io_fsync rb_f_notimplement
2944# define rb_io_sync rb_f_notimplement
2945static VALUE
2946rb_io_set_sync(VALUE io, VALUE sync)
2947{
2948 rb_notimplement();
2950}
2951#endif
2952
2953#ifdef HAVE_FDATASYNC
2954static VALUE
2955nogvl_fdatasync(void *ptr)
2956{
2957 rb_io_t *fptr = ptr;
2958
2959 return (VALUE)fdatasync(fptr->fd);
2960}
2961
2962/*
2963 * call-seq:
2964 * fdatasync -> 0
2965 *
2966 * Immediately writes to disk all data buffered in the stream,
2967 * via the operating system's: <tt>fdatasync(2)</tt>, if supported,
2968 * otherwise via <tt>fsync(2)</tt>, if supported;
2969 * otherwise raises an exception.
2970 *
2971 */
2972
2973static VALUE
2974rb_io_fdatasync(VALUE io)
2975{
2976 rb_io_t *fptr;
2977
2978 io = GetWriteIO(io);
2979 GetOpenFile(io, fptr);
2980
2981 if (io_fflush(fptr) < 0)
2982 rb_sys_fail_on_write(fptr);
2983
2984 if ((int)rb_io_blocking_region(fptr, nogvl_fdatasync, fptr) == 0)
2985 return INT2FIX(0);
2986
2987 /* fall back */
2988 return rb_io_fsync(io);
2989}
2990#else
2991#define rb_io_fdatasync rb_io_fsync
2992#endif
2993
2994/*
2995 * call-seq:
2996 * fileno -> integer
2997 *
2998 * Returns the integer file descriptor for the stream:
2999 *
3000 * $stdin.fileno # => 0
3001 * $stdout.fileno # => 1
3002 * $stderr.fileno # => 2
3003 * File.open('t.txt').fileno # => 10
3004 * f.close
3005 *
3006 */
3007
3008static VALUE
3009rb_io_fileno(VALUE io)
3010{
3011 rb_io_t *fptr = RFILE(io)->fptr;
3012 int fd;
3013
3014 rb_io_check_closed(fptr);
3015 fd = fptr->fd;
3016 return INT2FIX(fd);
3017}
3018
3019int
3021{
3022 if (RB_TYPE_P(io, T_FILE)) {
3023 rb_io_t *fptr = RFILE(io)->fptr;
3024 rb_io_check_closed(fptr);
3025 return fptr->fd;
3026 }
3027 else {
3028 VALUE fileno = rb_check_funcall(io, id_fileno, 0, NULL);
3029 if (!UNDEF_P(fileno)) {
3030 return RB_NUM2INT(fileno);
3031 }
3032 }
3033
3034 rb_raise(rb_eTypeError, "expected IO or #fileno, %"PRIsVALUE" given", rb_obj_class(io));
3035
3037}
3038
3039int
3040rb_io_mode(VALUE io)
3041{
3042 rb_io_t *fptr;
3043 GetOpenFile(io, fptr);
3044 return fptr->mode;
3045}
3046
3047/*
3048 * call-seq:
3049 * pid -> integer or nil
3050 *
3051 * Returns the process ID of a child process associated with the stream,
3052 * which will have been set by IO#popen, or +nil+ if the stream was not
3053 * created by IO#popen:
3054 *
3055 * pipe = IO.popen("-")
3056 * if pipe
3057 * $stderr.puts "In parent, child pid is #{pipe.pid}"
3058 * else
3059 * $stderr.puts "In child, pid is #{$$}"
3060 * end
3061 *
3062 * Output:
3063 *
3064 * In child, pid is 26209
3065 * In parent, child pid is 26209
3066 *
3067 */
3068
3069static VALUE
3070rb_io_pid(VALUE io)
3071{
3072 rb_io_t *fptr;
3073
3074 GetOpenFile(io, fptr);
3075 if (!fptr->pid)
3076 return Qnil;
3077 return PIDT2NUM(fptr->pid);
3078}
3079
3080/*
3081 * :markup: markdown
3082 *
3083 * call-seq:
3084 * path -> string or nil
3085 *
3086 * Returns the string path associated with `self`,
3087 * or `nil` if there is no associated path:
3088 *
3089 * ```ruby
3090 * path = 'doc/maintainers.md'
3091 * fd = File.open(path).fileno # => 6
3092 * IO.new(fd, path: path).path # => "doc/maintainers.md"
3093 * IO.new(fd).path # => nil
3094 * ```
3095 *
3096 */
3097
3098VALUE
3100{
3101 rb_io_t *fptr = RFILE(io)->fptr;
3102
3103 if (!fptr)
3104 return Qnil;
3105
3106 return rb_obj_dup(fptr->pathv);
3107}
3108
3109/*
3110 * call-seq:
3111 * inspect -> string
3112 *
3113 * Returns a string representation of +self+:
3114 *
3115 * f = File.open('t.txt')
3116 * f.inspect # => "#<File:t.txt>"
3117 * f.close
3118 *
3119 */
3120
3121static VALUE
3122rb_io_inspect(VALUE obj)
3123{
3124 rb_io_t *fptr;
3125 VALUE result;
3126 static const char closed[] = " (closed)";
3127
3128 fptr = RFILE(obj)->fptr;
3129 if (!fptr) return rb_any_to_s(obj);
3130 result = rb_str_new_cstr("#<");
3131 rb_str_append(result, rb_class_name(CLASS_OF(obj)));
3132 rb_str_cat2(result, ":");
3133 if (NIL_P(fptr->pathv)) {
3134 if (fptr->fd < 0) {
3135 rb_str_cat(result, closed+1, strlen(closed)-1);
3136 }
3137 else {
3138 rb_str_catf(result, "fd %d", fptr->fd);
3139 }
3140 }
3141 else {
3142 rb_str_append(result, fptr->pathv);
3143 if (fptr->fd < 0) {
3144 rb_str_cat(result, closed, strlen(closed));
3145 }
3146 }
3147 return rb_str_cat2(result, ">");
3148}
3149
3150/*
3151 * call-seq:
3152 * to_io -> self
3153 *
3154 * Returns +self+.
3155 *
3156 */
3157
3158static VALUE
3159rb_io_to_io(VALUE io)
3160{
3161 return io;
3162}
3163
3164/* reading functions */
3165static long
3166read_buffered_data(char *ptr, long len, rb_io_t *fptr)
3167{
3168 int n;
3169
3170 n = READ_DATA_PENDING_COUNT(fptr);
3171 if (n <= 0) return 0;
3172 if (n > len) n = (int)len;
3173 MEMMOVE(ptr, fptr->rbuf.ptr+fptr->rbuf.off, char, n);
3174 fptr->rbuf.off += n;
3175 fptr->rbuf.len -= n;
3176 return n;
3177}
3178
3179static long
3180io_bufread(char *ptr, long len, rb_io_t *fptr, long *read_len)
3181{
3182 long offset = 0;
3183 long n = len;
3184 long c;
3185
3186 *read_len = 0;
3187 if (READ_DATA_PENDING(fptr) == 0) {
3188 while (n > 0) {
3189 again:
3190 rb_io_check_closed(fptr);
3191 c = rb_io_read_memory(fptr, ptr+offset, n);
3192 if (c == 0) break;
3193 if (c < 0) {
3194 if (fptr_wait_readable(fptr))
3195 goto again;
3196 return -1;
3197 }
3198 offset += c;
3199 *read_len = offset;
3200 if ((n -= c) <= 0) break;
3201 }
3202 return len - n;
3203 }
3204
3205 while (n > 0) {
3206 c = read_buffered_data(ptr+offset, n, fptr);
3207 if (c > 0) {
3208 offset += c;
3209 *read_len = offset;
3210 if ((n -= c) <= 0) break;
3211 }
3212 rb_io_check_closed(fptr);
3213 if (io_fillbuf(fptr) < 0) {
3214 break;
3215 }
3216 }
3217 return len - n;
3218}
3219
3220static int io_setstrbuf(VALUE *str, long len);
3221
3223 char *str_ptr;
3224 long offset;
3225 long len;
3226 long read_len;
3227 rb_io_t *fptr;
3228};
3229
3230static VALUE
3231bufread_body(VALUE arg)
3232{
3233 struct bufread_arg *p = (struct bufread_arg *)arg;
3234 p->len = io_bufread(p->str_ptr + p->offset, p->len, p->fptr, &p->read_len);
3235 return Qundef;
3236}
3237
3238static VALUE
3239bufread_timeout(VALUE arg, VALUE error)
3240{
3241 struct bufread_arg *p = (struct bufread_arg *)arg;
3242
3243 if (p->offset + p->read_len > 0) {
3244 VALUE str = rb_str_new(p->str_ptr, p->offset + p->read_len);
3245 io_restore_read_buffer(str, p->fptr);
3246 }
3247 rb_exc_raise(error);
3249}
3250
3251static VALUE
3252bufread_call(VALUE arg)
3253{
3254 struct bufread_arg *p = (struct bufread_arg *)arg;
3255
3256 if (NIL_P(p->fptr->timeout)) {
3257 return bufread_body(arg);
3258 }
3259 return rb_rescue2(bufread_body, arg, bufread_timeout, arg,
3260 rb_eIOTimeoutError, (VALUE)0);
3261}
3262
3263static long
3264io_fread(VALUE str, long offset, long size, rb_io_t *fptr)
3265{
3266 long len;
3267 struct bufread_arg arg;
3268
3269 io_setstrbuf(&str, offset + size);
3270 arg.str_ptr = RSTRING_PTR(str);
3271 arg.offset = offset;
3272 arg.len = size;
3273 arg.read_len = 0;
3274 arg.fptr = fptr;
3275 rb_str_locktmp_ensure(str, bufread_call, (VALUE)&arg);
3276 len = arg.len;
3277 if (len < 0) rb_sys_fail_path(fptr->pathv);
3278 return len;
3279}
3280
3281static long
3282remain_size(rb_io_t *fptr)
3283{
3284 struct stat st;
3285 rb_off_t siz = READ_DATA_PENDING_COUNT(fptr);
3286 rb_off_t pos;
3287
3288 if (fstat(fptr->fd, &st) == 0 && S_ISREG(st.st_mode)
3289#if defined(__HAIKU__)
3290 && (st.st_dev > 3)
3291#endif
3292 )
3293 {
3294 if (io_fflush(fptr) < 0)
3295 rb_sys_fail_on_write(fptr);
3296 pos = lseek(fptr->fd, 0, SEEK_CUR);
3297 if (st.st_size >= pos && pos >= 0) {
3298 siz += st.st_size - pos;
3299 if (siz > LONG_MAX) {
3300 rb_raise(rb_eIOError, "file too big for single read");
3301 }
3302 }
3303 }
3304 else {
3305 siz += BUFSIZ;
3306 }
3307 return (long)siz;
3308}
3309
3310static VALUE
3311io_enc_str(VALUE str, rb_io_t *fptr)
3312{
3313 rb_enc_associate(str, io_read_encoding(fptr));
3314 return str;
3315}
3316
3317static void
3318make_readconv(rb_io_t *fptr, int size)
3319{
3320 if (!fptr->readconv) {
3321 int ecflags;
3322 VALUE ecopts;
3323 const char *sname, *dname;
3324 ecflags = fptr->encs.ecflags & ~ECONV_NEWLINE_DECORATOR_WRITE_MASK;
3325 ecopts = fptr->encs.ecopts;
3326 if (fptr->encs.enc2) {
3327 sname = rb_enc_name(fptr->encs.enc2);
3328 dname = rb_enc_name(io_read_encoding(fptr));
3329 }
3330 else {
3331 sname = dname = "";
3332 }
3333 fptr->readconv = rb_econv_open_opts(sname, dname, ecflags, ecopts);
3334 if (!fptr->readconv)
3335 rb_exc_raise(rb_econv_open_exc(sname, dname, ecflags));
3336 fptr->cbuf.off = 0;
3337 fptr->cbuf.len = 0;
3338 if (size < IO_CBUF_CAPA_MIN) size = IO_CBUF_CAPA_MIN;
3339 fptr->cbuf.capa = size;
3340 fptr->cbuf.ptr = ALLOC_N(char, fptr->cbuf.capa);
3341 }
3342}
3343
3344#define MORE_CHAR_SUSPENDED Qtrue
3345#define MORE_CHAR_FINISHED Qnil
3346static VALUE
3347fill_cbuf(rb_io_t *fptr, int ec_flags)
3348{
3349 const unsigned char *ss, *sp, *se;
3350 unsigned char *ds, *dp, *de;
3352 int putbackable;
3353 int cbuf_len0;
3354 VALUE exc;
3355
3356 ec_flags |= ECONV_PARTIAL_INPUT;
3357
3358 if (fptr->cbuf.len == fptr->cbuf.capa)
3359 return MORE_CHAR_SUSPENDED; /* cbuf full */
3360 if (fptr->cbuf.len == 0)
3361 fptr->cbuf.off = 0;
3362 else if (fptr->cbuf.off + fptr->cbuf.len == fptr->cbuf.capa) {
3363 memmove(fptr->cbuf.ptr, fptr->cbuf.ptr+fptr->cbuf.off, fptr->cbuf.len);
3364 fptr->cbuf.off = 0;
3365 }
3366
3367 cbuf_len0 = fptr->cbuf.len;
3368
3369 while (1) {
3370 ss = sp = (const unsigned char *)fptr->rbuf.ptr + fptr->rbuf.off;
3371 se = sp + fptr->rbuf.len;
3372 ds = dp = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.off + fptr->cbuf.len;
3373 de = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.capa;
3374 res = rb_econv_convert(fptr->readconv, &sp, se, &dp, de, ec_flags);
3375 fptr->rbuf.off += (int)(sp - ss);
3376 fptr->rbuf.len -= (int)(sp - ss);
3377 fptr->cbuf.len += (int)(dp - ds);
3378
3379 putbackable = rb_econv_putbackable(fptr->readconv);
3380 if (putbackable) {
3381 rb_econv_putback(fptr->readconv, (unsigned char *)fptr->rbuf.ptr + fptr->rbuf.off - putbackable, putbackable);
3382 fptr->rbuf.off -= putbackable;
3383 fptr->rbuf.len += putbackable;
3384 }
3385
3386 exc = rb_econv_make_exception(fptr->readconv);
3387 if (!NIL_P(exc))
3388 return exc;
3389
3390 if (cbuf_len0 != fptr->cbuf.len)
3391 return MORE_CHAR_SUSPENDED;
3392
3393 if (res == econv_finished) {
3394 return MORE_CHAR_FINISHED;
3395 }
3396
3397 if (res == econv_source_buffer_empty) {
3398 if (fptr->rbuf.len == 0) {
3399 READ_CHECK(fptr);
3400 if (io_fillbuf(fptr) < 0) {
3401 if (!fptr->readconv) {
3402 return MORE_CHAR_FINISHED;
3403 }
3404 ds = dp = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.off + fptr->cbuf.len;
3405 de = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.capa;
3406 res = rb_econv_convert(fptr->readconv, NULL, NULL, &dp, de, 0);
3407 fptr->cbuf.len += (int)(dp - ds);
3409 break;
3410 }
3411 }
3412 }
3413 }
3414 if (cbuf_len0 != fptr->cbuf.len)
3415 return MORE_CHAR_SUSPENDED;
3416
3417 return MORE_CHAR_FINISHED;
3418}
3419
3420static VALUE
3421more_char(rb_io_t *fptr)
3422{
3423 VALUE v;
3424 v = fill_cbuf(fptr, ECONV_AFTER_OUTPUT);
3425 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED)
3426 rb_exc_raise(v);
3427 return v;
3428}
3429
3430static VALUE
3431io_shift_cbuf(rb_io_t *fptr, int len, VALUE *strp)
3432{
3433 VALUE str = Qnil;
3434 if (strp) {
3435 str = *strp;
3436 if (NIL_P(str)) {
3437 *strp = str = rb_str_new(fptr->cbuf.ptr+fptr->cbuf.off, len);
3438 }
3439 else {
3440 rb_str_cat(str, fptr->cbuf.ptr+fptr->cbuf.off, len);
3441 }
3442 rb_enc_associate(str, fptr->encs.enc);
3443 }
3444 fptr->cbuf.off += len;
3445 fptr->cbuf.len -= len;
3446 /* xxx: set coderange */
3447 if (fptr->cbuf.len == 0)
3448 fptr->cbuf.off = 0;
3449 else if (fptr->cbuf.capa/2 < fptr->cbuf.off) {
3450 memmove(fptr->cbuf.ptr, fptr->cbuf.ptr+fptr->cbuf.off, fptr->cbuf.len);
3451 fptr->cbuf.off = 0;
3452 }
3453 return str;
3454}
3455
3456static int
3457io_setstrbuf(VALUE *str, long len)
3458{
3459 if (NIL_P(*str)) {
3460 *str = rb_str_new(0, len);
3461 return TRUE;
3462 }
3463 else {
3464 VALUE s = StringValue(*str);
3465 rb_str_modify(s);
3466
3467 long clen = RSTRING_LEN(s);
3468 if (clen >= len) {
3469 return FALSE;
3470 }
3471 len -= clen;
3472 }
3473 if ((rb_str_capacity(*str) - (size_t)RSTRING_LEN(*str)) < (size_t)len) {
3475 }
3476 return FALSE;
3477}
3478
3479#define MAX_REALLOC_GAP 4096
3480static void
3481io_shrink_read_string(VALUE str, long n)
3482{
3483 if (rb_str_capacity(str) - n > MAX_REALLOC_GAP) {
3484 rb_str_resize(str, n);
3485 }
3486}
3487
3488static void
3489io_set_read_length(VALUE str, long n, int shrinkable)
3490{
3491 if (RSTRING_LEN(str) != n) {
3492 rb_str_modify(str);
3493 rb_str_set_len(str, n);
3494 if (shrinkable) io_shrink_read_string(str, n);
3495 }
3496}
3497
3498static VALUE
3499read_all(rb_io_t *fptr, long siz, VALUE str)
3500{
3501 long bytes;
3502 long n;
3503 long pos;
3504 rb_encoding *enc;
3505 int cr;
3506 int shrinkable;
3507
3508 if (NEED_READCONV(fptr)) {
3509 int first = !NIL_P(str);
3510 SET_BINARY_MODE(fptr);
3511 shrinkable = io_setstrbuf(&str,0);
3512 make_readconv(fptr, 0);
3513 while (1) {
3514 VALUE v;
3515 if (fptr->cbuf.len) {
3516 if (first) rb_str_set_len(str, first = 0);
3517 io_shift_cbuf(fptr, fptr->cbuf.len, &str);
3518 }
3519 v = fill_cbuf(fptr, 0);
3520 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED) {
3521 if (fptr->cbuf.len) {
3522 if (first) rb_str_set_len(str, first = 0);
3523 io_shift_cbuf(fptr, fptr->cbuf.len, &str);
3524 }
3525 rb_exc_raise(v);
3526 }
3527 if (v == MORE_CHAR_FINISHED) {
3528 clear_readconv(fptr);
3529 if (first) rb_str_set_len(str, first = 0);
3530 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3531 return io_enc_str(str, fptr);
3532 }
3533 }
3534 }
3535
3536 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3537 bytes = 0;
3538 pos = 0;
3539
3540 enc = io_read_encoding(fptr);
3541 cr = 0;
3542
3543 if (siz == 0) {
3544 siz = BUFSIZ;
3545 }
3546 else {
3547 // If `siz` is set, we got it from `stat(2)`.
3548 // We attempt to read one extra byte because:
3549 // - If the file was appended to since then, we'll continue reading.
3550 // - If the file is still the same length, we won't issue a second `io_fread`.
3551 siz++;
3552 }
3553 shrinkable = io_setstrbuf(&str, siz);
3554 for (;;) {
3555 READ_CHECK(fptr);
3556 n = io_fread(str, bytes, siz - bytes, fptr);
3557 if (n == 0 && bytes == 0) {
3558 rb_str_set_len(str, 0);
3559 break;
3560 }
3561 bytes += n;
3562 rb_str_set_len(str, bytes);
3563 if (cr != ENC_CODERANGE_BROKEN)
3564 pos += rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + bytes, enc, &cr);
3565 if (bytes < siz) break;
3566 siz += BUFSIZ;
3567
3568 size_t capa = rb_str_capacity(str);
3569 if (capa < (size_t)RSTRING_LEN(str) + BUFSIZ) {
3570 if (capa < BUFSIZ) {
3571 capa = BUFSIZ;
3572 }
3573 else if (capa > IO_MAX_BUFFER_GROWTH) {
3574 capa = IO_MAX_BUFFER_GROWTH;
3575 }
3577 }
3578 }
3579 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3580 str = io_enc_str(str, fptr);
3581 ENC_CODERANGE_SET(str, cr);
3582 return str;
3583}
3584
3585void
3587{
3588 if (rb_fd_set_nonblock(fptr->fd) != 0) {
3589 rb_sys_fail_path(fptr->pathv);
3590 }
3591}
3592
3593static VALUE
3594io_read_memory_call(VALUE arg)
3595{
3596 struct io_internal_read_struct *iis = (struct io_internal_read_struct *)arg;
3597
3598 VALUE scheduler = rb_fiber_scheduler_current();
3599 if (scheduler != Qnil) {
3600 VALUE result = rb_fiber_scheduler_io_read_memory(scheduler, iis->fptr->self, iis->buf, iis->capa);
3601
3602 if (!UNDEF_P(result)) {
3603 // This is actually returned as a pseudo-VALUE and later cast to a long:
3605 }
3606 }
3607
3608 if (iis->nonblock) {
3609 return rb_io_blocking_region(iis->fptr, internal_read_func, iis);
3610 }
3611 else {
3612 return rb_io_blocking_region_wait(iis->fptr, internal_read_func, iis, RUBY_IO_READABLE);
3613 }
3614}
3615
3616static long
3617io_read_memory_locktmp(VALUE str, struct io_internal_read_struct *iis)
3618{
3619 return (long)rb_str_locktmp_ensure(str, io_read_memory_call, (VALUE)iis);
3620}
3621
3622#define no_exception_p(opts) !rb_opts_exception_p((opts), TRUE)
3623
3624static VALUE
3625io_getpartial(int argc, VALUE *argv, VALUE io, int no_exception, int nonblock)
3626{
3627 rb_io_t *fptr;
3628 VALUE length, str;
3629 long n, len;
3630 struct io_internal_read_struct iis;
3631 int shrinkable;
3632
3633 rb_scan_args(argc, argv, "11", &length, &str);
3634
3635 if ((len = NUM2LONG(length)) < 0) {
3636 rb_raise(rb_eArgError, "negative length %ld given", len);
3637 }
3638
3639 shrinkable = io_setstrbuf(&str, len);
3640
3641 GetOpenFile(io, fptr);
3643
3644 if (len == 0) {
3645 io_set_read_length(str, 0, shrinkable);
3646 return str;
3647 }
3648
3649 if (!nonblock)
3650 READ_CHECK(fptr);
3651 n = read_buffered_data(RSTRING_PTR(str), len, fptr);
3652 if (n <= 0) {
3653 again:
3654 if (nonblock) {
3655 rb_io_set_nonblock(fptr);
3656 }
3657 io_setstrbuf(&str, len);
3658 iis.th = rb_thread_current();
3659 iis.fptr = fptr;
3660 iis.nonblock = nonblock;
3661 iis.fd = fptr->fd;
3662 iis.buf = RSTRING_PTR(str);
3663 iis.capa = len;
3664 iis.timeout = NULL;
3665 n = io_read_memory_locktmp(str, &iis);
3666 if (n < 0) {
3667 int e = errno;
3668 if (!nonblock && fptr_wait_readable(fptr))
3669 goto again;
3670 if (nonblock && (io_again_p(e))) {
3671 if (no_exception)
3672 return sym_wait_readable;
3673 else
3674 rb_readwrite_syserr_fail(RB_IO_WAIT_READABLE,
3675 e, "read would block");
3676 }
3677 rb_syserr_fail_path(e, fptr->pathv);
3678 }
3679 }
3680 io_set_read_length(str, n, shrinkable);
3681
3682 if (n == 0)
3683 return Qnil;
3684 else
3685 return str;
3686}
3687
3688/*
3689 * call-seq:
3690 * readpartial(maxlen) -> string
3691 * readpartial(maxlen, out_string) -> out_string
3692 *
3693 * Reads up to +maxlen+ bytes from the stream;
3694 * returns a string (either a new string or the given +out_string+).
3695 * Its encoding is:
3696 *
3697 * - The unchanged encoding of +out_string+, if +out_string+ is given.
3698 * - ASCII-8BIT, otherwise.
3699 *
3700 * - Contains +maxlen+ bytes from the stream, if available.
3701 * - Otherwise contains all available bytes, if any available.
3702 * - Is an empty string if +maxlen+ is zero.
3703 *
3704 * With the single non-negative integer argument +maxlen+ given,
3705 * returns a new string:
3706 *
3707 * f = File.new('t.txt')
3708 * f.readpartial(20) # => "First line\nSecond l"
3709 * f.readpartial(20) # => "ine\n\nFourth line\n"
3710 * f.readpartial(20) # => "Fifth line\n"
3711 * f.readpartial(20) # Raises EOFError.
3712 * f.close
3713 *
3714 * With both argument +maxlen+ and string argument +out_string+ given,
3715 * returns modified +out_string+:
3716 *
3717 * f = File.new('t.txt')
3718 * s = 'foo'
3719 * f.readpartial(20, s) # => "First line\nSecond l"
3720 * s = 'bar'
3721 * f.readpartial(0, s) # => ""
3722 * f.close
3723 *
3724 * This method is useful for a stream such as a pipe, a socket, or a tty.
3725 * It blocks only when no data is immediately available.
3726 * This means that it blocks only when _all_ of the following are true:
3727 *
3728 * - The byte buffer in the stream is empty.
3729 * - The content of the stream is empty.
3730 * - The stream is not at EOF.
3731 *
3732 * When blocked, the method waits for either more data or EOF on the stream:
3733 *
3734 * - If more data is read, the method returns the data.
3735 * - If EOF is reached, the method raises EOFError.
3736 *
3737 * When not blocked, the method responds immediately:
3738 *
3739 * - Returns data from the buffer if there is any.
3740 * - Otherwise returns data from the stream if there is any.
3741 * - Otherwise raises EOFError if the stream has reached EOF.
3742 *
3743 * Note that this method is similar to sysread. The differences are:
3744 *
3745 * - If the byte buffer is not empty, read from the byte buffer
3746 * instead of "sysread for buffered IO (IOError)".
3747 * - It doesn't cause Errno::EWOULDBLOCK and Errno::EINTR. When
3748 * readpartial meets EWOULDBLOCK and EINTR by read system call,
3749 * readpartial retries the system call.
3750 *
3751 * The latter means that readpartial is non-blocking-flag insensitive.
3752 * It blocks on the situation IO#sysread causes Errno::EWOULDBLOCK as
3753 * if the fd is blocking mode.
3754 *
3755 * Examples:
3756 *
3757 * # # Returned Buffer Content Pipe Content
3758 * r, w = IO.pipe #
3759 * w << 'abc' # "" "abc".
3760 * r.readpartial(4096) # => "abc" "" ""
3761 * r.readpartial(4096) # (Blocks because buffer and pipe are empty.)
3762 *
3763 * # # Returned Buffer Content Pipe Content
3764 * r, w = IO.pipe #
3765 * w << 'abc' # "" "abc"
3766 * w.close # "" "abc" EOF
3767 * r.readpartial(4096) # => "abc" "" EOF
3768 * r.readpartial(4096) # raises EOFError
3769 *
3770 * # # Returned Buffer Content Pipe Content
3771 * r, w = IO.pipe #
3772 * w << "abc\ndef\n" # "" "abc\ndef\n"
3773 * r.gets # => "abc\n" "def\n" ""
3774 * w << "ghi\n" # "def\n" "ghi\n"
3775 * r.readpartial(4096) # => "def\n" "" "ghi\n"
3776 * r.readpartial(4096) # => "ghi\n" "" ""
3777 *
3778 */
3779
3780static VALUE
3781io_readpartial(int argc, VALUE *argv, VALUE io)
3782{
3783 VALUE ret;
3784
3785 ret = io_getpartial(argc, argv, io, Qnil, 0);
3786 if (NIL_P(ret))
3787 rb_eof_error();
3788 return ret;
3789}
3790
3791static VALUE
3792io_nonblock_eof(int no_exception)
3793{
3794 if (!no_exception) {
3795 rb_eof_error();
3796 }
3797 return Qnil;
3798}
3799
3800/* :nodoc: */
3801static VALUE
3802io_read_nonblock(rb_execution_context_t *ec, VALUE io, VALUE length, VALUE str, VALUE ex)
3803{
3804 rb_io_t *fptr;
3805 long n, len;
3806 struct io_internal_read_struct iis;
3807 int shrinkable;
3808
3809 if ((len = NUM2LONG(length)) < 0) {
3810 rb_raise(rb_eArgError, "negative length %ld given", len);
3811 }
3812
3813 shrinkable = io_setstrbuf(&str, len);
3814 rb_bool_expected(ex, "exception", TRUE);
3815
3816 GetOpenFile(io, fptr);
3818
3819 if (len == 0) {
3820 io_set_read_length(str, 0, shrinkable);
3821 return str;
3822 }
3823
3824 n = read_buffered_data(RSTRING_PTR(str), len, fptr);
3825 if (n <= 0) {
3826 rb_fd_set_nonblock(fptr->fd);
3827 shrinkable |= io_setstrbuf(&str, len);
3828 iis.fptr = fptr;
3829 iis.nonblock = 1;
3830 iis.fd = fptr->fd;
3831 iis.buf = RSTRING_PTR(str);
3832 iis.capa = len;
3833 iis.timeout = NULL;
3834 n = io_read_memory_locktmp(str, &iis);
3835 if (n < 0) {
3836 int e = errno;
3837 if (io_again_p(e)) {
3838 if (!ex) return sym_wait_readable;
3839 rb_readwrite_syserr_fail(RB_IO_WAIT_READABLE,
3840 e, "read would block");
3841 }
3842 rb_syserr_fail_path(e, fptr->pathv);
3843 }
3844 }
3845 io_set_read_length(str, n, shrinkable);
3846
3847 if (n == 0) {
3848 if (!ex) return Qnil;
3849 rb_eof_error();
3850 }
3851
3852 return str;
3853}
3854
3855/* :nodoc: */
3856static VALUE
3857io_write_nonblock(rb_execution_context_t *ec, VALUE io, VALUE str, VALUE ex)
3858{
3859 rb_io_t *fptr;
3860 long n;
3861
3862 if (!RB_TYPE_P(str, T_STRING))
3863 str = rb_obj_as_string(str);
3864 rb_bool_expected(ex, "exception", TRUE);
3865
3866 io = GetWriteIO(io);
3867 GetOpenFile(io, fptr);
3869
3870 if (io_fflush(fptr) < 0)
3871 rb_sys_fail_on_write(fptr);
3872
3873 rb_fd_set_nonblock(fptr->fd);
3874 n = write(fptr->fd, RSTRING_PTR(str), RSTRING_LEN(str));
3875 RB_GC_GUARD(str);
3876
3877 if (n < 0) {
3878 int e = errno;
3879 if (io_again_p(e)) {
3880 if (!ex) {
3881 return sym_wait_writable;
3882 }
3883 else {
3884 rb_readwrite_syserr_fail(RB_IO_WAIT_WRITABLE, e, "write would block");
3885 }
3886 }
3887 rb_syserr_fail_path(e, fptr->pathv);
3888 }
3889
3890 return LONG2FIX(n);
3891}
3892
3893/*
3894 * call-seq:
3895 * read(maxlen = nil, out_string = nil) -> new_string, out_string, or nil
3896 *
3897 * Reads bytes from the stream; the stream must be opened for reading
3898 * (see {Access Modes}[rdoc-ref:File@Access+Modes]):
3899 *
3900 * - If +maxlen+ is +nil+, reads all bytes using the stream's data mode.
3901 * - Otherwise reads up to +maxlen+ bytes in binary mode.
3902 *
3903 * Returns a string (either a new string or the given +out_string+)
3904 * containing the bytes read.
3905 * The encoding of the string depends on both +maxLen+ and +out_string+:
3906 *
3907 * - +maxlen+ is +nil+: uses internal encoding of +self+
3908 * (regardless of whether +out_string+ was given).
3909 * - +maxlen+ not +nil+:
3910 *
3911 * - +out_string+ given: encoding of +out_string+ not modified.
3912 * - +out_string+ not given: ASCII-8BIT is used.
3913 *
3914 * <b>Without Argument +out_string+</b>
3915 *
3916 * When argument +out_string+ is omitted,
3917 * the returned value is a new string:
3918 *
3919 * f = File.new('t.txt')
3920 * f.read
3921 * # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3922 * f.rewind
3923 * f.read(30) # => "First line\r\nSecond line\r\n\r\nFou"
3924 * f.read(30) # => "rth line\r\nFifth line\r\n"
3925 * f.read(30) # => nil
3926 * f.close
3927 *
3928 * If +maxlen+ is zero, returns an empty string.
3929 *
3930 * <b> With Argument +out_string+</b>
3931 *
3932 * When argument +out_string+ is given,
3933 * the returned value is +out_string+, whose content is replaced:
3934 *
3935 * f = File.new('t.txt')
3936 * s = 'foo' # => "foo"
3937 * f.read(nil, s) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3938 * s # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3939 * f.rewind
3940 * s = 'bar'
3941 * f.read(30, s) # => "First line\r\nSecond line\r\n\r\nFou"
3942 * s # => "First line\r\nSecond line\r\n\r\nFou"
3943 * s = 'baz'
3944 * f.read(30, s) # => "rth line\r\nFifth line\r\n"
3945 * s # => "rth line\r\nFifth line\r\n"
3946 * s = 'bat'
3947 * f.read(30, s) # => nil
3948 * s # => ""
3949 * f.close
3950 *
3951 * Note that this method behaves like the fread() function in C.
3952 * This means it retries to invoke read(2) system calls to read data
3953 * with the specified maxlen (or until EOF).
3954 *
3955 * This behavior is preserved even if the stream is in non-blocking mode.
3956 * (This method is non-blocking-flag insensitive as other methods.)
3957 *
3958 * If you need the behavior like a single read(2) system call,
3959 * consider #readpartial, #read_nonblock, and #sysread.
3960 *
3961 * Related: IO#write.
3962 */
3963
3964static VALUE
3965io_read(int argc, VALUE *argv, VALUE io)
3966{
3967 rb_io_t *fptr;
3968 long n, len;
3969 VALUE length, str;
3970 int shrinkable;
3971#if RUBY_CRLF_ENVIRONMENT
3972 int previous_mode;
3973#endif
3974
3975 rb_scan_args(argc, argv, "02", &length, &str);
3976
3977 if (NIL_P(length)) {
3978 GetOpenFile(io, fptr);
3980 return read_all(fptr, remain_size(fptr), str);
3981 }
3982 len = NUM2LONG(length);
3983 if (len < 0) {
3984 rb_raise(rb_eArgError, "negative length %ld given", len);
3985 }
3986
3987 shrinkable = io_setstrbuf(&str,len);
3988
3989 GetOpenFile(io, fptr);
3991 if (len == 0) {
3992 io_set_read_length(str, 0, shrinkable);
3993 return str;
3994 }
3995
3996 READ_CHECK(fptr);
3997#if RUBY_CRLF_ENVIRONMENT
3998 previous_mode = set_binary_mode_with_seek_cur(fptr);
3999#endif
4000 n = io_fread(str, 0, len, fptr);
4001 io_set_read_length(str, n, shrinkable);
4002#if RUBY_CRLF_ENVIRONMENT
4003 if (previous_mode == O_TEXT) {
4004 setmode(fptr->fd, O_TEXT);
4005 }
4006#endif
4007 if (n == 0) return Qnil;
4008
4009 return str;
4010}
4011
4012static void
4013rscheck(const char *rsptr, long rslen, VALUE rs)
4014{
4015 if (!rs) return;
4016 if (RSTRING_PTR(rs) != rsptr && RSTRING_LEN(rs) != rslen)
4017 rb_raise(rb_eRuntimeError, "rs modified");
4018}
4019
4020static const char *
4021search_delim(const char *p, long len, int delim, rb_encoding *enc)
4022{
4023 if (rb_enc_mbminlen(enc) == 1) {
4024 p = memchr(p, delim, len);
4025 if (p) return p + 1;
4026 }
4027 else {
4028 const char *end = p + len;
4029 while (p < end) {
4030 int r = rb_enc_precise_mbclen(p, end, enc);
4031 if (!MBCLEN_CHARFOUND_P(r)) {
4032 p += rb_enc_mbminlen(enc);
4033 continue;
4034 }
4035 int n = MBCLEN_CHARFOUND_LEN(r);
4036 if (rb_enc_mbc_to_codepoint(p, end, enc) == (unsigned int)delim) {
4037 return p + n;
4038 }
4039 p += n;
4040 }
4041 }
4042 return NULL;
4043}
4044
4045static int
4046read_raw_character(rb_io_t *fptr, rb_encoding *enc, char *buf)
4047{
4048 int n = 0;
4049 int r;
4050
4051 do {
4052 if (!READ_DATA_PENDING(fptr)) {
4053 READ_CHECK(fptr);
4054 if (io_fillbuf(fptr) < 0) break;
4055 }
4056 buf[n++] = *READ_DATA_PENDING_PTR(fptr);
4057 fptr->rbuf.off++;
4058 fptr->rbuf.len--;
4059 r = rb_enc_precise_mbclen(buf, buf + n, enc);
4060 } while (MBCLEN_NEEDMORE_P(r) && n < rb_enc_mbmaxlen(enc));
4061
4062 return n;
4063}
4064
4065static void
4066unread_raw_character(rb_io_t *fptr, const char *buf, int len)
4067{
4068 if (fptr->rbuf.capa - fptr->rbuf.len < len) {
4069 if (fptr->rbuf.capa > INT_MAX - len)
4070 rb_raise(rb_eIOError, "ungetbyte failed");
4071 fptr->rbuf.capa += len;
4072 REALLOC_N(fptr->rbuf.ptr, char, fptr->rbuf.capa);
4073 }
4074 io_ungetbyte(rb_str_new(buf, len), fptr);
4075}
4076
4077static const char *
4078search_wide_delim(const char *p, long len, const char *delim, int width)
4079{
4080 const char *e = p + len;
4081 int index = 0;
4082
4083 while (index < width && delim[index] == 0) index++;
4084 if (index == width) index = 0;
4085
4086 const char *candidate = p + index;
4087 while (candidate < e) {
4088 candidate = memchr(candidate, (unsigned char)delim[index], e - candidate);
4089 if (candidate == NULL) break;
4090 const char *start = candidate - index;
4091 if ((start - p) % width == 0 && start + width <= e &&
4092 memcmp(start, delim, width) == 0) {
4093 return start;
4094 }
4095 candidate++;
4096 }
4097 return NULL;
4098}
4099
4100static int
4101appendline(rb_io_t *fptr, int delim, VALUE *strp, long *lp, rb_encoding *enc)
4102{
4103 VALUE str = *strp;
4104 long limit = *lp;
4105
4106 if (NEED_READCONV(fptr)) {
4107 SET_BINARY_MODE(fptr);
4108 make_readconv(fptr, 0);
4109 do {
4110 const char *p, *e;
4111 int searchlen = READ_CHAR_PENDING_COUNT(fptr);
4112 if (searchlen) {
4113 p = READ_CHAR_PENDING_PTR(fptr);
4114 if (0 < limit && limit < searchlen)
4115 searchlen = (int)limit;
4116 e = search_delim(p, searchlen, delim, enc);
4117 if (e) {
4118 int len = (int)(e-p);
4119 if (NIL_P(str))
4120 *strp = str = rb_str_new(p, len);
4121 else
4122 rb_str_buf_cat(str, p, len);
4123 fptr->cbuf.off += len;
4124 fptr->cbuf.len -= len;
4125 limit -= len;
4126 *lp = limit;
4127 return delim;
4128 }
4129
4130 if (NIL_P(str))
4131 *strp = str = rb_str_new(p, searchlen);
4132 else
4133 rb_str_buf_cat(str, p, searchlen);
4134 fptr->cbuf.off += searchlen;
4135 fptr->cbuf.len -= searchlen;
4136 limit -= searchlen;
4137
4138 if (limit == 0) {
4139 *lp = limit;
4140 return (unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
4141 }
4142 }
4143 } while (more_char(fptr) != MORE_CHAR_FINISHED);
4144 clear_readconv(fptr);
4145 *lp = limit;
4146 return EOF;
4147 }
4148
4149 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4150 if (rb_enc_mbminlen(enc) != 1) {
4151 char buf[ONIGENC_CODE_TO_MBC_MAXLEN];
4152 int len;
4153
4154 if (limit < 0) {
4155 int width = rb_enc_mbminlen(enc);
4156 int delim_len = rb_enc_codelen(delim, enc);
4157
4158 if (delim_len == width) {
4159 rb_enc_mbcput(delim, buf, enc);
4160 for (;;) {
4161 if (!READ_DATA_PENDING(fptr)) {
4162 READ_CHECK(fptr);
4163 if (io_fillbuf(fptr) < 0) return EOF;
4164 }
4165 long pending = READ_DATA_PENDING_COUNT(fptr);
4166 long complete = pending - pending % width;
4167 const char *p = READ_DATA_PENDING_PTR(fptr);
4168 const char *q = complete ? search_wide_delim(p, complete, buf, width) : NULL;
4169 long take = q ? q - p + width : complete;
4170
4171 if (take > 0) {
4172 if (NIL_P(str))
4173 *strp = str = rb_str_buf_new(0);
4174 rb_str_buf_cat(str, p, take);
4175 fptr->rbuf.off += (int)take;
4176 fptr->rbuf.len -= (int)take;
4177 }
4178 if (q) return delim;
4179 if (complete == pending) continue;
4180
4181 len = read_raw_character(fptr, enc, buf);
4182 if (len == 0) return EOF;
4183 if (NIL_P(str))
4184 *strp = str = rb_str_buf_new(0);
4185 rb_str_buf_cat(str, buf, len);
4186 int r = rb_enc_precise_mbclen(buf, buf + len, enc);
4187 if (MBCLEN_CHARFOUND_P(r) &&
4188 rb_enc_mbc_to_codepoint(buf, buf + len, enc) == (unsigned int)delim)
4189 return delim;
4190 }
4191 }
4192 }
4193
4194 while ((len = read_raw_character(fptr, enc, buf)) > 0) {
4195 if (NIL_P(str))
4196 *strp = str = rb_str_buf_new(0);
4197 rb_str_buf_cat(str, buf, len);
4198 if (limit > 0) {
4199 if (len > limit) {
4200 *lp = 0;
4201 return (unsigned char)buf[len - 1];
4202 }
4203 *lp = limit -= len;
4204 }
4205 int r = rb_enc_precise_mbclen(buf, buf + len, enc);
4206 if (MBCLEN_CHARFOUND_P(r) &&
4207 rb_enc_mbc_to_codepoint(buf, buf + len, enc) == (unsigned int)delim)
4208 return delim;
4209 if (limit == 0)
4210 return (unsigned char)buf[len - 1];
4211 }
4212 *lp = limit;
4213 return EOF;
4214 }
4215 do {
4216 long pending = READ_DATA_PENDING_COUNT(fptr);
4217 if (pending > 0) {
4218 const char *p = READ_DATA_PENDING_PTR(fptr);
4219 const char *e;
4220 long last;
4221
4222 if (limit > 0 && pending > limit) pending = limit;
4223 e = search_delim(p, pending, delim, enc);
4224 if (e) pending = e - p;
4225 if (!NIL_P(str)) {
4226 last = RSTRING_LEN(str);
4227 rb_str_resize(str, last + pending);
4228 }
4229 else {
4230 last = 0;
4231 *strp = str = rb_str_buf_new(pending);
4232 rb_str_set_len(str, pending);
4233 }
4234 read_buffered_data(RSTRING_PTR(str) + last, pending, fptr); /* must not fail */
4235 limit -= pending;
4236 *lp = limit;
4237 if (e) return delim;
4238 if (limit == 0)
4239 return (unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
4240 }
4241 READ_CHECK(fptr);
4242 } while (io_fillbuf(fptr) >= 0);
4243 *lp = limit;
4244 return EOF;
4245}
4246
4247static inline int
4248swallow(rb_io_t *fptr, int term)
4249{
4250 if (NEED_READCONV(fptr)) {
4251 rb_encoding *enc = io_read_encoding(fptr);
4252 int needconv = rb_enc_mbminlen(enc) != 1;
4253 SET_BINARY_MODE(fptr);
4254 make_readconv(fptr, 0);
4255 do {
4256 size_t cnt;
4257 while ((cnt = READ_CHAR_PENDING_COUNT(fptr)) > 0) {
4258 const char *p = READ_CHAR_PENDING_PTR(fptr);
4259 int i;
4260 if (!needconv) {
4261 if (*p != term) return TRUE;
4262 i = (int)cnt;
4263 while (--i && *++p == term);
4264 }
4265 else {
4266 const char *e = p + cnt;
4267 if (rb_enc_ascget(p, e, &i, enc) != term) return TRUE;
4268 while ((p += i) < e && rb_enc_ascget(p, e, &i, enc) == term);
4269 i = (int)(e - p);
4270 }
4271 io_shift_cbuf(fptr, (int)cnt - i, NULL);
4272 }
4273 } while (more_char(fptr) != MORE_CHAR_FINISHED);
4274 return FALSE;
4275 }
4276
4277 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4278 rb_encoding *enc = io_read_encoding(fptr);
4279 int widechar = rb_enc_mbminlen(enc) != 1;
4280 if (widechar) {
4281 char buf[ONIGENC_CODE_TO_MBC_MAXLEN];
4282 int len;
4283
4284 while ((len = read_raw_character(fptr, enc, buf)) > 0) {
4285 if (rb_enc_ascget(buf, buf + len, NULL, enc) != term) {
4286 unread_raw_character(fptr, buf, len);
4287 return TRUE;
4288 }
4289 }
4290 return FALSE;
4291 }
4292 do {
4293 size_t cnt;
4294 while ((cnt = READ_DATA_PENDING_COUNT(fptr)) > 0) {
4295 char buf[1024];
4296 const char *p = READ_DATA_PENDING_PTR(fptr);
4297 int i;
4298 if (cnt > sizeof buf) cnt = sizeof buf;
4299 if (*p != term) return TRUE;
4300 i = (int)cnt;
4301 while (--i && *++p == term);
4302 if (!read_buffered_data(buf, cnt - i, fptr)) /* must not fail */
4303 rb_sys_fail_path(fptr->pathv);
4304 }
4305 READ_CHECK(fptr);
4306 } while (io_fillbuf(fptr) == 0);
4307 return FALSE;
4308}
4309
4310static VALUE
4311rb_io_getline_fast(rb_io_t *fptr, rb_encoding *enc, int chomp)
4312{
4313 VALUE str = Qnil;
4314 int len = 0;
4315 long pos = 0;
4316 int cr = 0;
4317
4318 do {
4319 int pending = READ_DATA_PENDING_COUNT(fptr);
4320
4321 if (pending > 0) {
4322 const char *p = READ_DATA_PENDING_PTR(fptr);
4323 const char *e;
4324 int chomplen = 0;
4325
4326 e = memchr(p, '\n', pending);
4327 if (e) {
4328 pending = (int)(e - p + 1);
4329 if (chomp) {
4330 chomplen = (pending > 1 && *(e-1) == '\r') + 1;
4331 }
4332 }
4333 if (NIL_P(str)) {
4334 str = rb_str_new(p, pending - chomplen);
4335 fptr->rbuf.off += pending;
4336 fptr->rbuf.len -= pending;
4337 }
4338 else {
4339 rb_str_resize(str, len + pending - chomplen);
4340 read_buffered_data(RSTRING_PTR(str)+len, pending - chomplen, fptr);
4341 fptr->rbuf.off += chomplen;
4342 fptr->rbuf.len -= chomplen;
4343 if (pending == 1 && chomplen == 1 && len > 0) {
4344 if (RSTRING_PTR(str)[len-1] == '\r') {
4345 rb_str_resize(str, --len);
4346 break;
4347 }
4348 }
4349 }
4350 len += pending - chomplen;
4351 if (cr != ENC_CODERANGE_BROKEN)
4352 pos += rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + len, enc, &cr);
4353 if (e) break;
4354 }
4355 READ_CHECK(fptr);
4356 } while (io_fillbuf(fptr) >= 0);
4357 if (NIL_P(str)) return Qnil;
4358
4359 str = io_enc_str(str, fptr);
4360 ENC_CODERANGE_SET(str, cr);
4361 fptr->lineno++;
4362
4363 return str;
4364}
4365
4367 VALUE io;
4368 VALUE rs;
4369 long limit;
4370 unsigned int chomp: 1;
4371};
4372
4373static void
4374extract_getline_opts(VALUE opts, struct getline_arg *args)
4375{
4376 int chomp = FALSE;
4377 if (!NIL_P(opts)) {
4378 static ID kwds[1];
4379 VALUE vchomp;
4380 if (!kwds[0]) {
4381 kwds[0] = rb_intern_const("chomp");
4382 }
4383 rb_get_kwargs(opts, kwds, 0, -2, &vchomp);
4384 chomp = (!UNDEF_P(vchomp)) && RTEST(vchomp);
4385 }
4386 args->chomp = chomp;
4387}
4388
4389static void
4390extract_getline_args(int argc, VALUE *argv, struct getline_arg *args)
4391{
4392 VALUE rs = rb_rs, lim = Qnil;
4393
4394 if (argc == 1) {
4395 VALUE tmp = Qnil;
4396
4397 if (NIL_P(argv[0]) || !NIL_P(tmp = rb_check_string_type(argv[0]))) {
4398 rs = tmp;
4399 }
4400 else {
4401 lim = argv[0];
4402 }
4403 }
4404 else if (2 <= argc) {
4405 rs = argv[0], lim = argv[1];
4406 if (!NIL_P(rs))
4407 StringValue(rs);
4408 }
4409 args->rs = rs;
4410 args->limit = NIL_P(lim) ? -1L : NUM2LONG(lim);
4411}
4412
4413static void
4414check_getline_args(VALUE *rsp, long *limit, VALUE io)
4415{
4416 rb_io_t *fptr;
4417 VALUE rs = *rsp;
4418
4419 if (!NIL_P(rs)) {
4420 rb_encoding *enc_rs, *enc_io;
4421
4422 GetOpenFile(io, fptr);
4423 enc_rs = rb_enc_get(rs);
4424 enc_io = io_read_encoding(fptr);
4425 if (enc_io != enc_rs &&
4426 (!is_ascii_string(rs) ||
4427 (RSTRING_LEN(rs) > 0 && !rb_enc_asciicompat(enc_io)))) {
4428 if (rs == rb_default_rs) {
4429 rs = rb_enc_str_new(0, 0, enc_io);
4430 rb_str_buf_cat_ascii(rs, "\n");
4431 *rsp = rs;
4432 }
4433 else {
4434 rb_raise(rb_eArgError, "encoding mismatch: %s IO with %s RS",
4435 rb_enc_name(enc_io),
4436 rb_enc_name(enc_rs));
4437 }
4438 }
4439 }
4440}
4441
4442static void
4443prepare_getline_args(int argc, VALUE *argv, struct getline_arg *args, VALUE io)
4444{
4445 VALUE opts;
4446 argc = rb_scan_args(argc, argv, "02:", NULL, NULL, &opts);
4447 extract_getline_args(argc, argv, args);
4448 extract_getline_opts(opts, args);
4449 check_getline_args(&args->rs, &args->limit, io);
4450}
4451
4452static VALUE
4453rb_io_getline_0(VALUE rs, long limit, int chomp, rb_io_t *fptr)
4454{
4455 VALUE str = Qnil;
4456 int nolimit = 0;
4457 rb_encoding *enc;
4458
4460 if (NIL_P(rs) && limit < 0) {
4461 str = read_all(fptr, 0, Qnil);
4462 if (RSTRING_LEN(str) == 0) return Qnil;
4463 }
4464 else if (limit == 0) {
4465 return rb_enc_str_new(0, 0, io_read_encoding(fptr));
4466 }
4467 else if (rs == rb_default_rs && limit < 0 && !NEED_READCONV(fptr) &&
4468 rb_enc_asciicompat(enc = io_read_encoding(fptr))) {
4469 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4470 return rb_io_getline_fast(fptr, enc, chomp);
4471 }
4472 else {
4473 int c, newline = -1;
4474 const char *rsptr = 0;
4475 long rslen = 0;
4476 int rspara = 0;
4477 int extra_limit = 16;
4478 int chomp_cr = chomp;
4479
4480 SET_BINARY_MODE(fptr);
4481 enc = io_read_encoding(fptr);
4482
4483 if (!NIL_P(rs)) {
4484 rslen = RSTRING_LEN(rs);
4485 if (rslen == 0) {
4486 rsptr = "\n\n";
4487 rslen = 2;
4488 rspara = 1;
4489 swallow(fptr, '\n');
4490 rs = 0;
4491 if (!rb_enc_asciicompat(enc)) {
4492 rs = rb_usascii_str_new(rsptr, rslen);
4493 rs = rb_str_conv_enc(rs, 0, enc);
4494 OBJ_FREEZE(rs);
4495 rsptr = RSTRING_PTR(rs);
4496 rslen = RSTRING_LEN(rs);
4497 }
4498 newline = '\n';
4499 }
4500 else if (rb_enc_mbminlen(enc) == 1) {
4501 rsptr = RSTRING_PTR(rs);
4502 newline = (unsigned char)rsptr[rslen - 1];
4503 }
4504 else {
4505 rs = rb_str_conv_enc(rs, 0, enc);
4506 rsptr = RSTRING_PTR(rs);
4507 const char *e = rsptr + rslen;
4508 const char *last = rb_enc_prev_char(rsptr, e, e, enc);
4509 int n;
4510 newline = rb_enc_codepoint_len(last, e, &n, enc);
4511 if (last + n != e) rb_raise(rb_eArgError, "broken separator");
4512 }
4513 chomp_cr = chomp && newline == '\n' && rslen == rb_enc_mbminlen(enc);
4514 }
4515
4516 /* MS - Optimization */
4517 while ((c = appendline(fptr, newline, &str, &limit, enc)) != EOF) {
4518 const char *s, *p, *pp, *e;
4519
4520 if (c == newline && RSTRING_LEN(str) >= rslen) {
4521 s = RSTRING_PTR(str);
4522 e = RSTRING_END(str);
4523 p = e - rslen;
4524 if (at_char_boundary(s, p, e, enc)) {
4525 if (!rspara) rscheck(rsptr, rslen, rs);
4526 if (memcmp(p, rsptr, rslen) == 0) {
4527 if (chomp) {
4528 if (chomp_cr && p > s && *(p-1) == '\r') --p;
4529 rb_str_set_len(str, p - s);
4530 }
4531 break;
4532 }
4533 }
4534 }
4535 if (limit == 0) {
4536 s = RSTRING_PTR(str);
4537 p = RSTRING_END(str);
4538 pp = rb_enc_prev_char(s, p, p, enc);
4539 if (extra_limit && pp &&
4540 MBCLEN_NEEDMORE_P(rb_enc_precise_mbclen(pp, p, enc))) {
4541 /* relax the limit while incomplete character.
4542 * extra_limit limits the relax length */
4543 limit = 1;
4544 extra_limit--;
4545 }
4546 else {
4547 nolimit = 1;
4548 break;
4549 }
4550 }
4551 }
4552
4553 if (rspara && c != EOF)
4554 swallow(fptr, '\n');
4555 if (!NIL_P(str))
4556 str = io_enc_str(str, fptr);
4557 }
4558
4559 if (!NIL_P(str) && !nolimit) {
4560 fptr->lineno++;
4561 }
4562
4563 return str;
4564}
4565
4566static VALUE
4567rb_io_getline_1(VALUE rs, long limit, int chomp, VALUE io)
4568{
4569 rb_io_t *fptr;
4570 int old_lineno, new_lineno;
4571 VALUE str;
4572
4573 GetOpenFile(io, fptr);
4574 old_lineno = fptr->lineno;
4575 str = rb_io_getline_0(rs, limit, chomp, fptr);
4576 if (!NIL_P(str) && (new_lineno = fptr->lineno) != old_lineno) {
4577 if (io == ARGF.current_file) {
4578 ARGF.lineno += new_lineno - old_lineno;
4579 ARGF.last_lineno = ARGF.lineno;
4580 }
4581 else {
4582 ARGF.last_lineno = new_lineno;
4583 }
4584 }
4585
4586 return str;
4587}
4588
4589static VALUE
4590rb_io_getline(int argc, VALUE *argv, VALUE io)
4591{
4592 struct getline_arg args;
4593
4594 prepare_getline_args(argc, argv, &args, io);
4595 return rb_io_getline_1(args.rs, args.limit, args.chomp, io);
4596}
4597
4598VALUE
4600{
4601 return rb_io_getline_1(rb_default_rs, -1, FALSE, io);
4602}
4603
4604VALUE
4605rb_io_gets_limit_internal(VALUE io, long limit)
4606{
4607 rb_io_t *fptr;
4608 GetOpenFile(io, fptr);
4609 return rb_io_getline_0(rb_default_rs, limit, FALSE, fptr);
4610}
4611
4612VALUE
4613rb_io_gets_internal(VALUE io)
4614{
4615 return rb_io_gets_limit_internal(io, -1);
4616}
4617
4618/*
4619 * call-seq:
4620 * gets(sep = $/, chomp: false) -> string or nil
4621 * gets(limit, chomp: false) -> string or nil
4622 * gets(sep, limit, chomp: false) -> string or nil
4623 *
4624 * Reads and returns a line from the stream;
4625 * assigns the return value to <tt>$_</tt>.
4626 * See {Line IO}[rdoc-ref:IO@Line+IO].
4627 *
4628 * With no arguments given, returns the next line
4629 * as determined by line separator <tt>$/</tt>, or +nil+ if none:
4630 *
4631 * f = File.open('t.txt')
4632 * f.gets # => "First line\n"
4633 * $_ # => "First line\n"
4634 * f.gets # => "\n"
4635 * f.gets # => "Fourth line\n"
4636 * f.gets # => "Fifth line\n"
4637 * f.gets # => nil
4638 * f.close
4639 *
4640 * With only string argument +sep+ given,
4641 * returns the next line as determined by line separator +sep+,
4642 * or +nil+ if none;
4643 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4644 *
4645 * f = File.new('t.txt')
4646 * f.gets('l') # => "First l"
4647 * f.gets('li') # => "ine\nSecond li"
4648 * f.gets('lin') # => "ne\n\nFourth lin"
4649 * f.gets # => "e\n"
4650 * f.close
4651 *
4652 * The two special values for +sep+ are honored:
4653 *
4654 * f = File.new('t.txt')
4655 * # Get all.
4656 * f.gets(nil) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
4657 * f.rewind
4658 * # Get paragraph (up to two line separators).
4659 * f.gets('') # => "First line\nSecond line\n\n"
4660 * f.close
4661 *
4662 * With only integer argument +limit+ given,
4663 * limits the number of bytes in the line;
4664 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4665 *
4666 * # No more than one line.
4667 * File.open('t.txt') {|f| f.gets(10) } # => "First line"
4668 * File.open('t.txt') {|f| f.gets(11) } # => "First line\n"
4669 * File.open('t.txt') {|f| f.gets(12) } # => "First line\n"
4670 *
4671 * With arguments +sep+ and +limit+ given,
4672 * combines the two behaviors
4673 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
4674 *
4675 * Optional keyword argument +chomp+ specifies whether line separators
4676 * are to be omitted:
4677 *
4678 * f = File.open('t.txt')
4679 * # Chomp the lines.
4680 * f.gets(chomp: true) # => "First line"
4681 * f.gets(chomp: true) # => "Second line"
4682 * f.gets(chomp: true) # => ""
4683 * f.gets(chomp: true) # => "Fourth line"
4684 * f.gets(chomp: true) # => "Fifth line"
4685 * f.gets(chomp: true) # => nil
4686 * f.close
4687 *
4688 */
4689
4690static VALUE
4691rb_io_gets_m(int argc, VALUE *argv, VALUE io)
4692{
4693 VALUE str;
4694
4695 str = rb_io_getline(argc, argv, io);
4696 rb_lastline_set(str);
4697
4698 return str;
4699}
4700
4701/*
4702 * call-seq:
4703 * lineno -> integer
4704 *
4705 * Returns the current line number for the stream;
4706 * see {Line Number}[rdoc-ref:IO@Line+Number].
4707 *
4708 */
4709
4710static VALUE
4711rb_io_lineno(VALUE io)
4712{
4713 rb_io_t *fptr;
4714
4715 GetOpenFile(io, fptr);
4717 return INT2NUM(fptr->lineno);
4718}
4719
4720/*
4721 * call-seq:
4722 * lineno = integer -> integer
4723 *
4724 * Sets and returns the line number for the stream;
4725 * see {Line Number}[rdoc-ref:IO@Line+Number].
4726 *
4727 */
4728
4729static VALUE
4730rb_io_set_lineno(VALUE io, VALUE lineno)
4731{
4732 rb_io_t *fptr;
4733
4734 GetOpenFile(io, fptr);
4736 fptr->lineno = NUM2INT(lineno);
4737 return lineno;
4738}
4739
4740/* :nodoc: */
4741static VALUE
4742io_readline(rb_execution_context_t *ec, VALUE io, VALUE sep, VALUE lim, VALUE chomp)
4743{
4744 long limit = -1;
4745 if (NIL_P(lim)) {
4746 VALUE tmp = Qnil;
4747 // If sep is specified, but it's not a string and not nil, then assume
4748 // it's the limit (it should be an integer)
4749 if (!NIL_P(sep) && NIL_P(tmp = rb_check_string_type(sep))) {
4750 // If the user has specified a non-nil / non-string value
4751 // for the separator, we assume it's the limit and set the
4752 // separator to default: rb_rs.
4753 lim = sep;
4754 limit = NUM2LONG(lim);
4755 sep = rb_rs;
4756 }
4757 else {
4758 sep = tmp;
4759 }
4760 }
4761 else {
4762 if (!NIL_P(sep)) StringValue(sep);
4763 limit = NUM2LONG(lim);
4764 }
4765
4766 check_getline_args(&sep, &limit, io);
4767
4768 VALUE line = rb_io_getline_1(sep, limit, RTEST(chomp), io);
4769 rb_lastline_set_up(line, 1);
4770
4771 if (NIL_P(line)) {
4772 rb_eof_error();
4773 }
4774 return line;
4775}
4776
4777static VALUE io_readlines(const struct getline_arg *arg, VALUE io);
4778
4779/*
4780 * call-seq:
4781 * readlines(sep = $/, chomp: false) -> array
4782 * readlines(limit, chomp: false) -> array
4783 * readlines(sep, limit, chomp: false) -> array
4784 *
4785 * Reads and returns all remaining line from the stream;
4786 * does not modify <tt>$_</tt>.
4787 * See {Line IO}[rdoc-ref:IO@Line+IO].
4788 *
4789 * With no arguments given, returns lines
4790 * as determined by line separator <tt>$/</tt>, or +nil+ if none:
4791 *
4792 * f = File.new('t.txt')
4793 * f.readlines
4794 * # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
4795 * f.readlines # => []
4796 * f.close
4797 *
4798 * With only string argument +sep+ given,
4799 * returns lines as determined by line separator +sep+,
4800 * or +nil+ if none;
4801 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4802 *
4803 * f = File.new('t.txt')
4804 * f.readlines('li')
4805 * # => ["First li", "ne\nSecond li", "ne\n\nFourth li", "ne\nFifth li", "ne\n"]
4806 * f.close
4807 *
4808 * The two special values for +sep+ are honored:
4809 *
4810 * f = File.new('t.txt')
4811 * # Get all into one string.
4812 * f.readlines(nil)
4813 * # => ["First line\nSecond line\n\nFourth line\nFifth line\n"]
4814 * # Get paragraphs (up to two line separators).
4815 * f.rewind
4816 * f.readlines('')
4817 * # => ["First line\nSecond line\n\n", "Fourth line\nFifth line\n"]
4818 * f.close
4819 *
4820 * With only integer argument +limit+ given,
4821 * limits the number of bytes in each line;
4822 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4823 *
4824 * f = File.new('t.txt')
4825 * f.readlines(8)
4826 * # => ["First li", "ne\n", "Second l", "ine\n", "\n", "Fourth l", "ine\n", "Fifth li", "ne\n"]
4827 * f.close
4828 *
4829 * With arguments +sep+ and +limit+ given,
4830 * combines the two behaviors
4831 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
4832 *
4833 * Optional keyword argument +chomp+ specifies whether line separators
4834 * are to be omitted:
4835 *
4836 * f = File.new('t.txt')
4837 * f.readlines(chomp: true)
4838 * # => ["First line", "Second line", "", "Fourth line", "Fifth line"]
4839 * f.close
4840 *
4841 */
4842
4843static VALUE
4844rb_io_readlines(int argc, VALUE *argv, VALUE io)
4845{
4846 struct getline_arg args;
4847
4848 prepare_getline_args(argc, argv, &args, io);
4849 return io_readlines(&args, io);
4850}
4851
4852static VALUE
4853io_readlines(const struct getline_arg *arg, VALUE io)
4854{
4855 VALUE line, ary;
4856
4857 if (arg->limit == 0)
4858 rb_raise(rb_eArgError, "invalid limit: 0 for readlines");
4859 ary = rb_ary_new();
4860 while (!NIL_P(line = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, io))) {
4861 rb_ary_push(ary, line);
4862 }
4863 return ary;
4864}
4865
4866/*
4867 * call-seq:
4868 * each_line(sep = $/, chomp: false) {|line| ... } -> self
4869 * each_line(limit, chomp: false) {|line| ... } -> self
4870 * each_line(sep, limit, chomp: false) {|line| ... } -> self
4871 * each_line -> enumerator
4872 *
4873 * Calls the block with each remaining line read from the stream;
4874 * returns +self+.
4875 * Does nothing if already at end-of-stream;
4876 * See {Line IO}[rdoc-ref:IO@Line+IO].
4877 *
4878 * With no arguments given, reads lines
4879 * as determined by line separator <tt>$/</tt>:
4880 *
4881 * f = File.new('t.txt')
4882 * f.each_line {|line| p line }
4883 * f.each_line {|line| fail 'Cannot happen' }
4884 * f.close
4885 *
4886 * Output:
4887 *
4888 * "First line\n"
4889 * "Second line\n"
4890 * "\n"
4891 * "Fourth line\n"
4892 * "Fifth line\n"
4893 *
4894 * With only string argument +sep+ given,
4895 * reads lines as determined by line separator +sep+;
4896 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4897 *
4898 * f = File.new('t.txt')
4899 * f.each_line('li') {|line| p line }
4900 * f.close
4901 *
4902 * Output:
4903 *
4904 * "First li"
4905 * "ne\nSecond li"
4906 * "ne\n\nFourth li"
4907 * "ne\nFifth li"
4908 * "ne\n"
4909 *
4910 * The two special values for +sep+ are honored:
4911 *
4912 * f = File.new('t.txt')
4913 * # Get all into one string.
4914 * f.each_line(nil) {|line| p line }
4915 * f.close
4916 *
4917 * Output:
4918 *
4919 * "First line\nSecond line\n\nFourth line\nFifth line\n"
4920 *
4921 * f.rewind
4922 * # Get paragraphs (up to two line separators).
4923 * f.each_line('') {|line| p line }
4924 *
4925 * Output:
4926 *
4927 * "First line\nSecond line\n\n"
4928 * "Fourth line\nFifth line\n"
4929 *
4930 * With only integer argument +limit+ given,
4931 * limits the number of bytes in each line;
4932 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4933 *
4934 * f = File.new('t.txt')
4935 * f.each_line(8) {|line| p line }
4936 * f.close
4937 *
4938 * Output:
4939 *
4940 * "First li"
4941 * "ne\n"
4942 * "Second l"
4943 * "ine\n"
4944 * "\n"
4945 * "Fourth l"
4946 * "ine\n"
4947 * "Fifth li"
4948 * "ne\n"
4949 *
4950 * With arguments +sep+ and +limit+ given,
4951 * combines the two behaviors
4952 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
4953 *
4954 * Optional keyword argument +chomp+ specifies whether line separators
4955 * are to be omitted:
4956 *
4957 * f = File.new('t.txt')
4958 * f.each_line(chomp: true) {|line| p line }
4959 * f.close
4960 *
4961 * Output:
4962 *
4963 * "First line"
4964 * "Second line"
4965 * ""
4966 * "Fourth line"
4967 * "Fifth line"
4968 *
4969 * Returns an Enumerator if no block is given.
4970 */
4971
4972static VALUE
4973rb_io_each_line(int argc, VALUE *argv, VALUE io)
4974{
4975 VALUE str;
4976 struct getline_arg args;
4977
4978 RETURN_ENUMERATOR(io, argc, argv);
4979 prepare_getline_args(argc, argv, &args, io);
4980 if (args.limit == 0)
4981 rb_raise(rb_eArgError, "invalid limit: 0 for each_line");
4982 while (!NIL_P(str = rb_io_getline_1(args.rs, args.limit, args.chomp, io))) {
4983 rb_yield(str);
4984 }
4985 return io;
4986}
4987
4988/*
4989 * call-seq:
4990 * each_byte {|byte| ... } -> self
4991 * each_byte -> enumerator
4992 *
4993 * Calls the given block with each byte (0..255) in the stream; returns +self+.
4994 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
4995 *
4996 * File.read('t.ja') # => "こんにちは"
4997 * f = File.new('t.ja')
4998 * a = []
4999 * f.each_byte {|b| a << b }
5000 * a # => [227, 129, 147, 227, 130, 147, 227, 129, 171, 227, 129, 161, 227, 129, 175]
5001 * f.close
5002 *
5003 * Returns an Enumerator if no block is given.
5004 *
5005 * Related: IO#each_char, IO#each_codepoint.
5006 *
5007 */
5008
5009static VALUE
5010rb_io_each_byte(VALUE io)
5011{
5012 rb_io_t *fptr;
5013
5014 RETURN_ENUMERATOR(io, 0, 0);
5015 GetOpenFile(io, fptr);
5016
5017 do {
5018 while (fptr->rbuf.len > 0) {
5019 char *p = fptr->rbuf.ptr + fptr->rbuf.off++;
5020 fptr->rbuf.len--;
5021 rb_yield(INT2FIX(*p & 0xff));
5023 errno = 0;
5024 }
5025 READ_CHECK(fptr);
5026 } while (io_fillbuf(fptr) >= 0);
5027 return io;
5028}
5029
5030static VALUE
5031io_getc(rb_io_t *fptr, rb_encoding *enc)
5032{
5033 int r, n, cr = 0;
5034 VALUE str;
5035
5036 if (NEED_READCONV(fptr)) {
5037 rb_encoding *read_enc = io_read_encoding(fptr);
5038
5039 str = Qnil;
5040 SET_BINARY_MODE(fptr);
5041 make_readconv(fptr, 0);
5042
5043 while (1) {
5044 if (fptr->cbuf.len) {
5045 r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
5046 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
5047 read_enc);
5048 if (!MBCLEN_NEEDMORE_P(r))
5049 break;
5050 if (fptr->cbuf.len == fptr->cbuf.capa) {
5051 rb_raise(rb_eIOError, "too long character");
5052 }
5053 }
5054
5055 if (more_char(fptr) == MORE_CHAR_FINISHED) {
5056 if (fptr->cbuf.len == 0) {
5057 clear_readconv(fptr);
5058 return Qnil;
5059 }
5060 /* return an unit of an incomplete character just before EOF */
5061 str = rb_enc_str_new(fptr->cbuf.ptr+fptr->cbuf.off, 1, read_enc);
5062 fptr->cbuf.off += 1;
5063 fptr->cbuf.len -= 1;
5064 if (fptr->cbuf.len == 0) clear_readconv(fptr);
5066 return str;
5067 }
5068 }
5069 if (MBCLEN_INVALID_P(r)) {
5070 r = rb_enc_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
5071 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
5072 read_enc);
5073 io_shift_cbuf(fptr, r, &str);
5075 }
5076 else {
5077 io_shift_cbuf(fptr, MBCLEN_CHARFOUND_LEN(r), &str);
5079 if (MBCLEN_CHARFOUND_LEN(r) == 1 && rb_enc_asciicompat(read_enc) &&
5080 ISASCII(RSTRING_PTR(str)[0])) {
5081 cr = ENC_CODERANGE_7BIT;
5082 }
5083 }
5084 str = io_enc_str(str, fptr);
5085 ENC_CODERANGE_SET(str, cr);
5086 return str;
5087 }
5088
5089 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
5090 if (io_fillbuf(fptr) < 0) {
5091 return Qnil;
5092 }
5093 if (rb_enc_asciicompat(enc) && ISASCII(fptr->rbuf.ptr[fptr->rbuf.off])) {
5094 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, 1);
5095 fptr->rbuf.off += 1;
5096 fptr->rbuf.len -= 1;
5097 cr = ENC_CODERANGE_7BIT;
5098 }
5099 else {
5100 r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off, fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
5101 if (MBCLEN_CHARFOUND_P(r) &&
5102 (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
5103 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, n);
5104 fptr->rbuf.off += n;
5105 fptr->rbuf.len -= n;
5107 }
5108 else if (MBCLEN_NEEDMORE_P(r)) {
5109 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, fptr->rbuf.len);
5110 fptr->rbuf.len = 0;
5111 getc_needmore:
5112 if (io_fillbuf(fptr) != -1) {
5113 rb_str_cat(str, fptr->rbuf.ptr+fptr->rbuf.off, 1);
5114 fptr->rbuf.off++;
5115 fptr->rbuf.len--;
5116 r = rb_enc_precise_mbclen(RSTRING_PTR(str), RSTRING_PTR(str)+RSTRING_LEN(str), enc);
5117 if (MBCLEN_NEEDMORE_P(r)) {
5118 goto getc_needmore;
5119 }
5120 else if (MBCLEN_CHARFOUND_P(r)) {
5122 }
5123 }
5124 }
5125 else {
5126 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, 1);
5127 fptr->rbuf.off++;
5128 fptr->rbuf.len--;
5129 }
5130 }
5131 if (!cr) cr = ENC_CODERANGE_BROKEN;
5132 str = io_enc_str(str, fptr);
5133 ENC_CODERANGE_SET(str, cr);
5134 return str;
5135}
5136
5137/*
5138 * call-seq:
5139 * each_char {|c| ... } -> self
5140 * each_char -> enumerator
5141 *
5142 * Calls the given block with each character in the stream; returns +self+.
5143 * See {Character IO}[rdoc-ref:IO@Character+IO].
5144 *
5145 * File.read('t.ja') # => "こんにちは"
5146 * f = File.new('t.ja')
5147 * a = []
5148 * f.each_char {|c| a << c.ord }
5149 * a # => [12371, 12435, 12395, 12385, 12399]
5150 * f.close
5151 *
5152 * Returns an Enumerator if no block is given.
5153 *
5154 * Related: IO#each_byte, IO#each_codepoint.
5155 *
5156 */
5157
5158static VALUE
5159rb_io_each_char(VALUE io)
5160{
5161 rb_io_t *fptr;
5162 rb_encoding *enc;
5163 VALUE c;
5164
5165 RETURN_ENUMERATOR(io, 0, 0);
5166 GetOpenFile(io, fptr);
5168
5169 enc = io_input_encoding(fptr);
5170 READ_CHECK(fptr);
5171 while (!NIL_P(c = io_getc(fptr, enc))) {
5172 rb_yield(c);
5173 }
5174 return io;
5175}
5176
5177/*
5178 * call-seq:
5179 * each_codepoint {|c| ... } -> self
5180 * each_codepoint -> enumerator
5181 *
5182 * Calls the given block with each codepoint in the stream; returns +self+:
5183 *
5184 * File.read('t.ja') # => "こんにちは"
5185 * f = File.new('t.ja')
5186 * a = []
5187 * f.each_codepoint {|c| a << c }
5188 * a # => [12371, 12435, 12395, 12385, 12399]
5189 * f.close
5190 *
5191 * Returns an Enumerator if no block is given.
5192 *
5193 * Related: IO#each_byte, IO#each_char.
5194 *
5195 */
5196
5197static VALUE
5198rb_io_each_codepoint(VALUE io)
5199{
5200 rb_io_t *fptr;
5201 rb_encoding *enc;
5202 unsigned int c;
5203 int r, n;
5204
5205 RETURN_ENUMERATOR(io, 0, 0);
5206 GetOpenFile(io, fptr);
5208
5209 READ_CHECK(fptr);
5210 enc = io_read_encoding(fptr);
5211 if (NEED_READCONV(fptr)) {
5212 SET_BINARY_MODE(fptr);
5213 r = 1; /* no invalid char yet */
5214 for (;;) {
5215 make_readconv(fptr, 0);
5216 for (;;) {
5217 if (fptr->cbuf.len) {
5218 r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
5219 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
5220 enc);
5221 if (!MBCLEN_NEEDMORE_P(r))
5222 break;
5223 if (fptr->cbuf.len == fptr->cbuf.capa) {
5224 rb_raise(rb_eIOError, "too long character");
5225 }
5226 }
5227 if (more_char(fptr) == MORE_CHAR_FINISHED) {
5228 clear_readconv(fptr);
5229 if (!MBCLEN_CHARFOUND_P(r)) {
5230 goto invalid;
5231 }
5232 return io;
5233 }
5234 }
5235 if (MBCLEN_INVALID_P(r)) {
5236 goto invalid;
5237 }
5238 n = MBCLEN_CHARFOUND_LEN(r);
5239 c = rb_enc_codepoint(fptr->cbuf.ptr+fptr->cbuf.off,
5240 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
5241 enc);
5242 fptr->cbuf.off += n;
5243 fptr->cbuf.len -= n;
5244 rb_yield(UINT2NUM(c));
5246 }
5247 }
5248 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
5249 while (io_fillbuf(fptr) >= 0) {
5250 r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off,
5251 fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
5252 if (MBCLEN_CHARFOUND_P(r) &&
5253 (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
5254 c = rb_enc_codepoint(fptr->rbuf.ptr+fptr->rbuf.off,
5255 fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
5256 fptr->rbuf.off += n;
5257 fptr->rbuf.len -= n;
5258 rb_yield(UINT2NUM(c));
5259 }
5260 else if (MBCLEN_INVALID_P(r)) {
5261 goto invalid;
5262 }
5263 else if (MBCLEN_NEEDMORE_P(r)) {
5264 char cbuf[8], *p = cbuf;
5265 int more = MBCLEN_NEEDMORE_LEN(r);
5266 if (more > numberof(cbuf)) goto invalid;
5267 more += n = fptr->rbuf.len;
5268 if (more > numberof(cbuf)) goto invalid;
5269 while ((n = (int)read_buffered_data(p, more, fptr)) > 0 &&
5270 (p += n, (more -= n) > 0)) {
5271 if (io_fillbuf(fptr) < 0) goto invalid;
5272 if ((n = fptr->rbuf.len) > more) n = more;
5273 }
5274 r = rb_enc_precise_mbclen(cbuf, p, enc);
5275 if (!MBCLEN_CHARFOUND_P(r)) goto invalid;
5276 c = rb_enc_codepoint(cbuf, p, enc);
5277 rb_yield(UINT2NUM(c));
5278 }
5279 else {
5280 continue;
5281 }
5283 }
5284 return io;
5285
5286 invalid:
5287 rb_raise(rb_eArgError, "invalid byte sequence in %s", rb_enc_name(enc));
5289}
5290
5291/*
5292 * call-seq:
5293 * getc -> character or nil
5294 *
5295 * Reads and returns the next 1-character string from the stream;
5296 * returns +nil+ if already at end-of-stream.
5297 * See {Character IO}[rdoc-ref:IO@Character+IO].
5298 *
5299 * f = File.open('t.txt')
5300 * f.getc # => "F"
5301 * f.close
5302 * File.read('t.ja') # => "こんにちは"
5303 * f = File.open('t.ja')
5304 * f.getc.ord # => 12371
5305 * f.close
5306 *
5307 * Related: IO#readchar (may raise EOFError).
5308 *
5309 */
5310
5311static VALUE
5312rb_io_getc(VALUE io)
5313{
5314 rb_io_t *fptr;
5315 rb_encoding *enc;
5316
5317 GetOpenFile(io, fptr);
5319
5320 enc = io_input_encoding(fptr);
5321 READ_CHECK(fptr);
5322 return io_getc(fptr, enc);
5323}
5324
5325/*
5326 * call-seq:
5327 * readchar -> string
5328 *
5329 * Reads and returns the next 1-character string from the stream;
5330 * raises EOFError if already at end-of-stream.
5331 * See {Character IO}[rdoc-ref:IO@Character+IO].
5332 *
5333 * f = File.open('t.txt')
5334 * f.readchar # => "F"
5335 * f.close
5336 * File.read('t.ja') # => "こんにちは"
5337 * f = File.open('t.ja')
5338 * f.readchar.ord # => 12371
5339 * f.close
5340 *
5341 * Related: IO#getc (will not raise EOFError).
5342 *
5343 */
5344
5345static VALUE
5346rb_io_readchar(VALUE io)
5347{
5348 VALUE c = rb_io_getc(io);
5349
5350 if (NIL_P(c)) {
5351 rb_eof_error();
5352 }
5353 return c;
5354}
5355
5356/*
5357 * call-seq:
5358 * getbyte -> integer or nil
5359 *
5360 * Reads and returns the next byte (in range 0..255) from the stream;
5361 * returns +nil+ if already at end-of-stream.
5362 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5363 *
5364 * f = File.open('t.txt')
5365 * f.getbyte # => 70
5366 * f.close
5367 * File.read('t.ja') # => "こんにちは"
5368 * f = File.open('t.ja')
5369 * f.getbyte # => 227
5370 * f.close
5371 *
5372 * Related: IO#readbyte (may raise EOFError).
5373 */
5374
5375VALUE
5377{
5378 rb_io_t *fptr;
5379 int c;
5380
5381 GetOpenFile(io, fptr);
5383 READ_CHECK(fptr);
5384 VALUE r_stdout = rb_ractor_stdout();
5385 if (fptr->fd == 0 && (fptr->mode & FMODE_TTY) && RB_TYPE_P(r_stdout, T_FILE)) {
5386 rb_io_t *ofp;
5387 GetOpenFile(r_stdout, ofp);
5388 if (ofp->mode & FMODE_TTY) {
5389 rb_io_flush(r_stdout);
5390 }
5391 }
5392 if (io_fillbuf(fptr) < 0) {
5393 return Qnil;
5394 }
5395 fptr->rbuf.off++;
5396 fptr->rbuf.len--;
5397 c = (unsigned char)fptr->rbuf.ptr[fptr->rbuf.off-1];
5398 return INT2FIX(c & 0xff);
5399}
5400
5401/*
5402 * call-seq:
5403 * readbyte -> integer
5404 *
5405 * Reads and returns the next byte (in range 0..255) from the stream;
5406 * raises EOFError if already at end-of-stream.
5407 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5408 *
5409 * f = File.open('t.txt')
5410 * f.readbyte # => 70
5411 * f.close
5412 * File.read('t.ja') # => "こんにちは"
5413 * f = File.open('t.ja')
5414 * f.readbyte # => 227
5415 * f.close
5416 *
5417 * Related: IO#getbyte (will not raise EOFError).
5418 *
5419 */
5420
5421static VALUE
5422rb_io_readbyte(VALUE io)
5423{
5424 VALUE c = rb_io_getbyte(io);
5425
5426 if (NIL_P(c)) {
5427 rb_eof_error();
5428 }
5429 return c;
5430}
5431
5432/*
5433 * call-seq:
5434 * ungetbyte(integer) -> nil
5435 * ungetbyte(string) -> nil
5436 *
5437 * Pushes back ("unshifts") the given data onto the stream's buffer,
5438 * placing the data so that it is next to be read; returns +nil+.
5439 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5440 *
5441 * Note that:
5442 *
5443 * - Calling the method has no effect with unbuffered reads (such as IO#sysread).
5444 * - Calling #rewind on the stream discards the pushed-back data.
5445 *
5446 * When argument +integer+ is given, uses only its low-order byte:
5447 *
5448 * File.write('t.tmp', '012')
5449 * f = File.open('t.tmp')
5450 * f.ungetbyte(0x41) # => nil
5451 * f.read # => "A012"
5452 * f.rewind
5453 * f.ungetbyte(0x4243) # => nil
5454 * f.read # => "C012"
5455 * f.close
5456 *
5457 * When argument +string+ is given, uses all bytes:
5458 *
5459 * File.write('t.tmp', '012')
5460 * f = File.open('t.tmp')
5461 * f.ungetbyte('A') # => nil
5462 * f.read # => "A012"
5463 * f.rewind
5464 * f.ungetbyte('BCDE') # => nil
5465 * f.read # => "BCDE012"
5466 * f.close
5467 *
5468 */
5469
5470VALUE
5472{
5473 rb_io_t *fptr;
5474
5475 GetOpenFile(io, fptr);
5477 switch (TYPE(b)) {
5478 case T_NIL:
5479 return Qnil;
5480 case T_FIXNUM:
5481 case T_BIGNUM: ;
5482 VALUE v = rb_int_modulo(b, INT2FIX(256));
5483 unsigned char c = NUM2INT(v) & 0xFF;
5484 b = rb_str_new((const char *)&c, 1);
5485 break;
5486 default:
5487 StringValue(b);
5488 }
5489 io_ungetbyte(b, fptr);
5490 return Qnil;
5491}
5492
5493/*
5494 * call-seq:
5495 * ungetc(integer) -> nil
5496 * ungetc(string) -> nil
5497 *
5498 * Pushes back ("unshifts") the given data onto the stream's buffer,
5499 * placing the data so that it is next to be read; returns +nil+.
5500 * See {Character IO}[rdoc-ref:IO@Character+IO].
5501 *
5502 * Note that:
5503 *
5504 * - Calling the method has no effect with unbuffered reads (such as IO#sysread).
5505 * - Calling #rewind on the stream discards the pushed-back data.
5506 *
5507 * When argument +integer+ is given, interprets the integer as a character:
5508 *
5509 * File.write('t.tmp', '012')
5510 * f = File.open('t.tmp')
5511 * f.ungetc(0x41) # => nil
5512 * f.read # => "A012"
5513 * f.rewind
5514 * f.ungetc(0x0442) # => nil
5515 * f.getc.ord # => 1090
5516 * f.close
5517 *
5518 * When argument +string+ is given, uses all characters:
5519 *
5520 * File.write('t.tmp', '012')
5521 * f = File.open('t.tmp')
5522 * f.ungetc('A') # => nil
5523 * f.read # => "A012"
5524 * f.rewind
5525 * f.ungetc("\u0442\u0435\u0441\u0442") # => nil
5526 * f.getc.ord # => 1090
5527 * f.getc.ord # => 1077
5528 * f.getc.ord # => 1089
5529 * f.getc.ord # => 1090
5530 * f.close
5531 *
5532 */
5533
5534VALUE
5536{
5537 rb_io_t *fptr;
5538 long len;
5539
5540 GetOpenFile(io, fptr);
5542 if (FIXNUM_P(c)) {
5543 c = rb_enc_uint_chr(FIX2UINT(c), io_read_encoding(fptr));
5544 }
5545 else if (RB_BIGNUM_TYPE_P(c)) {
5546 c = rb_enc_uint_chr(NUM2UINT(c), io_read_encoding(fptr));
5547 }
5548 else {
5549 StringValue(c);
5550 }
5551 if (NEED_READCONV(fptr)) {
5552 SET_BINARY_MODE(fptr);
5553 len = RSTRING_LEN(c);
5554#if SIZEOF_LONG > SIZEOF_INT
5555 if (len > INT_MAX)
5556 rb_raise(rb_eIOError, "ungetc failed");
5557#endif
5558 make_readconv(fptr, (int)len);
5559 if (fptr->cbuf.capa - fptr->cbuf.len < len)
5560 rb_raise(rb_eIOError, "ungetc failed");
5561 if (fptr->cbuf.off < len) {
5562 MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.capa-fptr->cbuf.len,
5563 fptr->cbuf.ptr+fptr->cbuf.off,
5564 char, fptr->cbuf.len);
5565 fptr->cbuf.off = fptr->cbuf.capa-fptr->cbuf.len;
5566 }
5567 fptr->cbuf.off -= (int)len;
5568 fptr->cbuf.len += (int)len;
5569 MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.off, RSTRING_PTR(c), char, len);
5570 }
5571 else {
5572 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
5573 io_ungetbyte(c, fptr);
5574 }
5575 return Qnil;
5576}
5577
5578/*
5579 * call-seq:
5580 * isatty -> true or false
5581 *
5582 * Returns +true+ if the stream is associated with a terminal device (tty),
5583 * +false+ otherwise:
5584 *
5585 * f = File.new('t.txt').isatty #=> false
5586 * f.close
5587 * f = File.new('/dev/tty').isatty #=> true
5588 * f.close
5589 *
5590 */
5591
5592static VALUE
5593rb_io_isatty(VALUE io)
5594{
5595 rb_io_t *fptr;
5596
5597 GetOpenFile(io, fptr);
5598 return RBOOL(isatty(fptr->fd) != 0);
5599}
5600
5601#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5602/*
5603 * call-seq:
5604 * close_on_exec? -> true or false
5605 *
5606 * Returns +true+ if the stream will be closed on exec, +false+ otherwise:
5607 *
5608 * f = File.open('t.txt')
5609 * f.close_on_exec? # => true
5610 * f.close_on_exec = false
5611 * f.close_on_exec? # => false
5612 * f.close
5613 *
5614 */
5615
5616static VALUE
5617rb_io_close_on_exec_p(VALUE io)
5618{
5619 rb_io_t *fptr;
5620 VALUE write_io;
5621 int fd, ret;
5622
5623 write_io = GetWriteIO(io);
5624 if (io != write_io) {
5625 GetOpenFile(write_io, fptr);
5626 if (fptr && 0 <= (fd = fptr->fd)) {
5627 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5628 if (!(ret & FD_CLOEXEC)) return Qfalse;
5629 }
5630 }
5631
5632 GetOpenFile(io, fptr);
5633 if (fptr && 0 <= (fd = fptr->fd)) {
5634 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5635 if (!(ret & FD_CLOEXEC)) return Qfalse;
5636 }
5637 return Qtrue;
5638}
5639#else
5640#define rb_io_close_on_exec_p rb_f_notimplement
5641#endif
5642
5643#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5644/*
5645 * call-seq:
5646 * self.close_on_exec = bool -> true or false
5647 *
5648 * Sets a close-on-exec flag.
5649 *
5650 * f = File.open(File::NULL)
5651 * f.close_on_exec = true
5652 * system("cat", "/proc/self/fd/#{f.fileno}") # cat: /proc/self/fd/3: No such file or directory
5653 * f.closed? #=> false
5654 *
5655 * Ruby sets close-on-exec flags of all file descriptors by default
5656 * since Ruby 2.0.0.
5657 * So you don't need to set by yourself.
5658 * Also, unsetting a close-on-exec flag can cause file descriptor leak
5659 * if another thread use fork() and exec() (via system() method for example).
5660 * If you really needs file descriptor inheritance to child process,
5661 * use spawn()'s argument such as fd=>fd.
5662 */
5663
5664static VALUE
5665rb_io_set_close_on_exec(VALUE io, VALUE arg)
5666{
5667 int flag = RTEST(arg) ? FD_CLOEXEC : 0;
5668 rb_io_t *fptr;
5669 VALUE write_io;
5670 int fd, ret;
5671
5672 write_io = GetWriteIO(io);
5673 if (io != write_io) {
5674 GetOpenFile(write_io, fptr);
5675 if (fptr && 0 <= (fd = fptr->fd)) {
5676 if ((ret = fcntl(fptr->fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5677 if ((ret & FD_CLOEXEC) != flag) {
5678 ret = (ret & ~FD_CLOEXEC) | flag;
5679 ret = fcntl(fd, F_SETFD, ret);
5680 if (ret != 0) rb_sys_fail_path(fptr->pathv);
5681 }
5682 }
5683
5684 }
5685
5686 GetOpenFile(io, fptr);
5687 if (fptr && 0 <= (fd = fptr->fd)) {
5688 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5689 if ((ret & FD_CLOEXEC) != flag) {
5690 ret = (ret & ~FD_CLOEXEC) | flag;
5691 ret = fcntl(fd, F_SETFD, ret);
5692 if (ret != 0) rb_sys_fail_path(fptr->pathv);
5693 }
5694 }
5695 return Qnil;
5696}
5697#else
5698#define rb_io_set_close_on_exec rb_f_notimplement
5699#endif
5700
5701#define RUBY_IO_EXTERNAL_P(f) ((f)->mode & FMODE_EXTERNAL)
5702#define PREP_STDIO_NAME(f) (RSTRING_PTR((f)->pathv))
5703
5704static VALUE
5705finish_writeconv(rb_io_t *fptr, int noalloc)
5706{
5707 unsigned char *ds, *dp, *de;
5709
5710 if (!fptr->wbuf.ptr) {
5711 unsigned char buf[1024];
5712
5714 while (res == econv_destination_buffer_full) {
5715 ds = dp = buf;
5716 de = buf + sizeof(buf);
5717 res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
5718 while (dp-ds) {
5719 size_t remaining = dp-ds;
5720 long result = rb_io_write_memory(fptr, ds, remaining);
5721
5722 if (result > 0) {
5723 ds += result;
5724 if ((size_t)result == remaining) break;
5725 }
5726 else if (rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
5727 if (fptr->fd < 0)
5728 return noalloc ? Qtrue : rb_exc_new3(rb_eIOError, rb_str_new_cstr(closed_stream));
5729 }
5730 else {
5731 return noalloc ? Qtrue : INT2NUM(errno);
5732 }
5733 }
5734 if (res == econv_invalid_byte_sequence ||
5735 res == econv_incomplete_input ||
5737 return noalloc ? Qtrue : rb_econv_make_exception(fptr->writeconv);
5738 }
5739 }
5740
5741 return Qnil;
5742 }
5743
5745 while (res == econv_destination_buffer_full) {
5746 if (fptr->wbuf.len == fptr->wbuf.capa) {
5747 if (io_fflush(fptr) < 0) {
5748 return noalloc ? Qtrue : INT2NUM(errno);
5749 }
5750 }
5751
5752 ds = dp = (unsigned char *)fptr->wbuf.ptr + fptr->wbuf.off + fptr->wbuf.len;
5753 de = (unsigned char *)fptr->wbuf.ptr + fptr->wbuf.capa;
5754 res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
5755 fptr->wbuf.len += (int)(dp - ds);
5756 if (res == econv_invalid_byte_sequence ||
5757 res == econv_incomplete_input ||
5759 return noalloc ? Qtrue : rb_econv_make_exception(fptr->writeconv);
5760 }
5761 }
5762 return Qnil;
5763}
5764
5766 rb_io_t *fptr;
5767 int noalloc;
5768};
5769
5770static VALUE
5771finish_writeconv_sync(VALUE arg)
5772{
5773 struct finish_writeconv_arg *p = (struct finish_writeconv_arg *)arg;
5774 return finish_writeconv(p->fptr, p->noalloc);
5775}
5776
5777static void*
5778nogvl_close(void *ptr)
5779{
5780 int *fd = ptr;
5781
5782 return (void*)(intptr_t)close(*fd);
5783}
5784
5785static int
5786maygvl_close(int fd, int keepgvl)
5787{
5788 if (keepgvl)
5789 return close(fd);
5790
5791 /*
5792 * close() may block for certain file types (NFS, SO_LINGER sockets,
5793 * inotify), so let other threads run.
5794 */
5795 return IO_WITHOUT_GVL_INT(nogvl_close, &fd);
5796}
5797
5798static void*
5799nogvl_fclose(void *ptr)
5800{
5801 FILE *file = ptr;
5802
5803 return (void*)(intptr_t)fclose(file);
5804}
5805
5806static int
5807maygvl_fclose(FILE *file, int keepgvl)
5808{
5809 if (keepgvl)
5810 return fclose(file);
5811
5812 return IO_WITHOUT_GVL_INT(nogvl_fclose, file);
5813}
5814
5815static void free_io_buffer(rb_io_buffer_t *buf);
5816
5817static void
5818fptr_finalize_flush(rb_io_t *fptr, int noraise, int keepgvl)
5819{
5820 VALUE error = Qnil;
5821 int fd = fptr->fd;
5822 FILE *stdio_file = fptr->stdio_file;
5823 int mode = fptr->mode;
5824
5825 if (fptr->writeconv) {
5826 if (!NIL_P(fptr->write_lock) && !noraise) {
5827 struct finish_writeconv_arg arg;
5828 arg.fptr = fptr;
5829 arg.noalloc = noraise;
5830 error = rb_mutex_synchronize(fptr->write_lock, finish_writeconv_sync, (VALUE)&arg);
5831 }
5832 else {
5833 error = finish_writeconv(fptr, noraise);
5834 }
5835 }
5836 /* Do not flush the write buffer on close when the stream is in sync
5837 * mode. In sync mode Ruby's write buffer is not authoritative (writes go
5838 * straight to the OS), so any bytes left in the buffer are the result of
5839 * writes made while sync was disabled. Setting sync = true is therefore a
5840 * way to abandon that pending output rather than replaying it on close,
5841 * which matters after an interrupted write where the amount actually
5842 * written is indeterminate. Call flush before enabling sync if the
5843 * buffered data should still be sent. */
5844 if (fptr->wbuf.len && !(fptr->mode & FMODE_SYNC)) {
5845 if (noraise) {
5846 io_flush_buffer_sync(fptr);
5847 }
5848 else {
5849 if (io_fflush(fptr) < 0 && NIL_P(error)) {
5850 error = INT2NUM(errno);
5851 }
5852 }
5853 }
5854
5855 int done = 0;
5856
5857 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2) {
5858 // Need to keep FILE objects of stdin, stdout and stderr, so we are done:
5859 done = 1;
5860 }
5861
5862 fptr->fd = -1;
5863 fptr->stdio_file = 0;
5865
5866 // Wait for blocking operations to ensure they do not hit EBADF:
5867 rb_thread_io_close_wait(fptr);
5868
5869 if (!done && stdio_file) {
5870 // stdio_file is deallocated anyway even if fclose failed.
5871 if ((maygvl_fclose(stdio_file, noraise) < 0) && NIL_P(error)) {
5872 if (!noraise) {
5873 error = INT2NUM(errno);
5874 }
5875 }
5876
5877 done = 1;
5878 }
5879
5880 VALUE scheduler = rb_fiber_scheduler_current();
5881 if (!done && fd >= 0 && scheduler != Qnil) {
5882 VALUE result = rb_fiber_scheduler_io_close(scheduler, RB_INT2NUM(fd));
5883
5884 if (!UNDEF_P(result)) {
5885 done = RTEST(result);
5886 }
5887 }
5888
5889 if (!done && fd >= 0) {
5890 // fptr->fd may be closed even if close fails. POSIX doesn't specify it.
5891 // We assumes it is closed.
5892
5893 keepgvl |= !(mode & FMODE_WRITABLE);
5894 keepgvl |= noraise;
5895 if ((maygvl_close(fd, keepgvl) < 0) && NIL_P(error)) {
5896 if (!noraise) {
5897 error = INT2NUM(errno);
5898 }
5899 }
5900
5901 done = 1;
5902 }
5903
5904 if (!NIL_P(error) && !noraise) {
5905 if (RB_INTEGER_TYPE_P(error))
5906 rb_syserr_fail_path(NUM2INT(error), fptr->pathv);
5907 else
5908 rb_exc_raise(error);
5909 }
5910}
5911
5912static void
5913fptr_finalize(rb_io_t *fptr, int noraise)
5914{
5915 fptr_finalize_flush(fptr, noraise, FALSE);
5916 free_io_buffer(&fptr->rbuf);
5917 free_io_buffer(&fptr->wbuf);
5918 clear_codeconv(fptr);
5919}
5920
5921static void
5922rb_io_fptr_cleanup(rb_io_t *fptr, int noraise)
5923{
5924 if (fptr->finalize) {
5925 (*fptr->finalize)(fptr, noraise);
5926 }
5927 else {
5928 fptr_finalize(fptr, noraise);
5929 }
5930}
5931
5932static void
5933free_io_buffer(rb_io_buffer_t *buf)
5934{
5935 if (buf->ptr) {
5936 ruby_xfree_sized(buf->ptr, (size_t)buf->capa);
5937 buf->ptr = NULL;
5938 }
5939 buf->off = buf->len = buf->capa = 0;
5940}
5941
5942static void
5943clear_readconv(rb_io_t *fptr)
5944{
5945 if (fptr->readconv) {
5946 rb_econv_close(fptr->readconv);
5947 fptr->readconv = NULL;
5948 }
5949 free_io_buffer(&fptr->cbuf);
5950}
5951
5952static void
5953clear_writeconv(rb_io_t *fptr)
5954{
5955 if (fptr->writeconv) {
5957 fptr->writeconv = NULL;
5958 }
5959 fptr->writeconv_initialized = 0;
5960}
5961
5962static void
5963clear_codeconv(rb_io_t *fptr)
5964{
5965 clear_readconv(fptr);
5966 clear_writeconv(fptr);
5967}
5968
5969static void
5970rb_io_fptr_cleanup_all(rb_io_t *fptr)
5971{
5972 fptr->pathv = Qnil;
5973 if (0 <= fptr->fd)
5974 rb_io_fptr_cleanup(fptr, TRUE);
5975 fptr->write_lock = Qnil;
5976 free_io_buffer(&fptr->rbuf);
5977 free_io_buffer(&fptr->wbuf);
5978 clear_codeconv(fptr);
5979}
5980
5981int
5983{
5984 if (!io) return 0;
5985 rb_io_fptr_cleanup_all(io);
5986 free(io);
5987
5988 return 1;
5989}
5990
5991bool
5992rb_io_fptr_finalize_closed(struct rb_io *io)
5993{
5994 if (!io) return true;
5995 if (io->fd >= 0) return false;
5997 return true;
5998}
5999
6000size_t
6001rb_io_memsize(const rb_io_t *io)
6002{
6003 size_t size = sizeof(rb_io_t);
6004 size += io->rbuf.capa;
6005 size += io->wbuf.capa;
6006 size += io->cbuf.capa;
6007 if (io->readconv) size += rb_econv_memsize(io->readconv);
6008 if (io->writeconv) size += rb_econv_memsize(io->writeconv);
6009
6010 struct rb_io_blocking_operation *blocking_operation = 0;
6011
6012 // Validate the fork generation of the IO object. If the IO object fork generation is different, the list of blocking operations is not valid memory. See `rb_io_blocking_operations` for the exact semantics.
6013 rb_serial_t fork_generation = GET_VM()->fork_gen;
6014 if (io->fork_generation == fork_generation) {
6015 ccan_list_for_each(&io->blocking_operations, blocking_operation, list) {
6016 size += sizeof(struct rb_io_blocking_operation);
6017 }
6018 }
6019
6020 return size;
6021}
6022
6023#ifdef _WIN32
6024/* keep GVL while closing to prevent crash on Windows */
6025# define KEEPGVL TRUE
6026#else
6027# define KEEPGVL FALSE
6028#endif
6029
6030static rb_io_t *
6031io_close_fptr(VALUE io)
6032{
6033 rb_io_t *fptr;
6034 VALUE write_io;
6035 rb_io_t *write_fptr;
6036
6037 write_io = GetWriteIO(io);
6038 if (io != write_io) {
6039 write_fptr = RFILE(write_io)->fptr;
6040 if (write_fptr && 0 <= write_fptr->fd) {
6041 rb_io_fptr_cleanup(write_fptr, TRUE);
6042 }
6043 }
6044
6045 fptr = RFILE(io)->fptr;
6046 if (!fptr) return 0;
6047 if (fptr->fd < 0) return 0;
6048
6049 // This guards against multiple threads closing the same IO object:
6050 if (rb_thread_io_close_interrupt(fptr)) {
6051 /* calls close(fptr->fd): */
6052 fptr_finalize_flush(fptr, FALSE, KEEPGVL);
6053 }
6054
6055 rb_io_fptr_cleanup(fptr, FALSE);
6056 return fptr;
6057}
6058
6059static void
6060fptr_waitpid(rb_io_t *fptr, int nohang)
6061{
6062 int status;
6063 if (fptr->pid) {
6064 rb_last_status_clear();
6065 rb_waitpid(fptr->pid, &status, nohang ? WNOHANG : 0);
6066 fptr->pid = 0;
6067 }
6068}
6069
6070VALUE
6072{
6073 rb_io_t *fptr = io_close_fptr(io);
6074 if (fptr) fptr_waitpid(fptr, 0);
6075 return Qnil;
6076}
6077
6078/*
6079 * call-seq:
6080 * close -> nil
6081 *
6082 * Closes the stream for both reading and writing
6083 * if open for either or both; returns +nil+.
6084 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
6085 *
6086 * If the stream is open for writing, flushes any buffered writes
6087 * to the operating system before closing.
6088 *
6089 * If the stream was opened by IO.popen, sets global variable <tt>$?</tt>
6090 * (child exit status).
6091 *
6092 * It is not an error to close an IO object that has already been closed.
6093 * It just returns nil.
6094 *
6095 * Example:
6096 *
6097 * IO.popen('ruby', 'r+') do |pipe|
6098 * puts pipe.closed?
6099 * pipe.close
6100 * puts $?
6101 * puts pipe.closed?
6102 * end
6103 *
6104 * Output:
6105 *
6106 * false
6107 * pid 13760 exit 0
6108 * true
6109 *
6110 * Related: IO#close_read, IO#close_write, IO#closed?.
6111 */
6112
6113static VALUE
6114rb_io_close_m(VALUE io)
6115{
6116 rb_io_t *fptr = rb_io_get_fptr(io);
6117 if (fptr->fd < 0) {
6118 return Qnil;
6119 }
6120 rb_io_close(io);
6121 return Qnil;
6122}
6123
6124static VALUE
6125io_call_close(VALUE io)
6126{
6127 rb_check_funcall(io, rb_intern("close"), 0, 0);
6128 return io;
6129}
6130
6131static VALUE
6132ignore_closed_stream(VALUE io, VALUE exc)
6133{
6134 enum {mesg_len = sizeof(closed_stream)-1};
6135 VALUE mesg = rb_attr_get(exc, idMesg);
6136 if (!RB_TYPE_P(mesg, T_STRING) ||
6137 RSTRING_LEN(mesg) != mesg_len ||
6138 memcmp(RSTRING_PTR(mesg), closed_stream, mesg_len)) {
6139 rb_exc_raise(exc);
6140 }
6141 return io;
6142}
6143
6144static VALUE
6145io_close(VALUE io)
6146{
6147 VALUE closed = rb_check_funcall(io, rb_intern("closed?"), 0, 0);
6148 if (!UNDEF_P(closed) && RTEST(closed)) return io;
6149 rb_rescue2(io_call_close, io, ignore_closed_stream, io,
6150 rb_eIOError, (VALUE)0);
6151 return io;
6152}
6153
6154/*
6155 * call-seq:
6156 * closed? -> true or false
6157 *
6158 * Returns +true+ if the stream is closed for both reading and writing,
6159 * +false+ otherwise.
6160 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
6161 *
6162 * IO.popen('ruby', 'r+') do |pipe|
6163 * puts pipe.closed?
6164 * pipe.close_read
6165 * puts pipe.closed?
6166 * pipe.close_write
6167 * puts pipe.closed?
6168 * end
6169 *
6170 * Output:
6171 *
6172 * false
6173 * false
6174 * true
6175 *
6176 * Related: IO#close_read, IO#close_write, IO#close.
6177 */
6178VALUE
6180{
6181 rb_io_t *fptr;
6182 VALUE write_io;
6183 rb_io_t *write_fptr;
6184
6185 write_io = GetWriteIO(io);
6186 if (io != write_io) {
6187 write_fptr = RFILE(write_io)->fptr;
6188 if (write_fptr && 0 <= write_fptr->fd) {
6189 return Qfalse;
6190 }
6191 }
6192
6193 fptr = rb_io_get_fptr(io);
6194 return RBOOL(0 > fptr->fd);
6195}
6196
6197/*
6198 * call-seq:
6199 * close_read -> nil
6200 *
6201 * Closes the stream for reading if open for reading;
6202 * returns +nil+.
6203 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
6204 *
6205 * If the stream was opened by IO.popen and is also closed for writing,
6206 * sets global variable <tt>$?</tt> (child exit status).
6207 *
6208 * Example:
6209 *
6210 * IO.popen('ruby', 'r+') do |pipe|
6211 * puts pipe.closed?
6212 * pipe.close_write
6213 * puts pipe.closed?
6214 * pipe.close_read
6215 * puts $?
6216 * puts pipe.closed?
6217 * end
6218 *
6219 * Output:
6220 *
6221 * false
6222 * false
6223 * pid 14748 exit 0
6224 * true
6225 *
6226 * Related: IO#close, IO#close_write, IO#closed?.
6227 */
6228
6229static VALUE
6230rb_io_close_read(VALUE io)
6231{
6232 rb_io_t *fptr;
6233 VALUE write_io;
6234
6235 fptr = rb_io_get_fptr(rb_io_taint_check(io));
6236 if (fptr->fd < 0) return Qnil;
6237 if (is_socket(fptr->fd, fptr->pathv)) {
6238#ifndef SHUT_RD
6239# define SHUT_RD 0
6240#endif
6241 if (shutdown(fptr->fd, SHUT_RD) < 0)
6242 rb_sys_fail_path(fptr->pathv);
6243 fptr->mode &= ~FMODE_READABLE;
6244 if (!(fptr->mode & FMODE_WRITABLE))
6245 return rb_io_close(io);
6246 return Qnil;
6247 }
6248
6249 write_io = GetWriteIO(io);
6250 if (io != write_io) {
6251 rb_io_t *wfptr;
6252 wfptr = rb_io_get_fptr(rb_io_taint_check(write_io));
6253 wfptr->pid = fptr->pid;
6254 fptr->pid = 0;
6255 RFILE(io)->fptr = wfptr;
6256 /* bind to write_io temporarily to get rid of memory/fd leak */
6257 fptr->tied_io_for_writing = 0;
6258 RFILE(write_io)->fptr = fptr;
6259 rb_io_fptr_cleanup(fptr, FALSE);
6260 /* should not finalize fptr because another thread may be reading it */
6261 return Qnil;
6262 }
6263
6264 if ((fptr->mode & (FMODE_DUPLEX|FMODE_WRITABLE)) == FMODE_WRITABLE) {
6265 rb_raise(rb_eIOError, "closing non-duplex IO for reading");
6266 }
6267 return rb_io_close(io);
6268}
6269
6270/*
6271 * call-seq:
6272 * close_write -> nil
6273 *
6274 * Closes the stream for writing if open for writing;
6275 * returns +nil+.
6276 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
6277 *
6278 * Flushes any buffered writes to the operating system before closing.
6279 *
6280 * If the stream was opened by IO.popen and is also closed for reading,
6281 * sets global variable <tt>$?</tt> (child exit status).
6282 *
6283 * IO.popen('ruby', 'r+') do |pipe|
6284 * puts pipe.closed?
6285 * pipe.close_read
6286 * puts pipe.closed?
6287 * pipe.close_write
6288 * puts $?
6289 * puts pipe.closed?
6290 * end
6291 *
6292 * Output:
6293 *
6294 * false
6295 * false
6296 * pid 15044 exit 0
6297 * true
6298 *
6299 * Related: IO#close, IO#close_read, IO#closed?.
6300 */
6301
6302static VALUE
6303rb_io_close_write(VALUE io)
6304{
6305 rb_io_t *fptr;
6306 VALUE write_io;
6307
6308 write_io = GetWriteIO(io);
6309 fptr = rb_io_get_fptr(rb_io_taint_check(write_io));
6310 if (fptr->fd < 0) return Qnil;
6311 if (is_socket(fptr->fd, fptr->pathv)) {
6312#ifndef SHUT_WR
6313# define SHUT_WR 1
6314#endif
6315 /* Flush any buffered data before shutting down the write side.
6316 * Otherwise the buffered bytes are silently dropped here, and a
6317 * subsequent #close would try to flush them into the now
6318 * shutdown(SHUT_WR) socket and fail with EPIPE. This matches the
6319 * behaviour of the non-socket path below, which flushes via
6320 * rb_io_close(). */
6321 if (fptr->mode & FMODE_WRITABLE) {
6322 if (io_fflush(fptr) < 0)
6323 rb_sys_fail_on_write(fptr);
6324 }
6325 if (shutdown(fptr->fd, SHUT_WR) < 0)
6326 rb_sys_fail_path(fptr->pathv);
6327 fptr->mode &= ~FMODE_WRITABLE;
6328 if (!(fptr->mode & FMODE_READABLE))
6329 return rb_io_close(write_io);
6330 return Qnil;
6331 }
6332
6333 if ((fptr->mode & (FMODE_DUPLEX|FMODE_READABLE)) == FMODE_READABLE) {
6334 rb_raise(rb_eIOError, "closing non-duplex IO for writing");
6335 }
6336
6337 if (io != write_io) {
6338 fptr = rb_io_get_fptr(rb_io_taint_check(io));
6339 fptr->tied_io_for_writing = 0;
6340 }
6341 rb_io_close(write_io);
6342 return Qnil;
6343}
6344
6345/*
6346 * call-seq:
6347 * sysseek(offset, whence = IO::SEEK_SET) -> integer
6348 *
6349 * Behaves like IO#seek, except that it:
6350 *
6351 * - Uses low-level system functions.
6352 * - Returns the new position.
6353 *
6354 */
6355
6356static VALUE
6357rb_io_sysseek(int argc, VALUE *argv, VALUE io)
6358{
6359 VALUE offset, ptrname;
6360 int whence = SEEK_SET;
6361 rb_io_t *fptr;
6362 rb_off_t pos;
6363
6364 if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
6365 whence = interpret_seek_whence(ptrname);
6366 }
6367 pos = NUM2OFFT(offset);
6368 GetOpenFile(io, fptr);
6369 if ((fptr->mode & FMODE_READABLE) &&
6370 (READ_DATA_BUFFERED(fptr) || READ_CHAR_PENDING(fptr))) {
6371 rb_raise(rb_eIOError, "sysseek for buffered IO");
6372 }
6373 if ((fptr->mode & FMODE_WRITABLE) && fptr->wbuf.len) {
6374 rb_warn("sysseek for buffered IO");
6375 }
6376 errno = 0;
6377 pos = lseek(fptr->fd, pos, whence);
6378 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
6379
6380 return OFFT2NUM(pos);
6381}
6382
6383/*
6384 * call-seq:
6385 * syswrite(object) -> integer
6386 *
6387 * Writes the given +object+ to self, which must be opened for writing (see Modes);
6388 * returns the number bytes written.
6389 * If +object+ is not a string is converted via method to_s:
6390 *
6391 * f = File.new('t.tmp', 'w')
6392 * f.syswrite('foo') # => 3
6393 * f.syswrite(30) # => 2
6394 * f.syswrite(:foo) # => 3
6395 * f.close
6396 *
6397 * This methods should not be used with other stream-writer methods.
6398 *
6399 */
6400
6401static VALUE
6402rb_io_syswrite(VALUE io, VALUE str)
6403{
6404 VALUE tmp;
6405 rb_io_t *fptr;
6406 long n, len;
6407 const char *ptr;
6408
6409 if (!RB_TYPE_P(str, T_STRING))
6410 str = rb_obj_as_string(str);
6411
6412 io = GetWriteIO(io);
6413 GetOpenFile(io, fptr);
6415
6416 if (fptr->wbuf.len) {
6417 rb_warn("syswrite for buffered IO");
6418 }
6419
6420 tmp = rb_str_tmp_frozen_acquire(str);
6421 RSTRING_GETMEM(tmp, ptr, len);
6422 n = rb_io_write_memory(fptr, ptr, len);
6423 if (n < 0) rb_sys_fail_path(fptr->pathv);
6424 rb_str_tmp_frozen_release(str, tmp);
6425
6426 return LONG2FIX(n);
6427}
6428
6429/*
6430 * call-seq:
6431 * sysread(maxlen) -> string
6432 * sysread(maxlen, out_string) -> string
6433 *
6434 * Behaves like IO#readpartial, except that it uses low-level system functions.
6435 *
6436 * This method should not be used with other stream-reader methods.
6437 *
6438 */
6439
6440static VALUE
6441rb_io_sysread(int argc, VALUE *argv, VALUE io)
6442{
6443 VALUE len, str;
6444 rb_io_t *fptr;
6445 long n, ilen;
6446 struct io_internal_read_struct iis;
6447 int shrinkable;
6448
6449 rb_scan_args(argc, argv, "11", &len, &str);
6450 ilen = NUM2LONG(len);
6451
6452 shrinkable = io_setstrbuf(&str, ilen);
6453 if (ilen == 0) return str;
6454
6455 GetOpenFile(io, fptr);
6457
6458 if (READ_DATA_BUFFERED(fptr)) {
6459 rb_raise(rb_eIOError, "sysread for buffered IO");
6460 }
6461
6462 rb_io_check_closed(fptr);
6463
6464 io_setstrbuf(&str, ilen);
6465 iis.th = rb_thread_current();
6466 iis.fptr = fptr;
6467 iis.nonblock = 0;
6468 iis.fd = fptr->fd;
6469 iis.buf = RSTRING_PTR(str);
6470 iis.capa = ilen;
6471 iis.timeout = NULL;
6472 n = io_read_memory_locktmp(str, &iis);
6473
6474 if (n < 0) {
6475 rb_sys_fail_path(fptr->pathv);
6476 }
6477
6478 io_set_read_length(str, n, shrinkable);
6479
6480 if (n == 0 && ilen > 0) {
6481 rb_eof_error();
6482 }
6483
6484 return str;
6485}
6486
6488 struct rb_io *io;
6489 int fd;
6490 void *buf;
6491 size_t count;
6492 rb_off_t offset;
6493};
6494
6495static VALUE
6496internal_pread_func(void *_arg)
6497{
6498 struct prdwr_internal_arg *arg = _arg;
6499
6500 return (VALUE)pread(arg->fd, arg->buf, arg->count, arg->offset);
6501}
6502
6503static VALUE
6504pread_internal_call(VALUE _arg)
6505{
6506 struct prdwr_internal_arg *arg = (struct prdwr_internal_arg *)_arg;
6507
6508 VALUE scheduler = rb_fiber_scheduler_current();
6509 if (scheduler != Qnil) {
6510 VALUE result = rb_fiber_scheduler_io_pread_memory(scheduler, arg->io->self, arg->offset, arg->buf, arg->count);
6511
6512 if (!UNDEF_P(result)) {
6514 }
6515 }
6516
6517 return rb_io_blocking_region_wait(arg->io, internal_pread_func, arg, RUBY_IO_READABLE);
6518}
6519
6520/*
6521 * call-seq:
6522 * pread(maxlen, offset) -> string
6523 * pread(maxlen, offset, out_string) -> string
6524 *
6525 * Behaves like IO#readpartial, except that it:
6526 *
6527 * - Reads at the given +offset+ (in bytes).
6528 * - Disregards, and does not modify, the stream's position
6529 * (see {Position}[rdoc-ref:IO@Position]).
6530 * - Bypasses any user space buffering in the stream.
6531 *
6532 * Because this method does not disturb the stream's state
6533 * (its position, in particular), +pread+ allows multiple threads and processes
6534 * to use the same \IO object for reading at various offsets.
6535 *
6536 * f = File.open('t.txt')
6537 * f.read # => "First line\nSecond line\n\nFourth line\nFifth line\n"
6538 * f.pos # => 52
6539 * # Read 12 bytes at offset 0.
6540 * f.pread(12, 0) # => "First line\n"
6541 * # Read 9 bytes at offset 8.
6542 * f.pread(9, 8) # => "ne\nSecon"
6543 * f.close
6544 *
6545 * Not available on some platforms.
6546 *
6547 */
6548static VALUE
6549rb_io_pread(int argc, VALUE *argv, VALUE io)
6550{
6551 VALUE len, offset, str;
6552 rb_io_t *fptr;
6553 ssize_t n;
6554 struct prdwr_internal_arg arg;
6555 int shrinkable;
6556
6557 rb_scan_args(argc, argv, "21", &len, &offset, &str);
6558 arg.count = NUM2SIZET(len);
6559 arg.offset = NUM2OFFT(offset);
6560
6561 shrinkable = io_setstrbuf(&str, (long)arg.count);
6562 if (arg.count == 0) return str;
6563 arg.buf = RSTRING_PTR(str);
6564
6565 GetOpenFile(io, fptr);
6567
6568 arg.io = fptr;
6569 arg.fd = fptr->fd;
6570 rb_io_check_closed(fptr);
6571
6572 rb_str_locktmp(str);
6573 n = (ssize_t)rb_ensure(pread_internal_call, (VALUE)&arg, rb_str_unlocktmp, str);
6574
6575 if (n < 0) {
6576 rb_sys_fail_path(fptr->pathv);
6577 }
6578 io_set_read_length(str, n, shrinkable);
6579 if (n == 0 && arg.count > 0) {
6580 rb_eof_error();
6581 }
6582
6583 return str;
6584}
6585
6586static VALUE
6587internal_pwrite_func(void *_arg)
6588{
6589 struct prdwr_internal_arg *arg = _arg;
6590
6591 return (VALUE)pwrite(arg->fd, arg->buf, arg->count, arg->offset);
6592}
6593
6594static VALUE
6595pwrite_internal_call(VALUE _arg)
6596{
6597 struct prdwr_internal_arg *arg = (struct prdwr_internal_arg *)_arg;
6598
6599 VALUE scheduler = rb_fiber_scheduler_current();
6600 if (scheduler != Qnil) {
6601 VALUE result = rb_fiber_scheduler_io_pwrite_memory(scheduler, arg->io->self, arg->offset, arg->buf, arg->count);
6602
6603 if (!UNDEF_P(result)) {
6605 }
6606 }
6607
6608 return rb_io_blocking_region_wait(arg->io, internal_pwrite_func, arg, RUBY_IO_WRITABLE);
6609}
6610
6611/*
6612 * call-seq:
6613 * pwrite(object, offset) -> integer
6614 *
6615 * Behaves like IO#write, except that it:
6616 *
6617 * - Writes at the given +offset+ (in bytes).
6618 * - Disregards, and does not modify, the stream's position
6619 * (see {Position}[rdoc-ref:IO@Position]).
6620 * - Bypasses any user space buffering in the stream.
6621 *
6622 * Because this method does not disturb the stream's state
6623 * (its position, in particular), +pwrite+ allows multiple threads and processes
6624 * to use the same \IO object for writing at various offsets.
6625 *
6626 * f = File.open('t.tmp', 'w+')
6627 * # Write 6 bytes at offset 3.
6628 * f.pwrite('ABCDEF', 3) # => 6
6629 * f.rewind
6630 * f.read # => "\u0000\u0000\u0000ABCDEF"
6631 * f.close
6632 *
6633 * Not available on some platforms.
6634 *
6635 */
6636static VALUE
6637rb_io_pwrite(VALUE io, VALUE str, VALUE offset)
6638{
6639 rb_io_t *fptr;
6640 ssize_t n;
6641 struct prdwr_internal_arg arg;
6642 VALUE tmp;
6643
6644 if (!RB_TYPE_P(str, T_STRING))
6645 str = rb_obj_as_string(str);
6646
6647 arg.offset = NUM2OFFT(offset);
6648
6649 io = GetWriteIO(io);
6650 GetOpenFile(io, fptr);
6652
6653 arg.io = fptr;
6654 arg.fd = fptr->fd;
6655
6656 tmp = rb_str_tmp_frozen_acquire(str);
6657 arg.buf = RSTRING_PTR(tmp);
6658 arg.count = (size_t)RSTRING_LEN(tmp);
6659
6660 n = (ssize_t)pwrite_internal_call((VALUE)&arg);
6661 if (n < 0) rb_sys_fail_path(fptr->pathv);
6662 rb_str_tmp_frozen_release(str, tmp);
6663
6664 return SSIZET2NUM(n);
6665}
6666
6667VALUE
6669{
6670 rb_io_t *fptr;
6671
6672 GetOpenFile(io, fptr);
6673 if (fptr->readconv)
6675 if (fptr->writeconv)
6677 fptr->mode |= FMODE_BINMODE;
6678 fptr->mode &= ~FMODE_TEXTMODE;
6679 fptr->writeconv_pre_ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
6680#ifdef O_BINARY
6681 if (!fptr->readconv) {
6682 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6683 }
6684 else {
6685 setmode(fptr->fd, O_BINARY);
6686 }
6687#endif
6688 return io;
6689}
6690
6691static void
6692io_ascii8bit_binmode(rb_io_t *fptr)
6693{
6694 if (fptr->readconv) {
6695 rb_econv_close(fptr->readconv);
6696 fptr->readconv = NULL;
6697 }
6698 if (fptr->writeconv) {
6700 fptr->writeconv = NULL;
6701 }
6702 fptr->mode |= FMODE_BINMODE;
6703 fptr->mode &= ~FMODE_TEXTMODE;
6704 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6705
6706 fptr->encs.enc = rb_ascii8bit_encoding();
6707 fptr->encs.enc2 = NULL;
6708 fptr->encs.ecflags = 0;
6709 fptr->encs.ecopts = Qnil;
6710 clear_codeconv(fptr);
6711}
6712
6713VALUE
6715{
6716 rb_io_t *fptr;
6717
6718 GetOpenFile(io, fptr);
6719 io_ascii8bit_binmode(fptr);
6720
6721 return io;
6722}
6723
6724/*
6725 * call-seq:
6726 * binmode -> self
6727 *
6728 * Sets the stream's data mode as binary
6729 * (see {Data Mode}[rdoc-ref:File@Data+Mode]).
6730 *
6731 * A stream's data mode may not be changed from binary to text.
6732 *
6733 */
6734
6735static VALUE
6736rb_io_binmode_m(VALUE io)
6737{
6738 VALUE write_io;
6739
6741
6742 write_io = GetWriteIO(io);
6743 if (write_io != io)
6744 rb_io_ascii8bit_binmode(write_io);
6745 return io;
6746}
6747
6748/*
6749 * call-seq:
6750 * binmode? -> true or false
6751 *
6752 * Returns +true+ if the stream is on binary mode, +false+ otherwise.
6753 * See {Data Mode}[rdoc-ref:File@Data+Mode].
6754 *
6755 */
6756static VALUE
6757rb_io_binmode_p(VALUE io)
6758{
6759 rb_io_t *fptr;
6760 GetOpenFile(io, fptr);
6761 return RBOOL(fptr->mode & FMODE_BINMODE);
6762}
6763
6764static const char*
6765rb_io_fmode_modestr(enum rb_io_mode fmode)
6766{
6767 if (fmode & FMODE_APPEND) {
6768 if ((fmode & FMODE_READWRITE) == FMODE_READWRITE) {
6769 return MODE_BTMODE("a+", "ab+", "at+");
6770 }
6771 return MODE_BTMODE("a", "ab", "at");
6772 }
6773 switch (fmode & FMODE_READWRITE) {
6774 default:
6775 rb_raise(rb_eArgError, "invalid access fmode 0x%x", fmode);
6776 case FMODE_READABLE:
6777 return MODE_BTMODE("r", "rb", "rt");
6778 case FMODE_WRITABLE:
6779 return MODE_BTXMODE("w", "wb", "wt", "wx", "wbx", "wtx");
6780 case FMODE_READWRITE:
6781 if (fmode & FMODE_CREATE) {
6782 return MODE_BTXMODE("w+", "wb+", "wt+", "w+x", "wb+x", "wt+x");
6783 }
6784 return MODE_BTMODE("r+", "rb+", "rt+");
6785 }
6786}
6787
6788static const char bom_prefix[] = "bom|";
6789static const char utf_prefix[] = "utf-";
6790enum {bom_prefix_len = (int)sizeof(bom_prefix) - 1};
6791enum {utf_prefix_len = (int)sizeof(utf_prefix) - 1};
6792
6793static int
6794io_encname_bom_p(const char *name, long len)
6795{
6796 return len > bom_prefix_len && STRNCASECMP(name, bom_prefix, bom_prefix_len) == 0;
6797}
6798
6799enum rb_io_mode
6800rb_io_modestr_fmode(const char *modestr)
6801{
6802 enum rb_io_mode fmode = 0;
6803 const char *m = modestr, *p = NULL;
6804
6805 switch (*m++) {
6806 case 'r':
6807 fmode |= FMODE_READABLE;
6808 break;
6809 case 'w':
6811 break;
6812 case 'a':
6814 break;
6815 default:
6816 goto error;
6817 }
6818
6819 while (*m) {
6820 switch (*m++) {
6821 case 'b':
6822 fmode |= FMODE_BINMODE;
6823 break;
6824 case 't':
6825 fmode |= FMODE_TEXTMODE;
6826 break;
6827 case '+':
6828 fmode |= FMODE_READWRITE;
6829 break;
6830 case 'x':
6831 if (modestr[0] != 'w')
6832 goto error;
6833 fmode |= FMODE_EXCL;
6834 break;
6835 default:
6836 goto error;
6837 case ':':
6838 p = strchr(m, ':');
6839 if (io_encname_bom_p(m, p ? (long)(p - m) : (long)strlen(m)))
6840 fmode |= FMODE_SETENC_BY_BOM;
6841 goto finished;
6842 }
6843 }
6844
6845 finished:
6846 if ((fmode & FMODE_BINMODE) && (fmode & FMODE_TEXTMODE))
6847 goto error;
6848
6849 return fmode;
6850
6851 error:
6852 rb_raise(rb_eArgError, "invalid access mode %s", modestr);
6854}
6855
6856int
6857rb_io_oflags_fmode(int oflags)
6858{
6859 enum rb_io_mode fmode = 0;
6860
6861 switch (oflags & O_ACCMODE) {
6862 case O_RDONLY:
6863 fmode = FMODE_READABLE;
6864 break;
6865 case O_WRONLY:
6866 fmode = FMODE_WRITABLE;
6867 break;
6868 case O_RDWR:
6869 fmode = FMODE_READWRITE;
6870 break;
6871 }
6872
6873 if (oflags & O_APPEND) {
6874 fmode |= FMODE_APPEND;
6875 }
6876 if (oflags & O_TRUNC) {
6877 fmode |= FMODE_TRUNC;
6878 }
6879 if (oflags & O_CREAT) {
6880 fmode |= FMODE_CREATE;
6881 }
6882 if (oflags & O_EXCL) {
6883 fmode |= FMODE_EXCL;
6884 }
6885#ifdef O_BINARY
6886 if (oflags & O_BINARY) {
6887 fmode |= FMODE_BINMODE;
6888 }
6889#endif
6890
6891 return fmode;
6892}
6893
6894static int
6895rb_io_fmode_oflags(enum rb_io_mode fmode)
6896{
6897 int oflags = 0;
6898
6899 switch (fmode & FMODE_READWRITE) {
6900 case FMODE_READABLE:
6901 oflags |= O_RDONLY;
6902 break;
6903 case FMODE_WRITABLE:
6904 oflags |= O_WRONLY;
6905 break;
6906 case FMODE_READWRITE:
6907 oflags |= O_RDWR;
6908 break;
6909 }
6910
6911 if (fmode & FMODE_APPEND) {
6912 oflags |= O_APPEND;
6913 }
6914 if (fmode & FMODE_TRUNC) {
6915 oflags |= O_TRUNC;
6916 }
6917 if (fmode & FMODE_CREATE) {
6918 oflags |= O_CREAT;
6919 }
6920 if (fmode & FMODE_EXCL) {
6921 oflags |= O_EXCL;
6922 }
6923#ifdef O_BINARY
6924 if (fmode & FMODE_BINMODE) {
6925 oflags |= O_BINARY;
6926 }
6927#endif
6928
6929 return oflags;
6930}
6931
6932int
6933rb_io_modestr_oflags(const char *modestr)
6934{
6935 return rb_io_fmode_oflags(rb_io_modestr_fmode(modestr));
6936}
6937
6938static const char*
6939rb_io_oflags_modestr(int oflags)
6940{
6941#ifdef O_BINARY
6942# define MODE_BINARY(a,b) ((oflags & O_BINARY) ? (b) : (a))
6943#else
6944# define MODE_BINARY(a,b) (a)
6945#endif
6946 int accmode;
6947 if (oflags & O_EXCL) {
6948 rb_raise(rb_eArgError, "exclusive access mode is not supported");
6949 }
6950 accmode = oflags & (O_RDONLY|O_WRONLY|O_RDWR);
6951 if (oflags & O_APPEND) {
6952 if (accmode == O_WRONLY) {
6953 return MODE_BINARY("a", "ab");
6954 }
6955 if (accmode == O_RDWR) {
6956 return MODE_BINARY("a+", "ab+");
6957 }
6958 }
6959 switch (accmode) {
6960 default:
6961 rb_raise(rb_eArgError, "invalid access oflags 0x%x", oflags);
6962 case O_RDONLY:
6963 return MODE_BINARY("r", "rb");
6964 case O_WRONLY:
6965 return MODE_BINARY("w", "wb");
6966 case O_RDWR:
6967 if (oflags & O_TRUNC) {
6968 return MODE_BINARY("w+", "wb+");
6969 }
6970 return MODE_BINARY("r+", "rb+");
6971 }
6972}
6973
6974/*
6975 * Convert external/internal encodings to enc/enc2
6976 * NULL => use default encoding
6977 * Qnil => no encoding specified (internal only)
6978 */
6979static void
6980rb_io_ext_int_to_encs(rb_encoding *ext, rb_encoding *intern, rb_encoding **enc, rb_encoding **enc2, enum rb_io_mode fmode)
6981{
6982 int default_ext = 0;
6983
6984 if (ext == NULL) {
6985 ext = rb_default_external_encoding();
6986 default_ext = 1;
6987 }
6988 if (rb_is_ascii8bit_enc(ext)) {
6989 /* If external is ASCII-8BIT, no transcoding */
6990 intern = NULL;
6991 }
6992 else if (intern == NULL) {
6993 intern = rb_default_internal_encoding();
6994 }
6995 if (intern == NULL || intern == (rb_encoding *)Qnil ||
6996 (!(fmode & FMODE_SETENC_BY_BOM) && (intern == ext))) {
6997 /* No internal encoding => use external + no transcoding */
6998 *enc = (default_ext && intern != ext) ? NULL : ext;
6999 *enc2 = NULL;
7000 }
7001 else {
7002 *enc = intern;
7003 *enc2 = ext;
7004 }
7005}
7006
7007static void
7008unsupported_encoding(const char *name, rb_encoding *enc)
7009{
7010 rb_enc_warn(enc, "Unsupported encoding %s ignored", name);
7011}
7012
7013static void
7014parse_mode_enc(const char *estr, rb_encoding *estr_enc,
7015 rb_encoding **enc_p, rb_encoding **enc2_p, enum rb_io_mode *fmode_p)
7016{
7017 const char *p;
7018 char encname[ENCODING_MAXNAMELEN+1];
7019 int idx, idx2;
7020 enum rb_io_mode fmode = fmode_p ? *fmode_p : 0;
7021 rb_encoding *ext_enc, *int_enc;
7022 long len;
7023
7024 /* parse estr as "enc" or "enc2:enc" or "enc:-" */
7025
7026 p = strrchr(estr, ':');
7027 len = p ? (p++ - estr) : (long)strlen(estr);
7028 if ((fmode & FMODE_SETENC_BY_BOM) || io_encname_bom_p(estr, len)) {
7029 estr += bom_prefix_len;
7030 len -= bom_prefix_len;
7031 if (!STRNCASECMP(estr, utf_prefix, utf_prefix_len)) {
7032 fmode |= FMODE_SETENC_BY_BOM;
7033 }
7034 else {
7035 rb_enc_warn(estr_enc, "BOM with non-UTF encoding %s is nonsense", estr);
7036 fmode &= ~FMODE_SETENC_BY_BOM;
7037 }
7038 }
7039 if (len == 0 || len > ENCODING_MAXNAMELEN) {
7040 idx = -1;
7041 }
7042 else {
7043 if (p) {
7044 memcpy(encname, estr, len);
7045 encname[len] = '\0';
7046 estr = encname;
7047 }
7048 idx = rb_enc_find_index(estr);
7049 }
7050 if (fmode_p) *fmode_p = fmode;
7051
7052 if (idx >= 0)
7053 ext_enc = rb_enc_from_index(idx);
7054 else {
7055 if (idx != -2)
7056 unsupported_encoding(estr, estr_enc);
7057 ext_enc = NULL;
7058 }
7059
7060 int_enc = NULL;
7061 if (p) {
7062 if (*p == '-' && *(p+1) == '\0') {
7063 /* Special case - "-" => no transcoding */
7064 int_enc = (rb_encoding *)Qnil;
7065 }
7066 else {
7067 idx2 = rb_enc_find_index(p);
7068 if (idx2 < 0)
7069 unsupported_encoding(p, estr_enc);
7070 else if (!(fmode & FMODE_SETENC_BY_BOM) && (idx2 == idx)) {
7071 int_enc = (rb_encoding *)Qnil;
7072 }
7073 else
7074 int_enc = rb_enc_from_index(idx2);
7075 }
7076 }
7077
7078 rb_io_ext_int_to_encs(ext_enc, int_enc, enc_p, enc2_p, fmode);
7079}
7080
7081int
7082rb_io_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding **enc2_p, enum rb_io_mode *fmode_p)
7083{
7084 VALUE encoding=Qnil, extenc=Qundef, intenc=Qundef, tmp;
7085 int extracted = 0;
7086 rb_encoding *extencoding = NULL;
7087 rb_encoding *intencoding = NULL;
7088
7089 if (!NIL_P(opt)) {
7090 VALUE v;
7091 v = rb_hash_lookup2(opt, sym_encoding, Qnil);
7092 if (v != Qnil) encoding = v;
7093 v = rb_hash_lookup2(opt, sym_extenc, Qundef);
7094 if (v != Qnil) extenc = v;
7095 v = rb_hash_lookup2(opt, sym_intenc, Qundef);
7096 if (!UNDEF_P(v)) intenc = v;
7097 }
7098 if ((!UNDEF_P(extenc) || !UNDEF_P(intenc)) && !NIL_P(encoding)) {
7099 if (!NIL_P(ruby_verbose)) {
7100 int idx = rb_to_encoding_index(encoding);
7101 if (idx >= 0) encoding = rb_enc_from_encoding(rb_enc_from_index(idx));
7102 rb_warn("Ignoring encoding parameter '%"PRIsVALUE"': %s_encoding is used",
7103 encoding, UNDEF_P(extenc) ? "internal" : "external");
7104 }
7105 encoding = Qnil;
7106 }
7107 if (!UNDEF_P(extenc) && !NIL_P(extenc)) {
7108 extencoding = rb_to_encoding(extenc);
7109 }
7110 if (!UNDEF_P(intenc)) {
7111 if (NIL_P(intenc)) {
7112 /* internal_encoding: nil => no transcoding */
7113 intencoding = (rb_encoding *)Qnil;
7114 }
7115 else if (!NIL_P(tmp = rb_check_string_type(intenc))) {
7116 char *p = StringValueCStr(tmp);
7117
7118 if (*p == '-' && *(p+1) == '\0') {
7119 /* Special case - "-" => no transcoding */
7120 intencoding = (rb_encoding *)Qnil;
7121 }
7122 else {
7123 intencoding = rb_to_encoding(intenc);
7124 }
7125 }
7126 else {
7127 intencoding = rb_to_encoding(intenc);
7128 }
7129 if (extencoding == intencoding) {
7130 intencoding = (rb_encoding *)Qnil;
7131 }
7132 }
7133 if (!NIL_P(encoding)) {
7134 extracted = 1;
7135 if (!NIL_P(tmp = rb_check_string_type(encoding))) {
7136 parse_mode_enc(StringValueCStr(tmp), rb_enc_get(tmp),
7137 enc_p, enc2_p, fmode_p);
7138 }
7139 else {
7140 rb_io_ext_int_to_encs(rb_to_encoding(encoding), NULL, enc_p, enc2_p, 0);
7141 }
7142 }
7143 else if (!UNDEF_P(extenc) || !UNDEF_P(intenc)) {
7144 extracted = 1;
7145 rb_io_ext_int_to_encs(extencoding, intencoding, enc_p, enc2_p, 0);
7146 }
7147 return extracted;
7148}
7149
7150static void
7151validate_enc_binmode(enum rb_io_mode *fmode_p, int ecflags, rb_encoding *enc, rb_encoding *enc2)
7152{
7153 enum rb_io_mode fmode = *fmode_p;
7154
7155 if ((fmode & FMODE_READABLE) &&
7156 !enc2 &&
7157 !(fmode & FMODE_BINMODE) &&
7158 !rb_enc_asciicompat(enc ? enc : rb_default_external_encoding()))
7159 rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
7160
7161 if ((fmode & FMODE_BINMODE) && (ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
7162 rb_raise(rb_eArgError, "newline decorator with binary mode");
7163 }
7164 if (!(fmode & FMODE_BINMODE) &&
7165 (DEFAULT_TEXTMODE || (ecflags & ECONV_NEWLINE_DECORATOR_MASK))) {
7166 fmode |= FMODE_TEXTMODE;
7167 *fmode_p = fmode;
7168 }
7169#if !DEFAULT_TEXTMODE
7170 else if (!(ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
7171 fmode &= ~FMODE_TEXTMODE;
7172 *fmode_p = fmode;
7173 }
7174#endif
7175}
7176
7177static void
7178extract_binmode(VALUE opthash, enum rb_io_mode *fmode)
7179{
7180 if (!NIL_P(opthash)) {
7181 VALUE v;
7182 v = rb_hash_aref(opthash, sym_textmode);
7183 if (!NIL_P(v)) {
7184 if (*fmode & FMODE_TEXTMODE)
7185 rb_raise(rb_eArgError, "textmode specified twice");
7186 if (*fmode & FMODE_BINMODE)
7187 rb_raise(rb_eArgError, "both textmode and binmode specified");
7188 if (RTEST(v))
7189 *fmode |= FMODE_TEXTMODE;
7190 }
7191 v = rb_hash_aref(opthash, sym_binmode);
7192 if (!NIL_P(v)) {
7193 if (*fmode & FMODE_BINMODE)
7194 rb_raise(rb_eArgError, "binmode specified twice");
7195 if (*fmode & FMODE_TEXTMODE)
7196 rb_raise(rb_eArgError, "both textmode and binmode specified");
7197 if (RTEST(v))
7198 *fmode |= FMODE_BINMODE;
7199 }
7200
7201 if ((*fmode & FMODE_BINMODE) && (*fmode & FMODE_TEXTMODE))
7202 rb_raise(rb_eArgError, "both textmode and binmode specified");
7203 }
7204}
7205
7206void
7207rb_io_extract_modeenc(VALUE *vmode_p, VALUE *vperm_p, VALUE opthash,
7208 int *oflags_p, enum rb_io_mode *fmode_p, struct rb_io_encoding *convconfig_p)
7209{
7210 VALUE vmode;
7211 int oflags;
7212 enum rb_io_mode fmode;
7213 rb_encoding *enc, *enc2;
7214 int ecflags;
7215 VALUE ecopts;
7216 int has_enc = 0, has_vmode = 0;
7217 VALUE intmode;
7218
7219 vmode = *vmode_p;
7220
7221 /* Set to defaults */
7222 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
7223
7224 vmode_handle:
7225 if (NIL_P(vmode)) {
7226 fmode = FMODE_READABLE;
7227 oflags = O_RDONLY;
7228 }
7229 else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int"))) {
7230 vmode = intmode;
7231 oflags = NUM2INT(intmode);
7232 fmode = rb_io_oflags_fmode(oflags);
7233 }
7234 else {
7235 const char *p;
7236
7237 StringValue(vmode);
7238 p = StringValueCStr(vmode);
7239 fmode = rb_io_modestr_fmode(p);
7240 oflags = rb_io_fmode_oflags(fmode);
7241 p = strchr(p, ':');
7242 if (p) {
7243 has_enc = 1;
7244 parse_mode_enc(p+1, rb_enc_get(vmode), &enc, &enc2, &fmode);
7245 }
7246 else {
7247 rb_encoding *e;
7248
7249 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
7250 rb_io_ext_int_to_encs(e, NULL, &enc, &enc2, fmode);
7251 }
7252 }
7253
7254 if (NIL_P(opthash)) {
7255 ecflags = (fmode & FMODE_READABLE) ?
7258#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7259 ecflags |= (fmode & FMODE_WRITABLE) ?
7260 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7261 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7262#endif
7263 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
7264 ecopts = Qnil;
7265 if (fmode & FMODE_BINMODE) {
7266#ifdef O_BINARY
7267 oflags |= O_BINARY;
7268#endif
7269 if (!has_enc)
7270 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
7271 }
7272#if DEFAULT_TEXTMODE
7273 else if (NIL_P(vmode)) {
7274 fmode |= DEFAULT_TEXTMODE;
7275 }
7276#endif
7277 }
7278 else {
7279 VALUE v;
7280 if (!has_vmode) {
7281 v = rb_hash_aref(opthash, sym_mode);
7282 if (!NIL_P(v)) {
7283 if (!NIL_P(vmode)) {
7284 rb_raise(rb_eArgError, "mode specified twice");
7285 }
7286 has_vmode = 1;
7287 vmode = v;
7288 goto vmode_handle;
7289 }
7290 }
7291 v = rb_hash_aref(opthash, sym_flags);
7292 if (!NIL_P(v)) {
7293 v = rb_to_int(v);
7294 oflags |= NUM2INT(v);
7295 vmode = INT2NUM(oflags);
7296 fmode = rb_io_oflags_fmode(oflags);
7297 }
7298 extract_binmode(opthash, &fmode);
7299 if (fmode & FMODE_BINMODE) {
7300#ifdef O_BINARY
7301 oflags |= O_BINARY;
7302#endif
7303 if (!has_enc)
7304 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
7305 }
7306#if DEFAULT_TEXTMODE
7307 else if (NIL_P(vmode)) {
7308 fmode |= DEFAULT_TEXTMODE;
7309 }
7310#endif
7311 v = rb_hash_aref(opthash, sym_perm);
7312 if (!NIL_P(v)) {
7313 if (vperm_p) {
7314 if (!NIL_P(*vperm_p)) {
7315 rb_raise(rb_eArgError, "perm specified twice");
7316 }
7317 *vperm_p = v;
7318 }
7319 else {
7320 /* perm no use, just ignore */
7321 }
7322 }
7323 ecflags = (fmode & FMODE_READABLE) ?
7326#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7327 ecflags |= (fmode & FMODE_WRITABLE) ?
7328 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7329 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7330#endif
7331
7332 if (rb_io_extract_encoding_option(opthash, &enc, &enc2, &fmode)) {
7333 if (has_enc) {
7334 rb_raise(rb_eArgError, "encoding specified twice");
7335 }
7336 }
7337 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
7338 ecflags = rb_econv_prepare_options(opthash, &ecopts, ecflags);
7339 }
7340
7341 validate_enc_binmode(&fmode, ecflags, enc, enc2);
7342
7343 *vmode_p = vmode;
7344
7345 *oflags_p = oflags;
7346 *fmode_p = fmode;
7347 convconfig_p->enc = enc;
7348 convconfig_p->enc2 = enc2;
7349 convconfig_p->ecflags = ecflags;
7350 convconfig_p->ecopts = ecopts;
7351}
7352
7354 VALUE fname;
7355 int oflags;
7356 mode_t perm;
7357};
7358
7359static void *
7360sysopen_func(void *ptr)
7361{
7362 const struct sysopen_struct *data = ptr;
7363 const char *fname = RSTRING_PTR(data->fname);
7364 return (void *)(VALUE)rb_cloexec_open(fname, data->oflags, data->perm);
7365}
7366
7367static inline int
7368rb_sysopen_internal(struct sysopen_struct *data)
7369{
7370 int fd;
7371 do {
7372 fd = IO_WITHOUT_GVL_INT(sysopen_func, data);
7373 } while (fd < 0 && errno == EINTR);
7374 if (0 <= fd)
7375 rb_update_max_fd(fd);
7376 return fd;
7377}
7378
7379static int
7380rb_sysopen(VALUE fname, int oflags, mode_t perm)
7381{
7382 int fd = -1;
7383 struct sysopen_struct data;
7384
7385 data.fname = rb_str_encode_ospath(fname);
7386 StringValueCStr(data.fname);
7387 data.oflags = oflags;
7388 data.perm = perm;
7389
7390 TRY_WITH_GC((fd = rb_sysopen_internal(&data)) >= 0) {
7391 rb_syserr_fail_path(first_errno, fname);
7392 }
7393 return fd;
7394}
7395
7396static inline FILE *
7397fdopen_internal(int fd, const char *modestr)
7398{
7399 FILE *file;
7400
7401#if defined(__sun)
7402 errno = 0;
7403#endif
7404 file = fdopen(fd, modestr);
7405 if (!file) {
7406#ifdef _WIN32
7407 if (errno == 0) errno = EINVAL;
7408#elif defined(__sun)
7409 if (errno == 0) errno = EMFILE;
7410#endif
7411 }
7412 return file;
7413}
7414
7415FILE *
7416rb_fdopen(int fd, const char *modestr)
7417{
7418 FILE *file = 0;
7419
7420 TRY_WITH_GC((file = fdopen_internal(fd, modestr)) != 0) {
7421 rb_syserr_fail(first_errno, 0);
7422 }
7423
7424 /* xxx: should be _IONBF? A buffer in FILE may have trouble. */
7425#ifdef USE_SETVBUF
7426 if (setvbuf(file, NULL, _IOFBF, 0) != 0)
7427 rb_warn("setvbuf() can't be honoured (fd=%d)", fd);
7428#endif
7429 return file;
7430}
7431
7432static int
7433io_check_tty(rb_io_t *fptr)
7434{
7435 int t = isatty(fptr->fd);
7436 if (t)
7437 fptr->mode |= FMODE_TTY|FMODE_DUPLEX;
7438 return t;
7439}
7440
7441static VALUE rb_io_internal_encoding(VALUE);
7442static void io_encoding_set(rb_io_t *, VALUE, VALUE, VALUE);
7443
7444static int
7445io_strip_bom(VALUE io)
7446{
7447 VALUE b1, b2, b3, b4;
7448 rb_io_t *fptr;
7449
7450 GetOpenFile(io, fptr);
7451 if (!(fptr->mode & FMODE_READABLE)) return 0;
7452 if (NIL_P(b1 = rb_io_getbyte(io))) return 0;
7453 switch (b1) {
7454 case INT2FIX(0xEF):
7455 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7456 if (b2 == INT2FIX(0xBB) && !NIL_P(b3 = rb_io_getbyte(io))) {
7457 if (b3 == INT2FIX(0xBF)) {
7458 return rb_utf8_encindex();
7459 }
7460 rb_io_ungetbyte(io, b3);
7461 }
7462 rb_io_ungetbyte(io, b2);
7463 break;
7464
7465 case INT2FIX(0xFE):
7466 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7467 if (b2 == INT2FIX(0xFF)) {
7468 return ENCINDEX_UTF_16BE;
7469 }
7470 rb_io_ungetbyte(io, b2);
7471 break;
7472
7473 case INT2FIX(0xFF):
7474 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7475 if (b2 == INT2FIX(0xFE)) {
7476 b3 = rb_io_getbyte(io);
7477 if (b3 == INT2FIX(0) && !NIL_P(b4 = rb_io_getbyte(io))) {
7478 if (b4 == INT2FIX(0)) {
7479 return ENCINDEX_UTF_32LE;
7480 }
7481 rb_io_ungetbyte(io, b4);
7482 }
7483 rb_io_ungetbyte(io, b3);
7484 return ENCINDEX_UTF_16LE;
7485 }
7486 rb_io_ungetbyte(io, b2);
7487 break;
7488
7489 case INT2FIX(0):
7490 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7491 if (b2 == INT2FIX(0) && !NIL_P(b3 = rb_io_getbyte(io))) {
7492 if (b3 == INT2FIX(0xFE) && !NIL_P(b4 = rb_io_getbyte(io))) {
7493 if (b4 == INT2FIX(0xFF)) {
7494 return ENCINDEX_UTF_32BE;
7495 }
7496 rb_io_ungetbyte(io, b4);
7497 }
7498 rb_io_ungetbyte(io, b3);
7499 }
7500 rb_io_ungetbyte(io, b2);
7501 break;
7502 }
7503 rb_io_ungetbyte(io, b1);
7504 return 0;
7505}
7506
7507static rb_encoding *
7508io_set_encoding_by_bom(VALUE io)
7509{
7510 int idx = io_strip_bom(io);
7511 rb_io_t *fptr;
7512 rb_encoding *extenc = NULL;
7513
7514 GetOpenFile(io, fptr);
7515 if (idx) {
7516 extenc = rb_enc_from_index(idx);
7517 io_encoding_set(fptr, rb_enc_from_encoding(extenc),
7518 rb_io_internal_encoding(io), Qnil);
7519 }
7520 else {
7521 fptr->encs.enc2 = NULL;
7522 }
7523 return extenc;
7524}
7525
7526static VALUE
7527rb_file_open_generic(VALUE io, VALUE filename, int oflags, enum rb_io_mode fmode,
7528 const struct rb_io_encoding *convconfig, mode_t perm)
7529{
7530 VALUE pathv;
7531 rb_io_t *fptr;
7532 struct rb_io_encoding cc;
7533 if (!convconfig) {
7534 /* Set to default encodings */
7535 rb_io_ext_int_to_encs(NULL, NULL, &cc.enc, &cc.enc2, fmode);
7536 cc.ecflags = 0;
7537 cc.ecopts = Qnil;
7538 convconfig = &cc;
7539 }
7540 validate_enc_binmode(&fmode, convconfig->ecflags,
7541 convconfig->enc, convconfig->enc2);
7542
7543 MakeOpenFile(io, fptr);
7544 fptr->mode = fmode;
7545 fptr->encs = *convconfig;
7546 pathv = rb_str_new_frozen(filename);
7547#ifdef O_TMPFILE
7548 if (!(oflags & O_TMPFILE)) {
7549 fptr->pathv = pathv;
7550 }
7551#else
7552 fptr->pathv = pathv;
7553#endif
7554 fptr->fd = rb_sysopen(pathv, oflags, perm);
7555 io_check_tty(fptr);
7556 if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
7557
7558 return io;
7559}
7560
7561static VALUE
7562rb_file_open_internal(VALUE io, VALUE filename, const char *modestr)
7563{
7564 enum rb_io_mode fmode = rb_io_modestr_fmode(modestr);
7565 const char *p = strchr(modestr, ':');
7566 struct rb_io_encoding convconfig;
7567
7568 if (p) {
7569 parse_mode_enc(p+1, rb_usascii_encoding(),
7570 &convconfig.enc, &convconfig.enc2, &fmode);
7571 }
7572 else {
7573 rb_encoding *e;
7574 /* Set to default encodings */
7575
7576 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
7577 rb_io_ext_int_to_encs(e, NULL, &convconfig.enc, &convconfig.enc2, fmode);
7578 }
7579
7580 convconfig.ecflags = (fmode & FMODE_READABLE) ?
7583#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7584 convconfig.ecflags |= (fmode & FMODE_WRITABLE) ?
7585 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7586 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7587#endif
7588 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.enc2, convconfig.ecflags);
7589 convconfig.ecopts = Qnil;
7590
7591 return rb_file_open_generic(io, filename,
7592 rb_io_fmode_oflags(fmode),
7593 fmode,
7594 &convconfig,
7595 0666);
7596}
7597
7598VALUE
7599rb_file_open_str(VALUE fname, const char *modestr)
7600{
7601 FilePathValue(fname);
7602 return rb_file_open_internal(io_alloc(rb_cFile), fname, modestr);
7603}
7604
7605VALUE
7606rb_file_open(const char *fname, const char *modestr)
7607{
7608 return rb_file_open_internal(io_alloc(rb_cFile), rb_str_new_cstr(fname), modestr);
7609}
7610
7611#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7612static struct pipe_list {
7613 rb_io_t *fptr;
7614 struct pipe_list *next;
7615} *pipe_list;
7616
7617static void
7618pipe_add_fptr(rb_io_t *fptr)
7619{
7620 struct pipe_list *list;
7621
7622 list = ALLOC(struct pipe_list);
7623 list->fptr = fptr;
7624 list->next = pipe_list;
7625 pipe_list = list;
7626}
7627
7628static void
7629pipe_del_fptr(rb_io_t *fptr)
7630{
7631 struct pipe_list **prev = &pipe_list;
7632 struct pipe_list *tmp;
7633
7634 while ((tmp = *prev) != 0) {
7635 if (tmp->fptr == fptr) {
7636 *prev = tmp->next;
7637 free(tmp);
7638 return;
7639 }
7640 prev = &tmp->next;
7641 }
7642}
7643
7644#if defined (_WIN32) || defined(__CYGWIN__)
7645static void
7646pipe_atexit(void)
7647{
7648 struct pipe_list *list = pipe_list;
7649 struct pipe_list *tmp;
7650
7651 while (list) {
7652 tmp = list->next;
7653 rb_io_fptr_finalize(list->fptr);
7654 list = tmp;
7655 }
7656}
7657#endif
7658
7659static void
7660pipe_finalize(rb_io_t *fptr, int noraise)
7661{
7662#if !defined(HAVE_WORKING_FORK) && !defined(_WIN32)
7663 int status = 0;
7664 if (fptr->stdio_file) {
7665 status = pclose(fptr->stdio_file);
7666 }
7667 fptr->fd = -1;
7668 fptr->stdio_file = 0;
7669 rb_last_status_set(status, fptr->pid);
7670#else
7671 fptr_finalize(fptr, noraise);
7672#endif
7673 pipe_del_fptr(fptr);
7674}
7675#endif
7676
7677static void
7678fptr_copy_finalizer(rb_io_t *fptr, const rb_io_t *orig)
7679{
7680#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7681 void (*const old_finalize)(struct rb_io*,int) = fptr->finalize;
7682
7683 if (old_finalize == orig->finalize) return;
7684#endif
7685
7686 fptr->finalize = orig->finalize;
7687
7688#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7689 if (old_finalize != pipe_finalize) {
7690 struct pipe_list *list;
7691 for (list = pipe_list; list; list = list->next) {
7692 if (list->fptr == fptr) break;
7693 }
7694 if (!list) pipe_add_fptr(fptr);
7695 }
7696 else {
7697 pipe_del_fptr(fptr);
7698 }
7699#endif
7700}
7701
7702void
7704{
7706 fptr->mode |= FMODE_SYNC;
7707}
7708
7709
7710int
7711rb_pipe(int *pipes)
7712{
7713 int ret;
7714 TRY_WITH_GC((ret = rb_cloexec_pipe(pipes)) >= 0);
7715 if (ret == 0) {
7716 rb_update_max_fd(pipes[0]);
7717 rb_update_max_fd(pipes[1]);
7718 }
7719 return ret;
7720}
7721
7722#ifdef _WIN32
7723#define spawnv(mode, cmd, args) rb_w32_uaspawn((mode), (cmd), (args))
7724#define spawn(mode, cmd) rb_w32_uspawn((mode), (cmd), 0)
7725#endif
7726
7727#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7728struct popen_arg {
7729 VALUE execarg_obj;
7730 struct rb_execarg *eargp;
7731 int modef;
7732 int pair[2];
7733 int write_pair[2];
7734};
7735#endif
7736
7737#ifdef HAVE_WORKING_FORK
7738# ifndef __EMSCRIPTEN__
7739static void
7740popen_redirect(struct popen_arg *p)
7741{
7742 if ((p->modef & FMODE_READABLE) && (p->modef & FMODE_WRITABLE)) {
7743 close(p->write_pair[1]);
7744 if (p->write_pair[0] != 0) {
7745 dup2(p->write_pair[0], 0);
7746 close(p->write_pair[0]);
7747 }
7748 close(p->pair[0]);
7749 if (p->pair[1] != 1) {
7750 dup2(p->pair[1], 1);
7751 close(p->pair[1]);
7752 }
7753 }
7754 else if (p->modef & FMODE_READABLE) {
7755 close(p->pair[0]);
7756 if (p->pair[1] != 1) {
7757 dup2(p->pair[1], 1);
7758 close(p->pair[1]);
7759 }
7760 }
7761 else {
7762 close(p->pair[1]);
7763 if (p->pair[0] != 0) {
7764 dup2(p->pair[0], 0);
7765 close(p->pair[0]);
7766 }
7767 }
7768}
7769# endif
7770
7771#if defined(__linux__)
7772/* Linux /proc/self/status contains a line: "FDSize:\t<nnn>\n"
7773 * Since /proc may not be available, linux_get_maxfd is just a hint.
7774 * This function, linux_get_maxfd, must be async-signal-safe.
7775 * I.e. opendir() is not usable.
7776 *
7777 * Note that memchr() and memcmp is *not* async-signal-safe in POSIX.
7778 * However they are easy to re-implement in async-signal-safe manner.
7779 * (Also note that there is missing/memcmp.c.)
7780 */
7781static int
7782linux_get_maxfd(void)
7783{
7784 int fd;
7785 char buf[4096], *p, *np, *e;
7786 ssize_t ss;
7787 fd = rb_cloexec_open("/proc/self/status", O_RDONLY|O_NOCTTY, 0);
7788 if (fd < 0) return fd;
7789 ss = read(fd, buf, sizeof(buf));
7790 if (ss < 0) goto err;
7791 p = buf;
7792 e = buf + ss;
7793 while ((int)sizeof("FDSize:\t0\n")-1 <= e-p &&
7794 (np = memchr(p, '\n', e-p)) != NULL) {
7795 if (memcmp(p, "FDSize:", sizeof("FDSize:")-1) == 0) {
7796 int fdsize;
7797 p += sizeof("FDSize:")-1;
7798 *np = '\0';
7799 fdsize = (int)ruby_strtoul(p, (char **)NULL, 10);
7800 close(fd);
7801 return fdsize;
7802 }
7803 p = np+1;
7804 }
7805 /* fall through */
7806
7807 err:
7808 close(fd);
7809 return (int)ss;
7810}
7811#endif
7812
7813/* This function should be async-signal-safe. */
7814void
7815rb_close_before_exec(int lowfd, int maxhint, VALUE noclose_fds)
7816{
7817#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
7818 int fd, ret;
7819 int max = (int)max_file_descriptor;
7820# ifdef F_MAXFD
7821 /* F_MAXFD is available since NetBSD 2.0. */
7822 ret = fcntl(0, F_MAXFD); /* async-signal-safe */
7823 if (ret != -1)
7824 maxhint = max = ret;
7825# elif defined(__linux__)
7826 ret = linux_get_maxfd();
7827 if (maxhint < ret)
7828 maxhint = ret;
7829 /* maxhint = max = ret; if (ret == -1) abort(); // test */
7830# endif
7831 if (max < maxhint)
7832 max = maxhint;
7833 for (fd = lowfd; fd <= max; fd++) {
7834 if (!NIL_P(noclose_fds) &&
7835 RTEST(rb_hash_lookup(noclose_fds, INT2FIX(fd)))) /* async-signal-safe */
7836 continue;
7837 ret = fcntl(fd, F_GETFD); /* async-signal-safe */
7838 if (ret != -1 && !(ret & FD_CLOEXEC)) {
7839 fcntl(fd, F_SETFD, ret|FD_CLOEXEC); /* async-signal-safe */
7840 }
7841# define CONTIGUOUS_CLOSED_FDS 20
7842 if (ret != -1) {
7843 if (max < fd + CONTIGUOUS_CLOSED_FDS)
7844 max = fd + CONTIGUOUS_CLOSED_FDS;
7845 }
7846 }
7847#endif
7848}
7849
7850# ifndef __EMSCRIPTEN__
7851static int
7852popen_exec(void *pp, char *errmsg, size_t errmsg_len)
7853{
7854 struct popen_arg *p = (struct popen_arg*)pp;
7855
7856 return rb_exec_async_signal_safe(p->eargp, errmsg, errmsg_len);
7857}
7858# endif
7859#endif
7860
7861#if (defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)) && !defined __EMSCRIPTEN__
7862static VALUE
7863rb_execarg_fixup_v(VALUE execarg_obj)
7864{
7865 rb_execarg_parent_start(execarg_obj);
7866 return Qnil;
7867}
7868#else
7869char *rb_execarg_commandline(const struct rb_execarg *eargp, VALUE *prog);
7870#endif
7871
7872#ifndef __EMSCRIPTEN__
7873static VALUE
7874pipe_open(VALUE execarg_obj, const char *modestr, enum rb_io_mode fmode,
7875 const struct rb_io_encoding *convconfig)
7876{
7877 struct rb_execarg *eargp = NIL_P(execarg_obj) ? NULL : rb_execarg_get(execarg_obj);
7878 VALUE prog = eargp ? (eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name) : Qfalse ;
7879 rb_pid_t pid = 0;
7880 rb_io_t *fptr;
7881 VALUE port;
7882 rb_io_t *write_fptr;
7883 VALUE write_port;
7884#if defined(HAVE_WORKING_FORK)
7885 int status;
7886 char errmsg[80] = { '\0' };
7887#endif
7888#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7889 int state;
7890 struct popen_arg arg;
7891#endif
7892 int e = 0;
7893#if defined(HAVE_SPAWNV)
7894# define DO_SPAWN(cmd, args) ((args) ? \
7895 spawnv(P_NOWAIT, (cmd), (args)) : \
7896 spawn(P_NOWAIT, (cmd)))
7897# if !defined(HAVE_WORKING_FORK)
7898 char **args = NULL;
7899# endif
7900#endif
7901#if !defined(HAVE_WORKING_FORK)
7902 struct rb_execarg sarg, *sargp = &sarg;
7903#endif
7904 FILE *fp = 0;
7905 int fd = -1;
7906 int write_fd = -1;
7907#if !defined(HAVE_WORKING_FORK)
7908 const char *cmd = 0;
7909
7910 if (prog)
7911 cmd = StringValueCStr(prog);
7912#endif
7913
7914#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7915 arg.execarg_obj = execarg_obj;
7916 arg.eargp = eargp;
7917 arg.modef = fmode;
7918 arg.pair[0] = arg.pair[1] = -1;
7919 arg.write_pair[0] = arg.write_pair[1] = -1;
7920# if !defined(HAVE_WORKING_FORK)
7921 if (eargp && !eargp->use_shell) {
7922 args = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
7923 }
7924# endif
7925 switch (fmode & (FMODE_READABLE|FMODE_WRITABLE)) {
7927 if (rb_pipe(arg.write_pair) < 0)
7928 rb_sys_fail_str(prog);
7929 if (rb_pipe(arg.pair) < 0) {
7930 e = errno;
7931 close(arg.write_pair[0]);
7932 close(arg.write_pair[1]);
7933 rb_syserr_fail_str(e, prog);
7934 }
7935 if (eargp) {
7936 rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.write_pair[0]));
7937 rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
7938 }
7939 break;
7940 case FMODE_READABLE:
7941 if (rb_pipe(arg.pair) < 0)
7942 rb_sys_fail_str(prog);
7943 if (eargp)
7944 rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
7945 break;
7946 case FMODE_WRITABLE:
7947 if (rb_pipe(arg.pair) < 0)
7948 rb_sys_fail_str(prog);
7949 if (eargp)
7950 rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.pair[0]));
7951 break;
7952 default:
7953 rb_sys_fail_str(prog);
7954 }
7955 if (!NIL_P(execarg_obj)) {
7956 rb_protect(rb_execarg_fixup_v, execarg_obj, &state);
7957 if (state) {
7958 if (0 <= arg.write_pair[0]) close(arg.write_pair[0]);
7959 if (0 <= arg.write_pair[1]) close(arg.write_pair[1]);
7960 if (0 <= arg.pair[0]) close(arg.pair[0]);
7961 if (0 <= arg.pair[1]) close(arg.pair[1]);
7962 rb_execarg_parent_end(execarg_obj);
7963 rb_jump_tag(state);
7964 }
7965
7966# if defined(HAVE_WORKING_FORK)
7967 pid = rb_fork_async_signal_safe(&status, popen_exec, &arg, arg.eargp->redirect_fds, errmsg, sizeof(errmsg));
7968# else
7969 rb_execarg_run_options(eargp, sargp, NULL, 0);
7970 while ((pid = DO_SPAWN(cmd, args)) < 0) {
7971 /* exec failed */
7972 switch (e = errno) {
7973 case EAGAIN:
7974# if EWOULDBLOCK != EAGAIN
7975 case EWOULDBLOCK:
7976# endif
7977 rb_thread_sleep(1);
7978 continue;
7979 }
7980 break;
7981 }
7982 if (eargp)
7983 rb_execarg_run_options(sargp, NULL, NULL, 0);
7984# endif
7985 rb_execarg_parent_end(execarg_obj);
7986 }
7987 else {
7988# if defined(HAVE_WORKING_FORK)
7989 pid = rb_call_proc__fork();
7990 if (pid == 0) { /* child */
7991 popen_redirect(&arg);
7992 rb_io_synchronized(RFILE(orig_stdout)->fptr);
7993 rb_io_synchronized(RFILE(orig_stderr)->fptr);
7994 return Qnil;
7995 }
7996# else
7997 rb_notimplement();
7998# endif
7999 }
8000
8001 /* parent */
8002 if (pid < 0) {
8003# if defined(HAVE_WORKING_FORK)
8004 e = errno;
8005# endif
8006 close(arg.pair[0]);
8007 close(arg.pair[1]);
8009 close(arg.write_pair[0]);
8010 close(arg.write_pair[1]);
8011 }
8012# if defined(HAVE_WORKING_FORK)
8013 if (errmsg[0])
8014 rb_syserr_fail(e, errmsg);
8015# endif
8016 rb_syserr_fail_str(e, prog);
8017 }
8018 if ((fmode & FMODE_READABLE) && (fmode & FMODE_WRITABLE)) {
8019 close(arg.pair[1]);
8020 fd = arg.pair[0];
8021 close(arg.write_pair[0]);
8022 write_fd = arg.write_pair[1];
8023 }
8024 else if (fmode & FMODE_READABLE) {
8025 close(arg.pair[1]);
8026 fd = arg.pair[0];
8027 }
8028 else {
8029 close(arg.pair[0]);
8030 fd = arg.pair[1];
8031 }
8032#else
8033 cmd = rb_execarg_commandline(eargp, &prog);
8034 if (!NIL_P(execarg_obj)) {
8035 rb_execarg_parent_start(execarg_obj);
8036 rb_execarg_run_options(eargp, sargp, NULL, 0);
8037 }
8038 fp = popen(cmd, modestr);
8039 e = errno;
8040 if (eargp) {
8041 rb_execarg_parent_end(execarg_obj);
8042 rb_execarg_run_options(sargp, NULL, NULL, 0);
8043 }
8044 if (!fp) rb_syserr_fail_path(e, prog);
8045 fd = fileno(fp);
8046#endif
8047
8048 port = io_alloc(rb_cIO);
8049 MakeOpenFile(port, fptr);
8050 fptr->fd = fd;
8051 fptr->stdio_file = fp;
8052 fptr->mode = fmode | FMODE_SYNC|FMODE_DUPLEX;
8053 if (convconfig) {
8054 fptr->encs = *convconfig;
8055#if RUBY_CRLF_ENVIRONMENT
8058 }
8059#endif
8060 }
8061 else {
8062 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
8064 }
8065#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
8066 if (NEED_NEWLINE_DECORATOR_ON_WRITE(fptr)) {
8067 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
8068 }
8069#endif
8070 }
8071 fptr->pid = pid;
8072
8073 if (0 <= write_fd) {
8074 write_port = io_alloc(rb_cIO);
8075 MakeOpenFile(write_port, write_fptr);
8076 write_fptr->fd = write_fd;
8077 write_fptr->mode = (fmode & ~FMODE_READABLE)| FMODE_SYNC|FMODE_DUPLEX;
8078 fptr->mode &= ~FMODE_WRITABLE;
8079 fptr->tied_io_for_writing = write_port;
8080 rb_ivar_set(port, rb_intern("@tied_io_for_writing"), write_port);
8081 }
8082
8083#if defined (__CYGWIN__) || !defined(HAVE_WORKING_FORK)
8084 fptr->finalize = pipe_finalize;
8085 pipe_add_fptr(fptr);
8086#endif
8087 return port;
8088}
8089#else
8090static VALUE
8091pipe_open(VALUE execarg_obj, const char *modestr, enum rb_io_mode fmode,
8092 const struct rb_io_encoding *convconfig)
8093{
8094 rb_raise(rb_eNotImpError, "popen() is not available");
8095}
8096#endif
8097
8098static int
8099is_popen_fork(VALUE prog)
8100{
8101 if (RSTRING_LEN(prog) == 1 && RSTRING_PTR(prog)[0] == '-') {
8102#if !defined(HAVE_WORKING_FORK)
8103 rb_raise(rb_eNotImpError,
8104 "fork() function is unimplemented on this machine");
8105#else
8106 return TRUE;
8107#endif
8108 }
8109 return FALSE;
8110}
8111
8112static VALUE
8113pipe_open_s(VALUE prog, const char *modestr, enum rb_io_mode fmode,
8114 const struct rb_io_encoding *convconfig)
8115{
8116 int argc = 1;
8117 VALUE *argv = &prog;
8118 VALUE execarg_obj = Qnil;
8119
8120 if (!is_popen_fork(prog))
8121 execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
8122 return pipe_open(execarg_obj, modestr, fmode, convconfig);
8123}
8124
8125static VALUE
8126pipe_close(VALUE io)
8127{
8128 rb_io_t *fptr = io_close_fptr(io);
8129 if (fptr) {
8130 fptr_waitpid(fptr, rb_thread_to_be_killed(rb_thread_current()));
8131 }
8132 return Qnil;
8133}
8134
8135static VALUE popen_finish(VALUE port, VALUE klass);
8136
8137/*
8138 * call-seq:
8139 * IO.popen(env = {}, cmd, mode = 'r', **opts) -> io
8140 * IO.popen(env = {}, cmd, mode = 'r', **opts) {|io| ... } -> object
8141 *
8142 * Executes the given command +cmd+ as a subprocess
8143 * whose $stdin and $stdout are connected to a new stream +io+.
8144 *
8145 * This method has potential security vulnerabilities if called with untrusted input;
8146 * see {Command Injection}[rdoc-ref:security/command_injection.rdoc].
8147 *
8148 * If no block is given, returns the new stream,
8149 * which depending on given +mode+ may be open for reading, writing, or both.
8150 * The stream should be explicitly closed (eventually) to avoid resource leaks.
8151 *
8152 * If a block is given, the stream is passed to the block
8153 * (again, open for reading, writing, or both);
8154 * when the block exits, the stream is closed,
8155 * the block's value is returned,
8156 * and the global variable <tt>$?</tt> is set to the child's exit status.
8157 *
8158 * Optional argument +mode+ may be any valid \IO mode.
8159 * See {Access Modes}[rdoc-ref:File@Access+Modes].
8160 *
8161 * Required argument +cmd+ determines which of the following occurs:
8162 *
8163 * - The process forks.
8164 * - A specified program runs in a shell.
8165 * - A specified program runs with specified arguments.
8166 * - A specified program runs with specified arguments and a specified +argv0+.
8167 *
8168 * Each of these is detailed below.
8169 *
8170 * The optional hash argument +env+ specifies name/value pairs that are to be added
8171 * to the environment variables for the subprocess:
8172 *
8173 * IO.popen({'FOO' => 'bar'}, 'ruby', 'r+') do |pipe|
8174 * pipe.puts 'puts ENV["FOO"]'
8175 * pipe.close_write
8176 * pipe.gets
8177 * end => "bar\n"
8178 *
8179 * Optional keyword arguments +opts+ specify:
8180 *
8181 * - {Open options}[rdoc-ref:IO@Open+Options].
8182 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
8183 * - Options for Kernel#spawn.
8184 *
8185 * <b>Forked Process</b>
8186 *
8187 * When argument +cmd+ is the 1-character string <tt>'-'</tt>, causes the process to fork:
8188 * IO.popen('-') do |pipe|
8189 * if pipe
8190 * $stderr.puts "In parent, child pid is #{pipe.pid}\n"
8191 * else
8192 * $stderr.puts "In child, pid is #{$$}\n"
8193 * end
8194 * end
8195 *
8196 * Output:
8197 *
8198 * In parent, child pid is 26253
8199 * In child, pid is 26253
8200 *
8201 * Note that this is not supported on all platforms.
8202 *
8203 * <b>Shell Subprocess</b>
8204 *
8205 * When argument +cmd+ is a single string (but not <tt>'-'</tt>),
8206 * the program named +cmd+ is run as a shell command:
8207 *
8208 * IO.popen('uname') do |pipe|
8209 * pipe.readlines
8210 * end
8211 *
8212 * Output:
8213 *
8214 * ["Linux\n"]
8215 *
8216 * Another example:
8217 *
8218 * IO.popen('/bin/sh', 'r+') do |pipe|
8219 * pipe.puts('ls')
8220 * pipe.close_write
8221 * $stderr.puts pipe.readlines.size
8222 * end
8223 *
8224 * Output:
8225 *
8226 * 213
8227 *
8228 * <b>Program Subprocess</b>
8229 *
8230 * When argument +cmd+ is an array of strings,
8231 * the program named <tt>cmd[0]</tt> is run with all elements of +cmd+ as its arguments:
8232 *
8233 * IO.popen(['du', '..', '.']) do |pipe|
8234 * $stderr.puts pipe.readlines.size
8235 * end
8236 *
8237 * Output:
8238 *
8239 * 1111
8240 *
8241 * <b>Program Subprocess with <tt>argv0</tt></b>
8242 *
8243 * When argument +cmd+ is an array whose first element is a 2-element string array
8244 * and whose remaining elements (if any) are strings:
8245 *
8246 * - <tt>cmd[0][0]</tt> (the first string in the nested array) is the name of a program that is run.
8247 * - <tt>cmd[0][1]</tt> (the second string in the nested array) is set as the program's <tt>argv[0]</tt>.
8248 * - <tt>cmd[1..-1]</tt> (the strings in the outer array) are the program's arguments.
8249 *
8250 * Example (sets <tt>$0</tt> to 'foo'):
8251 *
8252 * IO.popen([['/bin/sh', 'foo'], '-c', 'echo $0']).read # => "foo\n"
8253 *
8254 * <b>Some Special Examples</b>
8255 *
8256 * # Set IO encoding.
8257 * IO.popen("nkf -e filename", :external_encoding=>"EUC-JP") {|nkf_io|
8258 * euc_jp_string = nkf_io.read
8259 * }
8260 *
8261 * # Merge standard output and standard error using Kernel#spawn option. See Kernel#spawn.
8262 * IO.popen(["ls", "/", :err=>[:child, :out]]) do |io|
8263 * ls_result_with_error = io.read
8264 * end
8265 *
8266 * # Use mixture of spawn options and IO options.
8267 * IO.popen(["ls", "/"], :err=>[:child, :out]) do |io|
8268 * ls_result_with_error = io.read
8269 * end
8270 *
8271 * f = IO.popen("uname")
8272 * p f.readlines
8273 * f.close
8274 * puts "Parent is #{Process.pid}"
8275 * IO.popen("date") {|f| puts f.gets }
8276 * IO.popen("-") {|f| $stderr.puts "#{Process.pid} is here, f is #{f.inspect}"}
8277 * p $?
8278 * IO.popen(%w"sed -e s|^|<foo>| -e s&$&;zot;&", "r+") {|f|
8279 * f.puts "bar"; f.close_write; puts f.gets
8280 * }
8281 *
8282 * Output (from last section):
8283 *
8284 * ["Linux\n"]
8285 * Parent is 21346
8286 * Thu Jan 15 22:41:19 JST 2009
8287 * 21346 is here, f is #<IO:fd 3>
8288 * 21352 is here, f is nil
8289 * #<Process::Status: pid 21352 exit 0>
8290 * <foo>bar;zot;
8291 *
8292 * Raises exceptions that IO.pipe and Kernel.spawn raise.
8293 *
8294 */
8295
8296static VALUE
8297rb_io_s_popen(int argc, VALUE *argv, VALUE klass)
8298{
8299 VALUE pname, pmode = Qnil, opt = Qnil, env = Qnil;
8300
8301 if (argc > 1 && !NIL_P(opt = rb_check_hash_type(argv[argc-1]))) --argc;
8302 if (argc > 1 && !NIL_P(env = rb_check_hash_type(argv[0]))) --argc, ++argv;
8303 switch (argc) {
8304 case 2:
8305 pmode = argv[1];
8306 case 1:
8307 pname = argv[0];
8308 break;
8309 default:
8310 {
8311 int ex = !NIL_P(opt);
8312 rb_error_arity(argc + ex, 1 + ex, 2 + ex);
8313 }
8314 }
8315 return popen_finish(rb_io_popen(pname, pmode, env, opt), klass);
8316}
8317
8318VALUE
8319rb_io_popen(VALUE pname, VALUE pmode, VALUE env, VALUE opt)
8320{
8321 const char *modestr;
8322 VALUE tmp, execarg_obj = Qnil;
8323 int oflags;
8324 enum rb_io_mode fmode;
8325 struct rb_io_encoding convconfig;
8326
8327 tmp = rb_check_array_type(pname);
8328 if (!NIL_P(tmp)) {
8329 long len = RARRAY_LEN(tmp);
8330#if SIZEOF_LONG > SIZEOF_INT
8331 if (len > INT_MAX) {
8332 rb_raise(rb_eArgError, "too many arguments");
8333 }
8334#endif
8335 execarg_obj = rb_execarg_new((int)len, RARRAY_CONST_PTR(tmp), FALSE, FALSE);
8336 RB_GC_GUARD(tmp);
8337 }
8338 else {
8339 StringValue(pname);
8340 execarg_obj = Qnil;
8341 if (!is_popen_fork(pname))
8342 execarg_obj = rb_execarg_new(1, &pname, TRUE, FALSE);
8343 }
8344 if (!NIL_P(execarg_obj)) {
8345 if (!NIL_P(opt))
8346 opt = rb_execarg_extract_options(execarg_obj, opt);
8347 if (!NIL_P(env))
8348 rb_execarg_setenv(execarg_obj, env);
8349 }
8350 rb_io_extract_modeenc(&pmode, 0, opt, &oflags, &fmode, &convconfig);
8351 modestr = rb_io_oflags_modestr(oflags);
8352
8353 return pipe_open(execarg_obj, modestr, fmode, &convconfig);
8354}
8355
8356static VALUE
8357popen_finish(VALUE port, VALUE klass)
8358{
8359 if (NIL_P(port)) {
8360 /* child */
8361 if (rb_block_given_p()) {
8362 rb_protect(rb_yield, Qnil, NULL);
8363 rb_io_flush(rb_ractor_stdout());
8364 rb_io_flush(rb_ractor_stderr());
8365 _exit(EXIT_SUCCESS);
8366 }
8367 return Qnil;
8368 }
8369 RBASIC_SET_CLASS(port, klass);
8370 if (rb_block_given_p()) {
8371 return rb_ensure(rb_yield, port, pipe_close, port);
8372 }
8373 return port;
8374}
8375
8376#if defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)
8377struct popen_writer_arg {
8378 char *const *argv;
8379 struct popen_arg popen;
8380};
8381
8382static int
8383exec_popen_writer(void *arg, char *errmsg, size_t buflen)
8384{
8385 struct popen_writer_arg *pw = arg;
8386 pw->popen.modef = FMODE_WRITABLE;
8387 popen_redirect(&pw->popen);
8388 execv(pw->argv[0], pw->argv);
8389 strlcpy(errmsg, strerror(errno), buflen);
8390 return -1;
8391}
8392#endif
8393
8394FILE *
8395ruby_popen_writer(char *const *argv, rb_pid_t *pid)
8396{
8397#if (defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)) || defined(_WIN32)
8398# ifdef HAVE_WORKING_FORK
8399 struct popen_writer_arg pw;
8400 int *const write_pair = pw.popen.pair;
8401# else
8402 int write_pair[2];
8403# endif
8404
8405 *pid = -1;
8406 if (cloexec_pipe(write_pair, 0, false) == 0) {
8407# ifdef HAVE_WORKING_FORK
8408 pw.argv = argv;
8409 int status;
8410 char errmsg[80] = {'\0'};
8411 *pid = rb_fork_async_signal_safe(&status, exec_popen_writer, &pw, Qnil, errmsg, sizeof(errmsg));
8412# else
8413 *pid = rb_w32_uspawn_process(P_NOWAIT, argv[0], argv, write_pair[0], -1, -1, 0);
8414 const char *errmsg = (*pid < 0) ? strerror(errno) : NULL;
8415# endif
8416 close(write_pair[0]);
8417 if (*pid < 0) {
8418 close(write_pair[1]);
8419 fprintf(stderr, "ruby_popen_writer(%s): %s\n", argv[0], errmsg);
8420 }
8421 else {
8422 return fdopen(write_pair[1], "w");
8423 }
8424 }
8425#endif
8426 return NULL;
8427}
8428
8429static VALUE
8430rb_open_file(VALUE io, VALUE fname, VALUE vmode, VALUE vperm, VALUE opt)
8431{
8432 int oflags;
8433 enum rb_io_mode fmode;
8434 struct rb_io_encoding convconfig;
8435 mode_t perm;
8436
8437 FilePathValue(fname);
8438
8439 rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, &convconfig);
8440 perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
8441
8442 rb_file_open_generic(io, fname, oflags, fmode, &convconfig, perm);
8443
8444 return io;
8445}
8446
8447/*
8448 * Document-method: File::open
8449 *
8450 * :markup: markdown
8451 *
8452 * call-seq:
8453 * File.open(path, mode = 'r', permissions = 0666, **options) -> file
8454 * File.open(path, mode = 'r', permissions = 0666, **options) {|file| ... } -> object
8455 *
8456 * Creates a new \File object via File.new with the given arguments.
8457 *
8458 * With no block given, returns the \File object.
8459 *
8460 * With a block given, calls the block with the \File object,
8461 * closes the \File object, and returns the block's value:
8462 *
8463 * ```ruby
8464 * File.open('doc/maintainers.md') {|file| file.size } # => 14900
8465 * ```
8466 *
8467 * Note that the \File object is automatically closed
8468 * even if the block raises an exception.
8469 */
8470
8471/*
8472 * Document-method: IO::open
8473 *
8474 * :markup: markdown
8475 *
8476 * call-seq:
8477 * IO.open(fd, mode = 'r', **options) -> io
8478 * IO.open(fd, mode = 'r', **options) {|io| ... } -> object
8479 *
8480 * Creates a new \IO object via IO.new with the given arguments.
8481 *
8482 * With no block given, returns the \IO object.
8483 *
8484 * With a block given, calls the block with the \IO object,
8485 * closes the \IO object, and returns the block’s value:
8486 *
8487 * ```ruby
8488 * fd = File.sysopen('doc/maintainers.md') # => 6
8489 * IO.open(fd) {|io| io.read.size } # => 14897
8490 * ```
8491 */
8492
8493static VALUE
8494rb_io_s_open(int argc, VALUE *argv, VALUE klass)
8495{
8497
8498 if (rb_block_given_p()) {
8499 return rb_ensure(rb_yield, io, io_close, io);
8500 }
8501
8502 return io;
8503}
8504
8505/*
8506 * call-seq:
8507 * IO.sysopen(path, mode = 'r', perm = 0666) -> integer
8508 *
8509 * Opens the file at the given path with the given mode and permissions;
8510 * returns the integer file descriptor.
8511 *
8512 * If the file is to be readable, it must exist;
8513 * if the file is to be writable and does not exist,
8514 * it is created with the given permissions:
8515 *
8516 * File.write('t.tmp', '') # => 0
8517 * IO.sysopen('t.tmp') # => 8
8518 * IO.sysopen('t.tmp', 'w') # => 9
8519 *
8520 *
8521 */
8522
8523static VALUE
8524rb_io_s_sysopen(int argc, VALUE *argv, VALUE _)
8525{
8526 VALUE fname, vmode, vperm;
8527 VALUE intmode;
8528 int oflags, fd;
8529 mode_t perm;
8530
8531 rb_scan_args(argc, argv, "12", &fname, &vmode, &vperm);
8532 FilePathValue(fname);
8533
8534 if (NIL_P(vmode))
8535 oflags = O_RDONLY;
8536 else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int")))
8537 oflags = NUM2INT(intmode);
8538 else {
8539 StringValue(vmode);
8540 oflags = rb_io_modestr_oflags(StringValueCStr(vmode));
8541 }
8542 if (NIL_P(vperm)) perm = 0666;
8543 else perm = NUM2MODET(vperm);
8544
8545 RB_GC_GUARD(fname) = rb_str_new4(fname);
8546 fd = rb_sysopen(fname, oflags, perm);
8547 return INT2NUM(fd);
8548}
8549
8550/*
8551 * call-seq:
8552 * open(path, mode = 'r', perm = 0666, **opts) -> io or nil
8553 * open(path, mode = 'r', perm = 0666, **opts) {|io| ... } -> obj
8554 *
8555 * Creates an IO object connected to the given file.
8556 *
8557 * With no block given, file stream is returned:
8558 *
8559 * open('t.txt') # => #<File:t.txt>
8560 *
8561 * With a block given, calls the block with the open file stream,
8562 * then closes the stream:
8563 *
8564 * open('t.txt') {|f| p f } # => #<File:t.txt (closed)>
8565 *
8566 * Output:
8567 *
8568 * #<File:t.txt>
8569 *
8570 * See File.open for details.
8571 *
8572 */
8573
8574static VALUE
8575rb_f_open(int argc, VALUE *argv, VALUE _)
8576{
8577 ID to_open = 0;
8578 int redirect = FALSE;
8579
8580 if (argc >= 1) {
8581 CONST_ID(to_open, "to_open");
8582 if (rb_respond_to(argv[0], to_open)) {
8583 redirect = TRUE;
8584 }
8585 else {
8586 VALUE tmp = argv[0];
8587 FilePathValue(tmp);
8588 if (NIL_P(tmp)) {
8589 redirect = TRUE;
8590 }
8591 else {
8592 argv[0] = tmp;
8593 }
8594 }
8595 }
8596 if (redirect) {
8597 VALUE io = rb_funcallv_kw(argv[0], to_open, argc-1, argv+1, RB_PASS_CALLED_KEYWORDS);
8598
8599 if (rb_block_given_p()) {
8600 return rb_ensure(rb_yield, io, io_close, io);
8601 }
8602 return io;
8603 }
8604 return rb_io_s_open(argc, argv, rb_cFile);
8605}
8606
8607static VALUE
8608rb_io_open_generic(VALUE klass, VALUE filename, int oflags, enum rb_io_mode fmode,
8609 const struct rb_io_encoding *convconfig, mode_t perm)
8610{
8611 return rb_file_open_generic(io_alloc(klass), filename,
8612 oflags, fmode, convconfig, perm);
8613}
8614
8615static VALUE
8616rb_io_open(VALUE io, VALUE filename, VALUE vmode, VALUE vperm, VALUE opt)
8617{
8618 int oflags;
8619 enum rb_io_mode fmode;
8620 struct rb_io_encoding convconfig;
8621 mode_t perm;
8622
8623 rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, &convconfig);
8624 perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
8625 return rb_io_open_generic(io, filename, oflags, fmode, &convconfig, perm);
8626}
8627
8628static VALUE
8629io_reopen(VALUE io, VALUE nfile)
8630{
8631 rb_io_t *fptr, *orig;
8632 int fd, fd2;
8633 rb_off_t pos = 0;
8634
8635 nfile = rb_io_get_io(nfile);
8636 GetOpenFile(io, fptr);
8637 GetOpenFile(nfile, orig);
8638
8639 if (fptr == orig) return io;
8640 if (RUBY_IO_EXTERNAL_P(fptr)) {
8641 if ((fptr->stdio_file == stdin && !(orig->mode & FMODE_READABLE)) ||
8642 (fptr->stdio_file == stdout && !(orig->mode & FMODE_WRITABLE)) ||
8643 (fptr->stdio_file == stderr && !(orig->mode & FMODE_WRITABLE))) {
8644 rb_raise(rb_eArgError,
8645 "%s can't change access mode from \"%s\" to \"%s\"",
8646 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
8647 rb_io_fmode_modestr(orig->mode));
8648 }
8649 }
8650 flush_before_seek(fptr, true);
8651 /* in flush_before_seek, clear_codeconv called only if rbuf is filled */
8652 clear_codeconv(fptr);
8653 if (orig->mode & FMODE_READABLE) {
8654 pos = io_tell(orig);
8655 }
8656 if (orig->mode & FMODE_WRITABLE) {
8657 if (io_fflush(orig) < 0)
8658 rb_sys_fail_on_write(fptr);
8659 }
8660
8661 /* copy rb_io_t structure */
8662 fptr->mode = orig->mode | (fptr->mode & FMODE_EXTERNAL);
8663 fptr->encs = orig->encs;
8664 fptr->pid = orig->pid;
8665 fptr->lineno = orig->lineno;
8666 if (RTEST(orig->pathv)) fptr->pathv = orig->pathv;
8667 else if (!RUBY_IO_EXTERNAL_P(fptr)) fptr->pathv = Qnil;
8668 fptr_copy_finalizer(fptr, orig);
8669
8670 fd = fptr->fd;
8671 fd2 = orig->fd;
8672 if (fd != fd2) {
8673 // Interrupt all usage of the old file descriptor:
8674 rb_thread_io_close_interrupt(fptr);
8675 rb_thread_io_close_wait(fptr);
8676
8677 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2 || !fptr->stdio_file) {
8678 /* need to keep FILE objects of stdin, stdout and stderr */
8679 if (rb_cloexec_dup2(fd2, fd) < 0)
8680 rb_sys_fail_path(orig->pathv);
8681 rb_update_max_fd(fd);
8682 }
8683 else {
8684 fclose(fptr->stdio_file);
8685 fptr->stdio_file = 0;
8686 fptr->fd = -1;
8687 if (rb_cloexec_dup2(fd2, fd) < 0)
8688 rb_sys_fail_path(orig->pathv);
8689 rb_update_max_fd(fd);
8690 fptr->fd = fd;
8691 }
8692
8693 if ((orig->mode & FMODE_READABLE) && pos >= 0) {
8694 if (io_seek(fptr, pos, SEEK_SET) < 0 && errno) {
8695 rb_sys_fail_path(fptr->pathv);
8696 }
8697 if (io_seek(orig, pos, SEEK_SET) < 0 && errno) {
8698 rb_sys_fail_path(orig->pathv);
8699 }
8700 }
8701 }
8702
8703 if (fptr->mode & FMODE_BINMODE) {
8704 rb_io_binmode(io);
8705 }
8706
8707 RBASIC_SET_CLASS(io, rb_obj_class(nfile));
8708 return io;
8709}
8710
8711#ifdef _WIN32
8712int rb_freopen(VALUE fname, const char *mode, FILE *fp);
8713#else
8714static int
8715rb_freopen(VALUE fname, const char *mode, FILE *fp)
8716{
8717 if (!freopen(RSTRING_PTR(fname), mode, fp)) {
8718 RB_GC_GUARD(fname);
8719 return errno;
8720 }
8721 return 0;
8722}
8723#endif
8724
8725/*
8726 * call-seq:
8727 * reopen(other_io) -> self
8728 * reopen(path, mode = 'r', **opts) -> self
8729 *
8730 * Reassociates the stream with another stream,
8731 * which may be of a different class.
8732 * This method may be used to redirect an existing stream
8733 * to a new destination.
8734 *
8735 * With argument +other_io+ given, reassociates with that stream:
8736 *
8737 * # Redirect $stdin from a file.
8738 * f = File.open('t.txt')
8739 * $stdin.reopen(f)
8740 * f.close
8741 *
8742 * # Redirect $stdout to a file.
8743 * f = File.open('t.tmp', 'w')
8744 * $stdout.reopen(f)
8745 * f.close
8746 *
8747 * With argument +path+ given, reassociates with a new stream to that file path:
8748 *
8749 * $stdin.reopen('t.txt')
8750 * $stdout.reopen('t.tmp', 'w')
8751 *
8752 * Optional keyword arguments +opts+ specify:
8753 *
8754 * - {Open Options}[rdoc-ref:IO@Open+Options].
8755 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
8756 *
8757 */
8758
8759static VALUE
8760rb_io_reopen(int argc, VALUE *argv, VALUE file)
8761{
8762 VALUE fname, nmode, opt;
8763 int oflags;
8764 rb_io_t *fptr;
8765
8766 if (rb_scan_args(argc, argv, "11:", &fname, &nmode, &opt) == 1) {
8767 VALUE tmp = rb_io_check_io(fname);
8768 if (!NIL_P(tmp)) {
8769 return io_reopen(file, tmp);
8770 }
8771 }
8772
8773 FilePathValue(fname);
8774 rb_io_taint_check(file);
8775 fptr = RFILE(file)->fptr;
8776 if (!fptr) {
8777 fptr = RFILE(file)->fptr = ZALLOC(rb_io_t);
8778 }
8779
8780 if (!NIL_P(nmode) || !NIL_P(opt)) {
8781 enum rb_io_mode fmode;
8782 struct rb_io_encoding convconfig;
8783
8784 rb_io_extract_modeenc(&nmode, 0, opt, &oflags, &fmode, &convconfig);
8785 if (RUBY_IO_EXTERNAL_P(fptr) &&
8786 ((fptr->mode & FMODE_READWRITE) & (fmode & FMODE_READWRITE)) !=
8787 (fptr->mode & FMODE_READWRITE)) {
8788 rb_raise(rb_eArgError,
8789 "%s can't change access mode from \"%s\" to \"%s\"",
8790 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
8791 rb_io_fmode_modestr(fmode));
8792 }
8793 fptr->mode = fmode;
8794 fptr->encs = convconfig;
8795 }
8796 else {
8797 oflags = rb_io_fmode_oflags(fptr->mode);
8798 }
8799
8800 fptr->pathv = fname;
8801 if (fptr->fd < 0) {
8802 fptr->fd = rb_sysopen(fptr->pathv, oflags, 0666);
8803 fptr->stdio_file = 0;
8804 return file;
8805 }
8806
8807 if (fptr->mode & FMODE_WRITABLE) {
8808 if (io_fflush(fptr) < 0)
8809 rb_sys_fail_on_write(fptr);
8810 }
8811 fptr->rbuf.off = fptr->rbuf.len = 0;
8812 clear_codeconv(fptr);
8813
8814 if (fptr->stdio_file) {
8815 int e = rb_freopen(rb_str_encode_ospath(fptr->pathv),
8816 rb_io_oflags_modestr(oflags),
8817 fptr->stdio_file);
8818 if (e) rb_syserr_fail_path(e, fptr->pathv);
8819 fptr->fd = fileno(fptr->stdio_file);
8820 rb_fd_fix_cloexec(fptr->fd);
8821#ifdef USE_SETVBUF
8822 if (setvbuf(fptr->stdio_file, NULL, _IOFBF, 0) != 0)
8823 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8824#endif
8825 if (fptr->stdio_file == stderr) {
8826 if (setvbuf(fptr->stdio_file, NULL, _IONBF, BUFSIZ) != 0)
8827 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8828 }
8829 else if (fptr->stdio_file == stdout && isatty(fptr->fd)) {
8830 if (setvbuf(fptr->stdio_file, NULL, _IOLBF, BUFSIZ) != 0)
8831 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8832 }
8833 }
8834 else {
8835 int tmpfd = rb_sysopen(fptr->pathv, oflags, 0666);
8836 int err = 0;
8837 if (rb_cloexec_dup2(tmpfd, fptr->fd) < 0)
8838 err = errno;
8839 (void)close(tmpfd);
8840 if (err) {
8841 rb_syserr_fail_path(err, fptr->pathv);
8842 }
8843 }
8844
8845 return file;
8846}
8847
8848/* :nodoc: */
8849static VALUE
8850rb_io_init_copy(VALUE dest, VALUE io)
8851{
8852 rb_io_t *fptr, *orig;
8853 int fd;
8854 VALUE write_io;
8855 rb_off_t pos;
8856
8857 io = rb_io_get_io(io);
8858 if (!OBJ_INIT_COPY(dest, io)) return dest;
8859 GetOpenFile(io, orig);
8860 MakeOpenFile(dest, fptr);
8861
8862 rb_io_flush(io);
8863
8864 /* copy rb_io_t structure */
8865 fptr->mode = orig->mode & ~FMODE_EXTERNAL;
8866 fptr->encs = orig->encs;
8867 fptr->pid = orig->pid;
8868 fptr->lineno = orig->lineno;
8869 fptr->timeout = orig->timeout;
8870
8871 ccan_list_head_init(&fptr->blocking_operations);
8872 fptr->closing_ec = NULL;
8873 fptr->wakeup_mutex = Qnil;
8874 fptr->fork_generation = GET_VM()->fork_gen;
8875
8876 if (!NIL_P(orig->pathv)) fptr->pathv = orig->pathv;
8877 fptr_copy_finalizer(fptr, orig);
8878
8879 fd = ruby_dup(orig->fd);
8880 fptr->fd = fd;
8881 pos = io_tell(orig);
8882 if (0 <= pos)
8883 io_seek(fptr, pos, SEEK_SET);
8884 if (fptr->mode & FMODE_BINMODE) {
8885 rb_io_binmode(dest);
8886 }
8887
8888 write_io = GetWriteIO(io);
8889 if (io != write_io) {
8890 write_io = rb_obj_dup(write_io);
8891 fptr->tied_io_for_writing = write_io;
8892 rb_ivar_set(dest, rb_intern("@tied_io_for_writing"), write_io);
8893 }
8894
8895 return dest;
8896}
8897
8898/*
8899 * call-seq:
8900 * printf(format_string, *objects) -> nil
8901 *
8902 * Formats and writes +objects+ to the stream.
8903 *
8904 * For details on +format_string+, see
8905 * {Format Specifications}[rdoc-ref:language/format_specifications.rdoc].
8906 *
8907 */
8908
8909VALUE
8910rb_io_printf(int argc, const VALUE *argv, VALUE out)
8911{
8912 rb_io_write(out, rb_f_sprintf(argc, argv));
8913 return Qnil;
8914}
8915
8916/*
8917 * call-seq:
8918 * printf(format_string, *objects) -> nil
8919 * printf(io, format_string, *objects) -> nil
8920 *
8921 * Equivalent to:
8922 *
8923 * io.write(sprintf(format_string, *objects))
8924 *
8925 * For details on +format_string+, see
8926 * {Format Specifications}[rdoc-ref:language/format_specifications.rdoc].
8927 *
8928 * With the single argument +format_string+, formats +objects+ into the string,
8929 * then writes the formatted string to $stdout:
8930 *
8931 * printf('%4.4d %10s %2.2f', 24, 24, 24.0)
8932 *
8933 * Output (on $stdout):
8934 *
8935 * 0024 24 24.00#
8936 *
8937 * With arguments +io+ and +format_string+, formats +objects+ into the string,
8938 * then writes the formatted string to +io+:
8939 *
8940 * printf($stderr, '%4.4d %10s %2.2f', 24, 24, 24.0)
8941 *
8942 * Output (on $stderr):
8943 *
8944 * 0024 24 24.00# => nil
8945 *
8946 * With no arguments, does nothing.
8947 *
8948 */
8949
8950static VALUE
8951rb_f_printf(int argc, VALUE *argv, VALUE _)
8952{
8953 VALUE out;
8954
8955 if (argc == 0) return Qnil;
8956 if (RB_TYPE_P(argv[0], T_STRING)) {
8957 out = rb_ractor_stdout();
8958 }
8959 else {
8960 out = argv[0];
8961 argv++;
8962 argc--;
8963 }
8964 rb_io_write(out, rb_f_sprintf(argc, argv));
8965
8966 return Qnil;
8967}
8968
8969extern void rb_deprecated_str_setter(VALUE val, ID id, VALUE *var);
8970
8971static void
8972deprecated_rs_setter(VALUE val, ID id, VALUE *var)
8973{
8974 rb_deprecated_str_setter(val, id, &val);
8975 if (!NIL_P(val)) {
8976 if (rb_str_equal(val, rb_default_rs)) {
8977 val = rb_default_rs;
8978 }
8979 else {
8980 val = rb_str_frozen_bare_string(val);
8981 }
8982 }
8983 *var = val;
8984}
8985
8986/*
8987 * call-seq:
8988 * print(*objects) -> nil
8989 *
8990 * Writes the given objects to the stream; returns +nil+.
8991 * Appends the output record separator <tt>$OUTPUT_RECORD_SEPARATOR</tt>
8992 * (<tt>$\</tt>), if it is not +nil+.
8993 * See {Line IO}[rdoc-ref:IO@Line+IO].
8994 *
8995 * With argument +objects+ given, for each object:
8996 *
8997 * - Converts via its method +to_s+ if not a string.
8998 * - Writes to the stream.
8999 * - If not the last object, writes the output field separator
9000 * <tt>$OUTPUT_FIELD_SEPARATOR</tt> (<tt>$,</tt>) if it is not +nil+.
9001 *
9002 * With default separators:
9003 *
9004 * f = File.open('t.tmp', 'w+')
9005 * objects = [0, 0.0, Rational(0, 1), Complex(0, 0), :zero, 'zero']
9006 * p $OUTPUT_RECORD_SEPARATOR
9007 * p $OUTPUT_FIELD_SEPARATOR
9008 * f.print(*objects)
9009 * f.rewind
9010 * p f.read
9011 * f.close
9012 *
9013 * Output:
9014 *
9015 * nil
9016 * nil
9017 * "00.00/10+0izerozero"
9018 *
9019 * With specified separators:
9020 *
9021 * $\ = "\n"
9022 * $, = ','
9023 * f.rewind
9024 * f.print(*objects)
9025 * f.rewind
9026 * p f.read
9027 *
9028 * Output:
9029 *
9030 * "0,0.0,0/1,0+0i,zero,zero\n"
9031 *
9032 * With no argument given, writes the content of <tt>$_</tt>
9033 * (which is usually the most recent user input):
9034 *
9035 * f = File.open('t.tmp', 'w+')
9036 * gets # Sets $_ to the most recent user input.
9037 * f.print
9038 * f.close
9039 *
9040 */
9041
9042VALUE
9043rb_io_print(int argc, const VALUE *argv, VALUE out)
9044{
9045 int i;
9046 VALUE line;
9047
9048 /* if no argument given, print `$_' */
9049 if (argc == 0) {
9050 argc = 1;
9051 line = rb_lastline_get();
9052 argv = &line;
9053 }
9054 if (argc > 1 && !NIL_P(rb_output_fs)) {
9055 rb_category_warn(RB_WARN_CATEGORY_DEPRECATED, "$, is set to non-nil value");
9056 }
9057 for (i=0; i<argc; i++) {
9058 if (!NIL_P(rb_output_fs) && i>0) {
9059 rb_io_write(out, rb_output_fs);
9060 }
9061 rb_io_write(out, argv[i]);
9062 }
9063 if (argc > 0 && !NIL_P(rb_output_rs)) {
9064 rb_io_write(out, rb_output_rs);
9065 }
9066
9067 return Qnil;
9068}
9069
9070/*
9071 * call-seq:
9072 * print(*objects) -> nil
9073 *
9074 * Equivalent to <tt>$stdout.print(*objects)</tt>,
9075 * this method is the straightforward way to write to <tt>$stdout</tt>.
9076 *
9077 * Writes the given objects to <tt>$stdout</tt>; returns +nil+.
9078 * Appends the output record separator <tt>$OUTPUT_RECORD_SEPARATOR</tt>
9079 * (<tt>$\</tt>), if it is not +nil+.
9080 *
9081 * With argument +objects+ given, for each object:
9082 *
9083 * - Converts via its method +to_s+ if not a string.
9084 * - Writes to <tt>stdout</tt>.
9085 * - If not the last object, writes the output field separator
9086 * <tt>$OUTPUT_FIELD_SEPARATOR</tt> (<tt>$,</tt>) if it is not +nil+.
9087 *
9088 * With default separators:
9089 *
9090 * objects = [0, 0.0, Rational(0, 1), Complex(0, 0), :zero, 'zero']
9091 * $OUTPUT_RECORD_SEPARATOR
9092 * $OUTPUT_FIELD_SEPARATOR
9093 * print(*objects)
9094 *
9095 * Output:
9096 *
9097 * nil
9098 * nil
9099 * 00.00/10+0izerozero
9100 *
9101 * With specified separators:
9102 *
9103 * $OUTPUT_RECORD_SEPARATOR = "\n"
9104 * $OUTPUT_FIELD_SEPARATOR = ','
9105 * print(*objects)
9106 *
9107 * Output:
9108 *
9109 * 0,0.0,0/1,0+0i,zero,zero
9110 *
9111 * With no argument given, writes the content of <tt>$_</tt>
9112 * (which is usually the most recent user input):
9113 *
9114 * gets # Sets $_ to the most recent user input.
9115 * print # Prints $_.
9116 *
9117 */
9118
9119static VALUE
9120rb_f_print(int argc, const VALUE *argv, VALUE _)
9121{
9122 rb_io_print(argc, argv, rb_ractor_stdout());
9123 return Qnil;
9124}
9125
9126/*
9127 * call-seq:
9128 * putc(object) -> object
9129 *
9130 * Writes a character to the stream.
9131 * See {Character IO}[rdoc-ref:IO@Character+IO].
9132 *
9133 * If +object+ is numeric, converts to integer if necessary,
9134 * then writes the character whose code is the
9135 * least significant byte;
9136 * if +object+ is a string, writes the first character:
9137 *
9138 * $stdout.putc "A"
9139 * $stdout.putc 65
9140 *
9141 * Output:
9142 *
9143 * AA
9144 *
9145 */
9146
9147static VALUE
9148rb_io_putc(VALUE io, VALUE ch)
9149{
9150 VALUE str;
9151 if (RB_TYPE_P(ch, T_STRING)) {
9152 str = rb_str_substr(ch, 0, 1);
9153 }
9154 else {
9155 char c = NUM2CHR(ch);
9156 str = rb_str_new(&c, 1);
9157 }
9158 rb_io_write(io, str);
9159 return ch;
9160}
9161
9162#define forward(obj, id, argc, argv) \
9163 rb_funcallv_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
9164#define forward_public(obj, id, argc, argv) \
9165 rb_funcallv_public_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
9166#define forward_current(id, argc, argv) \
9167 forward_public(ARGF.current_file, id, argc, argv)
9168
9169/*
9170 * call-seq:
9171 * putc(int) -> int
9172 *
9173 * Equivalent to:
9174 *
9175 * $stdout.putc(int)
9176 *
9177 * See IO#putc for important information regarding multi-byte characters.
9178 *
9179 */
9180
9181static VALUE
9182rb_f_putc(VALUE recv, VALUE ch)
9183{
9184 VALUE r_stdout = rb_ractor_stdout();
9185 if (recv == r_stdout) {
9186 return rb_io_putc(recv, ch);
9187 }
9188 return forward(r_stdout, rb_intern("putc"), 1, &ch);
9189}
9190
9191
9192int
9193rb_str_end_with_asciichar(VALUE str, int c)
9194{
9195 long len = RSTRING_LEN(str);
9196 const char *ptr = RSTRING_PTR(str);
9197 rb_encoding *enc = rb_enc_from_index(ENCODING_GET(str));
9198 int n;
9199
9200 if (len == 0) return 0;
9201 if ((n = rb_enc_mbminlen(enc)) == 1) {
9202 return ptr[len - 1] == c;
9203 }
9204 return rb_enc_ascget(ptr + ((len - 1) / n) * n, ptr + len, &n, enc) == c;
9205}
9206
9207static VALUE
9208io_puts_ary(VALUE ary, VALUE out, int recur)
9209{
9210 VALUE tmp;
9211 long i;
9212
9213 if (recur) {
9214 tmp = rb_str_new2("[...]");
9215 rb_io_puts(1, &tmp, out);
9216 return Qtrue;
9217 }
9218 ary = rb_check_array_type(ary);
9219 if (NIL_P(ary)) return Qfalse;
9220 for (i=0; i<RARRAY_LEN(ary); i++) {
9221 tmp = RARRAY_AREF(ary, i);
9222 rb_io_puts(1, &tmp, out);
9223 }
9224 return Qtrue;
9225}
9226
9227/*
9228 * call-seq:
9229 * puts(*objects) -> nil
9230 *
9231 * Writes the given +objects+ to the stream, which must be open for writing;
9232 * returns +nil+.\
9233 * Writes a newline after each that does not already end with a newline sequence.
9234 * If called without arguments, writes a newline.
9235 * See {Line IO}[rdoc-ref:IO@Line+IO].
9236 *
9237 * Note that each added newline is the character <tt>"\n"</tt>,
9238 * not the output record separator (<tt>$\</tt>).
9239 *
9240 * Treatment for each object:
9241 *
9242 * - String: writes the string.
9243 * - Neither string nor array: writes <tt>object.to_s</tt>.
9244 * - Array: writes each element of the array; arrays may be nested.
9245 *
9246 * To keep these examples brief, we define this helper method:
9247 *
9248 * def show(*objects)
9249 * # Puts objects to file.
9250 * f = File.new('t.tmp', 'w+')
9251 * f.puts(objects)
9252 * # Return file content.
9253 * f.rewind
9254 * p f.read
9255 * f.close
9256 * end
9257 *
9258 * # Strings without newlines.
9259 * show('foo', 'bar', 'baz') # => "foo\nbar\nbaz\n"
9260 * # Strings, some with newlines.
9261 * show("foo\n", 'bar', "baz\n") # => "foo\nbar\nbaz\n"
9262 *
9263 * # Neither strings nor arrays:
9264 * show(0, 0.0, Rational(0, 1), Complex(9, 0), :zero)
9265 * # => "0\n0.0\n0/1\n9+0i\nzero\n"
9266 *
9267 * # Array of strings.
9268 * show(['foo', "bar\n", 'baz']) # => "foo\nbar\nbaz\n"
9269 * # Nested arrays.
9270 * show([[[0, 1], 2, 3], 4, 5]) # => "0\n1\n2\n3\n4\n5\n"
9271 *
9272 */
9273
9274VALUE
9275rb_io_puts(int argc, const VALUE *argv, VALUE out)
9276{
9277 VALUE line, args[2];
9278
9279 /* if no argument given, print newline. */
9280 if (argc == 0) {
9281 rb_io_write(out, rb_default_rs);
9282 return Qnil;
9283 }
9284 for (int i = 0; i < argc; i++) {
9285 // Convert the argument to a string:
9286 if (RB_TYPE_P(argv[i], T_STRING)) {
9287 line = argv[i];
9288 }
9289 else if (rb_exec_recursive(io_puts_ary, argv[i], out)) {
9290 continue;
9291 }
9292 else {
9293 line = rb_obj_as_string(argv[i]);
9294 }
9295
9296 // Write the line:
9297 int n = 0;
9298 if (RSTRING_LEN(line) == 0) {
9299 args[n++] = rb_default_rs;
9300 }
9301 else {
9302 args[n++] = line;
9303 if (!rb_str_end_with_asciichar(line, '\n')) {
9304 args[n++] = rb_default_rs;
9305 }
9306 }
9307
9308 rb_io_writev(out, n, args);
9309 }
9310
9311 return Qnil;
9312}
9313
9314/*
9315 * call-seq:
9316 * puts(*objects) -> nil
9317 *
9318 * Equivalent to
9319 *
9320 * $stdout.puts(objects)
9321 */
9322
9323static VALUE
9324rb_f_puts(int argc, VALUE *argv, VALUE recv)
9325{
9326 VALUE r_stdout = rb_ractor_stdout();
9327 if (recv == r_stdout) {
9328 return rb_io_puts(argc, argv, recv);
9329 }
9330 return forward(r_stdout, rb_intern("puts"), argc, argv);
9331}
9332
9333static VALUE
9334rb_p_write(VALUE str)
9335{
9336 VALUE args[2];
9337 args[0] = str;
9338 args[1] = rb_default_rs;
9339 VALUE r_stdout = rb_ractor_stdout();
9340 if (RB_TYPE_P(r_stdout, T_FILE) &&
9341 rb_method_basic_definition_p(CLASS_OF(r_stdout), id_write)) {
9342 io_writev(2, args, r_stdout);
9343 }
9344 else {
9345 rb_io_writev(r_stdout, 2, args);
9346 }
9347 return Qnil;
9348}
9349
9350void
9351rb_p(VALUE obj) /* for debug print within C code */
9352{
9353 rb_p_write(rb_obj_as_string(rb_inspect(obj)));
9354}
9355
9356static VALUE
9357rb_p_result(int argc, const VALUE *argv)
9358{
9359 VALUE ret = Qnil;
9360
9361 if (argc == 1) {
9362 ret = argv[0];
9363 }
9364 else if (argc > 1) {
9365 ret = rb_ary_new4(argc, argv);
9366 }
9367 VALUE r_stdout = rb_ractor_stdout();
9368 if (RB_TYPE_P(r_stdout, T_FILE)) {
9369 rb_uninterruptible(rb_io_flush, r_stdout);
9370 }
9371 return ret;
9372}
9373
9374/*
9375 * call-seq:
9376 * p(object) -> obj
9377 * p(*objects) -> array of objects
9378 * p -> nil
9379 *
9380 * For each object +obj+, executes:
9381 *
9382 * $stdout.write(obj.inspect, "\n")
9383 *
9384 * With one object given, returns the object;
9385 * with multiple objects given, returns an array containing the objects;
9386 * with no object given, returns +nil+.
9387 *
9388 * Examples:
9389 *
9390 * r = Range.new(0, 4)
9391 * p r # => 0..4
9392 * p [r, r, r] # => [0..4, 0..4, 0..4]
9393 * p # => nil
9394 *
9395 * Output:
9396 *
9397 * 0..4
9398 * [0..4, 0..4, 0..4]
9399 *
9400 * Kernel#p is designed for debugging purposes.
9401 * Ruby implementations may define Kernel#p to be uninterruptible
9402 * in whole or in part.
9403 * On CRuby, Kernel#p's writing of data is uninterruptible.
9404 */
9405
9406static VALUE
9407rb_f_p(int argc, VALUE *argv, VALUE self)
9408{
9409 int i;
9410 for (i=0; i<argc; i++) {
9411 VALUE inspected = rb_obj_as_string(rb_inspect(argv[i]));
9412 rb_uninterruptible(rb_p_write, inspected);
9413 }
9414 return rb_p_result(argc, argv);
9415}
9416
9417/*
9418 * call-seq:
9419 * display(port = $>) -> nil
9420 *
9421 * Writes +self+ on the given port:
9422 *
9423 * 1.display
9424 * "cat".display
9425 * [ 4, 5, 6 ].display
9426 * puts
9427 *
9428 * Output:
9429 *
9430 * 1cat[4, 5, 6]
9431 *
9432 */
9433
9434static VALUE
9435rb_obj_display(int argc, VALUE *argv, VALUE self)
9436{
9437 VALUE out;
9438
9439 out = (!rb_check_arity(argc, 0, 1) ? rb_ractor_stdout() : argv[0]);
9440 rb_io_write(out, self);
9441
9442 return Qnil;
9443}
9444
9445static int
9446rb_stderr_to_original_p(VALUE err)
9447{
9448 return (err == orig_stderr || RFILE(orig_stderr)->fptr->fd < 0);
9449}
9450
9451void
9452rb_write_error2(const char *mesg, long len)
9453{
9454 VALUE out = rb_ractor_stderr();
9455 if (rb_stderr_to_original_p(out)) {
9456#ifdef _WIN32
9457 if (isatty(fileno(stderr))) {
9458 if (rb_w32_write_console(rb_str_new(mesg, len), fileno(stderr)) > 0) return;
9459 }
9460#endif
9461 if (fwrite(mesg, sizeof(char), (size_t)len, stderr) < (size_t)len) {
9462 /* failed to write to stderr, what can we do? */
9463 return;
9464 }
9465 }
9466 else {
9467 rb_io_write(out, rb_str_new(mesg, len));
9468 }
9469}
9470
9471void
9472rb_write_error(const char *mesg)
9473{
9474 rb_write_error2(mesg, strlen(mesg));
9475}
9476
9477void
9478rb_write_error_str(VALUE mesg)
9479{
9480 VALUE out = rb_ractor_stderr();
9481 /* a stopgap measure for the time being */
9482 if (rb_stderr_to_original_p(out)) {
9483 size_t len = (size_t)RSTRING_LEN(mesg);
9484#ifdef _WIN32
9485 if (isatty(fileno(stderr))) {
9486 if (rb_w32_write_console(mesg, fileno(stderr)) > 0) return;
9487 }
9488#endif
9489 if (fwrite(RSTRING_PTR(mesg), sizeof(char), len, stderr) < len) {
9490 RB_GC_GUARD(mesg);
9491 return;
9492 }
9493 }
9494 else {
9495 /* may unlock GVL, and */
9496 rb_io_write(out, mesg);
9497 }
9498}
9499
9500int
9501rb_stderr_tty_p(void)
9502{
9503 if (rb_stderr_to_original_p(rb_ractor_stderr()))
9504 return isatty(fileno(stderr));
9505 return 0;
9506}
9507
9508static void
9509must_respond_to(ID mid, VALUE val, ID id)
9510{
9511 if (!rb_respond_to(val, mid)) {
9512 rb_raise(rb_eTypeError, "%"PRIsVALUE" must have %"PRIsVALUE" method, %"PRIsVALUE" given",
9513 rb_id2str(id), rb_id2str(mid),
9514 rb_obj_class(val));
9515 }
9516}
9517
9518static void
9519stdin_setter(VALUE val, ID id, VALUE *ptr)
9520{
9522}
9523
9524static VALUE
9525stdin_getter(ID id, VALUE *ptr)
9526{
9527 return rb_ractor_stdin();
9528}
9529
9530static void
9531stdout_setter(VALUE val, ID id, VALUE *ptr)
9532{
9533 must_respond_to(id_write, val, id);
9535}
9536
9537static VALUE
9538stdout_getter(ID id, VALUE *ptr)
9539{
9540 return rb_ractor_stdout();
9541}
9542
9543static void
9544stderr_setter(VALUE val, ID id, VALUE *ptr)
9545{
9546 must_respond_to(id_write, val, id);
9548}
9549
9550static VALUE
9551stderr_getter(ID id, VALUE *ptr)
9552{
9553 return rb_ractor_stderr();
9554}
9555
9556static VALUE
9557allocate_and_open_new_file(VALUE klass)
9558{
9559 VALUE self = io_alloc(klass);
9560 rb_io_make_open_file(self);
9561 return self;
9562}
9563
9564VALUE
9565rb_io_open_descriptor(VALUE klass, int descriptor, int mode, VALUE path, VALUE timeout, struct rb_io_encoding *encoding)
9566{
9567 int state;
9568 VALUE self = rb_protect(allocate_and_open_new_file, klass, &state);
9569 if (state) {
9570 /* if we raised an exception allocating an IO object, but the caller
9571 intended to transfer ownership of this FD to us, close the fd before
9572 raising the exception. Otherwise, we would leak a FD - the caller
9573 expects GC to close the file, but we never got around to assigning
9574 it to a rb_io. */
9575 if (!(mode & FMODE_EXTERNAL)) {
9576 maygvl_close(descriptor, 0);
9577 }
9578 rb_jump_tag(state);
9579 }
9580
9581
9582 rb_io_t *io = RFILE(self)->fptr;
9583 io->self = self;
9584 io->fd = descriptor;
9585 io->mode = mode;
9586
9587 /* At this point, Ruby fully owns the descriptor, and will close it when
9588 the IO gets GC'd (unless FMODE_EXTERNAL was set), no matter what happens
9589 in the rest of this method. */
9590
9591 if (NIL_P(path)) {
9592 io->pathv = Qnil;
9593 }
9594 else {
9595 StringValue(path);
9596 io->pathv = rb_str_new_frozen(path);
9597 }
9598
9599 io->timeout = timeout;
9600
9601 ccan_list_head_init(&io->blocking_operations);
9602 io->closing_ec = NULL;
9603 io->wakeup_mutex = Qnil;
9604 io->fork_generation = GET_VM()->fork_gen;
9605
9606 if (encoding) {
9607 io->encs = *encoding;
9608 }
9609
9610 rb_update_max_fd(descriptor);
9611
9612 return self;
9613}
9614
9615static VALUE
9616prep_io(int fd, enum rb_io_mode fmode, VALUE klass, const char *path)
9617{
9618 VALUE path_value = Qnil;
9619 rb_encoding *e;
9620 struct rb_io_encoding convconfig;
9621
9622 if (path) {
9623 path_value = rb_obj_freeze(rb_str_new_cstr(path));
9624 }
9625
9626 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
9627 rb_io_ext_int_to_encs(e, NULL, &convconfig.enc, &convconfig.enc2, fmode);
9628 convconfig.ecflags = (fmode & FMODE_READABLE) ?
9631#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9632 convconfig.ecflags |= (fmode & FMODE_WRITABLE) ?
9633 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
9634 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
9635#endif
9636 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.enc2, convconfig.ecflags);
9637 convconfig.ecopts = Qnil;
9638
9639 VALUE self = rb_io_open_descriptor(klass, fd, fmode, path_value, Qnil, &convconfig);
9640 rb_io_t*io = RFILE(self)->fptr;
9641
9642 if (!io_check_tty(io)) {
9643#ifdef __CYGWIN__
9644 io->mode |= FMODE_BINMODE;
9645 setmode(fd, O_BINARY);
9646#endif
9647 }
9648
9649 return self;
9650}
9651
9652VALUE
9653rb_io_fdopen(int fd, int oflags, const char *path)
9654{
9655 VALUE klass = rb_cIO;
9656
9657 if (path && strcmp(path, "-")) klass = rb_cFile;
9658 return prep_io(fd, rb_io_oflags_fmode(oflags), klass, path);
9659}
9660
9661static VALUE
9662prep_stdio(FILE *f, enum rb_io_mode fmode, VALUE klass, const char *path)
9663{
9664 rb_io_t *fptr;
9665 VALUE io = prep_io(fileno(f), fmode|FMODE_EXTERNAL|DEFAULT_TEXTMODE, klass, path);
9666
9667 GetOpenFile(io, fptr);
9669#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9670 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
9671 if (fmode & FMODE_READABLE) {
9673 }
9674#endif
9675 fptr->stdio_file = f;
9676
9677 return io;
9678}
9679
9680VALUE
9681rb_io_prep_stdin(void)
9682{
9683 return prep_stdio(stdin, FMODE_READABLE, rb_cIO, "<STDIN>");
9684}
9685
9686VALUE
9687rb_io_prep_stdout(void)
9688{
9689 return prep_stdio(stdout, FMODE_WRITABLE|FMODE_SIGNAL_ON_EPIPE, rb_cIO, "<STDOUT>");
9690}
9691
9692VALUE
9693rb_io_prep_stderr(void)
9694{
9695 return prep_stdio(stderr, FMODE_WRITABLE|FMODE_SYNC, rb_cIO, "<STDERR>");
9696}
9697
9698FILE *
9700{
9701 if (!fptr->stdio_file) {
9702 int oflags = rb_io_fmode_oflags(fptr->mode) & ~O_EXCL;
9703 fptr->stdio_file = rb_fdopen(fptr->fd, rb_io_oflags_modestr(oflags));
9704 }
9705 return fptr->stdio_file;
9706}
9707
9708static inline void
9709rb_io_buffer_init(struct rb_io_internal_buffer *buf)
9710{
9711 buf->ptr = NULL;
9712 buf->off = 0;
9713 buf->len = 0;
9714 buf->capa = 0;
9715}
9716
9717static inline rb_io_t *
9718rb_io_fptr_new(void)
9719{
9720 rb_io_t *fp = ALLOC(rb_io_t);
9721 fp->self = Qnil;
9722 fp->fd = -1;
9723 fp->stdio_file = NULL;
9724 fp->mode = 0;
9725 fp->pid = 0;
9726 fp->lineno = 0;
9727 fp->pathv = Qnil;
9728 fp->finalize = 0;
9729 rb_io_buffer_init(&fp->wbuf);
9730 rb_io_buffer_init(&fp->rbuf);
9731 rb_io_buffer_init(&fp->cbuf);
9732 fp->readconv = NULL;
9733 fp->writeconv = NULL;
9735 fp->writeconv_pre_ecflags = 0;
9737 fp->writeconv_initialized = 0;
9738 fp->tied_io_for_writing = 0;
9739 fp->encs.enc = NULL;
9740 fp->encs.enc2 = NULL;
9741 fp->encs.ecflags = 0;
9742 fp->encs.ecopts = Qnil;
9743 fp->write_lock = Qnil;
9744 fp->timeout = Qnil;
9745 ccan_list_head_init(&fp->blocking_operations);
9746 fp->closing_ec = NULL;
9747 fp->wakeup_mutex = Qnil;
9748 fp->fork_generation = GET_VM()->fork_gen;
9749 return fp;
9750}
9751
9752rb_io_t *
9753rb_io_make_open_file(VALUE obj)
9754{
9755 rb_io_t *fp = 0;
9756
9757 Check_Type(obj, T_FILE);
9758 if (RFILE(obj)->fptr) {
9759 rb_io_close(obj);
9760 rb_io_fptr_finalize(RFILE(obj)->fptr);
9761 RFILE(obj)->fptr = 0;
9762 }
9763 fp = rb_io_fptr_new();
9764 fp->self = obj;
9765 RFILE(obj)->fptr = fp;
9766 return fp;
9767}
9768
9769static VALUE io_initialize(VALUE io, VALUE fnum, VALUE vmode, VALUE opt);
9770
9771/*
9772 * call-seq:
9773 * IO.new(fd, mode = 'r', **opts) -> io
9774 *
9775 * Creates and returns a new \IO object (file stream) from a file descriptor.
9776 *
9777 * \IO.new may be useful for interaction with low-level libraries.
9778 * For higher-level interactions, it may be simpler to create
9779 * the file stream using File.open.
9780 *
9781 * Argument +fd+ must be a valid file descriptor (integer):
9782 *
9783 * path = 't.tmp'
9784 * fd = IO.sysopen(path) # => 3
9785 * IO.new(fd) # => #<IO:fd 3>
9786 *
9787 * The new \IO object does not inherit encoding
9788 * (because the integer file descriptor does not have an encoding):
9789 *
9790 * File.read('t.ja') # => "こんにちは"
9791 * fd = IO.sysopen('t.ja', 'rb')
9792 * io = IO.new(fd)
9793 * io.external_encoding # => #<Encoding:UTF-8> # Not ASCII-8BIT.
9794 *
9795 * Optional argument +mode+ (defaults to 'r') must specify a valid mode;
9796 * see {Access Modes}[rdoc-ref:File@Access+Modes]:
9797 *
9798 * IO.new(fd, 'w') # => #<IO:fd 3>
9799 * IO.new(fd, File::WRONLY) # => #<IO:fd 3>
9800 *
9801 * Optional keyword arguments +opts+ specify:
9802 *
9803 * - {Open Options}[rdoc-ref:IO@Open+Options].
9804 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
9805 *
9806 * Examples:
9807 *
9808 * IO.new(fd, internal_encoding: nil) # => #<IO:fd 3>
9809 * IO.new(fd, autoclose: true) # => #<IO:fd 3>
9810 *
9811 */
9812
9813static VALUE
9814rb_io_initialize(int argc, VALUE *argv, VALUE io)
9815{
9816 VALUE fnum, vmode;
9817 VALUE opt;
9818
9819 rb_scan_args(argc, argv, "11:", &fnum, &vmode, &opt);
9820 return io_initialize(io, fnum, vmode, opt);
9821}
9822
9823static VALUE
9824io_initialize(VALUE io, VALUE fnum, VALUE vmode, VALUE opt)
9825{
9826 rb_io_t *fp;
9827 int fd, oflags = O_RDONLY;
9828 enum rb_io_mode fmode;
9829 struct rb_io_encoding convconfig;
9830#if defined(HAVE_FCNTL) && defined(F_GETFL)
9831 int ofmode;
9832#else
9833 struct stat st;
9834#endif
9835
9836 rb_io_extract_modeenc(&vmode, 0, opt, &oflags, &fmode, &convconfig);
9837
9838 fd = NUM2INT(fnum);
9839 if (rb_reserved_fd_p(fd)) {
9840 rb_raise(rb_eArgError, "The given fd is not accessible because RubyVM reserves it");
9841 }
9842#if defined(HAVE_FCNTL) && defined(F_GETFL)
9843 oflags = fcntl(fd, F_GETFL);
9844 if (oflags == -1) rb_sys_fail(0);
9845#else
9846 if (fstat(fd, &st) < 0) rb_sys_fail(0);
9847#endif
9848 rb_update_max_fd(fd);
9849#if defined(HAVE_FCNTL) && defined(F_GETFL)
9850 ofmode = rb_io_oflags_fmode(oflags);
9851 if (NIL_P(vmode)) {
9852 fmode = ofmode;
9853 }
9854 else if ((~ofmode & fmode) & FMODE_READWRITE) {
9855 VALUE error = INT2FIX(EINVAL);
9857 }
9858#endif
9859 VALUE path = Qnil;
9860
9861 if (!NIL_P(opt)) {
9862 if (rb_hash_aref(opt, sym_autoclose) == Qfalse) {
9863 fmode |= FMODE_EXTERNAL;
9864 }
9865
9866 path = rb_hash_aref(opt, RB_ID2SYM(idPath));
9867 if (!NIL_P(path)) {
9868 StringValue(path);
9869 path = rb_str_new_frozen(path);
9870 }
9871 }
9872
9873 MakeOpenFile(io, fp);
9874 fp->self = io;
9875 fp->fd = fd;
9876 fp->mode = fmode;
9877 fp->encs = convconfig;
9878 fp->pathv = path;
9879 fp->timeout = Qnil;
9880 ccan_list_head_init(&fp->blocking_operations);
9881 fp->closing_ec = NULL;
9882 fp->wakeup_mutex = Qnil;
9883 fp->fork_generation = GET_VM()->fork_gen;
9884 clear_codeconv(fp);
9885 io_check_tty(fp);
9886 if (fileno(stdin) == fd)
9887 fp->stdio_file = stdin;
9888 else if (fileno(stdout) == fd)
9889 fp->stdio_file = stdout;
9890 else if (fileno(stderr) == fd)
9891 fp->stdio_file = stderr;
9892
9893 if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
9894 return io;
9895}
9896
9897/*
9898 * call-seq:
9899 * set_encoding_by_bom -> encoding or nil
9900 *
9901 * If the stream begins with a BOM
9902 * ({byte order marker}[https://en.wikipedia.org/wiki/Byte_order_mark]),
9903 * consumes the BOM and sets the external encoding accordingly;
9904 * returns the result encoding if found, or +nil+ otherwise:
9905 *
9906 * File.write('t.tmp', "\u{FEFF}abc")
9907 * io = File.open('t.tmp', 'rb')
9908 * io.set_encoding_by_bom # => #<Encoding:UTF-8>
9909 * io.close
9910 *
9911 * File.write('t.tmp', 'abc')
9912 * io = File.open('t.tmp', 'rb')
9913 * io.set_encoding_by_bom # => nil
9914 * io.close
9915 *
9916 * Raises an exception if the stream is not binmode
9917 * or its encoding has already been set.
9918 *
9919 */
9920
9921static VALUE
9922rb_io_set_encoding_by_bom(VALUE io)
9923{
9924 rb_io_t *fptr;
9925
9926 GetOpenFile(io, fptr);
9927 if (!(fptr->mode & FMODE_BINMODE)) {
9928 rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
9929 }
9930 if (fptr->encs.enc2) {
9931 rb_raise(rb_eArgError, "encoding conversion is set");
9932 }
9933 else if (fptr->encs.enc && fptr->encs.enc != rb_ascii8bit_encoding()) {
9934 rb_raise(rb_eArgError, "encoding is set to %s already",
9935 rb_enc_name(fptr->encs.enc));
9936 }
9937 if (!io_set_encoding_by_bom(io)) return Qnil;
9938 return rb_enc_from_encoding(fptr->encs.enc);
9939}
9940
9941/*
9942 * :markup: markdown
9943 *
9944 * call-seq:
9945 * File.new(path, mode = 'r', permissions = 0666, **options) -> file
9946 *
9947 * Opens the file as specified by the given arguments.
9948 * Creates and returns a new open \File object for that file;
9949 * the opened file is in non-synchronous mode.
9950 *
9951 * Argument `path` must the string path to an existing filesystem entry:
9952 *
9953 * ```ruby
9954 * file = File.new('doc/maintainers.md') # => #<File:doc/maintainers.md>
9955 * file.close # Clean up.
9956 * tty = File.new('/dev/tty') # => #<File:/dev/tty>
9957 * tty.close # Clean up.
9958 * ```
9959 *
9960 * Note that the caller is responsible for closing the file;
9961 * see File.open for automatic closing.
9962 *
9963 * Optional argument `mode` (defaults to `'r'`) must specify a valid mode;
9964 * see [Access Modes](rdoc-ref:File@Access+Modes):
9965 *
9966 * ```ruby
9967 * file = File.new('t.tmp', 'w') # => #<File:t.tmp>
9968 * file.close # Clean up.
9969 * file = File.new('t.tmp', File::RDONLY) # => #<File:t.tmp>
9970 * file.close # Clean up.
9971 * ```
9972 *
9973 * Optional argument `permissions` (defaults to `0666`) must specify valid permissions;
9974 * see [File Permissions](rdoc-ref:File@File+Permissions):
9975 *
9976 * ```ruby
9977 * file = File.new('t.tmp', 'w', 0644) # => #<File:t.tmp>
9978 * file.close # Clean up.
9979 * file = File.new('t.tmp', 'w', 0444) # => #<File:t.tmp>
9980 * file.close # Clean up.
9981 * ```
9982 *
9983 * Optional keyword arguments `options` specify:
9984 *
9985 * - [Open Options](rdoc-ref:IO@Open+Options).
9986 * - [Encoding options](rdoc-ref:encodings.rdoc@Encoding+Options).
9987 *
9988 */
9989
9990static VALUE
9991rb_file_initialize(int argc, VALUE *argv, VALUE io)
9992{
9993 if (RFILE(io)->fptr) {
9994 rb_raise(rb_eRuntimeError, "reinitializing File");
9995 }
9996 VALUE fname, vmode, vperm, opt;
9997 int posargc = rb_scan_args(argc, argv, "12:", &fname, &vmode, &vperm, &opt);
9998 if (posargc < 3) { /* perm is File only */
9999 VALUE fd = rb_check_to_int(fname);
10000
10001 if (!NIL_P(fd)) {
10002 return io_initialize(io, fd, vmode, opt);
10003 }
10004 }
10005 return rb_open_file(io, fname, vmode, vperm, opt);
10006}
10007
10008/* :nodoc: */
10009static VALUE
10010rb_io_s_new(int argc, VALUE *argv, VALUE klass)
10011{
10012 if (rb_block_given_p()) {
10013 VALUE cname = rb_obj_as_string(klass);
10014
10015 rb_warn("%"PRIsVALUE"::new() does not take block; use %"PRIsVALUE"::open() instead",
10016 cname, cname);
10017 }
10018 return rb_class_new_instance_kw(argc, argv, klass, RB_PASS_CALLED_KEYWORDS);
10019}
10020
10021
10022/*
10023 * call-seq:
10024 * IO.for_fd(fd, mode = 'r', **opts) -> io
10025 *
10026 * Synonym for IO.new.
10027 *
10028 */
10029
10030static VALUE
10031rb_io_s_for_fd(int argc, VALUE *argv, VALUE klass)
10032{
10033 VALUE io = rb_obj_alloc(klass);
10034 rb_io_initialize(argc, argv, io);
10035 return io;
10036}
10037
10038/*
10039 * call-seq:
10040 * ios.autoclose? -> true or false
10041 *
10042 * Returns +true+ if the underlying file descriptor of _ios_ will be
10043 * closed at its finalization or at calling #close, otherwise +false+.
10044 */
10045
10046static VALUE
10047rb_io_autoclose_p(VALUE io)
10048{
10049 rb_io_t *fptr = RFILE(io)->fptr;
10050 rb_io_check_closed(fptr);
10051 return RBOOL(!(fptr->mode & FMODE_EXTERNAL));
10052}
10053
10054/*
10055 * call-seq:
10056 * io.autoclose = bool -> true or false
10057 *
10058 * Sets auto-close flag.
10059 *
10060 * f = File.open(File::NULL)
10061 * IO.for_fd(f.fileno).close
10062 * f.gets # raises Errno::EBADF
10063 *
10064 * f = File.open(File::NULL)
10065 * g = IO.for_fd(f.fileno)
10066 * g.autoclose = false
10067 * g.close
10068 * f.gets # won't cause Errno::EBADF
10069 */
10070
10071static VALUE
10072rb_io_set_autoclose(VALUE io, VALUE autoclose)
10073{
10074 rb_io_t *fptr;
10075 GetOpenFile(io, fptr);
10076 if (!RTEST(autoclose))
10077 fptr->mode |= FMODE_EXTERNAL;
10078 else
10079 fptr->mode &= ~FMODE_EXTERNAL;
10080 return autoclose;
10081}
10082
10083static VALUE
10084io_wait_event(VALUE io, int event, VALUE timeout, int return_io)
10085{
10086 VALUE result = rb_io_wait(io, RB_INT2NUM(event), timeout);
10087
10088 if (!RB_TEST(result)) {
10089 return Qnil;
10090 }
10091
10092 int mask = RB_NUM2INT(result);
10093
10094 if (mask & event) {
10095 if (return_io)
10096 return io;
10097 else
10098 return result;
10099 }
10100 else {
10101 return Qfalse;
10102 }
10103}
10104
10105/*
10106 * call-seq:
10107 * io.wait_readable -> truthy or falsy
10108 * io.wait_readable(timeout) -> truthy or falsy
10109 *
10110 * Waits until IO is readable and returns a truthy value, or a falsy
10111 * value when times out. Returns a truthy value immediately when
10112 * buffered data is available.
10113 */
10114
10115static VALUE
10116io_wait_readable(int argc, VALUE *argv, VALUE io)
10117{
10118 rb_io_t *fptr;
10119
10120 RB_IO_POINTER(io, fptr);
10122
10123 if (rb_io_read_pending(fptr)) return Qtrue;
10124
10125 rb_check_arity(argc, 0, 1);
10126 VALUE timeout = (argc == 1 ? argv[0] : Qnil);
10127
10128 return io_wait_event(io, RUBY_IO_READABLE, timeout, 1);
10129}
10130
10131/*
10132 * call-seq:
10133 * io.wait_writable -> truthy or falsy
10134 * io.wait_writable(timeout) -> truthy or falsy
10135 *
10136 * Waits until IO is writable and returns a truthy value or a falsy
10137 * value when times out.
10138 */
10139static VALUE
10140io_wait_writable(int argc, VALUE *argv, VALUE io)
10141{
10142 rb_io_t *fptr;
10143
10144 RB_IO_POINTER(io, fptr);
10146
10147 rb_check_arity(argc, 0, 1);
10148 VALUE timeout = (argc == 1 ? argv[0] : Qnil);
10149
10150 return io_wait_event(io, RUBY_IO_WRITABLE, timeout, 1);
10151}
10152
10153/*
10154 * call-seq:
10155 * io.wait_priority -> truthy or falsy
10156 * io.wait_priority(timeout) -> truthy or falsy
10157 *
10158 * Waits until IO is priority and returns a truthy value or a falsy
10159 * value when times out. Priority data is sent and received using
10160 * the Socket::MSG_OOB flag and is typically limited to streams.
10161 */
10162static VALUE
10163io_wait_priority(int argc, VALUE *argv, VALUE io)
10164{
10165 rb_io_t *fptr = NULL;
10166
10167 RB_IO_POINTER(io, fptr);
10169
10170 if (rb_io_read_pending(fptr)) return Qtrue;
10171
10172 rb_check_arity(argc, 0, 1);
10173 VALUE timeout = argc == 1 ? argv[0] : Qnil;
10174
10175 return io_wait_event(io, RUBY_IO_PRIORITY, timeout, 1);
10176}
10177
10178static int
10179wait_mode_sym(VALUE mode)
10180{
10181 if (mode == ID2SYM(rb_intern("r"))) {
10182 return RB_WAITFD_IN;
10183 }
10184 if (mode == ID2SYM(rb_intern("read"))) {
10185 return RB_WAITFD_IN;
10186 }
10187 if (mode == ID2SYM(rb_intern("readable"))) {
10188 return RB_WAITFD_IN;
10189 }
10190 if (mode == ID2SYM(rb_intern("w"))) {
10191 return RB_WAITFD_OUT;
10192 }
10193 if (mode == ID2SYM(rb_intern("write"))) {
10194 return RB_WAITFD_OUT;
10195 }
10196 if (mode == ID2SYM(rb_intern("writable"))) {
10197 return RB_WAITFD_OUT;
10198 }
10199 if (mode == ID2SYM(rb_intern("rw"))) {
10200 return RB_WAITFD_IN|RB_WAITFD_OUT;
10201 }
10202 if (mode == ID2SYM(rb_intern("read_write"))) {
10203 return RB_WAITFD_IN|RB_WAITFD_OUT;
10204 }
10205 if (mode == ID2SYM(rb_intern("readable_writable"))) {
10206 return RB_WAITFD_IN|RB_WAITFD_OUT;
10207 }
10208
10209 rb_raise(rb_eArgError, "unsupported mode: %"PRIsVALUE, mode);
10210}
10211
10212static inline enum rb_io_event
10213io_event_from_value(VALUE value)
10214{
10215 int events = RB_NUM2INT(value);
10216
10217 if (events <= 0) rb_raise(rb_eArgError, "Events must be positive integer!");
10218
10219 return events;
10220}
10221
10222/*
10223 * call-seq:
10224 * io.wait(events, timeout) -> event mask, false or nil
10225 * io.wait(*event_symbols[, timeout]) -> self, true, or false
10226 *
10227 * Waits until the IO becomes ready for the specified events and returns the
10228 * subset of events that become ready, or a falsy value when times out.
10229 *
10230 * The events can be a bit mask of +IO::READABLE+, +IO::WRITABLE+ or
10231 * +IO::PRIORITY+.
10232 *
10233 * Returns an event mask (truthy value) immediately when buffered data is
10234 * available.
10235 *
10236 * The second form: if one or more event symbols (+:read+, +:write+, or
10237 * +:read_write+) are passed, the event mask is the bit OR of the bitmask
10238 * corresponding to those symbols. In this form, +timeout+ is optional, the
10239 * order of the arguments is arbitrary, and returns +io+ if any of the
10240 * events is ready.
10241 */
10242
10243static VALUE
10244io_wait(int argc, VALUE *argv, VALUE io)
10245{
10246 VALUE timeout = Qundef;
10247 enum rb_io_event events = 0;
10248 int return_io = 0;
10249
10250 if (argc != 2 || (RB_SYMBOL_P(argv[0]) || RB_SYMBOL_P(argv[1]))) {
10251 // We'd prefer to return the actual mask, but this form would return the io itself:
10252 return_io = 1;
10253
10254 // Slow/messy path:
10255 for (int i = 0; i < argc; i += 1) {
10256 if (RB_SYMBOL_P(argv[i])) {
10257 events |= wait_mode_sym(argv[i]);
10258 }
10259 else if (UNDEF_P(timeout)) {
10260 rb_time_interval(timeout = argv[i]);
10261 }
10262 else {
10263 rb_raise(rb_eArgError, "timeout given more than once");
10264 }
10265 }
10266
10267 if (UNDEF_P(timeout)) timeout = Qnil;
10268
10269 if (events == 0) {
10270 events = RUBY_IO_READABLE;
10271 }
10272 }
10273 else /* argc == 2 and neither are symbols */ {
10274 // This is the fast path:
10275 events = io_event_from_value(argv[0]);
10276 timeout = argv[1];
10277 }
10278
10279 if (events & RUBY_IO_READABLE) {
10280 rb_io_t *fptr = NULL;
10281 RB_IO_POINTER(io, fptr);
10282
10283 if (rb_io_read_pending(fptr)) {
10284 // This was the original behaviour:
10285 if (return_io) return Qtrue;
10286 // New behaviour always returns an event mask:
10287 else return RB_INT2NUM(RUBY_IO_READABLE);
10288 }
10289 }
10290
10291 return io_wait_event(io, events, timeout, return_io);
10292}
10293
10294static void
10295argf_mark_and_move(void *ptr)
10296{
10297 struct argf *p = ptr;
10298 rb_gc_mark_and_move(&p->filename);
10299 rb_gc_mark_and_move(&p->current_file);
10300 rb_gc_mark_and_move(&p->argv);
10301 rb_gc_mark_and_move(&p->inplace);
10302 rb_gc_mark_and_move(&p->encs.ecopts);
10303}
10304
10305static size_t
10306argf_memsize(const void *ptr)
10307{
10308 const struct argf *p = ptr;
10309 size_t size = sizeof(*p);
10310 return size;
10311}
10312
10313static const rb_data_type_t argf_type = {
10314 "ARGF",
10315 {argf_mark_and_move, RUBY_TYPED_DEFAULT_FREE, argf_memsize, argf_mark_and_move},
10316 0, 0, RUBY_TYPED_THREAD_SAFE_FREE | RUBY_TYPED_WB_PROTECTED
10317};
10318
10319static inline void
10320argf_init(VALUE argf, struct argf *p, VALUE v)
10321{
10322 p->filename = Qnil;
10323 p->current_file = Qnil;
10324 p->lineno = 0;
10325 RB_OBJ_WRITE(argf, &p->argv, v);
10326}
10327
10328static VALUE
10329argf_alloc(VALUE klass)
10330{
10331 struct argf *p;
10332 VALUE argf = TypedData_Make_Struct(klass, struct argf, &argf_type, p);
10333
10334 argf_init(argf, p, Qnil);
10335 return argf;
10336}
10337
10338#undef rb_argv
10339
10340/* :nodoc: */
10341static VALUE
10342argf_initialize(VALUE argf, VALUE argv)
10343{
10344 memset(&ARGF, 0, sizeof(ARGF));
10345 argf_init(argf, &ARGF, argv);
10346
10347 return argf;
10348}
10349
10350/* :nodoc: */
10351static VALUE
10352argf_initialize_copy(VALUE argf, VALUE orig)
10353{
10354 if (!OBJ_INIT_COPY(argf, orig)) return argf;
10355 ARGF = argf_of(orig);
10356 rb_gc_writebarrier_remember(argf);
10357 ARGF_SET(argv, rb_obj_dup(ARGF.argv));
10358 return argf;
10359}
10360
10361/*
10362 * call-seq:
10363 * ARGF.lineno = integer -> integer
10364 *
10365 * Sets the line number of ARGF as a whole to the given Integer.
10366 *
10367 * ARGF sets the line number automatically as you read data, so normally
10368 * you will not need to set it explicitly. To access the current line number
10369 * use ARGF.lineno.
10370 *
10371 * For example:
10372 *
10373 * ARGF.lineno #=> 0
10374 * ARGF.readline #=> "This is line 1\n"
10375 * ARGF.lineno #=> 1
10376 * ARGF.lineno = 0 #=> 0
10377 * ARGF.lineno #=> 0
10378 */
10379static VALUE
10380argf_set_lineno(VALUE argf, VALUE val)
10381{
10382 ARGF.lineno = NUM2INT(val);
10383 ARGF.last_lineno = ARGF.lineno;
10384 return val;
10385}
10386
10387/*
10388 * call-seq:
10389 * ARGF.lineno -> integer
10390 *
10391 * Returns the current line number of ARGF as a whole. This value
10392 * can be set manually with ARGF.lineno=.
10393 *
10394 * For example:
10395 *
10396 * ARGF.lineno #=> 0
10397 * ARGF.readline #=> "This is line 1\n"
10398 * ARGF.lineno #=> 1
10399 */
10400static VALUE
10401argf_lineno(VALUE argf)
10402{
10403 return INT2FIX(ARGF.lineno);
10404}
10405
10406static VALUE
10407argf_forward(int argc, VALUE *argv, VALUE argf)
10408{
10409 return forward_current(rb_frame_this_func(), argc, argv);
10410}
10411
10412#define next_argv() argf_next_argv(argf)
10413#define ARGF_GENERIC_INPUT_P() \
10414 (ARGF.current_file == rb_stdin && !RB_TYPE_P(ARGF.current_file, T_FILE))
10415#define ARGF_FORWARD(argc, argv) do {\
10416 if (ARGF_GENERIC_INPUT_P())\
10417 return argf_forward((argc), (argv), argf);\
10418} while (0)
10419#define NEXT_ARGF_FORWARD(argc, argv) do {\
10420 if (!next_argv()) return Qnil;\
10421 ARGF_FORWARD((argc), (argv));\
10422} while (0)
10423
10424static void
10425argf_close(VALUE argf)
10426{
10427 VALUE file = ARGF.current_file;
10428 if (file == rb_stdin) return;
10429 if (RB_TYPE_P(file, T_FILE)) {
10430 rb_io_set_write_io(file, Qnil);
10431 }
10432 io_close(file);
10433 ARGF.init_p = -1;
10434}
10435
10436static int
10437argf_next_argv(VALUE argf)
10438{
10439 char *fn;
10440 rb_io_t *fptr;
10441 int stdout_binmode = 0;
10442 enum rb_io_mode fmode;
10443
10444 VALUE r_stdout = rb_ractor_stdout();
10445
10446 if (RB_TYPE_P(r_stdout, T_FILE)) {
10447 GetOpenFile(r_stdout, fptr);
10448 if (fptr->mode & FMODE_BINMODE)
10449 stdout_binmode = 1;
10450 }
10451
10452 if (ARGF.init_p == 0) {
10453 if (!NIL_P(ARGF.argv) && RARRAY_LEN(ARGF.argv) > 0) {
10454 ARGF.next_p = 1;
10455 }
10456 else {
10457 ARGF.next_p = -1;
10458 }
10459 ARGF.init_p = 1;
10460 }
10461 else {
10462 if (NIL_P(ARGF.argv)) {
10463 ARGF.next_p = -1;
10464 }
10465 else if (ARGF.next_p == -1 && RARRAY_LEN(ARGF.argv) > 0) {
10466 ARGF.next_p = 1;
10467 }
10468 }
10469
10470 if (ARGF.next_p == 1) {
10471 if (ARGF.init_p == 1) argf_close(argf);
10472 retry:
10473 if (RARRAY_LEN(ARGF.argv) > 0) {
10474 VALUE filename = rb_ary_shift(ARGF.argv);
10475 FilePathValue(filename);
10476 ARGF_SET(filename, filename);
10477 filename = rb_str_encode_ospath(filename);
10478 fn = StringValueCStr(filename);
10479 if (RSTRING_LEN(filename) == 1 && fn[0] == '-') {
10480 ARGF_SET(current_file, rb_stdin);
10481 if (ARGF.inplace) {
10482 rb_warn("Can't do inplace edit for stdio; skipping");
10483 goto retry;
10484 }
10485 }
10486 else {
10487 VALUE write_io = Qnil;
10488 int fr = rb_sysopen(filename, O_RDONLY, 0);
10489
10490 if (ARGF.inplace) {
10491 struct stat st;
10492#ifndef NO_SAFE_RENAME
10493 struct stat st2;
10494#endif
10495 VALUE str;
10496 int fw;
10497
10498 if (RB_TYPE_P(r_stdout, T_FILE) && r_stdout != orig_stdout) {
10499 rb_io_close(r_stdout);
10500 }
10501 fstat(fr, &st);
10502 str = filename;
10503 if (!NIL_P(ARGF.inplace)) {
10504 VALUE suffix = ARGF.inplace;
10505 str = rb_str_dup(str);
10506 if (NIL_P(rb_str_cat_conv_enc_opts(str, RSTRING_LEN(str),
10507 RSTRING_PTR(suffix), RSTRING_LEN(suffix),
10508 rb_enc_get(suffix), 0, Qnil))) {
10509 rb_str_append(str, suffix);
10510 }
10511#ifdef NO_SAFE_RENAME
10512 (void)close(fr);
10513 (void)unlink(RSTRING_PTR(str));
10514 if (rename(fn, RSTRING_PTR(str)) < 0) {
10515 rb_warn("Can't rename %"PRIsVALUE" to %"PRIsVALUE": %s, skipping file",
10516 filename, str, strerror(errno));
10517 goto retry;
10518 }
10519 fr = rb_sysopen(str, O_RDONLY, 0);
10520#else
10521 if (rename(fn, RSTRING_PTR(str)) < 0) {
10522 rb_warn("Can't rename %"PRIsVALUE" to %"PRIsVALUE": %s, skipping file",
10523 filename, str, strerror(errno));
10524 close(fr);
10525 goto retry;
10526 }
10527#endif
10528 }
10529 else {
10530#ifdef NO_SAFE_RENAME
10531 rb_fatal("Can't do inplace edit without backup");
10532#else
10533 if (unlink(fn) < 0) {
10534 rb_warn("Can't remove %"PRIsVALUE": %s, skipping file",
10535 filename, strerror(errno));
10536 close(fr);
10537 goto retry;
10538 }
10539#endif
10540 }
10541 fw = rb_sysopen(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666);
10542#ifndef NO_SAFE_RENAME
10543 fstat(fw, &st2);
10544#ifdef HAVE_FCHMOD
10545 fchmod(fw, st.st_mode);
10546#else
10547 chmod(fn, st.st_mode);
10548#endif
10549 if (st.st_uid!=st2.st_uid || st.st_gid!=st2.st_gid) {
10550 int err;
10551#ifdef HAVE_FCHOWN
10552 err = fchown(fw, st.st_uid, st.st_gid);
10553#else
10554 err = chown(fn, st.st_uid, st.st_gid);
10555#endif
10556 if (err && getuid() == 0 && st2.st_uid == 0) {
10557 const char *wkfn = RSTRING_PTR(filename);
10558 rb_warn("Can't set owner/group of %"PRIsVALUE" to same as %"PRIsVALUE": %s, skipping file",
10559 filename, str, strerror(errno));
10560 (void)close(fr);
10561 (void)close(fw);
10562 (void)unlink(wkfn);
10563 goto retry;
10564 }
10565 }
10566#endif
10567 write_io = prep_io(fw, FMODE_WRITABLE, rb_cFile, fn);
10568 rb_ractor_stdout_set(write_io);
10569 if (stdout_binmode) rb_io_binmode(rb_stdout);
10570 }
10571 fmode = FMODE_READABLE;
10572 if (!ARGF.binmode) {
10573 fmode |= DEFAULT_TEXTMODE;
10574 }
10575 ARGF_SET(current_file, prep_io(fr, fmode, rb_cFile, fn));
10576 if (!NIL_P(write_io)) {
10577 rb_io_set_write_io(ARGF.current_file, write_io);
10578 }
10579 RB_GC_GUARD(filename);
10580 }
10581 if (ARGF.binmode) rb_io_ascii8bit_binmode(ARGF.current_file);
10582 GetOpenFile(ARGF.current_file, fptr);
10583 if (ARGF.encs.enc) {
10584 fptr->encs = ARGF.encs;
10585 clear_codeconv(fptr);
10586 }
10587 else {
10588 fptr->encs.ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
10589 if (!ARGF.binmode) {
10591#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
10592 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
10593#endif
10594 }
10595 }
10596 ARGF.next_p = 0;
10597 }
10598 else {
10599 ARGF.next_p = 1;
10600 return FALSE;
10601 }
10602 }
10603 else if (ARGF.next_p == -1) {
10604 ARGF_SET(current_file, rb_stdin);
10605 ARGF_SET(filename, rb_str_new2("-"));
10606 if (ARGF.inplace) {
10607 rb_warn("Can't do inplace edit for stdio");
10608 rb_ractor_stdout_set(orig_stdout);
10609 }
10610 }
10611 if (ARGF.init_p == -1) ARGF.init_p = 1;
10612 return TRUE;
10613}
10614
10615static VALUE
10616argf_getline(int argc, VALUE *argv, VALUE argf)
10617{
10618 VALUE line;
10619 long lineno = ARGF.lineno;
10620
10621 retry:
10622 if (!next_argv()) return Qnil;
10623 if (ARGF_GENERIC_INPUT_P()) {
10624 line = forward_current(idGets, argc, argv);
10625 }
10626 else {
10627 if (argc == 0 && rb_rs == rb_default_rs) {
10628 line = rb_io_gets(ARGF.current_file);
10629 }
10630 else {
10631 line = rb_io_getline(argc, argv, ARGF.current_file);
10632 }
10633 if (NIL_P(line) && ARGF.next_p != -1) {
10634 argf_close(argf);
10635 ARGF.next_p = 1;
10636 goto retry;
10637 }
10638 }
10639 if (!NIL_P(line)) {
10640 ARGF.lineno = ++lineno;
10641 ARGF.last_lineno = ARGF.lineno;
10642 }
10643 return line;
10644}
10645
10646static VALUE
10647argf_lineno_getter(ID id, VALUE *var)
10648{
10649 VALUE argf = *var;
10650 return INT2FIX(ARGF.last_lineno);
10651}
10652
10653static void
10654argf_lineno_setter(VALUE val, ID id, VALUE *var)
10655{
10656 VALUE argf = *var;
10657 int n = NUM2INT(val);
10658 ARGF.last_lineno = ARGF.lineno = n;
10659}
10660
10661void
10662rb_reset_argf_lineno(long n)
10663{
10664 ARGF.last_lineno = ARGF.lineno = n;
10665}
10666
10667static VALUE argf_gets(int, VALUE *, VALUE);
10668
10669/*
10670 * call-seq:
10671 * gets(sep=$/ [, getline_args]) -> string or nil
10672 * gets(limit [, getline_args]) -> string or nil
10673 * gets(sep, limit [, getline_args]) -> string or nil
10674 *
10675 * Returns (and assigns to <code>$_</code>) the next line from the list
10676 * of files in +ARGV+ (or <code>$*</code>), or from standard input if
10677 * no files are present on the command line. Returns +nil+ at end of
10678 * file. The optional argument specifies the record separator. The
10679 * separator is included with the contents of each record. A separator
10680 * of +nil+ reads the entire contents, and a zero-length separator
10681 * reads the input one paragraph at a time, where paragraphs are
10682 * divided by two consecutive newlines. If the first argument is an
10683 * integer, or optional second argument is given, the returning string
10684 * would not be longer than the given value in bytes. If multiple
10685 * filenames are present in +ARGV+, <code>gets(nil)</code> will read
10686 * the contents one file at a time.
10687 *
10688 * ARGV << "testfile"
10689 * print while gets
10690 *
10691 * <em>produces:</em>
10692 *
10693 * This is line one
10694 * This is line two
10695 * This is line three
10696 * And so on...
10697 *
10698 * The style of programming using <code>$_</code> as an implicit
10699 * parameter is gradually losing favor in the Ruby community.
10700 */
10701
10702static VALUE
10703rb_f_gets(int argc, VALUE *argv, VALUE recv)
10704{
10705 if (recv == argf) {
10706 return argf_gets(argc, argv, argf);
10707 }
10708 return forward(argf, idGets, argc, argv);
10709}
10710
10711/*
10712 * call-seq:
10713 * ARGF.gets(sep=$/ [, getline_args]) -> string or nil
10714 * ARGF.gets(limit [, getline_args]) -> string or nil
10715 * ARGF.gets(sep, limit [, getline_args]) -> string or nil
10716 *
10717 * Returns the next line from the current file in ARGF.
10718 *
10719 * By default lines are assumed to be separated by <code>$/</code>;
10720 * to use a different character as a separator, supply it as a String
10721 * for the _sep_ argument.
10722 *
10723 * The optional _limit_ argument specifies how many characters of each line
10724 * to return. By default all characters are returned.
10725 *
10726 * See IO.readlines for details about getline_args.
10727 *
10728 */
10729static VALUE
10730argf_gets(int argc, VALUE *argv, VALUE argf)
10731{
10732 VALUE line;
10733
10734 line = argf_getline(argc, argv, argf);
10735 rb_lastline_set(line);
10736
10737 return line;
10738}
10739
10740VALUE
10742{
10743 VALUE line;
10744
10745 if (rb_rs != rb_default_rs) {
10746 return rb_f_gets(0, 0, argf);
10747 }
10748
10749 retry:
10750 if (!next_argv()) return Qnil;
10751 line = rb_io_gets(ARGF.current_file);
10752 if (NIL_P(line) && ARGF.next_p != -1) {
10753 rb_io_close(ARGF.current_file);
10754 ARGF.next_p = 1;
10755 goto retry;
10756 }
10757 rb_lastline_set(line);
10758 if (!NIL_P(line)) {
10759 ARGF.lineno++;
10760 ARGF.last_lineno = ARGF.lineno;
10761 }
10762
10763 return line;
10764}
10765
10766static VALUE argf_readline(int, VALUE *, VALUE);
10767
10768/*
10769 * call-seq:
10770 * readline(sep = $/, chomp: false) -> string
10771 * readline(limit, chomp: false) -> string
10772 * readline(sep, limit, chomp: false) -> string
10773 *
10774 * Equivalent to method Kernel#gets, except that it raises an exception
10775 * if called at end-of-stream:
10776 *
10777 * $ cat t.txt | ruby -e "p readlines; readline"
10778 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10779 * in `readline': end of file reached (EOFError)
10780 *
10781 * Optional keyword argument +chomp+ specifies whether line separators
10782 * are to be omitted.
10783 */
10784
10785static VALUE
10786rb_f_readline(int argc, VALUE *argv, VALUE recv)
10787{
10788 if (recv == argf) {
10789 return argf_readline(argc, argv, argf);
10790 }
10791 return forward(argf, rb_intern("readline"), argc, argv);
10792}
10793
10794
10795/*
10796 * call-seq:
10797 * ARGF.readline(sep=$/) -> string
10798 * ARGF.readline(limit) -> string
10799 * ARGF.readline(sep, limit) -> string
10800 *
10801 * Returns the next line from the current file in ARGF.
10802 *
10803 * By default lines are assumed to be separated by <code>$/</code>;
10804 * to use a different character as a separator, supply it as a String
10805 * for the _sep_ argument.
10806 *
10807 * The optional _limit_ argument specifies how many characters of each line
10808 * to return. By default all characters are returned.
10809 *
10810 * An EOFError is raised at the end of the file.
10811 */
10812static VALUE
10813argf_readline(int argc, VALUE *argv, VALUE argf)
10814{
10815 VALUE line;
10816
10817 if (!next_argv()) rb_eof_error();
10818 ARGF_FORWARD(argc, argv);
10819 line = argf_gets(argc, argv, argf);
10820 if (NIL_P(line)) {
10821 rb_eof_error();
10822 }
10823
10824 return line;
10825}
10826
10827static VALUE argf_readlines(int, VALUE *, VALUE);
10828
10829/*
10830 * call-seq:
10831 * readlines(sep = $/, chomp: false, **enc_opts) -> array
10832 * readlines(limit, chomp: false, **enc_opts) -> array
10833 * readlines(sep, limit, chomp: false, **enc_opts) -> array
10834 *
10835 * Returns an array containing the lines returned by calling
10836 * Kernel#gets until the end-of-stream is reached;
10837 * (see {Line IO}[rdoc-ref:IO@Line+IO]).
10838 *
10839 * With only string argument +sep+ given,
10840 * returns the remaining lines as determined by line separator +sep+,
10841 * or +nil+ if none;
10842 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
10843 *
10844 * # Default separator.
10845 * $ cat t.txt | ruby -e "p readlines"
10846 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10847 *
10848 * # Specified separator.
10849 * $ cat t.txt | ruby -e "p readlines 'li'"
10850 * ["First li", "ne\nSecond li", "ne\n\nFourth li", "ne\nFifth li", "ne\n"]
10851 *
10852 * # Get-all separator.
10853 * $ cat t.txt | ruby -e "p readlines nil"
10854 * ["First line\nSecond line\n\nFourth line\nFifth line\n"]
10855 *
10856 * # Get-paragraph separator.
10857 * $ cat t.txt | ruby -e "p readlines ''"
10858 * ["First line\nSecond line\n\n", "Fourth line\nFifth line\n"]
10859 *
10860 * With only integer argument +limit+ given,
10861 * limits the number of bytes in the line;
10862 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
10863 *
10864 * $cat t.txt | ruby -e "p readlines 10"
10865 * ["First line", "\n", "Second lin", "e\n", "\n", "Fourth lin", "e\n", "Fifth line", "\n"]
10866 *
10867 * $cat t.txt | ruby -e "p readlines 11"
10868 * ["First line\n", "Second line", "\n", "\n", "Fourth line", "\n", "Fifth line\n"]
10869 *
10870 * $cat t.txt | ruby -e "p readlines 12"
10871 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10872 *
10873 * With arguments +sep+ and +limit+ given,
10874 * combines the two behaviors
10875 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
10876 *
10877 * Optional keyword argument +chomp+ specifies whether line separators
10878 * are to be omitted:
10879 *
10880 * $ cat t.txt | ruby -e "p readlines(chomp: true)"
10881 * ["First line", "Second line", "", "Fourth line", "Fifth line"]
10882 *
10883 * Optional keyword arguments +enc_opts+ specify encoding options;
10884 * see {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
10885 *
10886 */
10887
10888static VALUE
10889rb_f_readlines(int argc, VALUE *argv, VALUE recv)
10890{
10891 if (recv == argf) {
10892 return argf_readlines(argc, argv, argf);
10893 }
10894 return forward(argf, rb_intern("readlines"), argc, argv);
10895}
10896
10897/*
10898 * call-seq:
10899 * ARGF.readlines(sep = $/, chomp: false) -> array
10900 * ARGF.readlines(limit, chomp: false) -> array
10901 * ARGF.readlines(sep, limit, chomp: false) -> array
10902 *
10903 * ARGF.to_a(sep = $/, chomp: false) -> array
10904 * ARGF.to_a(limit, chomp: false) -> array
10905 * ARGF.to_a(sep, limit, chomp: false) -> array
10906 *
10907 * Reads each file in ARGF in its entirety, returning an Array containing
10908 * lines from the files. Lines are assumed to be separated by _sep_.
10909 *
10910 * lines = ARGF.readlines
10911 * lines[0] #=> "This is line one\n"
10912 *
10913 * See +IO.readlines+ for a full description of all options.
10914 */
10915static VALUE
10916argf_readlines(int argc, VALUE *argv, VALUE argf)
10917{
10918 long lineno = ARGF.lineno;
10919 VALUE lines, ary;
10920
10921 ary = rb_ary_new();
10922 while (next_argv()) {
10923 if (ARGF_GENERIC_INPUT_P()) {
10924 lines = forward_current(rb_intern("readlines"), argc, argv);
10925 }
10926 else {
10927 lines = rb_io_readlines(argc, argv, ARGF.current_file);
10928 argf_close(argf);
10929 }
10930 ARGF.next_p = 1;
10931 rb_ary_concat(ary, lines);
10932 ARGF.lineno = lineno + RARRAY_LEN(ary);
10933 ARGF.last_lineno = ARGF.lineno;
10934 }
10935 ARGF.init_p = 0;
10936 return ary;
10937}
10938
10939/*
10940 * call-seq:
10941 * `command` -> string
10942 *
10943 * Returns the <tt>$stdout</tt> output from running +command+ in a subshell;
10944 * sets global variable <tt>$?</tt> to the process status.
10945 *
10946 * This method has potential security vulnerabilities if called with untrusted input;
10947 * see {Command Injection}[rdoc-ref:security/command_injection.rdoc].
10948 *
10949 * Examples:
10950 *
10951 * $ `date` # => "Wed Apr 9 08:56:30 CDT 2003\n"
10952 * $ `echo oops && exit 99` # => "oops\n"
10953 * $ $? # => #<Process::Status: pid 17088 exit 99>
10954 * $ $?.exitstatus # => 99
10955 *
10956 * The built-in syntax <tt>%x{...}</tt> uses this method.
10957 *
10958 */
10959
10960static VALUE
10961rb_f_backquote(VALUE obj, VALUE str)
10962{
10963 VALUE port;
10964 VALUE result;
10965 rb_io_t *fptr;
10966
10967 StringValue(str);
10968 rb_last_status_clear();
10969 port = pipe_open_s(str, "r", FMODE_READABLE|DEFAULT_TEXTMODE, NULL);
10970 if (NIL_P(port)) return rb_str_new(0,0);
10971
10972 GetOpenFile(port, fptr);
10973 result = read_all(fptr, remain_size(fptr), Qnil);
10974 rb_io_close(port);
10975 rb_io_fptr_cleanup_all(fptr);
10976 RB_GC_GUARD(port);
10977
10978 return result;
10979}
10980
10981#ifdef HAVE_SYS_SELECT_H
10982#include <sys/select.h>
10983#endif
10984
10985static VALUE
10986select_internal(VALUE read, VALUE write, VALUE except, struct timeval *tp, rb_fdset_t *fds)
10987{
10988 VALUE res, list;
10989 rb_fdset_t *rp, *wp, *ep;
10990 rb_io_t *fptr;
10991 long i;
10992 int max = 0, n;
10993 int pending = 0;
10994 struct timeval timerec;
10995
10996 if (!NIL_P(read)) {
10997 Check_Type(read, T_ARRAY);
10998 for (i=0; i<RARRAY_LEN(read); i++) {
10999 GetOpenFile(rb_io_get_io(RARRAY_AREF(read, i)), fptr);
11000 rb_fd_set(fptr->fd, &fds[0]);
11001 if (READ_DATA_PENDING(fptr) || READ_CHAR_PENDING(fptr)) { /* check for buffered data */
11002 pending++;
11003 rb_fd_set(fptr->fd, &fds[3]);
11004 }
11005 if (max < fptr->fd) max = fptr->fd;
11006 }
11007 if (pending) { /* no blocking if there's buffered data */
11008 timerec.tv_sec = timerec.tv_usec = 0;
11009 tp = &timerec;
11010 }
11011 rp = &fds[0];
11012 }
11013 else
11014 rp = 0;
11015
11016 if (!NIL_P(write)) {
11017 Check_Type(write, T_ARRAY);
11018 for (i=0; i<RARRAY_LEN(write); i++) {
11019 VALUE write_io = GetWriteIO(rb_io_get_io(RARRAY_AREF(write, i)));
11020 GetOpenFile(write_io, fptr);
11021 rb_fd_set(fptr->fd, &fds[1]);
11022 if (max < fptr->fd) max = fptr->fd;
11023 }
11024 wp = &fds[1];
11025 }
11026 else
11027 wp = 0;
11028
11029 if (!NIL_P(except)) {
11030 Check_Type(except, T_ARRAY);
11031 for (i=0; i<RARRAY_LEN(except); i++) {
11032 VALUE io = rb_io_get_io(RARRAY_AREF(except, i));
11033 VALUE write_io = GetWriteIO(io);
11034 GetOpenFile(io, fptr);
11035 rb_fd_set(fptr->fd, &fds[2]);
11036 if (max < fptr->fd) max = fptr->fd;
11037 if (io != write_io) {
11038 GetOpenFile(write_io, fptr);
11039 rb_fd_set(fptr->fd, &fds[2]);
11040 if (max < fptr->fd) max = fptr->fd;
11041 }
11042 }
11043 ep = &fds[2];
11044 }
11045 else {
11046 ep = 0;
11047 }
11048
11049 max++;
11050
11051 n = rb_thread_fd_select(max, rp, wp, ep, tp);
11052 if (n < 0) {
11053 rb_sys_fail(0);
11054 }
11055 if (!pending && n == 0) return Qnil; /* returns nil on timeout */
11056
11057 res = rb_ary_new2(3);
11058 rb_ary_push(res, rp ? rb_ary_new_capa(RARRAY_LEN(read)) : rb_ary_new());
11059 rb_ary_push(res, wp ? rb_ary_new_capa(RARRAY_LEN(write)) : rb_ary_new());
11060 rb_ary_push(res, ep ? rb_ary_new_capa(RARRAY_LEN(except)) : rb_ary_new());
11061
11062 if (rp) {
11063 list = RARRAY_AREF(res, 0);
11064 for (i=0; i< RARRAY_LEN(read); i++) {
11065 VALUE obj = rb_ary_entry(read, i);
11066 VALUE io = rb_io_get_io(obj);
11067 GetOpenFile(io, fptr);
11068 if (rb_fd_isset(fptr->fd, &fds[0]) ||
11069 rb_fd_isset(fptr->fd, &fds[3])) {
11070 rb_ary_push(list, obj);
11071 }
11072 }
11073 }
11074
11075 if (wp) {
11076 list = RARRAY_AREF(res, 1);
11077 for (i=0; i< RARRAY_LEN(write); i++) {
11078 VALUE obj = rb_ary_entry(write, i);
11079 VALUE io = rb_io_get_io(obj);
11080 VALUE write_io = GetWriteIO(io);
11081 GetOpenFile(write_io, fptr);
11082 if (rb_fd_isset(fptr->fd, &fds[1])) {
11083 rb_ary_push(list, obj);
11084 }
11085 }
11086 }
11087
11088 if (ep) {
11089 list = RARRAY_AREF(res, 2);
11090 for (i=0; i< RARRAY_LEN(except); i++) {
11091 VALUE obj = rb_ary_entry(except, i);
11092 VALUE io = rb_io_get_io(obj);
11093 VALUE write_io = GetWriteIO(io);
11094 GetOpenFile(io, fptr);
11095 if (rb_fd_isset(fptr->fd, &fds[2])) {
11096 rb_ary_push(list, obj);
11097 }
11098 else if (io != write_io) {
11099 GetOpenFile(write_io, fptr);
11100 if (rb_fd_isset(fptr->fd, &fds[2])) {
11101 rb_ary_push(list, obj);
11102 }
11103 }
11104 }
11105 }
11106
11107 return res; /* returns an empty array on interrupt */
11108}
11109
11111 VALUE read, write, except;
11112 struct timeval *timeout;
11113 rb_fdset_t fdsets[4];
11114};
11115
11116static VALUE
11117select_call(VALUE arg)
11118{
11119 struct select_args *p = (struct select_args *)arg;
11120
11121 return select_internal(p->read, p->write, p->except, p->timeout, p->fdsets);
11122}
11123
11124static VALUE
11125select_end(VALUE arg)
11126{
11127 struct select_args *p = (struct select_args *)arg;
11128 int i;
11129
11130 for (i = 0; i < numberof(p->fdsets); ++i)
11131 rb_fd_term(&p->fdsets[i]);
11132 return Qnil;
11133}
11134
11135static VALUE sym_normal, sym_sequential, sym_random,
11136 sym_willneed, sym_dontneed, sym_noreuse;
11137
11138#ifdef HAVE_POSIX_FADVISE
11139struct io_advise_struct {
11140 int fd;
11141 int advice;
11142 rb_off_t offset;
11143 rb_off_t len;
11144};
11145
11146static VALUE
11147io_advise_internal(void *arg)
11148{
11149 struct io_advise_struct *ptr = arg;
11150 return posix_fadvise(ptr->fd, ptr->offset, ptr->len, ptr->advice);
11151}
11152
11153static VALUE
11154io_advise_sym_to_const(VALUE sym)
11155{
11156#ifdef POSIX_FADV_NORMAL
11157 if (sym == sym_normal)
11158 return INT2NUM(POSIX_FADV_NORMAL);
11159#endif
11160
11161#ifdef POSIX_FADV_RANDOM
11162 if (sym == sym_random)
11163 return INT2NUM(POSIX_FADV_RANDOM);
11164#endif
11165
11166#ifdef POSIX_FADV_SEQUENTIAL
11167 if (sym == sym_sequential)
11168 return INT2NUM(POSIX_FADV_SEQUENTIAL);
11169#endif
11170
11171#ifdef POSIX_FADV_WILLNEED
11172 if (sym == sym_willneed)
11173 return INT2NUM(POSIX_FADV_WILLNEED);
11174#endif
11175
11176#ifdef POSIX_FADV_DONTNEED
11177 if (sym == sym_dontneed)
11178 return INT2NUM(POSIX_FADV_DONTNEED);
11179#endif
11180
11181#ifdef POSIX_FADV_NOREUSE
11182 if (sym == sym_noreuse)
11183 return INT2NUM(POSIX_FADV_NOREUSE);
11184#endif
11185
11186 return Qnil;
11187}
11188
11189static VALUE
11190do_io_advise(rb_io_t *fptr, VALUE advice, rb_off_t offset, rb_off_t len)
11191{
11192 int rv;
11193 struct io_advise_struct ias;
11194 VALUE num_adv;
11195
11196 num_adv = io_advise_sym_to_const(advice);
11197
11198 /*
11199 * The platform doesn't support this hint. We don't raise exception, instead
11200 * silently ignore it. Because IO::advise is only hint.
11201 */
11202 if (NIL_P(num_adv))
11203 return Qnil;
11204
11205 ias.fd = fptr->fd;
11206 ias.advice = NUM2INT(num_adv);
11207 ias.offset = offset;
11208 ias.len = len;
11209
11210 rv = (int)rb_io_blocking_region(fptr, io_advise_internal, &ias);
11211 if (rv && rv != ENOSYS) {
11212 /* posix_fadvise(2) doesn't set errno. On success it returns 0; otherwise
11213 it returns the error code. */
11214 VALUE message = rb_sprintf("%"PRIsVALUE" "
11215 "(%"PRI_OFFT_PREFIX"d, "
11216 "%"PRI_OFFT_PREFIX"d, "
11217 "%"PRIsVALUE")",
11218 fptr->pathv, offset, len, advice);
11219 rb_syserr_fail_str(rv, message);
11220 }
11221
11222 return Qnil;
11223}
11224
11225#endif /* HAVE_POSIX_FADVISE */
11226
11227static void
11228advice_arg_check(VALUE advice)
11229{
11230 if (!SYMBOL_P(advice))
11231 rb_raise(rb_eTypeError, "advice must be a Symbol");
11232
11233 if (advice != sym_normal &&
11234 advice != sym_sequential &&
11235 advice != sym_random &&
11236 advice != sym_willneed &&
11237 advice != sym_dontneed &&
11238 advice != sym_noreuse) {
11239 rb_raise(rb_eNotImpError, "Unsupported advice: %+"PRIsVALUE, advice);
11240 }
11241}
11242
11243/*
11244 * call-seq:
11245 * advise(advice, offset = 0, len = 0) -> nil
11246 *
11247 * Invokes Posix system call
11248 * {posix_fadvise(2)}[https://man7.org/linux/man-pages/man2/posix_fadvise.2.html],
11249 * which announces an intention to access data from the current file
11250 * in a particular manner.
11251 *
11252 * The arguments and results are platform-dependent.
11253 *
11254 * The relevant data is specified by:
11255 *
11256 * - +offset+: The offset of the first byte of data.
11257 * - +len+: The number of bytes to be accessed;
11258 * if +len+ is zero, or is larger than the number of bytes remaining,
11259 * all remaining bytes will be accessed.
11260 *
11261 * Argument +advice+ is one of the following symbols:
11262 *
11263 * - +:normal+: The application has no advice to give
11264 * about its access pattern for the specified data.
11265 * If no advice is given for an open file, this is the default assumption.
11266 * - +:sequential+: The application expects to access the specified data sequentially
11267 * (with lower offsets read before higher ones).
11268 * - +:random+: The specified data will be accessed in random order.
11269 * - +:noreuse+: The specified data will be accessed only once.
11270 * - +:willneed+: The specified data will be accessed in the near future.
11271 * - +:dontneed+: The specified data will not be accessed in the near future.
11272 *
11273 * Not implemented on all platforms.
11274 *
11275 */
11276static VALUE
11277rb_io_advise(int argc, VALUE *argv, VALUE io)
11278{
11279 VALUE advice, offset, len;
11280 rb_off_t off, l;
11281 rb_io_t *fptr;
11282
11283 rb_scan_args(argc, argv, "12", &advice, &offset, &len);
11284 advice_arg_check(advice);
11285
11286 io = GetWriteIO(io);
11287 GetOpenFile(io, fptr);
11288
11289 off = NIL_P(offset) ? 0 : NUM2OFFT(offset);
11290 l = NIL_P(len) ? 0 : NUM2OFFT(len);
11291
11292#ifdef HAVE_POSIX_FADVISE
11293 return do_io_advise(fptr, advice, off, l);
11294#else
11295 ((void)off, (void)l); /* Ignore all hint */
11296 return Qnil;
11297#endif
11298}
11299
11300static int
11301is_pos_inf(VALUE x)
11302{
11303 double f;
11304 if (!RB_FLOAT_TYPE_P(x))
11305 return 0;
11306 f = RFLOAT_VALUE(x);
11307 return isinf(f) && 0 < f;
11308}
11309
11310/*
11311 * call-seq:
11312 * IO.select(read_ios, write_ios = [], error_ios = [], timeout = nil) -> array or nil
11313 *
11314 * Invokes system call {select(2)}[https://man7.org/linux/man-pages/man2/select.2.html],
11315 * which monitors multiple file descriptors,
11316 * waiting until one or more of the file descriptors
11317 * becomes ready for some class of I/O operation.
11318 *
11319 * Not implemented on all platforms.
11320 *
11321 * Each of the arguments +read_ios+, +write_ios+, and +error_ios+
11322 * is an array of IO objects.
11323 *
11324 * Argument +timeout+ is a numeric value (such as integer or float) timeout
11325 * interval in seconds.
11326 * +timeout+ can also be +nil+ or +Float::INFINITY+.
11327 * +nil+ and +Float::INFINITY+ means no timeout.
11328 *
11329 * The method monitors the \IO objects given in all three arrays,
11330 * waiting for some to be ready;
11331 * returns a 3-element array whose elements are:
11332 *
11333 * - An array of the objects in +read_ios+ that are ready for reading.
11334 * - An array of the objects in +write_ios+ that are ready for writing.
11335 * - An array of the objects in +error_ios+ have pending exceptions.
11336 *
11337 * If no object becomes ready within the given +timeout+, +nil+ is returned.
11338 *
11339 * \IO.select peeks the buffer of \IO objects for testing readability.
11340 * If the \IO buffer is not empty, \IO.select immediately notifies
11341 * readability. This "peek" only happens for \IO objects. It does not
11342 * happen for IO-like objects such as OpenSSL::SSL::SSLSocket.
11343 *
11344 * The best way to use \IO.select is invoking it after non-blocking
11345 * methods such as #read_nonblock, #write_nonblock, etc. The methods
11346 * raise an exception which is extended by IO::WaitReadable or
11347 * IO::WaitWritable. The modules notify how the caller should wait
11348 * with \IO.select. If IO::WaitReadable is raised, the caller should
11349 * wait for reading. If IO::WaitWritable is raised, the caller should
11350 * wait for writing.
11351 *
11352 * So, blocking read (#readpartial) can be emulated using
11353 * #read_nonblock and \IO.select as follows:
11354 *
11355 * begin
11356 * result = io_like.read_nonblock(maxlen)
11357 * rescue IO::WaitReadable
11358 * IO.select([io_like])
11359 * retry
11360 * rescue IO::WaitWritable
11361 * IO.select(nil, [io_like])
11362 * retry
11363 * end
11364 *
11365 * Especially, the combination of non-blocking methods and \IO.select is
11366 * preferred for IO like objects such as OpenSSL::SSL::SSLSocket. It
11367 * has #to_io method to return underlying IO object. IO.select calls
11368 * #to_io to obtain the file descriptor to wait.
11369 *
11370 * This means that readability notified by \IO.select doesn't mean
11371 * readability from OpenSSL::SSL::SSLSocket object.
11372 *
11373 * The most likely situation is that OpenSSL::SSL::SSLSocket buffers
11374 * some data. \IO.select doesn't see the buffer. So \IO.select can
11375 * block when OpenSSL::SSL::SSLSocket#readpartial doesn't block.
11376 *
11377 * However, several more complicated situations exist.
11378 *
11379 * SSL is a protocol which is sequence of records.
11380 * The record consists of multiple bytes.
11381 * So, the remote side of SSL sends a partial record, IO.select
11382 * notifies readability but OpenSSL::SSL::SSLSocket cannot decrypt a
11383 * byte and OpenSSL::SSL::SSLSocket#readpartial will block.
11384 *
11385 * Also, the remote side can request SSL renegotiation which forces
11386 * the local SSL engine to write some data.
11387 * This means OpenSSL::SSL::SSLSocket#readpartial may invoke #write
11388 * system call and it can block.
11389 * In such a situation, OpenSSL::SSL::SSLSocket#read_nonblock raises
11390 * IO::WaitWritable instead of blocking.
11391 * So, the caller should wait for ready for writability as above
11392 * example.
11393 *
11394 * The combination of non-blocking methods and \IO.select is also useful
11395 * for streams such as tty, pipe socket socket when multiple processes
11396 * read from a stream.
11397 *
11398 * Finally, Linux kernel developers don't guarantee that
11399 * readability of select(2) means readability of following read(2) even
11400 * for a single process;
11401 * see {select(2)}[https://man7.org/linux/man-pages/man2/select.2.html]
11402 *
11403 * Invoking \IO.select before IO#readpartial works well as usual.
11404 * However it is not the best way to use \IO.select.
11405 *
11406 * The writability notified by select(2) doesn't show
11407 * how many bytes are writable.
11408 * IO#write method blocks until given whole string is written.
11409 * So, <tt>IO#write(two or more bytes)</tt> can block after
11410 * writability is notified by \IO.select. IO#write_nonblock is required
11411 * to avoid the blocking.
11412 *
11413 * Blocking write (#write) can be emulated using #write_nonblock and
11414 * IO.select as follows: IO::WaitReadable should also be rescued for
11415 * SSL renegotiation in OpenSSL::SSL::SSLSocket.
11416 *
11417 * while 0 < string.bytesize
11418 * begin
11419 * written = io_like.write_nonblock(string)
11420 * rescue IO::WaitReadable
11421 * IO.select([io_like])
11422 * retry
11423 * rescue IO::WaitWritable
11424 * IO.select(nil, [io_like])
11425 * retry
11426 * end
11427 * string = string.byteslice(written..-1)
11428 * end
11429 *
11430 * Example:
11431 *
11432 * rp, wp = IO.pipe
11433 * mesg = "ping "
11434 * 100.times {
11435 * # IO.select follows IO#read. Not the best way to use IO.select.
11436 * rs, ws, = IO.select([rp], [wp])
11437 * if r = rs[0]
11438 * ret = r.read(5)
11439 * print ret
11440 * case ret
11441 * when /ping/
11442 * mesg = "pong\n"
11443 * when /pong/
11444 * mesg = "ping "
11445 * end
11446 * end
11447 * if w = ws[0]
11448 * w.write(mesg)
11449 * end
11450 * }
11451 *
11452 * Output:
11453 *
11454 * ping pong
11455 * ping pong
11456 * ping pong
11457 * (snipped)
11458 * ping
11459 *
11460 */
11461
11462static VALUE
11463rb_f_select(int argc, VALUE *argv, VALUE obj)
11464{
11465 VALUE scheduler = rb_fiber_scheduler_current();
11466 if (scheduler != Qnil) {
11467 // It's optionally supported.
11468 VALUE result = rb_fiber_scheduler_io_selectv(scheduler, argc, argv);
11469 if (!UNDEF_P(result)) return result;
11470 }
11471
11472 VALUE timeout;
11473 struct select_args args;
11474 struct timeval timerec;
11475 int i;
11476
11477 rb_scan_args(argc, argv, "13", &args.read, &args.write, &args.except, &timeout);
11478 if (NIL_P(timeout) || is_pos_inf(timeout)) {
11479 args.timeout = 0;
11480 }
11481 else {
11482 timerec = rb_time_interval(timeout);
11483 args.timeout = &timerec;
11484 }
11485
11486 for (i = 0; i < numberof(args.fdsets); ++i)
11487 rb_fd_init(&args.fdsets[i]);
11488
11489 return rb_ensure(select_call, (VALUE)&args, select_end, (VALUE)&args);
11490}
11491
11492#ifdef IOCTL_REQ_TYPE
11493 typedef IOCTL_REQ_TYPE ioctl_req_t;
11494#else
11495 typedef int ioctl_req_t;
11496# define NUM2IOCTLREQ(num) ((int)NUM2LONG(num))
11497#endif
11498
11499#ifdef HAVE_IOCTL
11500struct ioctl_arg {
11501 int fd;
11502 ioctl_req_t cmd;
11503 long narg;
11504};
11505
11506static VALUE
11507nogvl_ioctl(void *ptr)
11508{
11509 struct ioctl_arg *arg = ptr;
11510
11511 return (VALUE)ioctl(arg->fd, arg->cmd, arg->narg);
11512}
11513
11514static int
11515do_ioctl(struct rb_io *io, ioctl_req_t cmd, long narg)
11516{
11517 int retval;
11518 struct ioctl_arg arg;
11519
11520 arg.fd = io->fd;
11521 arg.cmd = cmd;
11522 arg.narg = narg;
11523
11524 retval = (int)rb_io_blocking_region(io, nogvl_ioctl, &arg);
11525
11526 return retval;
11527}
11528#endif
11529
11530#define DEFAULT_IOCTL_NARG_LEN (256)
11531
11532#if defined(__linux__) && defined(_IOC_SIZE)
11533static long
11534linux_iocparm_len(ioctl_req_t cmd)
11535{
11536 long len;
11537
11538 if ((cmd & 0xFFFF0000) == 0) {
11539 /* legacy and unstructured ioctl number. */
11540 return DEFAULT_IOCTL_NARG_LEN;
11541 }
11542
11543 len = _IOC_SIZE(cmd);
11544
11545 /* paranoia check for silly drivers which don't keep ioctl convention */
11546 if (len < DEFAULT_IOCTL_NARG_LEN)
11547 len = DEFAULT_IOCTL_NARG_LEN;
11548
11549 return len;
11550}
11551#endif
11552
11553#ifdef HAVE_IOCTL
11554static long
11555ioctl_narg_len(ioctl_req_t cmd)
11556{
11557 long len;
11558
11559#ifdef IOCPARM_MASK
11560#ifndef IOCPARM_LEN
11561#define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK)
11562#endif
11563#endif
11564#ifdef IOCPARM_LEN
11565 len = IOCPARM_LEN(cmd); /* on BSDish systems we're safe */
11566#elif defined(__linux__) && defined(_IOC_SIZE)
11567 len = linux_iocparm_len(cmd);
11568#else
11569 /* otherwise guess at what's safe */
11570 len = DEFAULT_IOCTL_NARG_LEN;
11571#endif
11572
11573 return len;
11574}
11575#endif
11576
11577#ifdef HAVE_FCNTL
11578#ifdef __linux__
11579typedef long fcntl_arg_t;
11580#else
11581/* posix */
11582typedef int fcntl_arg_t;
11583#endif
11584
11585static long
11586fcntl_narg_len(ioctl_req_t cmd)
11587{
11588 long len;
11589
11590 switch (cmd) {
11591#ifdef F_DUPFD
11592 case F_DUPFD:
11593 len = sizeof(fcntl_arg_t);
11594 break;
11595#endif
11596#ifdef F_DUP2FD /* bsd specific */
11597 case F_DUP2FD:
11598 len = sizeof(int);
11599 break;
11600#endif
11601#ifdef F_DUPFD_CLOEXEC /* linux specific */
11602 case F_DUPFD_CLOEXEC:
11603 len = sizeof(fcntl_arg_t);
11604 break;
11605#endif
11606#ifdef F_GETFD
11607 case F_GETFD:
11608 len = 1;
11609 break;
11610#endif
11611#ifdef F_SETFD
11612 case F_SETFD:
11613 len = sizeof(fcntl_arg_t);
11614 break;
11615#endif
11616#ifdef F_GETFL
11617 case F_GETFL:
11618 len = 1;
11619 break;
11620#endif
11621#ifdef F_SETFL
11622 case F_SETFL:
11623 len = sizeof(fcntl_arg_t);
11624 break;
11625#endif
11626#ifdef F_GETOWN
11627 case F_GETOWN:
11628 len = 1;
11629 break;
11630#endif
11631#ifdef F_SETOWN
11632 case F_SETOWN:
11633 len = sizeof(fcntl_arg_t);
11634 break;
11635#endif
11636#ifdef F_GETOWN_EX /* linux specific */
11637 case F_GETOWN_EX:
11638 len = sizeof(struct f_owner_ex);
11639 break;
11640#endif
11641#ifdef F_SETOWN_EX /* linux specific */
11642 case F_SETOWN_EX:
11643 len = sizeof(struct f_owner_ex);
11644 break;
11645#endif
11646#ifdef F_GETLK
11647 case F_GETLK:
11648 len = sizeof(struct flock);
11649 break;
11650#endif
11651#ifdef F_SETLK
11652 case F_SETLK:
11653 len = sizeof(struct flock);
11654 break;
11655#endif
11656#ifdef F_SETLKW
11657 case F_SETLKW:
11658 len = sizeof(struct flock);
11659 break;
11660#endif
11661#ifdef F_READAHEAD /* bsd specific */
11662 case F_READAHEAD:
11663 len = sizeof(int);
11664 break;
11665#endif
11666#ifdef F_RDAHEAD /* Darwin specific */
11667 case F_RDAHEAD:
11668 len = sizeof(int);
11669 break;
11670#endif
11671#ifdef F_GETSIG /* linux specific */
11672 case F_GETSIG:
11673 len = 1;
11674 break;
11675#endif
11676#ifdef F_SETSIG /* linux specific */
11677 case F_SETSIG:
11678 len = sizeof(fcntl_arg_t);
11679 break;
11680#endif
11681#ifdef F_GETLEASE /* linux specific */
11682 case F_GETLEASE:
11683 len = 1;
11684 break;
11685#endif
11686#ifdef F_SETLEASE /* linux specific */
11687 case F_SETLEASE:
11688 len = sizeof(fcntl_arg_t);
11689 break;
11690#endif
11691#ifdef F_NOTIFY /* linux specific */
11692 case F_NOTIFY:
11693 len = sizeof(fcntl_arg_t);
11694 break;
11695#endif
11696
11697 default:
11698 len = 256;
11699 break;
11700 }
11701
11702 return len;
11703}
11704#else /* HAVE_FCNTL */
11705static long
11706fcntl_narg_len(ioctl_req_t cmd)
11707{
11708 return 0;
11709}
11710#endif /* HAVE_FCNTL */
11711
11712#define NARG_SENTINEL 17
11713
11714static long
11715setup_narg(ioctl_req_t cmd, VALUE *argp, long (*narg_len)(ioctl_req_t))
11716{
11717 long narg = 0;
11718 VALUE arg = *argp;
11719
11720 if (!RTEST(arg)) {
11721 narg = 0;
11722 }
11723 else if (FIXNUM_P(arg)) {
11724 narg = FIX2LONG(arg);
11725 }
11726 else if (arg == Qtrue) {
11727 narg = 1;
11728 }
11729 else {
11730 VALUE tmp = rb_check_string_type(arg);
11731
11732 if (NIL_P(tmp)) {
11733 narg = NUM2LONG(arg);
11734 }
11735 else {
11736 char *ptr;
11737 long len, slen;
11738
11739 *argp = arg = tmp;
11740 len = narg_len(cmd);
11741 rb_str_modify(arg);
11742
11743 slen = RSTRING_LEN(arg);
11744 /* expand for data + sentinel. */
11745 if (slen < len+1) {
11746 rb_str_resize(arg, len+1);
11747 MEMZERO(RSTRING_PTR(arg)+slen, char, len-slen);
11748 slen = len+1;
11749 }
11750 /* a little sanity check here */
11751 ptr = RSTRING_PTR(arg);
11752 ptr[slen - 1] = NARG_SENTINEL;
11753 narg = (long)(SIGNED_VALUE)ptr;
11754 }
11755 }
11756
11757 return narg;
11758}
11759
11760static VALUE
11761finish_narg(int retval, VALUE arg, const rb_io_t *fptr)
11762{
11763 if (retval < 0) rb_sys_fail_path(fptr->pathv);
11764 if (RB_TYPE_P(arg, T_STRING)) {
11765 char *ptr;
11766 long slen;
11767 RSTRING_GETMEM(arg, ptr, slen);
11768 if (ptr[slen-1] != NARG_SENTINEL)
11769 rb_raise(rb_eArgError, "return value overflowed string");
11770 ptr[slen-1] = '\0';
11771 }
11772
11773 return INT2NUM(retval);
11774}
11775
11776#ifdef HAVE_IOCTL
11777static VALUE
11778rb_ioctl(VALUE io, VALUE req, VALUE arg)
11779{
11780 ioctl_req_t cmd = NUM2IOCTLREQ(req);
11781 rb_io_t *fptr;
11782 long narg;
11783 int retval;
11784
11785 narg = setup_narg(cmd, &arg, ioctl_narg_len);
11786 GetOpenFile(io, fptr);
11787 retval = do_ioctl(fptr, cmd, narg);
11788 return finish_narg(retval, arg, fptr);
11789}
11790
11791/*
11792 * call-seq:
11793 * ioctl(integer_cmd, argument) -> integer
11794 *
11795 * Invokes Posix system call {ioctl(2)}[https://man7.org/linux/man-pages/man2/ioctl.2.html],
11796 * which issues a low-level command to an I/O device.
11797 *
11798 * Issues a low-level command to an I/O device.
11799 * The arguments and returned value are platform-dependent.
11800 * The effect of the call is platform-dependent.
11801 *
11802 * If argument +argument+ is an integer, it is passed directly;
11803 * if it is a string, it is interpreted as a binary sequence of bytes.
11804 *
11805 * Not implemented on all platforms.
11806 *
11807 */
11808
11809static VALUE
11810rb_io_ioctl(int argc, VALUE *argv, VALUE io)
11811{
11812 VALUE req, arg;
11813
11814 rb_scan_args(argc, argv, "11", &req, &arg);
11815 return rb_ioctl(io, req, arg);
11816}
11817#else
11818#define rb_io_ioctl rb_f_notimplement
11819#endif
11820
11821#ifdef HAVE_FCNTL
11822struct fcntl_arg {
11823 int fd;
11824 int cmd;
11825 long narg;
11826};
11827
11828static VALUE
11829nogvl_fcntl(void *ptr)
11830{
11831 struct fcntl_arg *arg = ptr;
11832
11833#if defined(F_DUPFD)
11834 if (arg->cmd == F_DUPFD)
11835 return (VALUE)rb_cloexec_fcntl_dupfd(arg->fd, (int)arg->narg);
11836#endif
11837 return (VALUE)fcntl(arg->fd, arg->cmd, arg->narg);
11838}
11839
11840static int
11841do_fcntl(struct rb_io *io, int cmd, long narg)
11842{
11843 int retval;
11844 struct fcntl_arg arg;
11845
11846 arg.fd = io->fd;
11847 arg.cmd = cmd;
11848 arg.narg = narg;
11849
11850 retval = (int)rb_io_blocking_region(io, nogvl_fcntl, &arg);
11851 if (retval != -1) {
11852 switch (cmd) {
11853#if defined(F_DUPFD)
11854 case F_DUPFD:
11855#endif
11856#if defined(F_DUPFD_CLOEXEC)
11857 case F_DUPFD_CLOEXEC:
11858#endif
11859 rb_update_max_fd(retval);
11860 }
11861 }
11862
11863 return retval;
11864}
11865
11866static VALUE
11867rb_fcntl(VALUE io, VALUE req, VALUE arg)
11868{
11869 int cmd = NUM2INT(req);
11870 rb_io_t *fptr;
11871 long narg;
11872 int retval;
11873
11874 narg = setup_narg(cmd, &arg, fcntl_narg_len);
11875 GetOpenFile(io, fptr);
11876 retval = do_fcntl(fptr, cmd, narg);
11877 return finish_narg(retval, arg, fptr);
11878}
11879
11880/*
11881 * call-seq:
11882 * fcntl(integer_cmd, argument) -> integer
11883 *
11884 * Invokes Posix system call {fcntl(2)}[https://man7.org/linux/man-pages/man2/fcntl.2.html],
11885 * which provides a mechanism for issuing low-level commands to control or query
11886 * a file-oriented I/O stream. Arguments and results are platform
11887 * dependent.
11888 *
11889 * If +argument+ is a number, its value is passed directly;
11890 * if it is a string, it is interpreted as a binary sequence of bytes.
11891 * (Array#pack might be a useful way to build this string.)
11892 *
11893 * Not implemented on all platforms.
11894 *
11895 */
11896
11897static VALUE
11898rb_io_fcntl(int argc, VALUE *argv, VALUE io)
11899{
11900 VALUE req, arg;
11901
11902 rb_scan_args(argc, argv, "11", &req, &arg);
11903 return rb_fcntl(io, req, arg);
11904}
11905#else
11906#define rb_io_fcntl rb_f_notimplement
11907#endif
11908
11909#if defined(HAVE_SYSCALL) || defined(HAVE___SYSCALL)
11910/*
11911 * call-seq:
11912 * syscall(integer_callno, *arguments) -> integer
11913 *
11914 * Invokes Posix system call {syscall(2)}[https://man7.org/linux/man-pages/man2/syscall.2.html],
11915 * which calls a specified function.
11916 *
11917 * Calls the operating system function identified by +integer_callno+;
11918 * returns the result of the function or raises SystemCallError if it failed.
11919 * The effect of the call is platform-dependent.
11920 * The arguments and returned value are platform-dependent.
11921 *
11922 * For each of +arguments+: if it is an integer, it is passed directly;
11923 * if it is a string, it is interpreted as a binary sequence of bytes.
11924 * There may be as many as nine such arguments.
11925 *
11926 * Arguments +integer_callno+ and +argument+, as well as the returned value,
11927 * are platform-dependent.
11928 *
11929 * Note: Method +syscall+ is essentially unsafe and unportable.
11930 * The DL (Fiddle) library is preferred for safer and a bit
11931 * more portable programming.
11932 *
11933 * Not implemented on all platforms.
11934 *
11935 */
11936
11937static VALUE
11938rb_f_syscall(int argc, VALUE *argv, VALUE _)
11939{
11940 VALUE arg[8];
11941#if SIZEOF_VOIDP == 8 && defined(HAVE___SYSCALL) && SIZEOF_INT != 8 /* mainly *BSD */
11942# define SYSCALL __syscall
11943# define NUM2SYSCALLID(x) NUM2LONG(x)
11944# define RETVAL2NUM(x) LONG2NUM(x)
11945# if SIZEOF_LONG == 8
11946 long num, retval = -1;
11947# elif SIZEOF_LONG_LONG == 8
11948 long long num, retval = -1;
11949# else
11950# error ---->> it is asserted that __syscall takes the first argument and returns retval in 64bit signed integer. <<----
11951# endif
11952#elif defined(__linux__)
11953# define SYSCALL syscall
11954# define NUM2SYSCALLID(x) NUM2LONG(x)
11955# define RETVAL2NUM(x) LONG2NUM(x)
11956 /*
11957 * Linux man page says, syscall(2) function prototype is below.
11958 *
11959 * int syscall(int number, ...);
11960 *
11961 * But, it's incorrect. Actual one takes and returned long. (see unistd.h)
11962 */
11963 long num, retval = -1;
11964#else
11965# define SYSCALL syscall
11966# define NUM2SYSCALLID(x) NUM2INT(x)
11967# define RETVAL2NUM(x) INT2NUM(x)
11968 int num, retval = -1;
11969#endif
11970 int i;
11971
11972 if (RTEST(ruby_verbose)) {
11974 "We plan to remove a syscall function at future release. DL(Fiddle) provides safer alternative.");
11975 }
11976
11977 if (argc == 0)
11978 rb_raise(rb_eArgError, "too few arguments for syscall");
11979 if (argc > numberof(arg))
11980 rb_raise(rb_eArgError, "too many arguments for syscall");
11981 num = NUM2SYSCALLID(argv[0]); ++argv;
11982 for (i = argc - 1; i--; ) {
11983 VALUE v = rb_check_string_type(argv[i]);
11984
11985 if (!NIL_P(v)) {
11986 StringValue(v);
11987 rb_str_modify(v);
11988 arg[i] = (VALUE)StringValueCStr(v);
11989 }
11990 else {
11991 arg[i] = (VALUE)NUM2LONG(argv[i]);
11992 }
11993 }
11994
11995 switch (argc) {
11996 case 1:
11997 retval = SYSCALL(num);
11998 break;
11999 case 2:
12000 retval = SYSCALL(num, arg[0]);
12001 break;
12002 case 3:
12003 retval = SYSCALL(num, arg[0],arg[1]);
12004 break;
12005 case 4:
12006 retval = SYSCALL(num, arg[0],arg[1],arg[2]);
12007 break;
12008 case 5:
12009 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3]);
12010 break;
12011 case 6:
12012 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4]);
12013 break;
12014 case 7:
12015 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5]);
12016 break;
12017 case 8:
12018 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6]);
12019 break;
12020 }
12021
12022 if (retval == -1)
12023 rb_sys_fail(0);
12024 return RETVAL2NUM(retval);
12025#undef SYSCALL
12026#undef NUM2SYSCALLID
12027#undef RETVAL2NUM
12028}
12029#else
12030#define rb_f_syscall rb_f_notimplement
12031#endif
12032
12033static VALUE
12034io_new_instance(VALUE args)
12035{
12036 return rb_class_new_instance(2, (VALUE*)args+1, *(VALUE*)args);
12037}
12038
12039static rb_encoding *
12040find_encoding(VALUE v)
12041{
12042 rb_encoding *enc = rb_find_encoding(v);
12043 if (!enc) rb_warn("Unsupported encoding %"PRIsVALUE" ignored", v);
12044 return enc;
12045}
12046
12047static void
12048io_encoding_set(rb_io_t *fptr, VALUE v1, VALUE v2, VALUE opt)
12049{
12050 rb_encoding *enc, *enc2;
12051 int ecflags = fptr->encs.ecflags;
12052 VALUE ecopts, tmp;
12053
12054 if (!NIL_P(v2)) {
12055 enc2 = find_encoding(v1);
12056 tmp = rb_check_string_type(v2);
12057 if (!NIL_P(tmp)) {
12058 if (RSTRING_LEN(tmp) == 1 && RSTRING_PTR(tmp)[0] == '-') {
12059 /* Special case - "-" => no transcoding */
12060 enc = enc2;
12061 enc2 = NULL;
12062 }
12063 else
12064 enc = find_encoding(v2);
12065 if (enc == enc2) {
12066 /* Special case - "-" => no transcoding */
12067 enc2 = NULL;
12068 }
12069 }
12070 else {
12071 enc = find_encoding(v2);
12072 if (enc == enc2) {
12073 /* Special case - "-" => no transcoding */
12074 enc2 = NULL;
12075 }
12076 }
12077 if (enc2 == rb_ascii8bit_encoding()) {
12078 /* If external is ASCII-8BIT, no transcoding */
12079 enc = enc2;
12080 enc2 = NULL;
12081 }
12082 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
12083 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
12084 }
12085 else {
12086 if (NIL_P(v1)) {
12087 /* Set to default encodings */
12088 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
12089 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
12090 ecopts = Qnil;
12091 }
12092 else {
12093 tmp = rb_check_string_type(v1);
12094 if (!NIL_P(tmp) && rb_enc_asciicompat(enc = rb_enc_get(tmp))) {
12095 parse_mode_enc(RSTRING_PTR(tmp), enc, &enc, &enc2, NULL);
12096 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
12097 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
12098 }
12099 else {
12100 rb_io_ext_int_to_encs(find_encoding(v1), NULL, &enc, &enc2, 0);
12101 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
12102 ecopts = Qnil;
12103 }
12104 }
12105 }
12106 validate_enc_binmode(&fptr->mode, ecflags, enc, enc2);
12107 fptr->encs.enc = enc;
12108 fptr->encs.enc2 = enc2;
12109 fptr->encs.ecflags = ecflags;
12110 fptr->encs.ecopts = ecopts;
12111 clear_codeconv(fptr);
12112
12113}
12114
12116 rb_io_t *fptr;
12117 VALUE v1;
12118 VALUE v2;
12119 VALUE opt;
12120};
12121
12122static VALUE
12123io_encoding_set_v(VALUE v)
12124{
12125 struct io_encoding_set_args *arg = (struct io_encoding_set_args *)v;
12126 io_encoding_set(arg->fptr, arg->v1, arg->v2, arg->opt);
12127 return Qnil;
12128}
12129
12130static VALUE
12131pipe_pair_close(VALUE rw)
12132{
12133 VALUE *rwp = (VALUE *)rw;
12134 return rb_ensure(io_close, rwp[0], io_close, rwp[1]);
12135}
12136
12137/*
12138 * call-seq:
12139 * IO.pipe(**opts) -> [read_io, write_io]
12140 * IO.pipe(enc, **opts) -> [read_io, write_io]
12141 * IO.pipe(ext_enc, int_enc, **opts) -> [read_io, write_io]
12142 * IO.pipe(**opts) {|read_io, write_io| ...} -> object
12143 * IO.pipe(enc, **opts) {|read_io, write_io| ...} -> object
12144 * IO.pipe(ext_enc, int_enc, **opts) {|read_io, write_io| ...} -> object
12145 *
12146 * Creates a pair of pipe endpoints, +read_io+ and +write_io+,
12147 * connected to each other.
12148 *
12149 * If argument +enc_string+ is given, it must be a string containing one of:
12150 *
12151 * - The name of the encoding to be used as the external encoding.
12152 * - The colon-separated names of two encodings to be used as the external
12153 * and internal encodings.
12154 *
12155 * If argument +int_enc+ is given, it must be an Encoding object
12156 * or encoding name string that specifies the internal encoding to be used;
12157 * if argument +ext_enc+ is also given, it must be an Encoding object
12158 * or encoding name string that specifies the external encoding to be used.
12159 *
12160 * The string read from +read_io+ is tagged with the external encoding;
12161 * if an internal encoding is also specified, the string is converted
12162 * to, and tagged with, that encoding.
12163 *
12164 * If any encoding is specified,
12165 * optional hash arguments specify the conversion option.
12166 *
12167 * Optional keyword arguments +opts+ specify:
12168 *
12169 * - {Open Options}[rdoc-ref:IO@Open+Options].
12170 * - {Encoding Options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12171 *
12172 * With no block given, returns the two endpoints in an array:
12173 *
12174 * IO.pipe # => [#<IO:fd 4>, #<IO:fd 5>]
12175 *
12176 * With a block given, calls the block with the two endpoints;
12177 * closes both endpoints and returns the value of the block:
12178 *
12179 * IO.pipe {|read_io, write_io| p read_io; p write_io }
12180 *
12181 * Output:
12182 *
12183 * #<IO:fd 6>
12184 * #<IO:fd 7>
12185 *
12186 * Not available on all platforms.
12187 *
12188 * In the example below, the two processes close the ends of the pipe
12189 * that they are not using. This is not just a cosmetic nicety. The
12190 * read end of a pipe will not generate an end of file condition if
12191 * there are any writers with the pipe still open. In the case of the
12192 * parent process, the <tt>rd.read</tt> will never return if it
12193 * does not first issue a <tt>wr.close</tt>:
12194 *
12195 * rd, wr = IO.pipe
12196 *
12197 * if fork
12198 * wr.close
12199 * puts "Parent got: <#{rd.read}>"
12200 * rd.close
12201 * Process.wait
12202 * else
12203 * rd.close
12204 * puts 'Sending message to parent'
12205 * wr.write "Hi Dad"
12206 * wr.close
12207 * end
12208 *
12209 * <em>produces:</em>
12210 *
12211 * Sending message to parent
12212 * Parent got: <Hi Dad>
12213 *
12214 */
12215
12216static VALUE
12217rb_io_s_pipe(int argc, VALUE *argv, VALUE klass)
12218{
12219 int pipes[2], state;
12220 VALUE r, w, args[3], v1, v2;
12221 VALUE opt;
12222 rb_io_t *fptr, *fptr2;
12223 struct io_encoding_set_args ies_args;
12224 enum rb_io_mode fmode = 0;
12225 VALUE ret;
12226
12227 argc = rb_scan_args(argc, argv, "02:", &v1, &v2, &opt);
12228 if (rb_pipe(pipes) < 0)
12229 rb_sys_fail(0);
12230
12231 args[0] = klass;
12232 args[1] = INT2NUM(pipes[0]);
12233 args[2] = INT2FIX(O_RDONLY);
12234 r = rb_protect(io_new_instance, (VALUE)args, &state);
12235 if (state) {
12236 close(pipes[0]);
12237 close(pipes[1]);
12238 rb_jump_tag(state);
12239 }
12240 GetOpenFile(r, fptr);
12241
12242 ies_args.fptr = fptr;
12243 ies_args.v1 = v1;
12244 ies_args.v2 = v2;
12245 ies_args.opt = opt;
12246 rb_protect(io_encoding_set_v, (VALUE)&ies_args, &state);
12247 if (state) {
12248 close(pipes[1]);
12249 io_close(r);
12250 rb_jump_tag(state);
12251 }
12252
12253 args[1] = INT2NUM(pipes[1]);
12254 args[2] = INT2FIX(O_WRONLY);
12255 w = rb_protect(io_new_instance, (VALUE)args, &state);
12256 if (state) {
12257 close(pipes[1]);
12258 if (!NIL_P(r)) rb_io_close(r);
12259 rb_jump_tag(state);
12260 }
12261 GetOpenFile(w, fptr2);
12262 rb_io_synchronized(fptr2);
12263
12264 extract_binmode(opt, &fmode);
12265
12266 if ((fmode & FMODE_BINMODE) && NIL_P(v1)) {
12269 }
12270
12271#if DEFAULT_TEXTMODE
12272 if ((fptr->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
12273 fptr->mode &= ~FMODE_TEXTMODE;
12274 setmode(fptr->fd, O_BINARY);
12275 }
12276#if RUBY_CRLF_ENVIRONMENT
12279 }
12280#endif
12281#endif
12282 fptr->mode |= fmode;
12283#if DEFAULT_TEXTMODE
12284 if ((fptr2->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
12285 fptr2->mode &= ~FMODE_TEXTMODE;
12286 setmode(fptr2->fd, O_BINARY);
12287 }
12288#endif
12289 fptr2->mode |= fmode;
12290
12291 ret = rb_assoc_new(r, w);
12292 if (rb_block_given_p()) {
12293 VALUE rw[2];
12294 rw[0] = r;
12295 rw[1] = w;
12296 return rb_ensure(rb_yield, ret, pipe_pair_close, (VALUE)rw);
12297 }
12298 return ret;
12299}
12300
12302 int argc;
12303 VALUE *argv;
12304 VALUE io;
12305};
12306
12307static void
12308open_key_args(VALUE klass, int argc, VALUE *argv, VALUE opt, struct foreach_arg *arg)
12309{
12310 VALUE path, v;
12311 VALUE vmode = Qnil, vperm = Qnil;
12312
12313 path = *argv++;
12314 argc--;
12315 FilePathValue(path);
12316 arg->io = 0;
12317 arg->argc = argc;
12318 arg->argv = argv;
12319 if (NIL_P(opt)) {
12320 vmode = INT2NUM(O_RDONLY);
12321 vperm = INT2FIX(0666);
12322 }
12323 else if (!NIL_P(v = rb_hash_aref(opt, sym_open_args))) {
12324 int n;
12325
12326 v = rb_to_array_type(v);
12327 n = RARRAY_LENINT(v);
12328 rb_check_arity(n, 0, 3); /* rb_io_open */
12329 rb_scan_args_kw(RB_SCAN_ARGS_LAST_HASH_KEYWORDS, n, RARRAY_CONST_PTR(v), "02:", &vmode, &vperm, &opt);
12330 }
12331 arg->io = rb_io_open(klass, path, vmode, vperm, opt);
12332}
12333
12334static VALUE
12335io_s_foreach(VALUE v)
12336{
12337 struct getline_arg *arg = (void *)v;
12338 VALUE str;
12339
12340 if (arg->limit == 0)
12341 rb_raise(rb_eArgError, "invalid limit: 0 for foreach");
12342 while (!NIL_P(str = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, arg->io))) {
12343 rb_lastline_set(str);
12344 rb_yield(str);
12345 }
12347 return Qnil;
12348}
12349
12350/*
12351 * call-seq:
12352 * IO.foreach(path, sep = $/, **opts) {|line| block } -> nil
12353 * IO.foreach(path, limit, **opts) {|line| block } -> nil
12354 * IO.foreach(path, sep, limit, **opts) {|line| block } -> nil
12355 * IO.foreach(...) -> an_enumerator
12356 *
12357 * Calls the block with each successive line read from the stream.
12358 *
12359 * The first argument must be a string that is the path to a file.
12360 *
12361 * With only argument +path+ given, parses lines from the file at the given +path+,
12362 * as determined by the default line separator,
12363 * and calls the block with each successive line:
12364 *
12365 * File.foreach('t.txt') {|line| p line }
12366 *
12367 * Output: the same as above.
12368 *
12369 * For both forms, command and path, the remaining arguments are the same.
12370 *
12371 * With argument +sep+ given, parses lines as determined by that line separator
12372 * (see {Line Separator}[rdoc-ref:IO@Line+Separator]):
12373 *
12374 * File.foreach('t.txt', 'li') {|line| p line }
12375 *
12376 * Output:
12377 *
12378 * "First li"
12379 * "ne\nSecond li"
12380 * "ne\n\nThird li"
12381 * "ne\nFourth li"
12382 * "ne\n"
12383 *
12384 * Each paragraph:
12385 *
12386 * File.foreach('t.txt', '') {|paragraph| p paragraph }
12387 *
12388 * Output:
12389 *
12390 * "First line\nSecond line\n\n"
12391 * "Third line\nFourth line\n"
12392 *
12393 * With argument +limit+ given, parses lines as determined by the default
12394 * line separator and the given line-length limit
12395 * (see {Line Separator}[rdoc-ref:IO@Line+Separator] and {Line Limit}[rdoc-ref:IO@Line+Limit]):
12396 *
12397 * File.foreach('t.txt', 7) {|line| p line }
12398 *
12399 * Output:
12400 *
12401 * "First l"
12402 * "ine\n"
12403 * "Second "
12404 * "line\n"
12405 * "\n"
12406 * "Third l"
12407 * "ine\n"
12408 * "Fourth l"
12409 * "line\n"
12410 *
12411 * With arguments +sep+ and +limit+ given,
12412 * combines the two behaviors
12413 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
12414 *
12415 * Optional keyword arguments +opts+ specify:
12416 *
12417 * - {Open Options}[rdoc-ref:IO@Open+Options].
12418 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12419 * - {Line Input Options}[rdoc-ref:IO@Line+Input+Options].
12420 *
12421 * Returns an Enumerator if no block is given.
12422 *
12423 */
12424
12425static VALUE
12426rb_io_s_foreach(int argc, VALUE *argv, VALUE self)
12427{
12428 VALUE opt;
12429 int orig_argc = argc;
12430 struct foreach_arg arg;
12431 struct getline_arg garg;
12432
12433 argc = rb_scan_args(argc, argv, "12:", NULL, NULL, NULL, &opt);
12434 RETURN_ENUMERATOR(self, orig_argc, argv);
12435 extract_getline_args(argc-1, argv+1, &garg);
12436 open_key_args(self, argc, argv, opt, &arg);
12437 if (NIL_P(arg.io)) return Qnil;
12438 extract_getline_opts(opt, &garg);
12439 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12440 return rb_ensure(io_s_foreach, (VALUE)&garg, rb_io_close, arg.io);
12441}
12442
12443static VALUE
12444io_s_readlines(VALUE v)
12445{
12446 struct getline_arg *arg = (void *)v;
12447 return io_readlines(arg, arg->io);
12448}
12449
12450/*
12451 * call-seq:
12452 * IO.readlines(path, sep = $/, **opts) -> array
12453 * IO.readlines(path, limit, **opts) -> array
12454 * IO.readlines(path, sep, limit, **opts) -> array
12455 *
12456 * Returns an array of all lines read from the stream.
12457 *
12458 * The first argument must be a string that is the path to a file.
12459 *
12460 * With only argument +path+ given, parses lines from the file at the given +path+,
12461 * as determined by the default line separator,
12462 * and returns those lines in an array:
12463 *
12464 * IO.readlines('t.txt')
12465 * # => ["First line\n", "Second line\n", "\n", "Third line\n", "Fourth line\n"]
12466 *
12467 * With argument +sep+ given, parses lines as determined by that line separator
12468 * (see {Line Separator}[rdoc-ref:IO@Line+Separator]):
12469 *
12470 * # Ordinary separator.
12471 * IO.readlines('t.txt', 'li')
12472 * # =>["First li", "ne\nSecond li", "ne\n\nThird li", "ne\nFourth li", "ne\n"]
12473 * # Get-paragraphs separator.
12474 * IO.readlines('t.txt', '')
12475 * # => ["First line\nSecond line\n\n", "Third line\nFourth line\n"]
12476 * # Get-all separator.
12477 * IO.readlines('t.txt', nil)
12478 * # => ["First line\nSecond line\n\nThird line\nFourth line\n"]
12479 *
12480 * With argument +limit+ given, parses lines as determined by the default
12481 * line separator and the given line-length limit
12482 * (see {Line Separator}[rdoc-ref:IO@Line+Separator] and {Line Limit}[rdoc-ref:IO@Line+Limit]:
12483 *
12484 * IO.readlines('t.txt', 7)
12485 * # => ["First l", "ine\n", "Second ", "line\n", "\n", "Third l", "ine\n", "Fourth ", "line\n"]
12486 *
12487 * With arguments +sep+ and +limit+ given,
12488 * combines the two behaviors
12489 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
12490 *
12491 * Optional keyword arguments +opts+ specify:
12492 *
12493 * - {Open Options}[rdoc-ref:IO@Open+Options].
12494 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12495 * - {Line Input Options}[rdoc-ref:IO@Line+Input+Options].
12496 *
12497 */
12498
12499static VALUE
12500rb_io_s_readlines(int argc, VALUE *argv, VALUE io)
12501{
12502 VALUE opt;
12503 struct foreach_arg arg;
12504 struct getline_arg garg;
12505
12506 argc = rb_scan_args(argc, argv, "12:", NULL, NULL, NULL, &opt);
12507 extract_getline_args(argc-1, argv+1, &garg);
12508 open_key_args(io, argc, argv, opt, &arg);
12509 if (NIL_P(arg.io)) return Qnil;
12510 extract_getline_opts(opt, &garg);
12511 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12512 return rb_ensure(io_s_readlines, (VALUE)&garg, rb_io_close, arg.io);
12513}
12514
12515static VALUE
12516io_s_read(VALUE v)
12517{
12518 struct foreach_arg *arg = (void *)v;
12519 return io_read(arg->argc, arg->argv, arg->io);
12520}
12521
12522struct seek_arg {
12523 VALUE io;
12524 VALUE offset;
12525 int mode;
12526};
12527
12528static VALUE
12529seek_before_access(VALUE argp)
12530{
12531 struct seek_arg *arg = (struct seek_arg *)argp;
12532 rb_io_binmode(arg->io);
12533 return rb_io_seek(arg->io, arg->offset, arg->mode);
12534}
12535
12536/*
12537 * call-seq:
12538 * IO.read(path, length = nil, offset = 0, **opts) -> string or nil
12539 *
12540 * Opens the stream, reads and returns some or all of its content,
12541 * and closes the stream; returns +nil+ if no bytes were read.
12542 *
12543 * The first argument must be a string that is the path to a file.
12544 *
12545 * With only argument +path+ given, reads in text mode and returns the entire content
12546 * of the file at the given path:
12547 *
12548 * File.read('t.txt')
12549 * # => "First line\nSecond line\n\nFourth line\nFifth line\n"
12550 * File.read('t.ja')
12551 * # => "こんにちは"
12552 * File.read('t.dat')
12553 * # => "\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"
12554 *
12555 * On Windows, text mode can terminate reading and leave bytes in the file
12556 * unread when encountering certain special bytes. Consider using
12557 * IO.binread if all bytes in the file should be read.
12558 *
12559 * With argument +length+, returns +length+ bytes if available:
12560 *
12561 * File.read('t.txt', 7)
12562 * # => "First l"
12563 * File.read('t.ja', 7)
12564 * # => "\xE3\x81\x93\xE3\x82\x93\xE3"
12565 * File.read('t.dat', 7)
12566 * # => "\xFE\xFF\x99\x90\x99\x91\x99"
12567 *
12568 * Returns all bytes if +length+ is larger than the files size:
12569 *
12570 * File.read('t.txt', 700)
12571 * # => "First line\r\nSecond line\r\n\r\nFourth line\r\nFifth line\r\n"
12572 * File.read('t.ja', 700)
12573 * # => "\xE3\x81\x93\xE3\x82\x93\xE3\x81\xAB\xE3\x81\xA1\xE3\x81\xAF"
12574 * File.read('t.dat', 700)
12575 * # => "\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"
12576 *
12577 * With arguments +length+ and +offset+, returns +length+ bytes
12578 * if available, beginning at the given +offset+:
12579 *
12580 * File.read('t.txt', 10, 2)
12581 * # => "rst line\r\n"
12582 * File.read('t.ja', 10, 2)
12583 * # => "\x93\xE3\x82\x93\xE3\x81\xAB\xE3\x81\xA1"
12584 * File.read('t.dat', 10, 2)
12585 * # => "\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"
12586 *
12587 * Returns +nil+ if +offset+ is past the end of the stream:
12588 *
12589 * File.read('t.txt', 10, 200)
12590 * # => nil
12591 *
12592 * Optional keyword arguments +opts+ specify:
12593 *
12594 * - {Open Options}[rdoc-ref:IO@Open+Options].
12595 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12596 *
12597 */
12598
12599static VALUE
12600rb_io_s_read(int argc, VALUE *argv, VALUE io)
12601{
12602 VALUE opt, offset;
12603 long off;
12604 struct foreach_arg arg;
12605
12606 argc = rb_scan_args(argc, argv, "13:", NULL, NULL, &offset, NULL, &opt);
12607 if (!NIL_P(offset) && (off = NUM2LONG(offset)) < 0) {
12608 rb_raise(rb_eArgError, "negative offset %ld given", off);
12609 }
12610 open_key_args(io, argc, argv, opt, &arg);
12611 if (NIL_P(arg.io)) return Qnil;
12612 if (!NIL_P(offset)) {
12613 struct seek_arg sarg;
12614 int state = 0;
12615 sarg.io = arg.io;
12616 sarg.offset = offset;
12617 sarg.mode = SEEK_SET;
12618 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12619 if (state) {
12620 rb_io_close(arg.io);
12621 rb_jump_tag(state);
12622 }
12623 if (arg.argc == 2) arg.argc = 1;
12624 }
12625 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
12626}
12627
12628/*
12629 * call-seq:
12630 * IO.binread(path, length = nil, offset = 0) -> string or nil
12631 *
12632 * Behaves like IO.read, except that the stream is opened in binary mode
12633 * with ASCII-8BIT encoding.
12634 *
12635 */
12636
12637static VALUE
12638rb_io_s_binread(int argc, VALUE *argv, VALUE io)
12639{
12640 VALUE offset;
12641 struct foreach_arg arg;
12642 enum rb_io_mode fmode = FMODE_READABLE|FMODE_BINMODE;
12643 enum {
12644 oflags = O_RDONLY
12645#ifdef O_BINARY
12646 |O_BINARY
12647#endif
12648 };
12649 struct rb_io_encoding convconfig = {NULL, NULL, 0, Qnil};
12650
12651 rb_scan_args(argc, argv, "12", NULL, NULL, &offset);
12652 FilePathValue(argv[0]);
12653 convconfig.enc = rb_ascii8bit_encoding();
12654 arg.io = rb_io_open_generic(io, argv[0], oflags, fmode, &convconfig, 0);
12655 if (NIL_P(arg.io)) return Qnil;
12656 arg.argv = argv+1;
12657 arg.argc = (argc > 1) ? 1 : 0;
12658 if (!NIL_P(offset)) {
12659 struct seek_arg sarg;
12660 int state = 0;
12661 sarg.io = arg.io;
12662 sarg.offset = offset;
12663 sarg.mode = SEEK_SET;
12664 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12665 if (state) {
12666 rb_io_close(arg.io);
12667 rb_jump_tag(state);
12668 }
12669 }
12670 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
12671}
12672
12673static VALUE
12674io_s_write0(VALUE v)
12675{
12676 struct write_arg *arg = (void *)v;
12677 return io_write(arg->io,arg->str,arg->nosync);
12678}
12679
12680static VALUE
12681io_s_write(int argc, VALUE *argv, VALUE klass, int binary)
12682{
12683 VALUE string, offset, opt;
12684 struct foreach_arg arg;
12685 struct write_arg warg;
12686
12687 rb_scan_args(argc, argv, "21:", NULL, &string, &offset, &opt);
12688
12689 if (NIL_P(opt)) opt = rb_hash_new();
12690 else opt = rb_hash_dup(opt);
12691
12692
12693 if (NIL_P(rb_hash_aref(opt,sym_mode))) {
12694 int mode = O_WRONLY|O_CREAT;
12695#ifdef O_BINARY
12696 if (binary) mode |= O_BINARY;
12697#endif
12698 if (NIL_P(offset)) mode |= O_TRUNC;
12699 rb_hash_aset(opt,sym_mode,INT2NUM(mode));
12700 }
12701 open_key_args(klass, argc, argv, opt, &arg);
12702
12703#ifndef O_BINARY
12704 if (binary) rb_io_binmode_m(arg.io);
12705#endif
12706
12707 if (NIL_P(arg.io)) return Qnil;
12708 if (!NIL_P(offset)) {
12709 struct seek_arg sarg;
12710 int state = 0;
12711 sarg.io = arg.io;
12712 sarg.offset = offset;
12713 sarg.mode = SEEK_SET;
12714 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12715 if (state) {
12716 rb_io_close(arg.io);
12717 rb_jump_tag(state);
12718 }
12719 }
12720
12721 warg.io = arg.io;
12722 warg.str = string;
12723 warg.nosync = 0;
12724
12725 return rb_ensure(io_s_write0, (VALUE)&warg, rb_io_close, arg.io);
12726}
12727
12728/*
12729 * call-seq:
12730 * IO.write(path, data, offset = 0, **opts) -> nonnegative_integer
12731 *
12732 * Opens the stream, writes the given +data+ to it,
12733 * and closes the stream; returns the number of bytes written.
12734 *
12735 * The first argument must be a string that is the path to a file.
12736 *
12737 * With only arguments +path+ and +data+ given,
12738 * writes the given data to the file at that path:
12739 *
12740 * path = 't.tmp'
12741 * File.write(path, "First line\nSecond line\n\nFourth line\nFifth line\n") # => 47
12742 * File.write(path, 'こんにちは') # => 15
12743 * File.write(path, "\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94") # => 12
12744 *
12745 * When +offset+ is zero (the default), the entire file content is overwritten:
12746 *
12747 * File.read(path) # => "\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"
12748 * File.write(path, 'foo')
12749 * File.read(path) # => "foo"
12750 *
12751 * When +offset+ in within the file content, the file content is partly overwritten,
12752 * beginning at byte +offset+:
12753 *
12754 * File.write(path, "First line\nSecond line\n\nFourth line\nFifth line\n")
12755 * File.write(path, 'LINE', 6)
12756 * File.read(path) # => "First LINE\nSecond line\n\nFourth line\nFifth line\n"
12757 *
12758 * When the file contains multi-byte characters,
12759 * the effect of writing may disturb some characters:
12760 *
12761 * File.write(path, "こんにちは")
12762 * File.write(path, 'FOO', 3) # Replace one 3-byte character.
12763 * File.read(path) # => "こFOOにちは"
12764 * File.write(path, 'BAR', 7) # Replace bytes in two different 3-byte characters.
12765 * File.read(path) # => "こFOO\xE3BAR\x81\xA1は"
12766 *
12767 * If +offset+ is outside the file content,
12768 * the file is padded with null characters <tt>"\u0000"</tt>:
12769 *
12770 * File.write(path, "First line\nSecond line\n\nFourth line\nFifth line\n")
12771 * File.write(path, 'FOO', 55)
12772 * File.read(path)
12773 * # => "First line\nSecond line\n\nFourth line\nFifth line\n\u0000\u0000\u0000FOO"
12774 *
12775 * Optional keyword arguments +opts+ specify:
12776 *
12777 * - {Open Options}[rdoc-ref:IO@Open+Options].
12778 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12779 *
12780 */
12781
12782static VALUE
12783rb_io_s_write(int argc, VALUE *argv, VALUE io)
12784{
12785 return io_s_write(argc, argv, io, 0);
12786}
12787
12788/*
12789 * call-seq:
12790 * IO.binwrite(path, string, offset = 0, **opts) -> integer
12791 *
12792 * Behaves like IO.write, except that the stream is opened in binary mode
12793 * with ASCII-8BIT encoding.
12794 *
12795 */
12796
12797static VALUE
12798rb_io_s_binwrite(int argc, VALUE *argv, VALUE io)
12799{
12800 return io_s_write(argc, argv, io, 1);
12801}
12802
12804 VALUE src;
12805 VALUE dst;
12806 rb_off_t copy_length; /* (rb_off_t)-1 if not specified */
12807 rb_off_t src_offset; /* (rb_off_t)-1 if not specified */
12808
12809 rb_io_t *src_fptr;
12810 rb_io_t *dst_fptr;
12811 unsigned close_src : 1;
12812 unsigned close_dst : 1;
12813 int error_no;
12814 rb_off_t total;
12815 const char *syserr;
12816 const char *notimp;
12817 VALUE th;
12818 struct stat src_stat;
12819 struct stat dst_stat;
12820#ifdef HAVE_FCOPYFILE
12821 copyfile_state_t copyfile_state;
12822#endif
12823};
12824
12825static void *
12826exec_interrupts(void *arg)
12827{
12828 VALUE th = (VALUE)arg;
12829 rb_thread_execute_interrupts(th);
12830 return NULL;
12831}
12832
12833/*
12834 * returns TRUE if the preceding system call was interrupted
12835 * so we can continue. If the thread was interrupted, we
12836 * reacquire the GVL to execute interrupts before continuing.
12837 */
12838static int
12839maygvl_copy_stream_continue_p(int has_gvl, struct copy_stream_struct *stp)
12840{
12841 switch (errno) {
12842 case EINTR:
12843#if defined(ERESTART)
12844 case ERESTART:
12845#endif
12846 if (rb_thread_interrupted(stp->th)) {
12847 if (has_gvl)
12848 rb_thread_execute_interrupts(stp->th);
12849 else
12850 rb_thread_call_with_gvl(exec_interrupts, (void *)stp->th);
12851 }
12852 return TRUE;
12853 }
12854 return FALSE;
12855}
12856
12858 VALUE scheduler;
12859
12860 rb_io_t *fptr;
12861 short events;
12862
12863 VALUE result;
12864};
12865
12866static void *
12867fiber_scheduler_wait_for(void * _arguments)
12868{
12869 struct fiber_scheduler_wait_for_arguments *arguments = (struct fiber_scheduler_wait_for_arguments *)_arguments;
12870
12871 arguments->result = rb_fiber_scheduler_io_wait(arguments->scheduler, arguments->fptr->self, INT2NUM(arguments->events), RUBY_IO_TIMEOUT_DEFAULT);
12872
12873 return NULL;
12874}
12875
12876#if USE_POLL
12877# define IOWAIT_SYSCALL "poll"
12878STATIC_ASSERT(pollin_expected, POLLIN == RB_WAITFD_IN);
12879STATIC_ASSERT(pollout_expected, POLLOUT == RB_WAITFD_OUT);
12880static int
12881nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout)
12882{
12884 if (scheduler != Qnil) {
12885 struct fiber_scheduler_wait_for_arguments args = {.scheduler = scheduler, .fptr = fptr, .events = events};
12886 rb_thread_call_with_gvl(fiber_scheduler_wait_for, &args);
12887 return RTEST(args.result);
12888 }
12889
12890 int fd = fptr->fd;
12891 if (fd == -1) return 0;
12892
12893 struct pollfd fds;
12894
12895 fds.fd = fd;
12896 fds.events = events;
12897
12898 int timeout_milliseconds = -1;
12899
12900 if (timeout) {
12901 timeout_milliseconds = (int)(timeout->tv_sec * 1000) + (int)(timeout->tv_usec / 1000);
12902 }
12903
12904 return poll(&fds, 1, timeout_milliseconds);
12905}
12906#else /* !USE_POLL */
12907# define IOWAIT_SYSCALL "select"
12908static int
12909nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout)
12910{
12912 if (scheduler != Qnil) {
12913 struct fiber_scheduler_wait_for_arguments args = {.scheduler = scheduler, .fptr = fptr, .events = events};
12914 rb_thread_call_with_gvl(fiber_scheduler_wait_for, &args);
12915 return RTEST(args.result);
12916 }
12917
12918 int fd = fptr->fd;
12919
12920 if (fd == -1) {
12921 errno = EBADF;
12922 return -1;
12923 }
12924
12925 rb_fdset_t fds;
12926 int ret;
12927
12928 rb_fd_init(&fds);
12929 rb_fd_set(fd, &fds);
12930
12931 switch (events) {
12932 case RB_WAITFD_IN:
12933 ret = rb_fd_select(fd + 1, &fds, 0, 0, timeout);
12934 break;
12935 case RB_WAITFD_OUT:
12936 ret = rb_fd_select(fd + 1, 0, &fds, 0, timeout);
12937 break;
12938 default:
12939 VM_UNREACHABLE(nogvl_wait_for);
12940 }
12941
12942 rb_fd_term(&fds);
12943
12944 // On timeout, this returns 0.
12945 return ret;
12946}
12947#endif /* !USE_POLL */
12948
12949static int
12950maygvl_copy_stream_wait_read(int has_gvl, struct copy_stream_struct *stp)
12951{
12952 int ret;
12953
12954 do {
12955 if (has_gvl) {
12957 }
12958 else {
12959 ret = nogvl_wait_for(stp->th, stp->src_fptr, RB_WAITFD_IN, NULL);
12960 }
12961 } while (ret < 0 && maygvl_copy_stream_continue_p(has_gvl, stp));
12962
12963 if (ret < 0) {
12964 stp->syserr = IOWAIT_SYSCALL;
12965 stp->error_no = errno;
12966 return ret;
12967 }
12968 return 0;
12969}
12970
12971static int
12972nogvl_copy_stream_wait_write(struct copy_stream_struct *stp)
12973{
12974 int ret;
12975
12976 do {
12977 ret = nogvl_wait_for(stp->th, stp->dst_fptr, RB_WAITFD_OUT, NULL);
12978 } while (ret < 0 && maygvl_copy_stream_continue_p(0, stp));
12979
12980 if (ret < 0) {
12981 stp->syserr = IOWAIT_SYSCALL;
12982 stp->error_no = errno;
12983 return ret;
12984 }
12985 return 0;
12986}
12987
12988#ifdef USE_COPY_FILE_RANGE
12989
12990static ssize_t
12991simple_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)
12992{
12993#ifdef HAVE_COPY_FILE_RANGE
12994 return copy_file_range(in_fd, in_offset, out_fd, out_offset, count, flags);
12995#else
12996 return syscall(__NR_copy_file_range, in_fd, in_offset, out_fd, out_offset, count, flags);
12997#endif
12998}
12999
13000static int
13001nogvl_copy_file_range(struct copy_stream_struct *stp)
13002{
13003 ssize_t ss;
13004 rb_off_t src_size;
13005 rb_off_t copy_length, src_offset, *src_offset_ptr;
13006
13007 if (!S_ISREG(stp->src_stat.st_mode))
13008 return 0;
13009
13010 src_size = stp->src_stat.st_size;
13011 src_offset = stp->src_offset;
13012 if (src_offset >= (rb_off_t)0) {
13013 src_offset_ptr = &src_offset;
13014 }
13015 else {
13016 src_offset_ptr = NULL; /* if src_offset_ptr is NULL, then bytes are read from in_fd starting from the file offset */
13017 }
13018
13019 copy_length = stp->copy_length;
13020 if (copy_length < (rb_off_t)0) {
13021 if (src_offset < (rb_off_t)0) {
13022 rb_off_t current_offset;
13023 errno = 0;
13024 current_offset = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
13025 if (current_offset < (rb_off_t)0 && errno) {
13026 stp->syserr = "lseek";
13027 stp->error_no = errno;
13028 return (int)current_offset;
13029 }
13030 copy_length = src_size - current_offset;
13031 }
13032 else {
13033 copy_length = src_size - src_offset;
13034 }
13035 }
13036
13037 retry_copy_file_range:
13038# if SIZEOF_OFF_T > SIZEOF_SIZE_T
13039 /* we are limited by the 32-bit ssize_t return value on 32-bit */
13040 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
13041# else
13042 ss = (ssize_t)copy_length;
13043# endif
13044 ss = simple_copy_file_range(stp->src_fptr->fd, src_offset_ptr, stp->dst_fptr->fd, NULL, ss, 0);
13045 if (0 < ss) {
13046 stp->total += ss;
13047 copy_length -= ss;
13048 if (0 < copy_length) {
13049 goto retry_copy_file_range;
13050 }
13051 }
13052 if (ss < 0) {
13053 if (maygvl_copy_stream_continue_p(0, stp)) {
13054 goto retry_copy_file_range;
13055 }
13056 switch (errno) {
13057 case EINVAL:
13058 case EPERM: /* copy_file_range(2) doesn't exist (may happen in
13059 docker container) */
13060#ifdef ENOSYS
13061 case ENOSYS:
13062#endif
13063#ifdef EXDEV
13064 case EXDEV: /* in_fd and out_fd are not on the same filesystem */
13065#endif
13066 return 0;
13067 case EAGAIN:
13068#if EWOULDBLOCK != EAGAIN
13069 case EWOULDBLOCK:
13070#endif
13071 {
13072 int ret = nogvl_copy_stream_wait_write(stp);
13073 if (ret < 0) return ret;
13074 }
13075 goto retry_copy_file_range;
13076 case EBADF:
13077 {
13078 int e = errno;
13079 int flags = fcntl(stp->dst_fptr->fd, F_GETFL);
13080
13081 if (flags != -1 && flags & O_APPEND) {
13082 return 0;
13083 }
13084 errno = e;
13085 }
13086 }
13087 stp->syserr = "copy_file_range";
13088 stp->error_no = errno;
13089 return (int)ss;
13090 }
13091 return 1;
13092}
13093#endif
13094
13095#ifdef HAVE_FCOPYFILE
13096static int
13097nogvl_fcopyfile(struct copy_stream_struct *stp)
13098{
13099 rb_off_t cur, ss = 0;
13100 const rb_off_t src_offset = stp->src_offset;
13101 int ret;
13102
13103 if (stp->copy_length >= (rb_off_t)0) {
13104 /* copy_length can't be specified in fcopyfile(3) */
13105 return 0;
13106 }
13107
13108 if (!S_ISREG(stp->src_stat.st_mode))
13109 return 0;
13110
13111 if (!S_ISREG(stp->dst_stat.st_mode))
13112 return 0;
13113 if (lseek(stp->dst_fptr->fd, 0, SEEK_CUR) > (rb_off_t)0) /* if dst IO was already written */
13114 return 0;
13115 if (fcntl(stp->dst_fptr->fd, F_GETFL) & O_APPEND) {
13116 /* fcopyfile(3) appends src IO to dst IO and then truncates
13117 * dst IO to src IO's original size. */
13118 rb_off_t end = lseek(stp->dst_fptr->fd, 0, SEEK_END);
13119 lseek(stp->dst_fptr->fd, 0, SEEK_SET);
13120 if (end > (rb_off_t)0) return 0;
13121 }
13122
13123 if (src_offset > (rb_off_t)0) {
13124 rb_off_t r;
13125
13126 /* get current offset */
13127 errno = 0;
13128 cur = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
13129 if (cur < (rb_off_t)0 && errno) {
13130 stp->error_no = errno;
13131 return 1;
13132 }
13133
13134 errno = 0;
13135 r = lseek(stp->src_fptr->fd, src_offset, SEEK_SET);
13136 if (r < (rb_off_t)0 && errno) {
13137 stp->error_no = errno;
13138 return 1;
13139 }
13140 }
13141
13142 stp->copyfile_state = copyfile_state_alloc(); /* this will be freed by copy_stream_finalize() */
13143 ret = fcopyfile(stp->src_fptr->fd, stp->dst_fptr->fd, stp->copyfile_state, COPYFILE_DATA);
13144 copyfile_state_get(stp->copyfile_state, COPYFILE_STATE_COPIED, &ss); /* get copied bytes */
13145
13146 if (ret == 0) { /* success */
13147 stp->total = ss;
13148 if (src_offset > (rb_off_t)0) {
13149 rb_off_t r;
13150 errno = 0;
13151 /* reset offset */
13152 r = lseek(stp->src_fptr->fd, cur, SEEK_SET);
13153 if (r < (rb_off_t)0 && errno) {
13154 stp->error_no = errno;
13155 return 1;
13156 }
13157 }
13158 }
13159 else {
13160 switch (errno) {
13161 case ENOTSUP:
13162 case EPERM:
13163 case EINVAL:
13164 return 0;
13165 }
13166 stp->syserr = "fcopyfile";
13167 stp->error_no = errno;
13168 return (int)ret;
13169 }
13170 return 1;
13171}
13172#endif
13173
13174#ifdef HAVE_SENDFILE
13175
13176# ifdef __linux__
13177# define USE_SENDFILE
13178
13179# ifdef HAVE_SYS_SENDFILE_H
13180# include <sys/sendfile.h>
13181# endif
13182
13183static ssize_t
13184simple_sendfile(int out_fd, int in_fd, rb_off_t *offset, rb_off_t count)
13185{
13186 return sendfile(out_fd, in_fd, offset, (size_t)count);
13187}
13188
13189# elif 0 /* defined(__FreeBSD__) || defined(__DragonFly__) */ || defined(__APPLE__)
13190/* This runs on FreeBSD8.1 r30210, but sendfiles blocks its execution
13191 * without cpuset -l 0.
13192 */
13193# define USE_SENDFILE
13194
13195static ssize_t
13196simple_sendfile(int out_fd, int in_fd, rb_off_t *offset, rb_off_t count)
13197{
13198 int r;
13199 rb_off_t pos = offset ? *offset : lseek(in_fd, 0, SEEK_CUR);
13200 rb_off_t sbytes;
13201# ifdef __APPLE__
13202 r = sendfile(in_fd, out_fd, pos, &count, NULL, 0);
13203 sbytes = count;
13204# else
13205 r = sendfile(in_fd, out_fd, pos, (size_t)count, NULL, &sbytes, 0);
13206# endif
13207 if (r != 0 && sbytes == 0) return r;
13208 if (offset) {
13209 *offset += sbytes;
13210 }
13211 else {
13212 lseek(in_fd, sbytes, SEEK_CUR);
13213 }
13214 return (ssize_t)sbytes;
13215}
13216
13217# endif
13218
13219#endif
13220
13221#ifdef USE_SENDFILE
13222static int
13223nogvl_copy_stream_sendfile(struct copy_stream_struct *stp)
13224{
13225 ssize_t ss;
13226 rb_off_t src_size;
13227 rb_off_t copy_length;
13228 rb_off_t src_offset;
13229 int use_pread;
13230
13231 if (!S_ISREG(stp->src_stat.st_mode))
13232 return 0;
13233
13234 src_size = stp->src_stat.st_size;
13235#ifndef __linux__
13236 if ((stp->dst_stat.st_mode & S_IFMT) != S_IFSOCK)
13237 return 0;
13238#endif
13239
13240 src_offset = stp->src_offset;
13241 use_pread = src_offset >= (rb_off_t)0;
13242
13243 copy_length = stp->copy_length;
13244 if (copy_length < (rb_off_t)0) {
13245 if (use_pread)
13246 copy_length = src_size - src_offset;
13247 else {
13248 rb_off_t cur;
13249 errno = 0;
13250 cur = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
13251 if (cur < (rb_off_t)0 && errno) {
13252 stp->syserr = "lseek";
13253 stp->error_no = errno;
13254 return (int)cur;
13255 }
13256 copy_length = src_size - cur;
13257 }
13258 }
13259
13260 retry_sendfile:
13261# if SIZEOF_OFF_T > SIZEOF_SIZE_T
13262 /* we are limited by the 32-bit ssize_t return value on 32-bit */
13263 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
13264# else
13265 ss = (ssize_t)copy_length;
13266# endif
13267 if (use_pread) {
13268 ss = simple_sendfile(stp->dst_fptr->fd, stp->src_fptr->fd, &src_offset, ss);
13269 }
13270 else {
13271 ss = simple_sendfile(stp->dst_fptr->fd, stp->src_fptr->fd, NULL, ss);
13272 }
13273 if (0 < ss) {
13274 stp->total += ss;
13275 copy_length -= ss;
13276 if (0 < copy_length) {
13277 goto retry_sendfile;
13278 }
13279 }
13280 if (ss < 0) {
13281 if (maygvl_copy_stream_continue_p(0, stp))
13282 goto retry_sendfile;
13283 switch (errno) {
13284 case EINVAL:
13285#ifdef ENOSYS
13286 case ENOSYS:
13287#endif
13288#ifdef EOPNOTSUP
13289 /* some RedHat kernels may return EOPNOTSUP on an NFS mount.
13290 see also: [Feature #16965] */
13291 case EOPNOTSUP:
13292#endif
13293 return 0;
13294 case EAGAIN:
13295#if EWOULDBLOCK != EAGAIN
13296 case EWOULDBLOCK:
13297#endif
13298 {
13299 int ret;
13300#ifndef __linux__
13301 /*
13302 * Linux requires stp->src_fptr->fd to be a mmap-able (regular) file,
13303 * select() reports regular files to always be "ready", so
13304 * there is no need to select() on it.
13305 * Other OSes may have the same limitation for sendfile() which
13306 * allow us to bypass maygvl_copy_stream_wait_read()...
13307 */
13308 ret = maygvl_copy_stream_wait_read(0, stp);
13309 if (ret < 0) return ret;
13310#endif
13311 ret = nogvl_copy_stream_wait_write(stp);
13312 if (ret < 0) return ret;
13313 }
13314 goto retry_sendfile;
13315 }
13316 stp->syserr = "sendfile";
13317 stp->error_no = errno;
13318 return (int)ss;
13319 }
13320 return 1;
13321}
13322#endif
13323
13324static ssize_t
13325maygvl_read(int has_gvl, rb_io_t *fptr, void *buf, size_t count)
13326{
13327 if (has_gvl)
13328 return rb_io_read_memory(fptr, buf, count);
13329 else
13330 return read(fptr->fd, buf, count);
13331}
13332
13333static ssize_t
13334maygvl_copy_stream_read(int has_gvl, struct copy_stream_struct *stp, char *buf, size_t len, rb_off_t offset)
13335{
13336 ssize_t ss;
13337 retry_read:
13338 if (offset < (rb_off_t)0) {
13339 ss = maygvl_read(has_gvl, stp->src_fptr, buf, len);
13340 }
13341 else {
13342 ss = pread(stp->src_fptr->fd, buf, len, offset);
13343 }
13344 if (ss == 0) {
13345 return 0;
13346 }
13347 if (ss < 0) {
13348 if (maygvl_copy_stream_continue_p(has_gvl, stp))
13349 goto retry_read;
13350 switch (errno) {
13351 case EAGAIN:
13352#if EWOULDBLOCK != EAGAIN
13353 case EWOULDBLOCK:
13354#endif
13355 {
13356 int ret = maygvl_copy_stream_wait_read(has_gvl, stp);
13357 if (ret < 0) return ret;
13358 }
13359 goto retry_read;
13360#ifdef ENOSYS
13361 case ENOSYS:
13362 stp->notimp = "pread";
13363 return ss;
13364#endif
13365 }
13366 stp->syserr = offset < (rb_off_t)0 ? "read" : "pread";
13367 stp->error_no = errno;
13368 }
13369 return ss;
13370}
13371
13372static int
13373nogvl_copy_stream_write(struct copy_stream_struct *stp, char *buf, size_t len)
13374{
13375 ssize_t ss;
13376 int off = 0;
13377 while (len) {
13378 ss = write(stp->dst_fptr->fd, buf+off, len);
13379 if (ss < 0) {
13380 if (maygvl_copy_stream_continue_p(0, stp))
13381 continue;
13382 if (io_again_p(errno)) {
13383 int ret = nogvl_copy_stream_wait_write(stp);
13384 if (ret < 0) return ret;
13385 continue;
13386 }
13387 stp->syserr = "write";
13388 stp->error_no = errno;
13389 return (int)ss;
13390 }
13391 off += (int)ss;
13392 len -= (int)ss;
13393 stp->total += ss;
13394 }
13395 return 0;
13396}
13397
13398static void
13399nogvl_copy_stream_read_write(struct copy_stream_struct *stp)
13400{
13401 char buf[1024*16];
13402 size_t len;
13403 ssize_t ss;
13404 int ret;
13405 rb_off_t copy_length;
13406 rb_off_t src_offset;
13407 int use_eof;
13408 int use_pread;
13409
13410 copy_length = stp->copy_length;
13411 use_eof = copy_length < (rb_off_t)0;
13412 src_offset = stp->src_offset;
13413 use_pread = src_offset >= (rb_off_t)0;
13414
13415 if (use_pread && stp->close_src) {
13416 rb_off_t r;
13417 errno = 0;
13418 r = lseek(stp->src_fptr->fd, src_offset, SEEK_SET);
13419 if (r < (rb_off_t)0 && errno) {
13420 stp->syserr = "lseek";
13421 stp->error_no = errno;
13422 return;
13423 }
13424 src_offset = (rb_off_t)-1;
13425 use_pread = 0;
13426 }
13427
13428 while (use_eof || 0 < copy_length) {
13429 if (!use_eof && copy_length < (rb_off_t)sizeof(buf)) {
13430 len = (size_t)copy_length;
13431 }
13432 else {
13433 len = sizeof(buf);
13434 }
13435 if (use_pread) {
13436 ss = maygvl_copy_stream_read(0, stp, buf, len, src_offset);
13437 if (0 < ss)
13438 src_offset += ss;
13439 }
13440 else {
13441 ss = maygvl_copy_stream_read(0, stp, buf, len, (rb_off_t)-1);
13442 }
13443 if (ss <= 0) /* EOF or error */
13444 return;
13445
13446 ret = nogvl_copy_stream_write(stp, buf, ss);
13447 if (ret < 0)
13448 return;
13449
13450 if (!use_eof)
13451 copy_length -= ss;
13452 }
13453}
13454
13455static void *
13456nogvl_copy_stream_func(void *arg)
13457{
13458 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13459#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13460 int ret;
13461#endif
13462
13463#ifdef USE_COPY_FILE_RANGE
13464 ret = nogvl_copy_file_range(stp);
13465 if (ret != 0)
13466 goto finish; /* error or success */
13467#endif
13468
13469#ifdef HAVE_FCOPYFILE
13470 ret = nogvl_fcopyfile(stp);
13471 if (ret != 0)
13472 goto finish; /* error or success */
13473#endif
13474
13475#ifdef USE_SENDFILE
13476 ret = nogvl_copy_stream_sendfile(stp);
13477 if (ret != 0)
13478 goto finish; /* error or success */
13479#endif
13480
13481 nogvl_copy_stream_read_write(stp);
13482
13483#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13484 finish:
13485#endif
13486 return 0;
13487}
13488
13489static VALUE
13490copy_stream_fallback_body(VALUE arg)
13491{
13492 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13493 const int buflen = 16*1024;
13494 VALUE n;
13495 VALUE buf = rb_str_buf_new(buflen);
13496 rb_off_t rest = stp->copy_length;
13497 rb_off_t off = stp->src_offset;
13498 ID read_method = id_readpartial;
13499
13500 if (!stp->src_fptr) {
13501 if (!rb_respond_to(stp->src, read_method)) {
13502 read_method = id_read;
13503 }
13504 }
13505
13506 while (1) {
13507 long numwrote;
13508 long l;
13509 rb_str_make_independent(buf);
13510 if (stp->copy_length < (rb_off_t)0) {
13511 l = buflen;
13512 }
13513 else {
13514 if (rest == 0) {
13515 rb_str_resize(buf, 0);
13516 break;
13517 }
13518 l = buflen < rest ? buflen : (long)rest;
13519 }
13520 if (!stp->src_fptr) {
13521 VALUE rc = rb_funcall(stp->src, read_method, 2, INT2FIX(l), buf);
13522
13523 if (read_method == id_read && NIL_P(rc))
13524 break;
13525 }
13526 else {
13527 ssize_t ss;
13528 rb_str_resize(buf, buflen);
13529 ss = maygvl_copy_stream_read(1, stp, RSTRING_PTR(buf), l, off);
13530 rb_str_resize(buf, ss > 0 ? ss : 0);
13531 if (ss < 0)
13532 return Qnil;
13533 if (ss == 0)
13534 rb_eof_error();
13535 if (off >= (rb_off_t)0)
13536 off += ss;
13537 }
13538 n = rb_io_write(stp->dst, buf);
13539 numwrote = NUM2LONG(n);
13540 stp->total += numwrote;
13541 rest -= numwrote;
13542 if (read_method == id_read && RSTRING_LEN(buf) == 0) {
13543 break;
13544 }
13545 }
13546
13547 return Qnil;
13548}
13549
13550static VALUE
13551copy_stream_fallback(struct copy_stream_struct *stp)
13552{
13553 if (!stp->src_fptr && stp->src_offset >= (rb_off_t)0) {
13554 rb_raise(rb_eArgError, "cannot specify src_offset for non-IO");
13555 }
13556 rb_rescue2(copy_stream_fallback_body, (VALUE)stp,
13557 (VALUE (*) (VALUE, VALUE))0, (VALUE)0,
13558 rb_eEOFError, (VALUE)0);
13559 return Qnil;
13560}
13561
13562static VALUE
13563copy_stream_body(VALUE arg)
13564{
13565 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13566 VALUE src_io = stp->src, dst_io = stp->dst;
13567 const int common_oflags = 0
13568#ifdef O_NOCTTY
13569 | O_NOCTTY
13570#endif
13571 ;
13572
13573 stp->th = rb_thread_current();
13574
13575 stp->total = 0;
13576
13577 if (src_io == argf ||
13578 !(RB_TYPE_P(src_io, T_FILE) ||
13579 RB_TYPE_P(src_io, T_STRING) ||
13580 rb_respond_to(src_io, rb_intern("to_path")))) {
13581 stp->src_fptr = NULL;
13582 }
13583 else {
13584 int stat_ret;
13585 VALUE tmp_io = rb_io_check_io(src_io);
13586 if (!NIL_P(tmp_io)) {
13587 src_io = tmp_io;
13588 }
13589 else if (!RB_TYPE_P(src_io, T_FILE)) {
13590 VALUE args[2];
13591 FilePathValue(src_io);
13592 args[0] = src_io;
13593 args[1] = INT2NUM(O_RDONLY|common_oflags);
13594 src_io = rb_class_new_instance(2, args, rb_cFile);
13595 stp->src = src_io;
13596 stp->close_src = 1;
13597 }
13598 RB_IO_POINTER(src_io, stp->src_fptr);
13599 rb_io_check_byte_readable(stp->src_fptr);
13600
13601 stat_ret = fstat(stp->src_fptr->fd, &stp->src_stat);
13602 if (stat_ret < 0) {
13603 stp->syserr = "fstat";
13604 stp->error_no = errno;
13605 return Qnil;
13606 }
13607 }
13608
13609 if (dst_io == argf ||
13610 !(RB_TYPE_P(dst_io, T_FILE) ||
13611 RB_TYPE_P(dst_io, T_STRING) ||
13612 rb_respond_to(dst_io, rb_intern("to_path")))) {
13613 stp->dst_fptr = NULL;
13614 }
13615 else {
13616 int stat_ret;
13617 VALUE tmp_io = rb_io_check_io(dst_io);
13618 if (!NIL_P(tmp_io)) {
13619 dst_io = GetWriteIO(tmp_io);
13620 }
13621 else if (!RB_TYPE_P(dst_io, T_FILE)) {
13622 VALUE args[3];
13623 FilePathValue(dst_io);
13624 args[0] = dst_io;
13625 args[1] = INT2NUM(O_WRONLY|O_CREAT|O_TRUNC|common_oflags);
13626 args[2] = INT2FIX(0666);
13627 dst_io = rb_class_new_instance(3, args, rb_cFile);
13628 stp->dst = dst_io;
13629 stp->close_dst = 1;
13630 }
13631 else {
13632 dst_io = GetWriteIO(dst_io);
13633 stp->dst = dst_io;
13634 }
13635 RB_IO_POINTER(dst_io, stp->dst_fptr);
13636 rb_io_check_writable(stp->dst_fptr);
13637
13638 stat_ret = fstat(stp->dst_fptr->fd, &stp->dst_stat);
13639 if (stat_ret < 0) {
13640 stp->syserr = "fstat";
13641 stp->error_no = errno;
13642 return Qnil;
13643 }
13644 }
13645
13646#ifdef O_BINARY
13647 if (stp->src_fptr)
13648 SET_BINARY_MODE_WITH_SEEK_CUR(stp->src_fptr);
13649#endif
13650 if (stp->dst_fptr)
13651 io_ascii8bit_binmode(stp->dst_fptr);
13652
13653 if (stp->src_offset < (rb_off_t)0 && stp->src_fptr && stp->src_fptr->rbuf.len) {
13654 size_t len = stp->src_fptr->rbuf.len;
13655 VALUE str;
13656 if (stp->copy_length >= (rb_off_t)0 && stp->copy_length < (rb_off_t)len) {
13657 len = (size_t)stp->copy_length;
13658 }
13659 str = rb_str_buf_new(len);
13660 rb_str_resize(str,len);
13661 read_buffered_data(RSTRING_PTR(str), len, stp->src_fptr);
13662 if (stp->dst_fptr) { /* IO or filename */
13663 if (io_binwrite(RSTRING_PTR(str), RSTRING_LEN(str), stp->dst_fptr, 0) < 0)
13664 rb_sys_fail_on_write(stp->dst_fptr);
13665 }
13666 else /* others such as StringIO */
13667 rb_io_write(dst_io, str);
13668 rb_str_resize(str, 0);
13669 stp->total += len;
13670 if (stp->copy_length >= (rb_off_t)0)
13671 stp->copy_length -= len;
13672 }
13673
13674 if (stp->dst_fptr && io_fflush(stp->dst_fptr) < 0) {
13675 rb_raise(rb_eIOError, "flush failed");
13676 }
13677
13678 if (stp->copy_length == 0)
13679 return Qnil;
13680
13681 if (stp->src_fptr == NULL || stp->dst_fptr == NULL) {
13682 return copy_stream_fallback(stp);
13683 }
13684
13685 IO_WITHOUT_GVL(nogvl_copy_stream_func, stp);
13686 return Qnil;
13687}
13688
13689static VALUE
13690copy_stream_finalize(VALUE arg)
13691{
13692 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13693
13694#ifdef HAVE_FCOPYFILE
13695 if (stp->copyfile_state) {
13696 copyfile_state_free(stp->copyfile_state);
13697 }
13698#endif
13699
13700 if (stp->close_src) {
13701 rb_io_close_m(stp->src);
13702 }
13703 if (stp->close_dst) {
13704 rb_io_close_m(stp->dst);
13705 }
13706 if (stp->syserr) {
13707 rb_syserr_fail(stp->error_no, stp->syserr);
13708 }
13709 if (stp->notimp) {
13710 rb_raise(rb_eNotImpError, "%s() not implemented", stp->notimp);
13711 }
13712 return Qnil;
13713}
13714
13715/*
13716 * call-seq:
13717 * IO.copy_stream(src, dst, src_length = nil, src_offset = 0) -> integer
13718 *
13719 * Copies from the given +src+ to the given +dst+,
13720 * returning the number of bytes copied.
13721 *
13722 * - The given +src+ must be one of the following:
13723 *
13724 * - The path to a readable file, from which source data is to be read.
13725 * - An \IO-like object, opened for reading and capable of responding
13726 * to method +:readpartial+ or method +:read+.
13727 *
13728 * - The given +dst+ must be one of the following:
13729 *
13730 * - The path to a writable file, to which data is to be written.
13731 * - An \IO-like object, opened for writing and capable of responding
13732 * to method +:write+.
13733 *
13734 * The examples here use file <tt>t.txt</tt> as source:
13735 *
13736 * File.read('t.txt')
13737 * # => "First line\nSecond line\n\nThird line\nFourth line\n"
13738 * File.read('t.txt').size # => 47
13739 *
13740 * If only arguments +src+ and +dst+ are given,
13741 * the entire source stream is copied:
13742 *
13743 * # Paths.
13744 * IO.copy_stream('t.txt', 't.tmp') # => 47
13745 *
13746 * # IOs (recall that a File is also an IO).
13747 * src_io = File.open('t.txt', 'r') # => #<File:t.txt>
13748 * dst_io = File.open('t.tmp', 'w') # => #<File:t.tmp>
13749 * IO.copy_stream(src_io, dst_io) # => 47
13750 * src_io.close
13751 * dst_io.close
13752 *
13753 * With argument +src_length+ a non-negative integer,
13754 * no more than that many bytes are copied:
13755 *
13756 * IO.copy_stream('t.txt', 't.tmp', 10) # => 10
13757 * File.read('t.tmp') # => "First line"
13758 *
13759 * With argument +src_offset+ also given,
13760 * the source stream is read beginning at that offset:
13761 *
13762 * IO.copy_stream('t.txt', 't.tmp', 11, 11) # => 11
13763 * IO.read('t.tmp') # => "Second line"
13764 *
13765 */
13766static VALUE
13767rb_io_s_copy_stream(int argc, VALUE *argv, VALUE io)
13768{
13769 VALUE src, dst, length, src_offset;
13770 struct copy_stream_struct st;
13771
13772 MEMZERO(&st, struct copy_stream_struct, 1);
13773
13774 rb_scan_args(argc, argv, "22", &src, &dst, &length, &src_offset);
13775
13776 st.src = src;
13777 st.dst = dst;
13778
13779 st.src_fptr = NULL;
13780 st.dst_fptr = NULL;
13781
13782 if (NIL_P(length))
13783 st.copy_length = (rb_off_t)-1;
13784 else
13785 st.copy_length = NUM2OFFT(length);
13786
13787 if (NIL_P(src_offset))
13788 st.src_offset = (rb_off_t)-1;
13789 else
13790 st.src_offset = NUM2OFFT(src_offset);
13791
13792 rb_ensure(copy_stream_body, (VALUE)&st, copy_stream_finalize, (VALUE)&st);
13793
13794 return OFFT2NUM(st.total);
13795}
13796
13797/*
13798 * call-seq:
13799 * external_encoding -> encoding or nil
13800 *
13801 * Returns the Encoding object that represents the encoding of the stream,
13802 * or +nil+ if the stream is in write mode and no encoding is specified.
13803 *
13804 * See {Encodings}[rdoc-ref:File@Encodings].
13805 *
13806 */
13807
13808static VALUE
13809rb_io_external_encoding(VALUE io)
13810{
13811 rb_io_t *fptr = RFILE(rb_io_taint_check(io))->fptr;
13812
13813 if (fptr->encs.enc2) {
13814 return rb_enc_from_encoding(fptr->encs.enc2);
13815 }
13816 if (fptr->mode & FMODE_WRITABLE) {
13817 if (fptr->encs.enc)
13818 return rb_enc_from_encoding(fptr->encs.enc);
13819 return Qnil;
13820 }
13821 return rb_enc_from_encoding(io_read_encoding(fptr));
13822}
13823
13824/*
13825 * call-seq:
13826 * internal_encoding -> encoding or nil
13827 *
13828 * Returns the Encoding object that represents the encoding of the internal string,
13829 * if conversion is specified,
13830 * or +nil+ otherwise.
13831 *
13832 * See {Encodings}[rdoc-ref:File@Encodings].
13833 *
13834 */
13835
13836static VALUE
13837rb_io_internal_encoding(VALUE io)
13838{
13839 rb_io_t *fptr = RFILE(rb_io_taint_check(io))->fptr;
13840
13841 if (!fptr->encs.enc2) return Qnil;
13842 return rb_enc_from_encoding(io_read_encoding(fptr));
13843}
13844
13845/*
13846 * call-seq:
13847 * set_encoding(ext_enc) -> self
13848 * set_encoding(ext_enc, int_enc, **enc_opts) -> self
13849 * set_encoding('ext_enc:int_enc', **enc_opts) -> self
13850 *
13851 * See {Encodings}[rdoc-ref:File@Encodings].
13852 *
13853 * Argument +ext_enc+, if given, must be an Encoding object
13854 * or a String with the encoding name;
13855 * it is assigned as the encoding for the stream.
13856 *
13857 * Argument +int_enc+, if given, must be an Encoding object
13858 * or a String with the encoding name;
13859 * it is assigned as the encoding for the internal string.
13860 *
13861 * Argument <tt>'ext_enc:int_enc'</tt>, if given, is a string
13862 * containing two colon-separated encoding names;
13863 * corresponding Encoding objects are assigned as the external
13864 * and internal encodings for the stream.
13865 *
13866 * If the external encoding of a string is binary/ASCII-8BIT,
13867 * the internal encoding of the string is set to nil, since no
13868 * transcoding is needed.
13869 *
13870 * Optional keyword arguments +enc_opts+ specify
13871 * {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
13872 *
13873 */
13874
13875static VALUE
13876rb_io_set_encoding(int argc, VALUE *argv, VALUE io)
13877{
13878 rb_io_t *fptr;
13879 VALUE v1, v2, opt;
13880
13881 if (!RB_TYPE_P(io, T_FILE)) {
13882 return forward(io, id_set_encoding, argc, argv);
13883 }
13884
13885 argc = rb_scan_args(argc, argv, "11:", &v1, &v2, &opt);
13886 GetOpenFile(io, fptr);
13887 io_encoding_set(fptr, v1, v2, opt);
13888 return io;
13889}
13890
13891void
13892rb_stdio_set_default_encoding(void)
13893{
13894 VALUE val = Qnil;
13895
13896#ifdef _WIN32
13897 if (isatty(fileno(stdin))) {
13898 rb_encoding *external = rb_locale_encoding();
13899 rb_encoding *internal = rb_default_internal_encoding();
13900 if (!internal) internal = rb_default_external_encoding();
13901 io_encoding_set(RFILE(rb_stdin)->fptr,
13902 rb_enc_from_encoding(external),
13903 rb_enc_from_encoding(internal),
13904 Qnil);
13905 }
13906 else
13907#endif
13908 rb_io_set_encoding(1, &val, rb_stdin);
13909 rb_io_set_encoding(1, &val, rb_stdout);
13910 rb_io_set_encoding(1, &val, rb_stderr);
13911}
13912
13913static inline int
13914global_argf_p(VALUE arg)
13915{
13916 return arg == argf;
13917}
13918
13919typedef VALUE (*argf_encoding_func)(VALUE io);
13920
13921static VALUE
13922argf_encoding(VALUE argf, argf_encoding_func func)
13923{
13924 if (!RTEST(ARGF.current_file)) {
13925 return rb_enc_default_external();
13926 }
13927 return func(rb_io_check_io(ARGF.current_file));
13928}
13929
13930/*
13931 * call-seq:
13932 * ARGF.external_encoding -> encoding
13933 *
13934 * Returns the external encoding for files read from ARGF as an Encoding
13935 * object. The external encoding is the encoding of the text as stored in a
13936 * file. Contrast with ARGF.internal_encoding, which is the encoding used to
13937 * represent this text within Ruby.
13938 *
13939 * To set the external encoding use ARGF.set_encoding.
13940 *
13941 * For example:
13942 *
13943 * ARGF.external_encoding #=> #<Encoding:UTF-8>
13944 *
13945 */
13946static VALUE
13947argf_external_encoding(VALUE argf)
13948{
13949 return argf_encoding(argf, rb_io_external_encoding);
13950}
13951
13952/*
13953 * call-seq:
13954 * ARGF.internal_encoding -> encoding
13955 *
13956 * Returns the internal encoding for strings read from ARGF as an
13957 * Encoding object.
13958 *
13959 * If ARGF.set_encoding has been called with two encoding names, the second
13960 * is returned. Otherwise, if +Encoding.default_external+ has been set, that
13961 * value is returned. Failing that, if a default external encoding was
13962 * specified on the command-line, that value is used. If the encoding is
13963 * unknown, +nil+ is returned.
13964 */
13965static VALUE
13966argf_internal_encoding(VALUE argf)
13967{
13968 return argf_encoding(argf, rb_io_internal_encoding);
13969}
13970
13971/*
13972 * call-seq:
13973 * ARGF.set_encoding(ext_enc) -> ARGF
13974 * ARGF.set_encoding("ext_enc:int_enc") -> ARGF
13975 * ARGF.set_encoding(ext_enc, int_enc) -> ARGF
13976 * ARGF.set_encoding("ext_enc:int_enc", opt) -> ARGF
13977 * ARGF.set_encoding(ext_enc, int_enc, opt) -> ARGF
13978 *
13979 * If single argument is specified, strings read from ARGF are tagged with
13980 * the encoding specified.
13981 *
13982 * If two encoding names separated by a colon are given, e.g. "ascii:utf-8",
13983 * the read string is converted from the first encoding (external encoding)
13984 * to the second encoding (internal encoding), then tagged with the second
13985 * encoding.
13986 *
13987 * If two arguments are specified, they must be encoding objects or encoding
13988 * names. Again, the first specifies the external encoding; the second
13989 * specifies the internal encoding.
13990 *
13991 * If the external encoding and the internal encoding are specified, the
13992 * optional Hash argument can be used to adjust the conversion process. The
13993 * structure of this hash is explained in the String#encode documentation.
13994 *
13995 * For example:
13996 *
13997 * ARGF.set_encoding('ascii') # Tag the input as US-ASCII text
13998 * ARGF.set_encoding(Encoding::UTF_8) # Tag the input as UTF-8 text
13999 * ARGF.set_encoding('utf-8','ascii') # Transcode the input from US-ASCII
14000 * # to UTF-8.
14001 */
14002static VALUE
14003argf_set_encoding(int argc, VALUE *argv, VALUE argf)
14004{
14005 rb_io_t *fptr;
14006
14007 if (!next_argv()) {
14008 rb_raise(rb_eArgError, "no stream to set encoding");
14009 }
14010 rb_io_set_encoding(argc, argv, ARGF.current_file);
14011 GetOpenFile(ARGF.current_file, fptr);
14012 ARGF.encs = fptr->encs;
14013 RB_OBJ_WRITTEN(argf, Qundef, ARGF.encs.ecopts);
14014 return argf;
14015}
14016
14017/*
14018 * call-seq:
14019 * ARGF.tell -> Integer
14020 * ARGF.pos -> Integer
14021 *
14022 * Returns the current offset (in bytes) of the current file in ARGF.
14023 *
14024 * ARGF.pos #=> 0
14025 * ARGF.gets #=> "This is line one\n"
14026 * ARGF.pos #=> 17
14027 *
14028 */
14029static VALUE
14030argf_tell(VALUE argf)
14031{
14032 if (!next_argv()) {
14033 rb_raise(rb_eArgError, "no stream to tell");
14034 }
14035 ARGF_FORWARD(0, 0);
14036 return rb_io_tell(ARGF.current_file);
14037}
14038
14039/*
14040 * call-seq:
14041 * ARGF.seek(amount, whence=IO::SEEK_SET) -> 0
14042 *
14043 * Seeks to offset _amount_ (an Integer) in the ARGF stream according to
14044 * the value of _whence_. See IO#seek for further details.
14045 */
14046static VALUE
14047argf_seek_m(int argc, VALUE *argv, VALUE argf)
14048{
14049 if (!next_argv()) {
14050 rb_raise(rb_eArgError, "no stream to seek");
14051 }
14052 ARGF_FORWARD(argc, argv);
14053 return rb_io_seek_m(argc, argv, ARGF.current_file);
14054}
14055
14056/*
14057 * call-seq:
14058 * ARGF.pos = position -> Integer
14059 *
14060 * Seeks to the position given by _position_ (in bytes) in ARGF.
14061 *
14062 * For example:
14063 *
14064 * ARGF.pos = 17
14065 * ARGF.gets #=> "This is line two\n"
14066 */
14067static VALUE
14068argf_set_pos(VALUE argf, VALUE offset)
14069{
14070 if (!next_argv()) {
14071 rb_raise(rb_eArgError, "no stream to set position");
14072 }
14073 ARGF_FORWARD(1, &offset);
14074 return rb_io_set_pos(ARGF.current_file, offset);
14075}
14076
14077/*
14078 * call-seq:
14079 * ARGF.rewind -> 0
14080 *
14081 * Positions the current file to the beginning of input, resetting
14082 * ARGF.lineno to zero.
14083 *
14084 * ARGF.readline #=> "This is line one\n"
14085 * ARGF.rewind #=> 0
14086 * ARGF.lineno #=> 0
14087 * ARGF.readline #=> "This is line one\n"
14088 */
14089static VALUE
14090argf_rewind(VALUE argf)
14091{
14092 VALUE ret;
14093 int old_lineno;
14094
14095 if (!next_argv()) {
14096 rb_raise(rb_eArgError, "no stream to rewind");
14097 }
14098 ARGF_FORWARD(0, 0);
14099 old_lineno = RFILE(ARGF.current_file)->fptr->lineno;
14100 ret = rb_io_rewind(ARGF.current_file);
14101 if (!global_argf_p(argf)) {
14102 ARGF.last_lineno = ARGF.lineno -= old_lineno;
14103 }
14104 return ret;
14105}
14106
14107/*
14108 * call-seq:
14109 * ARGF.fileno -> integer
14110 * ARGF.to_i -> integer
14111 *
14112 * Returns an integer representing the numeric file descriptor for
14113 * the current file. Raises an ArgumentError if there isn't a current file.
14114 *
14115 * ARGF.fileno #=> 3
14116 */
14117static VALUE
14118argf_fileno(VALUE argf)
14119{
14120 if (!next_argv()) {
14121 rb_raise(rb_eArgError, "no stream");
14122 }
14123 ARGF_FORWARD(0, 0);
14124 return rb_io_fileno(ARGF.current_file);
14125}
14126
14127/*
14128 * call-seq:
14129 * ARGF.to_io -> IO
14130 *
14131 * Returns an IO object representing the current file. This will be a
14132 * File object unless the current file is a stream such as STDIN.
14133 *
14134 * For example:
14135 *
14136 * ARGF.to_io #=> #<File:glark.txt>
14137 * ARGF.to_io #=> #<IO:<STDIN>>
14138 */
14139static VALUE
14140argf_to_io(VALUE argf)
14141{
14142 next_argv();
14143 ARGF_FORWARD(0, 0);
14144 return ARGF.current_file;
14145}
14146
14147/*
14148 * call-seq:
14149 * ARGF.eof? -> true or false
14150 * ARGF.eof -> true or false
14151 *
14152 * Returns true if the current file in ARGF is at end of file, i.e. it has
14153 * no data to read. The stream must be opened for reading or an IOError
14154 * will be raised.
14155 *
14156 * $ echo "eof" | ruby argf.rb
14157 *
14158 * ARGF.eof? #=> false
14159 * 3.times { ARGF.readchar }
14160 * ARGF.eof? #=> false
14161 * ARGF.readchar #=> "\n"
14162 * ARGF.eof? #=> true
14163 */
14164
14165static VALUE
14166argf_eof(VALUE argf)
14167{
14168 next_argv();
14169 if (RTEST(ARGF.current_file)) {
14170 if (ARGF.init_p == 0) return Qtrue;
14171 next_argv();
14172 ARGF_FORWARD(0, 0);
14173 if (rb_io_eof(ARGF.current_file)) {
14174 return Qtrue;
14175 }
14176 }
14177 return Qfalse;
14178}
14179
14180/*
14181 * call-seq:
14182 * ARGF.read([length [, outbuf]]) -> string, outbuf, or nil
14183 *
14184 * Reads _length_ bytes from ARGF. The files named on the command line
14185 * are concatenated and treated as a single file by this method, so when
14186 * called without arguments the contents of this pseudo file are returned in
14187 * their entirety.
14188 *
14189 * _length_ must be a non-negative integer or +nil+.
14190 *
14191 * If _length_ is a positive integer, +read+ tries to read
14192 * _length_ bytes without any conversion (binary mode).
14193 * It returns +nil+ if an EOF is encountered before anything can be read.
14194 * Fewer than _length_ bytes are returned if an EOF is encountered during
14195 * the read.
14196 * In the case of an integer _length_, the resulting string is always
14197 * in ASCII-8BIT encoding.
14198 *
14199 * If _length_ is omitted or is +nil+, it reads until EOF
14200 * and the encoding conversion is applied, if applicable.
14201 * A string is returned even if EOF is encountered before any data is read.
14202 *
14203 * If _length_ is zero, it returns an empty string (<code>""</code>).
14204 *
14205 * If the optional _outbuf_ argument is present,
14206 * it must reference a String, which will receive the data.
14207 * The _outbuf_ will contain only the received data after the method call
14208 * even if it is not empty at the beginning.
14209 *
14210 * For example:
14211 *
14212 * $ echo "small" > small.txt
14213 * $ echo "large" > large.txt
14214 * $ ./glark.rb small.txt large.txt
14215 *
14216 * ARGF.read #=> "small\nlarge"
14217 * ARGF.read(200) #=> "small\nlarge"
14218 * ARGF.read(2) #=> "sm"
14219 * ARGF.read(0) #=> ""
14220 *
14221 * Note that this method behaves like the fread() function in C.
14222 * This means it retries to invoke read(2) system calls to read data
14223 * with the specified length.
14224 * If you need the behavior like a single read(2) system call,
14225 * consider ARGF#readpartial or ARGF#read_nonblock.
14226 */
14227
14228static VALUE
14229argf_read(int argc, VALUE *argv, VALUE argf)
14230{
14231 VALUE tmp, str, length;
14232 long len = 0;
14233
14234 rb_scan_args(argc, argv, "02", &length, &str);
14235 if (!NIL_P(length)) {
14236 len = NUM2LONG(argv[0]);
14237 }
14238 if (!NIL_P(str)) {
14239 StringValue(str);
14240 rb_str_resize(str,0);
14241 argv[1] = Qnil;
14242 }
14243
14244 retry:
14245 if (!next_argv()) {
14246 return str;
14247 }
14248 if (ARGF_GENERIC_INPUT_P()) {
14249 tmp = argf_forward(argc, argv, argf);
14250 }
14251 else {
14252 tmp = io_read(argc, argv, ARGF.current_file);
14253 }
14254 if (NIL_P(str)) str = tmp;
14255 else if (!NIL_P(tmp)) rb_str_append(str, tmp);
14256 if (NIL_P(tmp) || NIL_P(length)) {
14257 if (ARGF.next_p != -1) {
14258 argf_close(argf);
14259 ARGF.next_p = 1;
14260 goto retry;
14261 }
14262 }
14263 else if (argc >= 1) {
14264 long slen = RSTRING_LEN(str);
14265 if (slen < len) {
14266 argv[0] = LONG2NUM(len - slen);
14267 goto retry;
14268 }
14269 }
14270 return str;
14271}
14272
14274 int argc;
14275 VALUE *argv;
14276 VALUE argf;
14277};
14278
14279static VALUE
14280argf_forward_call(VALUE arg)
14281{
14282 struct argf_call_arg *p = (struct argf_call_arg *)arg;
14283 argf_forward(p->argc, p->argv, p->argf);
14284 return Qnil;
14285}
14286
14287static VALUE argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts,
14288 int nonblock);
14289
14290/*
14291 * call-seq:
14292 * ARGF.readpartial(maxlen) -> string
14293 * ARGF.readpartial(maxlen, outbuf) -> outbuf
14294 *
14295 * Reads at most _maxlen_ bytes from the ARGF stream.
14296 *
14297 * If the optional _outbuf_ argument is present,
14298 * it must reference a String, which will receive the data.
14299 * The _outbuf_ will contain only the received data after the method call
14300 * even if it is not empty at the beginning.
14301 *
14302 * It raises EOFError on end of ARGF stream.
14303 * Since ARGF stream is a concatenation of multiple files,
14304 * internally EOF is occur for each file.
14305 * ARGF.readpartial returns empty strings for EOFs except the last one and
14306 * raises EOFError for the last one.
14307 *
14308 */
14309
14310static VALUE
14311argf_readpartial(int argc, VALUE *argv, VALUE argf)
14312{
14313 return argf_getpartial(argc, argv, argf, Qnil, 0);
14314}
14315
14316/*
14317 * call-seq:
14318 * ARGF.read_nonblock(maxlen[, options]) -> string
14319 * ARGF.read_nonblock(maxlen, outbuf[, options]) -> outbuf
14320 *
14321 * Reads at most _maxlen_ bytes from the ARGF stream in non-blocking mode.
14322 */
14323
14324static VALUE
14325argf_read_nonblock(int argc, VALUE *argv, VALUE argf)
14326{
14327 VALUE opts;
14328
14329 rb_scan_args(argc, argv, "11:", NULL, NULL, &opts);
14330
14331 if (!NIL_P(opts))
14332 argc--;
14333
14334 return argf_getpartial(argc, argv, argf, opts, 1);
14335}
14336
14337static VALUE
14338argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts, int nonblock)
14339{
14340 VALUE tmp, str, length;
14341 int no_exception;
14342
14343 rb_scan_args(argc, argv, "11", &length, &str);
14344 if (!NIL_P(str)) {
14345 StringValue(str);
14346 argv[1] = str;
14347 }
14348 no_exception = no_exception_p(opts);
14349
14350 if (!next_argv()) {
14351 if (!NIL_P(str)) {
14352 rb_str_resize(str, 0);
14353 }
14354 rb_eof_error();
14355 }
14356 if (ARGF_GENERIC_INPUT_P()) {
14357 VALUE (*const rescue_does_nothing)(VALUE, VALUE) = 0;
14358 struct argf_call_arg arg;
14359 arg.argc = argc;
14360 arg.argv = argv;
14361 arg.argf = argf;
14362 tmp = rb_rescue2(argf_forward_call, (VALUE)&arg,
14363 rescue_does_nothing, Qnil, rb_eEOFError, (VALUE)0);
14364 }
14365 else {
14366 tmp = io_getpartial(argc, argv, ARGF.current_file, no_exception, nonblock);
14367 }
14368 if (NIL_P(tmp)) {
14369 if (ARGF.next_p == -1) {
14370 return io_nonblock_eof(no_exception);
14371 }
14372 argf_close(argf);
14373 ARGF.next_p = 1;
14374 if (RARRAY_LEN(ARGF.argv) == 0) {
14375 return io_nonblock_eof(no_exception);
14376 }
14377 if (NIL_P(str))
14378 str = rb_str_new(NULL, 0);
14379 return str;
14380 }
14381 return tmp;
14382}
14383
14384/*
14385 * call-seq:
14386 * ARGF.getc -> String or nil
14387 *
14388 * Reads the next character from ARGF and returns it as a String. Returns
14389 * +nil+ at the end of the stream.
14390 *
14391 * ARGF treats the files named on the command line as a single file created
14392 * by concatenating their contents. After returning the last character of the
14393 * first file, it returns the first character of the second file, and so on.
14394 *
14395 * For example:
14396 *
14397 * $ echo "foo" > file
14398 * $ ruby argf.rb file
14399 *
14400 * ARGF.getc #=> "f"
14401 * ARGF.getc #=> "o"
14402 * ARGF.getc #=> "o"
14403 * ARGF.getc #=> "\n"
14404 * ARGF.getc #=> nil
14405 * ARGF.getc #=> nil
14406 */
14407static VALUE
14408argf_getc(VALUE argf)
14409{
14410 VALUE ch;
14411
14412 retry:
14413 if (!next_argv()) return Qnil;
14414 if (ARGF_GENERIC_INPUT_P()) {
14415 ch = forward_current(rb_intern("getc"), 0, 0);
14416 }
14417 else {
14418 ch = rb_io_getc(ARGF.current_file);
14419 }
14420 if (NIL_P(ch) && ARGF.next_p != -1) {
14421 argf_close(argf);
14422 ARGF.next_p = 1;
14423 goto retry;
14424 }
14425
14426 return ch;
14427}
14428
14429/*
14430 * call-seq:
14431 * ARGF.getbyte -> Integer or nil
14432 *
14433 * Gets the next 8-bit byte (0..255) from ARGF. Returns +nil+ if called at
14434 * the end of the stream.
14435 *
14436 * For example:
14437 *
14438 * $ echo "foo" > file
14439 * $ ruby argf.rb file
14440 *
14441 * ARGF.getbyte #=> 102
14442 * ARGF.getbyte #=> 111
14443 * ARGF.getbyte #=> 111
14444 * ARGF.getbyte #=> 10
14445 * ARGF.getbyte #=> nil
14446 */
14447static VALUE
14448argf_getbyte(VALUE argf)
14449{
14450 VALUE ch;
14451
14452 retry:
14453 if (!next_argv()) return Qnil;
14454 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
14455 ch = forward_current(rb_intern("getbyte"), 0, 0);
14456 }
14457 else {
14458 ch = rb_io_getbyte(ARGF.current_file);
14459 }
14460 if (NIL_P(ch) && ARGF.next_p != -1) {
14461 argf_close(argf);
14462 ARGF.next_p = 1;
14463 goto retry;
14464 }
14465
14466 return ch;
14467}
14468
14469/*
14470 * call-seq:
14471 * ARGF.readchar -> String or nil
14472 *
14473 * Reads the next character from ARGF and returns it as a String. Raises
14474 * an EOFError after the last character of the last file has been read.
14475 *
14476 * For example:
14477 *
14478 * $ echo "foo" > file
14479 * $ ruby argf.rb file
14480 *
14481 * ARGF.readchar #=> "f"
14482 * ARGF.readchar #=> "o"
14483 * ARGF.readchar #=> "o"
14484 * ARGF.readchar #=> "\n"
14485 * ARGF.readchar #=> end of file reached (EOFError)
14486 */
14487static VALUE
14488argf_readchar(VALUE argf)
14489{
14490 VALUE ch;
14491
14492 retry:
14493 if (!next_argv()) rb_eof_error();
14494 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
14495 ch = forward_current(rb_intern("getc"), 0, 0);
14496 }
14497 else {
14498 ch = rb_io_getc(ARGF.current_file);
14499 }
14500 if (NIL_P(ch) && ARGF.next_p != -1) {
14501 argf_close(argf);
14502 ARGF.next_p = 1;
14503 goto retry;
14504 }
14505
14506 return ch;
14507}
14508
14509/*
14510 * call-seq:
14511 * ARGF.readbyte -> Integer
14512 *
14513 * Reads the next 8-bit byte from ARGF and returns it as an Integer. Raises
14514 * an EOFError after the last byte of the last file has been read.
14515 *
14516 * For example:
14517 *
14518 * $ echo "foo" > file
14519 * $ ruby argf.rb file
14520 *
14521 * ARGF.readbyte #=> 102
14522 * ARGF.readbyte #=> 111
14523 * ARGF.readbyte #=> 111
14524 * ARGF.readbyte #=> 10
14525 * ARGF.readbyte #=> end of file reached (EOFError)
14526 */
14527static VALUE
14528argf_readbyte(VALUE argf)
14529{
14530 VALUE c;
14531
14532 NEXT_ARGF_FORWARD(0, 0);
14533 c = argf_getbyte(argf);
14534 if (NIL_P(c)) {
14535 rb_eof_error();
14536 }
14537 return c;
14538}
14539
14540#define FOREACH_ARGF() while (next_argv())
14541
14542static VALUE
14543argf_block_call_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
14544{
14545 const VALUE current = ARGF.current_file;
14546 rb_yield_values2(argc, argv);
14547 if (ARGF.init_p == -1 || current != ARGF.current_file) {
14549 }
14550 return Qnil;
14551}
14552
14553#define ARGF_block_call(mid, argc, argv, func, argf) \
14554 rb_block_call_kw(ARGF.current_file, mid, argc, argv, \
14555 func, argf, rb_keyword_given_p())
14556
14557static void
14558argf_block_call(ID mid, int argc, VALUE *argv, VALUE argf)
14559{
14560 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_i, argf);
14561 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14562}
14563
14564static VALUE
14565argf_block_call_line_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
14566{
14567 if (!global_argf_p(argf)) {
14568 ARGF.last_lineno = ++ARGF.lineno;
14569 }
14570 return argf_block_call_i(i, argf, argc, argv, blockarg);
14571}
14572
14573static void
14574argf_block_call_line(ID mid, int argc, VALUE *argv, VALUE argf)
14575{
14576 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_line_i, argf);
14577 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14578}
14579
14580/*
14581 * call-seq:
14582 * ARGF.each(sep=$/) {|line| block } -> ARGF
14583 * ARGF.each(sep=$/, limit) {|line| block } -> ARGF
14584 * ARGF.each(...) -> an_enumerator
14585 *
14586 * ARGF.each_line(sep=$/) {|line| block } -> ARGF
14587 * ARGF.each_line(sep=$/, limit) {|line| block } -> ARGF
14588 * ARGF.each_line(...) -> an_enumerator
14589 *
14590 * Returns an enumerator which iterates over each line (separated by _sep_,
14591 * which defaults to your platform's newline character) of each file in
14592 * +ARGV+. If a block is supplied, each line in turn will be yielded to the
14593 * block, otherwise an enumerator is returned.
14594 * The optional _limit_ argument is an Integer specifying the maximum
14595 * length of each line; longer lines will be split according to this limit.
14596 *
14597 * This method allows you to treat the files supplied on the command line as
14598 * a single file consisting of the concatenation of each named file. After
14599 * the last line of the first file has been returned, the first line of the
14600 * second file is returned. The ARGF.filename and ARGF.lineno methods can be
14601 * used to determine the filename of the current line and line number of the
14602 * whole input, respectively.
14603 *
14604 * For example, the following code prints out each line of each named file
14605 * prefixed with its line number, displaying the filename once per file:
14606 *
14607 * ARGF.each_line do |line|
14608 * puts ARGF.filename if ARGF.file.lineno == 1
14609 * puts "#{ARGF.file.lineno}: #{line}"
14610 * end
14611 *
14612 * While the following code prints only the first file's name at first, and
14613 * the contents with line number counted through all named files.
14614 *
14615 * ARGF.each_line do |line|
14616 * puts ARGF.filename if ARGF.lineno == 1
14617 * puts "#{ARGF.lineno}: #{line}"
14618 * end
14619 */
14620static VALUE
14621argf_each_line(int argc, VALUE *argv, VALUE argf)
14622{
14623 RETURN_ENUMERATOR(argf, argc, argv);
14624 FOREACH_ARGF() {
14625 argf_block_call_line(rb_intern("each_line"), argc, argv, argf);
14626 }
14627 return argf;
14628}
14629
14630/*
14631 * call-seq:
14632 * ARGF.each_byte {|byte| block } -> ARGF
14633 * ARGF.each_byte -> an_enumerator
14634 *
14635 * Iterates over each byte of each file in +ARGV+.
14636 * A byte is returned as an Integer in the range 0..255.
14637 *
14638 * This method allows you to treat the files supplied on the command line as
14639 * a single file consisting of the concatenation of each named file. After
14640 * the last byte of the first file has been returned, the first byte of the
14641 * second file is returned. The ARGF.filename method can be used to
14642 * determine the filename of the current byte.
14643 *
14644 * If no block is given, an enumerator is returned instead.
14645 *
14646 * For example:
14647 *
14648 * ARGF.bytes.to_a #=> [35, 32, ... 95, 10]
14649 *
14650 */
14651static VALUE
14652argf_each_byte(VALUE argf)
14653{
14654 RETURN_ENUMERATOR(argf, 0, 0);
14655 FOREACH_ARGF() {
14656 argf_block_call(rb_intern("each_byte"), 0, 0, argf);
14657 }
14658 return argf;
14659}
14660
14661/*
14662 * call-seq:
14663 * ARGF.each_char {|char| block } -> ARGF
14664 * ARGF.each_char -> an_enumerator
14665 *
14666 * Iterates over each character of each file in ARGF.
14667 *
14668 * This method allows you to treat the files supplied on the command line as
14669 * a single file consisting of the concatenation of each named file. After
14670 * the last character of the first file has been returned, the first
14671 * character of the second file is returned. The ARGF.filename method can
14672 * be used to determine the name of the file in which the current character
14673 * appears.
14674 *
14675 * If no block is given, an enumerator is returned instead.
14676 */
14677static VALUE
14678argf_each_char(VALUE argf)
14679{
14680 RETURN_ENUMERATOR(argf, 0, 0);
14681 FOREACH_ARGF() {
14682 argf_block_call(rb_intern("each_char"), 0, 0, argf);
14683 }
14684 return argf;
14685}
14686
14687/*
14688 * call-seq:
14689 * ARGF.each_codepoint {|codepoint| block } -> ARGF
14690 * ARGF.each_codepoint -> an_enumerator
14691 *
14692 * Iterates over each codepoint of each file in ARGF.
14693 *
14694 * This method allows you to treat the files supplied on the command line as
14695 * a single file consisting of the concatenation of each named file. After
14696 * the last codepoint of the first file has been returned, the first
14697 * codepoint of the second file is returned. The ARGF.filename method can
14698 * be used to determine the name of the file in which the current codepoint
14699 * appears.
14700 *
14701 * If no block is given, an enumerator is returned instead.
14702 */
14703static VALUE
14704argf_each_codepoint(VALUE argf)
14705{
14706 RETURN_ENUMERATOR(argf, 0, 0);
14707 FOREACH_ARGF() {
14708 argf_block_call(rb_intern("each_codepoint"), 0, 0, argf);
14709 }
14710 return argf;
14711}
14712
14713/*
14714 * call-seq:
14715 * ARGF.filename -> String
14716 * ARGF.path -> String
14717 *
14718 * Returns the current filename. "-" is returned when the current file is
14719 * STDIN.
14720 *
14721 * For example:
14722 *
14723 * $ echo "foo" > foo
14724 * $ echo "bar" > bar
14725 * $ echo "glark" > glark
14726 *
14727 * $ ruby argf.rb foo bar glark
14728 *
14729 * ARGF.filename #=> "foo"
14730 * ARGF.read(5) #=> "foo\nb"
14731 * ARGF.filename #=> "bar"
14732 * ARGF.skip
14733 * ARGF.filename #=> "glark"
14734 */
14735static VALUE
14736argf_filename(VALUE argf)
14737{
14738 next_argv();
14739 return ARGF.filename;
14740}
14741
14742static VALUE
14743argf_filename_getter(ID id, VALUE *var)
14744{
14745 return argf_filename(*var);
14746}
14747
14748/*
14749 * call-seq:
14750 * ARGF.file -> IO or File object
14751 *
14752 * Returns the current file as an IO or File object.
14753 * <code>$stdin</code> is returned when the current file is STDIN.
14754 *
14755 * For example:
14756 *
14757 * $ echo "foo" > foo
14758 * $ echo "bar" > bar
14759 *
14760 * $ ruby argf.rb foo bar
14761 *
14762 * ARGF.file #=> #<File:foo>
14763 * ARGF.read(5) #=> "foo\nb"
14764 * ARGF.file #=> #<File:bar>
14765 */
14766static VALUE
14767argf_file(VALUE argf)
14768{
14769 next_argv();
14770 return ARGF.current_file;
14771}
14772
14773/*
14774 * call-seq:
14775 * ARGF.binmode -> ARGF
14776 *
14777 * Puts ARGF into binary mode. Once a stream is in binary mode, it cannot
14778 * be reset to non-binary mode. This option has the following effects:
14779 *
14780 * * Newline conversion is disabled.
14781 * * Encoding conversion is disabled.
14782 * * Content is treated as ASCII-8BIT.
14783 */
14784static VALUE
14785argf_binmode_m(VALUE argf)
14786{
14787 ARGF.binmode = 1;
14788 next_argv();
14789 ARGF_FORWARD(0, 0);
14790 rb_io_ascii8bit_binmode(ARGF.current_file);
14791 return argf;
14792}
14793
14794/*
14795 * call-seq:
14796 * ARGF.binmode? -> true or false
14797 *
14798 * Returns true if ARGF is being read in binary mode; false otherwise.
14799 * To enable binary mode use ARGF.binmode.
14800 *
14801 * For example:
14802 *
14803 * ARGF.binmode? #=> false
14804 * ARGF.binmode
14805 * ARGF.binmode? #=> true
14806 */
14807static VALUE
14808argf_binmode_p(VALUE argf)
14809{
14810 return RBOOL(ARGF.binmode);
14811}
14812
14813/*
14814 * call-seq:
14815 * ARGF.skip -> ARGF
14816 *
14817 * Sets the current file to the next file in ARGV. If there aren't any more
14818 * files it has no effect.
14819 *
14820 * For example:
14821 *
14822 * $ ruby argf.rb foo bar
14823 * ARGF.filename #=> "foo"
14824 * ARGF.skip
14825 * ARGF.filename #=> "bar"
14826 */
14827static VALUE
14828argf_skip(VALUE argf)
14829{
14830 if (ARGF.init_p && ARGF.next_p == 0) {
14831 argf_close(argf);
14832 ARGF.next_p = 1;
14833 }
14834 return argf;
14835}
14836
14837/*
14838 * call-seq:
14839 * ARGF.close -> ARGF
14840 *
14841 * Closes the current file and skips to the next file in ARGV. If there are
14842 * no more files to open, just closes the current file. STDIN will not be
14843 * closed.
14844 *
14845 * For example:
14846 *
14847 * $ ruby argf.rb foo bar
14848 *
14849 * ARGF.filename #=> "foo"
14850 * ARGF.close
14851 * ARGF.filename #=> "bar"
14852 * ARGF.close
14853 */
14854static VALUE
14855argf_close_m(VALUE argf)
14856{
14857 next_argv();
14858 argf_close(argf);
14859 if (ARGF.next_p != -1) {
14860 ARGF.next_p = 1;
14861 }
14862 ARGF.lineno = 0;
14863 return argf;
14864}
14865
14866/*
14867 * call-seq:
14868 * ARGF.closed? -> true or false
14869 *
14870 * Returns _true_ if the current file has been closed; _false_ otherwise. Use
14871 * ARGF.close to actually close the current file.
14872 */
14873static VALUE
14874argf_closed(VALUE argf)
14875{
14876 next_argv();
14877 ARGF_FORWARD(0, 0);
14878 return rb_io_closed_p(ARGF.current_file);
14879}
14880
14881/*
14882 * call-seq:
14883 * ARGF.to_s -> String
14884 *
14885 * Returns "ARGF".
14886 */
14887static VALUE
14888argf_to_s(VALUE argf)
14889{
14890 return rb_str_new2("ARGF");
14891}
14892
14893/*
14894 * call-seq:
14895 * ARGF.inplace_mode -> String
14896 *
14897 * Returns the file extension appended to the names of backup copies of
14898 * modified files under in-place edit mode. This value can be set using
14899 * ARGF.inplace_mode= or passing the +-i+ switch to the Ruby binary.
14900 */
14901static VALUE
14902argf_inplace_mode_get(VALUE argf)
14903{
14904 if (!ARGF.inplace) return Qnil;
14905 if (NIL_P(ARGF.inplace)) return rb_str_new(0, 0);
14906 return rb_str_dup(ARGF.inplace);
14907}
14908
14909static VALUE
14910opt_i_get(ID id, VALUE *var)
14911{
14912 return argf_inplace_mode_get(*var);
14913}
14914
14915/*
14916 * call-seq:
14917 * ARGF.inplace_mode = ext -> ARGF
14918 *
14919 * Sets the filename extension for in-place editing mode to the given String.
14920 * The backup copy of each file being edited has this value appended to its
14921 * filename.
14922 *
14923 * For example:
14924 *
14925 * $ ruby argf.rb file.txt
14926 *
14927 * ARGF.inplace_mode = '.bak'
14928 * ARGF.each_line do |line|
14929 * print line.sub("foo","bar")
14930 * end
14931 *
14932 * First, _file.txt.bak_ is created as a backup copy of _file.txt_.
14933 * Then, each line of _file.txt_ has the first occurrence of "foo" replaced with
14934 * "bar".
14935 */
14936static VALUE
14937argf_inplace_mode_set(VALUE argf, VALUE val)
14938{
14939 if (!RTEST(val)) {
14940 ARGF.inplace = Qfalse;
14941 }
14942 else if (StringValueCStr(val), !RSTRING_LEN(val)) {
14943 ARGF.inplace = Qnil;
14944 }
14945 else {
14946 ARGF_SET(inplace, rb_str_new_frozen(val));
14947 }
14948 return argf;
14949}
14950
14951static void
14952opt_i_set(VALUE val, ID id, VALUE *var)
14953{
14954 argf_inplace_mode_set(*var, val);
14955}
14956
14957void
14958ruby_set_inplace_mode(const char *suffix)
14959{
14960 ARGF_SET(inplace, !suffix ? Qfalse : !*suffix ? Qnil : rb_str_new(suffix, strlen(suffix)));
14961}
14962
14963/*
14964 * call-seq:
14965 * ARGF.argv -> ARGV
14966 *
14967 * Returns the +ARGV+ array, which contains the arguments passed to your
14968 * script, one per element.
14969 *
14970 * For example:
14971 *
14972 * $ ruby argf.rb -v glark.txt
14973 *
14974 * ARGF.argv #=> ["-v", "glark.txt"]
14975 *
14976 */
14977static VALUE
14978argf_argv(VALUE argf)
14979{
14980 return ARGF.argv;
14981}
14982
14983static VALUE
14984argf_argv_getter(ID id, VALUE *var)
14985{
14986 return argf_argv(*var);
14987}
14988
14989VALUE
14991{
14992 return ARGF.argv;
14993}
14994
14995/*
14996 * call-seq:
14997 * ARGF.to_write_io -> io
14998 *
14999 * Returns IO instance tied to _ARGF_ for writing if inplace mode is
15000 * enabled.
15001 */
15002static VALUE
15003argf_write_io(VALUE argf)
15004{
15005 if (!RTEST(ARGF.current_file)) {
15006 rb_raise(rb_eIOError, "not opened for writing");
15007 }
15008 return GetWriteIO(ARGF.current_file);
15009}
15010
15011/*
15012 * call-seq:
15013 * ARGF.write(*objects) -> integer
15014 *
15015 * Writes each of the given +objects+ if inplace mode.
15016 */
15017static VALUE
15018argf_write(int argc, VALUE *argv, VALUE argf)
15019{
15020 return rb_io_writev(argf_write_io(argf), argc, argv);
15021}
15022
15023void
15024rb_readwrite_sys_fail(enum rb_io_wait_readwrite waiting, const char *mesg)
15025{
15026 rb_readwrite_syserr_fail(waiting, errno, mesg);
15027}
15028
15029void
15030rb_readwrite_syserr_fail(enum rb_io_wait_readwrite waiting, int n, const char *mesg)
15031{
15032 VALUE arg, c = Qnil;
15033 arg = mesg ? rb_str_new2(mesg) : Qnil;
15034 switch (waiting) {
15035 case RB_IO_WAIT_WRITABLE:
15036 switch (n) {
15037 case EAGAIN:
15038 c = rb_eEAGAINWaitWritable;
15039 break;
15040#if EAGAIN != EWOULDBLOCK
15041 case EWOULDBLOCK:
15042 c = rb_eEWOULDBLOCKWaitWritable;
15043 break;
15044#endif
15045 case EINPROGRESS:
15046 c = rb_eEINPROGRESSWaitWritable;
15047 break;
15048 default:
15050 }
15051 break;
15052 case RB_IO_WAIT_READABLE:
15053 switch (n) {
15054 case EAGAIN:
15055 c = rb_eEAGAINWaitReadable;
15056 break;
15057#if EAGAIN != EWOULDBLOCK
15058 case EWOULDBLOCK:
15059 c = rb_eEWOULDBLOCKWaitReadable;
15060 break;
15061#endif
15062 case EINPROGRESS:
15063 c = rb_eEINPROGRESSWaitReadable;
15064 break;
15065 default:
15067 }
15068 break;
15069 default:
15070 rb_bug("invalid read/write type passed to rb_readwrite_sys_fail: %d", waiting);
15071 }
15073}
15074
15075static VALUE
15076get_LAST_READ_LINE(ID _x, VALUE *_y)
15077{
15078 return rb_lastline_get();
15079}
15080
15081static void
15082set_LAST_READ_LINE(VALUE val, ID _x, VALUE *_y)
15083{
15084 rb_lastline_set(val);
15085}
15086
15087/*
15088 * Document-class: IOError
15089 *
15090 * Raised when an IO operation fails.
15091 *
15092 * File.open("/etc/hosts") {|f| f << "example"}
15093 * #=> IOError: not opened for writing
15094 *
15095 * File.open("/etc/hosts") {|f| f.close; f.read }
15096 * #=> IOError: closed stream
15097 *
15098 * Note that some IO failures raise <code>SystemCallError</code>s
15099 * and these are not subclasses of IOError:
15100 *
15101 * File.open("does/not/exist")
15102 * #=> Errno::ENOENT: No such file or directory - does/not/exist
15103 */
15104
15105/*
15106 * Document-class: EOFError
15107 *
15108 * Raised by some IO operations when reaching the end of file. Many IO
15109 * methods exist in two forms,
15110 *
15111 * one that returns +nil+ when the end of file is reached, the other
15112 * raises EOFError.
15113 *
15114 * EOFError is a subclass of IOError.
15115 *
15116 * file = File.open("/etc/hosts")
15117 * file.read
15118 * file.gets #=> nil
15119 * file.readline #=> EOFError: end of file reached
15120 * file.close
15121 */
15122
15123/*
15124 * Document-class: ARGF
15125 *
15126 * == \ARGF and +ARGV+
15127 *
15128 * The \ARGF object works with the array at global variable +ARGV+
15129 * to make <tt>$stdin</tt> and file streams available in the Ruby program:
15130 *
15131 * - **ARGV** may be thought of as the <b>argument vector</b> array.
15132 *
15133 * Initially, it contains the command-line arguments and options
15134 * that are passed to the Ruby program;
15135 * the program can modify that array as it likes.
15136 *
15137 * - **ARGF** may be thought of as the <b>argument files</b> object.
15138 *
15139 * It can access file streams and/or the <tt>$stdin</tt> stream,
15140 * based on what it finds in +ARGV+.
15141 * This provides a convenient way for the command line
15142 * to specify streams for a Ruby program to read.
15143 *
15144 * == Reading
15145 *
15146 * \ARGF may read from _source_ streams,
15147 * which at any particular time are determined by the content of +ARGV+.
15148 *
15149 * === Simplest Case
15150 *
15151 * When the <i>very first</i> \ARGF read occurs with an empty +ARGV+ (<tt>[]</tt>),
15152 * the source is <tt>$stdin</tt>:
15153 *
15154 * - \File +t.rb+:
15155 *
15156 * p ['ARGV', ARGV]
15157 * p ['ARGF.read', ARGF.read]
15158 *
15159 * - Commands and outputs
15160 * (see below for the content of files +foo.txt+ and +bar.txt+):
15161 *
15162 * $ echo "Open the pod bay doors, Hal." | ruby t.rb
15163 * ["ARGV", []]
15164 * ["ARGF.read", "Open the pod bay doors, Hal.\n"]
15165 *
15166 * $ cat foo.txt bar.txt | ruby t.rb
15167 * ["ARGV", []]
15168 * ["ARGF.read", "Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"]
15169 *
15170 * === About the Examples
15171 *
15172 * Many examples here assume the existence of files +foo.txt+ and +bar.txt+:
15173 *
15174 * $ cat foo.txt
15175 * Foo 0
15176 * Foo 1
15177 * $ cat bar.txt
15178 * Bar 0
15179 * Bar 1
15180 * Bar 2
15181 * Bar 3
15182 *
15183 * === Sources in +ARGV+
15184 *
15185 * For any \ARGF read _except_ the {simplest case}[rdoc-ref:ARGF@Simplest+Case]
15186 * (that is, _except_ for the <i>very first</i> \ARGF read with an empty +ARGV+),
15187 * the sources are found in +ARGV+.
15188 *
15189 * \ARGF assumes that each element in array +ARGV+ is a potential source,
15190 * and is one of:
15191 *
15192 * - The string path to a file that may be opened as a stream.
15193 * - The character <tt>'-'</tt>, meaning stream <tt>$stdin</tt>.
15194 *
15195 * Each element that is _not_ one of these
15196 * should be removed from +ARGV+ before \ARGF accesses that source.
15197 *
15198 * In the following example:
15199 *
15200 * - Filepaths +foo.txt+ and +bar.txt+ may be retained as potential sources.
15201 * - Options <tt>--xyzzy</tt> and <tt>--mojo</tt> should be removed.
15202 *
15203 * Example:
15204 *
15205 * - \File +t.rb+:
15206 *
15207 * # Print arguments (and options, if any) found on command line.
15208 * p ['ARGV', ARGV]
15209 *
15210 * - Command and output:
15211 *
15212 * $ ruby t.rb --xyzzy --mojo foo.txt bar.txt
15213 * ["ARGV", ["--xyzzy", "--mojo", "foo.txt", "bar.txt"]]
15214 *
15215 * \ARGF's stream access considers the elements of +ARGV+, left to right:
15216 *
15217 * - \File +t.rb+:
15218 *
15219 * p "ARGV: #{ARGV}"
15220 * p "Read: #{ARGF.read}" # Read everything from all specified streams.
15221 *
15222 * - Command and output:
15223 *
15224 * $ ruby t.rb foo.txt bar.txt
15225 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
15226 * "Read: Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"
15227 *
15228 * Because the value at +ARGV+ is an ordinary array,
15229 * you can manipulate it to control which sources \ARGF considers:
15230 *
15231 * - If you remove an element from +ARGV+, \ARGF will not consider the corresponding source.
15232 * - If you add an element to +ARGV+, \ARGF will consider the corresponding source.
15233 *
15234 * Each element in +ARGV+ is removed when its corresponding source is accessed;
15235 * when all sources have been accessed, the array is empty:
15236 *
15237 * - \File +t.rb+:
15238 *
15239 * until ARGV.empty? && ARGF.eof?
15240 * p "ARGV: #{ARGV}"
15241 * p "Line: #{ARGF.readline}" # Read each line from each specified stream.
15242 * end
15243 *
15244 * - Command and output:
15245 *
15246 * $ ruby t.rb foo.txt bar.txt
15247 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
15248 * "Line: Foo 0\n"
15249 * "ARGV: [\"bar.txt\"]"
15250 * "Line: Foo 1\n"
15251 * "ARGV: [\"bar.txt\"]"
15252 * "Line: Bar 0\n"
15253 * "ARGV: []"
15254 * "Line: Bar 1\n"
15255 * "ARGV: []"
15256 * "Line: Bar 2\n"
15257 * "ARGV: []"
15258 * "Line: Bar 3\n"
15259 *
15260 * ==== Filepaths in +ARGV+
15261 *
15262 * The +ARGV+ array may contain filepaths the specify sources for \ARGF reading.
15263 *
15264 * This program prints what it reads from files at the paths specified
15265 * on the command line:
15266 *
15267 * - \File +t.rb+:
15268 *
15269 * p ['ARGV', ARGV]
15270 * # Read and print all content from the specified sources.
15271 * p ['ARGF.read', ARGF.read]
15272 *
15273 * - Command and output:
15274 *
15275 * $ ruby t.rb foo.txt bar.txt
15276 * ["ARGV", [foo.txt, bar.txt]
15277 * ["ARGF.read", "Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"]
15278 *
15279 * ==== Specifying <tt>$stdin</tt> in +ARGV+
15280 *
15281 * To specify stream <tt>$stdin</tt> in +ARGV+, us the character <tt>'-'</tt>:
15282 *
15283 * - \File +t.rb+:
15284 *
15285 * p ['ARGV', ARGV]
15286 * p ['ARGF.read', ARGF.read]
15287 *
15288 * - Command and output:
15289 *
15290 * $ echo "Open the pod bay doors, Hal." | ruby t.rb -
15291 * ["ARGV", ["-"]]
15292 * ["ARGF.read", "Open the pod bay doors, Hal.\n"]
15293 *
15294 * When no character <tt>'-'</tt> is given, stream <tt>$stdin</tt> is ignored.
15295 *
15296 * - Command and output:
15297 *
15298 * $ echo "Open the pod bay doors, Hal." | ruby t.rb foo.txt bar.txt
15299 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
15300 * "Read: Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"
15301 *
15302 * ==== Mixtures and Repetitions in +ARGV+
15303 *
15304 * For an \ARGF reader, +ARGV+ may contain any mixture of filepaths
15305 * and character <tt>'-'</tt>, including repetitions.
15306 *
15307 * ==== Modifications to +ARGV+
15308 *
15309 * The running Ruby program may make any modifications to the +ARGV+ array;
15310 * the current value of +ARGV+ affects \ARGF reading.
15311 *
15312 * ==== Empty +ARGV+
15313 *
15314 * For an empty +ARGV+, an \ARGF read method either returns +nil+
15315 * or raises an exception, depending on the specific method.
15316 *
15317 * === More Read Methods
15318 *
15319 * As seen above, method ARGF#read reads the content of all sources
15320 * into a single string.
15321 * Other \ARGF methods provide other ways to access that content;
15322 * these include:
15323 *
15324 * - Byte access: #each_byte, #getbyte, #readbyte.
15325 * - Character access: #each_char, #getc, #readchar.
15326 * - Codepoint access: #each_codepoint.
15327 * - Line access: #each_line, #gets, #readline, #readlines.
15328 * - Source access: #read, #read_nonblock, #readpartial.
15329 *
15330 * === About \Enumerable
15331 *
15332 * \ARGF includes module Enumerable.
15333 * Virtually all methods in \Enumerable call method <tt>#each</tt> in the including class.
15334 *
15335 * <b>Note well</b>: In \ARGF, method #each returns data from the _sources_,
15336 * _not_ from +ARGV+;
15337 * therefore, for example, <tt>ARGF#entries</tt> returns an array of lines from the sources,
15338 * not an array of the strings from +ARGV+:
15339 *
15340 * - \File +t.rb+:
15341 *
15342 * p ['ARGV', ARGV]
15343 * p ['ARGF.entries', ARGF.entries]
15344 *
15345 * - Command and output:
15346 *
15347 * $ ruby t.rb foo.txt bar.txt
15348 * ["ARGV", ["foo.txt", "bar.txt"]]
15349 * ["ARGF.entries", ["Foo 0\n", "Foo 1\n", "Bar 0\n", "Bar 1\n", "Bar 2\n", "Bar 3\n"]]
15350 *
15351 * == Writing
15352 *
15353 * If <i>inplace mode</i> is in effect,
15354 * \ARGF may write to target streams,
15355 * which at any particular time are determined by the content of ARGV.
15356 *
15357 * Methods about inplace mode:
15358 *
15359 * - #inplace_mode
15360 * - #inplace_mode=
15361 * - #to_write_io
15362 *
15363 * Methods for writing:
15364 *
15365 * - #print
15366 * - #printf
15367 * - #putc
15368 * - #puts
15369 * - #write
15370 *
15371 */
15372
15373/*
15374 * An instance of class \IO (commonly called a _stream_)
15375 * represents an input/output stream in the underlying operating system.
15376 * Class \IO is the basis for input and output in Ruby.
15377 *
15378 * Class File is the only class in the Ruby core that is a subclass of \IO.
15379 * Some classes in the Ruby standard library are also subclasses of \IO;
15380 * these include TCPSocket and UDPSocket.
15381 *
15382 * The global constant ARGF (also accessible as <tt>$<</tt>)
15383 * provides an IO-like stream that allows access to all file paths
15384 * found in ARGV (or found in STDIN if ARGV is empty).
15385 * ARGF is not itself a subclass of \IO.
15386 *
15387 * Class StringIO provides an IO-like stream that handles a String.
15388 * StringIO is not itself a subclass of \IO.
15389 *
15390 * Important objects based on \IO include:
15391 *
15392 * - $stdin.
15393 * - $stdout.
15394 * - $stderr.
15395 * - Instances of class File.
15396 *
15397 * An instance of \IO may be created using:
15398 *
15399 * - IO.new: returns a new \IO object for the given integer file descriptor.
15400 * - IO.open: passes a new \IO object to the given block.
15401 * - IO.popen: returns a new \IO object that is connected to the $stdin and $stdout
15402 * of a newly-launched subprocess.
15403 * - Kernel#open: Returns a new \IO object connected to a given source:
15404 * stream, file, or subprocess.
15405 *
15406 * Like a File stream, an \IO stream has:
15407 *
15408 * - A read/write mode, which may be read-only, write-only, or read/write;
15409 * see {Read/Write Mode}[rdoc-ref:File@ReadWrite+Mode].
15410 * - A data mode, which may be text-only or binary;
15411 * see {Data Mode}[rdoc-ref:File@Data+Mode].
15412 * - Internal and external encodings;
15413 * see {Encodings}[rdoc-ref:File@Encodings].
15414 *
15415 * And like other \IO streams, it has:
15416 *
15417 * - A position, which determines where in the stream the next
15418 * read or write is to occur;
15419 * see {Position}[rdoc-ref:IO@Position].
15420 * - A line number, which is a special, line-oriented, "position"
15421 * (different from the position mentioned above);
15422 * see {Line Number}[rdoc-ref:IO@Line+Number].
15423 *
15424 * == Extension <tt>io/console</tt>
15425 *
15426 * Extension <tt>io/console</tt> provides numerous methods
15427 * for interacting with the console;
15428 * requiring it adds numerous methods to class \IO.
15429 *
15430 * == Example Files
15431 *
15432 * Many examples here use these variables:
15433 *
15434 * :include: doc/examples/files.rdoc
15435 *
15436 * == Open Options
15437 *
15438 * A number of \IO methods accept optional keyword arguments
15439 * that determine how a new stream is to be opened:
15440 *
15441 * - +:mode+: Stream mode.
15442 * - +:flags+: Integer file open flags;
15443 * If +mode+ is also given, the two are bitwise-ORed.
15444 * - +:external_encoding+: External encoding for the stream.
15445 * - +:internal_encoding+: Internal encoding for the stream.
15446 * <tt>'-'</tt> is a synonym for the default internal encoding.
15447 * If the value is +nil+ no conversion occurs.
15448 * - +:encoding+: Specifies external and internal encodings as <tt>'extern:intern'</tt>.
15449 * - +:textmode+: If a truthy value, specifies the mode as text-only, binary otherwise.
15450 * - +:binmode+: If a truthy value, specifies the mode as binary, text-only otherwise.
15451 * - +:autoclose+: If a truthy value, specifies that the +fd+ will close
15452 * when the stream closes; otherwise it remains open.
15453 * - +:path+: If a string value is provided, it is used in #inspect and is available as
15454 * #path method.
15455 *
15456 * Also available are the options offered in String#encode,
15457 * which may control conversion between external and internal encoding.
15458 *
15459 * == Basic \IO
15460 *
15461 * You can perform basic stream \IO with these methods,
15462 * which typically operate on multi-byte strings:
15463 *
15464 * - IO#read: Reads and returns some or all of the remaining bytes from the stream.
15465 * - IO#write: Writes zero or more strings to the stream;
15466 * each given object that is not already a string is converted via +to_s+.
15467 *
15468 * === Position
15469 *
15470 * An \IO stream has a nonnegative integer _position_,
15471 * which is the byte offset at which the next read or write is to occur.
15472 * A new stream has position zero (and line number zero);
15473 * method +rewind+ resets the position (and line number) to zero.
15474 *
15475 * These methods discard {buffers}[rdoc-ref:IO@Buffering] and the
15476 * Encoding::Converter instances used for that \IO.
15477 *
15478 * The relevant methods:
15479 *
15480 * - IO#tell (aliased as +#pos+): Returns the current position (in bytes) in the stream.
15481 * - IO#pos=: Sets the position of the stream to a given integer +new_position+ (in bytes).
15482 * - IO#seek: Sets the position of the stream to a given integer +offset+ (in bytes),
15483 * relative to a given position +whence+
15484 * (indicating the beginning, end, or current position).
15485 * - IO#rewind: Positions the stream at the beginning (also resetting the line number).
15486 *
15487 * === Open and Closed Streams
15488 *
15489 * A new \IO stream may be open for reading, open for writing, or both.
15490 *
15491 * A stream is automatically closed when claimed by the garbage collector.
15492 *
15493 * Attempted reading or writing on a closed stream raises an exception.
15494 *
15495 * The relevant methods:
15496 *
15497 * - IO#close: Closes the stream for both reading and writing.
15498 * - IO#close_read: Closes the stream for reading.
15499 * - IO#close_write: Closes the stream for writing.
15500 * - IO#closed?: Returns whether the stream is closed.
15501 *
15502 * === End-of-Stream
15503 *
15504 * You can query whether a stream is positioned at its end:
15505 *
15506 * - IO#eof? (also aliased as +#eof+): Returns whether the stream is at end-of-stream.
15507 *
15508 * You can reposition to end-of-stream by using method IO#seek:
15509 *
15510 * f = File.new('t.txt')
15511 * f.eof? # => false
15512 * f.seek(0, :END)
15513 * f.eof? # => true
15514 * f.close
15515 *
15516 * Or by reading all stream content (which is slower than using IO#seek):
15517 *
15518 * f.rewind
15519 * f.eof? # => false
15520 * f.read # => "First line\nSecond line\n\nFourth line\nFifth line\n"
15521 * f.eof? # => true
15522 *
15523 * == Line \IO
15524 *
15525 * Class \IO supports line-oriented
15526 * {input}[rdoc-ref:IO@Line+Input] and {output}[rdoc-ref:IO@Line+Output]
15527 *
15528 * === Line Input
15529 *
15530 * Class \IO supports line-oriented input for
15531 * {files}[rdoc-ref:IO@File+Line+Input] and {IO streams}[rdoc-ref:IO@Stream+Line+Input].
15532 *
15533 * ==== Line Input Options
15534 *
15535 * Optional keyword argument +chomp+ (default: +false+)
15536 * specifies whether line separators are to be excluded from the result of a read.
15537 *
15538 * ==== \File Line Input
15539 *
15540 * You can read lines from a file using these methods:
15541 *
15542 * - IO.foreach: Reads each line and passes it to the given block.
15543 * - IO.readlines: Reads and returns all lines in an array.
15544 *
15545 * For each of these methods:
15546 *
15547 * - You can specify {open options}[rdoc-ref:IO@Open+Options].
15548 * - Line parsing depends on the effective <i>line separator</i>;
15549 * see {Line Separator}[rdoc-ref:IO@Line+Separator].
15550 * - The length of each returned line depends on the effective <i>line limit</i>;
15551 * see {Line Limit}[rdoc-ref:IO@Line+Limit].
15552 *
15553 * ==== Stream Line Input
15554 *
15555 * You can read lines from an \IO stream using these methods:
15556 *
15557 * - IO#each_line: Reads each remaining line, passing it to the given block.
15558 * - IO#gets: Returns the next line.
15559 * - IO#readline: Like #gets, but raises an exception at end-of-stream.
15560 * - IO#readlines: Returns all remaining lines in an array.
15561 *
15562 * For each of these methods:
15563 *
15564 * - Reading may begin mid-line,
15565 * depending on the stream's _position_;
15566 * see {Position}[rdoc-ref:IO@Position].
15567 * - Line parsing depends on the effective <i>line separator</i>;
15568 * see {Line Separator}[rdoc-ref:IO@Line+Separator].
15569 * - The length of each returned line depends on the effective <i>line limit</i>;
15570 * see {Line Limit}[rdoc-ref:IO@Line+Limit].
15571 *
15572 * ===== Line Separator
15573 *
15574 * Each of the {line input methods}[rdoc-ref:IO@Line+Input] uses a <i>line separator</i>:
15575 * the string that determines what is considered a line;
15576 * it is sometimes called the <i>input record separator</i>.
15577 *
15578 * The default line separator is taken from global variable <tt>$/</tt>,
15579 * whose initial value is <tt>"\n"</tt>.
15580 *
15581 * Generally, the line to be read next is all data
15582 * from the current {position}[rdoc-ref:IO@Position]
15583 * to the next line separator
15584 * (but see {Special Line Separator Values}[rdoc-ref:IO@Special+Line+Separator+Values]):
15585 *
15586 * f = File.new('t.txt')
15587 * # Method gets with no sep argument returns the next line, according to $/.
15588 * f.gets # => "First line\n"
15589 * f.gets # => "Second line\n"
15590 * f.gets # => "\n"
15591 * f.gets # => "Fourth line\n"
15592 * f.gets # => "Fifth line\n"
15593 * f.close
15594 *
15595 * You can use a different line separator by passing argument +sep+:
15596 *
15597 * f = File.new('t.txt')
15598 * f.gets('l') # => "First l"
15599 * f.gets('li') # => "ine\nSecond li"
15600 * f.gets('lin') # => "ne\n\nFourth lin"
15601 * f.gets # => "e\n"
15602 * f.close
15603 *
15604 * Or by setting global variable <tt>$/</tt>:
15605 *
15606 * f = File.new('t.txt')
15607 * $/ = 'l'
15608 * f.gets # => "First l"
15609 * f.gets # => "ine\nSecond l"
15610 * f.gets # => "ine\n\nFourth l"
15611 * f.close
15612 *
15613 * ===== Special Line Separator Values
15614 *
15615 * Each of the {line input methods}[rdoc-ref:IO@Line+Input]
15616 * accepts two special values for parameter +sep+:
15617 *
15618 * - +nil+: The entire stream is to be read ("slurped") into a single string:
15619 *
15620 * f = File.new('t.txt')
15621 * f.gets(nil) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
15622 * f.close
15623 *
15624 * - <tt>''</tt> (the empty string): The next "paragraph" is to be read
15625 * (paragraphs being separated by two consecutive line separators):
15626 *
15627 * f = File.new('t.txt')
15628 * f.gets('') # => "First line\nSecond line\n\n"
15629 * f.gets('') # => "Fourth line\nFifth line\n"
15630 * f.close
15631 *
15632 * ===== Line Limit
15633 *
15634 * Each of the {line input methods}[rdoc-ref:IO@Line+Input]
15635 * uses an integer <i>line limit</i>,
15636 * which restricts the number of bytes that may be returned.
15637 * (A multi-byte character will not be split, and so a returned line may be slightly longer
15638 * than the limit).
15639 *
15640 * The default limit value is <tt>-1</tt>;
15641 * any negative limit value means that there is no limit.
15642 *
15643 * If there is no limit, the line is determined only by +sep+.
15644 *
15645 * # Text with 1-byte characters.
15646 * File.open('t.txt') {|f| f.gets(1) } # => "F"
15647 * File.open('t.txt') {|f| f.gets(2) } # => "Fi"
15648 * File.open('t.txt') {|f| f.gets(3) } # => "Fir"
15649 * File.open('t.txt') {|f| f.gets(4) } # => "Firs"
15650 * # No more than one line.
15651 * File.open('t.txt') {|f| f.gets(10) } # => "First line"
15652 * File.open('t.txt') {|f| f.gets(11) } # => "First line\n"
15653 * File.open('t.txt') {|f| f.gets(12) } # => "First line\n"
15654 *
15655 * # Text with 3-byte characters, which will not be split.
15656 * File.read('t.ja') # => "こんにちは"
15657 * File.open('t.ja') {|f| f.gets(1).size } # => 1
15658 * File.open('t.ja') {|f| f.gets(2).size } # => 1
15659 * File.open('t.ja') {|f| f.gets(3).size } # => 1
15660 * File.open('t.ja') {|f| f.gets(4).size } # => 2
15661 * File.open('t.ja') {|f| f.gets(5).size } # => 2
15662 *
15663 * ===== Line Separator and Line Limit
15664 *
15665 * With arguments +sep+ and +limit+ given, combines the two behaviors:
15666 *
15667 * - Returns the next line as determined by line separator +sep+.
15668 * - But returns no more bytes than are allowed by the limit +limit+.
15669 *
15670 * Example:
15671 *
15672 * File.open('t.txt') {|f| f.gets('li', 20) } # => "First li"
15673 * File.open('t.txt') {|f| f.gets('li', 2) } # => "Fi"
15674 *
15675 * ===== Line Number
15676 *
15677 * A readable \IO stream has a non-negative integer <i>line number</i>:
15678 *
15679 * - IO#lineno: Returns the line number.
15680 * - IO#lineno=: Resets and returns the line number.
15681 *
15682 * Unless modified by a call to method IO#lineno=,
15683 * the line number is the number of lines read
15684 * by certain line-oriented methods,
15685 * according to the effective {line separator}[rdoc-ref:IO@Line+Separator]:
15686 *
15687 * - IO.foreach: Increments the line number on each call to the block.
15688 * - IO#each_line: Increments the line number on each call to the block.
15689 * - IO#gets: Increments the line number.
15690 * - IO#readline: Increments the line number.
15691 * - IO#readlines: Increments the line number for each line read.
15692 *
15693 * A new stream is initially has line number zero (and position zero);
15694 * method +rewind+ resets the line number (and position) to zero:
15695 *
15696 * f = File.new('t.txt')
15697 * f.lineno # => 0
15698 * f.gets # => "First line\n"
15699 * f.lineno # => 1
15700 * f.rewind
15701 * f.lineno # => 0
15702 * f.close
15703 *
15704 * Reading lines from a stream usually changes its line number:
15705 *
15706 * f = File.new('t.txt', 'r')
15707 * f.lineno # => 0
15708 * f.readline # => "This is line one.\n"
15709 * f.lineno # => 1
15710 * f.readline # => "This is the second line.\n"
15711 * f.lineno # => 2
15712 * f.readline # => "Here's the third line.\n"
15713 * f.lineno # => 3
15714 * f.eof? # => true
15715 * f.close
15716 *
15717 * Iterating over lines in a stream usually changes its line number:
15718 *
15719 * File.open('t.txt') do |f|
15720 * f.each_line do |line|
15721 * p "position=#{f.pos} eof?=#{f.eof?} lineno=#{f.lineno}"
15722 * end
15723 * end
15724 *
15725 * Output:
15726 *
15727 * "position=11 eof?=false lineno=1"
15728 * "position=23 eof?=false lineno=2"
15729 * "position=24 eof?=false lineno=3"
15730 * "position=36 eof?=false lineno=4"
15731 * "position=47 eof?=true lineno=5"
15732 *
15733 * Unlike the stream's {position}[rdoc-ref:IO@Position],
15734 * the line number does not affect where the next read or write will occur:
15735 *
15736 * f = File.new('t.txt')
15737 * f.lineno = 1000
15738 * f.lineno # => 1000
15739 * f.gets # => "First line\n"
15740 * f.lineno # => 1001
15741 * f.close
15742 *
15743 * Associated with the line number is the global variable <tt>$.</tt>:
15744 *
15745 * - When a stream is opened, <tt>$.</tt> is not set;
15746 * its value is left over from previous activity in the process:
15747 *
15748 * $. = 41
15749 * f = File.new('t.txt')
15750 * $. = 41
15751 * # => 41
15752 * f.close
15753 *
15754 * - When a stream is read, <tt>$.</tt> is set to the line number for that stream:
15755 *
15756 * f0 = File.new('t.txt')
15757 * f1 = File.new('t.dat')
15758 * f0.readlines # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
15759 * $. # => 5
15760 * f1.readlines # => ["\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"]
15761 * $. # => 1
15762 * f0.close
15763 * f1.close
15764 *
15765 * - Methods IO#rewind and IO#seek do not affect <tt>$.</tt>:
15766 *
15767 * f = File.new('t.txt')
15768 * f.readlines # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
15769 * $. # => 5
15770 * f.rewind
15771 * f.seek(0, :SET)
15772 * $. # => 5
15773 * f.close
15774 *
15775 * === Line Output
15776 *
15777 * You can write to an \IO stream line-by-line using this method:
15778 *
15779 * - IO#puts: Writes objects to the stream.
15780 *
15781 * == Character \IO
15782 *
15783 * You can process an \IO stream character-by-character using these methods:
15784 *
15785 * - IO#getc: Reads and returns the next character from the stream.
15786 * - IO#readchar: Like #getc, but raises an exception at end-of-stream.
15787 * - IO#ungetc: Pushes back ("unshifts") a character or integer onto the stream.
15788 * - IO#putc: Writes a character to the stream.
15789 * - IO#each_char: Reads each remaining character in the stream,
15790 * passing the character to the given block.
15791 *
15792 * == Byte \IO
15793 *
15794 * You can process an \IO stream byte-by-byte using these methods:
15795 *
15796 * - IO#getbyte: Returns the next 8-bit byte as an integer in range 0..255.
15797 * - IO#readbyte: Like #getbyte, but raises an exception if at end-of-stream.
15798 * - IO#ungetbyte: Pushes back ("unshifts") a byte back onto the stream.
15799 * - IO#each_byte: Reads each remaining byte in the stream,
15800 * passing the byte to the given block.
15801 *
15802 * == Codepoint \IO
15803 *
15804 * You can process an \IO stream codepoint-by-codepoint:
15805 *
15806 * - IO#each_codepoint: Reads each remaining codepoint, passing it to the given block.
15807 *
15808 * == What's Here
15809 *
15810 * First, what's elsewhere. Class \IO:
15811 *
15812 * - Inherits from {class Object}[rdoc-ref:Object@Whats+Here].
15813 * - Includes {module Enumerable}[rdoc-ref:Enumerable@Whats+Here],
15814 * which provides dozens of additional methods.
15815 *
15816 * Here, class \IO provides methods that are useful for:
15817 *
15818 * - {Creating}[rdoc-ref:IO@Creating]
15819 * - {Reading}[rdoc-ref:IO@Reading]
15820 * - {Writing}[rdoc-ref:IO@Writing]
15821 * - {Positioning}[rdoc-ref:IO@Positioning]
15822 * - {Iterating}[rdoc-ref:IO@Iterating]
15823 * - {Settings}[rdoc-ref:IO@Settings]
15824 * - {Querying}[rdoc-ref:IO@Querying]
15825 * - {Buffering}[rdoc-ref:IO@Buffering]
15826 * - {Low-Level Access}[rdoc-ref:IO@Low-Level+Access]
15827 * - {Other}[rdoc-ref:IO@Other]
15828 *
15829 * === Creating
15830 *
15831 * - ::new (aliased as ::for_fd): Creates and returns a new \IO object for the given
15832 * integer file descriptor.
15833 * - ::open: Creates a new \IO object.
15834 * - ::pipe: Creates a connected pair of reader and writer \IO objects.
15835 * - ::popen: Creates an \IO object to interact with a subprocess.
15836 * - ::select: Selects which given \IO instances are ready for reading,
15837 * writing, or have pending exceptions.
15838 *
15839 * === Reading
15840 *
15841 * - ::binread: Returns a binary string with all or a subset of bytes
15842 * from the given file.
15843 * - ::read: Returns a string with all or a subset of bytes from the given file.
15844 * - ::readlines: Returns an array of strings, which are the lines from the given file.
15845 * - #getbyte: Returns the next 8-bit byte read from +self+ as an integer.
15846 * - #getc: Returns the next character read from +self+ as a string.
15847 * - #gets: Returns the line read from +self+.
15848 * - #pread: Returns all or the next _n_ bytes read from +self+,
15849 * not updating the receiver's offset.
15850 * - #read: Returns all remaining or the next _n_ bytes read from +self+
15851 * for a given _n_.
15852 * - #read_nonblock: the next _n_ bytes read from +self+ for a given _n_,
15853 * in non-block mode.
15854 * - #readbyte: Returns the next byte read from +self+;
15855 * same as #getbyte, but raises an exception on end-of-stream.
15856 * - #readchar: Returns the next character read from +self+;
15857 * same as #getc, but raises an exception on end-of-stream.
15858 * - #readline: Returns the next line read from +self+;
15859 * same as #getline, but raises an exception of end-of-stream.
15860 * - #readlines: Returns an array of all lines read read from +self+.
15861 * - #readpartial: Returns up to the given number of bytes from +self+.
15862 *
15863 * === Writing
15864 *
15865 * - ::binwrite: Writes the given string to the file at the given filepath,
15866 * in binary mode.
15867 * - ::write: Writes the given string to +self+.
15868 * - #<<: Appends the given string to +self+.
15869 * - #print: Prints last read line or given objects to +self+.
15870 * - #printf: Writes to +self+ based on the given format string and objects.
15871 * - #putc: Writes a character to +self+.
15872 * - #puts: Writes lines to +self+, making sure line ends with a newline.
15873 * - #pwrite: Writes the given string at the given offset,
15874 * not updating the receiver's offset.
15875 * - #write: Writes one or more given strings to +self+.
15876 * - #write_nonblock: Writes one or more given strings to +self+ in non-blocking mode.
15877 *
15878 * === Positioning
15879 *
15880 * - #lineno: Returns the current line number in +self+.
15881 * - #lineno=: Sets the line number is +self+.
15882 * - #pos (aliased as #tell): Returns the current byte offset in +self+.
15883 * - #pos=: Sets the byte offset in +self+.
15884 * - #reopen: Reassociates +self+ with a new or existing \IO stream.
15885 * - #rewind: Positions +self+ to the beginning of input.
15886 * - #seek: Sets the offset for +self+ relative to given position.
15887 *
15888 * === Iterating
15889 *
15890 * - ::foreach: Yields each line of given file to the block.
15891 * - #each (aliased as #each_line): Calls the given block
15892 * with each successive line in +self+.
15893 * - #each_byte: Calls the given block with each successive byte in +self+
15894 * as an integer.
15895 * - #each_char: Calls the given block with each successive character in +self+
15896 * as a string.
15897 * - #each_codepoint: Calls the given block with each successive codepoint in +self+
15898 * as an integer.
15899 *
15900 * === Settings
15901 *
15902 * - #autoclose=: Sets whether +self+ auto-closes.
15903 * - #binmode: Sets +self+ to binary mode.
15904 * - #close: Closes +self+.
15905 * - #close_on_exec=: Sets the close-on-exec flag.
15906 * - #close_read: Closes +self+ for reading.
15907 * - #close_write: Closes +self+ for writing.
15908 * - #set_encoding: Sets the encoding for +self+.
15909 * - #set_encoding_by_bom: Sets the encoding for +self+, based on its
15910 * Unicode byte-order-mark.
15911 * - #sync=: Sets the sync-mode to the given value.
15912 *
15913 * === Querying
15914 *
15915 * - #autoclose?: Returns whether +self+ auto-closes.
15916 * - #binmode?: Returns whether +self+ is in binary mode.
15917 * - #close_on_exec?: Returns the close-on-exec flag for +self+.
15918 * - #closed?: Returns whether +self+ is closed.
15919 * - #eof? (aliased as #eof): Returns whether +self+ is at end-of-stream.
15920 * - #external_encoding: Returns the external encoding object for +self+.
15921 * - #fileno (aliased as #to_i): Returns the integer file descriptor for +self+
15922 * - #internal_encoding: Returns the internal encoding object for +self+.
15923 * - #pid: Returns the process ID of a child process associated with +self+,
15924 * if +self+ was created by ::popen.
15925 * - #stat: Returns the File::Stat object containing status information for +self+.
15926 * - #sync: Returns whether +self+ is in sync-mode.
15927 * - #tty? (aliased as #isatty): Returns whether +self+ is a terminal.
15928 *
15929 * === Buffering
15930 *
15931 * - #fdatasync: Immediately writes all buffered data in +self+ to disk.
15932 * - #flush: Flushes any buffered data within +self+ to the underlying
15933 * operating system.
15934 * - #fsync: Immediately writes all buffered data and attributes in +self+ to disk.
15935 * - #ungetbyte: Prepends buffer for +self+ with given integer byte or string.
15936 * - #ungetc: Prepends buffer for +self+ with given string.
15937 *
15938 * === Low-Level Access
15939 *
15940 * - ::sysopen: Opens the file given by its path,
15941 * returning the integer file descriptor.
15942 * - #advise: Announces the intention to access data from +self+ in a specific way.
15943 * - #fcntl: Passes a low-level command to the file specified
15944 * by the given file descriptor.
15945 * - #ioctl: Passes a low-level command to the device specified
15946 * by the given file descriptor.
15947 * - #sysread: Returns up to the next _n_ bytes read from self using a low-level read.
15948 * - #sysseek: Sets the offset for +self+.
15949 * - #syswrite: Writes the given string to +self+ using a low-level write.
15950 *
15951 * === Other
15952 *
15953 * - ::copy_stream: Copies data from a source to a destination,
15954 * each of which is a filepath or an \IO-like object.
15955 * - ::try_convert: Returns a new \IO object resulting from converting
15956 * the given object.
15957 * - #inspect: Returns the string representation of +self+.
15958 *
15959 */
15960
15961void
15962Init_IO(void)
15963{
15964 VALUE rb_cARGF;
15965#ifdef __CYGWIN__
15966#include <sys/cygwin.h>
15967 static struct __cygwin_perfile pf[] =
15968 {
15969 {"", O_RDONLY | O_BINARY},
15970 {"", O_WRONLY | O_BINARY},
15971 {"", O_RDWR | O_BINARY},
15972 {"", O_APPEND | O_BINARY},
15973 {NULL, 0}
15974 };
15975 cygwin_internal(CW_PERFILE, pf);
15976#endif
15977
15978 rb_eIOError = rb_define_class("IOError", rb_eStandardError);
15979 rb_eEOFError = rb_define_class("EOFError", rb_eIOError);
15980
15981 id_write = rb_intern_const("write");
15982 id_read = rb_intern_const("read");
15983 id_flush = rb_intern_const("flush");
15984 id_readpartial = rb_intern_const("readpartial");
15985 id_set_encoding = rb_intern_const("set_encoding");
15986 id_fileno = rb_intern_const("fileno");
15987
15988 rb_define_global_function("syscall", rb_f_syscall, -1);
15989
15990 rb_define_global_function("open", rb_f_open, -1);
15991 rb_define_global_function("printf", rb_f_printf, -1);
15992 rb_define_global_function("print", rb_f_print, -1);
15993 rb_define_global_function("putc", rb_f_putc, 1);
15994 rb_define_global_function("puts", rb_f_puts, -1);
15995 rb_define_global_function("gets", rb_f_gets, -1);
15996 rb_define_global_function("readline", rb_f_readline, -1);
15997 rb_define_global_function("select", rb_f_select, -1);
15998
15999 rb_define_global_function("readlines", rb_f_readlines, -1);
16000
16001 rb_define_global_function("`", rb_f_backquote, 1);
16002
16003 rb_define_global_function("p", rb_f_p, -1);
16004 rb_define_method(rb_mKernel, "display", rb_obj_display, -1);
16005
16006 rb_cIO = rb_define_class("IO", rb_cObject);
16008
16009 /* Can be raised by IO operations when IO#timeout= is set. */
16010 rb_eIOTimeoutError = rb_define_class_under(rb_cIO, "TimeoutError", rb_eIOError);
16011
16012 /* Readable event mask for IO#wait. */
16013 rb_define_const(rb_cIO, "READABLE", INT2NUM(RUBY_IO_READABLE));
16014 /* Writable event mask for IO#wait. */
16015 rb_define_const(rb_cIO, "WRITABLE", INT2NUM(RUBY_IO_WRITABLE));
16016 /* Priority event mask for IO#wait. */
16017 rb_define_const(rb_cIO, "PRIORITY", INT2NUM(RUBY_IO_PRIORITY));
16018
16019 /* exception to wait for reading. see IO.select. */
16020 rb_mWaitReadable = rb_define_module_under(rb_cIO, "WaitReadable");
16021 /* exception to wait for writing. see IO.select. */
16022 rb_mWaitWritable = rb_define_module_under(rb_cIO, "WaitWritable");
16023 /* exception to wait for reading by EAGAIN. see IO.select. */
16024 rb_eEAGAINWaitReadable = rb_define_class_under(rb_cIO, "EAGAINWaitReadable", rb_eEAGAIN);
16025 rb_include_module(rb_eEAGAINWaitReadable, rb_mWaitReadable);
16026 /* exception to wait for writing by EAGAIN. see IO.select. */
16027 rb_eEAGAINWaitWritable = rb_define_class_under(rb_cIO, "EAGAINWaitWritable", rb_eEAGAIN);
16028 rb_include_module(rb_eEAGAINWaitWritable, rb_mWaitWritable);
16029#if EAGAIN == EWOULDBLOCK
16030 /* same as IO::EAGAINWaitReadable */
16031 rb_define_const(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEAGAINWaitReadable);
16032 /* same as IO::EAGAINWaitWritable */
16033 rb_define_const(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEAGAINWaitWritable);
16034#else
16035 /* exception to wait for reading by EWOULDBLOCK. see IO.select. */
16036 rb_eEWOULDBLOCKWaitReadable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEWOULDBLOCK);
16037 rb_include_module(rb_eEWOULDBLOCKWaitReadable, rb_mWaitReadable);
16038 /* exception to wait for writing by EWOULDBLOCK. see IO.select. */
16039 rb_eEWOULDBLOCKWaitWritable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEWOULDBLOCK);
16040 rb_include_module(rb_eEWOULDBLOCKWaitWritable, rb_mWaitWritable);
16041#endif
16042 /* exception to wait for reading by EINPROGRESS. see IO.select. */
16043 rb_eEINPROGRESSWaitReadable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitReadable", rb_eEINPROGRESS);
16044 rb_include_module(rb_eEINPROGRESSWaitReadable, rb_mWaitReadable);
16045 /* exception to wait for writing by EINPROGRESS. see IO.select. */
16046 rb_eEINPROGRESSWaitWritable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitWritable", rb_eEINPROGRESS);
16047 rb_include_module(rb_eEINPROGRESSWaitWritable, rb_mWaitWritable);
16048
16049#if 0
16050 /* This is necessary only for forcing rdoc handle File::open */
16051 rb_define_singleton_method(rb_cFile, "open", rb_io_s_open, -1);
16052#endif
16053
16054 rb_define_alloc_func(rb_cIO, io_alloc);
16055 rb_define_singleton_method(rb_cIO, "new", rb_io_s_new, -1);
16056 rb_define_singleton_method(rb_cIO, "open", rb_io_s_open, -1);
16057 rb_define_singleton_method(rb_cIO, "sysopen", rb_io_s_sysopen, -1);
16058 rb_define_singleton_method(rb_cIO, "for_fd", rb_io_s_for_fd, -1);
16059 rb_define_singleton_method(rb_cIO, "popen", rb_io_s_popen, -1);
16060 rb_define_singleton_method(rb_cIO, "foreach", rb_io_s_foreach, -1);
16061 rb_define_singleton_method(rb_cIO, "readlines", rb_io_s_readlines, -1);
16062 rb_define_singleton_method(rb_cIO, "read", rb_io_s_read, -1);
16063 rb_define_singleton_method(rb_cIO, "binread", rb_io_s_binread, -1);
16064 rb_define_singleton_method(rb_cIO, "write", rb_io_s_write, -1);
16065 rb_define_singleton_method(rb_cIO, "binwrite", rb_io_s_binwrite, -1);
16066 rb_define_singleton_method(rb_cIO, "select", rb_f_select, -1);
16067 rb_define_singleton_method(rb_cIO, "pipe", rb_io_s_pipe, -1);
16068 rb_define_singleton_method(rb_cIO, "try_convert", rb_io_s_try_convert, 1);
16069 rb_define_singleton_method(rb_cIO, "copy_stream", rb_io_s_copy_stream, -1);
16070
16071 rb_define_method(rb_cIO, "initialize", rb_io_initialize, -1);
16072
16074 rb_define_hooked_variable("$,", &rb_output_fs, 0, rb_deprecated_str_setter);
16075
16076 rb_default_rs = rb_fstring_lit("\n"); /* avoid modifying RS_default */
16077 rb_vm_register_global_object(rb_default_rs);
16078 rb_rs = rb_default_rs;
16080 rb_define_hooked_variable("$/", &rb_rs, 0, deprecated_rs_setter);
16081 rb_gvar_ractor_local("$/"); // not local but ractor safe
16082 rb_define_hooked_variable("$-0", &rb_rs, 0, deprecated_rs_setter);
16083 rb_gvar_ractor_local("$-0"); // not local but ractor safe
16084 rb_define_hooked_variable("$\\", &rb_output_rs, 0, rb_deprecated_str_setter);
16085
16086 rb_define_virtual_variable("$_", get_LAST_READ_LINE, set_LAST_READ_LINE);
16087 rb_gvar_ractor_local("$_");
16088 rb_gvar_box_dynamic("$_");
16089
16090 rb_define_method(rb_cIO, "initialize_copy", rb_io_init_copy, 1);
16091 rb_define_method(rb_cIO, "reopen", rb_io_reopen, -1);
16092
16093 rb_define_method(rb_cIO, "print", rb_io_print, -1);
16094 rb_define_method(rb_cIO, "putc", rb_io_putc, 1);
16095 rb_define_method(rb_cIO, "puts", rb_io_puts, -1);
16096 rb_define_method(rb_cIO, "printf", rb_io_printf, -1);
16097
16098 rb_define_method(rb_cIO, "each", rb_io_each_line, -1);
16099 rb_define_method(rb_cIO, "each_line", rb_io_each_line, -1);
16100 rb_define_method(rb_cIO, "each_byte", rb_io_each_byte, 0);
16101 rb_define_method(rb_cIO, "each_char", rb_io_each_char, 0);
16102 rb_define_method(rb_cIO, "each_codepoint", rb_io_each_codepoint, 0);
16103
16104 rb_define_method(rb_cIO, "syswrite", rb_io_syswrite, 1);
16105 rb_define_method(rb_cIO, "sysread", rb_io_sysread, -1);
16106
16107 rb_define_method(rb_cIO, "pread", rb_io_pread, -1);
16108 rb_define_method(rb_cIO, "pwrite", rb_io_pwrite, 2);
16109
16110 rb_define_method(rb_cIO, "fileno", rb_io_fileno, 0);
16111 rb_define_alias(rb_cIO, "to_i", "fileno");
16112 rb_define_method(rb_cIO, "to_io", rb_io_to_io, 0);
16113
16114 rb_define_method(rb_cIO, "timeout", rb_io_timeout, 0);
16115 rb_define_method(rb_cIO, "timeout=", rb_io_set_timeout, 1);
16116
16117 rb_define_method(rb_cIO, "fsync", rb_io_fsync, 0);
16118 rb_define_method(rb_cIO, "fdatasync", rb_io_fdatasync, 0);
16119 rb_define_method(rb_cIO, "sync", rb_io_sync, 0);
16120 rb_define_method(rb_cIO, "sync=", rb_io_set_sync, 1);
16121
16122 rb_define_method(rb_cIO, "lineno", rb_io_lineno, 0);
16123 rb_define_method(rb_cIO, "lineno=", rb_io_set_lineno, 1);
16124
16125 rb_define_method(rb_cIO, "readlines", rb_io_readlines, -1);
16126
16127 rb_define_method(rb_cIO, "readpartial", io_readpartial, -1);
16128 rb_define_method(rb_cIO, "read", io_read, -1);
16129 rb_define_method(rb_cIO, "write", io_write_m, -1);
16130 rb_define_method(rb_cIO, "gets", rb_io_gets_m, -1);
16131 rb_define_method(rb_cIO, "getc", rb_io_getc, 0);
16132 rb_define_method(rb_cIO, "getbyte", rb_io_getbyte, 0);
16133 rb_define_method(rb_cIO, "readchar", rb_io_readchar, 0);
16134 rb_define_method(rb_cIO, "readbyte", rb_io_readbyte, 0);
16135 rb_define_method(rb_cIO, "ungetbyte",rb_io_ungetbyte, 1);
16136 rb_define_method(rb_cIO, "ungetc",rb_io_ungetc, 1);
16138 rb_define_method(rb_cIO, "flush", rb_io_flush, 0);
16139 rb_define_method(rb_cIO, "tell", rb_io_tell, 0);
16140 rb_define_method(rb_cIO, "seek", rb_io_seek_m, -1);
16141 /* Set I/O position from the beginning */
16142 rb_define_const(rb_cIO, "SEEK_SET", INT2FIX(SEEK_SET));
16143 /* Set I/O position from the current position */
16144 rb_define_const(rb_cIO, "SEEK_CUR", INT2FIX(SEEK_CUR));
16145 /* Set I/O position from the end */
16146 rb_define_const(rb_cIO, "SEEK_END", INT2FIX(SEEK_END));
16147#ifdef SEEK_DATA
16148 /* Set I/O position to the next location containing data */
16149 rb_define_const(rb_cIO, "SEEK_DATA", INT2FIX(SEEK_DATA));
16150#endif
16151#ifdef SEEK_HOLE
16152 /* Set I/O position to the next hole */
16153 rb_define_const(rb_cIO, "SEEK_HOLE", INT2FIX(SEEK_HOLE));
16154#endif
16155 rb_define_method(rb_cIO, "rewind", rb_io_rewind, 0);
16156 rb_define_method(rb_cIO, "pos", rb_io_tell, 0);
16157 rb_define_method(rb_cIO, "pos=", rb_io_set_pos, 1);
16158 rb_define_method(rb_cIO, "eof", rb_io_eof, 0);
16159 rb_define_method(rb_cIO, "eof?", rb_io_eof, 0);
16160
16161 rb_define_method(rb_cIO, "close_on_exec?", rb_io_close_on_exec_p, 0);
16162 rb_define_method(rb_cIO, "close_on_exec=", rb_io_set_close_on_exec, 1);
16163
16164 rb_define_method(rb_cIO, "close", rb_io_close_m, 0);
16165 rb_define_method(rb_cIO, "closed?", rb_io_closed_p, 0);
16166 rb_define_method(rb_cIO, "close_read", rb_io_close_read, 0);
16167 rb_define_method(rb_cIO, "close_write", rb_io_close_write, 0);
16168
16169 rb_define_method(rb_cIO, "isatty", rb_io_isatty, 0);
16170 rb_define_method(rb_cIO, "tty?", rb_io_isatty, 0);
16171 rb_define_method(rb_cIO, "binmode", rb_io_binmode_m, 0);
16172 rb_define_method(rb_cIO, "binmode?", rb_io_binmode_p, 0);
16173 rb_define_method(rb_cIO, "sysseek", rb_io_sysseek, -1);
16174 rb_define_method(rb_cIO, "advise", rb_io_advise, -1);
16175
16176 rb_define_method(rb_cIO, "ioctl", rb_io_ioctl, -1);
16177 rb_define_method(rb_cIO, "fcntl", rb_io_fcntl, -1);
16178 rb_define_method(rb_cIO, "pid", rb_io_pid, 0);
16179
16180 rb_define_method(rb_cIO, "path", rb_io_path, 0);
16181 rb_define_method(rb_cIO, "to_path", rb_io_path, 0);
16182
16183 rb_define_method(rb_cIO, "inspect", rb_io_inspect, 0);
16184
16185 rb_define_method(rb_cIO, "external_encoding", rb_io_external_encoding, 0);
16186 rb_define_method(rb_cIO, "internal_encoding", rb_io_internal_encoding, 0);
16187 rb_define_method(rb_cIO, "set_encoding", rb_io_set_encoding, -1);
16188 rb_define_method(rb_cIO, "set_encoding_by_bom", rb_io_set_encoding_by_bom, 0);
16189
16190 rb_define_method(rb_cIO, "autoclose?", rb_io_autoclose_p, 0);
16191 rb_define_method(rb_cIO, "autoclose=", rb_io_set_autoclose, 1);
16192
16193 rb_define_method(rb_cIO, "wait", io_wait, -1);
16194
16195 rb_define_method(rb_cIO, "wait_readable", io_wait_readable, -1);
16196 rb_define_method(rb_cIO, "wait_writable", io_wait_writable, -1);
16197 rb_define_method(rb_cIO, "wait_priority", io_wait_priority, -1);
16198
16199 rb_define_virtual_variable("$stdin", stdin_getter, stdin_setter);
16200 rb_define_virtual_variable("$stdout", stdout_getter, stdout_setter);
16201 rb_define_virtual_variable("$>", stdout_getter, stdout_setter);
16202 rb_define_virtual_variable("$stderr", stderr_getter, stderr_setter);
16203
16204 rb_gvar_ractor_local("$stdin");
16205 rb_gvar_ractor_local("$stdout");
16206 rb_gvar_ractor_local("$>");
16207 rb_gvar_ractor_local("$stderr");
16208
16209 rb_gvar_box_dynamic("$stdin");
16210 rb_gvar_box_dynamic("$stdout");
16211 rb_gvar_box_dynamic("$>");
16212 rb_gvar_box_dynamic("$stderr");
16213
16215 rb_stdin = rb_io_prep_stdin();
16217 rb_stdout = rb_io_prep_stdout();
16219 rb_stderr = rb_io_prep_stderr();
16220
16221 orig_stdout = rb_stdout;
16222 orig_stderr = rb_stderr;
16223
16224 /* Holds the original stdin */
16226 /* Holds the original stdout */
16228 /* Holds the original stderr */
16230
16231#if 0
16232 /* Hack to get rdoc to regard ARGF as a class: */
16233 rb_cARGF = rb_define_class("ARGF", rb_cObject);
16234#endif
16235
16236 rb_cARGF = rb_class_new(rb_cObject);
16237 rb_set_class_path(rb_cARGF, rb_cObject, "ARGF.class");
16238 rb_define_alloc_func(rb_cARGF, argf_alloc);
16239
16241
16242 rb_define_method(rb_cARGF, "initialize", argf_initialize, -2);
16243 rb_define_method(rb_cARGF, "initialize_copy", argf_initialize_copy, 1);
16244 rb_define_method(rb_cARGF, "to_s", argf_to_s, 0);
16245 rb_define_alias(rb_cARGF, "inspect", "to_s");
16246 rb_define_method(rb_cARGF, "argv", argf_argv, 0);
16247
16248 rb_define_method(rb_cARGF, "fileno", argf_fileno, 0);
16249 rb_define_method(rb_cARGF, "to_i", argf_fileno, 0);
16250 rb_define_method(rb_cARGF, "to_io", argf_to_io, 0);
16251 rb_define_method(rb_cARGF, "to_write_io", argf_write_io, 0);
16252 rb_define_method(rb_cARGF, "each", argf_each_line, -1);
16253 rb_define_method(rb_cARGF, "each_line", argf_each_line, -1);
16254 rb_define_method(rb_cARGF, "each_byte", argf_each_byte, 0);
16255 rb_define_method(rb_cARGF, "each_char", argf_each_char, 0);
16256 rb_define_method(rb_cARGF, "each_codepoint", argf_each_codepoint, 0);
16257
16258 rb_define_method(rb_cARGF, "read", argf_read, -1);
16259 rb_define_method(rb_cARGF, "readpartial", argf_readpartial, -1);
16260 rb_define_method(rb_cARGF, "read_nonblock", argf_read_nonblock, -1);
16261 rb_define_method(rb_cARGF, "readlines", argf_readlines, -1);
16262 rb_define_method(rb_cARGF, "to_a", argf_readlines, -1);
16263 rb_define_method(rb_cARGF, "gets", argf_gets, -1);
16264 rb_define_method(rb_cARGF, "readline", argf_readline, -1);
16265 rb_define_method(rb_cARGF, "getc", argf_getc, 0);
16266 rb_define_method(rb_cARGF, "getbyte", argf_getbyte, 0);
16267 rb_define_method(rb_cARGF, "readchar", argf_readchar, 0);
16268 rb_define_method(rb_cARGF, "readbyte", argf_readbyte, 0);
16269 rb_define_method(rb_cARGF, "tell", argf_tell, 0);
16270 rb_define_method(rb_cARGF, "seek", argf_seek_m, -1);
16271 rb_define_method(rb_cARGF, "rewind", argf_rewind, 0);
16272 rb_define_method(rb_cARGF, "pos", argf_tell, 0);
16273 rb_define_method(rb_cARGF, "pos=", argf_set_pos, 1);
16274 rb_define_method(rb_cARGF, "eof", argf_eof, 0);
16275 rb_define_method(rb_cARGF, "eof?", argf_eof, 0);
16276 rb_define_method(rb_cARGF, "binmode", argf_binmode_m, 0);
16277 rb_define_method(rb_cARGF, "binmode?", argf_binmode_p, 0);
16278
16279 rb_define_method(rb_cARGF, "write", argf_write, -1);
16280 rb_define_method(rb_cARGF, "print", rb_io_print, -1);
16281 rb_define_method(rb_cARGF, "putc", rb_io_putc, 1);
16282 rb_define_method(rb_cARGF, "puts", rb_io_puts, -1);
16283 rb_define_method(rb_cARGF, "printf", rb_io_printf, -1);
16284
16285 rb_define_method(rb_cARGF, "filename", argf_filename, 0);
16286 rb_define_method(rb_cARGF, "path", argf_filename, 0);
16287 rb_define_method(rb_cARGF, "file", argf_file, 0);
16288 rb_define_method(rb_cARGF, "skip", argf_skip, 0);
16289 rb_define_method(rb_cARGF, "close", argf_close_m, 0);
16290 rb_define_method(rb_cARGF, "closed?", argf_closed, 0);
16291
16292 rb_define_method(rb_cARGF, "lineno", argf_lineno, 0);
16293 rb_define_method(rb_cARGF, "lineno=", argf_set_lineno, 1);
16294
16295 rb_define_method(rb_cARGF, "inplace_mode", argf_inplace_mode_get, 0);
16296 rb_define_method(rb_cARGF, "inplace_mode=", argf_inplace_mode_set, 1);
16297
16298 rb_define_method(rb_cARGF, "external_encoding", argf_external_encoding, 0);
16299 rb_define_method(rb_cARGF, "internal_encoding", argf_internal_encoding, 0);
16300 rb_define_method(rb_cARGF, "set_encoding", argf_set_encoding, -1);
16301
16302 argf = rb_class_new_instance(0, 0, rb_cARGF);
16303
16305 /*
16306 * ARGF is a stream designed for use in scripts that process files given
16307 * as command-line arguments or passed in via STDIN.
16308 *
16309 * See ARGF (the class) for more details.
16310 */
16312
16313 rb_define_hooked_variable("$.", &argf, argf_lineno_getter, argf_lineno_setter);
16314 rb_define_hooked_variable("$FILENAME", &argf, argf_filename_getter, rb_gvar_readonly_setter);
16315 ARGF_SET(filename, rb_str_new2("-"));
16316
16317 rb_define_hooked_variable("$-i", &argf, opt_i_get, opt_i_set);
16318 rb_gvar_ractor_local("$-i");
16319
16320 rb_define_hooked_variable("$*", &argf, argf_argv_getter, rb_gvar_readonly_setter);
16321
16322#if defined (_WIN32) || defined(__CYGWIN__)
16323 atexit(pipe_atexit);
16324#endif
16325
16326 Init_File();
16327
16328 rb_define_method(rb_cFile, "initialize", rb_file_initialize, -1);
16329
16330 sym_mode = ID2SYM(rb_intern_const("mode"));
16331 sym_perm = ID2SYM(rb_intern_const("perm"));
16332 sym_flags = ID2SYM(rb_intern_const("flags"));
16333 sym_extenc = ID2SYM(rb_intern_const("external_encoding"));
16334 sym_intenc = ID2SYM(rb_intern_const("internal_encoding"));
16335 sym_encoding = ID2SYM(rb_id_encoding());
16336 sym_open_args = ID2SYM(rb_intern_const("open_args"));
16337 sym_textmode = ID2SYM(rb_intern_const("textmode"));
16338 sym_binmode = ID2SYM(rb_intern_const("binmode"));
16339 sym_autoclose = ID2SYM(rb_intern_const("autoclose"));
16340 sym_normal = ID2SYM(rb_intern_const("normal"));
16341 sym_sequential = ID2SYM(rb_intern_const("sequential"));
16342 sym_random = ID2SYM(rb_intern_const("random"));
16343 sym_willneed = ID2SYM(rb_intern_const("willneed"));
16344 sym_dontneed = ID2SYM(rb_intern_const("dontneed"));
16345 sym_noreuse = ID2SYM(rb_intern_const("noreuse"));
16346 sym_SET = ID2SYM(rb_intern_const("SET"));
16347 sym_CUR = ID2SYM(rb_intern_const("CUR"));
16348 sym_END = ID2SYM(rb_intern_const("END"));
16349#ifdef SEEK_DATA
16350 sym_DATA = ID2SYM(rb_intern_const("DATA"));
16351#endif
16352#ifdef SEEK_HOLE
16353 sym_HOLE = ID2SYM(rb_intern_const("HOLE"));
16354#endif
16355 sym_wait_readable = ID2SYM(rb_intern_const("wait_readable"));
16356 sym_wait_writable = ID2SYM(rb_intern_const("wait_writable"));
16357}
16358
16359static void init_builtin_io(void);
16360#define Init_builtin_io init_builtin_io
16361#include "io.rbinc"
16362#undef Init_builtin_io
16363
16364void
16365Init_builtin_io(void)
16366{
16367 init_builtin_io();
16368
16369 /* Init_IO is called earlier than `loaded_features` is initialized */
16370 rb_provide("io/wait.rb");
16371 rb_provide("io/wait.so");
16372}
#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:15030
VALUE rb_eIOError
IOError exception.
Definition io.c:189
VALUE rb_eStandardError
StandardError exception.
Definition error.c:1470
void rb_mod_syserr_fail_str(VALUE mod, int e, VALUE mesg)
Identical to rb_mod_syserr_fail(), except it takes the message in Ruby's String instead of C's.
Definition error.c:4174
void rb_syserr_fail_str(int e, VALUE mesg)
Identical to rb_syserr_fail(), except it takes the message in Ruby's String instead of C's.
Definition error.c:4090
#define ruby_verbose
This variable controls whether the interpreter is in debug mode.
Definition error.h:476
VALUE rb_eTypeError
TypeError exception.
Definition error.c:1473
VALUE rb_eEOFError
EOFError exception.
Definition io.c:188
void rb_readwrite_sys_fail(enum rb_io_wait_readwrite waiting, const char *mesg)
Raises appropriate exception using the parameters.
Definition io.c:15024
void rb_iter_break_value(VALUE val)
Identical to rb_iter_break(), except it additionally takes the "value" of this breakage.
Definition vm.c:2387
rb_io_wait_readwrite
for rb_readwrite_sys_fail first argument
Definition error.h:73
VALUE rb_eRuntimeError
RuntimeError exception.
Definition error.c:1471
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports unless $VERBOSE is nil.
Definition error.c:468
VALUE rb_eSystemCallError
SystemCallError exception.
Definition error.c:1493
@ RB_WARN_CATEGORY_DEPRECATED
Warning is for deprecated features.
Definition error.h:48
VALUE rb_mKernel
Kernel module.
Definition object.c:59
VALUE rb_check_to_int(VALUE val)
Identical to rb_check_to_integer(), except it uses #to_int for conversion.
Definition object.c:3334
VALUE rb_cObject
Object class.
Definition object.c:60
VALUE rb_any_to_s(VALUE obj)
Generates a textual representation of the given object.
Definition object.c:658
VALUE rb_obj_alloc(VALUE klass)
Allocates an instance of the given class.
Definition object.c:2252
VALUE rb_class_new_instance(int argc, const VALUE *argv, VALUE klass)
Allocates, then initialises an instance of the given class.
Definition object.c:2293
VALUE rb_cIO
IO class.
Definition io.c:187
VALUE rb_class_new_instance_kw(int argc, const VALUE *argv, VALUE klass, int kw_splat)
Identical to rb_class_new_instance(), except you can specify how to handle the last element of the gi...
Definition object.c:2281
VALUE rb_mEnumerable
Enumerable module.
Definition enum.c:28
VALUE rb_stdin
STDIN constant.
Definition io.c:203
VALUE rb_stderr
STDERR constant.
Definition io.c:203
VALUE rb_obj_class(VALUE obj)
Queries the class of an object.
Definition object.c:234
VALUE rb_obj_dup(VALUE obj)
Duplicates the given object.
Definition object.c:556
VALUE rb_inspect(VALUE obj)
Generates a human-readable textual representation of the given object.
Definition object.c:669
VALUE rb_mWaitReadable
IO::WaitReadable module.
Definition io.c:191
VALUE rb_mWaitWritable
IO::WaitReadable module.
Definition io.c:192
VALUE rb_obj_freeze(VALUE obj)
Same as RB_OBJ_FREEZE(), but returns the given object.
Definition object.c:1309
VALUE rb_check_to_integer(VALUE val, const char *mid)
Identical to rb_check_convert_type(), except the return value type is fixed to rb_cInteger.
Definition object.c:3315
VALUE rb_cFile
File class.
Definition file.c:175
VALUE rb_stdout
STDOUT constant.
Definition io.c:203
VALUE rb_to_int(VALUE val)
Identical to rb_check_to_int(), except it raises in case of conversion mismatch.
Definition object.c:3328
#define RB_OBJ_WRITTEN(old, oldv, young)
Identical to RB_OBJ_WRITE(), except it doesn't write any values, but only a WB declaration.
Definition gc.h:504
#define RB_OBJ_WRITE(old, slot, young)
Declaration of a "back" pointer.
Definition gc.h:492
Scheduler APIs.
VALUE rb_fiber_scheduler_current(void)
Identical to rb_fiber_scheduler_get(), except it also returns RUBY_Qnil in case of a blocking fiber.
Definition scheduler.c:581
VALUE rb_fiber_scheduler_make_timeout(struct timeval *timeout)
Converts the passed timeout to an expression that rb_fiber_scheduler_block() etc.
Definition scheduler.c:632
VALUE rb_fiber_scheduler_io_wait_readable(VALUE scheduler, VALUE io)
Non-blocking wait until the passed IO is ready for reading.
Definition scheduler.c:866
VALUE rb_fiber_scheduler_io_wait(VALUE scheduler, VALUE io, VALUE events, VALUE timeout)
Non-blocking version of rb_io_wait().
Definition scheduler.c:856
static ssize_t rb_fiber_scheduler_io_result_apply(VALUE result)
Apply an io result to the local thread, returning the value of the original system call that created ...
Definition scheduler.h:74
VALUE rb_fiber_scheduler_io_pread_memory(VALUE scheduler, VALUE io, rb_off_t from, void *base, size_t size)
Non-blocking pread from the passed IO using a native buffer.
Definition scheduler.c:1127
VALUE rb_fiber_scheduler_io_selectv(VALUE scheduler, int argc, VALUE *argv)
Non-blocking version of IO.select, argv variant.
Definition scheduler.c:896
VALUE rb_fiber_scheduler_io_read_memory(VALUE scheduler, VALUE io, void *base, size_t size)
Non-blocking read from the passed IO using a native buffer.
Definition scheduler.c:1079
VALUE rb_fiber_scheduler_current_for_thread(VALUE thread)
Identical to rb_fiber_scheduler_current(), except it queries for that of the passed thread value inst...
Definition scheduler.c:589
VALUE rb_fiber_scheduler_io_pwrite_memory(VALUE scheduler, VALUE io, rb_off_t from, const void *base, size_t size)
Non-blocking pwrite to the passed IO using a native buffer.
Definition scheduler.c:1152
VALUE rb_fiber_scheduler_current_for_threadptr(struct rb_thread_struct *thread)
Identical to rb_fiber_scheduler_current_for_thread(), except it expects a threadptr instead of a thre...
Definition scheduler.c:594
VALUE rb_fiber_scheduler_io_wait_writable(VALUE scheduler, VALUE io)
Non-blocking wait until the passed IO is ready for writing.
Definition scheduler.c:872
VALUE rb_fiber_scheduler_io_close(VALUE scheduler, VALUE io)
Non-blocking close the given IO.
Definition scheduler.c:1177
VALUE rb_fiber_scheduler_io_write_memory(VALUE scheduler, VALUE io, const void *base, size_t size)
Non-blocking write to the passed IO using a native buffer.
Definition scheduler.c:1103
static unsigned int rb_enc_codepoint(const char *p, const char *e, rb_encoding *enc)
Queries the code point of character pointed by the passed pointer.
Definition encoding.h:571
static int rb_enc_mbmaxlen(rb_encoding *enc)
Queries the maximum number of bytes that the passed encoding needs to represent a character.
Definition encoding.h:447
VALUE rb_str_conv_enc(VALUE str, rb_encoding *from, rb_encoding *to)
Encoding conversion main routine.
Definition string.c:1379
VALUE rb_enc_uint_chr(unsigned int code, rb_encoding *enc)
Encodes the passed code point into a series of bytes.
Definition numeric.c:3946
long rb_str_coderange_scan_restartable(const char *str, const char *end, rb_encoding *enc, int *cr)
Scans the passed string until it finds something odd.
Definition string.c:844
int rb_econv_prepare_options(VALUE opthash, VALUE *ecopts, int ecflags)
Identical to rb_econv_prepare_opts(), except it additionally takes the initial value of flags.
Definition transcode.c:2679
VALUE rb_econv_open_exc(const char *senc, const char *denc, int ecflags)
Creates a rb_eConverterNotFoundError exception object (but does not raise).
Definition transcode.c:2126
rb_econv_result_t rb_econv_convert(rb_econv_t *ec, const unsigned char **source_buffer_ptr, const unsigned char *source_buffer_end, unsigned char **destination_buffer_ptr, unsigned char *destination_buffer_end, int flags)
Converts a string from an encoding to another.
Definition transcode.c:1487
rb_econv_result_t
return value of rb_econv_convert()
Definition transcode.h:30
@ econv_incomplete_input
The conversion stopped in middle of reading a character, possibly due to a partial read of a socket e...
Definition transcode.h:69
@ econv_finished
The conversion stopped after converting everything.
Definition transcode.h:57
@ econv_undefined_conversion
The conversion stopped when it found a character in the input which cannot be representable in the ou...
Definition transcode.h:41
@ econv_source_buffer_empty
The conversion stopped because there is no input.
Definition transcode.h:51
@ econv_destination_buffer_full
The conversion stopped because there is no destination.
Definition transcode.h:46
@ econv_invalid_byte_sequence
The conversion stopped when it found an invalid sequence.
Definition transcode.h:35
int rb_econv_putbackable(rb_econv_t *ec)
Queries if rb_econv_putback() makes sense, i.e.
Definition transcode.c:1783
const char * rb_econv_asciicompat_encoding(const char *encname)
Queries the passed encoding's corresponding ASCII compatible encoding.
Definition transcode.c:1827
VALUE rb_econv_str_convert(rb_econv_t *ec, VALUE src, int flags)
Identical to rb_econv_convert(), except it takes Ruby's string instead of C's pointer.
Definition transcode.c:1962
rb_econv_t * rb_econv_open_opts(const char *source_encoding, const char *destination_encoding, int ecflags, VALUE ecopts)
Identical to rb_econv_open(), except it additionally takes a hash of optional strings.
Definition transcode.c:2730
void rb_econv_binmode(rb_econv_t *ec)
This badly named function does not set the destination encoding to binary, but instead just nullifies...
Definition transcode.c:2025
VALUE rb_str_encode(VALUE str, VALUE to, int ecflags, VALUE ecopts)
Converts the contents of the passed string from its encoding to the passed one.
Definition transcode.c:2993
VALUE rb_econv_make_exception(rb_econv_t *ec)
This function makes sense right after rb_econv_convert() returns.
Definition transcode.c:4359
void rb_econv_check_error(rb_econv_t *ec)
This is a rb_econv_make_exception() + rb_exc_raise() combo.
Definition transcode.c:4365
void rb_econv_close(rb_econv_t *ec)
Destructs a converter.
Definition transcode.c:1744
void rb_econv_putback(rb_econv_t *ec, unsigned char *p, int n)
Puts back the bytes.
Definition transcode.c:1794
VALUE rb_funcall(VALUE recv, ID mid, int n,...)
Calls a method.
Definition vm_eval.c:1123
VALUE rb_funcallv_kw(VALUE recv, ID mid, int argc, const VALUE *argv, int kw_splat)
Identical to rb_funcallv(), except you can specify how to handle the last element of the given array.
Definition vm_eval.c:1090
VALUE rb_funcallv(VALUE recv, ID mid, int argc, const VALUE *argv)
Identical to rb_funcall(), except it takes the method arguments as a C array.
Definition vm_eval.c:1081
Defines RBIMPL_HAS_BUILTIN.
VALUE rb_ary_concat(VALUE lhs, VALUE rhs)
Destructively appends the contents of latter into the end of former.
VALUE rb_ary_shift(VALUE ary)
Destructively deletes an element from the beginning of the passed array and returns what was deleted.
VALUE rb_check_array_type(VALUE obj)
Try converting an object to its array representation using its to_ary method, if any.
VALUE rb_ary_new(void)
Allocates a new, empty array.
VALUE rb_ary_new_capa(long capa)
Identical to rb_ary_new(), except it additionally specifies how many rooms of objects it should alloc...
VALUE rb_ary_push(VALUE ary, VALUE elem)
Special case of rb_ary_cat() that it adds only one element.
VALUE rb_ary_entry(VALUE ary, long off)
Queries an element of an array.
VALUE rb_assoc_new(VALUE car, VALUE cdr)
Identical to rb_ary_new_from_values(), except it expects exactly two parameters.
#define RETURN_ENUMERATOR(obj, argc, argv)
Identical to RETURN_SIZED_ENUMERATOR(), except its size is unknown.
Definition enumerator.h:242
static int rb_check_arity(int argc, int min, int max)
Ensures that the passed integer is in the passed range.
Definition error.h:284
VALUE rb_io_printf(int argc, const VALUE *argv, VALUE io)
This is a rb_f_sprintf() + rb_io_write() combo.
Definition io.c:8910
VALUE rb_io_gets(VALUE io)
Reads a "line" from the given IO.
Definition io.c:4599
int rb_cloexec_pipe(int fildes[2])
Opens a pipe with closing on exec.
Definition io.c:511
VALUE rb_io_print(int argc, const VALUE *argv, VALUE io)
Iterates over the passed array to apply rb_io_write() individually.
Definition io.c:9043
VALUE rb_io_addstr(VALUE io, VALUE str)
Identical to rb_io_write(), except it always returns the passed IO.
Definition io.c:2479
void rb_write_error(const char *str)
Writes the given error message to somewhere applicable.
Definition io.c:9472
VALUE rb_io_ungetbyte(VALUE io, VALUE b)
Identical to rb_io_ungetc(), except it doesn't take the encoding of the passed IO into account.
Definition io.c:5471
VALUE rb_io_getbyte(VALUE io)
Reads a byte from the given IO.
Definition io.c:5376
int rb_cloexec_dup2(int oldfd, int newfd)
Identical to rb_cloexec_dup(), except you can specify the destination file descriptor.
Definition io.c:409
VALUE rb_io_fdopen(int fd, int flags, const char *path)
Creates an IO instance whose backend is the given file descriptor.
Definition io.c:9653
void rb_update_max_fd(int fd)
Informs the interpreter that the passed fd can be the max.
Definition io.c:283
int rb_cloexec_open(const char *pathname, int flags, mode_t mode)
Opens a file that closes on exec.
Definition io.c:363
VALUE rb_output_rs
The record separator character for outputs, or the $\.
Definition io.c:208
VALUE rb_io_eof(VALUE io)
Queries if the passed IO is at the end of file.
Definition io.c:2821
void rb_write_error2(const char *str, long len)
Identical to rb_write_error(), except it additionally takes the message's length.
Definition io.c:9452
void rb_close_before_exec(int lowfd, int maxhint, VALUE noclose_fds)
Closes everything.
int rb_reserved_fd_p(int fd)
Queries if the given FD is reserved or not.
void rb_fd_fix_cloexec(int fd)
Sets or clears the close-on-exec flag of the passed file descriptor to the desired state.
Definition io.c:333
VALUE rb_io_ascii8bit_binmode(VALUE io)
Forces no conversions be applied to the passed IO.
Definition io.c:6714
VALUE rb_io_binmode(VALUE io)
Sets the binmode.
Definition io.c:6668
VALUE rb_io_ungetc(VALUE io, VALUE c)
"Unget"s a string.
Definition io.c:5535
int rb_pipe(int *pipes)
This is an rb_cloexec_pipe() + rb_update_max_fd() combo.
Definition io.c:7711
VALUE rb_gets(void)
Much like rb_io_gets(), but it reads from the mysterious ARGF object.
Definition io.c:10741
int rb_cloexec_fcntl_dupfd(int fd, int minfd)
Duplicates a file descriptor with closing on exec.
Definition io.c:517
VALUE rb_output_fs
The field separator character for outputs, or the $,.
Definition io.c:206
VALUE rb_file_open_str(VALUE fname, const char *fmode)
Identical to rb_file_open(), except it takes the pathname as a Ruby's string instead of C's.
Definition io.c:7599
int rb_cloexec_dup(int oldfd)
Identical to rb_cloexec_fcntl_dupfd(), except it implies minfd is 3.
Definition io.c:402
VALUE rb_file_open(const char *fname, const char *fmode)
Opens a file located at the given path.
Definition io.c:7606
VALUE rb_io_close(VALUE io)
Closes the IO.
Definition io.c:6071
VALUE rb_default_rs
This is the default value of rb_rs, i.e.
Definition io.c:209
void rb_provide(const char *feature)
Declares that the given feature is already provided by someone else.
Definition load.c:710
void rb_lastline_set(VALUE str)
Updates $_.
Definition vm.c:2149
VALUE rb_lastline_get(void)
Queries the last line, or the $_.
Definition vm.c:2143
int rb_obj_method_arity(VALUE obj, ID mid)
Identical to rb_mod_method_arity(), except it searches for singleton methods rather than instance met...
Definition proc.c:3761
rb_pid_t rb_waitpid(rb_pid_t pid, int *status, int flags)
Waits for a process, with releasing GVL.
Definition process.c:1161
void rb_last_status_set(int status, rb_pid_t pid)
Sets the "last status", or the $?.
Definition process.c:676
VALUE rb_str_append(VALUE dst, VALUE src)
Identical to rb_str_buf_append(), except it converts the right hand side before concatenating.
Definition string.c: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:1719
VALUE rb_exec_recursive(VALUE(*f)(VALUE g, VALUE h, int r), VALUE g, VALUE h)
"Recursion" API entry point.
VALUE rb_mutex_synchronize(VALUE mutex, VALUE(*func)(VALUE arg), VALUE arg)
Obtains the lock, runs the passed function, and releases the lock when it completes.
void rb_thread_check_ints(void)
Checks for interrupts.
Definition thread.c:1645
VALUE rb_thread_current(void)
Obtains the "current" thread.
Definition thread.c:3480
int rb_thread_wait_fd(int fd)
Blocks the current thread until the given file descriptor is ready to be read.
Definition io.c:1713
void rb_thread_sleep(int sec)
Blocks for the given period of time.
Definition thread.c:1668
struct timeval rb_time_interval(VALUE num)
Creates a "time interval".
Definition time.c:2984
void rb_set_class_path(VALUE klass, VALUE space, const char *name)
Names a class.
Definition variable.c:459
VALUE rb_ivar_set(VALUE obj, ID name, VALUE val)
Identical to rb_iv_set(), except it accepts the name as an ID instead of a C string.
Definition variable.c:2141
VALUE rb_class_name(VALUE obj)
Queries the name of the given object's class.
Definition variable.c:518
int rb_respond_to(VALUE obj, ID mid)
Queries if the object responds to the method.
Definition vm_method.c:3690
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:3568
VALUE rb_check_funcall(VALUE recv, ID mid, int argc, const VALUE *argv)
Identical to rb_funcallv(), except it returns RUBY_Qundef instead of raising rb_eNoMethodError.
Definition vm_eval.c:691
void rb_define_alloc_func(VALUE klass, rb_alloc_func_t func)
Sets the allocator function of a class.
static ID rb_intern_const(const char *str)
This is a "tiny optimisation" over rb_intern().
Definition symbol.h:285
#define RB_ID2SYM
Just another name of rb_id2sym.
Definition symbol.h:42
void rb_define_global_const(const char *name, VALUE val)
Identical to rb_define_const(), except it defines that of "global", i.e.
Definition variable.c:4095
void rb_define_readonly_variable(const char *name, const VALUE *var)
Identical to rb_define_variable(), except it does not allow Ruby programs to assign values to such gl...
Definition variable.c:890
rb_gvar_setter_t rb_gvar_readonly_setter
This function just raises rb_eNameError.
Definition variable.h:135
#define FMODE_READABLE
The IO is opened for reading.
Definition io.h:162
enum rb_io_mode rb_io_modestr_fmode(const char *modestr)
Maps a file mode string (that rb_file_open() takes) into a mixture of FMODE_ flags.
Definition io.c:6800
VALUE rb_io_get_io(VALUE io)
Identical to rb_io_check_io(), except it raises exceptions on conversion failures.
Definition io.c:869
VALUE rb_io_timeout(VALUE io)
Get the timeout associated with the specified io object.
Definition io.c:915
VALUE rb_io_taint_check(VALUE obj)
Definition io.c:839
void rb_io_read_check(rb_io_t *fptr)
Blocks until there is a pending read in the passed IO.
Definition io.c:1153
int rb_io_modestr_oflags(const char *modestr)
Identical to rb_io_modestr_fmode(), except it returns a mixture of O_ flags.
Definition io.c:6933
#define FMODE_SETENC_BY_BOM
This flag amends the encoding of the IO so that the BOM of the contents of the IO takes effect.
Definition io.h:260
rb_io_event
Type of events that an IO can wait.
Definition io.h:96
@ RUBY_IO_READABLE
IO::READABLE
Definition io.h:97
@ RUBY_IO_PRIORITY
IO::PRIORITY
Definition io.h:99
@ RUBY_IO_WRITABLE
IO::WRITABLE
Definition io.h:98
#define FMODE_READWRITE
The IO is opened for both read/write.
Definition io.h:168
#define FMODE_EXTERNAL
This flag means that an IO object is wrapping an "external" file descriptor, which is owned by someth...
Definition io.h:252
#define GetOpenFile
This is an old name of RB_IO_POINTER.
Definition io.h:442
void rb_io_check_byte_readable(rb_io_t *fptr)
Asserts that an IO is opened for byte-based reading.
Definition io.c:1099
#define FMODE_TTY
The IO is a TTY.
Definition io.h:192
#define FMODE_CREATE
The IO is opened for creating.
Definition io.h:215
void rb_io_check_readable(rb_io_t *fptr)
Just another name of rb_io_check_byte_readable.
Definition io.c:1108
int rb_wait_for_single_fd(int fd, int events, struct timeval *tv)
Blocks until the passed file descriptor is ready for the passed events.
Definition io.c:1705
FILE * rb_fdopen(int fd, const char *modestr)
Identical to rb_io_stdio_file(), except it takes file descriptors instead of Ruby's IO.
Definition io.c:7416
int rb_io_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding **enc2_p, enum rb_io_mode *fmode_p)
This function breaks down the option hash that IO#initialize takes into components.
Definition io.c:7082
int rb_io_descriptor(VALUE io)
Returns an integer representing the numeric file descriptor for io.
Definition io.c:3020
#define FMODE_WRITABLE
The IO is opened for writing.
Definition io.h:165
FILE * rb_io_stdio_file(rb_io_t *fptr)
Finds or creates a stdio's file structure from a Ruby's one.
Definition io.c:9699
#define FMODE_APPEND
The IO is opened for appending.
Definition io.h:207
#define MakeOpenFile
This is an old name of RB_IO_OPEN.
Definition io.h:465
#define FMODE_DUPLEX
Ruby eventually detects that the IO is bidirectional.
Definition io.h:200
#define FMODE_BINMODE
The IO is in "binary mode".
Definition io.h:179
int rb_io_maybe_wait_readable(int error, VALUE io, VALUE timeout)
Blocks until the passed IO is ready for reading, if that makes sense for the passed errno.
Definition io.c:1772
int capa
Designed capacity of the buffer.
Definition io.h:11
#define RB_IO_POINTER(obj, fp)
Queries the underlying IO pointer.
Definition io.h:436
VALUE rb_io_maybe_wait(int error, VALUE io, VALUE events, VALUE timeout)
Identical to rb_io_wait() except it additionally takes previous errno.
Definition io.c:1725
VALUE rb_eIOTimeoutError
Indicates that a timeout has occurred while performing an IO operation.
Definition io.c:190
char * ptr
Pointer to the underlying memory region, of at least capa bytes.
Definition io.h:2
#define FMODE_SYNC
The IO is in "sync mode".
Definition io.h:186
int off
Offset inside of ptr.
Definition io.h:5
VALUE rb_io_path(VALUE io)
Returns the path for the given IO.
Definition io.c:3099
void rb_io_extract_modeenc(VALUE *vmode_p, VALUE *vperm_p, VALUE opthash, int *oflags_p, enum rb_io_mode *fmode_p, rb_io_enc_t *convconfig_p)
This function can be seen as an extended version of rb_io_extract_encoding_option() that not only con...
Definition io.c:7207
void rb_io_check_initialized(rb_io_t *fptr)
Asserts that the passed IO is initialised.
Definition io.c:846
#define FMODE_EXCL
This flag amends the effect of FMODE_CREATE, so that if there already is a file at the given path the...
Definition io.h:223
#define FMODE_TEXTMODE
The IO is in "text mode".
Definition io.h:243
int rb_io_fptr_finalize(rb_io_t *fptr)
Destroys the given IO.
Definition io.c:5982
VALUE rb_io_check_io(VALUE io)
Try converting an object to its IO representation using its to_io method, if any.
Definition io.c:875
VALUE rb_io_closed_p(VALUE io)
Returns whether or not the underlying IO is closed.
Definition io.c:6179
VALUE rb_io_set_timeout(VALUE io, VALUE timeout)
Set the timeout associated with the specified io object.
Definition io.c:944
ssize_t rb_io_bufwrite(VALUE io, const void *buf, size_t size)
Buffered write to the passed IO.
Definition io.c:2136
void rb_io_check_char_readable(rb_io_t *fptr)
Asserts that an IO is opened for character-based reading.
Definition io.c:1080
#define FMODE_TRUNC
This flag amends the effect of FMODE_CREATE, so that if there already is a file at the given path it ...
Definition io.h:229
VALUE rb_io_get_write_io(VALUE io)
Queries the tied IO for writing.
Definition io.c:881
void rb_io_set_nonblock(rb_io_t *fptr)
Instructs the OS to put its internal file structure into "nonblocking mode".
Definition io.c:3586
int rb_io_wait_writable(int fd)
Blocks until the passed file descriptor gets writable.
Definition io.c:1661
VALUE rb_io_open_descriptor(VALUE klass, int descriptor, int mode, VALUE path, VALUE timeout, struct rb_io_encoding *encoding)
Allocate a new IO object, with the given file descriptor.
Definition io.c:9565
VALUE rb_io_set_write_io(VALUE io, VALUE w)
Assigns the tied IO for writing.
Definition io.c:892
void rb_io_check_writable(rb_io_t *fptr)
Asserts that an IO is opened for writing.
Definition io.c:1132
int rb_io_maybe_wait_writable(int error, VALUE io, VALUE timeout)
Blocks until the passed IO is ready for writing, if that makes sense for the passed errno.
Definition io.c:1787
void rb_io_check_closed(rb_io_t *fptr)
This badly named function asserts that the passed IO is open.
Definition io.c:854
int rb_io_wait_readable(int fd)
Blocks until the passed file descriptor gets readable.
Definition io.c:1626
void rb_io_synchronized(rb_io_t *fptr)
Sets FMODE_SYNC.
Definition io.c:7703
VALUE rb_io_wait(VALUE io, VALUE events, VALUE timeout)
Blocks until the passed IO is ready for the passed events.
Definition io.c:1566
int len
Length of the buffer.
Definition io.h:8
VALUE rb_ractor_stdin(void)
Queries the standard input of the current Ractor that is calling this function.
Definition ractor.c:1455
void rb_ractor_stderr_set(VALUE io)
Assigns an IO to the standard error of the Ractor that is calling this function.
Definition ractor.c:1524
void rb_ractor_stdout_set(VALUE io)
Assigns an IO to the standard output of the Ractor that is calling this function.
Definition ractor.c:1512
void rb_ractor_stdin_set(VALUE io)
Assigns an IO to the standard input of the Ractor that is calling this function.
Definition ractor.c:1500
void * rb_thread_call_with_gvl(void *(*func)(void *), void *data1)
(Re-)acquires the GVL.
Definition thread.c:2319
#define RB_NUM2INT
Just another name of rb_num2int_inline.
Definition int.h:38
#define RB_INT2NUM
Just another name of rb_int2num_inline.
Definition int.h:37
VALUE rb_f_sprintf(int argc, const VALUE *argv)
Identical to rb_str_format(), except how the arguments are arranged.
Definition sprintf.c:232
#define RB_BLOCK_CALL_FUNC_ARGLIST(yielded_arg, callback_arg)
Shim for block function parameters.
Definition iterator.h:58
VALUE rb_yield_values2(int n, const VALUE *argv)
Identical to rb_yield_values(), except it takes the parameters as a C array instead of variadic argum...
Definition vm_eval.c:1423
VALUE rb_yield(VALUE val)
Yields the block.
Definition vm_eval.c:1378
void rb_fd_term(rb_fdset_t *f)
Destroys the rb_fdset_t, releasing any memory and resources it used.
#define MEMZERO(p, type, n)
Handy macro to erase a region of memory.
Definition memory.h:360
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
Definition memory.h:167
#define MEMMOVE(p1, p2, type, n)
Handy macro to call memmove.
Definition memory.h:384
#define NUM2MODET
Converts a C's mode_t into an instance of rb_cInteger.
Definition mode_t.h:28
void rb_define_hooked_variable(const char *q, VALUE *w, type *e, void_type *r)
Define a function-backended global variable.
void rb_define_virtual_variable(const char *q, type *w, void_type *e)
Define a function-backended global variable.
VALUE rb_rescue2(type *q, VALUE w, type *e, VALUE r,...)
An equivalent of rescue clause.
VALUE rb_ensure(type *q, VALUE w, type *e, VALUE r)
An equivalent of ensure clause.
#define PRI_OFFT_PREFIX
A rb_sprintf() format prefix to be used for an off_t parameter.
Definition off_t.h:55
#define OFFT2NUM
Converts a C's off_t into an instance of rb_cInteger.
Definition off_t.h:33
#define NUM2OFFT
Converts an instance of rb_cNumeric into C's off_t.
Definition off_t.h:44
#define PIDT2NUM
Converts a C's pid_t into an instance of rb_cInteger.
Definition pid_t.h:28
#define rb_fd_isset
Queries if the given fd is in the rb_fdset_t.
Definition posix.h:60
#define rb_fd_select
Waits for multiple file descriptors at once.
Definition posix.h:66
#define rb_fd_init
Initialises the :given :rb_fdset_t.
Definition posix.h:63
#define rb_fd_set
Sets the given fd to the rb_fdset_t.
Definition posix.h:54
#define RARRAY_LEN
Just another name of rb_array_len.
Definition rarray.h:50
static int RARRAY_LENINT(VALUE ary)
Identical to rb_array_len(), except it differs for the return type.
Definition rarray.h:280
#define RARRAY_AREF(a, i)
Definition rarray.h:402
#define RARRAY_CONST_PTR
Just another name of rb_array_const_ptr.
Definition rarray.h:51
#define RFILE(obj)
Convenient casting macro.
Definition rfile.h:50
#define StringValue(v)
Ensures that the parameter object is a String.
Definition rstring.h:66
static char * RSTRING_END(VALUE str)
Queries the end of the contents pointer of the string.
Definition rstring.h:409
#define RSTRING_GETMEM(str, ptrvar, lenvar)
Convenient macro to obtain the contents and length at once.
Definition rstring.h:450
#define StringValueCStr(v)
Identical to StringValuePtr, except it additionally checks for the contents for viability as a C stri...
Definition rstring.h:89
#define RUBY_TYPED_DEFAULT_FREE
This is a value you can set to rb_data_type_struct::dfree.
Definition rtypeddata.h:81
#define TypedData_Make_Struct(klass, type, data_type, sval)
Identical to TypedData_Wrap_Struct, except it allocates a new data region internally instead of takin...
Definition rtypeddata.h:604
VALUE rb_get_argv(void)
Queries the arguments passed to the current process that you can access from Ruby as ARGV.
Definition io.c:14990
void rb_p(VALUE obj)
Inspects an object.
Definition io.c:9351
#define FilePathValue(v)
Ensures that the parameter object is a path.
Definition ruby.h:90
#define errno
Ractor-aware version of errno.
Definition ruby.h:388
#define RB_SCAN_ARGS_LAST_HASH_KEYWORDS
Treat a final argument as keywords if it is a hash, and not as keywords otherwise.
Definition scan_args.h:59
#define RB_PASS_CALLED_KEYWORDS
Pass keywords if current method is called with keywords, useful for argument delegation.
Definition scan_args.h:78
int rb_thread_fd_select(int nfds, rb_fdset_t *rfds, rb_fdset_t *wfds, rb_fdset_t *efds, struct timeval *timeout)
Waits for multiple file descriptors at once.
Definition thread.c:4853
static bool RB_TEST(VALUE obj)
Emulates Ruby's "if" statement.
@ RUBY_Qfalse
#define RTEST
This is an old name of RB_TEST.
#define _(args)
This was a transition path from K&R to ANSI.
Definition stdarg.h:35
C99 shim for <stdbool.h>
Ruby's File and IO.
Definition rfile.h:35
Definition io.c:238
Definition win32.h:196
This is the struct that holds necessary info for a struct.
Definition rtypeddata.h:242
The data structure which wraps the fd_set bitmap used by select(2).
Definition largesize.h:71
Decomposed encoding flags (e.g.
Definition io.h:134
int ecflags
Flags.
Definition io.h:144
VALUE ecopts
Flags as Ruby hash.
Definition io.h:152
rb_encoding * enc2
External encoding.
Definition io.h:138
rb_encoding * enc
Internal encoding.
Definition io.h:136
IO buffers.
Definition io.h:109
char * ptr
Pointer to the underlying memory region, of at least capa bytes.
Definition io.h:112
int off
Offset inside of ptr.
Definition io.h:115
int len
Length of the buffer.
Definition io.h:118
int capa
Designed capacity of the buffer.
Definition io.h:121
Ruby's IO, metadata and buffers.
Definition io.h:295
rb_io_buffer_t wbuf
Write buffer.
Definition io.h:330
enum rb_io_mode mode
mode flags: FMODE_XXXs
Definition io.h:310
void(* finalize)(struct rb_io *, int)
finalize proc
Definition io.h:326
rb_econv_t * readconv
Encoding converter used when reading from this IO.
Definition io.h:352
rb_econv_t * writeconv
Encoding converter used when writing to this IO.
Definition io.h:363
struct rb_io_encoding encs
Decomposed encoding flags.
Definition io.h:348
VALUE self
The IO's Ruby level counterpart.
Definition io.h:298
VALUE write_lock
This is a Ruby level mutex.
Definition io.h:400
VALUE timeout
The timeout associated with this IO when performing blocking operations.
Definition io.h:406
FILE * stdio_file
stdio ptr for read/write, if available.
Definition io.h:302
VALUE writeconv_pre_ecopts
Value of ::rb_io_t::rb_io_enc_t::ecopts stored right before initialising rb_io_t::writeconv.
Definition io.h:390
VALUE tied_io_for_writing
Duplex IO object, if set.
Definition io.h:345
int writeconv_initialized
Whether rb_io_t::writeconv is already set up.
Definition io.h:376
int fd
file descriptor.
Definition io.h:306
rb_io_buffer_t rbuf
(Byte) read buffer.
Definition io.h:337
int lineno
number of lines read
Definition io.h:318
struct ccan_list_head blocking_operations
Threads that are performing a blocking operation without the GVL using this IO.
Definition io.h:134
VALUE writeconv_asciicompat
This is, when set, an instance of rb_cString which holds the "common" encoding.
Definition io.h:372
rb_io_buffer_t cbuf
rb_io_ungetc() destination.
Definition io.h:359
rb_pid_t pid
child's pid (for pipes)
Definition io.h:314
int writeconv_pre_ecflags
Value of ::rb_io_t::rb_io_enc_t::ecflags stored right before initialising rb_io_t::writeconv.
Definition io.h:383
VALUE pathv
pathname for file
Definition io.h:322
intptr_t SIGNED_VALUE
A signed integer type that has the same width with VALUE.
Definition value.h:63
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
Definition value.h:52
uintptr_t VALUE
Type that represents a Ruby object.
Definition value.h:40
static bool RB_FLOAT_TYPE_P(VALUE obj)
Queries if the object is an instance of rb_cFloat.
Definition value_type.h:264
static bool RB_SYMBOL_P(VALUE obj)
Queries if the object is an instance of rb_cSymbol.
Definition value_type.h:307
static void Check_Type(VALUE v, enum ruby_value_type t)
Identical to RB_TYPE_P(), except it raises exceptions on predication failure.
Definition value_type.h:425
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.
Definition value_type.h:376
#define RBIMPL_WARNING_IGNORED(flag)
Suppresses a warning.
#define RBIMPL_WARNING_PUSH()
Pushes compiler warning state.
#define RBIMPL_WARNING_POP()
Pops compiler warning state.