Ruby 3.2.3p157 (2024-01-18 revision 52bb2ac0a6971d0391efa2275f7a66bff319087c)
io.c
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#ifdef _WIN32
20# include "ruby/ruby.h"
21# include "ruby/io.h"
22#endif
23
24#include <ctype.h>
25#include <errno.h>
26#include <stddef.h>
27
28/* non-Linux poll may not work on all FDs */
29#if defined(HAVE_POLL)
30# if defined(__linux__)
31# define USE_POLL 1
32# endif
33# if defined(__FreeBSD_version) && __FreeBSD_version >= 1100000
34# define USE_POLL 1
35# endif
36#endif
37
38#ifndef USE_POLL
39# define USE_POLL 0
40#endif
41
42#undef free
43#define free(x) xfree(x)
44
45#if defined(DOSISH) || defined(__CYGWIN__)
46#include <io.h>
47#endif
48
49#include <sys/types.h>
50#if defined HAVE_NET_SOCKET_H
51# include <net/socket.h>
52#elif defined HAVE_SYS_SOCKET_H
53# include <sys/socket.h>
54#endif
55
56#if defined(__BOW__) || defined(__CYGWIN__) || defined(_WIN32)
57# define NO_SAFE_RENAME
58#endif
59
60#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__sun) || defined(_nec_ews)
61# define USE_SETVBUF
62#endif
63
64#ifdef __QNXNTO__
65#include <unix.h>
66#endif
67
68#include <sys/types.h>
69#if defined(HAVE_SYS_IOCTL_H) && !defined(_WIN32)
70#include <sys/ioctl.h>
71#endif
72#if defined(HAVE_FCNTL_H) || defined(_WIN32)
73#include <fcntl.h>
74#elif defined(HAVE_SYS_FCNTL_H)
75#include <sys/fcntl.h>
76#endif
77
78#ifdef HAVE_SYS_TIME_H
79# include <sys/time.h>
80#endif
81
82#include <sys/stat.h>
83
84#if defined(HAVE_SYS_PARAM_H) || defined(__HIUX_MPP__)
85# include <sys/param.h>
86#endif
87
88#if !defined NOFILE
89# define NOFILE 64
90#endif
91
92#ifdef HAVE_UNISTD_H
93#include <unistd.h>
94#endif
95
96#ifdef HAVE_SYSCALL_H
97#include <syscall.h>
98#elif defined HAVE_SYS_SYSCALL_H
99#include <sys/syscall.h>
100#endif
101
102#ifdef HAVE_SYS_UIO_H
103#include <sys/uio.h>
104#endif
105
106#ifdef HAVE_SYS_WAIT_H
107# include <sys/wait.h> /* for WNOHANG on BSD */
108#endif
109
110#ifdef HAVE_COPYFILE_H
111# include <copyfile.h>
112#endif
113
115#include "ccan/list/list.h"
116#include "dln.h"
117#include "encindex.h"
118#include "id.h"
119#include "internal.h"
120#include "internal/encoding.h"
121#include "internal/error.h"
122#include "internal/inits.h"
123#include "internal/io.h"
124#include "internal/numeric.h"
125#include "internal/object.h"
126#include "internal/process.h"
127#include "internal/thread.h"
128#include "internal/transcode.h"
129#include "internal/variable.h"
130#include "ruby/io.h"
131#include "ruby/io/buffer.h"
132#include "ruby/missing.h"
133#include "ruby/thread.h"
134#include "ruby/util.h"
135#include "ruby_atomic.h"
136#include "ruby/ractor.h"
137
138#if !USE_POLL
139# include "vm_core.h"
140#endif
141
142#include "builtin.h"
143
144#ifndef O_ACCMODE
145#define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR)
146#endif
147
148#ifndef PIPE_BUF
149# ifdef _POSIX_PIPE_BUF
150# define PIPE_BUF _POSIX_PIPE_BUF
151# else
152# define PIPE_BUF 512 /* is this ok? */
153# endif
154#endif
155
156#ifndef EWOULDBLOCK
157# define EWOULDBLOCK EAGAIN
158#endif
159
160#if defined(HAVE___SYSCALL) && (defined(__APPLE__) || defined(__OpenBSD__))
161/* Mac OS X and OpenBSD have __syscall but don't define it in headers */
162off_t __syscall(quad_t number, ...);
163#endif
164
165#define IO_RBUF_CAPA_MIN 8192
166#define IO_CBUF_CAPA_MIN (128*1024)
167#define IO_RBUF_CAPA_FOR(fptr) (NEED_READCONV(fptr) ? IO_CBUF_CAPA_MIN : IO_RBUF_CAPA_MIN)
168#define IO_WBUF_CAPA_MIN 8192
169
170#define IO_MAX_BUFFER_GROWTH 8 * 1024 * 1024 // 8MB
171
172/* define system APIs */
173#ifdef _WIN32
174#undef open
175#define open rb_w32_uopen
176#undef rename
177#define rename(f, t) rb_w32_urename((f), (t))
178#endif
179
186
187static VALUE rb_eEAGAINWaitReadable;
188static VALUE rb_eEAGAINWaitWritable;
189static VALUE rb_eEWOULDBLOCKWaitReadable;
190static VALUE rb_eEWOULDBLOCKWaitWritable;
191static VALUE rb_eEINPROGRESSWaitWritable;
192static VALUE rb_eEINPROGRESSWaitReadable;
193
195static VALUE orig_stdout, orig_stderr;
196
197VALUE rb_output_fs;
198VALUE rb_rs;
201
202static VALUE argf;
203
204static ID id_write, id_read, id_getc, id_flush, id_readpartial, id_set_encoding, id_fileno;
205static VALUE sym_mode, sym_perm, sym_flags, sym_extenc, sym_intenc, sym_encoding, sym_open_args;
206static VALUE sym_textmode, sym_binmode, sym_autoclose;
207static VALUE sym_SET, sym_CUR, sym_END;
208static VALUE sym_wait_readable, sym_wait_writable;
209#ifdef SEEK_DATA
210static VALUE sym_DATA;
211#endif
212#ifdef SEEK_HOLE
213static VALUE sym_HOLE;
214#endif
215
216static VALUE prep_io(int fd, int fmode, VALUE klass, const char *path);
217
218struct argf {
219 VALUE filename, current_file;
220 long last_lineno; /* $. */
221 long lineno;
222 VALUE argv;
223 VALUE inplace;
224 struct rb_io_enc_t encs;
225 int8_t init_p, next_p, binmode;
226};
227
228static rb_atomic_t max_file_descriptor = NOFILE;
229void
231{
232 rb_atomic_t afd = (rb_atomic_t)fd;
233 rb_atomic_t max_fd = max_file_descriptor;
234 int err;
235
236 if (fd < 0 || afd <= max_fd)
237 return;
238
239#if defined(HAVE_FCNTL) && defined(F_GETFL)
240 err = fcntl(fd, F_GETFL) == -1;
241#else
242 {
243 struct stat buf;
244 err = fstat(fd, &buf) != 0;
245 }
246#endif
247 if (err && errno == EBADF) {
248 rb_bug("rb_update_max_fd: invalid fd (%d) given.", fd);
249 }
250
251 while (max_fd < afd) {
252 max_fd = ATOMIC_CAS(max_file_descriptor, max_fd, afd);
253 }
254}
255
256void
257rb_maygvl_fd_fix_cloexec(int fd)
258{
259 /* MinGW don't have F_GETFD and FD_CLOEXEC. [ruby-core:40281] */
260#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
261 int flags, flags2, ret;
262 flags = fcntl(fd, F_GETFD); /* should not fail except EBADF. */
263 if (flags == -1) {
264 rb_bug("rb_maygvl_fd_fix_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(errno));
265 }
266 if (fd <= 2)
267 flags2 = flags & ~FD_CLOEXEC; /* Clear CLOEXEC for standard file descriptors: 0, 1, 2. */
268 else
269 flags2 = flags | FD_CLOEXEC; /* Set CLOEXEC for non-standard file descriptors: 3, 4, 5, ... */
270 if (flags != flags2) {
271 ret = fcntl(fd, F_SETFD, flags2);
272 if (ret != 0) {
273 rb_bug("rb_maygvl_fd_fix_cloexec: fcntl(%d, F_SETFD, %d) failed: %s", fd, flags2, strerror(errno));
274 }
275 }
276#endif
277}
278
279void
281{
282 rb_maygvl_fd_fix_cloexec(fd);
284}
285
286/* this is only called once */
287static int
288rb_fix_detect_o_cloexec(int fd)
289{
290#if defined(O_CLOEXEC) && defined(F_GETFD)
291 int flags = fcntl(fd, F_GETFD);
292
293 if (flags == -1)
294 rb_bug("rb_fix_detect_o_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(errno));
295
296 if (flags & FD_CLOEXEC)
297 return 1;
298#endif /* fall through if O_CLOEXEC does not work: */
299 rb_maygvl_fd_fix_cloexec(fd);
300 return 0;
301}
302
303static inline bool
304io_again_p(int e)
305{
306 return (e == EWOULDBLOCK) || (e == EAGAIN);
307}
308
309int
310rb_cloexec_open(const char *pathname, int flags, mode_t mode)
311{
312 int ret;
313 static int o_cloexec_state = -1; /* <0: unknown, 0: ignored, >0: working */
314
315 static const int retry_interval = 0;
316 static const int retry_max_count = 10000;
317
318 int retry_count = 0;
319
320#ifdef O_CLOEXEC
321 /* O_CLOEXEC is available since Linux 2.6.23. Linux 2.6.18 silently ignore it. */
322 flags |= O_CLOEXEC;
323#elif defined O_NOINHERIT
324 flags |= O_NOINHERIT;
325#endif
326
327 while ((ret = open(pathname, flags, mode)) == -1) {
328 int e = errno;
329 if (!io_again_p(e)) break;
330 if (retry_count++ >= retry_max_count) break;
331
332 sleep(retry_interval);
333 }
334
335 if (ret < 0) return ret;
336 if (ret <= 2 || o_cloexec_state == 0) {
337 rb_maygvl_fd_fix_cloexec(ret);
338 }
339 else if (o_cloexec_state > 0) {
340 return ret;
341 }
342 else {
343 o_cloexec_state = rb_fix_detect_o_cloexec(ret);
344 }
345 return ret;
346}
347
348int
350{
351 /* Don't allocate standard file descriptors: 0, 1, 2 */
352 return rb_cloexec_fcntl_dupfd(oldfd, 3);
353}
354
355int
356rb_cloexec_dup2(int oldfd, int newfd)
357{
358 int ret;
359
360 /* When oldfd == newfd, dup2 succeeds but dup3 fails with EINVAL.
361 * rb_cloexec_dup2 succeeds as dup2. */
362 if (oldfd == newfd) {
363 ret = newfd;
364 }
365 else {
366#if defined(HAVE_DUP3) && defined(O_CLOEXEC)
367 static int try_dup3 = 1;
368 if (2 < newfd && try_dup3) {
369 ret = dup3(oldfd, newfd, O_CLOEXEC);
370 if (ret != -1)
371 return ret;
372 /* dup3 is available since Linux 2.6.27, glibc 2.9. */
373 if (errno == ENOSYS) {
374 try_dup3 = 0;
375 ret = dup2(oldfd, newfd);
376 }
377 }
378 else {
379 ret = dup2(oldfd, newfd);
380 }
381#else
382 ret = dup2(oldfd, newfd);
383#endif
384 if (ret < 0) return ret;
385 }
386 rb_maygvl_fd_fix_cloexec(ret);
387 return ret;
388}
389
390static int
391rb_fd_set_nonblock(int fd)
392{
393#ifdef _WIN32
394 return rb_w32_set_nonblock(fd);
395#elif defined(F_GETFL)
396 int oflags = fcntl(fd, F_GETFL);
397
398 if (oflags == -1)
399 return -1;
400 if (oflags & O_NONBLOCK)
401 return 0;
402 oflags |= O_NONBLOCK;
403 return fcntl(fd, F_SETFL, oflags);
404#endif
405 return 0;
406}
407
408int
409rb_cloexec_pipe(int descriptors[2])
410{
411#ifdef HAVE_PIPE2
412 int result = pipe2(descriptors, O_CLOEXEC | O_NONBLOCK);
413#else
414 int result = pipe(descriptors);
415#endif
416
417 if (result < 0)
418 return result;
419
420#ifdef __CYGWIN__
421 if (result == 0 && descriptors[1] == -1) {
422 close(descriptors[0]);
423 descriptors[0] = -1;
424 errno = ENFILE;
425 return -1;
426 }
427#endif
428
429#ifndef HAVE_PIPE2
430 rb_maygvl_fd_fix_cloexec(descriptors[0]);
431 rb_maygvl_fd_fix_cloexec(descriptors[1]);
432
433#ifndef _WIN32
434 rb_fd_set_nonblock(descriptors[0]);
435 rb_fd_set_nonblock(descriptors[1]);
436#endif
437#endif
438
439 return result;
440}
441
442int
443rb_cloexec_fcntl_dupfd(int fd, int minfd)
444{
445 int ret;
446
447#if defined(HAVE_FCNTL) && defined(F_DUPFD_CLOEXEC) && defined(F_DUPFD)
448 static int try_dupfd_cloexec = 1;
449 if (try_dupfd_cloexec) {
450 ret = fcntl(fd, F_DUPFD_CLOEXEC, minfd);
451 if (ret != -1) {
452 if (ret <= 2)
453 rb_maygvl_fd_fix_cloexec(ret);
454 return ret;
455 }
456 /* F_DUPFD_CLOEXEC is available since Linux 2.6.24. Linux 2.6.18 fails with EINVAL */
457 if (errno == EINVAL) {
458 ret = fcntl(fd, F_DUPFD, minfd);
459 if (ret != -1) {
460 try_dupfd_cloexec = 0;
461 }
462 }
463 }
464 else {
465 ret = fcntl(fd, F_DUPFD, minfd);
466 }
467#elif defined(HAVE_FCNTL) && defined(F_DUPFD)
468 ret = fcntl(fd, F_DUPFD, minfd);
469#else
470 ret = dup(fd);
471 if (ret >= 0 && ret < minfd) {
472 const int prev_fd = ret;
473 ret = rb_cloexec_fcntl_dupfd(fd, minfd);
474 close(prev_fd);
475 }
476 return ret;
477#endif
478 if (ret < 0) return ret;
479 rb_maygvl_fd_fix_cloexec(ret);
480 return ret;
481}
482
483#define argf_of(obj) (*(struct argf *)DATA_PTR(obj))
484#define ARGF argf_of(argf)
485
486#define GetWriteIO(io) rb_io_get_write_io(io)
487
488#define READ_DATA_PENDING(fptr) ((fptr)->rbuf.len)
489#define READ_DATA_PENDING_COUNT(fptr) ((fptr)->rbuf.len)
490#define READ_DATA_PENDING_PTR(fptr) ((fptr)->rbuf.ptr+(fptr)->rbuf.off)
491#define READ_DATA_BUFFERED(fptr) READ_DATA_PENDING(fptr)
492
493#define READ_CHAR_PENDING(fptr) ((fptr)->cbuf.len)
494#define READ_CHAR_PENDING_COUNT(fptr) ((fptr)->cbuf.len)
495#define READ_CHAR_PENDING_PTR(fptr) ((fptr)->cbuf.ptr+(fptr)->cbuf.off)
496
497#if defined(_WIN32)
498#define WAIT_FD_IN_WIN32(fptr) \
499 (rb_w32_io_cancelable_p((fptr)->fd) ? Qnil : rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), RUBY_IO_TIMEOUT_DEFAULT))
500#else
501#define WAIT_FD_IN_WIN32(fptr)
502#endif
503
504#define READ_CHECK(fptr) do {\
505 if (!READ_DATA_PENDING(fptr)) {\
506 WAIT_FD_IN_WIN32(fptr);\
507 rb_io_check_closed(fptr);\
508 }\
509} while(0)
510
511#ifndef S_ISSOCK
512# ifdef _S_ISSOCK
513# define S_ISSOCK(m) _S_ISSOCK(m)
514# else
515# ifdef _S_IFSOCK
516# define S_ISSOCK(m) (((m) & S_IFMT) == _S_IFSOCK)
517# else
518# ifdef S_IFSOCK
519# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
520# endif
521# endif
522# endif
523#endif
524
525static int io_fflush(rb_io_t *);
526static rb_io_t *flush_before_seek(rb_io_t *fptr);
527
528#define FMODE_PREP (1<<16)
529#define FMODE_SIGNAL_ON_EPIPE (1<<17)
530
531#define fptr_signal_on_epipe(fptr) \
532 (((fptr)->mode & FMODE_SIGNAL_ON_EPIPE) != 0)
533
534#define fptr_set_signal_on_epipe(fptr, flag) \
535 ((flag) ? \
536 (fptr)->mode |= FMODE_SIGNAL_ON_EPIPE : \
537 (fptr)->mode &= ~FMODE_SIGNAL_ON_EPIPE)
538
539extern ID ruby_static_id_signo;
540
541NORETURN(static void raise_on_write(rb_io_t *fptr, int e, VALUE errinfo));
542static void
543raise_on_write(rb_io_t *fptr, int e, VALUE errinfo)
544{
545#if defined EPIPE
546 if (fptr_signal_on_epipe(fptr) && (e == EPIPE)) {
547 const VALUE sig =
548# if defined SIGPIPE
549 INT2FIX(SIGPIPE) - INT2FIX(0) +
550# endif
551 INT2FIX(0);
552 rb_ivar_set(errinfo, ruby_static_id_signo, sig);
553 }
554#endif
555 rb_exc_raise(errinfo);
556}
557
558#define rb_sys_fail_on_write(fptr) \
559 do { \
560 int e = errno; \
561 raise_on_write(fptr, e, rb_syserr_new_path(e, (fptr)->pathv)); \
562 } while (0)
563
564#define NEED_NEWLINE_DECORATOR_ON_READ(fptr) ((fptr)->mode & FMODE_TEXTMODE)
565#define NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) ((fptr)->mode & FMODE_TEXTMODE)
566#if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)
567# define RUBY_CRLF_ENVIRONMENT 1
568#else
569# define RUBY_CRLF_ENVIRONMENT 0
570#endif
571
572#if RUBY_CRLF_ENVIRONMENT
573/* Windows */
574# define DEFAULT_TEXTMODE FMODE_TEXTMODE
575# define TEXTMODE_NEWLINE_DECORATOR_ON_WRITE ECONV_CRLF_NEWLINE_DECORATOR
576/*
577 * CRLF newline is set as default newline decorator.
578 * If only CRLF newline conversion is needed, we use binary IO process
579 * with OS's text mode for IO performance improvement.
580 * If encoding conversion is needed or a user sets text mode, we use encoding
581 * conversion IO process and universal newline decorator by default.
582 */
583#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || (fptr)->encs.ecflags & ~ECONV_CRLF_NEWLINE_DECORATOR)
584#define WRITECONV_MASK ( \
585 (ECONV_DECORATOR_MASK & ~ECONV_CRLF_NEWLINE_DECORATOR)|\
586 ECONV_STATEFUL_DECORATOR_MASK|\
587 0)
588#define NEED_WRITECONV(fptr) ( \
589 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
590 ((fptr)->encs.ecflags & WRITECONV_MASK) || \
591 0)
592#define SET_BINARY_MODE(fptr) setmode((fptr)->fd, O_BINARY)
593
594#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) do {\
595 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {\
596 if (((fptr)->mode & FMODE_READABLE) &&\
597 !((fptr)->encs.ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {\
598 setmode((fptr)->fd, O_BINARY);\
599 }\
600 else {\
601 setmode((fptr)->fd, O_TEXT);\
602 }\
603 }\
604} while(0)
605
606#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) do {\
607 if ((enc2) && ((ecflags) & ECONV_DEFAULT_NEWLINE_DECORATOR)) {\
608 (ecflags) |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;\
609 }\
610} while(0)
611
612/*
613 * IO unread with taking care of removed '\r' in text mode.
614 */
615static void
616io_unread(rb_io_t *fptr)
617{
618 rb_off_t r, pos;
619 ssize_t read_size;
620 long i;
621 long newlines = 0;
622 long extra_max;
623 char *p;
624 char *buf;
625
626 rb_io_check_closed(fptr);
627 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX) {
628 return;
629 }
630
631 errno = 0;
632 if (!rb_w32_fd_is_text(fptr->fd)) {
633 r = lseek(fptr->fd, -fptr->rbuf.len, SEEK_CUR);
634 if (r < 0 && errno) {
635 if (errno == ESPIPE)
636 fptr->mode |= FMODE_DUPLEX;
637 return;
638 }
639
640 fptr->rbuf.off = 0;
641 fptr->rbuf.len = 0;
642 return;
643 }
644
645 pos = lseek(fptr->fd, 0, SEEK_CUR);
646 if (pos < 0 && errno) {
647 if (errno == ESPIPE)
648 fptr->mode |= FMODE_DUPLEX;
649 return;
650 }
651
652 /* add extra offset for removed '\r' in rbuf */
653 extra_max = (long)(pos - fptr->rbuf.len);
654 p = fptr->rbuf.ptr + fptr->rbuf.off;
655
656 /* if the end of rbuf is '\r', rbuf doesn't have '\r' within rbuf.len */
657 if (*(fptr->rbuf.ptr + fptr->rbuf.capa - 1) == '\r') {
658 newlines++;
659 }
660
661 for (i = 0; i < fptr->rbuf.len; i++) {
662 if (*p == '\n') newlines++;
663 if (extra_max == newlines) break;
664 p++;
665 }
666
667 buf = ALLOC_N(char, fptr->rbuf.len + newlines);
668 while (newlines >= 0) {
669 r = lseek(fptr->fd, pos - fptr->rbuf.len - newlines, SEEK_SET);
670 if (newlines == 0) break;
671 if (r < 0) {
672 newlines--;
673 continue;
674 }
675 read_size = _read(fptr->fd, buf, fptr->rbuf.len + newlines);
676 if (read_size < 0) {
677 int e = errno;
678 free(buf);
679 rb_syserr_fail_path(e, fptr->pathv);
680 }
681 if (read_size == fptr->rbuf.len) {
682 lseek(fptr->fd, r, SEEK_SET);
683 break;
684 }
685 else {
686 newlines--;
687 }
688 }
689 free(buf);
690 fptr->rbuf.off = 0;
691 fptr->rbuf.len = 0;
692 return;
693}
694
695/*
696 * We use io_seek to back cursor position when changing mode from text to binary,
697 * but stdin and pipe cannot seek back. Stdin and pipe read should use encoding
698 * conversion for working properly with mode change.
699 *
700 * Return previous translation mode.
701 */
702static inline int
703set_binary_mode_with_seek_cur(rb_io_t *fptr)
704{
705 if (!rb_w32_fd_is_text(fptr->fd)) return O_BINARY;
706
707 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX) {
708 return setmode(fptr->fd, O_BINARY);
709 }
710 flush_before_seek(fptr);
711 return setmode(fptr->fd, O_BINARY);
712}
713#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) set_binary_mode_with_seek_cur(fptr)
714
715#else
716/* Unix */
717# define DEFAULT_TEXTMODE 0
718#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || NEED_NEWLINE_DECORATOR_ON_READ(fptr))
719#define NEED_WRITECONV(fptr) ( \
720 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
721 NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) || \
722 ((fptr)->encs.ecflags & (ECONV_DECORATOR_MASK|ECONV_STATEFUL_DECORATOR_MASK)) || \
723 0)
724#define SET_BINARY_MODE(fptr) (void)(fptr)
725#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) (void)(fptr)
726#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) ((void)(enc2), (void)(ecflags))
727#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) (void)(fptr)
728#endif
729
730#if !defined HAVE_SHUTDOWN && !defined shutdown
731#define shutdown(a,b) 0
732#endif
733
734#if defined(_WIN32)
735#define is_socket(fd, path) rb_w32_is_socket(fd)
736#elif !defined(S_ISSOCK)
737#define is_socket(fd, path) 0
738#else
739static int
740is_socket(int fd, VALUE path)
741{
742 struct stat sbuf;
743 if (fstat(fd, &sbuf) < 0)
744 rb_sys_fail_path(path);
745 return S_ISSOCK(sbuf.st_mode);
746}
747#endif
748
749static const char closed_stream[] = "closed stream";
750
751static void
752io_fd_check_closed(int fd)
753{
754 if (fd < 0) {
755 rb_thread_check_ints(); /* check for ruby_error_stream_closed */
756 rb_raise(rb_eIOError, closed_stream);
757 }
758}
759
760void
761rb_eof_error(void)
762{
763 rb_raise(rb_eEOFError, "end of file reached");
764}
765
766VALUE
768{
769 rb_check_frozen(io);
770 return io;
771}
772
773void
775{
776 if (!fptr) {
777 rb_raise(rb_eIOError, "uninitialized stream");
778 }
779}
780
781void
783{
785 io_fd_check_closed(fptr->fd);
786}
787
788static rb_io_t *
789rb_io_get_fptr(VALUE io)
790{
791 rb_io_t *fptr = RFILE(io)->fptr;
793 return fptr;
794}
795
796VALUE
798{
799 return rb_convert_type_with_id(io, T_FILE, "IO", idTo_io);
800}
801
802VALUE
804{
805 return rb_check_convert_type_with_id(io, T_FILE, "IO", idTo_io);
806}
807
808VALUE
810{
811 VALUE write_io;
812 write_io = rb_io_get_fptr(io)->tied_io_for_writing;
813 if (write_io) {
814 return write_io;
815 }
816 return io;
817}
818
819VALUE
821{
822 VALUE write_io;
823 rb_io_t *fptr = rb_io_get_fptr(io);
824 if (!RTEST(w)) {
825 w = 0;
826 }
827 else {
828 GetWriteIO(w);
829 }
830 write_io = fptr->tied_io_for_writing;
831 fptr->tied_io_for_writing = w;
832 return write_io ? write_io : Qnil;
833}
834
835/*
836 * call-seq:
837 * timeout -> duration or nil
838 *
839 * Get the internal timeout duration or nil if it was not set.
840 *
841 */
842VALUE
844{
845 rb_io_t *fptr = rb_io_get_fptr(self);
846
847 return fptr->timeout;
848}
849
850/*
851 * call-seq:
852 * timeout = duration -> duration
853 * timeout = nil -> nil
854 *
855 * Set the internal timeout to the specified duration or nil. The timeout
856 * applies to all blocking operations where possible.
857 *
858 * This affects the following methods (but is not limited to): #gets, #puts,
859 * #read, #write, #wait_readable and #wait_writable. This also affects
860 * blocking socket operations like Socket#accept and Socket#connect.
861 *
862 * Some operations like File#open and IO#close are not affected by the
863 * timeout. A timeout during a write operation may leave the IO in an
864 * inconsistent state, e.g. data was partially written. Generally speaking, a
865 * timeout is a last ditch effort to prevent an application from hanging on
866 * slow I/O operations, such as those that occur during a slowloris attack.
867 */
868VALUE
870{
871 // Validate it:
872 if (RTEST(timeout)) {
873 rb_time_interval(timeout);
874 }
875
876 rb_io_t *fptr = rb_io_get_fptr(self);
877
878 fptr->timeout = timeout;
879
880 return self;
881}
882
883/*
884 * call-seq:
885 * IO.try_convert(object) -> new_io or nil
886 *
887 * Attempts to convert +object+ into an \IO object via method +to_io+;
888 * returns the new \IO object if successful, or +nil+ otherwise:
889 *
890 * IO.try_convert(STDOUT) # => #<IO:<STDOUT>>
891 * IO.try_convert(ARGF) # => #<IO:<STDIN>>
892 * IO.try_convert('STDOUT') # => nil
893 *
894 */
895static VALUE
896rb_io_s_try_convert(VALUE dummy, VALUE io)
897{
898 return rb_io_check_io(io);
899}
900
901#if !RUBY_CRLF_ENVIRONMENT
902static void
903io_unread(rb_io_t *fptr)
904{
905 rb_off_t r;
906 rb_io_check_closed(fptr);
907 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX)
908 return;
909 /* xxx: target position may be negative if buffer is filled by ungetc */
910 errno = 0;
911 r = lseek(fptr->fd, -fptr->rbuf.len, SEEK_CUR);
912 if (r < 0 && errno) {
913 if (errno == ESPIPE)
914 fptr->mode |= FMODE_DUPLEX;
915 return;
916 }
917 fptr->rbuf.off = 0;
918 fptr->rbuf.len = 0;
919 return;
920}
921#endif
922
923static rb_encoding *io_input_encoding(rb_io_t *fptr);
924
925static void
926io_ungetbyte(VALUE str, rb_io_t *fptr)
927{
928 long len = RSTRING_LEN(str);
929
930 if (fptr->rbuf.ptr == NULL) {
931 const int min_capa = IO_RBUF_CAPA_FOR(fptr);
932 fptr->rbuf.off = 0;
933 fptr->rbuf.len = 0;
934#if SIZEOF_LONG > SIZEOF_INT
935 if (len > INT_MAX)
936 rb_raise(rb_eIOError, "ungetbyte failed");
937#endif
938 if (len > min_capa)
939 fptr->rbuf.capa = (int)len;
940 else
941 fptr->rbuf.capa = min_capa;
942 fptr->rbuf.ptr = ALLOC_N(char, fptr->rbuf.capa);
943 }
944 if (fptr->rbuf.capa < len + fptr->rbuf.len) {
945 rb_raise(rb_eIOError, "ungetbyte failed");
946 }
947 if (fptr->rbuf.off < len) {
948 MEMMOVE(fptr->rbuf.ptr+fptr->rbuf.capa-fptr->rbuf.len,
949 fptr->rbuf.ptr+fptr->rbuf.off,
950 char, fptr->rbuf.len);
951 fptr->rbuf.off = fptr->rbuf.capa-fptr->rbuf.len;
952 }
953 fptr->rbuf.off-=(int)len;
954 fptr->rbuf.len+=(int)len;
955 MEMMOVE(fptr->rbuf.ptr+fptr->rbuf.off, RSTRING_PTR(str), char, len);
956}
957
958static rb_io_t *
959flush_before_seek(rb_io_t *fptr)
960{
961 if (io_fflush(fptr) < 0)
962 rb_sys_fail_on_write(fptr);
963 io_unread(fptr);
964 errno = 0;
965 return fptr;
966}
967
968#define io_seek(fptr, ofs, whence) (errno = 0, lseek(flush_before_seek(fptr)->fd, (ofs), (whence)))
969#define io_tell(fptr) lseek(flush_before_seek(fptr)->fd, 0, SEEK_CUR)
970
971#ifndef SEEK_CUR
972# define SEEK_SET 0
973# define SEEK_CUR 1
974# define SEEK_END 2
975#endif
976
977void
979{
980 rb_io_check_closed(fptr);
981 if (!(fptr->mode & FMODE_READABLE)) {
982 rb_raise(rb_eIOError, "not opened for reading");
983 }
984 if (fptr->wbuf.len) {
985 if (io_fflush(fptr) < 0)
986 rb_sys_fail_on_write(fptr);
987 }
988 if (fptr->tied_io_for_writing) {
989 rb_io_t *wfptr;
990 GetOpenFile(fptr->tied_io_for_writing, wfptr);
991 if (io_fflush(wfptr) < 0)
992 rb_sys_fail_on_write(wfptr);
993 }
994}
995
996void
998{
1000 if (READ_CHAR_PENDING(fptr)) {
1001 rb_raise(rb_eIOError, "byte oriented read for character buffered IO");
1002 }
1003}
1004
1005void
1010
1011static rb_encoding*
1012io_read_encoding(rb_io_t *fptr)
1013{
1014 if (fptr->encs.enc) {
1015 return fptr->encs.enc;
1016 }
1017 return rb_default_external_encoding();
1018}
1019
1020static rb_encoding*
1021io_input_encoding(rb_io_t *fptr)
1022{
1023 if (fptr->encs.enc2) {
1024 return fptr->encs.enc2;
1025 }
1026 return io_read_encoding(fptr);
1027}
1028
1029void
1031{
1032 rb_io_check_closed(fptr);
1033 if (!(fptr->mode & FMODE_WRITABLE)) {
1034 rb_raise(rb_eIOError, "not opened for writing");
1035 }
1036 if (fptr->rbuf.len) {
1037 io_unread(fptr);
1038 }
1039}
1040
1041int
1042rb_io_read_pending(rb_io_t *fptr)
1043{
1044 /* This function is used for bytes and chars. Confusing. */
1045 if (READ_CHAR_PENDING(fptr))
1046 return 1; /* should raise? */
1047 return READ_DATA_PENDING(fptr);
1048}
1049
1050void
1052{
1053 if (!READ_DATA_PENDING(fptr)) {
1054 rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), RUBY_IO_TIMEOUT_DEFAULT);
1055 }
1056 return;
1057}
1058
1059int
1060rb_gc_for_fd(int err)
1061{
1062 if (err == EMFILE || err == ENFILE || err == ENOMEM) {
1063 rb_gc();
1064 return 1;
1065 }
1066 return 0;
1067}
1068
1069static int
1070ruby_dup(int orig)
1071{
1072 int fd;
1073
1074 fd = rb_cloexec_dup(orig);
1075 if (fd < 0) {
1076 int e = errno;
1077 if (rb_gc_for_fd(e)) {
1078 fd = rb_cloexec_dup(orig);
1079 }
1080 if (fd < 0) {
1081 rb_syserr_fail(e, 0);
1082 }
1083 }
1084 rb_update_max_fd(fd);
1085 return fd;
1086}
1087
1088static VALUE
1089io_alloc(VALUE klass)
1090{
1091 NEWOBJ_OF(io, struct RFile, klass, T_FILE);
1092
1093 io->fptr = 0;
1094
1095 return (VALUE)io;
1096}
1097
1098#ifndef S_ISREG
1099# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
1100#endif
1101
1103 VALUE th;
1104 rb_io_t *fptr;
1105 int nonblock;
1106 int fd;
1107
1108 void *buf;
1109 size_t capa;
1110 struct timeval *timeout;
1111};
1112
1114 VALUE th;
1115 rb_io_t *fptr;
1116 int nonblock;
1117 int fd;
1118
1119 const void *buf;
1120 size_t capa;
1121 struct timeval *timeout;
1122};
1123
1124#ifdef HAVE_WRITEV
1125struct io_internal_writev_struct {
1126 VALUE th;
1127 rb_io_t *fptr;
1128 int nonblock;
1129 int fd;
1130
1131 int iovcnt;
1132 const struct iovec *iov;
1133 struct timeval *timeout;
1134};
1135#endif
1136
1137static int nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout);
1138
1144static inline int
1145io_internal_wait(VALUE thread, rb_io_t *fptr, int error, int events, struct timeval *timeout)
1146{
1147 int ready = nogvl_wait_for(thread, fptr, events, timeout);
1148
1149 if (ready > 0) {
1150 return ready;
1151 } else if (ready == 0) {
1152 errno = ETIMEDOUT;
1153 return -1;
1154 }
1155
1156 errno = error;
1157 return -1;
1158}
1159
1160static VALUE
1161internal_read_func(void *ptr)
1162{
1163 struct io_internal_read_struct *iis = ptr;
1164 ssize_t result;
1165
1166 if (iis->timeout && !iis->nonblock) {
1167 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_IN, iis->timeout) == -1) {
1168 return -1;
1169 }
1170 }
1171
1172 retry:
1173 result = read(iis->fd, iis->buf, iis->capa);
1174
1175 if (result < 0 && !iis->nonblock) {
1176 if (io_again_p(errno)) {
1177 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_IN, iis->timeout) == -1) {
1178 return -1;
1179 } else {
1180 goto retry;
1181 }
1182 }
1183 }
1184
1185 return result;
1186}
1187
1188#if defined __APPLE__
1189# define do_write_retry(code) do {result = code;} while (result == -1 && errno == EPROTOTYPE)
1190#else
1191# define do_write_retry(code) result = code
1192#endif
1193
1194static VALUE
1195internal_write_func(void *ptr)
1196{
1197 struct io_internal_write_struct *iis = ptr;
1198 ssize_t result;
1199
1200 if (iis->timeout && !iis->nonblock) {
1201 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1202 return -1;
1203 }
1204 }
1205
1206 retry:
1207 do_write_retry(write(iis->fd, iis->buf, iis->capa));
1208
1209 if (result < 0 && !iis->nonblock) {
1210 int e = errno;
1211 if (io_again_p(e)) {
1212 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1213 return -1;
1214 } else {
1215 goto retry;
1216 }
1217 }
1218 }
1219
1220 return result;
1221}
1222
1223#ifdef HAVE_WRITEV
1224static VALUE
1225internal_writev_func(void *ptr)
1226{
1227 struct io_internal_writev_struct *iis = ptr;
1228 ssize_t result;
1229
1230 if (iis->timeout && !iis->nonblock) {
1231 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1232 return -1;
1233 }
1234 }
1235
1236 retry:
1237 do_write_retry(writev(iis->fd, iis->iov, iis->iovcnt));
1238
1239 if (result < 0 && !iis->nonblock) {
1240 if (io_again_p(errno)) {
1241 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1242 return -1;
1243 } else {
1244 goto retry;
1245 }
1246 }
1247 }
1248
1249 return result;
1250}
1251#endif
1252
1253static ssize_t
1254rb_io_read_memory(rb_io_t *fptr, void *buf, size_t count)
1255{
1256 VALUE scheduler = rb_fiber_scheduler_current();
1257 if (scheduler != Qnil) {
1258 VALUE result = rb_fiber_scheduler_io_read_memory(scheduler, fptr->self, buf, count, 0);
1259
1260 if (!UNDEF_P(result)) {
1262 }
1263 }
1264
1265 struct io_internal_read_struct iis = {
1266 .th = rb_thread_current(),
1267 .fptr = fptr,
1268 .nonblock = 0,
1269 .fd = fptr->fd,
1270
1271 .buf = buf,
1272 .capa = count,
1273 .timeout = NULL,
1274 };
1275
1276 struct timeval timeout_storage;
1277
1278 if (fptr->timeout != Qnil) {
1279 timeout_storage = rb_time_interval(fptr->timeout);
1280 iis.timeout = &timeout_storage;
1281 }
1282
1283 return (ssize_t)rb_thread_io_blocking_region(internal_read_func, &iis, fptr->fd);
1284}
1285
1286static ssize_t
1287rb_io_write_memory(rb_io_t *fptr, const void *buf, size_t count)
1288{
1289 VALUE scheduler = rb_fiber_scheduler_current();
1290 if (scheduler != Qnil) {
1291 VALUE result = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, buf, count, 0);
1292
1293 if (!UNDEF_P(result)) {
1295 }
1296 }
1297
1298 struct io_internal_write_struct iis = {
1299 .th = rb_thread_current(),
1300 .fptr = fptr,
1301 .nonblock = 0,
1302 .fd = fptr->fd,
1303
1304 .buf = buf,
1305 .capa = count,
1306 .timeout = NULL
1307 };
1308
1309 struct timeval timeout_storage;
1310
1311 if (fptr->timeout != Qnil) {
1312 timeout_storage = rb_time_interval(fptr->timeout);
1313 iis.timeout = &timeout_storage;
1314 }
1315
1316 return (ssize_t)rb_thread_io_blocking_region(internal_write_func, &iis, fptr->fd);
1317}
1318
1319#ifdef HAVE_WRITEV
1320static ssize_t
1321rb_writev_internal(rb_io_t *fptr, const struct iovec *iov, int iovcnt)
1322{
1323 if (!iovcnt) return 0;
1324
1325 VALUE scheduler = rb_fiber_scheduler_current();
1326 if (scheduler != Qnil) {
1327 // This path assumes at least one `iov`:
1328 VALUE result = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, iov[0].iov_base, iov[0].iov_len, 0);
1329
1330 if (!UNDEF_P(result)) {
1332 }
1333 }
1334
1335 struct io_internal_writev_struct iis = {
1336 .th = rb_thread_current(),
1337 .fptr = fptr,
1338 .nonblock = 0,
1339 .fd = fptr->fd,
1340
1341 .iov = iov,
1342 .iovcnt = iovcnt,
1343 .timeout = NULL
1344 };
1345
1346 struct timeval timeout_storage;
1347
1348 if (fptr->timeout != Qnil) {
1349 timeout_storage = rb_time_interval(fptr->timeout);
1350 iis.timeout = &timeout_storage;
1351 }
1352
1353 return (ssize_t)rb_thread_io_blocking_region(internal_writev_func, &iis, fptr->fd);
1354}
1355#endif
1356
1357static VALUE
1358io_flush_buffer_sync(void *arg)
1359{
1360 rb_io_t *fptr = arg;
1361 long l = fptr->wbuf.len;
1362 ssize_t r = write(fptr->fd, fptr->wbuf.ptr+fptr->wbuf.off, (size_t)l);
1363
1364 if (fptr->wbuf.len <= r) {
1365 fptr->wbuf.off = 0;
1366 fptr->wbuf.len = 0;
1367 return 0;
1368 }
1369
1370 if (0 <= r) {
1371 fptr->wbuf.off += (int)r;
1372 fptr->wbuf.len -= (int)r;
1373 errno = EAGAIN;
1374 }
1375
1376 return (VALUE)-1;
1377}
1378
1379static VALUE
1380io_flush_buffer_async(VALUE arg)
1381{
1382 rb_io_t *fptr = (rb_io_t *)arg;
1383 return rb_thread_io_blocking_region(io_flush_buffer_sync, fptr, fptr->fd);
1384}
1385
1386static inline int
1387io_flush_buffer(rb_io_t *fptr)
1388{
1389 if (!NIL_P(fptr->write_lock) && rb_mutex_owned_p(fptr->write_lock)) {
1390 return (int)io_flush_buffer_async((VALUE)fptr);
1391 }
1392 else {
1393 return (int)rb_mutex_synchronize(fptr->write_lock, io_flush_buffer_async, (VALUE)fptr);
1394 }
1395}
1396
1397static int
1398io_fflush(rb_io_t *fptr)
1399{
1400 rb_io_check_closed(fptr);
1401
1402 if (fptr->wbuf.len == 0)
1403 return 0;
1404
1405 while (fptr->wbuf.len > 0 && io_flush_buffer(fptr) != 0) {
1406 if (!rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT))
1407 return -1;
1408
1409 rb_io_check_closed(fptr);
1410 }
1411
1412 return 0;
1413}
1414
1415VALUE
1416rb_io_wait(VALUE io, VALUE events, VALUE timeout)
1417{
1418 VALUE scheduler = rb_fiber_scheduler_current();
1419
1420 if (scheduler != Qnil) {
1421 return rb_fiber_scheduler_io_wait(scheduler, io, events, timeout);
1422 }
1423
1424 rb_io_t * fptr = NULL;
1425 RB_IO_POINTER(io, fptr);
1426
1427 struct timeval tv_storage;
1428 struct timeval *tv = NULL;
1429
1430 if (NIL_OR_UNDEF_P(timeout)) {
1431 timeout = fptr->timeout;
1432 }
1433
1434 if (timeout != Qnil) {
1435 tv_storage = rb_time_interval(timeout);
1436 tv = &tv_storage;
1437 }
1438
1439 int ready = rb_thread_wait_for_single_fd(fptr->fd, RB_NUM2INT(events), tv);
1440
1441 if (ready < 0) {
1442 rb_sys_fail(0);
1443 }
1444
1445 // Not sure if this is necessary:
1446 rb_io_check_closed(fptr);
1447
1448 if (ready) {
1449 return RB_INT2NUM(ready);
1450 }
1451 else {
1452 return Qfalse;
1453 }
1454}
1455
1456static VALUE
1457io_from_fd(int fd)
1458{
1459 return prep_io(fd, FMODE_PREP, rb_cIO, NULL);
1460}
1461
1462static int
1463io_wait_for_single_fd(int fd, int events, struct timeval *timeout)
1464{
1465 VALUE scheduler = rb_fiber_scheduler_current();
1466
1467 if (scheduler != Qnil) {
1468 return RTEST(
1469 rb_fiber_scheduler_io_wait(scheduler, io_from_fd(fd), RB_INT2NUM(events), rb_fiber_scheduler_make_timeout(timeout))
1470 );
1471 }
1472
1473 return rb_thread_wait_for_single_fd(fd, events, timeout);
1474}
1475
1476int
1478{
1479 io_fd_check_closed(f);
1480
1481 VALUE scheduler = rb_fiber_scheduler_current();
1482
1483 switch (errno) {
1484 case EINTR:
1485#if defined(ERESTART)
1486 case ERESTART:
1487#endif
1489 return TRUE;
1490
1491 case EAGAIN:
1492#if EWOULDBLOCK != EAGAIN
1493 case EWOULDBLOCK:
1494#endif
1495 if (scheduler != Qnil) {
1496 return RTEST(
1497 rb_fiber_scheduler_io_wait_readable(scheduler, io_from_fd(f))
1498 );
1499 }
1500 else {
1501 io_wait_for_single_fd(f, RUBY_IO_READABLE, NULL);
1502 }
1503 return TRUE;
1504
1505 default:
1506 return FALSE;
1507 }
1508}
1509
1510int
1512{
1513 io_fd_check_closed(f);
1514
1515 VALUE scheduler = rb_fiber_scheduler_current();
1516
1517 switch (errno) {
1518 case EINTR:
1519#if defined(ERESTART)
1520 case ERESTART:
1521#endif
1522 /*
1523 * In old Linux, several special files under /proc and /sys don't handle
1524 * select properly. Thus we need avoid to call if don't use O_NONBLOCK.
1525 * Otherwise, we face nasty hang up. Sigh.
1526 * e.g. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1527 * https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1528 * In EINTR case, we only need to call RUBY_VM_CHECK_INTS_BLOCKING().
1529 * Then rb_thread_check_ints() is enough.
1530 */
1532 return TRUE;
1533
1534 case EAGAIN:
1535#if EWOULDBLOCK != EAGAIN
1536 case EWOULDBLOCK:
1537#endif
1538 if (scheduler != Qnil) {
1539 return RTEST(
1540 rb_fiber_scheduler_io_wait_writable(scheduler, io_from_fd(f))
1541 );
1542 }
1543 else {
1544 io_wait_for_single_fd(f, RUBY_IO_WRITABLE, NULL);
1545 }
1546 return TRUE;
1547
1548 default:
1549 return FALSE;
1550 }
1551}
1552
1553int
1554rb_wait_for_single_fd(int fd, int events, struct timeval *timeout)
1555{
1556 return io_wait_for_single_fd(fd, events, timeout);
1557}
1558
1559int
1561{
1562 return rb_wait_for_single_fd(fd, RUBY_IO_READABLE, NULL);
1563}
1564
1565int
1567{
1568 return rb_wait_for_single_fd(fd, RUBY_IO_WRITABLE, NULL);
1569}
1570
1571VALUE
1572rb_io_maybe_wait(int error, VALUE io, VALUE events, VALUE timeout)
1573{
1574 // fptr->fd can be set to -1 at any time by another thread when the GVL is
1575 // released. Many code, e.g. `io_bufread` didn't check this correctly and
1576 // instead relies on `read(-1) -> -1` which causes this code path. We then
1577 // check here whether the IO was in fact closed. Probably it's better to
1578 // check that `fptr->fd != -1` before using it in syscall.
1579 rb_io_check_closed(RFILE(io)->fptr);
1580
1581 switch (error) {
1582 // In old Linux, several special files under /proc and /sys don't handle
1583 // select properly. Thus we need avoid to call if don't use O_NONBLOCK.
1584 // Otherwise, we face nasty hang up. Sigh.
1585 // e.g. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1586 // https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1587 // In EINTR case, we only need to call RUBY_VM_CHECK_INTS_BLOCKING().
1588 // Then rb_thread_check_ints() is enough.
1589 case EINTR:
1590#if defined(ERESTART)
1591 case ERESTART:
1592#endif
1593 // We might have pending interrupts since the previous syscall was interrupted:
1595
1596 // The operation was interrupted, so retry it immediately:
1597 return events;
1598
1599 case EAGAIN:
1600#if EWOULDBLOCK != EAGAIN
1601 case EWOULDBLOCK:
1602#endif
1603 // The operation would block, so wait for the specified events:
1604 return rb_io_wait(io, events, timeout);
1605
1606 default:
1607 // Non-specific error, no event is ready:
1608 return Qfalse;
1609 }
1610}
1611
1612int
1614{
1615 VALUE result = rb_io_maybe_wait(error, io, RB_INT2NUM(RUBY_IO_READABLE), timeout);
1616
1617 if (RTEST(result)) {
1618 return RB_NUM2INT(result);
1619 }
1620 else {
1621 return 0;
1622 }
1623}
1624
1625int
1627{
1628 VALUE result = rb_io_maybe_wait(error, io, RB_INT2NUM(RUBY_IO_WRITABLE), timeout);
1629
1630 if (RTEST(result)) {
1631 return RB_NUM2INT(result);
1632 }
1633 else {
1634 return 0;
1635 }
1636}
1637
1638static void
1639make_writeconv(rb_io_t *fptr)
1640{
1641 if (!fptr->writeconv_initialized) {
1642 const char *senc, *denc;
1643 rb_encoding *enc;
1644 int ecflags;
1645 VALUE ecopts;
1646
1647 fptr->writeconv_initialized = 1;
1648
1649 ecflags = fptr->encs.ecflags & ~ECONV_NEWLINE_DECORATOR_READ_MASK;
1650 ecopts = fptr->encs.ecopts;
1651
1652 if (!fptr->encs.enc || (rb_is_ascii8bit_enc(fptr->encs.enc) && !fptr->encs.enc2)) {
1653 /* no encoding conversion */
1654 fptr->writeconv_pre_ecflags = 0;
1655 fptr->writeconv_pre_ecopts = Qnil;
1656 fptr->writeconv = rb_econv_open_opts("", "", ecflags, ecopts);
1657 if (!fptr->writeconv)
1658 rb_exc_raise(rb_econv_open_exc("", "", ecflags));
1660 }
1661 else {
1662 enc = fptr->encs.enc2 ? fptr->encs.enc2 : fptr->encs.enc;
1664 if (!senc && !(fptr->encs.ecflags & ECONV_STATEFUL_DECORATOR_MASK)) {
1665 /* single conversion */
1666 fptr->writeconv_pre_ecflags = ecflags;
1667 fptr->writeconv_pre_ecopts = ecopts;
1668 fptr->writeconv = NULL;
1670 }
1671 else {
1672 /* double conversion */
1673 fptr->writeconv_pre_ecflags = ecflags & ~ECONV_STATEFUL_DECORATOR_MASK;
1674 fptr->writeconv_pre_ecopts = ecopts;
1675 if (senc) {
1676 denc = rb_enc_name(enc);
1677 fptr->writeconv_asciicompat = rb_str_new2(senc);
1678 }
1679 else {
1680 senc = denc = "";
1682 }
1684 ecopts = fptr->encs.ecopts;
1685 fptr->writeconv = rb_econv_open_opts(senc, denc, ecflags, ecopts);
1686 if (!fptr->writeconv)
1687 rb_exc_raise(rb_econv_open_exc(senc, denc, ecflags));
1688 }
1689 }
1690 }
1691}
1692
1693/* writing functions */
1695 rb_io_t *fptr;
1696 VALUE str;
1697 const char *ptr;
1698 long length;
1699};
1700
1702 VALUE io;
1703 VALUE str;
1704 int nosync;
1705};
1706
1707#ifdef HAVE_WRITEV
1708static ssize_t
1709io_binwrite_string_internal(rb_io_t *fptr, const char *ptr, long length)
1710{
1711 if (fptr->wbuf.len) {
1712 struct iovec iov[2];
1713
1714 iov[0].iov_base = fptr->wbuf.ptr+fptr->wbuf.off;
1715 iov[0].iov_len = fptr->wbuf.len;
1716 iov[1].iov_base = (void*)ptr;
1717 iov[1].iov_len = length;
1718
1719 ssize_t result = rb_writev_internal(fptr, iov, 2);
1720
1721 if (result < 0)
1722 return result;
1723
1724 if (result >= fptr->wbuf.len) {
1725 // We wrote more than the internal buffer:
1726 result -= fptr->wbuf.len;
1727 fptr->wbuf.off = 0;
1728 fptr->wbuf.len = 0;
1729 }
1730 else {
1731 // We only wrote less data than the internal buffer:
1732 fptr->wbuf.off += (int)result;
1733 fptr->wbuf.len -= (int)result;
1734
1735 result = 0;
1736 }
1737
1738 return result;
1739 }
1740 else {
1741 return rb_io_write_memory(fptr, ptr, length);
1742 }
1743}
1744#else
1745static ssize_t
1746io_binwrite_string_internal(rb_io_t *fptr, const char *ptr, long length)
1747{
1748 long remaining = length;
1749
1750 if (fptr->wbuf.len) {
1751 if (fptr->wbuf.len+length <= fptr->wbuf.capa) {
1752 if (fptr->wbuf.capa < fptr->wbuf.off+fptr->wbuf.len+length) {
1753 MEMMOVE(fptr->wbuf.ptr, fptr->wbuf.ptr+fptr->wbuf.off, char, fptr->wbuf.len);
1754 fptr->wbuf.off = 0;
1755 }
1756
1757 MEMMOVE(fptr->wbuf.ptr+fptr->wbuf.off+fptr->wbuf.len, ptr, char, length);
1758 fptr->wbuf.len += (int)length;
1759
1760 // We copied the entire incoming data to the internal buffer:
1761 remaining = 0;
1762 }
1763
1764 // Flush the internal buffer:
1765 if (io_fflush(fptr) < 0) {
1766 return -1;
1767 }
1768
1769 // If all the data was buffered, we are done:
1770 if (remaining == 0) {
1771 return length;
1772 }
1773 }
1774
1775 // Otherwise, we should write the data directly:
1776 return rb_io_write_memory(fptr, ptr, length);
1777}
1778#endif
1779
1780static VALUE
1781io_binwrite_string(VALUE arg)
1782{
1783 struct binwrite_arg *p = (struct binwrite_arg *)arg;
1784
1785 const char *ptr = p->ptr;
1786 size_t remaining = p->length;
1787
1788 while (remaining) {
1789 // Write as much as possible:
1790 ssize_t result = io_binwrite_string_internal(p->fptr, ptr, remaining);
1791
1792 // If only the internal buffer is written, result will be zero [bytes of given data written]. This means we
1793 // should try again.
1794 if (result == 0) {
1795 errno = EWOULDBLOCK;
1796 }
1797
1798 if (result > 0) {
1799 if ((size_t)result == remaining) break;
1800 ptr += result;
1801 remaining -= result;
1802 }
1803 // Wait for it to become writable:
1804 else if (rb_io_maybe_wait_writable(errno, p->fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
1805 rb_io_check_closed(p->fptr);
1806 }
1807 else {
1808 // The error was unrelated to waiting for it to become writable, so we fail:
1809 return -1;
1810 }
1811 }
1812
1813 return p->length;
1814}
1815
1816inline static void
1817io_allocate_write_buffer(rb_io_t *fptr, int sync)
1818{
1819 if (fptr->wbuf.ptr == NULL && !(sync && (fptr->mode & FMODE_SYNC))) {
1820 fptr->wbuf.off = 0;
1821 fptr->wbuf.len = 0;
1822 fptr->wbuf.capa = IO_WBUF_CAPA_MIN;
1823 fptr->wbuf.ptr = ALLOC_N(char, fptr->wbuf.capa);
1824 }
1825
1826 if (NIL_P(fptr->write_lock)) {
1827 fptr->write_lock = rb_mutex_new();
1828 rb_mutex_allow_trap(fptr->write_lock, 1);
1829 }
1830}
1831
1832static inline int
1833io_binwrite_requires_flush_write(rb_io_t *fptr, long len, int nosync)
1834{
1835 // If the requested operation was synchronous and the output mode is synchronus or a TTY:
1836 if (!nosync && (fptr->mode & (FMODE_SYNC|FMODE_TTY)))
1837 return 1;
1838
1839 // If the amount of data we want to write exceeds the internal buffer:
1840 if (fptr->wbuf.ptr && fptr->wbuf.capa <= fptr->wbuf.len + len)
1841 return 1;
1842
1843 // Otherwise, we can append to the internal buffer:
1844 return 0;
1845}
1846
1847static long
1848io_binwrite(VALUE str, const char *ptr, long len, rb_io_t *fptr, int nosync)
1849{
1850 if (len <= 0) return len;
1851
1852 // Don't write anything if current thread has a pending interrupt:
1854
1855 io_allocate_write_buffer(fptr, !nosync);
1856
1857 if (io_binwrite_requires_flush_write(fptr, len, nosync)) {
1858 struct binwrite_arg arg;
1859
1860 arg.fptr = fptr;
1861 arg.str = str;
1862 arg.ptr = ptr;
1863 arg.length = len;
1864
1865 if (!NIL_P(fptr->write_lock)) {
1866 return rb_mutex_synchronize(fptr->write_lock, io_binwrite_string, (VALUE)&arg);
1867 }
1868 else {
1869 return io_binwrite_string((VALUE)&arg);
1870 }
1871 }
1872 else {
1873 if (fptr->wbuf.off) {
1874 if (fptr->wbuf.len)
1875 MEMMOVE(fptr->wbuf.ptr, fptr->wbuf.ptr+fptr->wbuf.off, char, fptr->wbuf.len);
1876 fptr->wbuf.off = 0;
1877 }
1878
1879 MEMMOVE(fptr->wbuf.ptr+fptr->wbuf.off+fptr->wbuf.len, ptr, char, len);
1880 fptr->wbuf.len += (int)len;
1881
1882 return len;
1883 }
1884}
1885
1886# define MODE_BTMODE(a,b,c) ((fmode & FMODE_BINMODE) ? (b) : \
1887 (fmode & FMODE_TEXTMODE) ? (c) : (a))
1888
1889#define MODE_BTXMODE(a, b, c, d, e, f) ((fmode & FMODE_EXCL) ? \
1890 MODE_BTMODE(d, e, f) : \
1891 MODE_BTMODE(a, b, c))
1892
1893static VALUE
1894do_writeconv(VALUE str, rb_io_t *fptr, int *converted)
1895{
1896 if (NEED_WRITECONV(fptr)) {
1897 VALUE common_encoding = Qnil;
1898 SET_BINARY_MODE(fptr);
1899
1900 make_writeconv(fptr);
1901
1902 if (fptr->writeconv) {
1903#define fmode (fptr->mode)
1904 if (!NIL_P(fptr->writeconv_asciicompat))
1905 common_encoding = fptr->writeconv_asciicompat;
1906 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1) && !rb_enc_asciicompat(rb_enc_get(str))) {
1907 rb_raise(rb_eArgError, "ASCII incompatible string written for text mode IO without encoding conversion: %s",
1908 rb_enc_name(rb_enc_get(str)));
1909 }
1910#undef fmode
1911 }
1912 else {
1913 if (fptr->encs.enc2)
1914 common_encoding = rb_enc_from_encoding(fptr->encs.enc2);
1915 else if (fptr->encs.enc != rb_ascii8bit_encoding())
1916 common_encoding = rb_enc_from_encoding(fptr->encs.enc);
1917 }
1918
1919 if (!NIL_P(common_encoding)) {
1920 str = rb_str_encode(str, common_encoding,
1922 *converted = 1;
1923 }
1924
1925 if (fptr->writeconv) {
1927 *converted = 1;
1928 }
1929 }
1930#if RUBY_CRLF_ENVIRONMENT
1931#define fmode (fptr->mode)
1932 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1)) {
1933 if ((fptr->mode & FMODE_READABLE) &&
1935 setmode(fptr->fd, O_BINARY);
1936 }
1937 else {
1938 setmode(fptr->fd, O_TEXT);
1939 }
1940 if (!rb_enc_asciicompat(rb_enc_get(str))) {
1941 rb_raise(rb_eArgError, "ASCII incompatible string written for text mode IO without encoding conversion: %s",
1942 rb_enc_name(rb_enc_get(str)));
1943 }
1944 }
1945#undef fmode
1946#endif
1947 return str;
1948}
1949
1950static long
1951io_fwrite(VALUE str, rb_io_t *fptr, int nosync)
1952{
1953 int converted = 0;
1954 VALUE tmp;
1955 long n, len;
1956 const char *ptr;
1957
1958#ifdef _WIN32
1959 if (fptr->mode & FMODE_TTY) {
1960 long len = rb_w32_write_console(str, fptr->fd);
1961 if (len > 0) return len;
1962 }
1963#endif
1964
1965 str = do_writeconv(str, fptr, &converted);
1966 if (converted)
1967 OBJ_FREEZE(str);
1968
1969 tmp = rb_str_tmp_frozen_acquire(str);
1970 RSTRING_GETMEM(tmp, ptr, len);
1971 n = io_binwrite(tmp, ptr, len, fptr, nosync);
1972 rb_str_tmp_frozen_release(str, tmp);
1973
1974 return n;
1975}
1976
1977ssize_t
1978rb_io_bufwrite(VALUE io, const void *buf, size_t size)
1979{
1980 rb_io_t *fptr;
1981
1982 GetOpenFile(io, fptr);
1984 return (ssize_t)io_binwrite(0, buf, (long)size, fptr, 0);
1985}
1986
1987static VALUE
1988io_write(VALUE io, VALUE str, int nosync)
1989{
1990 rb_io_t *fptr;
1991 long n;
1992 VALUE tmp;
1993
1994 io = GetWriteIO(io);
1995 str = rb_obj_as_string(str);
1996 tmp = rb_io_check_io(io);
1997
1998 if (NIL_P(tmp)) {
1999 /* port is not IO, call write method for it. */
2000 return rb_funcall(io, id_write, 1, str);
2001 }
2002
2003 io = tmp;
2004 if (RSTRING_LEN(str) == 0) return INT2FIX(0);
2005
2006 GetOpenFile(io, fptr);
2008
2009 n = io_fwrite(str, fptr, nosync);
2010 if (n < 0L) rb_sys_fail_on_write(fptr);
2011
2012 return LONG2FIX(n);
2013}
2014
2015#ifdef HAVE_WRITEV
2016struct binwritev_arg {
2017 rb_io_t *fptr;
2018 struct iovec *iov;
2019 int iovcnt;
2020 size_t total;
2021};
2022
2023static VALUE
2024io_binwritev_internal(VALUE arg)
2025{
2026 struct binwritev_arg *p = (struct binwritev_arg *)arg;
2027
2028 size_t remaining = p->total;
2029 size_t offset = 0;
2030
2031 rb_io_t *fptr = p->fptr;
2032 struct iovec *iov = p->iov;
2033 int iovcnt = p->iovcnt;
2034
2035 while (remaining) {
2036 long result = rb_writev_internal(fptr, iov, iovcnt);
2037
2038 if (result >= 0) {
2039 offset += result;
2040 if (fptr->wbuf.ptr && fptr->wbuf.len) {
2041 if (offset < (size_t)fptr->wbuf.len) {
2042 fptr->wbuf.off += result;
2043 fptr->wbuf.len -= result;
2044 }
2045 else {
2046 offset -= (size_t)fptr->wbuf.len;
2047 fptr->wbuf.off = 0;
2048 fptr->wbuf.len = 0;
2049 }
2050 }
2051
2052 if (offset == p->total) {
2053 return p->total;
2054 }
2055
2056 while (result >= (ssize_t)iov->iov_len) {
2057 /* iovcnt > 0 */
2058 result -= iov->iov_len;
2059 iov->iov_len = 0;
2060 iov++;
2061
2062 if (!--iovcnt) {
2063 // I don't believe this code path can ever occur.
2064 return offset;
2065 }
2066 }
2067
2068 iov->iov_base = (char *)iov->iov_base + result;
2069 iov->iov_len -= result;
2070 }
2071 else if (rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
2072 rb_io_check_closed(fptr);
2073 }
2074 else {
2075 return -1;
2076 }
2077 }
2078
2079 return offset;
2080}
2081
2082static long
2083io_binwritev(struct iovec *iov, int iovcnt, rb_io_t *fptr)
2084{
2085 // Don't write anything if current thread has a pending interrupt:
2087
2088 if (iovcnt == 0) return 0;
2089
2090 size_t total = 0;
2091 for (int i = 1; i < iovcnt; i++) total += iov[i].iov_len;
2092
2093 io_allocate_write_buffer(fptr, 1);
2094
2095 if (fptr->wbuf.ptr && fptr->wbuf.len) {
2096 // The end of the buffered data:
2097 size_t offset = fptr->wbuf.off + fptr->wbuf.len;
2098
2099 if (offset + total <= (size_t)fptr->wbuf.capa) {
2100 for (int i = 1; i < iovcnt; i++) {
2101 memcpy(fptr->wbuf.ptr+offset, iov[i].iov_base, iov[i].iov_len);
2102 offset += iov[i].iov_len;
2103 }
2104
2105 fptr->wbuf.len += total;
2106
2107 return total;
2108 }
2109 else {
2110 iov[0].iov_base = fptr->wbuf.ptr + fptr->wbuf.off;
2111 iov[0].iov_len = fptr->wbuf.len;
2112 }
2113 }
2114 else {
2115 // The first iov is reserved for the internal buffer, and it's empty.
2116 iov++;
2117
2118 if (!--iovcnt) {
2119 // If there are no other io vectors we are done.
2120 return 0;
2121 }
2122 }
2123
2124 struct binwritev_arg arg;
2125 arg.fptr = fptr;
2126 arg.iov = iov;
2127 arg.iovcnt = iovcnt;
2128 arg.total = total;
2129
2130 if (!NIL_P(fptr->write_lock)) {
2131 return rb_mutex_synchronize(fptr->write_lock, io_binwritev_internal, (VALUE)&arg);
2132 }
2133 else {
2134 return io_binwritev_internal((VALUE)&arg);
2135 }
2136}
2137
2138static long
2139io_fwritev(int argc, const VALUE *argv, rb_io_t *fptr)
2140{
2141 int i, converted, iovcnt = argc + 1;
2142 long n;
2143 VALUE v1, v2, str, tmp, *tmp_array;
2144 struct iovec *iov;
2145
2146 iov = ALLOCV_N(struct iovec, v1, iovcnt);
2147 tmp_array = ALLOCV_N(VALUE, v2, argc);
2148
2149 for (i = 0; i < argc; i++) {
2150 str = rb_obj_as_string(argv[i]);
2151 converted = 0;
2152 str = do_writeconv(str, fptr, &converted);
2153
2154 if (converted)
2155 OBJ_FREEZE(str);
2156
2157 tmp = rb_str_tmp_frozen_acquire(str);
2158 tmp_array[i] = tmp;
2159
2160 /* iov[0] is reserved for buffer of fptr */
2161 iov[i+1].iov_base = RSTRING_PTR(tmp);
2162 iov[i+1].iov_len = RSTRING_LEN(tmp);
2163 }
2164
2165 n = io_binwritev(iov, iovcnt, fptr);
2166 if (v1) ALLOCV_END(v1);
2167
2168 for (i = 0; i < argc; i++) {
2169 rb_str_tmp_frozen_release(argv[i], tmp_array[i]);
2170 }
2171
2172 if (v2) ALLOCV_END(v2);
2173
2174 return n;
2175}
2176
2177static int
2178iovcnt_ok(int iovcnt)
2179{
2180#ifdef IOV_MAX
2181 return iovcnt < IOV_MAX;
2182#else /* GNU/Hurd has writev, but no IOV_MAX */
2183 return 1;
2184#endif
2185}
2186#endif /* HAVE_WRITEV */
2187
2188static VALUE
2189io_writev(int argc, const VALUE *argv, VALUE io)
2190{
2191 rb_io_t *fptr;
2192 long n;
2193 VALUE tmp, total = INT2FIX(0);
2194 int i, cnt = 1;
2195
2196 io = GetWriteIO(io);
2197 tmp = rb_io_check_io(io);
2198
2199 if (NIL_P(tmp)) {
2200 /* port is not IO, call write method for it. */
2201 return rb_funcallv(io, id_write, argc, argv);
2202 }
2203
2204 io = tmp;
2205
2206 GetOpenFile(io, fptr);
2208
2209 for (i = 0; i < argc; i += cnt) {
2210#ifdef HAVE_WRITEV
2211 if ((fptr->mode & (FMODE_SYNC|FMODE_TTY)) && iovcnt_ok(cnt = argc - i)) {
2212 n = io_fwritev(cnt, &argv[i], fptr);
2213 }
2214 else
2215#endif
2216 {
2217 cnt = 1;
2218 /* sync at last item */
2219 n = io_fwrite(rb_obj_as_string(argv[i]), fptr, (i < argc-1));
2220 }
2221
2222 if (n < 0L)
2223 rb_sys_fail_on_write(fptr);
2224
2225 total = rb_fix_plus(LONG2FIX(n), total);
2226 }
2227
2228 return total;
2229}
2230
2231/*
2232 * call-seq:
2233 * write(*objects) -> integer
2234 *
2235 * Writes each of the given +objects+ to +self+,
2236 * which must be opened for writing
2237 * (see {Access Modes}[rdoc-ref:File@Access+Modes]);
2238 * returns the total number bytes written;
2239 * each of +objects+ that is not a string is converted via method +to_s+:
2240 *
2241 * $stdout.write('Hello', ', ', 'World!', "\n") # => 14
2242 * $stdout.write('foo', :bar, 2, "\n") # => 8
2243 *
2244 * Output:
2245 *
2246 * Hello, World!
2247 * foobar2
2248 *
2249 * Related: IO#read.
2250 */
2251
2252static VALUE
2253io_write_m(int argc, VALUE *argv, VALUE io)
2254{
2255 if (argc != 1) {
2256 return io_writev(argc, argv, io);
2257 }
2258 else {
2259 VALUE str = argv[0];
2260 return io_write(io, str, 0);
2261 }
2262}
2263
2264VALUE
2266{
2267 return rb_funcallv(io, id_write, 1, &str);
2268}
2269
2270static VALUE
2271rb_io_writev(VALUE io, int argc, const VALUE *argv)
2272{
2273 if (argc > 1 && rb_obj_method_arity(io, id_write) == 1) {
2274 if (io != rb_ractor_stderr() && RTEST(ruby_verbose)) {
2275 VALUE klass = CLASS_OF(io);
2276 char sep = FL_TEST(klass, FL_SINGLETON) ? (klass = io, '.') : '#';
2278 RB_WARN_CATEGORY_DEPRECATED, "%+"PRIsVALUE"%c""write is outdated interface"
2279 " which accepts just one argument",
2280 klass, sep
2281 );
2282 }
2283
2284 do rb_io_write(io, *argv++); while (--argc);
2285
2286 return Qnil;
2287 }
2288
2289 return rb_funcallv(io, id_write, argc, argv);
2290}
2291
2292/*
2293 * call-seq:
2294 * self << object -> self
2295 *
2296 * Writes the given +object+ to +self+,
2297 * which must be opened for writing (see {Access Modes}[rdoc-ref:File@Access+Modes]);
2298 * returns +self+;
2299 * if +object+ is not a string, it is converted via method +to_s+:
2300 *
2301 * $stdout << 'Hello' << ', ' << 'World!' << "\n"
2302 * $stdout << 'foo' << :bar << 2 << "\n"
2303 *
2304 * Output:
2305 *
2306 * Hello, World!
2307 * foobar2
2308 *
2309 */
2310
2311
2312VALUE
2314{
2315 rb_io_write(io, str);
2316 return io;
2317}
2318
2319#ifdef HAVE_FSYNC
2320static VALUE
2321nogvl_fsync(void *ptr)
2322{
2323 rb_io_t *fptr = ptr;
2324
2325#ifdef _WIN32
2326 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->fd)) != FILE_TYPE_DISK)
2327 return 0;
2328#endif
2329 return (VALUE)fsync(fptr->fd);
2330}
2331#endif
2332
2333VALUE
2334rb_io_flush_raw(VALUE io, int sync)
2335{
2336 rb_io_t *fptr;
2337
2338 if (!RB_TYPE_P(io, T_FILE)) {
2339 return rb_funcall(io, id_flush, 0);
2340 }
2341
2342 io = GetWriteIO(io);
2343 GetOpenFile(io, fptr);
2344
2345 if (fptr->mode & FMODE_WRITABLE) {
2346 if (io_fflush(fptr) < 0)
2347 rb_sys_fail_on_write(fptr);
2348 }
2349 if (fptr->mode & FMODE_READABLE) {
2350 io_unread(fptr);
2351 }
2352
2353 return io;
2354}
2355
2356/*
2357 * call-seq:
2358 * flush -> self
2359 *
2360 * Flushes data buffered in +self+ to the operating system
2361 * (but does not necessarily flush data buffered in the operating system):
2362 *
2363 * $stdout.print 'no newline' # Not necessarily flushed.
2364 * $stdout.flush # Flushed.
2365 *
2366 */
2367
2368VALUE
2370{
2371 return rb_io_flush_raw(io, 1);
2372}
2373
2374/*
2375 * call-seq:
2376 * tell -> integer
2377 *
2378 * Returns the current position (in bytes) in +self+
2379 * (see {Position}[rdoc-ref:IO@Position]):
2380 *
2381 * f = File.open('t.txt')
2382 * f.tell # => 0
2383 * f.gets # => "First line\n"
2384 * f.tell # => 12
2385 * f.close
2386 *
2387 * Related: IO#pos=, IO#seek.
2388 *
2389 * IO#pos is an alias for IO#tell.
2390 *
2391 */
2392
2393static VALUE
2394rb_io_tell(VALUE io)
2395{
2396 rb_io_t *fptr;
2397 rb_off_t pos;
2398
2399 GetOpenFile(io, fptr);
2400 pos = io_tell(fptr);
2401 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2402 pos -= fptr->rbuf.len;
2403 return OFFT2NUM(pos);
2404}
2405
2406static VALUE
2407rb_io_seek(VALUE io, VALUE offset, int whence)
2408{
2409 rb_io_t *fptr;
2410 rb_off_t pos;
2411
2412 pos = NUM2OFFT(offset);
2413 GetOpenFile(io, fptr);
2414 pos = io_seek(fptr, pos, whence);
2415 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2416
2417 return INT2FIX(0);
2418}
2419
2420static int
2421interpret_seek_whence(VALUE vwhence)
2422{
2423 if (vwhence == sym_SET)
2424 return SEEK_SET;
2425 if (vwhence == sym_CUR)
2426 return SEEK_CUR;
2427 if (vwhence == sym_END)
2428 return SEEK_END;
2429#ifdef SEEK_DATA
2430 if (vwhence == sym_DATA)
2431 return SEEK_DATA;
2432#endif
2433#ifdef SEEK_HOLE
2434 if (vwhence == sym_HOLE)
2435 return SEEK_HOLE;
2436#endif
2437 return NUM2INT(vwhence);
2438}
2439
2440/*
2441 * call-seq:
2442 * seek(offset, whence = IO::SEEK_SET) -> 0
2443 *
2444 * Seeks to the position given by integer +offset+
2445 * (see {Position}[rdoc-ref:IO@Position])
2446 * and constant +whence+, which is one of:
2447 *
2448 * - +:CUR+ or <tt>IO::SEEK_CUR</tt>:
2449 * Repositions the stream to its current position plus the given +offset+:
2450 *
2451 * f = File.open('t.txt')
2452 * f.tell # => 0
2453 * f.seek(20, :CUR) # => 0
2454 * f.tell # => 20
2455 * f.seek(-10, :CUR) # => 0
2456 * f.tell # => 10
2457 * f.close
2458 *
2459 * - +:END+ or <tt>IO::SEEK_END</tt>:
2460 * Repositions the stream to its end plus the given +offset+:
2461 *
2462 * f = File.open('t.txt')
2463 * f.tell # => 0
2464 * f.seek(0, :END) # => 0 # Repositions to stream end.
2465 * f.tell # => 52
2466 * f.seek(-20, :END) # => 0
2467 * f.tell # => 32
2468 * f.seek(-40, :END) # => 0
2469 * f.tell # => 12
2470 * f.close
2471 *
2472 * - +:SET+ or <tt>IO:SEEK_SET</tt>:
2473 * Repositions the stream to the given +offset+:
2474 *
2475 * f = File.open('t.txt')
2476 * f.tell # => 0
2477 * f.seek(20, :SET) # => 0
2478 * f.tell # => 20
2479 * f.seek(40, :SET) # => 0
2480 * f.tell # => 40
2481 * f.close
2482 *
2483 * Related: IO#pos=, IO#tell.
2484 *
2485 */
2486
2487static VALUE
2488rb_io_seek_m(int argc, VALUE *argv, VALUE io)
2489{
2490 VALUE offset, ptrname;
2491 int whence = SEEK_SET;
2492
2493 if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
2494 whence = interpret_seek_whence(ptrname);
2495 }
2496
2497 return rb_io_seek(io, offset, whence);
2498}
2499
2500/*
2501 * call-seq:
2502 * pos = new_position -> new_position
2503 *
2504 * Seeks to the given +new_position+ (in bytes);
2505 * see {Position}[rdoc-ref:IO@Position]:
2506 *
2507 * f = File.open('t.txt')
2508 * f.tell # => 0
2509 * f.pos = 20 # => 20
2510 * f.tell # => 20
2511 * f.close
2512 *
2513 * Related: IO#seek, IO#tell.
2514 *
2515 */
2516
2517static VALUE
2518rb_io_set_pos(VALUE io, VALUE offset)
2519{
2520 rb_io_t *fptr;
2521 rb_off_t pos;
2522
2523 pos = NUM2OFFT(offset);
2524 GetOpenFile(io, fptr);
2525 pos = io_seek(fptr, pos, SEEK_SET);
2526 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2527
2528 return OFFT2NUM(pos);
2529}
2530
2531static void clear_readconv(rb_io_t *fptr);
2532
2533/*
2534 * call-seq:
2535 * rewind -> 0
2536 *
2537 * Repositions the stream to its beginning,
2538 * setting both the position and the line number to zero;
2539 * see {Position}[rdoc-ref:IO@Position]
2540 * and {Line Number}[rdoc-ref:IO@Line+Number]:
2541 *
2542 * f = File.open('t.txt')
2543 * f.tell # => 0
2544 * f.lineno # => 0
2545 * f.gets # => "First line\n"
2546 * f.tell # => 12
2547 * f.lineno # => 1
2548 * f.rewind # => 0
2549 * f.tell # => 0
2550 * f.lineno # => 0
2551 * f.close
2552 *
2553 * Note that this method cannot be used with streams such as pipes, ttys, and sockets.
2554 *
2555 */
2556
2557static VALUE
2558rb_io_rewind(VALUE io)
2559{
2560 rb_io_t *fptr;
2561
2562 GetOpenFile(io, fptr);
2563 if (io_seek(fptr, 0L, 0) < 0 && errno) rb_sys_fail_path(fptr->pathv);
2564 if (io == ARGF.current_file) {
2565 ARGF.lineno -= fptr->lineno;
2566 }
2567 fptr->lineno = 0;
2568 if (fptr->readconv) {
2569 clear_readconv(fptr);
2570 }
2571
2572 return INT2FIX(0);
2573}
2574
2575static int
2576fptr_wait_readable(rb_io_t *fptr)
2577{
2578 int result = rb_io_maybe_wait_readable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT);
2579
2580 if (result)
2581 rb_io_check_closed(fptr);
2582
2583 return result;
2584}
2585
2586static int
2587io_fillbuf(rb_io_t *fptr)
2588{
2589 ssize_t r;
2590
2591 if (fptr->rbuf.ptr == NULL) {
2592 fptr->rbuf.off = 0;
2593 fptr->rbuf.len = 0;
2594 fptr->rbuf.capa = IO_RBUF_CAPA_FOR(fptr);
2595 fptr->rbuf.ptr = ALLOC_N(char, fptr->rbuf.capa);
2596#ifdef _WIN32
2597 fptr->rbuf.capa--;
2598#endif
2599 }
2600 if (fptr->rbuf.len == 0) {
2601 retry:
2602 r = rb_io_read_memory(fptr, fptr->rbuf.ptr, fptr->rbuf.capa);
2603
2604 if (r < 0) {
2605 if (fptr_wait_readable(fptr))
2606 goto retry;
2607
2608 int e = errno;
2609 VALUE path = rb_sprintf("fd:%d ", fptr->fd);
2610 if (!NIL_P(fptr->pathv)) {
2611 rb_str_append(path, fptr->pathv);
2612 }
2613
2614 rb_syserr_fail_path(e, path);
2615 }
2616 if (r > 0) rb_io_check_closed(fptr);
2617 fptr->rbuf.off = 0;
2618 fptr->rbuf.len = (int)r; /* r should be <= rbuf_capa */
2619 if (r == 0)
2620 return -1; /* EOF */
2621 }
2622 return 0;
2623}
2624
2625/*
2626 * call-seq:
2627 * eof -> true or false
2628 *
2629 * Returns +true+ if the stream is positioned at its end, +false+ otherwise;
2630 * see {Position}[rdoc-ref:IO@Position]:
2631 *
2632 * f = File.open('t.txt')
2633 * f.eof # => false
2634 * f.seek(0, :END) # => 0
2635 * f.eof # => true
2636 * f.close
2637 *
2638 * Raises an exception unless the stream is opened for reading;
2639 * see {Mode}[rdoc-ref:File@Access+Modes].
2640 *
2641 * If +self+ is a stream such as pipe or socket, this method
2642 * blocks until the other end sends some data or closes it:
2643 *
2644 * r, w = IO.pipe
2645 * Thread.new { sleep 1; w.close }
2646 * r.eof? # => true # After 1-second wait.
2647 *
2648 * r, w = IO.pipe
2649 * Thread.new { sleep 1; w.puts "a" }
2650 * r.eof? # => false # After 1-second wait.
2651 *
2652 * r, w = IO.pipe
2653 * r.eof? # blocks forever
2654 *
2655 * Note that this method reads data to the input byte buffer. So
2656 * IO#sysread may not behave as you intend with IO#eof?, unless you
2657 * call IO#rewind first (which is not available for some streams).
2658 *
2659 * IO#eof? is an alias for IO#eof.
2660 *
2661 */
2662
2663VALUE
2665{
2666 rb_io_t *fptr;
2667
2668 GetOpenFile(io, fptr);
2670
2671 if (READ_CHAR_PENDING(fptr)) return Qfalse;
2672 if (READ_DATA_PENDING(fptr)) return Qfalse;
2673 READ_CHECK(fptr);
2674#if RUBY_CRLF_ENVIRONMENT
2675 if (!NEED_READCONV(fptr) && NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
2676 return RBOOL(eof(fptr->fd));;
2677 }
2678#endif
2679 return RBOOL(io_fillbuf(fptr) < 0);
2680}
2681
2682/*
2683 * call-seq:
2684 * sync -> true or false
2685 *
2686 * Returns the current sync mode of the stream.
2687 * When sync mode is true, all output is immediately flushed to the underlying
2688 * operating system and is not buffered by Ruby internally. See also #fsync.
2689 *
2690 * f = File.open('t.tmp', 'w')
2691 * f.sync # => false
2692 * f.sync = true
2693 * f.sync # => true
2694 * f.close
2695 *
2696 */
2697
2698static VALUE
2699rb_io_sync(VALUE io)
2700{
2701 rb_io_t *fptr;
2702
2703 io = GetWriteIO(io);
2704 GetOpenFile(io, fptr);
2705 return RBOOL(fptr->mode & FMODE_SYNC);
2706}
2707
2708#ifdef HAVE_FSYNC
2709
2710/*
2711 * call-seq:
2712 * sync = boolean -> boolean
2713 *
2714 * Sets the _sync_ _mode_ for the stream to the given value;
2715 * returns the given value.
2716 *
2717 * Values for the sync mode:
2718 *
2719 * - +true+: All output is immediately flushed to the
2720 * underlying operating system and is not buffered internally.
2721 * - +false+: Output may be buffered internally.
2722 *
2723 * Example;
2724 *
2725 * f = File.open('t.tmp', 'w')
2726 * f.sync # => false
2727 * f.sync = true
2728 * f.sync # => true
2729 * f.close
2730 *
2731 * Related: IO#fsync.
2732 *
2733 */
2734
2735static VALUE
2736rb_io_set_sync(VALUE io, VALUE sync)
2737{
2738 rb_io_t *fptr;
2739
2740 io = GetWriteIO(io);
2741 GetOpenFile(io, fptr);
2742 if (RTEST(sync)) {
2743 fptr->mode |= FMODE_SYNC;
2744 }
2745 else {
2746 fptr->mode &= ~FMODE_SYNC;
2747 }
2748 return sync;
2749}
2750
2751/*
2752 * call-seq:
2753 * fsync -> 0
2754 *
2755 * Immediately writes to disk all data buffered in the stream,
2756 * via the operating system's <tt>fsync(2)</tt>.
2757
2758 * Note this difference:
2759 *
2760 * - IO#sync=: Ensures that data is flushed from the stream's internal buffers,
2761 * but does not guarantee that the operating system actually writes the data to disk.
2762 * - IO#fsync: Ensures both that data is flushed from internal buffers,
2763 * and that data is written to disk.
2764 *
2765 * Raises an exception if the operating system does not support <tt>fsync(2)</tt>.
2766 *
2767 */
2768
2769static VALUE
2770rb_io_fsync(VALUE io)
2771{
2772 rb_io_t *fptr;
2773
2774 io = GetWriteIO(io);
2775 GetOpenFile(io, fptr);
2776
2777 if (io_fflush(fptr) < 0)
2778 rb_sys_fail_on_write(fptr);
2779 if ((int)rb_thread_io_blocking_region(nogvl_fsync, fptr, fptr->fd) < 0)
2780 rb_sys_fail_path(fptr->pathv);
2781 return INT2FIX(0);
2782}
2783#else
2784# define rb_io_fsync rb_f_notimplement
2785# define rb_io_sync rb_f_notimplement
2786static VALUE
2787rb_io_set_sync(VALUE io, VALUE sync)
2788{
2791}
2792#endif
2793
2794#ifdef HAVE_FDATASYNC
2795static VALUE
2796nogvl_fdatasync(void *ptr)
2797{
2798 rb_io_t *fptr = ptr;
2799
2800#ifdef _WIN32
2801 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->fd)) != FILE_TYPE_DISK)
2802 return 0;
2803#endif
2804 return (VALUE)fdatasync(fptr->fd);
2805}
2806
2807/*
2808 * call-seq:
2809 * fdatasync -> 0
2810 *
2811 * Immediately writes to disk all data buffered in the stream,
2812 * via the operating system's: <tt>fdatasync(2)</tt>, if supported,
2813 * otherwise via <tt>fsync(2)</tt>, if supported;
2814 * otherwise raises an exception.
2815 *
2816 */
2817
2818static VALUE
2819rb_io_fdatasync(VALUE io)
2820{
2821 rb_io_t *fptr;
2822
2823 io = GetWriteIO(io);
2824 GetOpenFile(io, fptr);
2825
2826 if (io_fflush(fptr) < 0)
2827 rb_sys_fail_on_write(fptr);
2828
2829 if ((int)rb_thread_io_blocking_region(nogvl_fdatasync, fptr, fptr->fd) == 0)
2830 return INT2FIX(0);
2831
2832 /* fall back */
2833 return rb_io_fsync(io);
2834}
2835#else
2836#define rb_io_fdatasync rb_io_fsync
2837#endif
2838
2839/*
2840 * call-seq:
2841 * fileno -> integer
2842 *
2843 * Returns the integer file descriptor for the stream:
2844 *
2845 * $stdin.fileno # => 0
2846 * $stdout.fileno # => 1
2847 * $stderr.fileno # => 2
2848 * File.open('t.txt').fileno # => 10
2849 * f.close
2850 *
2851 * IO#to_i is an alias for IO#fileno.
2852 *
2853 */
2854
2855static VALUE
2856rb_io_fileno(VALUE io)
2857{
2858 rb_io_t *fptr = RFILE(io)->fptr;
2859 int fd;
2860
2861 rb_io_check_closed(fptr);
2862 fd = fptr->fd;
2863 return INT2FIX(fd);
2864}
2865
2866int
2868{
2869 if (RB_TYPE_P(io, T_FILE)) {
2870 rb_io_t *fptr = RFILE(io)->fptr;
2871 rb_io_check_closed(fptr);
2872 return fptr->fd;
2873 }
2874 else {
2875 return RB_NUM2INT(rb_funcall(io, id_fileno, 0));
2876 }
2877}
2878
2879/*
2880 * call-seq:
2881 * pid -> integer or nil
2882 *
2883 * Returns the process ID of a child process associated with the stream,
2884 * which will have been set by IO#popen, or +nil+ if the stream was not
2885 * created by IO#popen:
2886 *
2887 * pipe = IO.popen("-")
2888 * if pipe
2889 * $stderr.puts "In parent, child pid is #{pipe.pid}"
2890 * else
2891 * $stderr.puts "In child, pid is #{$$}"
2892 * end
2893 *
2894 * Output:
2895 *
2896 * In child, pid is 26209
2897 * In parent, child pid is 26209
2898 *
2899 */
2900
2901static VALUE
2902rb_io_pid(VALUE io)
2903{
2904 rb_io_t *fptr;
2905
2906 GetOpenFile(io, fptr);
2907 if (!fptr->pid)
2908 return Qnil;
2909 return PIDT2NUM(fptr->pid);
2910}
2911
2912/*
2913 * call-seq:
2914 * path -> string or nil
2915 *
2916 * Returns the path associated with the IO, or +nil+ if there is no path
2917 * associated with the IO. It is not guaranteed that the path exists on
2918 * the filesystem.
2919 *
2920 * $stdin.path # => "<STDIN>"
2921 *
2922 * File.open("testfile") {|f| f.path} # => "testfile"
2923 */
2924
2925static VALUE
2926rb_io_path(VALUE io)
2927{
2928 rb_io_t *fptr = RFILE(io)->fptr;
2929
2930 if (!fptr)
2931 return Qnil;
2932
2933 return rb_obj_dup(fptr->pathv);
2934}
2935
2936/*
2937 * call-seq:
2938 * inspect -> string
2939 *
2940 * Returns a string representation of +self+:
2941 *
2942 * f = File.open('t.txt')
2943 * f.inspect # => "#<File:t.txt>"
2944 * f.close
2945 *
2946 */
2947
2948static VALUE
2949rb_io_inspect(VALUE obj)
2950{
2951 rb_io_t *fptr;
2952 VALUE result;
2953 static const char closed[] = " (closed)";
2954
2955 fptr = RFILE(obj)->fptr;
2956 if (!fptr) return rb_any_to_s(obj);
2957 result = rb_str_new_cstr("#<");
2958 rb_str_append(result, rb_class_name(CLASS_OF(obj)));
2959 rb_str_cat2(result, ":");
2960 if (NIL_P(fptr->pathv)) {
2961 if (fptr->fd < 0) {
2962 rb_str_cat(result, closed+1, strlen(closed)-1);
2963 }
2964 else {
2965 rb_str_catf(result, "fd %d", fptr->fd);
2966 }
2967 }
2968 else {
2969 rb_str_append(result, fptr->pathv);
2970 if (fptr->fd < 0) {
2971 rb_str_cat(result, closed, strlen(closed));
2972 }
2973 }
2974 return rb_str_cat2(result, ">");
2975}
2976
2977/*
2978 * call-seq:
2979 * to_io -> self
2980 *
2981 * Returns +self+.
2982 *
2983 */
2984
2985static VALUE
2986rb_io_to_io(VALUE io)
2987{
2988 return io;
2989}
2990
2991/* reading functions */
2992static long
2993read_buffered_data(char *ptr, long len, rb_io_t *fptr)
2994{
2995 int n;
2996
2997 n = READ_DATA_PENDING_COUNT(fptr);
2998 if (n <= 0) return 0;
2999 if (n > len) n = (int)len;
3000 MEMMOVE(ptr, fptr->rbuf.ptr+fptr->rbuf.off, char, n);
3001 fptr->rbuf.off += n;
3002 fptr->rbuf.len -= n;
3003 return n;
3004}
3005
3006static long
3007io_bufread(char *ptr, long len, rb_io_t *fptr)
3008{
3009 long offset = 0;
3010 long n = len;
3011 long c;
3012
3013 if (READ_DATA_PENDING(fptr) == 0) {
3014 while (n > 0) {
3015 again:
3016 rb_io_check_closed(fptr);
3017 c = rb_io_read_memory(fptr, ptr+offset, n);
3018 if (c == 0) break;
3019 if (c < 0) {
3020 if (fptr_wait_readable(fptr))
3021 goto again;
3022 return -1;
3023 }
3024 offset += c;
3025 if ((n -= c) <= 0) break;
3026 }
3027 return len - n;
3028 }
3029
3030 while (n > 0) {
3031 c = read_buffered_data(ptr+offset, n, fptr);
3032 if (c > 0) {
3033 offset += c;
3034 if ((n -= c) <= 0) break;
3035 }
3036 rb_io_check_closed(fptr);
3037 if (io_fillbuf(fptr) < 0) {
3038 break;
3039 }
3040 }
3041 return len - n;
3042}
3043
3044static int io_setstrbuf(VALUE *str, long len);
3045
3047 char *str_ptr;
3048 long len;
3049 rb_io_t *fptr;
3050};
3051
3052static VALUE
3053bufread_call(VALUE arg)
3054{
3055 struct bufread_arg *p = (struct bufread_arg *)arg;
3056 p->len = io_bufread(p->str_ptr, p->len, p->fptr);
3057 return Qundef;
3058}
3059
3060static long
3061io_fread(VALUE str, long offset, long size, rb_io_t *fptr)
3062{
3063 long len;
3064 struct bufread_arg arg;
3065
3066 io_setstrbuf(&str, offset + size);
3067 arg.str_ptr = RSTRING_PTR(str) + offset;
3068 arg.len = size;
3069 arg.fptr = fptr;
3070 rb_str_locktmp_ensure(str, bufread_call, (VALUE)&arg);
3071 len = arg.len;
3072 if (len < 0) rb_sys_fail_path(fptr->pathv);
3073 return len;
3074}
3075
3076static long
3077remain_size(rb_io_t *fptr)
3078{
3079 struct stat st;
3080 rb_off_t siz = READ_DATA_PENDING_COUNT(fptr);
3081 rb_off_t pos;
3082
3083 if (fstat(fptr->fd, &st) == 0 && S_ISREG(st.st_mode)
3084#if defined(__HAIKU__)
3085 && (st.st_dev > 3)
3086#endif
3087 )
3088 {
3089 if (io_fflush(fptr) < 0)
3090 rb_sys_fail_on_write(fptr);
3091 pos = lseek(fptr->fd, 0, SEEK_CUR);
3092 if (st.st_size >= pos && pos >= 0) {
3093 siz += st.st_size - pos;
3094 if (siz > LONG_MAX) {
3095 rb_raise(rb_eIOError, "file too big for single read");
3096 }
3097 }
3098 }
3099 else {
3100 siz += BUFSIZ;
3101 }
3102 return (long)siz;
3103}
3104
3105static VALUE
3106io_enc_str(VALUE str, rb_io_t *fptr)
3107{
3108 rb_enc_associate(str, io_read_encoding(fptr));
3109 return str;
3110}
3111
3112static rb_encoding *io_read_encoding(rb_io_t *fptr);
3113
3114static void
3115make_readconv(rb_io_t *fptr, int size)
3116{
3117 if (!fptr->readconv) {
3118 int ecflags;
3119 VALUE ecopts;
3120 const char *sname, *dname;
3121 ecflags = fptr->encs.ecflags & ~ECONV_NEWLINE_DECORATOR_WRITE_MASK;
3122 ecopts = fptr->encs.ecopts;
3123 if (fptr->encs.enc2) {
3124 sname = rb_enc_name(fptr->encs.enc2);
3125 dname = rb_enc_name(io_read_encoding(fptr));
3126 }
3127 else {
3128 sname = dname = "";
3129 }
3130 fptr->readconv = rb_econv_open_opts(sname, dname, ecflags, ecopts);
3131 if (!fptr->readconv)
3132 rb_exc_raise(rb_econv_open_exc(sname, dname, ecflags));
3133 fptr->cbuf.off = 0;
3134 fptr->cbuf.len = 0;
3135 if (size < IO_CBUF_CAPA_MIN) size = IO_CBUF_CAPA_MIN;
3136 fptr->cbuf.capa = size;
3137 fptr->cbuf.ptr = ALLOC_N(char, fptr->cbuf.capa);
3138 }
3139}
3140
3141#define MORE_CHAR_SUSPENDED Qtrue
3142#define MORE_CHAR_FINISHED Qnil
3143static VALUE
3144fill_cbuf(rb_io_t *fptr, int ec_flags)
3145{
3146 const unsigned char *ss, *sp, *se;
3147 unsigned char *ds, *dp, *de;
3149 int putbackable;
3150 int cbuf_len0;
3151 VALUE exc;
3152
3153 ec_flags |= ECONV_PARTIAL_INPUT;
3154
3155 if (fptr->cbuf.len == fptr->cbuf.capa)
3156 return MORE_CHAR_SUSPENDED; /* cbuf full */
3157 if (fptr->cbuf.len == 0)
3158 fptr->cbuf.off = 0;
3159 else if (fptr->cbuf.off + fptr->cbuf.len == fptr->cbuf.capa) {
3160 memmove(fptr->cbuf.ptr, fptr->cbuf.ptr+fptr->cbuf.off, fptr->cbuf.len);
3161 fptr->cbuf.off = 0;
3162 }
3163
3164 cbuf_len0 = fptr->cbuf.len;
3165
3166 while (1) {
3167 ss = sp = (const unsigned char *)fptr->rbuf.ptr + fptr->rbuf.off;
3168 se = sp + fptr->rbuf.len;
3169 ds = dp = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.off + fptr->cbuf.len;
3170 de = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.capa;
3171 res = rb_econv_convert(fptr->readconv, &sp, se, &dp, de, ec_flags);
3172 fptr->rbuf.off += (int)(sp - ss);
3173 fptr->rbuf.len -= (int)(sp - ss);
3174 fptr->cbuf.len += (int)(dp - ds);
3175
3176 putbackable = rb_econv_putbackable(fptr->readconv);
3177 if (putbackable) {
3178 rb_econv_putback(fptr->readconv, (unsigned char *)fptr->rbuf.ptr + fptr->rbuf.off - putbackable, putbackable);
3179 fptr->rbuf.off -= putbackable;
3180 fptr->rbuf.len += putbackable;
3181 }
3182
3183 exc = rb_econv_make_exception(fptr->readconv);
3184 if (!NIL_P(exc))
3185 return exc;
3186
3187 if (cbuf_len0 != fptr->cbuf.len)
3188 return MORE_CHAR_SUSPENDED;
3189
3190 if (res == econv_finished) {
3191 return MORE_CHAR_FINISHED;
3192 }
3193
3194 if (res == econv_source_buffer_empty) {
3195 if (fptr->rbuf.len == 0) {
3196 READ_CHECK(fptr);
3197 if (io_fillbuf(fptr) < 0) {
3198 if (!fptr->readconv) {
3199 return MORE_CHAR_FINISHED;
3200 }
3201 ds = dp = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.off + fptr->cbuf.len;
3202 de = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.capa;
3203 res = rb_econv_convert(fptr->readconv, NULL, NULL, &dp, de, 0);
3204 fptr->cbuf.len += (int)(dp - ds);
3206 break;
3207 }
3208 }
3209 }
3210 }
3211 if (cbuf_len0 != fptr->cbuf.len)
3212 return MORE_CHAR_SUSPENDED;
3213
3214 return MORE_CHAR_FINISHED;
3215}
3216
3217static VALUE
3218more_char(rb_io_t *fptr)
3219{
3220 VALUE v;
3221 v = fill_cbuf(fptr, ECONV_AFTER_OUTPUT);
3222 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED)
3223 rb_exc_raise(v);
3224 return v;
3225}
3226
3227static VALUE
3228io_shift_cbuf(rb_io_t *fptr, int len, VALUE *strp)
3229{
3230 VALUE str = Qnil;
3231 if (strp) {
3232 str = *strp;
3233 if (NIL_P(str)) {
3234 *strp = str = rb_str_new(fptr->cbuf.ptr+fptr->cbuf.off, len);
3235 }
3236 else {
3237 rb_str_cat(str, fptr->cbuf.ptr+fptr->cbuf.off, len);
3238 }
3239 rb_enc_associate(str, fptr->encs.enc);
3240 }
3241 fptr->cbuf.off += len;
3242 fptr->cbuf.len -= len;
3243 /* xxx: set coderange */
3244 if (fptr->cbuf.len == 0)
3245 fptr->cbuf.off = 0;
3246 else if (fptr->cbuf.capa/2 < fptr->cbuf.off) {
3247 memmove(fptr->cbuf.ptr, fptr->cbuf.ptr+fptr->cbuf.off, fptr->cbuf.len);
3248 fptr->cbuf.off = 0;
3249 }
3250 return str;
3251}
3252
3253static int
3254io_setstrbuf(VALUE *str, long len)
3255{
3256#ifdef _WIN32
3257 if (len > 0)
3258 len = (len + 1) & ~1L; /* round up for wide char */
3259#endif
3260 if (NIL_P(*str)) {
3261 *str = rb_str_new(0, len);
3262 return TRUE;
3263 }
3264 else {
3265 VALUE s = StringValue(*str);
3266 long clen = RSTRING_LEN(s);
3267 if (clen >= len) {
3268 rb_str_modify(s);
3269 return FALSE;
3270 }
3271 len -= clen;
3272 }
3273 if ((rb_str_capacity(*str) - (size_t)RSTRING_LEN(*str)) < (size_t)len) {
3274 rb_str_modify_expand(*str, len);
3275 }
3276 return FALSE;
3277}
3278
3279#define MAX_REALLOC_GAP 4096
3280static void
3281io_shrink_read_string(VALUE str, long n)
3282{
3283 if (rb_str_capacity(str) - n > MAX_REALLOC_GAP) {
3284 rb_str_resize(str, n);
3285 }
3286}
3287
3288static void
3289io_set_read_length(VALUE str, long n, int shrinkable)
3290{
3291 if (RSTRING_LEN(str) != n) {
3292 rb_str_modify(str);
3293 rb_str_set_len(str, n);
3294 if (shrinkable) io_shrink_read_string(str, n);
3295 }
3296}
3297
3298static VALUE
3299read_all(rb_io_t *fptr, long siz, VALUE str)
3300{
3301 long bytes;
3302 long n;
3303 long pos;
3304 rb_encoding *enc;
3305 int cr;
3306 int shrinkable;
3307
3308 if (NEED_READCONV(fptr)) {
3309 int first = !NIL_P(str);
3310 SET_BINARY_MODE(fptr);
3311 shrinkable = io_setstrbuf(&str,0);
3312 make_readconv(fptr, 0);
3313 while (1) {
3314 VALUE v;
3315 if (fptr->cbuf.len) {
3316 if (first) rb_str_set_len(str, first = 0);
3317 io_shift_cbuf(fptr, fptr->cbuf.len, &str);
3318 }
3319 v = fill_cbuf(fptr, 0);
3320 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED) {
3321 if (fptr->cbuf.len) {
3322 if (first) rb_str_set_len(str, first = 0);
3323 io_shift_cbuf(fptr, fptr->cbuf.len, &str);
3324 }
3325 rb_exc_raise(v);
3326 }
3327 if (v == MORE_CHAR_FINISHED) {
3328 clear_readconv(fptr);
3329 if (first) rb_str_set_len(str, first = 0);
3330 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3331 return io_enc_str(str, fptr);
3332 }
3333 }
3334 }
3335
3336 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3337 bytes = 0;
3338 pos = 0;
3339
3340 enc = io_read_encoding(fptr);
3341 cr = 0;
3342
3343 if (siz == 0) siz = BUFSIZ;
3344 shrinkable = io_setstrbuf(&str, siz);
3345 for (;;) {
3346 READ_CHECK(fptr);
3347 n = io_fread(str, bytes, siz - bytes, fptr);
3348 if (n == 0 && bytes == 0) {
3349 rb_str_set_len(str, 0);
3350 break;
3351 }
3352 bytes += n;
3353 rb_str_set_len(str, bytes);
3354 if (cr != ENC_CODERANGE_BROKEN)
3355 pos += rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + bytes, enc, &cr);
3356 if (bytes < siz) break;
3357 siz += BUFSIZ;
3358
3359 size_t capa = rb_str_capacity(str);
3360 if (capa < (size_t)RSTRING_LEN(str) + BUFSIZ) {
3361 if (capa < BUFSIZ) {
3362 capa = BUFSIZ;
3363 }
3364 else if (capa > IO_MAX_BUFFER_GROWTH) {
3365 capa = IO_MAX_BUFFER_GROWTH;
3366 }
3367 rb_str_modify_expand(str, capa);
3368 }
3369 }
3370 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3371 str = io_enc_str(str, fptr);
3372 ENC_CODERANGE_SET(str, cr);
3373 return str;
3374}
3375
3376void
3378{
3379 if (rb_fd_set_nonblock(fptr->fd) != 0) {
3380 rb_sys_fail_path(fptr->pathv);
3381 }
3382}
3383
3384static VALUE
3385io_read_memory_call(VALUE arg)
3386{
3387 struct io_internal_read_struct *iis = (struct io_internal_read_struct *)arg;
3388
3389 VALUE scheduler = rb_fiber_scheduler_current();
3390 if (scheduler != Qnil) {
3391 VALUE result = rb_fiber_scheduler_io_read_memory(scheduler, iis->fptr->self, iis->buf, iis->capa, 0);
3392
3393 if (!UNDEF_P(result)) {
3394 // This is actually returned as a pseudo-VALUE and later cast to a long:
3396 }
3397 }
3398
3399 return rb_thread_io_blocking_region(internal_read_func, iis, iis->fptr->fd);
3400}
3401
3402static long
3403io_read_memory_locktmp(VALUE str, struct io_internal_read_struct *iis)
3404{
3405 return (long)rb_str_locktmp_ensure(str, io_read_memory_call, (VALUE)iis);
3406}
3407
3408#define no_exception_p(opts) !rb_opts_exception_p((opts), TRUE)
3409
3410static VALUE
3411io_getpartial(int argc, VALUE *argv, VALUE io, int no_exception, int nonblock)
3412{
3413 rb_io_t *fptr;
3414 VALUE length, str;
3415 long n, len;
3416 struct io_internal_read_struct iis;
3417 int shrinkable;
3418
3419 rb_scan_args(argc, argv, "11", &length, &str);
3420
3421 if ((len = NUM2LONG(length)) < 0) {
3422 rb_raise(rb_eArgError, "negative length %ld given", len);
3423 }
3424
3425 shrinkable = io_setstrbuf(&str, len);
3426
3427 GetOpenFile(io, fptr);
3429
3430 if (len == 0) {
3431 io_set_read_length(str, 0, shrinkable);
3432 return str;
3433 }
3434
3435 if (!nonblock)
3436 READ_CHECK(fptr);
3437 n = read_buffered_data(RSTRING_PTR(str), len, fptr);
3438 if (n <= 0) {
3439 again:
3440 if (nonblock) {
3441 rb_io_set_nonblock(fptr);
3442 }
3443 io_setstrbuf(&str, len);
3444 iis.th = rb_thread_current();
3445 iis.fptr = fptr;
3446 iis.nonblock = nonblock;
3447 iis.fd = fptr->fd;
3448 iis.buf = RSTRING_PTR(str);
3449 iis.capa = len;
3450 iis.timeout = NULL;
3451 n = io_read_memory_locktmp(str, &iis);
3452 if (n < 0) {
3453 int e = errno;
3454 if (!nonblock && fptr_wait_readable(fptr))
3455 goto again;
3456 if (nonblock && (io_again_p(e))) {
3457 if (no_exception)
3458 return sym_wait_readable;
3459 else
3460 rb_readwrite_syserr_fail(RB_IO_WAIT_READABLE,
3461 e, "read would block");
3462 }
3463 rb_syserr_fail_path(e, fptr->pathv);
3464 }
3465 }
3466 io_set_read_length(str, n, shrinkable);
3467
3468 if (n == 0)
3469 return Qnil;
3470 else
3471 return str;
3472}
3473
3474/*
3475 * call-seq:
3476 * readpartial(maxlen) -> string
3477 * readpartial(maxlen, out_string) -> out_string
3478 *
3479 * Reads up to +maxlen+ bytes from the stream;
3480 * returns a string (either a new string or the given +out_string+).
3481 * Its encoding is:
3482 *
3483 * - The unchanged encoding of +out_string+, if +out_string+ is given.
3484 * - ASCII-8BIT, otherwise.
3485 *
3486 * - Contains +maxlen+ bytes from the stream, if available.
3487 * - Otherwise contains all available bytes, if any available.
3488 * - Otherwise is an empty string.
3489 *
3490 * With the single non-negative integer argument +maxlen+ given,
3491 * returns a new string:
3492 *
3493 * f = File.new('t.txt')
3494 * f.readpartial(20) # => "First line\nSecond l"
3495 * f.readpartial(20) # => "ine\n\nFourth line\n"
3496 * f.readpartial(20) # => "Fifth line\n"
3497 * f.readpartial(20) # Raises EOFError.
3498 * f.close
3499 *
3500 * With both argument +maxlen+ and string argument +out_string+ given,
3501 * returns modified +out_string+:
3502 *
3503 * f = File.new('t.txt')
3504 * s = 'foo'
3505 * f.readpartial(20, s) # => "First line\nSecond l"
3506 * s = 'bar'
3507 * f.readpartial(0, s) # => ""
3508 * f.close
3509 *
3510 * This method is useful for a stream such as a pipe, a socket, or a tty.
3511 * It blocks only when no data is immediately available.
3512 * This means that it blocks only when _all_ of the following are true:
3513 *
3514 * - The byte buffer in the stream is empty.
3515 * - The content of the stream is empty.
3516 * - The stream is not at EOF.
3517 *
3518 * When blocked, the method waits for either more data or EOF on the stream:
3519 *
3520 * - If more data is read, the method returns the data.
3521 * - If EOF is reached, the method raises EOFError.
3522 *
3523 * When not blocked, the method responds immediately:
3524 *
3525 * - Returns data from the buffer if there is any.
3526 * - Otherwise returns data from the stream if there is any.
3527 * - Otherwise raises EOFError if the stream has reached EOF.
3528 *
3529 * Note that this method is similar to sysread. The differences are:
3530 *
3531 * - If the byte buffer is not empty, read from the byte buffer
3532 * instead of "sysread for buffered IO (IOError)".
3533 * - It doesn't cause Errno::EWOULDBLOCK and Errno::EINTR. When
3534 * readpartial meets EWOULDBLOCK and EINTR by read system call,
3535 * readpartial retries the system call.
3536 *
3537 * The latter means that readpartial is non-blocking-flag insensitive.
3538 * It blocks on the situation IO#sysread causes Errno::EWOULDBLOCK as
3539 * if the fd is blocking mode.
3540 *
3541 * Examples:
3542 *
3543 * # # Returned Buffer Content Pipe Content
3544 * r, w = IO.pipe #
3545 * w << 'abc' # "" "abc".
3546 * r.readpartial(4096) # => "abc" "" ""
3547 * r.readpartial(4096) # (Blocks because buffer and pipe are empty.)
3548 *
3549 * # # Returned Buffer Content Pipe Content
3550 * r, w = IO.pipe #
3551 * w << 'abc' # "" "abc"
3552 * w.close # "" "abc" EOF
3553 * r.readpartial(4096) # => "abc" "" EOF
3554 * r.readpartial(4096) # raises EOFError
3555 *
3556 * # # Returned Buffer Content Pipe Content
3557 * r, w = IO.pipe #
3558 * w << "abc\ndef\n" # "" "abc\ndef\n"
3559 * r.gets # => "abc\n" "def\n" ""
3560 * w << "ghi\n" # "def\n" "ghi\n"
3561 * r.readpartial(4096) # => "def\n" "" "ghi\n"
3562 * r.readpartial(4096) # => "ghi\n" "" ""
3563 *
3564 */
3565
3566static VALUE
3567io_readpartial(int argc, VALUE *argv, VALUE io)
3568{
3569 VALUE ret;
3570
3571 ret = io_getpartial(argc, argv, io, Qnil, 0);
3572 if (NIL_P(ret))
3573 rb_eof_error();
3574 return ret;
3575}
3576
3577static VALUE
3578io_nonblock_eof(int no_exception)
3579{
3580 if (!no_exception) {
3581 rb_eof_error();
3582 }
3583 return Qnil;
3584}
3585
3586/* :nodoc: */
3587static VALUE
3588io_read_nonblock(rb_execution_context_t *ec, VALUE io, VALUE length, VALUE str, VALUE ex)
3589{
3590 rb_io_t *fptr;
3591 long n, len;
3592 struct io_internal_read_struct iis;
3593 int shrinkable;
3594
3595 if ((len = NUM2LONG(length)) < 0) {
3596 rb_raise(rb_eArgError, "negative length %ld given", len);
3597 }
3598
3599 shrinkable = io_setstrbuf(&str, len);
3600 rb_bool_expected(ex, "exception", TRUE);
3601
3602 GetOpenFile(io, fptr);
3604
3605 if (len == 0) {
3606 io_set_read_length(str, 0, shrinkable);
3607 return str;
3608 }
3609
3610 n = read_buffered_data(RSTRING_PTR(str), len, fptr);
3611 if (n <= 0) {
3612 rb_fd_set_nonblock(fptr->fd);
3613 shrinkable |= io_setstrbuf(&str, len);
3614 iis.fptr = fptr;
3615 iis.nonblock = 1;
3616 iis.fd = fptr->fd;
3617 iis.buf = RSTRING_PTR(str);
3618 iis.capa = len;
3619 iis.timeout = NULL;
3620 n = io_read_memory_locktmp(str, &iis);
3621 if (n < 0) {
3622 int e = errno;
3623 if (io_again_p(e)) {
3624 if (!ex) return sym_wait_readable;
3625 rb_readwrite_syserr_fail(RB_IO_WAIT_READABLE,
3626 e, "read would block");
3627 }
3628 rb_syserr_fail_path(e, fptr->pathv);
3629 }
3630 }
3631 io_set_read_length(str, n, shrinkable);
3632
3633 if (n == 0) {
3634 if (!ex) return Qnil;
3635 rb_eof_error();
3636 }
3637
3638 return str;
3639}
3640
3641/* :nodoc: */
3642static VALUE
3643io_write_nonblock(rb_execution_context_t *ec, VALUE io, VALUE str, VALUE ex)
3644{
3645 rb_io_t *fptr;
3646 long n;
3647
3648 if (!RB_TYPE_P(str, T_STRING))
3649 str = rb_obj_as_string(str);
3650 rb_bool_expected(ex, "exception", TRUE);
3651
3652 io = GetWriteIO(io);
3653 GetOpenFile(io, fptr);
3655
3656 if (io_fflush(fptr) < 0)
3657 rb_sys_fail_on_write(fptr);
3658
3659 rb_fd_set_nonblock(fptr->fd);
3660 n = write(fptr->fd, RSTRING_PTR(str), RSTRING_LEN(str));
3661 RB_GC_GUARD(str);
3662
3663 if (n < 0) {
3664 int e = errno;
3665 if (io_again_p(e)) {
3666 if (!ex) {
3667 return sym_wait_writable;
3668 }
3669 else {
3670 rb_readwrite_syserr_fail(RB_IO_WAIT_WRITABLE, e, "write would block");
3671 }
3672 }
3673 rb_syserr_fail_path(e, fptr->pathv);
3674 }
3675
3676 return LONG2FIX(n);
3677}
3678
3679/*
3680 * call-seq:
3681 * read(maxlen = nil, out_string = nil) -> new_string, out_string, or nil
3682 *
3683 * Reads bytes from the stream; the stream must be opened for reading
3684 * (see {Access Modes}[rdoc-ref:File@Access+Modes]):
3685 *
3686 * - If +maxlen+ is +nil+, reads all bytes using the stream's data mode.
3687 * - Otherwise reads up to +maxlen+ bytes in binary mode.
3688 *
3689 * Returns a string (either a new string or the given +out_string+)
3690 * containing the bytes read.
3691 * The encoding of the string depends on both +maxLen+ and +out_string+:
3692 *
3693 * - +maxlen+ is +nil+: uses internal encoding of +self+
3694 * (regardless of whether +out_string+ was given).
3695 * - +maxlen+ not +nil+:
3696 *
3697 * - +out_string+ given: encoding of +out_string+ not modified.
3698 * - +out_string+ not given: ASCII-8BIT is used.
3699 *
3700 * <b>Without Argument +out_string+</b>
3701 *
3702 * When argument +out_string+ is omitted,
3703 * the returned value is a new string:
3704 *
3705 * f = File.new('t.txt')
3706 * f.read
3707 * # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3708 * f.rewind
3709 * f.read(30) # => "First line\r\nSecond line\r\n\r\nFou"
3710 * f.read(30) # => "rth line\r\nFifth line\r\n"
3711 * f.read(30) # => nil
3712 * f.close
3713 *
3714 * If +maxlen+ is zero, returns an empty string.
3715 *
3716 * <b> With Argument +out_string+</b>
3717 *
3718 * When argument +out_string+ is given,
3719 * the returned value is +out_string+, whose content is replaced:
3720 *
3721 * f = File.new('t.txt')
3722 * s = 'foo' # => "foo"
3723 * f.read(nil, s) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3724 * s # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3725 * f.rewind
3726 * s = 'bar'
3727 * f.read(30, s) # => "First line\r\nSecond line\r\n\r\nFou"
3728 * s # => "First line\r\nSecond line\r\n\r\nFou"
3729 * s = 'baz'
3730 * f.read(30, s) # => "rth line\r\nFifth line\r\n"
3731 * s # => "rth line\r\nFifth line\r\n"
3732 * s = 'bat'
3733 * f.read(30, s) # => nil
3734 * s # => ""
3735 * f.close
3736 *
3737 * Note that this method behaves like the fread() function in C.
3738 * This means it retries to invoke read(2) system calls to read data
3739 * with the specified maxlen (or until EOF).
3740 *
3741 * This behavior is preserved even if the stream is in non-blocking mode.
3742 * (This method is non-blocking-flag insensitive as other methods.)
3743 *
3744 * If you need the behavior like a single read(2) system call,
3745 * consider #readpartial, #read_nonblock, and #sysread.
3746 *
3747 * Related: IO#write.
3748 */
3749
3750static VALUE
3751io_read(int argc, VALUE *argv, VALUE io)
3752{
3753 rb_io_t *fptr;
3754 long n, len;
3755 VALUE length, str;
3756 int shrinkable;
3757#if RUBY_CRLF_ENVIRONMENT
3758 int previous_mode;
3759#endif
3760
3761 rb_scan_args(argc, argv, "02", &length, &str);
3762
3763 if (NIL_P(length)) {
3764 GetOpenFile(io, fptr);
3766 return read_all(fptr, remain_size(fptr), str);
3767 }
3768 len = NUM2LONG(length);
3769 if (len < 0) {
3770 rb_raise(rb_eArgError, "negative length %ld given", len);
3771 }
3772
3773 shrinkable = io_setstrbuf(&str,len);
3774
3775 GetOpenFile(io, fptr);
3777 if (len == 0) {
3778 io_set_read_length(str, 0, shrinkable);
3779 return str;
3780 }
3781
3782 READ_CHECK(fptr);
3783#if RUBY_CRLF_ENVIRONMENT
3784 previous_mode = set_binary_mode_with_seek_cur(fptr);
3785#endif
3786 n = io_fread(str, 0, len, fptr);
3787 io_set_read_length(str, n, shrinkable);
3788#if RUBY_CRLF_ENVIRONMENT
3789 if (previous_mode == O_TEXT) {
3790 setmode(fptr->fd, O_TEXT);
3791 }
3792#endif
3793 if (n == 0) return Qnil;
3794
3795 return str;
3796}
3797
3798static void
3799rscheck(const char *rsptr, long rslen, VALUE rs)
3800{
3801 if (!rs) return;
3802 if (RSTRING_PTR(rs) != rsptr && RSTRING_LEN(rs) != rslen)
3803 rb_raise(rb_eRuntimeError, "rs modified");
3804}
3805
3806static int
3807appendline(rb_io_t *fptr, int delim, VALUE *strp, long *lp)
3808{
3809 VALUE str = *strp;
3810 long limit = *lp;
3811
3812 if (NEED_READCONV(fptr)) {
3813 SET_BINARY_MODE(fptr);
3814 make_readconv(fptr, 0);
3815 do {
3816 const char *p, *e;
3817 int searchlen = READ_CHAR_PENDING_COUNT(fptr);
3818 if (searchlen) {
3819 p = READ_CHAR_PENDING_PTR(fptr);
3820 if (0 < limit && limit < searchlen)
3821 searchlen = (int)limit;
3822 e = memchr(p, delim, searchlen);
3823 if (e) {
3824 int len = (int)(e-p+1);
3825 if (NIL_P(str))
3826 *strp = str = rb_str_new(p, len);
3827 else
3828 rb_str_buf_cat(str, p, len);
3829 fptr->cbuf.off += len;
3830 fptr->cbuf.len -= len;
3831 limit -= len;
3832 *lp = limit;
3833 return delim;
3834 }
3835
3836 if (NIL_P(str))
3837 *strp = str = rb_str_new(p, searchlen);
3838 else
3839 rb_str_buf_cat(str, p, searchlen);
3840 fptr->cbuf.off += searchlen;
3841 fptr->cbuf.len -= searchlen;
3842 limit -= searchlen;
3843
3844 if (limit == 0) {
3845 *lp = limit;
3846 return (unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
3847 }
3848 }
3849 } while (more_char(fptr) != MORE_CHAR_FINISHED);
3850 clear_readconv(fptr);
3851 *lp = limit;
3852 return EOF;
3853 }
3854
3855 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3856 do {
3857 long pending = READ_DATA_PENDING_COUNT(fptr);
3858 if (pending > 0) {
3859 const char *p = READ_DATA_PENDING_PTR(fptr);
3860 const char *e;
3861 long last;
3862
3863 if (limit > 0 && pending > limit) pending = limit;
3864 e = memchr(p, delim, pending);
3865 if (e) pending = e - p + 1;
3866 if (!NIL_P(str)) {
3867 last = RSTRING_LEN(str);
3868 rb_str_resize(str, last + pending);
3869 }
3870 else {
3871 last = 0;
3872 *strp = str = rb_str_buf_new(pending);
3873 rb_str_set_len(str, pending);
3874 }
3875 read_buffered_data(RSTRING_PTR(str) + last, pending, fptr); /* must not fail */
3876 limit -= pending;
3877 *lp = limit;
3878 if (e) return delim;
3879 if (limit == 0)
3880 return (unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
3881 }
3882 READ_CHECK(fptr);
3883 } while (io_fillbuf(fptr) >= 0);
3884 *lp = limit;
3885 return EOF;
3886}
3887
3888static inline int
3889swallow(rb_io_t *fptr, int term)
3890{
3891 if (NEED_READCONV(fptr)) {
3892 rb_encoding *enc = io_read_encoding(fptr);
3893 int needconv = rb_enc_mbminlen(enc) != 1;
3894 SET_BINARY_MODE(fptr);
3895 make_readconv(fptr, 0);
3896 do {
3897 size_t cnt;
3898 while ((cnt = READ_CHAR_PENDING_COUNT(fptr)) > 0) {
3899 const char *p = READ_CHAR_PENDING_PTR(fptr);
3900 int i;
3901 if (!needconv) {
3902 if (*p != term) return TRUE;
3903 i = (int)cnt;
3904 while (--i && *++p == term);
3905 }
3906 else {
3907 const char *e = p + cnt;
3908 if (rb_enc_ascget(p, e, &i, enc) != term) return TRUE;
3909 while ((p += i) < e && rb_enc_ascget(p, e, &i, enc) == term);
3910 i = (int)(e - p);
3911 }
3912 io_shift_cbuf(fptr, (int)cnt - i, NULL);
3913 }
3914 } while (more_char(fptr) != MORE_CHAR_FINISHED);
3915 return FALSE;
3916 }
3917
3918 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3919 do {
3920 size_t cnt;
3921 while ((cnt = READ_DATA_PENDING_COUNT(fptr)) > 0) {
3922 char buf[1024];
3923 const char *p = READ_DATA_PENDING_PTR(fptr);
3924 int i;
3925 if (cnt > sizeof buf) cnt = sizeof buf;
3926 if (*p != term) return TRUE;
3927 i = (int)cnt;
3928 while (--i && *++p == term);
3929 if (!read_buffered_data(buf, cnt - i, fptr)) /* must not fail */
3930 rb_sys_fail_path(fptr->pathv);
3931 }
3932 READ_CHECK(fptr);
3933 } while (io_fillbuf(fptr) == 0);
3934 return FALSE;
3935}
3936
3937static VALUE
3938rb_io_getline_fast(rb_io_t *fptr, rb_encoding *enc, int chomp)
3939{
3940 VALUE str = Qnil;
3941 int len = 0;
3942 long pos = 0;
3943 int cr = 0;
3944
3945 do {
3946 int pending = READ_DATA_PENDING_COUNT(fptr);
3947
3948 if (pending > 0) {
3949 const char *p = READ_DATA_PENDING_PTR(fptr);
3950 const char *e;
3951 int chomplen = 0;
3952
3953 e = memchr(p, '\n', pending);
3954 if (e) {
3955 pending = (int)(e - p + 1);
3956 if (chomp) {
3957 chomplen = (pending > 1 && *(e-1) == '\r') + 1;
3958 }
3959 }
3960 if (NIL_P(str)) {
3961 str = rb_str_new(p, pending - chomplen);
3962 fptr->rbuf.off += pending;
3963 fptr->rbuf.len -= pending;
3964 }
3965 else {
3966 rb_str_resize(str, len + pending - chomplen);
3967 read_buffered_data(RSTRING_PTR(str)+len, pending - chomplen, fptr);
3968 fptr->rbuf.off += chomplen;
3969 fptr->rbuf.len -= chomplen;
3970 if (pending == 1 && chomplen == 1 && len > 0) {
3971 if (RSTRING_PTR(str)[len-1] == '\r') {
3972 rb_str_resize(str, --len);
3973 break;
3974 }
3975 }
3976 }
3977 len += pending - chomplen;
3978 if (cr != ENC_CODERANGE_BROKEN)
3979 pos += rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + len, enc, &cr);
3980 if (e) break;
3981 }
3982 READ_CHECK(fptr);
3983 } while (io_fillbuf(fptr) >= 0);
3984 if (NIL_P(str)) return Qnil;
3985
3986 str = io_enc_str(str, fptr);
3987 ENC_CODERANGE_SET(str, cr);
3988 fptr->lineno++;
3989
3990 return str;
3991}
3992
3994 VALUE io;
3995 VALUE rs;
3996 long limit;
3997 unsigned int chomp: 1;
3998};
3999
4000static void
4001extract_getline_opts(VALUE opts, struct getline_arg *args)
4002{
4003 int chomp = FALSE;
4004 if (!NIL_P(opts)) {
4005 static ID kwds[1];
4006 VALUE vchomp;
4007 if (!kwds[0]) {
4008 kwds[0] = rb_intern_const("chomp");
4009 }
4010 rb_get_kwargs(opts, kwds, 0, -2, &vchomp);
4011 chomp = (!UNDEF_P(vchomp)) && RTEST(vchomp);
4012 }
4013 args->chomp = chomp;
4014}
4015
4016static void
4017extract_getline_args(int argc, VALUE *argv, struct getline_arg *args)
4018{
4019 VALUE rs = rb_rs, lim = Qnil;
4020
4021 if (argc == 1) {
4022 VALUE tmp = Qnil;
4023
4024 if (NIL_P(argv[0]) || !NIL_P(tmp = rb_check_string_type(argv[0]))) {
4025 rs = tmp;
4026 }
4027 else {
4028 lim = argv[0];
4029 }
4030 }
4031 else if (2 <= argc) {
4032 rs = argv[0], lim = argv[1];
4033 if (!NIL_P(rs))
4034 StringValue(rs);
4035 }
4036 args->rs = rs;
4037 args->limit = NIL_P(lim) ? -1L : NUM2LONG(lim);
4038}
4039
4040static void
4041check_getline_args(VALUE *rsp, long *limit, VALUE io)
4042{
4043 rb_io_t *fptr;
4044 VALUE rs = *rsp;
4045
4046 if (!NIL_P(rs)) {
4047 rb_encoding *enc_rs, *enc_io;
4048
4049 GetOpenFile(io, fptr);
4050 enc_rs = rb_enc_get(rs);
4051 enc_io = io_read_encoding(fptr);
4052 if (enc_io != enc_rs &&
4053 (!is_ascii_string(rs) ||
4054 (RSTRING_LEN(rs) > 0 && !rb_enc_asciicompat(enc_io)))) {
4055 if (rs == rb_default_rs) {
4056 rs = rb_enc_str_new(0, 0, enc_io);
4057 rb_str_buf_cat_ascii(rs, "\n");
4058 *rsp = rs;
4059 }
4060 else {
4061 rb_raise(rb_eArgError, "encoding mismatch: %s IO with %s RS",
4062 rb_enc_name(enc_io),
4063 rb_enc_name(enc_rs));
4064 }
4065 }
4066 }
4067}
4068
4069static void
4070prepare_getline_args(int argc, VALUE *argv, struct getline_arg *args, VALUE io)
4071{
4072 VALUE opts;
4073 argc = rb_scan_args(argc, argv, "02:", NULL, NULL, &opts);
4074 extract_getline_args(argc, argv, args);
4075 extract_getline_opts(opts, args);
4076 check_getline_args(&args->rs, &args->limit, io);
4077}
4078
4079static VALUE
4080rb_io_getline_0(VALUE rs, long limit, int chomp, rb_io_t *fptr)
4081{
4082 VALUE str = Qnil;
4083 int nolimit = 0;
4084 rb_encoding *enc;
4085
4087 if (NIL_P(rs) && limit < 0) {
4088 str = read_all(fptr, 0, Qnil);
4089 if (RSTRING_LEN(str) == 0) return Qnil;
4090 }
4091 else if (limit == 0) {
4092 return rb_enc_str_new(0, 0, io_read_encoding(fptr));
4093 }
4094 else if (rs == rb_default_rs && limit < 0 && !NEED_READCONV(fptr) &&
4095 rb_enc_asciicompat(enc = io_read_encoding(fptr))) {
4096 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4097 return rb_io_getline_fast(fptr, enc, chomp);
4098 }
4099 else {
4100 int c, newline = -1;
4101 const char *rsptr = 0;
4102 long rslen = 0;
4103 int rspara = 0;
4104 int extra_limit = 16;
4105 int chomp_cr = chomp;
4106
4107 SET_BINARY_MODE(fptr);
4108 enc = io_read_encoding(fptr);
4109
4110 if (!NIL_P(rs)) {
4111 rslen = RSTRING_LEN(rs);
4112 if (rslen == 0) {
4113 rsptr = "\n\n";
4114 rslen = 2;
4115 rspara = 1;
4116 swallow(fptr, '\n');
4117 rs = 0;
4118 if (!rb_enc_asciicompat(enc)) {
4119 rs = rb_usascii_str_new(rsptr, rslen);
4120 rs = rb_str_encode(rs, rb_enc_from_encoding(enc), 0, Qnil);
4121 OBJ_FREEZE(rs);
4122 rsptr = RSTRING_PTR(rs);
4123 rslen = RSTRING_LEN(rs);
4124 }
4125 }
4126 else {
4127 rsptr = RSTRING_PTR(rs);
4128 }
4129 newline = (unsigned char)rsptr[rslen - 1];
4130 chomp_cr = chomp && rslen == 1 && newline == '\n';
4131 }
4132
4133 /* MS - Optimization */
4134 while ((c = appendline(fptr, newline, &str, &limit)) != EOF) {
4135 const char *s, *p, *pp, *e;
4136
4137 if (c == newline) {
4138 if (RSTRING_LEN(str) < rslen) continue;
4139 s = RSTRING_PTR(str);
4140 e = RSTRING_END(str);
4141 p = e - rslen;
4142 pp = rb_enc_left_char_head(s, p, e, enc);
4143 if (pp != p) continue;
4144 if (!rspara) rscheck(rsptr, rslen, rs);
4145 if (memcmp(p, rsptr, rslen) == 0) {
4146 if (chomp) {
4147 if (chomp_cr && p > s && *(p-1) == '\r') --p;
4148 rb_str_set_len(str, p - s);
4149 }
4150 break;
4151 }
4152 }
4153 if (limit == 0) {
4154 s = RSTRING_PTR(str);
4155 p = RSTRING_END(str);
4156 pp = rb_enc_left_char_head(s, p-1, p, enc);
4157 if (extra_limit &&
4158 MBCLEN_NEEDMORE_P(rb_enc_precise_mbclen(pp, p, enc))) {
4159 /* relax the limit while incomplete character.
4160 * extra_limit limits the relax length */
4161 limit = 1;
4162 extra_limit--;
4163 }
4164 else {
4165 nolimit = 1;
4166 break;
4167 }
4168 }
4169 }
4170
4171 if (rspara && c != EOF)
4172 swallow(fptr, '\n');
4173 if (!NIL_P(str))
4174 str = io_enc_str(str, fptr);
4175 }
4176
4177 if (!NIL_P(str) && !nolimit) {
4178 fptr->lineno++;
4179 }
4180
4181 return str;
4182}
4183
4184static VALUE
4185rb_io_getline_1(VALUE rs, long limit, int chomp, VALUE io)
4186{
4187 rb_io_t *fptr;
4188 int old_lineno, new_lineno;
4189 VALUE str;
4190
4191 GetOpenFile(io, fptr);
4192 old_lineno = fptr->lineno;
4193 str = rb_io_getline_0(rs, limit, chomp, fptr);
4194 if (!NIL_P(str) && (new_lineno = fptr->lineno) != old_lineno) {
4195 if (io == ARGF.current_file) {
4196 ARGF.lineno += new_lineno - old_lineno;
4197 ARGF.last_lineno = ARGF.lineno;
4198 }
4199 else {
4200 ARGF.last_lineno = new_lineno;
4201 }
4202 }
4203
4204 return str;
4205}
4206
4207static VALUE
4208rb_io_getline(int argc, VALUE *argv, VALUE io)
4209{
4210 struct getline_arg args;
4211
4212 prepare_getline_args(argc, argv, &args, io);
4213 return rb_io_getline_1(args.rs, args.limit, args.chomp, io);
4214}
4215
4216VALUE
4218{
4219 return rb_io_getline_1(rb_default_rs, -1, FALSE, io);
4220}
4221
4222VALUE
4223rb_io_gets_internal(VALUE io)
4224{
4225 rb_io_t *fptr;
4226 GetOpenFile(io, fptr);
4227 return rb_io_getline_0(rb_default_rs, -1, FALSE, fptr);
4228}
4229
4230/*
4231 * call-seq:
4232 * gets(sep = $/, chomp: false) -> string or nil
4233 * gets(limit, chomp: false) -> string or nil
4234 * gets(sep, limit, chomp: false) -> string or nil
4235 *
4236 * Reads and returns a line from the stream;
4237 * assigns the return value to <tt>$_</tt>.
4238 * See {Line IO}[rdoc-ref:IO@Line+IO].
4239 *
4240 * With no arguments given, returns the next line
4241 * as determined by line separator <tt>$/</tt>, or +nil+ if none:
4242 *
4243 * f = File.open('t.txt')
4244 * f.gets # => "First line\n"
4245 * $_ # => "First line\n"
4246 * f.gets # => "\n"
4247 * f.gets # => "Fourth line\n"
4248 * f.gets # => "Fifth line\n"
4249 * f.gets # => nil
4250 * f.close
4251 *
4252 * With only string argument +sep+ given,
4253 * returns the next line as determined by line separator +sep+,
4254 * or +nil+ if none;
4255 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4256 *
4257 * f = File.new('t.txt')
4258 * f.gets('l') # => "First l"
4259 * f.gets('li') # => "ine\nSecond li"
4260 * f.gets('lin') # => "ne\n\nFourth lin"
4261 * f.gets # => "e\n"
4262 * f.close
4263 *
4264 * The two special values for +sep+ are honored:
4265 *
4266 * f = File.new('t.txt')
4267 * # Get all.
4268 * f.gets(nil) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
4269 * f.rewind
4270 * # Get paragraph (up to two line separators).
4271 * f.gets('') # => "First line\nSecond line\n\n"
4272 * f.close
4273 *
4274 * With only integer argument +limit+ given,
4275 * limits the number of bytes in the line;
4276 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4277 *
4278 * # No more than one line.
4279 * File.open('t.txt') {|f| f.gets(10) } # => "First line"
4280 * File.open('t.txt') {|f| f.gets(11) } # => "First line\n"
4281 * File.open('t.txt') {|f| f.gets(12) } # => "First line\n"
4282 *
4283 * With arguments +sep+ and +limit+ given,
4284 * combines the two behaviors:
4285 *
4286 * - Returns the next line as determined by line separator +sep+,
4287 * or +nil+ if none.
4288 * - But returns no more bytes than are allowed by the limit.
4289 *
4290 * Optional keyword argument +chomp+ specifies whether line separators
4291 * are to be omitted:
4292 *
4293 * f = File.open('t.txt')
4294 * # Chomp the lines.
4295 * f.gets(chomp: true) # => "First line"
4296 * f.gets(chomp: true) # => "Second line"
4297 * f.gets(chomp: true) # => ""
4298 * f.gets(chomp: true) # => "Fourth line"
4299 * f.gets(chomp: true) # => "Fifth line"
4300 * f.gets(chomp: true) # => nil
4301 * f.close
4302 *
4303 */
4304
4305static VALUE
4306rb_io_gets_m(int argc, VALUE *argv, VALUE io)
4307{
4308 VALUE str;
4309
4310 str = rb_io_getline(argc, argv, io);
4311 rb_lastline_set(str);
4312
4313 return str;
4314}
4315
4316/*
4317 * call-seq:
4318 * lineno -> integer
4319 *
4320 * Returns the current line number for the stream;
4321 * see {Line Number}[rdoc-ref:IO@Line+Number].
4322 *
4323 */
4324
4325static VALUE
4326rb_io_lineno(VALUE io)
4327{
4328 rb_io_t *fptr;
4329
4330 GetOpenFile(io, fptr);
4332 return INT2NUM(fptr->lineno);
4333}
4334
4335/*
4336 * call-seq:
4337 * lineno = integer -> integer
4338 *
4339 * Sets and returns the line number for the stream;
4340 * see {Line Number}[rdoc-ref:IO@Line+Number].
4341 *
4342 */
4343
4344static VALUE
4345rb_io_set_lineno(VALUE io, VALUE lineno)
4346{
4347 rb_io_t *fptr;
4348
4349 GetOpenFile(io, fptr);
4351 fptr->lineno = NUM2INT(lineno);
4352 return lineno;
4353}
4354
4355/*
4356 * call-seq:
4357 * readline(sep = $/, chomp: false) -> string
4358 * readline(limit, chomp: false) -> string
4359 * readline(sep, limit, chomp: false) -> string
4360 *
4361 * Reads a line as with IO#gets, but raises EOFError if already at end-of-stream.
4362 *
4363 * Optional keyword argument +chomp+ specifies whether line separators
4364 * are to be omitted.
4365 */
4366
4367static VALUE
4368rb_io_readline(int argc, VALUE *argv, VALUE io)
4369{
4370 VALUE line = rb_io_gets_m(argc, argv, io);
4371
4372 if (NIL_P(line)) {
4373 rb_eof_error();
4374 }
4375 return line;
4376}
4377
4378static VALUE io_readlines(const struct getline_arg *arg, VALUE io);
4379
4380/*
4381 * call-seq:
4382 * readlines(sep = $/, chomp: false) -> array
4383 * readlines(limit, chomp: false) -> array
4384 * readlines(sep, limit, chomp: false) -> array
4385 *
4386 * Reads and returns all remaining line from the stream;
4387 * does not modify <tt>$_</tt>.
4388 * See {Line IO}[rdoc-ref:IO@Line+IO].
4389 *
4390 * With no arguments given, returns lines
4391 * as determined by line separator <tt>$/</tt>, or +nil+ if none:
4392 *
4393 * f = File.new('t.txt')
4394 * f.readlines
4395 * # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
4396 * f.readlines # => []
4397 * f.close
4398 *
4399 * With only string argument +sep+ given,
4400 * returns lines as determined by line separator +sep+,
4401 * or +nil+ if none;
4402 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4403 *
4404 * f = File.new('t.txt')
4405 * f.readlines('li')
4406 * # => ["First li", "ne\nSecond li", "ne\n\nFourth li", "ne\nFifth li", "ne\n"]
4407 * f.close
4408 *
4409 * The two special values for +sep+ are honored:
4410 *
4411 * f = File.new('t.txt')
4412 * # Get all into one string.
4413 * f.readlines(nil)
4414 * # => ["First line\nSecond line\n\nFourth line\nFifth line\n"]
4415 * # Get paragraphs (up to two line separators).
4416 * f.rewind
4417 * f.readlines('')
4418 * # => ["First line\nSecond line\n\n", "Fourth line\nFifth line\n"]
4419 * f.close
4420 *
4421 * With only integer argument +limit+ given,
4422 * limits the number of bytes in each line;
4423 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4424 *
4425 * f = File.new('t.txt')
4426 * f.readlines(8)
4427 * # => ["First li", "ne\n", "Second l", "ine\n", "\n", "Fourth l", "ine\n", "Fifth li", "ne\n"]
4428 * f.close
4429 *
4430 * With arguments +sep+ and +limit+ given,
4431 * combines the two behaviors:
4432 *
4433 * - Returns lines as determined by line separator +sep+.
4434 * - But returns no more bytes in a line than are allowed by the limit.
4435 *
4436 * Optional keyword argument +chomp+ specifies whether line separators
4437 * are to be omitted:
4438 *
4439 * f = File.new('t.txt')
4440 * f.readlines(chomp: true)
4441 * # => ["First line", "Second line", "", "Fourth line", "Fifth line"]
4442 * f.close
4443 *
4444 */
4445
4446static VALUE
4447rb_io_readlines(int argc, VALUE *argv, VALUE io)
4448{
4449 struct getline_arg args;
4450
4451 prepare_getline_args(argc, argv, &args, io);
4452 return io_readlines(&args, io);
4453}
4454
4455static VALUE
4456io_readlines(const struct getline_arg *arg, VALUE io)
4457{
4458 VALUE line, ary;
4459
4460 if (arg->limit == 0)
4461 rb_raise(rb_eArgError, "invalid limit: 0 for readlines");
4462 ary = rb_ary_new();
4463 while (!NIL_P(line = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, io))) {
4464 rb_ary_push(ary, line);
4465 }
4466 return ary;
4467}
4468
4469/*
4470 * call-seq:
4471 * each_line(sep = $/, chomp: false) {|line| ... } -> self
4472 * each_line(limit, chomp: false) {|line| ... } -> self
4473 * each_line(sep, limit, chomp: false) {|line| ... } -> self
4474 * each_line -> enumerator
4475 *
4476 * Calls the block with each remaining line read from the stream;
4477 * returns +self+.
4478 * Does nothing if already at end-of-stream;
4479 * See {Line IO}[rdoc-ref:IO@Line+IO].
4480 *
4481 * With no arguments given, reads lines
4482 * as determined by line separator <tt>$/</tt>:
4483 *
4484 * f = File.new('t.txt')
4485 * f.each_line {|line| p line }
4486 * f.each_line {|line| fail 'Cannot happen' }
4487 * f.close
4488 *
4489 * Output:
4490 *
4491 * "First line\n"
4492 * "Second line\n"
4493 * "\n"
4494 * "Fourth line\n"
4495 * "Fifth line\n"
4496 *
4497 * With only string argument +sep+ given,
4498 * reads lines as determined by line separator +sep+;
4499 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4500 *
4501 * f = File.new('t.txt')
4502 * f.each_line('li') {|line| p line }
4503 * f.close
4504 *
4505 * Output:
4506 *
4507 * "First li"
4508 * "ne\nSecond li"
4509 * "ne\n\nFourth li"
4510 * "ne\nFifth li"
4511 * "ne\n"
4512 *
4513 * The two special values for +sep+ are honored:
4514 *
4515 * f = File.new('t.txt')
4516 * # Get all into one string.
4517 * f.each_line(nil) {|line| p line }
4518 * f.close
4519 *
4520 * Output:
4521 *
4522 * "First line\nSecond line\n\nFourth line\nFifth line\n"
4523 *
4524 * f.rewind
4525 * # Get paragraphs (up to two line separators).
4526 * f.each_line('') {|line| p line }
4527 *
4528 * Output:
4529 *
4530 * "First line\nSecond line\n\n"
4531 * "Fourth line\nFifth line\n"
4532 *
4533 * With only integer argument +limit+ given,
4534 * limits the number of bytes in each line;
4535 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4536 *
4537 * f = File.new('t.txt')
4538 * f.each_line(8) {|line| p line }
4539 * f.close
4540 *
4541 * Output:
4542 *
4543 * "First li"
4544 * "ne\n"
4545 * "Second l"
4546 * "ine\n"
4547 * "\n"
4548 * "Fourth l"
4549 * "ine\n"
4550 * "Fifth li"
4551 * "ne\n"
4552 *
4553 * With arguments +sep+ and +limit+ given,
4554 * combines the two behaviors:
4555 *
4556 * - Calls with the next line as determined by line separator +sep+.
4557 * - But returns no more bytes than are allowed by the limit.
4558 *
4559 * Optional keyword argument +chomp+ specifies whether line separators
4560 * are to be omitted:
4561 *
4562 * f = File.new('t.txt')
4563 * f.each_line(chomp: true) {|line| p line }
4564 * f.close
4565 *
4566 * Output:
4567 *
4568 * "First line"
4569 * "Second line"
4570 * ""
4571 * "Fourth line"
4572 * "Fifth line"
4573 *
4574 * Returns an Enumerator if no block is given.
4575 *
4576 * IO#each is an alias for IO#each_line.
4577 *
4578 */
4579
4580static VALUE
4581rb_io_each_line(int argc, VALUE *argv, VALUE io)
4582{
4583 VALUE str;
4584 struct getline_arg args;
4585
4586 RETURN_ENUMERATOR(io, argc, argv);
4587 prepare_getline_args(argc, argv, &args, io);
4588 if (args.limit == 0)
4589 rb_raise(rb_eArgError, "invalid limit: 0 for each_line");
4590 while (!NIL_P(str = rb_io_getline_1(args.rs, args.limit, args.chomp, io))) {
4591 rb_yield(str);
4592 }
4593 return io;
4594}
4595
4596/*
4597 * call-seq:
4598 * each_byte {|byte| ... } -> self
4599 * each_byte -> enumerator
4600 *
4601 * Calls the given block with each byte (0..255) in the stream; returns +self+.
4602 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
4603 *
4604 * f = File.new('t.rus')
4605 * a = []
4606 * f.each_byte {|b| a << b }
4607 * a # => [209, 130, 208, 181, 209, 129, 209, 130]
4608 * f.close
4609 *
4610 * Returns an Enumerator if no block is given.
4611 *
4612 * Related: IO#each_char, IO#each_codepoint.
4613 *
4614 */
4615
4616static VALUE
4617rb_io_each_byte(VALUE io)
4618{
4619 rb_io_t *fptr;
4620
4621 RETURN_ENUMERATOR(io, 0, 0);
4622 GetOpenFile(io, fptr);
4623
4624 do {
4625 while (fptr->rbuf.len > 0) {
4626 char *p = fptr->rbuf.ptr + fptr->rbuf.off++;
4627 fptr->rbuf.len--;
4628 rb_yield(INT2FIX(*p & 0xff));
4630 errno = 0;
4631 }
4632 READ_CHECK(fptr);
4633 } while (io_fillbuf(fptr) >= 0);
4634 return io;
4635}
4636
4637static VALUE
4638io_getc(rb_io_t *fptr, rb_encoding *enc)
4639{
4640 int r, n, cr = 0;
4641 VALUE str;
4642
4643 if (NEED_READCONV(fptr)) {
4644 rb_encoding *read_enc = io_read_encoding(fptr);
4645
4646 str = Qnil;
4647 SET_BINARY_MODE(fptr);
4648 make_readconv(fptr, 0);
4649
4650 while (1) {
4651 if (fptr->cbuf.len) {
4652 r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4653 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4654 read_enc);
4655 if (!MBCLEN_NEEDMORE_P(r))
4656 break;
4657 if (fptr->cbuf.len == fptr->cbuf.capa) {
4658 rb_raise(rb_eIOError, "too long character");
4659 }
4660 }
4661
4662 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4663 if (fptr->cbuf.len == 0) {
4664 clear_readconv(fptr);
4665 return Qnil;
4666 }
4667 /* return an unit of an incomplete character just before EOF */
4668 str = rb_enc_str_new(fptr->cbuf.ptr+fptr->cbuf.off, 1, read_enc);
4669 fptr->cbuf.off += 1;
4670 fptr->cbuf.len -= 1;
4671 if (fptr->cbuf.len == 0) clear_readconv(fptr);
4673 return str;
4674 }
4675 }
4676 if (MBCLEN_INVALID_P(r)) {
4677 r = rb_enc_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4678 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4679 read_enc);
4680 io_shift_cbuf(fptr, r, &str);
4682 }
4683 else {
4684 io_shift_cbuf(fptr, MBCLEN_CHARFOUND_LEN(r), &str);
4686 if (MBCLEN_CHARFOUND_LEN(r) == 1 && rb_enc_asciicompat(read_enc) &&
4687 ISASCII(RSTRING_PTR(str)[0])) {
4688 cr = ENC_CODERANGE_7BIT;
4689 }
4690 }
4691 str = io_enc_str(str, fptr);
4692 ENC_CODERANGE_SET(str, cr);
4693 return str;
4694 }
4695
4696 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4697 if (io_fillbuf(fptr) < 0) {
4698 return Qnil;
4699 }
4700 if (rb_enc_asciicompat(enc) && ISASCII(fptr->rbuf.ptr[fptr->rbuf.off])) {
4701 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, 1);
4702 fptr->rbuf.off += 1;
4703 fptr->rbuf.len -= 1;
4704 cr = ENC_CODERANGE_7BIT;
4705 }
4706 else {
4707 r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off, fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4708 if (MBCLEN_CHARFOUND_P(r) &&
4709 (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
4710 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, n);
4711 fptr->rbuf.off += n;
4712 fptr->rbuf.len -= n;
4714 }
4715 else if (MBCLEN_NEEDMORE_P(r)) {
4716 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, fptr->rbuf.len);
4717 fptr->rbuf.len = 0;
4718 getc_needmore:
4719 if (io_fillbuf(fptr) != -1) {
4720 rb_str_cat(str, fptr->rbuf.ptr+fptr->rbuf.off, 1);
4721 fptr->rbuf.off++;
4722 fptr->rbuf.len--;
4723 r = rb_enc_precise_mbclen(RSTRING_PTR(str), RSTRING_PTR(str)+RSTRING_LEN(str), enc);
4724 if (MBCLEN_NEEDMORE_P(r)) {
4725 goto getc_needmore;
4726 }
4727 else if (MBCLEN_CHARFOUND_P(r)) {
4729 }
4730 }
4731 }
4732 else {
4733 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, 1);
4734 fptr->rbuf.off++;
4735 fptr->rbuf.len--;
4736 }
4737 }
4738 if (!cr) cr = ENC_CODERANGE_BROKEN;
4739 str = io_enc_str(str, fptr);
4740 ENC_CODERANGE_SET(str, cr);
4741 return str;
4742}
4743
4744/*
4745 * call-seq:
4746 * each_char {|c| ... } -> self
4747 * each_char -> enumerator
4748 *
4749 * Calls the given block with each character in the stream; returns +self+.
4750 * See {Character IO}[rdoc-ref:IO@Character+IO].
4751 *
4752 * f = File.new('t.rus')
4753 * a = []
4754 * f.each_char {|c| a << c.ord }
4755 * a # => [1090, 1077, 1089, 1090]
4756 * f.close
4757 *
4758 * Returns an Enumerator if no block is given.
4759 *
4760 * Related: IO#each_byte, IO#each_codepoint.
4761 *
4762 */
4763
4764static VALUE
4765rb_io_each_char(VALUE io)
4766{
4767 rb_io_t *fptr;
4768 rb_encoding *enc;
4769 VALUE c;
4770
4771 RETURN_ENUMERATOR(io, 0, 0);
4772 GetOpenFile(io, fptr);
4774
4775 enc = io_input_encoding(fptr);
4776 READ_CHECK(fptr);
4777 while (!NIL_P(c = io_getc(fptr, enc))) {
4778 rb_yield(c);
4779 }
4780 return io;
4781}
4782
4783/*
4784 * call-seq:
4785 * each_codepoint {|c| ... } -> self
4786 * each_codepoint -> enumerator
4787 *
4788 * Calls the given block with each codepoint in the stream; returns +self+:
4789 *
4790 * f = File.new('t.rus')
4791 * a = []
4792 * f.each_codepoint {|c| a << c }
4793 * a # => [1090, 1077, 1089, 1090]
4794 * f.close
4795 *
4796 * Returns an Enumerator if no block is given.
4797 *
4798 * Related: IO#each_byte, IO#each_char.
4799 *
4800 */
4801
4802static VALUE
4803rb_io_each_codepoint(VALUE io)
4804{
4805 rb_io_t *fptr;
4806 rb_encoding *enc;
4807 unsigned int c;
4808 int r, n;
4809
4810 RETURN_ENUMERATOR(io, 0, 0);
4811 GetOpenFile(io, fptr);
4813
4814 READ_CHECK(fptr);
4815 if (NEED_READCONV(fptr)) {
4816 SET_BINARY_MODE(fptr);
4817 r = 1; /* no invalid char yet */
4818 for (;;) {
4819 make_readconv(fptr, 0);
4820 for (;;) {
4821 if (fptr->cbuf.len) {
4822 if (fptr->encs.enc)
4823 r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4824 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4825 fptr->encs.enc);
4826 else
4827 r = ONIGENC_CONSTRUCT_MBCLEN_CHARFOUND(1);
4828 if (!MBCLEN_NEEDMORE_P(r))
4829 break;
4830 if (fptr->cbuf.len == fptr->cbuf.capa) {
4831 rb_raise(rb_eIOError, "too long character");
4832 }
4833 }
4834 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4835 clear_readconv(fptr);
4836 if (!MBCLEN_CHARFOUND_P(r)) {
4837 enc = fptr->encs.enc;
4838 goto invalid;
4839 }
4840 return io;
4841 }
4842 }
4843 if (MBCLEN_INVALID_P(r)) {
4844 enc = fptr->encs.enc;
4845 goto invalid;
4846 }
4847 n = MBCLEN_CHARFOUND_LEN(r);
4848 if (fptr->encs.enc) {
4849 c = rb_enc_codepoint(fptr->cbuf.ptr+fptr->cbuf.off,
4850 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4851 fptr->encs.enc);
4852 }
4853 else {
4854 c = (unsigned char)fptr->cbuf.ptr[fptr->cbuf.off];
4855 }
4856 fptr->cbuf.off += n;
4857 fptr->cbuf.len -= n;
4858 rb_yield(UINT2NUM(c));
4860 }
4861 }
4862 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4863 enc = io_input_encoding(fptr);
4864 while (io_fillbuf(fptr) >= 0) {
4865 r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off,
4866 fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4867 if (MBCLEN_CHARFOUND_P(r) &&
4868 (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
4869 c = rb_enc_codepoint(fptr->rbuf.ptr+fptr->rbuf.off,
4870 fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4871 fptr->rbuf.off += n;
4872 fptr->rbuf.len -= n;
4873 rb_yield(UINT2NUM(c));
4874 }
4875 else if (MBCLEN_INVALID_P(r)) {
4876 goto invalid;
4877 }
4878 else if (MBCLEN_NEEDMORE_P(r)) {
4879 char cbuf[8], *p = cbuf;
4880 int more = MBCLEN_NEEDMORE_LEN(r);
4881 if (more > numberof(cbuf)) goto invalid;
4882 more += n = fptr->rbuf.len;
4883 if (more > numberof(cbuf)) goto invalid;
4884 while ((n = (int)read_buffered_data(p, more, fptr)) > 0 &&
4885 (p += n, (more -= n) > 0)) {
4886 if (io_fillbuf(fptr) < 0) goto invalid;
4887 if ((n = fptr->rbuf.len) > more) n = more;
4888 }
4889 r = rb_enc_precise_mbclen(cbuf, p, enc);
4890 if (!MBCLEN_CHARFOUND_P(r)) goto invalid;
4891 c = rb_enc_codepoint(cbuf, p, enc);
4892 rb_yield(UINT2NUM(c));
4893 }
4894 else {
4895 continue;
4896 }
4898 }
4899 return io;
4900
4901 invalid:
4902 rb_raise(rb_eArgError, "invalid byte sequence in %s", rb_enc_name(enc));
4904}
4905
4906/*
4907 * call-seq:
4908 * getc -> character or nil
4909 *
4910 * Reads and returns the next 1-character string from the stream;
4911 * returns +nil+ if already at end-of-stream.
4912 * See {Character IO}[rdoc-ref:IO@Character+IO].
4913 *
4914 * f = File.open('t.txt')
4915 * f.getc # => "F"
4916 * f.close
4917 * f = File.open('t.rus')
4918 * f.getc.ord # => 1090
4919 * f.close
4920 *
4921 * Related: IO#readchar (may raise EOFError).
4922 *
4923 */
4924
4925static VALUE
4926rb_io_getc(VALUE io)
4927{
4928 rb_io_t *fptr;
4929 rb_encoding *enc;
4930
4931 GetOpenFile(io, fptr);
4933
4934 enc = io_input_encoding(fptr);
4935 READ_CHECK(fptr);
4936 return io_getc(fptr, enc);
4937}
4938
4939/*
4940 * call-seq:
4941 * readchar -> string
4942 *
4943 * Reads and returns the next 1-character string from the stream;
4944 * raises EOFError if already at end-of-stream.
4945 * See {Character IO}[rdoc-ref:IO@Character+IO].
4946 *
4947 * f = File.open('t.txt')
4948 * f.readchar # => "F"
4949 * f.close
4950 * f = File.open('t.rus')
4951 * f.readchar.ord # => 1090
4952 * f.close
4953 *
4954 * Related: IO#getc (will not raise EOFError).
4955 *
4956 */
4957
4958static VALUE
4959rb_io_readchar(VALUE io)
4960{
4961 VALUE c = rb_io_getc(io);
4962
4963 if (NIL_P(c)) {
4964 rb_eof_error();
4965 }
4966 return c;
4967}
4968
4969/*
4970 * call-seq:
4971 * getbyte -> integer or nil
4972 *
4973 * Reads and returns the next byte (in range 0..255) from the stream;
4974 * returns +nil+ if already at end-of-stream.
4975 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
4976 *
4977 * f = File.open('t.txt')
4978 * f.getbyte # => 70
4979 * f.close
4980 * f = File.open('t.rus')
4981 * f.getbyte # => 209
4982 * f.close
4983 *
4984 * Related: IO#readbyte (may raise EOFError).
4985 */
4986
4987VALUE
4989{
4990 rb_io_t *fptr;
4991 int c;
4992
4993 GetOpenFile(io, fptr);
4995 READ_CHECK(fptr);
4996 VALUE r_stdout = rb_ractor_stdout();
4997 if (fptr->fd == 0 && (fptr->mode & FMODE_TTY) && RB_TYPE_P(r_stdout, T_FILE)) {
4998 rb_io_t *ofp;
4999 GetOpenFile(r_stdout, ofp);
5000 if (ofp->mode & FMODE_TTY) {
5001 rb_io_flush(r_stdout);
5002 }
5003 }
5004 if (io_fillbuf(fptr) < 0) {
5005 return Qnil;
5006 }
5007 fptr->rbuf.off++;
5008 fptr->rbuf.len--;
5009 c = (unsigned char)fptr->rbuf.ptr[fptr->rbuf.off-1];
5010 return INT2FIX(c & 0xff);
5011}
5012
5013/*
5014 * call-seq:
5015 * readbyte -> integer
5016 *
5017 * Reads and returns the next byte (in range 0..255) from the stream;
5018 * raises EOFError if already at end-of-stream.
5019 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5020 *
5021 * f = File.open('t.txt')
5022 * f.readbyte # => 70
5023 * f.close
5024 * f = File.open('t.rus')
5025 * f.readbyte # => 209
5026 * f.close
5027 *
5028 * Related: IO#getbyte (will not raise EOFError).
5029 *
5030 */
5031
5032static VALUE
5033rb_io_readbyte(VALUE io)
5034{
5035 VALUE c = rb_io_getbyte(io);
5036
5037 if (NIL_P(c)) {
5038 rb_eof_error();
5039 }
5040 return c;
5041}
5042
5043/*
5044 * call-seq:
5045 * ungetbyte(integer) -> nil
5046 * ungetbyte(string) -> nil
5047 *
5048 * Pushes back ("unshifts") the given data onto the stream's buffer,
5049 * placing the data so that it is next to be read; returns +nil+.
5050 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5051 *
5052 * Note that:
5053 *
5054 * - Calling the method has no effect with unbuffered reads (such as IO#sysread).
5055 * - Calling #rewind on the stream discards the pushed-back data.
5056 *
5057 * When argument +integer+ is given, uses only its low-order byte:
5058 *
5059 * File.write('t.tmp', '012')
5060 * f = File.open('t.tmp')
5061 * f.ungetbyte(0x41) # => nil
5062 * f.read # => "A012"
5063 * f.rewind
5064 * f.ungetbyte(0x4243) # => nil
5065 * f.read # => "C012"
5066 * f.close
5067 *
5068 * When argument +string+ is given, uses all bytes:
5069 *
5070 * File.write('t.tmp', '012')
5071 * f = File.open('t.tmp')
5072 * f.ungetbyte('A') # => nil
5073 * f.read # => "A012"
5074 * f.rewind
5075 * f.ungetbyte('BCDE') # => nil
5076 * f.read # => "BCDE012"
5077 * f.close
5078 *
5079 */
5080
5081VALUE
5083{
5084 rb_io_t *fptr;
5085
5086 GetOpenFile(io, fptr);
5088 switch (TYPE(b)) {
5089 case T_NIL:
5090 return Qnil;
5091 case T_FIXNUM:
5092 case T_BIGNUM: ;
5093 VALUE v = rb_int_modulo(b, INT2FIX(256));
5094 unsigned char c = NUM2INT(v) & 0xFF;
5095 b = rb_str_new((const char *)&c, 1);
5096 break;
5097 default:
5098 SafeStringValue(b);
5099 }
5100 io_ungetbyte(b, fptr);
5101 return Qnil;
5102}
5103
5104/*
5105 * call-seq:
5106 * ungetc(integer) -> nil
5107 * ungetc(string) -> nil
5108 *
5109 * Pushes back ("unshifts") the given data onto the stream's buffer,
5110 * placing the data so that it is next to be read; returns +nil+.
5111 * See {Character IO}[rdoc-ref:IO@Character+IO].
5112 *
5113 * Note that:
5114 *
5115 * - Calling the method has no effect with unbuffered reads (such as IO#sysread).
5116 * - Calling #rewind on the stream discards the pushed-back data.
5117 *
5118 * When argument +integer+ is given, interprets the integer as a character:
5119 *
5120 * File.write('t.tmp', '012')
5121 * f = File.open('t.tmp')
5122 * f.ungetc(0x41) # => nil
5123 * f.read # => "A012"
5124 * f.rewind
5125 * f.ungetc(0x0442) # => nil
5126 * f.getc.ord # => 1090
5127 * f.close
5128 *
5129 * When argument +string+ is given, uses all characters:
5130 *
5131 * File.write('t.tmp', '012')
5132 * f = File.open('t.tmp')
5133 * f.ungetc('A') # => nil
5134 * f.read # => "A012"
5135 * f.rewind
5136 * f.ungetc("\u0442\u0435\u0441\u0442") # => nil
5137 * f.getc.ord # => 1090
5138 * f.getc.ord # => 1077
5139 * f.getc.ord # => 1089
5140 * f.getc.ord # => 1090
5141 * f.close
5142 *
5143 */
5144
5145VALUE
5147{
5148 rb_io_t *fptr;
5149 long len;
5150
5151 GetOpenFile(io, fptr);
5153 if (FIXNUM_P(c)) {
5154 c = rb_enc_uint_chr(FIX2UINT(c), io_read_encoding(fptr));
5155 }
5156 else if (RB_BIGNUM_TYPE_P(c)) {
5157 c = rb_enc_uint_chr(NUM2UINT(c), io_read_encoding(fptr));
5158 }
5159 else {
5160 SafeStringValue(c);
5161 }
5162 if (NEED_READCONV(fptr)) {
5163 SET_BINARY_MODE(fptr);
5164 len = RSTRING_LEN(c);
5165#if SIZEOF_LONG > SIZEOF_INT
5166 if (len > INT_MAX)
5167 rb_raise(rb_eIOError, "ungetc failed");
5168#endif
5169 make_readconv(fptr, (int)len);
5170 if (fptr->cbuf.capa - fptr->cbuf.len < len)
5171 rb_raise(rb_eIOError, "ungetc failed");
5172 if (fptr->cbuf.off < len) {
5173 MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.capa-fptr->cbuf.len,
5174 fptr->cbuf.ptr+fptr->cbuf.off,
5175 char, fptr->cbuf.len);
5176 fptr->cbuf.off = fptr->cbuf.capa-fptr->cbuf.len;
5177 }
5178 fptr->cbuf.off -= (int)len;
5179 fptr->cbuf.len += (int)len;
5180 MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.off, RSTRING_PTR(c), char, len);
5181 }
5182 else {
5183 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
5184 io_ungetbyte(c, fptr);
5185 }
5186 return Qnil;
5187}
5188
5189/*
5190 * call-seq:
5191 * isatty -> true or false
5192 *
5193 * Returns +true+ if the stream is associated with a terminal device (tty),
5194 * +false+ otherwise:
5195 *
5196 * f = File.new('t.txt').isatty #=> false
5197 * f.close
5198 * f = File.new('/dev/tty').isatty #=> true
5199 * f.close
5200 *
5201 * IO#tty? is an alias for IO#isatty.
5202 *
5203 */
5204
5205static VALUE
5206rb_io_isatty(VALUE io)
5207{
5208 rb_io_t *fptr;
5209
5210 GetOpenFile(io, fptr);
5211 return RBOOL(isatty(fptr->fd) != 0);
5212}
5213
5214#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5215/*
5216 * call-seq:
5217 * close_on_exec? -> true or false
5218 *
5219 * Returns +true+ if the stream will be closed on exec, +false+ otherwise:
5220 *
5221 * f = File.open('t.txt')
5222 * f.close_on_exec? # => true
5223 * f.close_on_exec = false
5224 * f.close_on_exec? # => false
5225 * f.close
5226 *
5227 */
5228
5229static VALUE
5230rb_io_close_on_exec_p(VALUE io)
5231{
5232 rb_io_t *fptr;
5233 VALUE write_io;
5234 int fd, ret;
5235
5236 write_io = GetWriteIO(io);
5237 if (io != write_io) {
5238 GetOpenFile(write_io, fptr);
5239 if (fptr && 0 <= (fd = fptr->fd)) {
5240 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5241 if (!(ret & FD_CLOEXEC)) return Qfalse;
5242 }
5243 }
5244
5245 GetOpenFile(io, fptr);
5246 if (fptr && 0 <= (fd = fptr->fd)) {
5247 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5248 if (!(ret & FD_CLOEXEC)) return Qfalse;
5249 }
5250 return Qtrue;
5251}
5252#else
5253#define rb_io_close_on_exec_p rb_f_notimplement
5254#endif
5255
5256#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5257/*
5258 * call-seq:
5259 * self.close_on_exec = bool -> true or false
5260 *
5261 * Sets a close-on-exec flag.
5262 *
5263 * f = open("/dev/null")
5264 * f.close_on_exec = true
5265 * system("cat", "/proc/self/fd/#{f.fileno}") # cat: /proc/self/fd/3: No such file or directory
5266 * f.closed? #=> false
5267 *
5268 * Ruby sets close-on-exec flags of all file descriptors by default
5269 * since Ruby 2.0.0.
5270 * So you don't need to set by yourself.
5271 * Also, unsetting a close-on-exec flag can cause file descriptor leak
5272 * if another thread use fork() and exec() (via system() method for example).
5273 * If you really needs file descriptor inheritance to child process,
5274 * use spawn()'s argument such as fd=>fd.
5275 */
5276
5277static VALUE
5278rb_io_set_close_on_exec(VALUE io, VALUE arg)
5279{
5280 int flag = RTEST(arg) ? FD_CLOEXEC : 0;
5281 rb_io_t *fptr;
5282 VALUE write_io;
5283 int fd, ret;
5284
5285 write_io = GetWriteIO(io);
5286 if (io != write_io) {
5287 GetOpenFile(write_io, fptr);
5288 if (fptr && 0 <= (fd = fptr->fd)) {
5289 if ((ret = fcntl(fptr->fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5290 if ((ret & FD_CLOEXEC) != flag) {
5291 ret = (ret & ~FD_CLOEXEC) | flag;
5292 ret = fcntl(fd, F_SETFD, ret);
5293 if (ret != 0) rb_sys_fail_path(fptr->pathv);
5294 }
5295 }
5296
5297 }
5298
5299 GetOpenFile(io, fptr);
5300 if (fptr && 0 <= (fd = fptr->fd)) {
5301 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5302 if ((ret & FD_CLOEXEC) != flag) {
5303 ret = (ret & ~FD_CLOEXEC) | flag;
5304 ret = fcntl(fd, F_SETFD, ret);
5305 if (ret != 0) rb_sys_fail_path(fptr->pathv);
5306 }
5307 }
5308 return Qnil;
5309}
5310#else
5311#define rb_io_set_close_on_exec rb_f_notimplement
5312#endif
5313
5314#define IS_PREP_STDIO(f) ((f)->mode & FMODE_PREP)
5315#define PREP_STDIO_NAME(f) (RSTRING_PTR((f)->pathv))
5316
5317static VALUE
5318finish_writeconv(rb_io_t *fptr, int noalloc)
5319{
5320 unsigned char *ds, *dp, *de;
5322
5323 if (!fptr->wbuf.ptr) {
5324 unsigned char buf[1024];
5325
5327 while (res == econv_destination_buffer_full) {
5328 ds = dp = buf;
5329 de = buf + sizeof(buf);
5330 res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
5331 while (dp-ds) {
5332 size_t remaining = dp-ds;
5333 long result = rb_io_write_memory(fptr, ds, remaining);
5334
5335 if (result > 0) {
5336 ds += result;
5337 if ((size_t)result == remaining) break;
5338 }
5339 else if (rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
5340 if (fptr->fd < 0)
5341 return noalloc ? Qtrue : rb_exc_new3(rb_eIOError, rb_str_new_cstr(closed_stream));
5342 }
5343 else {
5344 return noalloc ? Qtrue : INT2NUM(errno);
5345 }
5346 }
5347 if (res == econv_invalid_byte_sequence ||
5348 res == econv_incomplete_input ||
5350 return noalloc ? Qtrue : rb_econv_make_exception(fptr->writeconv);
5351 }
5352 }
5353
5354 return Qnil;
5355 }
5356
5358 while (res == econv_destination_buffer_full) {
5359 if (fptr->wbuf.len == fptr->wbuf.capa) {
5360 if (io_fflush(fptr) < 0) {
5361 return noalloc ? Qtrue : INT2NUM(errno);
5362 }
5363 }
5364
5365 ds = dp = (unsigned char *)fptr->wbuf.ptr + fptr->wbuf.off + fptr->wbuf.len;
5366 de = (unsigned char *)fptr->wbuf.ptr + fptr->wbuf.capa;
5367 res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
5368 fptr->wbuf.len += (int)(dp - ds);
5369 if (res == econv_invalid_byte_sequence ||
5370 res == econv_incomplete_input ||
5372 return noalloc ? Qtrue : rb_econv_make_exception(fptr->writeconv);
5373 }
5374 }
5375 return Qnil;
5376}
5377
5379 rb_io_t *fptr;
5380 int noalloc;
5381};
5382
5383static VALUE
5384finish_writeconv_sync(VALUE arg)
5385{
5386 struct finish_writeconv_arg *p = (struct finish_writeconv_arg *)arg;
5387 return finish_writeconv(p->fptr, p->noalloc);
5388}
5389
5390static void*
5391nogvl_close(void *ptr)
5392{
5393 int *fd = ptr;
5394
5395 return (void*)(intptr_t)close(*fd);
5396}
5397
5398static int
5399maygvl_close(int fd, int keepgvl)
5400{
5401 if (keepgvl)
5402 return close(fd);
5403
5404 /*
5405 * close() may block for certain file types (NFS, SO_LINGER sockets,
5406 * inotify), so let other threads run.
5407 */
5408 return (int)(intptr_t)rb_thread_call_without_gvl(nogvl_close, &fd, RUBY_UBF_IO, 0);
5409}
5410
5411static void*
5412nogvl_fclose(void *ptr)
5413{
5414 FILE *file = ptr;
5415
5416 return (void*)(intptr_t)fclose(file);
5417}
5418
5419static int
5420maygvl_fclose(FILE *file, int keepgvl)
5421{
5422 if (keepgvl)
5423 return fclose(file);
5424
5425 return (int)(intptr_t)rb_thread_call_without_gvl(nogvl_fclose, file, RUBY_UBF_IO, 0);
5426}
5427
5428static void free_io_buffer(rb_io_buffer_t *buf);
5429static void clear_codeconv(rb_io_t *fptr);
5430
5431static void
5432fptr_finalize_flush(rb_io_t *fptr, int noraise, int keepgvl,
5433 struct ccan_list_head *busy)
5434{
5435 VALUE error = Qnil;
5436 int fd = fptr->fd;
5437 FILE *stdio_file = fptr->stdio_file;
5438 int mode = fptr->mode;
5439
5440 if (fptr->writeconv) {
5441 if (!NIL_P(fptr->write_lock) && !noraise) {
5442 struct finish_writeconv_arg arg;
5443 arg.fptr = fptr;
5444 arg.noalloc = noraise;
5445 error = rb_mutex_synchronize(fptr->write_lock, finish_writeconv_sync, (VALUE)&arg);
5446 }
5447 else {
5448 error = finish_writeconv(fptr, noraise);
5449 }
5450 }
5451 if (fptr->wbuf.len) {
5452 if (noraise) {
5453 io_flush_buffer_sync(fptr);
5454 }
5455 else {
5456 if (io_fflush(fptr) < 0 && NIL_P(error)) {
5457 error = INT2NUM(errno);
5458 }
5459 }
5460 }
5461
5462 int done = 0;
5463
5464 if (IS_PREP_STDIO(fptr) || fd <= 2) {
5465 // Need to keep FILE objects of stdin, stdout and stderr, so we are done:
5466 done = 1;
5467 }
5468
5469 fptr->fd = -1;
5470 fptr->stdio_file = 0;
5472
5473 // Ensure waiting_fd users do not hit EBADF.
5474 if (busy) {
5475 // Wait for them to exit before we call close().
5476 do rb_thread_schedule(); while (!ccan_list_empty(busy));
5477 }
5478
5479 // Disable for now.
5480 // if (!done && fd >= 0) {
5481 // VALUE scheduler = rb_fiber_scheduler_current();
5482 // if (scheduler != Qnil) {
5483 // VALUE result = rb_fiber_scheduler_io_close(scheduler, fptr->self);
5484 // if (!UNDEF_P(result)) done = 1;
5485 // }
5486 // }
5487
5488 if (!done && stdio_file) {
5489 // stdio_file is deallocated anyway even if fclose failed.
5490 if ((maygvl_fclose(stdio_file, noraise) < 0) && NIL_P(error)) {
5491 if (!noraise) {
5492 error = INT2NUM(errno);
5493 }
5494 }
5495
5496 done = 1;
5497 }
5498
5499 if (!done && fd >= 0) {
5500 // fptr->fd may be closed even if close fails. POSIX doesn't specify it.
5501 // We assumes it is closed.
5502
5503 keepgvl |= !(mode & FMODE_WRITABLE);
5504 keepgvl |= noraise;
5505 if ((maygvl_close(fd, keepgvl) < 0) && NIL_P(error)) {
5506 if (!noraise) {
5507 error = INT2NUM(errno);
5508 }
5509 }
5510
5511 done = 1;
5512 }
5513
5514 if (!NIL_P(error) && !noraise) {
5515 if (RB_INTEGER_TYPE_P(error))
5516 rb_syserr_fail_path(NUM2INT(error), fptr->pathv);
5517 else
5518 rb_exc_raise(error);
5519 }
5520}
5521
5522static void
5523fptr_finalize(rb_io_t *fptr, int noraise)
5524{
5525 fptr_finalize_flush(fptr, noraise, FALSE, 0);
5526 free_io_buffer(&fptr->rbuf);
5527 free_io_buffer(&fptr->wbuf);
5528 clear_codeconv(fptr);
5529}
5530
5531static void
5532rb_io_fptr_cleanup(rb_io_t *fptr, int noraise)
5533{
5534 if (fptr->finalize) {
5535 (*fptr->finalize)(fptr, noraise);
5536 }
5537 else {
5538 fptr_finalize(fptr, noraise);
5539 }
5540}
5541
5542static void
5543free_io_buffer(rb_io_buffer_t *buf)
5544{
5545 if (buf->ptr) {
5546 ruby_sized_xfree(buf->ptr, (size_t)buf->capa);
5547 buf->ptr = NULL;
5548 }
5549}
5550
5551static void
5552clear_readconv(rb_io_t *fptr)
5553{
5554 if (fptr->readconv) {
5555 rb_econv_close(fptr->readconv);
5556 fptr->readconv = NULL;
5557 }
5558 free_io_buffer(&fptr->cbuf);
5559}
5560
5561static void
5562clear_writeconv(rb_io_t *fptr)
5563{
5564 if (fptr->writeconv) {
5566 fptr->writeconv = NULL;
5567 }
5568 fptr->writeconv_initialized = 0;
5569}
5570
5571static void
5572clear_codeconv(rb_io_t *fptr)
5573{
5574 clear_readconv(fptr);
5575 clear_writeconv(fptr);
5576}
5577
5578void
5579rb_io_fptr_finalize_internal(void *ptr)
5580{
5581 rb_io_t *fptr = ptr;
5582
5583 if (!ptr) return;
5584 fptr->pathv = Qnil;
5585 if (0 <= fptr->fd)
5586 rb_io_fptr_cleanup(fptr, TRUE);
5587 fptr->write_lock = Qnil;
5588 free_io_buffer(&fptr->rbuf);
5589 free_io_buffer(&fptr->wbuf);
5590 clear_codeconv(fptr);
5591 free(fptr);
5592}
5593
5594#undef rb_io_fptr_finalize
5595int
5596rb_io_fptr_finalize(rb_io_t *fptr)
5597{
5598 if (!fptr) {
5599 return 0;
5600 }
5601 else {
5602 rb_io_fptr_finalize_internal(fptr);
5603 return 1;
5604 }
5605}
5606#define rb_io_fptr_finalize(fptr) rb_io_fptr_finalize_internal(fptr)
5607
5608RUBY_FUNC_EXPORTED size_t
5609rb_io_memsize(const rb_io_t *fptr)
5610{
5611 size_t size = sizeof(rb_io_t);
5612 size += fptr->rbuf.capa;
5613 size += fptr->wbuf.capa;
5614 size += fptr->cbuf.capa;
5615 if (fptr->readconv) size += rb_econv_memsize(fptr->readconv);
5616 if (fptr->writeconv) size += rb_econv_memsize(fptr->writeconv);
5617 return size;
5618}
5619
5620#ifdef _WIN32
5621/* keep GVL while closing to prevent crash on Windows */
5622# define KEEPGVL TRUE
5623#else
5624# define KEEPGVL FALSE
5625#endif
5626
5627int rb_notify_fd_close(int fd, struct ccan_list_head *);
5628static rb_io_t *
5629io_close_fptr(VALUE io)
5630{
5631 rb_io_t *fptr;
5632 VALUE write_io;
5633 rb_io_t *write_fptr;
5634 struct ccan_list_head busy;
5635
5636 ccan_list_head_init(&busy);
5637 write_io = GetWriteIO(io);
5638 if (io != write_io) {
5639 write_fptr = RFILE(write_io)->fptr;
5640 if (write_fptr && 0 <= write_fptr->fd) {
5641 rb_io_fptr_cleanup(write_fptr, TRUE);
5642 }
5643 }
5644
5645 fptr = RFILE(io)->fptr;
5646 if (!fptr) return 0;
5647 if (fptr->fd < 0) return 0;
5648
5649 if (rb_notify_fd_close(fptr->fd, &busy)) {
5650 /* calls close(fptr->fd): */
5651 fptr_finalize_flush(fptr, FALSE, KEEPGVL, &busy);
5652 }
5653 rb_io_fptr_cleanup(fptr, FALSE);
5654 return fptr;
5655}
5656
5657static void
5658fptr_waitpid(rb_io_t *fptr, int nohang)
5659{
5660 int status;
5661 if (fptr->pid) {
5662 rb_last_status_clear();
5663 rb_waitpid(fptr->pid, &status, nohang ? WNOHANG : 0);
5664 fptr->pid = 0;
5665 }
5666}
5667
5668VALUE
5670{
5671 rb_io_t *fptr = io_close_fptr(io);
5672 if (fptr) fptr_waitpid(fptr, 0);
5673 return Qnil;
5674}
5675
5676/*
5677 * call-seq:
5678 * close -> nil
5679 *
5680 * Closes the stream for both reading and writing
5681 * if open for either or both; returns +nil+.
5682 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5683 *
5684 * If the stream is open for writing, flushes any buffered writes
5685 * to the operating system before closing.
5686 *
5687 * If the stream was opened by IO.popen, sets global variable <tt>$?</tt>
5688 * (child exit status).
5689 *
5690 * Example:
5691 *
5692 * IO.popen('ruby', 'r+') do |pipe|
5693 * puts pipe.closed?
5694 * pipe.close
5695 * puts $?
5696 * puts pipe.closed?
5697 * end
5698 *
5699 * Output:
5700 *
5701 * false
5702 * pid 13760 exit 0
5703 * true
5704 *
5705 * Related: IO#close_read, IO#close_write, IO#closed?.
5706 */
5707
5708static VALUE
5709rb_io_close_m(VALUE io)
5710{
5711 rb_io_t *fptr = rb_io_get_fptr(io);
5712 if (fptr->fd < 0) {
5713 return Qnil;
5714 }
5715 rb_io_close(io);
5716 return Qnil;
5717}
5718
5719static VALUE
5720io_call_close(VALUE io)
5721{
5722 rb_check_funcall(io, rb_intern("close"), 0, 0);
5723 return io;
5724}
5725
5726static VALUE
5727ignore_closed_stream(VALUE io, VALUE exc)
5728{
5729 enum {mesg_len = sizeof(closed_stream)-1};
5730 VALUE mesg = rb_attr_get(exc, idMesg);
5731 if (!RB_TYPE_P(mesg, T_STRING) ||
5732 RSTRING_LEN(mesg) != mesg_len ||
5733 memcmp(RSTRING_PTR(mesg), closed_stream, mesg_len)) {
5734 rb_exc_raise(exc);
5735 }
5736 return io;
5737}
5738
5739static VALUE
5740io_close(VALUE io)
5741{
5742 VALUE closed = rb_check_funcall(io, rb_intern("closed?"), 0, 0);
5743 if (!UNDEF_P(closed) && RTEST(closed)) return io;
5744 rb_rescue2(io_call_close, io, ignore_closed_stream, io,
5745 rb_eIOError, (VALUE)0);
5746 return io;
5747}
5748
5749/*
5750 * call-seq:
5751 * closed? -> true or false
5752 *
5753 * Returns +true+ if the stream is closed for both reading and writing,
5754 * +false+ otherwise.
5755 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5756 *
5757 * IO.popen('ruby', 'r+') do |pipe|
5758 * puts pipe.closed?
5759 * pipe.close_read
5760 * puts pipe.closed?
5761 * pipe.close_write
5762 * puts pipe.closed?
5763 * end
5764 *
5765 * Output:
5766 *
5767 * false
5768 * false
5769 * true
5770 *
5771 * Related: IO#close_read, IO#close_write, IO#close.
5772 */
5773
5774
5775static VALUE
5776rb_io_closed(VALUE io)
5777{
5778 rb_io_t *fptr;
5779 VALUE write_io;
5780 rb_io_t *write_fptr;
5781
5782 write_io = GetWriteIO(io);
5783 if (io != write_io) {
5784 write_fptr = RFILE(write_io)->fptr;
5785 if (write_fptr && 0 <= write_fptr->fd) {
5786 return Qfalse;
5787 }
5788 }
5789
5790 fptr = rb_io_get_fptr(io);
5791 return RBOOL(0 > fptr->fd);
5792}
5793
5794/*
5795 * call-seq:
5796 * close_read -> nil
5797 *
5798 * Closes the stream for reading if open for reading;
5799 * returns +nil+.
5800 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5801 *
5802 * If the stream was opened by IO.popen and is also closed for writing,
5803 * sets global variable <tt>$?</tt> (child exit status).
5804 *
5805 * Example:
5806 *
5807 * IO.popen('ruby', 'r+') do |pipe|
5808 * puts pipe.closed?
5809 * pipe.close_write
5810 * puts pipe.closed?
5811 * pipe.close_read
5812 * puts $?
5813 * puts pipe.closed?
5814 * end
5815 *
5816 * Output:
5817 *
5818 * false
5819 * false
5820 * pid 14748 exit 0
5821 * true
5822 *
5823 * Related: IO#close, IO#close_write, IO#closed?.
5824 */
5825
5826static VALUE
5827rb_io_close_read(VALUE io)
5828{
5829 rb_io_t *fptr;
5830 VALUE write_io;
5831
5832 fptr = rb_io_get_fptr(rb_io_taint_check(io));
5833 if (fptr->fd < 0) return Qnil;
5834 if (is_socket(fptr->fd, fptr->pathv)) {
5835#ifndef SHUT_RD
5836# define SHUT_RD 0
5837#endif
5838 if (shutdown(fptr->fd, SHUT_RD) < 0)
5839 rb_sys_fail_path(fptr->pathv);
5840 fptr->mode &= ~FMODE_READABLE;
5841 if (!(fptr->mode & FMODE_WRITABLE))
5842 return rb_io_close(io);
5843 return Qnil;
5844 }
5845
5846 write_io = GetWriteIO(io);
5847 if (io != write_io) {
5848 rb_io_t *wfptr;
5849 wfptr = rb_io_get_fptr(rb_io_taint_check(write_io));
5850 wfptr->pid = fptr->pid;
5851 fptr->pid = 0;
5852 RFILE(io)->fptr = wfptr;
5853 /* bind to write_io temporarily to get rid of memory/fd leak */
5854 fptr->tied_io_for_writing = 0;
5855 RFILE(write_io)->fptr = fptr;
5856 rb_io_fptr_cleanup(fptr, FALSE);
5857 /* should not finalize fptr because another thread may be reading it */
5858 return Qnil;
5859 }
5860
5861 if ((fptr->mode & (FMODE_DUPLEX|FMODE_WRITABLE)) == FMODE_WRITABLE) {
5862 rb_raise(rb_eIOError, "closing non-duplex IO for reading");
5863 }
5864 return rb_io_close(io);
5865}
5866
5867/*
5868 * call-seq:
5869 * close_write -> nil
5870 *
5871 * Closes the stream for writing if open for writing;
5872 * returns +nil+.
5873 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5874 *
5875 * Flushes any buffered writes to the operating system before closing.
5876 *
5877 * If the stream was opened by IO.popen and is also closed for reading,
5878 * sets global variable <tt>$?</tt> (child exit status).
5879 *
5880 * IO.popen('ruby', 'r+') do |pipe|
5881 * puts pipe.closed?
5882 * pipe.close_read
5883 * puts pipe.closed?
5884 * pipe.close_write
5885 * puts $?
5886 * puts pipe.closed?
5887 * end
5888 *
5889 * Output:
5890 *
5891 * false
5892 * false
5893 * pid 15044 exit 0
5894 * true
5895 *
5896 * Related: IO#close, IO#close_read, IO#closed?.
5897 */
5898
5899static VALUE
5900rb_io_close_write(VALUE io)
5901{
5902 rb_io_t *fptr;
5903 VALUE write_io;
5904
5905 write_io = GetWriteIO(io);
5906 fptr = rb_io_get_fptr(rb_io_taint_check(write_io));
5907 if (fptr->fd < 0) return Qnil;
5908 if (is_socket(fptr->fd, fptr->pathv)) {
5909#ifndef SHUT_WR
5910# define SHUT_WR 1
5911#endif
5912 if (shutdown(fptr->fd, SHUT_WR) < 0)
5913 rb_sys_fail_path(fptr->pathv);
5914 fptr->mode &= ~FMODE_WRITABLE;
5915 if (!(fptr->mode & FMODE_READABLE))
5916 return rb_io_close(write_io);
5917 return Qnil;
5918 }
5919
5920 if ((fptr->mode & (FMODE_DUPLEX|FMODE_READABLE)) == FMODE_READABLE) {
5921 rb_raise(rb_eIOError, "closing non-duplex IO for writing");
5922 }
5923
5924 if (io != write_io) {
5925 fptr = rb_io_get_fptr(rb_io_taint_check(io));
5926 fptr->tied_io_for_writing = 0;
5927 }
5928 rb_io_close(write_io);
5929 return Qnil;
5930}
5931
5932/*
5933 * call-seq:
5934 * sysseek(offset, whence = IO::SEEK_SET) -> integer
5935 *
5936 * Behaves like IO#seek, except that it:
5937 *
5938 * - Uses low-level system functions.
5939 * - Returns the new position.
5940 *
5941 */
5942
5943static VALUE
5944rb_io_sysseek(int argc, VALUE *argv, VALUE io)
5945{
5946 VALUE offset, ptrname;
5947 int whence = SEEK_SET;
5948 rb_io_t *fptr;
5949 rb_off_t pos;
5950
5951 if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
5952 whence = interpret_seek_whence(ptrname);
5953 }
5954 pos = NUM2OFFT(offset);
5955 GetOpenFile(io, fptr);
5956 if ((fptr->mode & FMODE_READABLE) &&
5957 (READ_DATA_BUFFERED(fptr) || READ_CHAR_PENDING(fptr))) {
5958 rb_raise(rb_eIOError, "sysseek for buffered IO");
5959 }
5960 if ((fptr->mode & FMODE_WRITABLE) && fptr->wbuf.len) {
5961 rb_warn("sysseek for buffered IO");
5962 }
5963 errno = 0;
5964 pos = lseek(fptr->fd, pos, whence);
5965 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
5966
5967 return OFFT2NUM(pos);
5968}
5969
5970/*
5971 * call-seq:
5972 * syswrite(object) -> integer
5973 *
5974 * Writes the given +object+ to self, which must be opened for writing (see Modes);
5975 * returns the number bytes written.
5976 * If +object+ is not a string is converted via method to_s:
5977 *
5978 * f = File.new('t.tmp', 'w')
5979 * f.syswrite('foo') # => 3
5980 * f.syswrite(30) # => 2
5981 * f.syswrite(:foo) # => 3
5982 * f.close
5983 *
5984 * This methods should not be used with other stream-writer methods.
5985 *
5986 */
5987
5988static VALUE
5989rb_io_syswrite(VALUE io, VALUE str)
5990{
5991 VALUE tmp;
5992 rb_io_t *fptr;
5993 long n, len;
5994 const char *ptr;
5995
5996 if (!RB_TYPE_P(str, T_STRING))
5997 str = rb_obj_as_string(str);
5998
5999 io = GetWriteIO(io);
6000 GetOpenFile(io, fptr);
6002
6003 if (fptr->wbuf.len) {
6004 rb_warn("syswrite for buffered IO");
6005 }
6006
6007 tmp = rb_str_tmp_frozen_acquire(str);
6008 RSTRING_GETMEM(tmp, ptr, len);
6009 n = rb_io_write_memory(fptr, ptr, len);
6010 if (n < 0) rb_sys_fail_path(fptr->pathv);
6011 rb_str_tmp_frozen_release(str, tmp);
6012
6013 return LONG2FIX(n);
6014}
6015
6016/*
6017 * call-seq:
6018 * sysread(maxlen) -> string
6019 * sysread(maxlen, out_string) -> string
6020 *
6021 * Behaves like IO#readpartial, except that it uses low-level system functions.
6022 *
6023 * This method should not be used with other stream-reader methods.
6024 *
6025 */
6026
6027static VALUE
6028rb_io_sysread(int argc, VALUE *argv, VALUE io)
6029{
6030 VALUE len, str;
6031 rb_io_t *fptr;
6032 long n, ilen;
6033 struct io_internal_read_struct iis;
6034 int shrinkable;
6035
6036 rb_scan_args(argc, argv, "11", &len, &str);
6037 ilen = NUM2LONG(len);
6038
6039 shrinkable = io_setstrbuf(&str, ilen);
6040 if (ilen == 0) return str;
6041
6042 GetOpenFile(io, fptr);
6044
6045 if (READ_DATA_BUFFERED(fptr)) {
6046 rb_raise(rb_eIOError, "sysread for buffered IO");
6047 }
6048
6049 rb_io_check_closed(fptr);
6050
6051 io_setstrbuf(&str, ilen);
6052 iis.th = rb_thread_current();
6053 iis.fptr = fptr;
6054 iis.nonblock = 0;
6055 iis.fd = fptr->fd;
6056 iis.buf = RSTRING_PTR(str);
6057 iis.capa = ilen;
6058 iis.timeout = NULL;
6059 n = io_read_memory_locktmp(str, &iis);
6060
6061 if (n < 0) {
6062 rb_sys_fail_path(fptr->pathv);
6063 }
6064
6065 io_set_read_length(str, n, shrinkable);
6066
6067 if (n == 0 && ilen > 0) {
6068 rb_eof_error();
6069 }
6070
6071 return str;
6072}
6073
6074#if defined(HAVE_PREAD) || defined(HAVE_PWRITE)
6075struct prdwr_internal_arg {
6076 int fd;
6077 void *buf;
6078 size_t count;
6079 rb_off_t offset;
6080};
6081#endif /* HAVE_PREAD || HAVE_PWRITE */
6082
6083#if defined(HAVE_PREAD)
6084static VALUE
6085internal_pread_func(void *arg)
6086{
6087 struct prdwr_internal_arg *p = arg;
6088 return (VALUE)pread(p->fd, p->buf, p->count, p->offset);
6089}
6090
6091static VALUE
6092pread_internal_call(VALUE arg)
6093{
6094 struct prdwr_internal_arg *p = (struct prdwr_internal_arg *)arg;
6095 return rb_thread_io_blocking_region(internal_pread_func, p, p->fd);
6096}
6097
6098/*
6099 * call-seq:
6100 * pread(maxlen, offset) -> string
6101 * pread(maxlen, offset, out_string) -> string
6102 *
6103 * Behaves like IO#readpartial, except that it:
6104 *
6105 * - Reads at the given +offset+ (in bytes).
6106 * - Disregards, and does not modify, the stream's position
6107 * (see {Position}[rdoc-ref:IO@Position]).
6108 * - Bypasses any user space buffering in the stream.
6109 *
6110 * Because this method does not disturb the stream's state
6111 * (its position, in particular), +pread+ allows multiple threads and processes
6112 * to use the same \IO object for reading at various offsets.
6113 *
6114 * f = File.open('t.txt')
6115 * f.read # => "First line\nSecond line\n\nFourth line\nFifth line\n"
6116 * f.pos # => 52
6117 * # Read 12 bytes at offset 0.
6118 * f.pread(12, 0) # => "First line\n"
6119 * # Read 9 bytes at offset 8.
6120 * f.pread(9, 8) # => "ne\nSecon"
6121 * f.close
6122 *
6123 * Not available on some platforms.
6124 *
6125 */
6126static VALUE
6127rb_io_pread(int argc, VALUE *argv, VALUE io)
6128{
6129 VALUE len, offset, str;
6130 rb_io_t *fptr;
6131 ssize_t n;
6132 struct prdwr_internal_arg arg;
6133 int shrinkable;
6134
6135 rb_scan_args(argc, argv, "21", &len, &offset, &str);
6136 arg.count = NUM2SIZET(len);
6137 arg.offset = NUM2OFFT(offset);
6138
6139 shrinkable = io_setstrbuf(&str, (long)arg.count);
6140 if (arg.count == 0) return str;
6141 arg.buf = RSTRING_PTR(str);
6142
6143 GetOpenFile(io, fptr);
6145
6146 arg.fd = fptr->fd;
6147 rb_io_check_closed(fptr);
6148
6149 rb_str_locktmp(str);
6150 n = (ssize_t)rb_ensure(pread_internal_call, (VALUE)&arg, rb_str_unlocktmp, str);
6151
6152 if (n < 0) {
6153 rb_sys_fail_path(fptr->pathv);
6154 }
6155 io_set_read_length(str, n, shrinkable);
6156 if (n == 0 && arg.count > 0) {
6157 rb_eof_error();
6158 }
6159
6160 return str;
6161}
6162#else
6163# define rb_io_pread rb_f_notimplement
6164#endif /* HAVE_PREAD */
6165
6166#if defined(HAVE_PWRITE)
6167static VALUE
6168internal_pwrite_func(void *ptr)
6169{
6170 struct prdwr_internal_arg *arg = ptr;
6171
6172 return (VALUE)pwrite(arg->fd, arg->buf, arg->count, arg->offset);
6173}
6174
6175/*
6176 * call-seq:
6177 * pwrite(object, offset) -> integer
6178 *
6179 * Behaves like IO#write, except that it:
6180 *
6181 * - Writes at the given +offset+ (in bytes).
6182 * - Disregards, and does not modify, the stream's position
6183 * (see {Position}[rdoc-ref:IO@Position]).
6184 * - Bypasses any user space buffering in the stream.
6185 *
6186 * Because this method does not disturb the stream's state
6187 * (its position, in particular), +pwrite+ allows multiple threads and processes
6188 * to use the same \IO object for writing at various offsets.
6189 *
6190 * f = File.open('t.tmp', 'w+')
6191 * # Write 6 bytes at offset 3.
6192 * f.pwrite('ABCDEF', 3) # => 6
6193 * f.rewind
6194 * f.read # => "\u0000\u0000\u0000ABCDEF"
6195 * f.close
6196 *
6197 * Not available on some platforms.
6198 *
6199 */
6200static VALUE
6201rb_io_pwrite(VALUE io, VALUE str, VALUE offset)
6202{
6203 rb_io_t *fptr;
6204 ssize_t n;
6205 struct prdwr_internal_arg arg;
6206 VALUE tmp;
6207
6208 if (!RB_TYPE_P(str, T_STRING))
6209 str = rb_obj_as_string(str);
6210
6211 arg.offset = NUM2OFFT(offset);
6212
6213 io = GetWriteIO(io);
6214 GetOpenFile(io, fptr);
6216 arg.fd = fptr->fd;
6217
6218 tmp = rb_str_tmp_frozen_acquire(str);
6219 arg.buf = RSTRING_PTR(tmp);
6220 arg.count = (size_t)RSTRING_LEN(tmp);
6221
6222 n = (ssize_t)rb_thread_io_blocking_region(internal_pwrite_func, &arg, fptr->fd);
6223 if (n < 0) rb_sys_fail_path(fptr->pathv);
6224 rb_str_tmp_frozen_release(str, tmp);
6225
6226 return SSIZET2NUM(n);
6227}
6228#else
6229# define rb_io_pwrite rb_f_notimplement
6230#endif /* HAVE_PWRITE */
6231
6232VALUE
6234{
6235 rb_io_t *fptr;
6236
6237 GetOpenFile(io, fptr);
6238 if (fptr->readconv)
6240 if (fptr->writeconv)
6242 fptr->mode |= FMODE_BINMODE;
6243 fptr->mode &= ~FMODE_TEXTMODE;
6244 fptr->writeconv_pre_ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
6245#ifdef O_BINARY
6246 if (!fptr->readconv) {
6247 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6248 }
6249 else {
6250 setmode(fptr->fd, O_BINARY);
6251 }
6252#endif
6253 return io;
6254}
6255
6256static void
6257io_ascii8bit_binmode(rb_io_t *fptr)
6258{
6259 if (fptr->readconv) {
6260 rb_econv_close(fptr->readconv);
6261 fptr->readconv = NULL;
6262 }
6263 if (fptr->writeconv) {
6265 fptr->writeconv = NULL;
6266 }
6267 fptr->mode |= FMODE_BINMODE;
6268 fptr->mode &= ~FMODE_TEXTMODE;
6269 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6270
6271 fptr->encs.enc = rb_ascii8bit_encoding();
6272 fptr->encs.enc2 = NULL;
6273 fptr->encs.ecflags = 0;
6274 fptr->encs.ecopts = Qnil;
6275 clear_codeconv(fptr);
6276}
6277
6278VALUE
6280{
6281 rb_io_t *fptr;
6282
6283 GetOpenFile(io, fptr);
6284 io_ascii8bit_binmode(fptr);
6285
6286 return io;
6287}
6288
6289/*
6290 * call-seq:
6291 * binmode -> self
6292 *
6293 * Sets the stream's data mode as binary
6294 * (see {Data Mode}[rdoc-ref:File@Data+Mode]).
6295 *
6296 * A stream's data mode may not be changed from binary to text.
6297 *
6298 */
6299
6300static VALUE
6301rb_io_binmode_m(VALUE io)
6302{
6303 VALUE write_io;
6304
6306
6307 write_io = GetWriteIO(io);
6308 if (write_io != io)
6309 rb_io_ascii8bit_binmode(write_io);
6310 return io;
6311}
6312
6313/*
6314 * call-seq:
6315 * binmode? -> true or false
6316 *
6317 * Returns +true+ if the stream is on binary mode, +false+ otherwise.
6318 * See {Data Mode}[rdoc-ref:File@Data+Mode].
6319 *
6320 */
6321static VALUE
6322rb_io_binmode_p(VALUE io)
6323{
6324 rb_io_t *fptr;
6325 GetOpenFile(io, fptr);
6326 return RBOOL(fptr->mode & FMODE_BINMODE);
6327}
6328
6329static const char*
6330rb_io_fmode_modestr(int fmode)
6331{
6332 if (fmode & FMODE_APPEND) {
6333 if ((fmode & FMODE_READWRITE) == FMODE_READWRITE) {
6334 return MODE_BTMODE("a+", "ab+", "at+");
6335 }
6336 return MODE_BTMODE("a", "ab", "at");
6337 }
6338 switch (fmode & FMODE_READWRITE) {
6339 default:
6340 rb_raise(rb_eArgError, "invalid access fmode 0x%x", fmode);
6341 case FMODE_READABLE:
6342 return MODE_BTMODE("r", "rb", "rt");
6343 case FMODE_WRITABLE:
6344 return MODE_BTXMODE("w", "wb", "wt", "wx", "wbx", "wtx");
6345 case FMODE_READWRITE:
6346 if (fmode & FMODE_CREATE) {
6347 return MODE_BTXMODE("w+", "wb+", "wt+", "w+x", "wb+x", "wt+x");
6348 }
6349 return MODE_BTMODE("r+", "rb+", "rt+");
6350 }
6351}
6352
6353static const char bom_prefix[] = "bom|";
6354static const char utf_prefix[] = "utf-";
6355enum {bom_prefix_len = (int)sizeof(bom_prefix) - 1};
6356enum {utf_prefix_len = (int)sizeof(utf_prefix) - 1};
6357
6358static int
6359io_encname_bom_p(const char *name, long len)
6360{
6361 return len > bom_prefix_len && STRNCASECMP(name, bom_prefix, bom_prefix_len) == 0;
6362}
6363
6364int
6365rb_io_modestr_fmode(const char *modestr)
6366{
6367 int fmode = 0;
6368 const char *m = modestr, *p = NULL;
6369
6370 switch (*m++) {
6371 case 'r':
6372 fmode |= FMODE_READABLE;
6373 break;
6374 case 'w':
6376 break;
6377 case 'a':
6379 break;
6380 default:
6381 goto error;
6382 }
6383
6384 while (*m) {
6385 switch (*m++) {
6386 case 'b':
6387 fmode |= FMODE_BINMODE;
6388 break;
6389 case 't':
6390 fmode |= FMODE_TEXTMODE;
6391 break;
6392 case '+':
6393 fmode |= FMODE_READWRITE;
6394 break;
6395 case 'x':
6396 if (modestr[0] != 'w')
6397 goto error;
6398 fmode |= FMODE_EXCL;
6399 break;
6400 default:
6401 goto error;
6402 case ':':
6403 p = strchr(m, ':');
6404 if (io_encname_bom_p(m, p ? (long)(p - m) : (long)strlen(m)))
6405 fmode |= FMODE_SETENC_BY_BOM;
6406 goto finished;
6407 }
6408 }
6409
6410 finished:
6411 if ((fmode & FMODE_BINMODE) && (fmode & FMODE_TEXTMODE))
6412 goto error;
6413
6414 return fmode;
6415
6416 error:
6417 rb_raise(rb_eArgError, "invalid access mode %s", modestr);
6419}
6420
6421int
6422rb_io_oflags_fmode(int oflags)
6423{
6424 int fmode = 0;
6425
6426 switch (oflags & O_ACCMODE) {
6427 case O_RDONLY:
6428 fmode = FMODE_READABLE;
6429 break;
6430 case O_WRONLY:
6431 fmode = FMODE_WRITABLE;
6432 break;
6433 case O_RDWR:
6434 fmode = FMODE_READWRITE;
6435 break;
6436 }
6437
6438 if (oflags & O_APPEND) {
6439 fmode |= FMODE_APPEND;
6440 }
6441 if (oflags & O_TRUNC) {
6442 fmode |= FMODE_TRUNC;
6443 }
6444 if (oflags & O_CREAT) {
6445 fmode |= FMODE_CREATE;
6446 }
6447 if (oflags & O_EXCL) {
6448 fmode |= FMODE_EXCL;
6449 }
6450#ifdef O_BINARY
6451 if (oflags & O_BINARY) {
6452 fmode |= FMODE_BINMODE;
6453 }
6454#endif
6455
6456 return fmode;
6457}
6458
6459static int
6460rb_io_fmode_oflags(int fmode)
6461{
6462 int oflags = 0;
6463
6464 switch (fmode & FMODE_READWRITE) {
6465 case FMODE_READABLE:
6466 oflags |= O_RDONLY;
6467 break;
6468 case FMODE_WRITABLE:
6469 oflags |= O_WRONLY;
6470 break;
6471 case FMODE_READWRITE:
6472 oflags |= O_RDWR;
6473 break;
6474 }
6475
6476 if (fmode & FMODE_APPEND) {
6477 oflags |= O_APPEND;
6478 }
6479 if (fmode & FMODE_TRUNC) {
6480 oflags |= O_TRUNC;
6481 }
6482 if (fmode & FMODE_CREATE) {
6483 oflags |= O_CREAT;
6484 }
6485 if (fmode & FMODE_EXCL) {
6486 oflags |= O_EXCL;
6487 }
6488#ifdef O_BINARY
6489 if (fmode & FMODE_BINMODE) {
6490 oflags |= O_BINARY;
6491 }
6492#endif
6493
6494 return oflags;
6495}
6496
6497int
6498rb_io_modestr_oflags(const char *modestr)
6499{
6500 return rb_io_fmode_oflags(rb_io_modestr_fmode(modestr));
6501}
6502
6503static const char*
6504rb_io_oflags_modestr(int oflags)
6505{
6506#ifdef O_BINARY
6507# define MODE_BINARY(a,b) ((oflags & O_BINARY) ? (b) : (a))
6508#else
6509# define MODE_BINARY(a,b) (a)
6510#endif
6511 int accmode;
6512 if (oflags & O_EXCL) {
6513 rb_raise(rb_eArgError, "exclusive access mode is not supported");
6514 }
6515 accmode = oflags & (O_RDONLY|O_WRONLY|O_RDWR);
6516 if (oflags & O_APPEND) {
6517 if (accmode == O_WRONLY) {
6518 return MODE_BINARY("a", "ab");
6519 }
6520 if (accmode == O_RDWR) {
6521 return MODE_BINARY("a+", "ab+");
6522 }
6523 }
6524 switch (accmode) {
6525 default:
6526 rb_raise(rb_eArgError, "invalid access oflags 0x%x", oflags);
6527 case O_RDONLY:
6528 return MODE_BINARY("r", "rb");
6529 case O_WRONLY:
6530 return MODE_BINARY("w", "wb");
6531 case O_RDWR:
6532 if (oflags & O_TRUNC) {
6533 return MODE_BINARY("w+", "wb+");
6534 }
6535 return MODE_BINARY("r+", "rb+");
6536 }
6537}
6538
6539/*
6540 * Convert external/internal encodings to enc/enc2
6541 * NULL => use default encoding
6542 * Qnil => no encoding specified (internal only)
6543 */
6544static void
6545rb_io_ext_int_to_encs(rb_encoding *ext, rb_encoding *intern, rb_encoding **enc, rb_encoding **enc2, int fmode)
6546{
6547 int default_ext = 0;
6548
6549 if (ext == NULL) {
6550 ext = rb_default_external_encoding();
6551 default_ext = 1;
6552 }
6553 if (rb_is_ascii8bit_enc(ext)) {
6554 /* If external is ASCII-8BIT, no transcoding */
6555 intern = NULL;
6556 }
6557 else if (intern == NULL) {
6558 intern = rb_default_internal_encoding();
6559 }
6560 if (intern == NULL || intern == (rb_encoding *)Qnil ||
6561 (!(fmode & FMODE_SETENC_BY_BOM) && (intern == ext))) {
6562 /* No internal encoding => use external + no transcoding */
6563 *enc = (default_ext && intern != ext) ? NULL : ext;
6564 *enc2 = NULL;
6565 }
6566 else {
6567 *enc = intern;
6568 *enc2 = ext;
6569 }
6570}
6571
6572static void
6573unsupported_encoding(const char *name, rb_encoding *enc)
6574{
6575 rb_enc_warn(enc, "Unsupported encoding %s ignored", name);
6576}
6577
6578static void
6579parse_mode_enc(const char *estr, rb_encoding *estr_enc,
6580 rb_encoding **enc_p, rb_encoding **enc2_p, int *fmode_p)
6581{
6582 const char *p;
6583 char encname[ENCODING_MAXNAMELEN+1];
6584 int idx, idx2;
6585 int fmode = fmode_p ? *fmode_p : 0;
6586 rb_encoding *ext_enc, *int_enc;
6587 long len;
6588
6589 /* parse estr as "enc" or "enc2:enc" or "enc:-" */
6590
6591 p = strrchr(estr, ':');
6592 len = p ? (p++ - estr) : (long)strlen(estr);
6593 if ((fmode & FMODE_SETENC_BY_BOM) || io_encname_bom_p(estr, len)) {
6594 estr += bom_prefix_len;
6595 len -= bom_prefix_len;
6596 if (!STRNCASECMP(estr, utf_prefix, utf_prefix_len)) {
6597 fmode |= FMODE_SETENC_BY_BOM;
6598 }
6599 else {
6600 rb_enc_warn(estr_enc, "BOM with non-UTF encoding %s is nonsense", estr);
6601 fmode &= ~FMODE_SETENC_BY_BOM;
6602 }
6603 }
6604 if (len == 0 || len > ENCODING_MAXNAMELEN) {
6605 idx = -1;
6606 }
6607 else {
6608 if (p) {
6609 memcpy(encname, estr, len);
6610 encname[len] = '\0';
6611 estr = encname;
6612 }
6613 idx = rb_enc_find_index(estr);
6614 }
6615 if (fmode_p) *fmode_p = fmode;
6616
6617 if (idx >= 0)
6618 ext_enc = rb_enc_from_index(idx);
6619 else {
6620 if (idx != -2)
6621 unsupported_encoding(estr, estr_enc);
6622 ext_enc = NULL;
6623 }
6624
6625 int_enc = NULL;
6626 if (p) {
6627 if (*p == '-' && *(p+1) == '\0') {
6628 /* Special case - "-" => no transcoding */
6629 int_enc = (rb_encoding *)Qnil;
6630 }
6631 else {
6632 idx2 = rb_enc_find_index(p);
6633 if (idx2 < 0)
6634 unsupported_encoding(p, estr_enc);
6635 else if (!(fmode & FMODE_SETENC_BY_BOM) && (idx2 == idx)) {
6636 int_enc = (rb_encoding *)Qnil;
6637 }
6638 else
6639 int_enc = rb_enc_from_index(idx2);
6640 }
6641 }
6642
6643 rb_io_ext_int_to_encs(ext_enc, int_enc, enc_p, enc2_p, fmode);
6644}
6645
6646int
6647rb_io_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding **enc2_p, int *fmode_p)
6648{
6649 VALUE encoding=Qnil, extenc=Qundef, intenc=Qundef, tmp;
6650 int extracted = 0;
6651 rb_encoding *extencoding = NULL;
6652 rb_encoding *intencoding = NULL;
6653
6654 if (!NIL_P(opt)) {
6655 VALUE v;
6656 v = rb_hash_lookup2(opt, sym_encoding, Qnil);
6657 if (v != Qnil) encoding = v;
6658 v = rb_hash_lookup2(opt, sym_extenc, Qundef);
6659 if (v != Qnil) extenc = v;
6660 v = rb_hash_lookup2(opt, sym_intenc, Qundef);
6661 if (!UNDEF_P(v)) intenc = v;
6662 }
6663 if ((!UNDEF_P(extenc) || !UNDEF_P(intenc)) && !NIL_P(encoding)) {
6664 if (!NIL_P(ruby_verbose)) {
6665 int idx = rb_to_encoding_index(encoding);
6666 if (idx >= 0) encoding = rb_enc_from_encoding(rb_enc_from_index(idx));
6667 rb_warn("Ignoring encoding parameter '%"PRIsVALUE"': %s_encoding is used",
6668 encoding, UNDEF_P(extenc) ? "internal" : "external");
6669 }
6670 encoding = Qnil;
6671 }
6672 if (!UNDEF_P(extenc) && !NIL_P(extenc)) {
6673 extencoding = rb_to_encoding(extenc);
6674 }
6675 if (!UNDEF_P(intenc)) {
6676 if (NIL_P(intenc)) {
6677 /* internal_encoding: nil => no transcoding */
6678 intencoding = (rb_encoding *)Qnil;
6679 }
6680 else if (!NIL_P(tmp = rb_check_string_type(intenc))) {
6681 char *p = StringValueCStr(tmp);
6682
6683 if (*p == '-' && *(p+1) == '\0') {
6684 /* Special case - "-" => no transcoding */
6685 intencoding = (rb_encoding *)Qnil;
6686 }
6687 else {
6688 intencoding = rb_to_encoding(intenc);
6689 }
6690 }
6691 else {
6692 intencoding = rb_to_encoding(intenc);
6693 }
6694 if (extencoding == intencoding) {
6695 intencoding = (rb_encoding *)Qnil;
6696 }
6697 }
6698 if (!NIL_P(encoding)) {
6699 extracted = 1;
6700 if (!NIL_P(tmp = rb_check_string_type(encoding))) {
6701 parse_mode_enc(StringValueCStr(tmp), rb_enc_get(tmp),
6702 enc_p, enc2_p, fmode_p);
6703 }
6704 else {
6705 rb_io_ext_int_to_encs(rb_to_encoding(encoding), NULL, enc_p, enc2_p, 0);
6706 }
6707 }
6708 else if (!UNDEF_P(extenc) || !UNDEF_P(intenc)) {
6709 extracted = 1;
6710 rb_io_ext_int_to_encs(extencoding, intencoding, enc_p, enc2_p, 0);
6711 }
6712 return extracted;
6713}
6714
6715typedef struct rb_io_enc_t convconfig_t;
6716
6717static void
6718validate_enc_binmode(int *fmode_p, int ecflags, rb_encoding *enc, rb_encoding *enc2)
6719{
6720 int fmode = *fmode_p;
6721
6722 if ((fmode & FMODE_READABLE) &&
6723 !enc2 &&
6724 !(fmode & FMODE_BINMODE) &&
6725 !rb_enc_asciicompat(enc ? enc : rb_default_external_encoding()))
6726 rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
6727
6728 if ((fmode & FMODE_BINMODE) && (ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
6729 rb_raise(rb_eArgError, "newline decorator with binary mode");
6730 }
6731 if (!(fmode & FMODE_BINMODE) &&
6732 (DEFAULT_TEXTMODE || (ecflags & ECONV_NEWLINE_DECORATOR_MASK))) {
6733 fmode |= FMODE_TEXTMODE;
6734 *fmode_p = fmode;
6735 }
6736#if !DEFAULT_TEXTMODE
6737 else if (!(ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
6738 fmode &= ~FMODE_TEXTMODE;
6739 *fmode_p = fmode;
6740 }
6741#endif
6742}
6743
6744static void
6745extract_binmode(VALUE opthash, int *fmode)
6746{
6747 if (!NIL_P(opthash)) {
6748 VALUE v;
6749 v = rb_hash_aref(opthash, sym_textmode);
6750 if (!NIL_P(v)) {
6751 if (*fmode & FMODE_TEXTMODE)
6752 rb_raise(rb_eArgError, "textmode specified twice");
6753 if (*fmode & FMODE_BINMODE)
6754 rb_raise(rb_eArgError, "both textmode and binmode specified");
6755 if (RTEST(v))
6756 *fmode |= FMODE_TEXTMODE;
6757 }
6758 v = rb_hash_aref(opthash, sym_binmode);
6759 if (!NIL_P(v)) {
6760 if (*fmode & FMODE_BINMODE)
6761 rb_raise(rb_eArgError, "binmode specified twice");
6762 if (*fmode & FMODE_TEXTMODE)
6763 rb_raise(rb_eArgError, "both textmode and binmode specified");
6764 if (RTEST(v))
6765 *fmode |= FMODE_BINMODE;
6766 }
6767
6768 if ((*fmode & FMODE_BINMODE) && (*fmode & FMODE_TEXTMODE))
6769 rb_raise(rb_eArgError, "both textmode and binmode specified");
6770 }
6771}
6772
6773void
6774rb_io_extract_modeenc(VALUE *vmode_p, VALUE *vperm_p, VALUE opthash,
6775 int *oflags_p, int *fmode_p, convconfig_t *convconfig_p)
6776{
6777 VALUE vmode;
6778 int oflags, fmode;
6779 rb_encoding *enc, *enc2;
6780 int ecflags;
6781 VALUE ecopts;
6782 int has_enc = 0, has_vmode = 0;
6783 VALUE intmode;
6784
6785 vmode = *vmode_p;
6786
6787 /* Set to defaults */
6788 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
6789
6790 vmode_handle:
6791 if (NIL_P(vmode)) {
6792 fmode = FMODE_READABLE;
6793 oflags = O_RDONLY;
6794 }
6795 else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int"))) {
6796 vmode = intmode;
6797 oflags = NUM2INT(intmode);
6798 fmode = rb_io_oflags_fmode(oflags);
6799 }
6800 else {
6801 const char *p;
6802
6803 SafeStringValue(vmode);
6804 p = StringValueCStr(vmode);
6805 fmode = rb_io_modestr_fmode(p);
6806 oflags = rb_io_fmode_oflags(fmode);
6807 p = strchr(p, ':');
6808 if (p) {
6809 has_enc = 1;
6810 parse_mode_enc(p+1, rb_enc_get(vmode), &enc, &enc2, &fmode);
6811 }
6812 else {
6813 rb_encoding *e;
6814
6815 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
6816 rb_io_ext_int_to_encs(e, NULL, &enc, &enc2, fmode);
6817 }
6818 }
6819
6820 if (NIL_P(opthash)) {
6821 ecflags = (fmode & FMODE_READABLE) ?
6824#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
6825 ecflags |= (fmode & FMODE_WRITABLE) ?
6826 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
6827 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
6828#endif
6829 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
6830 ecopts = Qnil;
6831 if (fmode & FMODE_BINMODE) {
6832#ifdef O_BINARY
6833 oflags |= O_BINARY;
6834#endif
6835 if (!has_enc)
6836 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
6837 }
6838#if DEFAULT_TEXTMODE
6839 else if (NIL_P(vmode)) {
6840 fmode |= DEFAULT_TEXTMODE;
6841 }
6842#endif
6843 }
6844 else {
6845 VALUE v;
6846 if (!has_vmode) {
6847 v = rb_hash_aref(opthash, sym_mode);
6848 if (!NIL_P(v)) {
6849 if (!NIL_P(vmode)) {
6850 rb_raise(rb_eArgError, "mode specified twice");
6851 }
6852 has_vmode = 1;
6853 vmode = v;
6854 goto vmode_handle;
6855 }
6856 }
6857 v = rb_hash_aref(opthash, sym_flags);
6858 if (!NIL_P(v)) {
6859 v = rb_to_int(v);
6860 oflags |= NUM2INT(v);
6861 vmode = INT2NUM(oflags);
6862 fmode = rb_io_oflags_fmode(oflags);
6863 }
6864 extract_binmode(opthash, &fmode);
6865 if (fmode & FMODE_BINMODE) {
6866#ifdef O_BINARY
6867 oflags |= O_BINARY;
6868#endif
6869 if (!has_enc)
6870 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
6871 }
6872#if DEFAULT_TEXTMODE
6873 else if (NIL_P(vmode)) {
6874 fmode |= DEFAULT_TEXTMODE;
6875 }
6876#endif
6877 v = rb_hash_aref(opthash, sym_perm);
6878 if (!NIL_P(v)) {
6879 if (vperm_p) {
6880 if (!NIL_P(*vperm_p)) {
6881 rb_raise(rb_eArgError, "perm specified twice");
6882 }
6883 *vperm_p = v;
6884 }
6885 else {
6886 /* perm no use, just ignore */
6887 }
6888 }
6889 ecflags = (fmode & FMODE_READABLE) ?
6892#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
6893 ecflags |= (fmode & FMODE_WRITABLE) ?
6894 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
6895 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
6896#endif
6897
6898 if (rb_io_extract_encoding_option(opthash, &enc, &enc2, &fmode)) {
6899 if (has_enc) {
6900 rb_raise(rb_eArgError, "encoding specified twice");
6901 }
6902 }
6903 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
6905 }
6906
6907 validate_enc_binmode(&fmode, ecflags, enc, enc2);
6908
6909 *vmode_p = vmode;
6910
6911 *oflags_p = oflags;
6912 *fmode_p = fmode;
6913 convconfig_p->enc = enc;
6914 convconfig_p->enc2 = enc2;
6915 convconfig_p->ecflags = ecflags;
6916 convconfig_p->ecopts = ecopts;
6917}
6918
6920 VALUE fname;
6921 int oflags;
6922 mode_t perm;
6923};
6924
6925static void *
6926sysopen_func(void *ptr)
6927{
6928 const struct sysopen_struct *data = ptr;
6929 const char *fname = RSTRING_PTR(data->fname);
6930 return (void *)(VALUE)rb_cloexec_open(fname, data->oflags, data->perm);
6931}
6932
6933static inline int
6934rb_sysopen_internal(struct sysopen_struct *data)
6935{
6936 int fd;
6937 fd = (int)(VALUE)rb_thread_call_without_gvl(sysopen_func, data, RUBY_UBF_IO, 0);
6938 if (0 <= fd)
6939 rb_update_max_fd(fd);
6940 return fd;
6941}
6942
6943static int
6944rb_sysopen(VALUE fname, int oflags, mode_t perm)
6945{
6946 int fd;
6947 struct sysopen_struct data;
6948
6949 data.fname = rb_str_encode_ospath(fname);
6950 StringValueCStr(data.fname);
6951 data.oflags = oflags;
6952 data.perm = perm;
6953
6954 fd = rb_sysopen_internal(&data);
6955 if (fd < 0) {
6956 int e = errno;
6957 if (rb_gc_for_fd(e)) {
6958 fd = rb_sysopen_internal(&data);
6959 }
6960 if (fd < 0) {
6961 rb_syserr_fail_path(e, fname);
6962 }
6963 }
6964 return fd;
6965}
6966
6967FILE *
6968rb_fdopen(int fd, const char *modestr)
6969{
6970 FILE *file;
6971
6972#if defined(__sun)
6973 errno = 0;
6974#endif
6975 file = fdopen(fd, modestr);
6976 if (!file) {
6977 int e = errno;
6978#if defined(__sun)
6979 if (e == 0) {
6980 rb_gc();
6981 errno = 0;
6982 file = fdopen(fd, modestr);
6983 }
6984 else
6985#endif
6986 if (rb_gc_for_fd(e)) {
6987 file = fdopen(fd, modestr);
6988 }
6989 if (!file) {
6990#ifdef _WIN32
6991 if (e == 0) e = EINVAL;
6992#elif defined(__sun)
6993 if (e == 0) e = EMFILE;
6994#endif
6995 rb_syserr_fail(e, 0);
6996 }
6997 }
6998
6999 /* xxx: should be _IONBF? A buffer in FILE may have trouble. */
7000#ifdef USE_SETVBUF
7001 if (setvbuf(file, NULL, _IOFBF, 0) != 0)
7002 rb_warn("setvbuf() can't be honoured (fd=%d)", fd);
7003#endif
7004 return file;
7005}
7006
7007static int
7008io_check_tty(rb_io_t *fptr)
7009{
7010 int t = isatty(fptr->fd);
7011 if (t)
7012 fptr->mode |= FMODE_TTY|FMODE_DUPLEX;
7013 return t;
7014}
7015
7016static VALUE rb_io_internal_encoding(VALUE);
7017static void io_encoding_set(rb_io_t *, VALUE, VALUE, VALUE);
7018
7019static int
7020io_strip_bom(VALUE io)
7021{
7022 VALUE b1, b2, b3, b4;
7023 rb_io_t *fptr;
7024
7025 GetOpenFile(io, fptr);
7026 if (!(fptr->mode & FMODE_READABLE)) return 0;
7027 if (NIL_P(b1 = rb_io_getbyte(io))) return 0;
7028 switch (b1) {
7029 case INT2FIX(0xEF):
7030 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7031 if (b2 == INT2FIX(0xBB) && !NIL_P(b3 = rb_io_getbyte(io))) {
7032 if (b3 == INT2FIX(0xBF)) {
7033 return rb_utf8_encindex();
7034 }
7035 rb_io_ungetbyte(io, b3);
7036 }
7037 rb_io_ungetbyte(io, b2);
7038 break;
7039
7040 case INT2FIX(0xFE):
7041 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7042 if (b2 == INT2FIX(0xFF)) {
7043 return ENCINDEX_UTF_16BE;
7044 }
7045 rb_io_ungetbyte(io, b2);
7046 break;
7047
7048 case INT2FIX(0xFF):
7049 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7050 if (b2 == INT2FIX(0xFE)) {
7051 b3 = rb_io_getbyte(io);
7052 if (b3 == INT2FIX(0) && !NIL_P(b4 = rb_io_getbyte(io))) {
7053 if (b4 == INT2FIX(0)) {
7054 return ENCINDEX_UTF_32LE;
7055 }
7056 rb_io_ungetbyte(io, b4);
7057 }
7058 rb_io_ungetbyte(io, b3);
7059 return ENCINDEX_UTF_16LE;
7060 }
7061 rb_io_ungetbyte(io, b2);
7062 break;
7063
7064 case INT2FIX(0):
7065 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7066 if (b2 == INT2FIX(0) && !NIL_P(b3 = rb_io_getbyte(io))) {
7067 if (b3 == INT2FIX(0xFE) && !NIL_P(b4 = rb_io_getbyte(io))) {
7068 if (b4 == INT2FIX(0xFF)) {
7069 return ENCINDEX_UTF_32BE;
7070 }
7071 rb_io_ungetbyte(io, b4);
7072 }
7073 rb_io_ungetbyte(io, b3);
7074 }
7075 rb_io_ungetbyte(io, b2);
7076 break;
7077 }
7078 rb_io_ungetbyte(io, b1);
7079 return 0;
7080}
7081
7082static rb_encoding *
7083io_set_encoding_by_bom(VALUE io)
7084{
7085 int idx = io_strip_bom(io);
7086 rb_io_t *fptr;
7087 rb_encoding *extenc = NULL;
7088
7089 GetOpenFile(io, fptr);
7090 if (idx) {
7091 extenc = rb_enc_from_index(idx);
7092 io_encoding_set(fptr, rb_enc_from_encoding(extenc),
7093 rb_io_internal_encoding(io), Qnil);
7094 }
7095 else {
7096 fptr->encs.enc2 = NULL;
7097 }
7098 return extenc;
7099}
7100
7101static VALUE
7102rb_file_open_generic(VALUE io, VALUE filename, int oflags, int fmode,
7103 const convconfig_t *convconfig, mode_t perm)
7104{
7105 VALUE pathv;
7106 rb_io_t *fptr;
7107 convconfig_t cc;
7108 if (!convconfig) {
7109 /* Set to default encodings */
7110 rb_io_ext_int_to_encs(NULL, NULL, &cc.enc, &cc.enc2, fmode);
7111 cc.ecflags = 0;
7112 cc.ecopts = Qnil;
7113 convconfig = &cc;
7114 }
7115 validate_enc_binmode(&fmode, convconfig->ecflags,
7116 convconfig->enc, convconfig->enc2);
7117
7118 MakeOpenFile(io, fptr);
7119 fptr->mode = fmode;
7120 fptr->encs = *convconfig;
7121 pathv = rb_str_new_frozen(filename);
7122#ifdef O_TMPFILE
7123 if (!(oflags & O_TMPFILE)) {
7124 fptr->pathv = pathv;
7125 }
7126#else
7127 fptr->pathv = pathv;
7128#endif
7129 fptr->fd = rb_sysopen(pathv, oflags, perm);
7130 io_check_tty(fptr);
7131 if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
7132
7133 return io;
7134}
7135
7136static VALUE
7137rb_file_open_internal(VALUE io, VALUE filename, const char *modestr)
7138{
7139 int fmode = rb_io_modestr_fmode(modestr);
7140 const char *p = strchr(modestr, ':');
7141 convconfig_t convconfig;
7142
7143 if (p) {
7144 parse_mode_enc(p+1, rb_usascii_encoding(),
7145 &convconfig.enc, &convconfig.enc2, &fmode);
7146 convconfig.ecflags = 0;
7147 convconfig.ecopts = Qnil;
7148 }
7149 else {
7150 rb_encoding *e;
7151 /* Set to default encodings */
7152
7153 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
7154 rb_io_ext_int_to_encs(e, NULL, &convconfig.enc, &convconfig.enc2, fmode);
7155 convconfig.ecflags = 0;
7156 convconfig.ecopts = Qnil;
7157 }
7158
7159 return rb_file_open_generic(io, filename,
7160 rb_io_fmode_oflags(fmode),
7161 fmode,
7162 &convconfig,
7163 0666);
7164}
7165
7166VALUE
7167rb_file_open_str(VALUE fname, const char *modestr)
7168{
7169 FilePathValue(fname);
7170 return rb_file_open_internal(io_alloc(rb_cFile), fname, modestr);
7171}
7172
7173VALUE
7174rb_file_open(const char *fname, const char *modestr)
7175{
7176 return rb_file_open_internal(io_alloc(rb_cFile), rb_str_new_cstr(fname), modestr);
7177}
7178
7179#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7180static struct pipe_list {
7181 rb_io_t *fptr;
7182 struct pipe_list *next;
7183} *pipe_list;
7184
7185static void
7186pipe_add_fptr(rb_io_t *fptr)
7187{
7188 struct pipe_list *list;
7189
7190 list = ALLOC(struct pipe_list);
7191 list->fptr = fptr;
7192 list->next = pipe_list;
7193 pipe_list = list;
7194}
7195
7196static void
7197pipe_del_fptr(rb_io_t *fptr)
7198{
7199 struct pipe_list **prev = &pipe_list;
7200 struct pipe_list *tmp;
7201
7202 while ((tmp = *prev) != 0) {
7203 if (tmp->fptr == fptr) {
7204 *prev = tmp->next;
7205 free(tmp);
7206 return;
7207 }
7208 prev = &tmp->next;
7209 }
7210}
7211
7212#if defined (_WIN32) || defined(__CYGWIN__)
7213static void
7214pipe_atexit(void)
7215{
7216 struct pipe_list *list = pipe_list;
7217 struct pipe_list *tmp;
7218
7219 while (list) {
7220 tmp = list->next;
7221 rb_io_fptr_finalize(list->fptr);
7222 list = tmp;
7223 }
7224}
7225#endif
7226
7227static void
7228pipe_finalize(rb_io_t *fptr, int noraise)
7229{
7230#if !defined(HAVE_WORKING_FORK) && !defined(_WIN32)
7231 int status = 0;
7232 if (fptr->stdio_file) {
7233 status = pclose(fptr->stdio_file);
7234 }
7235 fptr->fd = -1;
7236 fptr->stdio_file = 0;
7237 rb_last_status_set(status, fptr->pid);
7238#else
7239 fptr_finalize(fptr, noraise);
7240#endif
7241 pipe_del_fptr(fptr);
7242}
7243#endif
7244
7245static void
7246fptr_copy_finalizer(rb_io_t *fptr, const rb_io_t *orig)
7247{
7248#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7249 void (*const old_finalize)(struct rb_io_t*,int) = fptr->finalize;
7250
7251 if (old_finalize == orig->finalize) return;
7252#endif
7253
7254 fptr->finalize = orig->finalize;
7255
7256#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7257 if (old_finalize != pipe_finalize) {
7258 struct pipe_list *list;
7259 for (list = pipe_list; list; list = list->next) {
7260 if (list->fptr == fptr) break;
7261 }
7262 if (!list) pipe_add_fptr(fptr);
7263 }
7264 else {
7265 pipe_del_fptr(fptr);
7266 }
7267#endif
7268}
7269
7270void
7272{
7274 fptr->mode |= FMODE_SYNC;
7275}
7276
7277void
7278rb_io_unbuffered(rb_io_t *fptr)
7279{
7280 rb_io_synchronized(fptr);
7281}
7282
7283int
7284rb_pipe(int *pipes)
7285{
7286 int ret;
7287 ret = rb_cloexec_pipe(pipes);
7288 if (ret < 0) {
7289 if (rb_gc_for_fd(errno)) {
7290 ret = rb_cloexec_pipe(pipes);
7291 }
7292 }
7293 if (ret == 0) {
7294 rb_update_max_fd(pipes[0]);
7295 rb_update_max_fd(pipes[1]);
7296 }
7297 return ret;
7298}
7299
7300#ifdef _WIN32
7301#define HAVE_SPAWNV 1
7302#define spawnv(mode, cmd, args) rb_w32_uaspawn((mode), (cmd), (args))
7303#define spawn(mode, cmd) rb_w32_uspawn((mode), (cmd), 0)
7304#endif
7305
7306#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7307struct popen_arg {
7308 VALUE execarg_obj;
7309 struct rb_execarg *eargp;
7310 int modef;
7311 int pair[2];
7312 int write_pair[2];
7313};
7314#endif
7315
7316#ifdef HAVE_WORKING_FORK
7317# ifndef __EMSCRIPTEN__
7318static void
7319popen_redirect(struct popen_arg *p)
7320{
7321 if ((p->modef & FMODE_READABLE) && (p->modef & FMODE_WRITABLE)) {
7322 close(p->write_pair[1]);
7323 if (p->write_pair[0] != 0) {
7324 dup2(p->write_pair[0], 0);
7325 close(p->write_pair[0]);
7326 }
7327 close(p->pair[0]);
7328 if (p->pair[1] != 1) {
7329 dup2(p->pair[1], 1);
7330 close(p->pair[1]);
7331 }
7332 }
7333 else if (p->modef & FMODE_READABLE) {
7334 close(p->pair[0]);
7335 if (p->pair[1] != 1) {
7336 dup2(p->pair[1], 1);
7337 close(p->pair[1]);
7338 }
7339 }
7340 else {
7341 close(p->pair[1]);
7342 if (p->pair[0] != 0) {
7343 dup2(p->pair[0], 0);
7344 close(p->pair[0]);
7345 }
7346 }
7347}
7348# endif
7349
7350#if defined(__linux__)
7351/* Linux /proc/self/status contains a line: "FDSize:\t<nnn>\n"
7352 * Since /proc may not be available, linux_get_maxfd is just a hint.
7353 * This function, linux_get_maxfd, must be async-signal-safe.
7354 * I.e. opendir() is not usable.
7355 *
7356 * Note that memchr() and memcmp is *not* async-signal-safe in POSIX.
7357 * However they are easy to re-implement in async-signal-safe manner.
7358 * (Also note that there is missing/memcmp.c.)
7359 */
7360static int
7361linux_get_maxfd(void)
7362{
7363 int fd;
7364 char buf[4096], *p, *np, *e;
7365 ssize_t ss;
7366 fd = rb_cloexec_open("/proc/self/status", O_RDONLY|O_NOCTTY, 0);
7367 if (fd < 0) return fd;
7368 ss = read(fd, buf, sizeof(buf));
7369 if (ss < 0) goto err;
7370 p = buf;
7371 e = buf + ss;
7372 while ((int)sizeof("FDSize:\t0\n")-1 <= e-p &&
7373 (np = memchr(p, '\n', e-p)) != NULL) {
7374 if (memcmp(p, "FDSize:", sizeof("FDSize:")-1) == 0) {
7375 int fdsize;
7376 p += sizeof("FDSize:")-1;
7377 *np = '\0';
7378 fdsize = (int)ruby_strtoul(p, (char **)NULL, 10);
7379 close(fd);
7380 return fdsize;
7381 }
7382 p = np+1;
7383 }
7384 /* fall through */
7385
7386 err:
7387 close(fd);
7388 return (int)ss;
7389}
7390#endif
7391
7392/* This function should be async-signal-safe. */
7393void
7394rb_close_before_exec(int lowfd, int maxhint, VALUE noclose_fds)
7395{
7396#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
7397 int fd, ret;
7398 int max = (int)max_file_descriptor;
7399# ifdef F_MAXFD
7400 /* F_MAXFD is available since NetBSD 2.0. */
7401 ret = fcntl(0, F_MAXFD); /* async-signal-safe */
7402 if (ret != -1)
7403 maxhint = max = ret;
7404# elif defined(__linux__)
7405 ret = linux_get_maxfd();
7406 if (maxhint < ret)
7407 maxhint = ret;
7408 /* maxhint = max = ret; if (ret == -1) abort(); // test */
7409# endif
7410 if (max < maxhint)
7411 max = maxhint;
7412 for (fd = lowfd; fd <= max; fd++) {
7413 if (!NIL_P(noclose_fds) &&
7414 RTEST(rb_hash_lookup(noclose_fds, INT2FIX(fd)))) /* async-signal-safe */
7415 continue;
7416 ret = fcntl(fd, F_GETFD); /* async-signal-safe */
7417 if (ret != -1 && !(ret & FD_CLOEXEC)) {
7418 fcntl(fd, F_SETFD, ret|FD_CLOEXEC); /* async-signal-safe */
7419 }
7420# define CONTIGUOUS_CLOSED_FDS 20
7421 if (ret != -1) {
7422 if (max < fd + CONTIGUOUS_CLOSED_FDS)
7423 max = fd + CONTIGUOUS_CLOSED_FDS;
7424 }
7425 }
7426#endif
7427}
7428
7429# ifndef __EMSCRIPTEN__
7430static int
7431popen_exec(void *pp, char *errmsg, size_t errmsg_len)
7432{
7433 struct popen_arg *p = (struct popen_arg*)pp;
7434
7435 return rb_exec_async_signal_safe(p->eargp, errmsg, errmsg_len);
7436}
7437# endif
7438#endif
7439
7440#if (defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)) && !defined __EMSCRIPTEN__
7441static VALUE
7442rb_execarg_fixup_v(VALUE execarg_obj)
7443{
7444 rb_execarg_parent_start(execarg_obj);
7445 return Qnil;
7446}
7447#else
7448char *rb_execarg_commandline(const struct rb_execarg *eargp, VALUE *prog);
7449#endif
7450
7451#ifndef __EMSCRIPTEN__
7452static VALUE
7453pipe_open(VALUE execarg_obj, const char *modestr, int fmode,
7454 const convconfig_t *convconfig)
7455{
7456 struct rb_execarg *eargp = NIL_P(execarg_obj) ? NULL : rb_execarg_get(execarg_obj);
7457 VALUE prog = eargp ? (eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name) : Qfalse ;
7458 rb_pid_t pid = 0;
7459 rb_io_t *fptr;
7460 VALUE port;
7461 rb_io_t *write_fptr;
7462 VALUE write_port;
7463#if defined(HAVE_WORKING_FORK)
7464 int status;
7465 char errmsg[80] = { '\0' };
7466#endif
7467#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7468 int state;
7469 struct popen_arg arg;
7470#endif
7471 int e = 0;
7472#if defined(HAVE_SPAWNV)
7473# if defined(HAVE_SPAWNVE)
7474# define DO_SPAWN(cmd, args, envp) ((args) ? \
7475 spawnve(P_NOWAIT, (cmd), (args), (envp)) : \
7476 spawne(P_NOWAIT, (cmd), (envp)))
7477# else
7478# define DO_SPAWN(cmd, args, envp) ((args) ? \
7479 spawnv(P_NOWAIT, (cmd), (args)) : \
7480 spawn(P_NOWAIT, (cmd)))
7481# endif
7482# if !defined(HAVE_WORKING_FORK)
7483 char **args = NULL;
7484# if defined(HAVE_SPAWNVE)
7485 char **envp = NULL;
7486# endif
7487# endif
7488#endif
7489#if !defined(HAVE_WORKING_FORK)
7490 struct rb_execarg sarg, *sargp = &sarg;
7491#endif
7492 FILE *fp = 0;
7493 int fd = -1;
7494 int write_fd = -1;
7495#if !defined(HAVE_WORKING_FORK)
7496 const char *cmd = 0;
7497
7498 if (prog)
7499 cmd = StringValueCStr(prog);
7500#endif
7501
7502#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7503 arg.execarg_obj = execarg_obj;
7504 arg.eargp = eargp;
7505 arg.modef = fmode;
7506 arg.pair[0] = arg.pair[1] = -1;
7507 arg.write_pair[0] = arg.write_pair[1] = -1;
7508# if !defined(HAVE_WORKING_FORK)
7509 if (eargp && !eargp->use_shell) {
7510 args = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
7511 }
7512# endif
7513 switch (fmode & (FMODE_READABLE|FMODE_WRITABLE)) {
7515 if (rb_pipe(arg.write_pair) < 0)
7516 rb_sys_fail_str(prog);
7517 if (rb_pipe(arg.pair) < 0) {
7518 e = errno;
7519 close(arg.write_pair[0]);
7520 close(arg.write_pair[1]);
7521 rb_syserr_fail_str(e, prog);
7522 }
7523 if (eargp) {
7524 rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.write_pair[0]));
7525 rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
7526 }
7527 break;
7528 case FMODE_READABLE:
7529 if (rb_pipe(arg.pair) < 0)
7530 rb_sys_fail_str(prog);
7531 if (eargp)
7532 rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
7533 break;
7534 case FMODE_WRITABLE:
7535 if (rb_pipe(arg.pair) < 0)
7536 rb_sys_fail_str(prog);
7537 if (eargp)
7538 rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.pair[0]));
7539 break;
7540 default:
7541 rb_sys_fail_str(prog);
7542 }
7543 if (!NIL_P(execarg_obj)) {
7544 rb_protect(rb_execarg_fixup_v, execarg_obj, &state);
7545 if (state) {
7546 if (0 <= arg.write_pair[0]) close(arg.write_pair[0]);
7547 if (0 <= arg.write_pair[1]) close(arg.write_pair[1]);
7548 if (0 <= arg.pair[0]) close(arg.pair[0]);
7549 if (0 <= arg.pair[1]) close(arg.pair[1]);
7550 rb_execarg_parent_end(execarg_obj);
7551 rb_jump_tag(state);
7552 }
7553
7554# if defined(HAVE_WORKING_FORK)
7555 pid = rb_fork_async_signal_safe(&status, popen_exec, &arg, arg.eargp->redirect_fds, errmsg, sizeof(errmsg));
7556# else
7557 rb_execarg_run_options(eargp, sargp, NULL, 0);
7558# if defined(HAVE_SPAWNVE)
7559 if (eargp->envp_str) envp = (char **)RSTRING_PTR(eargp->envp_str);
7560# endif
7561 while ((pid = DO_SPAWN(cmd, args, envp)) < 0) {
7562 /* exec failed */
7563 switch (e = errno) {
7564 case EAGAIN:
7565# if EWOULDBLOCK != EAGAIN
7566 case EWOULDBLOCK:
7567# endif
7568 rb_thread_sleep(1);
7569 continue;
7570 }
7571 break;
7572 }
7573 if (eargp)
7574 rb_execarg_run_options(sargp, NULL, NULL, 0);
7575# endif
7576 rb_execarg_parent_end(execarg_obj);
7577 }
7578 else {
7579# if defined(HAVE_WORKING_FORK)
7580 pid = rb_call_proc__fork();
7581 if (pid == 0) { /* child */
7582 popen_redirect(&arg);
7583 rb_io_synchronized(RFILE(orig_stdout)->fptr);
7584 rb_io_synchronized(RFILE(orig_stderr)->fptr);
7585 return Qnil;
7586 }
7587# else
7589# endif
7590 }
7591
7592 /* parent */
7593 if (pid < 0) {
7594# if defined(HAVE_WORKING_FORK)
7595 e = errno;
7596# endif
7597 close(arg.pair[0]);
7598 close(arg.pair[1]);
7600 close(arg.write_pair[0]);
7601 close(arg.write_pair[1]);
7602 }
7603# if defined(HAVE_WORKING_FORK)
7604 if (errmsg[0])
7605 rb_syserr_fail(e, errmsg);
7606# endif
7607 rb_syserr_fail_str(e, prog);
7608 }
7609 if ((fmode & FMODE_READABLE) && (fmode & FMODE_WRITABLE)) {
7610 close(arg.pair[1]);
7611 fd = arg.pair[0];
7612 close(arg.write_pair[0]);
7613 write_fd = arg.write_pair[1];
7614 }
7615 else if (fmode & FMODE_READABLE) {
7616 close(arg.pair[1]);
7617 fd = arg.pair[0];
7618 }
7619 else {
7620 close(arg.pair[0]);
7621 fd = arg.pair[1];
7622 }
7623#else
7624 cmd = rb_execarg_commandline(eargp, &prog);
7625 if (!NIL_P(execarg_obj)) {
7626 rb_execarg_parent_start(execarg_obj);
7627 rb_execarg_run_options(eargp, sargp, NULL, 0);
7628 }
7629 fp = popen(cmd, modestr);
7630 e = errno;
7631 if (eargp) {
7632 rb_execarg_parent_end(execarg_obj);
7633 rb_execarg_run_options(sargp, NULL, NULL, 0);
7634 }
7635 if (!fp) rb_syserr_fail_path(e, prog);
7636 fd = fileno(fp);
7637#endif
7638
7639 port = io_alloc(rb_cIO);
7640 MakeOpenFile(port, fptr);
7641 fptr->fd = fd;
7642 fptr->stdio_file = fp;
7643 fptr->mode = fmode | FMODE_SYNC|FMODE_DUPLEX;
7644 if (convconfig) {
7645 fptr->encs = *convconfig;
7646#if RUBY_CRLF_ENVIRONMENT
7649 }
7650#endif
7651 }
7652 else {
7653 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
7655 }
7656#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7657 if (NEED_NEWLINE_DECORATOR_ON_WRITE(fptr)) {
7658 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
7659 }
7660#endif
7661 }
7662 fptr->pid = pid;
7663
7664 if (0 <= write_fd) {
7665 write_port = io_alloc(rb_cIO);
7666 MakeOpenFile(write_port, write_fptr);
7667 write_fptr->fd = write_fd;
7668 write_fptr->mode = (fmode & ~FMODE_READABLE)| FMODE_SYNC|FMODE_DUPLEX;
7669 fptr->mode &= ~FMODE_WRITABLE;
7670 fptr->tied_io_for_writing = write_port;
7671 rb_ivar_set(port, rb_intern("@tied_io_for_writing"), write_port);
7672 }
7673
7674#if defined (__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7675 fptr->finalize = pipe_finalize;
7676 pipe_add_fptr(fptr);
7677#endif
7678 return port;
7679}
7680#else
7681static VALUE
7682pipe_open(VALUE execarg_obj, const char *modestr, int fmode,
7683 const convconfig_t *convconfig)
7684{
7685 rb_raise(rb_eNotImpError, "popen() is not available");
7686}
7687#endif
7688
7689static int
7690is_popen_fork(VALUE prog)
7691{
7692 if (RSTRING_LEN(prog) == 1 && RSTRING_PTR(prog)[0] == '-') {
7693#if !defined(HAVE_WORKING_FORK)
7695 "fork() function is unimplemented on this machine");
7696#else
7697 return TRUE;
7698#endif
7699 }
7700 return FALSE;
7701}
7702
7703static VALUE
7704pipe_open_s(VALUE prog, const char *modestr, int fmode,
7705 const convconfig_t *convconfig)
7706{
7707 int argc = 1;
7708 VALUE *argv = &prog;
7709 VALUE execarg_obj = Qnil;
7710
7711 if (!is_popen_fork(prog))
7712 execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
7713 return pipe_open(execarg_obj, modestr, fmode, convconfig);
7714}
7715
7716static VALUE
7717pipe_close(VALUE io)
7718{
7719 rb_io_t *fptr = io_close_fptr(io);
7720 if (fptr) {
7721 fptr_waitpid(fptr, rb_thread_to_be_killed(rb_thread_current()));
7722 }
7723 return Qnil;
7724}
7725
7726static VALUE popen_finish(VALUE port, VALUE klass);
7727
7728/*
7729 * call-seq:
7730 * IO.popen(env = {}, cmd, mode = 'r', **opts) -> io
7731 * IO.popen(env = {}, cmd, mode = 'r', **opts) {|io| ... } -> object
7732 *
7733 * Executes the given command +cmd+ as a subprocess
7734 * whose $stdin and $stdout are connected to a new stream +io+.
7735 *
7736 * This method has potential security vulnerabilities if called with untrusted input;
7737 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
7738 *
7739 * If no block is given, returns the new stream,
7740 * which depending on given +mode+ may be open for reading, writing, or both.
7741 * The stream should be explicitly closed (eventually) to avoid resource leaks.
7742 *
7743 * If a block is given, the stream is passed to the block
7744 * (again, open for reading, writing, or both);
7745 * when the block exits, the stream is closed,
7746 * and the block's value is assigned to global variable <tt>$?</tt> and returned.
7747 *
7748 * Optional argument +mode+ may be any valid \IO mode.
7749 * See {Access Modes}[rdoc-ref:File@Access+Modes].
7750 *
7751 * Required argument +cmd+ determines which of the following occurs:
7752 *
7753 * - The process forks.
7754 * - A specified program runs in a shell.
7755 * - A specified program runs with specified arguments.
7756 * - A specified program runs with specified arguments and a specified +argv0+.
7757 *
7758 * Each of these is detailed below.
7759 *
7760 * The optional hash argument +env+ specifies name/value pairs that are to be added
7761 * to the environment variables for the subprocess:
7762 *
7763 * IO.popen({'FOO' => 'bar'}, 'ruby', 'r+') do |pipe|
7764 * pipe.puts 'puts ENV["FOO"]'
7765 * pipe.close_write
7766 * pipe.gets
7767 * end => "bar\n"
7768 *
7769 * Optional keyword arguments +opts+ specify:
7770 *
7771 * - {Open options}[rdoc-ref:IO@Open+Options].
7772 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
7773 * - Options for Kernel#spawn.
7774 *
7775 * <b>Forked \Process</b>
7776 *
7777 * When argument +cmd+ is the 1-character string <tt>'-'</tt>, causes the process to fork:
7778 * IO.popen('-') do |pipe|
7779 * if pipe
7780 * $stderr.puts "In parent, child pid is #{pipe.pid}\n"
7781 * else
7782 * $stderr.puts "In child, pid is #{$$}\n"
7783 * end
7784 * end
7785 *
7786 * Output:
7787 *
7788 * In parent, child pid is 26253
7789 * In child, pid is 26253
7790 *
7791 * Note that this is not supported on all platforms.
7792 *
7793 * <b>Shell Subprocess</b>
7794 *
7795 * When argument +cmd+ is a single string (but not <tt>'-'</tt>),
7796 * the program named +cmd+ is run as a shell command:
7797 *
7798 * IO.popen('uname') do |pipe|
7799 * pipe.readlines
7800 * end
7801 *
7802 * Output:
7803 *
7804 * ["Linux\n"]
7805 *
7806 * Another example:
7807 *
7808 * IO.popen('/bin/sh', 'r+') do |pipe|
7809 * pipe.puts('ls')
7810 * pipe.close_write
7811 * $stderr.puts pipe.readlines.size
7812 * end
7813 *
7814 * Output:
7815 *
7816 * 213
7817 *
7818 * <b>Program Subprocess</b>
7819 *
7820 * When argument +cmd+ is an array of strings,
7821 * the program named <tt>cmd[0]</tt> is run with all elements of +cmd+ as its arguments:
7822 *
7823 * IO.popen(['du', '..', '.']) do |pipe|
7824 * $stderr.puts pipe.readlines.size
7825 * end
7826 *
7827 * Output:
7828 *
7829 * 1111
7830 *
7831 * <b>Program Subprocess with <tt>argv0</tt></b>
7832 *
7833 * When argument +cmd+ is an array whose first element is a 2-element string array
7834 * and whose remaining elements (if any) are strings:
7835 *
7836 * - <tt>cmd[0][0]</tt> (the first string in the nested array) is the name of a program that is run.
7837 * - <tt>cmd[0][1]</tt> (the second string in the nested array) is set as the program's <tt>argv[0]</tt>.
7838 * - <tt>cmd[1..-1]</tt> (the strings in the outer array) are the program's arguments.
7839 *
7840 * Example (sets <tt>$0</tt> to 'foo'):
7841 *
7842 * IO.popen([['/bin/sh', 'foo'], '-c', 'echo $0']).read # => "foo\n"
7843 *
7844 * <b>Some Special Examples</b>
7845 *
7846 * # Set IO encoding.
7847 * IO.popen("nkf -e filename", :external_encoding=>"EUC-JP") {|nkf_io|
7848 * euc_jp_string = nkf_io.read
7849 * }
7850 *
7851 * # Merge standard output and standard error using Kernel#spawn option. See Kernel#spawn.
7852 * IO.popen(["ls", "/", :err=>[:child, :out]]) do |io|
7853 * ls_result_with_error = io.read
7854 * end
7855 *
7856 * # Use mixture of spawn options and IO options.
7857 * IO.popen(["ls", "/"], :err=>[:child, :out]) do |io|
7858 * ls_result_with_error = io.read
7859 * end
7860 *
7861 * f = IO.popen("uname")
7862 * p f.readlines
7863 * f.close
7864 * puts "Parent is #{Process.pid}"
7865 * IO.popen("date") {|f| puts f.gets }
7866 * IO.popen("-") {|f| $stderr.puts "#{Process.pid} is here, f is #{f.inspect}"}
7867 * p $?
7868 * IO.popen(%w"sed -e s|^|<foo>| -e s&$&;zot;&", "r+") {|f|
7869 * f.puts "bar"; f.close_write; puts f.gets
7870 * }
7871 *
7872 * Output (from last section):
7873 *
7874 * ["Linux\n"]
7875 * Parent is 21346
7876 * Thu Jan 15 22:41:19 JST 2009
7877 * 21346 is here, f is #<IO:fd 3>
7878 * 21352 is here, f is nil
7879 * #<Process::Status: pid 21352 exit 0>
7880 * <foo>bar;zot;
7881 *
7882 * Raises exceptions that IO.pipe and Kernel.spawn raise.
7883 *
7884 */
7885
7886static VALUE
7887rb_io_s_popen(int argc, VALUE *argv, VALUE klass)
7888{
7889 VALUE pname, pmode = Qnil, opt = Qnil, env = Qnil;
7890
7891 if (argc > 1 && !NIL_P(opt = rb_check_hash_type(argv[argc-1]))) --argc;
7892 if (argc > 1 && !NIL_P(env = rb_check_hash_type(argv[0]))) --argc, ++argv;
7893 switch (argc) {
7894 case 2:
7895 pmode = argv[1];
7896 case 1:
7897 pname = argv[0];
7898 break;
7899 default:
7900 {
7901 int ex = !NIL_P(opt);
7902 rb_error_arity(argc + ex, 1 + ex, 2 + ex);
7903 }
7904 }
7905 return popen_finish(rb_io_popen(pname, pmode, env, opt), klass);
7906}
7907
7908VALUE
7909rb_io_popen(VALUE pname, VALUE pmode, VALUE env, VALUE opt)
7910{
7911 const char *modestr;
7912 VALUE tmp, execarg_obj = Qnil;
7913 int oflags, fmode;
7914 convconfig_t convconfig;
7915
7916 tmp = rb_check_array_type(pname);
7917 if (!NIL_P(tmp)) {
7918 long len = RARRAY_LEN(tmp);
7919#if SIZEOF_LONG > SIZEOF_INT
7920 if (len > INT_MAX) {
7921 rb_raise(rb_eArgError, "too many arguments");
7922 }
7923#endif
7924 execarg_obj = rb_execarg_new((int)len, RARRAY_CONST_PTR(tmp), FALSE, FALSE);
7925 RB_GC_GUARD(tmp);
7926 }
7927 else {
7928 SafeStringValue(pname);
7929 execarg_obj = Qnil;
7930 if (!is_popen_fork(pname))
7931 execarg_obj = rb_execarg_new(1, &pname, TRUE, FALSE);
7932 }
7933 if (!NIL_P(execarg_obj)) {
7934 if (!NIL_P(opt))
7935 opt = rb_execarg_extract_options(execarg_obj, opt);
7936 if (!NIL_P(env))
7937 rb_execarg_setenv(execarg_obj, env);
7938 }
7939 rb_io_extract_modeenc(&pmode, 0, opt, &oflags, &fmode, &convconfig);
7940 modestr = rb_io_oflags_modestr(oflags);
7941
7942 return pipe_open(execarg_obj, modestr, fmode, &convconfig);
7943}
7944
7945static VALUE
7946popen_finish(VALUE port, VALUE klass)
7947{
7948 if (NIL_P(port)) {
7949 /* child */
7950 if (rb_block_given_p()) {
7951 rb_yield(Qnil);
7954 _exit(0);
7955 }
7956 return Qnil;
7957 }
7958 RBASIC_SET_CLASS(port, klass);
7959 if (rb_block_given_p()) {
7960 return rb_ensure(rb_yield, port, pipe_close, port);
7961 }
7962 return port;
7963}
7964
7965static void
7966rb_scan_open_args(int argc, const VALUE *argv,
7967 VALUE *fname_p, int *oflags_p, int *fmode_p,
7968 convconfig_t *convconfig_p, mode_t *perm_p)
7969{
7970 VALUE opt, fname, vmode, vperm;
7971 int oflags, fmode;
7972 mode_t perm;
7973
7974 argc = rb_scan_args(argc, argv, "12:", &fname, &vmode, &vperm, &opt);
7975 FilePathValue(fname);
7976
7977 rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, convconfig_p);
7978
7979 perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
7980
7981 *fname_p = fname;
7982 *oflags_p = oflags;
7983 *fmode_p = fmode;
7984 *perm_p = perm;
7985}
7986
7987static VALUE
7988rb_open_file(int argc, const VALUE *argv, VALUE io)
7989{
7990 VALUE fname;
7991 int oflags, fmode;
7992 convconfig_t convconfig;
7993 mode_t perm;
7994
7995 rb_scan_open_args(argc, argv, &fname, &oflags, &fmode, &convconfig, &perm);
7996 rb_file_open_generic(io, fname, oflags, fmode, &convconfig, perm);
7997
7998 return io;
7999}
8000
8001/*
8002 * Document-method: File::open
8003 *
8004 * call-seq:
8005 * File.open(path, mode = 'r', perm = 0666, **opts) -> file
8006 * File.open(path, mode = 'r', perm = 0666, **opts) {|f| ... } -> object
8007 *
8008 * Creates a new \File object, via File.new with the given arguments.
8009 *
8010 * With no block given, returns the \File object.
8011 *
8012 * With a block given, calls the block with the \File object
8013 * and returns the block's value.
8014 *
8015 */
8016
8017/*
8018 * Document-method: IO::open
8019 *
8020 * call-seq:
8021 * IO.open(fd, mode = 'r', **opts) -> io
8022 * IO.open(fd, mode = 'r', **opts) {|io| ... } -> object
8023 *
8024 * Creates a new \IO object, via IO.new with the given arguments.
8025 *
8026 * With no block given, returns the \IO object.
8027 *
8028 * With a block given, calls the block with the \IO object
8029 * and returns the block's value.
8030 *
8031 */
8032
8033static VALUE
8034rb_io_s_open(int argc, VALUE *argv, VALUE klass)
8035{
8037
8038 if (rb_block_given_p()) {
8039 return rb_ensure(rb_yield, io, io_close, io);
8040 }
8041
8042 return io;
8043}
8044
8045/*
8046 * call-seq:
8047 * IO.sysopen(path, mode = 'r', perm = 0666) -> integer
8048 *
8049 * Opens the file at the given path with the given mode and permissions;
8050 * returns the integer file descriptor.
8051 *
8052 * If the file is to be readable, it must exist;
8053 * if the file is to be writable and does not exist,
8054 * it is created with the given permissions:
8055 *
8056 * File.write('t.tmp', '') # => 0
8057 * IO.sysopen('t.tmp') # => 8
8058 * IO.sysopen('t.tmp', 'w') # => 9
8059 *
8060 *
8061 */
8062
8063static VALUE
8064rb_io_s_sysopen(int argc, VALUE *argv, VALUE _)
8065{
8066 VALUE fname, vmode, vperm;
8067 VALUE intmode;
8068 int oflags, fd;
8069 mode_t perm;
8070
8071 rb_scan_args(argc, argv, "12", &fname, &vmode, &vperm);
8072 FilePathValue(fname);
8073
8074 if (NIL_P(vmode))
8075 oflags = O_RDONLY;
8076 else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int")))
8077 oflags = NUM2INT(intmode);
8078 else {
8079 SafeStringValue(vmode);
8080 oflags = rb_io_modestr_oflags(StringValueCStr(vmode));
8081 }
8082 if (NIL_P(vperm)) perm = 0666;
8083 else perm = NUM2MODET(vperm);
8084
8085 RB_GC_GUARD(fname) = rb_str_new4(fname);
8086 fd = rb_sysopen(fname, oflags, perm);
8087 return INT2NUM(fd);
8088}
8089
8090static VALUE
8091check_pipe_command(VALUE filename_or_command)
8092{
8093 char *s = RSTRING_PTR(filename_or_command);
8094 long l = RSTRING_LEN(filename_or_command);
8095 char *e = s + l;
8096 int chlen;
8097
8098 if (rb_enc_ascget(s, e, &chlen, rb_enc_get(filename_or_command)) == '|') {
8099 VALUE cmd = rb_str_new(s+chlen, l-chlen);
8100 return cmd;
8101 }
8102 return Qnil;
8103}
8104
8105/*
8106 * call-seq:
8107 * open(path, mode = 'r', perm = 0666, **opts) -> io or nil
8108 * open(path, mode = 'r', perm = 0666, **opts) {|io| ... } -> obj
8109 *
8110 * Creates an IO object connected to the given stream, file, or subprocess.
8111 *
8112 * Required string argument +path+ determines which of the following occurs:
8113 *
8114 * - The file at the specified +path+ is opened.
8115 * - The process forks.
8116 * - A subprocess is created.
8117 *
8118 * Each of these is detailed below.
8119 *
8120 * <b>File Opened</b>
8121
8122 * If +path+ does _not_ start with a pipe character (<tt>'|'</tt>),
8123 * a file stream is opened with <tt>File.open(path, mode, perm, **opts)</tt>.
8124 *
8125 * With no block given, file stream is returned:
8126 *
8127 * open('t.txt') # => #<File:t.txt>
8128 *
8129 * With a block given, calls the block with the open file stream,
8130 * then closes the stream:
8131 *
8132 * open('t.txt') {|f| p f } # => #<File:t.txt (closed)>
8133 *
8134 * Output:
8135 *
8136 * #<File:t.txt>
8137 *
8138 * See File.open for details.
8139 *
8140 * <b>Process Forked</b>
8141 *
8142 * If +path+ is the 2-character string <tt>'|-'</tt>, the process forks
8143 * and the child process is connected to the parent.
8144 *
8145 * With no block given:
8146 *
8147 * io = open('|-')
8148 * if io
8149 * $stderr.puts "In parent, child pid is #{io.pid}."
8150 * else
8151 * $stderr.puts "In child, pid is #{$$}."
8152 * end
8153 *
8154 * Output:
8155 *
8156 * In parent, child pid is 27903.
8157 * In child, pid is 27903.
8158 *
8159 * With a block given:
8160 *
8161 * open('|-') do |io|
8162 * if io
8163 * $stderr.puts "In parent, child pid is #{io.pid}."
8164 * else
8165 * $stderr.puts "In child, pid is #{$$}."
8166 * end
8167 * end
8168 *
8169 * Output:
8170 *
8171 * In parent, child pid is 28427.
8172 * In child, pid is 28427.
8173 *
8174 * <b>Subprocess Created</b>
8175 *
8176 * If +path+ is <tt>'|command'</tt> (<tt>'command' != '-'</tt>),
8177 * a new subprocess runs the command; its open stream is returned.
8178 * Note that the command may be processed by shell if it contains
8179 * shell metacharacters.
8180 *
8181 * With no block given:
8182 *
8183 * io = open('|echo "Hi!"') # => #<IO:fd 12>
8184 * print io.gets
8185 * io.close
8186 *
8187 * Output:
8188 *
8189 * "Hi!"
8190 *
8191 * With a block given, calls the block with the stream, then closes the stream:
8192 *
8193 * open('|echo "Hi!"') do |io|
8194 * print io.gets
8195 * end
8196 *
8197 * Output:
8198 *
8199 * "Hi!"
8200 *
8201 */
8202
8203static VALUE
8204rb_f_open(int argc, VALUE *argv, VALUE _)
8205{
8206 ID to_open = 0;
8207 int redirect = FALSE;
8208
8209 if (argc >= 1) {
8210 CONST_ID(to_open, "to_open");
8211 if (rb_respond_to(argv[0], to_open)) {
8212 redirect = TRUE;
8213 }
8214 else {
8215 VALUE tmp = argv[0];
8216 FilePathValue(tmp);
8217 if (NIL_P(tmp)) {
8218 redirect = TRUE;
8219 }
8220 else {
8221 VALUE cmd = check_pipe_command(tmp);
8222 if (!NIL_P(cmd)) {
8223 argv[0] = cmd;
8224 return rb_io_s_popen(argc, argv, rb_cIO);
8225 }
8226 }
8227 }
8228 }
8229 if (redirect) {
8230 VALUE io = rb_funcallv_kw(argv[0], to_open, argc-1, argv+1, RB_PASS_CALLED_KEYWORDS);
8231
8232 if (rb_block_given_p()) {
8233 return rb_ensure(rb_yield, io, io_close, io);
8234 }
8235 return io;
8236 }
8237 return rb_io_s_open(argc, argv, rb_cFile);
8238}
8239
8240static VALUE rb_io_open_generic(VALUE, VALUE, int, int, const convconfig_t *, mode_t);
8241
8242static VALUE
8243rb_io_open(VALUE io, VALUE filename, VALUE vmode, VALUE vperm, VALUE opt)
8244{
8245 int oflags, fmode;
8246 convconfig_t convconfig;
8247 mode_t perm;
8248
8249 rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, &convconfig);
8250 perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
8251 return rb_io_open_generic(io, filename, oflags, fmode, &convconfig, perm);
8252}
8253
8254static VALUE
8255rb_io_open_generic(VALUE klass, VALUE filename, int oflags, int fmode,
8256 const convconfig_t *convconfig, mode_t perm)
8257{
8258 VALUE cmd;
8259 if (klass == rb_cIO && !NIL_P(cmd = check_pipe_command(filename))) {
8260 return pipe_open_s(cmd, rb_io_oflags_modestr(oflags), fmode, convconfig);
8261 }
8262 else {
8263 return rb_file_open_generic(io_alloc(klass), filename,
8264 oflags, fmode, convconfig, perm);
8265 }
8266}
8267
8268static VALUE
8269io_reopen(VALUE io, VALUE nfile)
8270{
8271 rb_io_t *fptr, *orig;
8272 int fd, fd2;
8273 rb_off_t pos = 0;
8274
8275 nfile = rb_io_get_io(nfile);
8276 GetOpenFile(io, fptr);
8277 GetOpenFile(nfile, orig);
8278
8279 if (fptr == orig) return io;
8280 if (IS_PREP_STDIO(fptr)) {
8281 if ((fptr->stdio_file == stdin && !(orig->mode & FMODE_READABLE)) ||
8282 (fptr->stdio_file == stdout && !(orig->mode & FMODE_WRITABLE)) ||
8283 (fptr->stdio_file == stderr && !(orig->mode & FMODE_WRITABLE))) {
8285 "%s can't change access mode from \"%s\" to \"%s\"",
8286 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
8287 rb_io_fmode_modestr(orig->mode));
8288 }
8289 }
8290 if (fptr->mode & FMODE_WRITABLE) {
8291 if (io_fflush(fptr) < 0)
8292 rb_sys_fail_on_write(fptr);
8293 }
8294 else {
8295 flush_before_seek(fptr);
8296 }
8297 if (orig->mode & FMODE_READABLE) {
8298 pos = io_tell(orig);
8299 }
8300 if (orig->mode & FMODE_WRITABLE) {
8301 if (io_fflush(orig) < 0)
8302 rb_sys_fail_on_write(fptr);
8303 }
8304
8305 /* copy rb_io_t structure */
8306 fptr->mode = orig->mode | (fptr->mode & FMODE_PREP);
8307 fptr->pid = orig->pid;
8308 fptr->lineno = orig->lineno;
8309 if (RTEST(orig->pathv)) fptr->pathv = orig->pathv;
8310 else if (!IS_PREP_STDIO(fptr)) fptr->pathv = Qnil;
8311 fptr_copy_finalizer(fptr, orig);
8312
8313 fd = fptr->fd;
8314 fd2 = orig->fd;
8315 if (fd != fd2) {
8316 if (IS_PREP_STDIO(fptr) || fd <= 2 || !fptr->stdio_file) {
8317 /* need to keep FILE objects of stdin, stdout and stderr */
8318 if (rb_cloexec_dup2(fd2, fd) < 0)
8319 rb_sys_fail_path(orig->pathv);
8320 rb_update_max_fd(fd);
8321 }
8322 else {
8323 fclose(fptr->stdio_file);
8324 fptr->stdio_file = 0;
8325 fptr->fd = -1;
8326 if (rb_cloexec_dup2(fd2, fd) < 0)
8327 rb_sys_fail_path(orig->pathv);
8328 rb_update_max_fd(fd);
8329 fptr->fd = fd;
8330 }
8332 if ((orig->mode & FMODE_READABLE) && pos >= 0) {
8333 if (io_seek(fptr, pos, SEEK_SET) < 0 && errno) {
8334 rb_sys_fail_path(fptr->pathv);
8335 }
8336 if (io_seek(orig, pos, SEEK_SET) < 0 && errno) {
8337 rb_sys_fail_path(orig->pathv);
8338 }
8339 }
8340 }
8341
8342 if (fptr->mode & FMODE_BINMODE) {
8343 rb_io_binmode(io);
8344 }
8345
8346 RBASIC_SET_CLASS(io, rb_obj_class(nfile));
8347 return io;
8348}
8349
8350#ifdef _WIN32
8351int rb_freopen(VALUE fname, const char *mode, FILE *fp);
8352#else
8353static int
8354rb_freopen(VALUE fname, const char *mode, FILE *fp)
8355{
8356 if (!freopen(RSTRING_PTR(fname), mode, fp)) {
8357 RB_GC_GUARD(fname);
8358 return errno;
8359 }
8360 return 0;
8361}
8362#endif
8363
8364/*
8365 * call-seq:
8366 * reopen(other_io) -> self
8367 * reopen(path, mode = 'r', **opts) -> self
8368 *
8369 * Reassociates the stream with another stream,
8370 * which may be of a different class.
8371 * This method may be used to redirect an existing stream
8372 * to a new destination.
8373 *
8374 * With argument +other_io+ given, reassociates with that stream:
8375 *
8376 * # Redirect $stdin from a file.
8377 * f = File.open('t.txt')
8378 * $stdin.reopen(f)
8379 * f.close
8380 *
8381 * # Redirect $stdout to a file.
8382 * f = File.open('t.tmp', 'w')
8383 * $stdout.reopen(f)
8384 * f.close
8385 *
8386 * With argument +path+ given, reassociates with a new stream to that file path:
8387 *
8388 * $stdin.reopen('t.txt')
8389 * $stdout.reopen('t.tmp', 'w')
8390 *
8391 * Optional keyword arguments +opts+ specify:
8392 *
8393 * - {Open Options}[rdoc-ref:IO@Open+Options].
8394 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
8395 *
8396 */
8397
8398static VALUE
8399rb_io_reopen(int argc, VALUE *argv, VALUE file)
8400{
8401 VALUE fname, nmode, opt;
8402 int oflags;
8403 rb_io_t *fptr;
8404
8405 if (rb_scan_args(argc, argv, "11:", &fname, &nmode, &opt) == 1) {
8406 VALUE tmp = rb_io_check_io(fname);
8407 if (!NIL_P(tmp)) {
8408 return io_reopen(file, tmp);
8409 }
8410 }
8411
8412 FilePathValue(fname);
8413 rb_io_taint_check(file);
8414 fptr = RFILE(file)->fptr;
8415 if (!fptr) {
8416 fptr = RFILE(file)->fptr = ZALLOC(rb_io_t);
8417 }
8418
8419 if (!NIL_P(nmode) || !NIL_P(opt)) {
8420 int fmode;
8421 convconfig_t convconfig;
8422
8423 rb_io_extract_modeenc(&nmode, 0, opt, &oflags, &fmode, &convconfig);
8424 if (IS_PREP_STDIO(fptr) &&
8425 ((fptr->mode & FMODE_READWRITE) & (fmode & FMODE_READWRITE)) !=
8426 (fptr->mode & FMODE_READWRITE)) {
8428 "%s can't change access mode from \"%s\" to \"%s\"",
8429 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
8430 rb_io_fmode_modestr(fmode));
8431 }
8432 fptr->mode = fmode;
8433 fptr->encs = convconfig;
8434 }
8435 else {
8436 oflags = rb_io_fmode_oflags(fptr->mode);
8437 }
8438
8439 fptr->pathv = fname;
8440 if (fptr->fd < 0) {
8441 fptr->fd = rb_sysopen(fptr->pathv, oflags, 0666);
8442 fptr->stdio_file = 0;
8443 return file;
8444 }
8445
8446 if (fptr->mode & FMODE_WRITABLE) {
8447 if (io_fflush(fptr) < 0)
8448 rb_sys_fail_on_write(fptr);
8449 }
8450 fptr->rbuf.off = fptr->rbuf.len = 0;
8451
8452 if (fptr->stdio_file) {
8453 int e = rb_freopen(rb_str_encode_ospath(fptr->pathv),
8454 rb_io_oflags_modestr(oflags),
8455 fptr->stdio_file);
8456 if (e) rb_syserr_fail_path(e, fptr->pathv);
8457 fptr->fd = fileno(fptr->stdio_file);
8458 rb_fd_fix_cloexec(fptr->fd);
8459#ifdef USE_SETVBUF
8460 if (setvbuf(fptr->stdio_file, NULL, _IOFBF, 0) != 0)
8461 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8462#endif
8463 if (fptr->stdio_file == stderr) {
8464 if (setvbuf(fptr->stdio_file, NULL, _IONBF, BUFSIZ) != 0)
8465 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8466 }
8467 else if (fptr->stdio_file == stdout && isatty(fptr->fd)) {
8468 if (setvbuf(fptr->stdio_file, NULL, _IOLBF, BUFSIZ) != 0)
8469 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8470 }
8471 }
8472 else {
8473 int tmpfd = rb_sysopen(fptr->pathv, oflags, 0666);
8474 int err = 0;
8475 if (rb_cloexec_dup2(tmpfd, fptr->fd) < 0)
8476 err = errno;
8477 (void)close(tmpfd);
8478 if (err) {
8479 rb_syserr_fail_path(err, fptr->pathv);
8480 }
8481 }
8482
8483 return file;
8484}
8485
8486/* :nodoc: */
8487static VALUE
8488rb_io_init_copy(VALUE dest, VALUE io)
8489{
8490 rb_io_t *fptr, *orig;
8491 int fd;
8492 VALUE write_io;
8493 rb_off_t pos;
8494
8495 io = rb_io_get_io(io);
8496 if (!OBJ_INIT_COPY(dest, io)) return dest;
8497 GetOpenFile(io, orig);
8498 MakeOpenFile(dest, fptr);
8499
8500 rb_io_flush(io);
8501
8502 /* copy rb_io_t structure */
8503 fptr->mode = orig->mode & ~FMODE_PREP;
8504 fptr->encs = orig->encs;
8505 fptr->pid = orig->pid;
8506 fptr->lineno = orig->lineno;
8507 fptr->timeout = orig->timeout;
8508 if (!NIL_P(orig->pathv)) fptr->pathv = orig->pathv;
8509 fptr_copy_finalizer(fptr, orig);
8510
8511 fd = ruby_dup(orig->fd);
8512 fptr->fd = fd;
8513 pos = io_tell(orig);
8514 if (0 <= pos)
8515 io_seek(fptr, pos, SEEK_SET);
8516 if (fptr->mode & FMODE_BINMODE) {
8517 rb_io_binmode(dest);
8518 }
8519
8520 write_io = GetWriteIO(io);
8521 if (io != write_io) {
8522 write_io = rb_obj_dup(write_io);
8523 fptr->tied_io_for_writing = write_io;
8524 rb_ivar_set(dest, rb_intern("@tied_io_for_writing"), write_io);
8525 }
8526
8527 return dest;
8528}
8529
8530/*
8531 * call-seq:
8532 * printf(format_string, *objects) -> nil
8533 *
8534 * Formats and writes +objects+ to the stream.
8535 *
8536 * For details on +format_string+, see
8537 * {Format Specifications}[rdoc-ref:format_specifications.rdoc].
8538 *
8539 */
8540
8541VALUE
8542rb_io_printf(int argc, const VALUE *argv, VALUE out)
8543{
8544 rb_io_write(out, rb_f_sprintf(argc, argv));
8545 return Qnil;
8546}
8547
8548/*
8549 * call-seq:
8550 * printf(format_string, *objects) -> nil
8551 * printf(io, format_string, *objects) -> nil
8552 *
8553 * Equivalent to:
8554 *
8555 * io.write(sprintf(format_string, *objects))
8556 *
8557 * For details on +format_string+, see
8558 * {Format Specifications}[rdoc-ref:format_specifications.rdoc].
8559 *
8560 * With the single argument +format_string+, formats +objects+ into the string,
8561 * then writes the formatted string to $stdout:
8562 *
8563 * printf('%4.4d %10s %2.2f', 24, 24, 24.0)
8564 *
8565 * Output (on $stdout):
8566 *
8567 * 0024 24 24.00#
8568 *
8569 * With arguments +io+ and +format_string+, formats +objects+ into the string,
8570 * then writes the formatted string to +io+:
8571 *
8572 * printf($stderr, '%4.4d %10s %2.2f', 24, 24, 24.0)
8573 *
8574 * Output (on $stderr):
8575 *
8576 * 0024 24 24.00# => nil
8577 *
8578 * With no arguments, does nothing.
8579 *
8580 */
8581
8582static VALUE
8583rb_f_printf(int argc, VALUE *argv, VALUE _)
8584{
8585 VALUE out;
8586
8587 if (argc == 0) return Qnil;
8588 if (RB_TYPE_P(argv[0], T_STRING)) {
8589 out = rb_ractor_stdout();
8590 }
8591 else {
8592 out = argv[0];
8593 argv++;
8594 argc--;
8595 }
8596 rb_io_write(out, rb_f_sprintf(argc, argv));
8597
8598 return Qnil;
8599}
8600
8601static void
8602deprecated_str_setter(VALUE val, ID id, VALUE *var)
8603{
8604 rb_str_setter(val, id, &val);
8605 if (!NIL_P(val)) {
8606 rb_warn_deprecated("`%s'", NULL, rb_id2name(id));
8607 }
8608 *var = val;
8609}
8610
8611/*
8612 * call-seq:
8613 * print(*objects) -> nil
8614 *
8615 * Writes the given objects to the stream; returns +nil+.
8616 * Appends the output record separator <tt>$OUTPUT_RECORD_SEPARATOR</tt>
8617 * (<tt>$\</tt>), if it is not +nil+.
8618 * See {Line IO}[rdoc-ref:IO@Line+IO].
8619 *
8620 * With argument +objects+ given, for each object:
8621 *
8622 * - Converts via its method +to_s+ if not a string.
8623 * - Writes to the stream.
8624 * - If not the last object, writes the output field separator
8625 * <tt>$OUTPUT_FIELD_SEPARATOR</tt> (<tt>$,</tt>) if it is not +nil+.
8626 *
8627 * With default separators:
8628 *
8629 * f = File.open('t.tmp', 'w+')
8630 * objects = [0, 0.0, Rational(0, 1), Complex(0, 0), :zero, 'zero']
8631 * p $OUTPUT_RECORD_SEPARATOR
8632 * p $OUTPUT_FIELD_SEPARATOR
8633 * f.print(*objects)
8634 * f.rewind
8635 * p f.read
8636 * f.close
8637 *
8638 * Output:
8639 *
8640 * nil
8641 * nil
8642 * "00.00/10+0izerozero"
8643 *
8644 * With specified separators:
8645 *
8646 * $\ = "\n"
8647 * $, = ','
8648 * f.rewind
8649 * f.print(*objects)
8650 * f.rewind
8651 * p f.read
8652 *
8653 * Output:
8654 *
8655 * "0,0.0,0/1,0+0i,zero,zero\n"
8656 *
8657 * With no argument given, writes the content of <tt>$_</tt>
8658 * (which is usually the most recent user input):
8659 *
8660 * f = File.open('t.tmp', 'w+')
8661 * gets # Sets $_ to the most recent user input.
8662 * f.print
8663 * f.close
8664 *
8665 */
8666
8667VALUE
8668rb_io_print(int argc, const VALUE *argv, VALUE out)
8669{
8670 int i;
8671 VALUE line;
8672
8673 /* if no argument given, print `$_' */
8674 if (argc == 0) {
8675 argc = 1;
8676 line = rb_lastline_get();
8677 argv = &line;
8678 }
8679 if (argc > 1 && !NIL_P(rb_output_fs)) {
8680 rb_category_warn(RB_WARN_CATEGORY_DEPRECATED, "$, is set to non-nil value");
8681 }
8682 for (i=0; i<argc; i++) {
8683 if (!NIL_P(rb_output_fs) && i>0) {
8684 rb_io_write(out, rb_output_fs);
8685 }
8686 rb_io_write(out, argv[i]);
8687 }
8688 if (argc > 0 && !NIL_P(rb_output_rs)) {
8690 }
8691
8692 return Qnil;
8693}
8694
8695/*
8696 * call-seq:
8697 * print(*objects) -> nil
8698 *
8699 * Equivalent to <tt>$stdout.print(*objects)</tt>,
8700 * this method is the straightforward way to write to <tt>$stdout</tt>.
8701 *
8702 * Writes the given objects to <tt>$stdout</tt>; returns +nil+.
8703 * Appends the output record separator <tt>$OUTPUT_RECORD_SEPARATOR</tt>
8704 * <tt>$\</tt>), if it is not +nil+.
8705 *
8706 * With argument +objects+ given, for each object:
8707 *
8708 * - Converts via its method +to_s+ if not a string.
8709 * - Writes to <tt>stdout</tt>.
8710 * - If not the last object, writes the output field separator
8711 * <tt>$OUTPUT_FIELD_SEPARATOR</tt> (<tt>$,</tt> if it is not +nil+.
8712 *
8713 * With default separators:
8714 *
8715 * objects = [0, 0.0, Rational(0, 1), Complex(0, 0), :zero, 'zero']
8716 * $OUTPUT_RECORD_SEPARATOR
8717 * $OUTPUT_FIELD_SEPARATOR
8718 * print(*objects)
8719 *
8720 * Output:
8721 *
8722 * nil
8723 * nil
8724 * 00.00/10+0izerozero
8725 *
8726 * With specified separators:
8727 *
8728 * $OUTPUT_RECORD_SEPARATOR = "\n"
8729 * $OUTPUT_FIELD_SEPARATOR = ','
8730 * print(*objects)
8731 *
8732 * Output:
8733 *
8734 * 0,0.0,0/1,0+0i,zero,zero
8735 *
8736 * With no argument given, writes the content of <tt>$_</tt>
8737 * (which is usually the most recent user input):
8738 *
8739 * gets # Sets $_ to the most recent user input.
8740 * print # Prints $_.
8741 *
8742 */
8743
8744static VALUE
8745rb_f_print(int argc, const VALUE *argv, VALUE _)
8746{
8747 rb_io_print(argc, argv, rb_ractor_stdout());
8748 return Qnil;
8749}
8750
8751/*
8752 * call-seq:
8753 * putc(object) -> object
8754 *
8755 * Writes a character to the stream.
8756 * See {Character IO}[rdoc-ref:IO@Character+IO].
8757 *
8758 * If +object+ is numeric, converts to integer if necessary,
8759 * then writes the character whose code is the
8760 * least significant byte;
8761 * if +object+ is a string, writes the first character:
8762 *
8763 * $stdout.putc "A"
8764 * $stdout.putc 65
8765 *
8766 * Output:
8767 *
8768 * AA
8769 *
8770 */
8771
8772static VALUE
8773rb_io_putc(VALUE io, VALUE ch)
8774{
8775 VALUE str;
8776 if (RB_TYPE_P(ch, T_STRING)) {
8777 str = rb_str_substr(ch, 0, 1);
8778 }
8779 else {
8780 char c = NUM2CHR(ch);
8781 str = rb_str_new(&c, 1);
8782 }
8783 rb_io_write(io, str);
8784 return ch;
8785}
8786
8787#define forward(obj, id, argc, argv) \
8788 rb_funcallv_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8789#define forward_public(obj, id, argc, argv) \
8790 rb_funcallv_public_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8791#define forward_current(id, argc, argv) \
8792 forward_public(ARGF.current_file, id, argc, argv)
8793
8794/*
8795 * call-seq:
8796 * putc(int) -> int
8797 *
8798 * Equivalent to:
8799 *
8800 * $stdout.putc(int)
8801 *
8802 * See IO#putc for important information regarding multi-byte characters.
8803 *
8804 */
8805
8806static VALUE
8807rb_f_putc(VALUE recv, VALUE ch)
8808{
8809 VALUE r_stdout = rb_ractor_stdout();
8810 if (recv == r_stdout) {
8811 return rb_io_putc(recv, ch);
8812 }
8813 return forward(r_stdout, rb_intern("putc"), 1, &ch);
8814}
8815
8816
8817int
8818rb_str_end_with_asciichar(VALUE str, int c)
8819{
8820 long len = RSTRING_LEN(str);
8821 const char *ptr = RSTRING_PTR(str);
8822 rb_encoding *enc = rb_enc_from_index(ENCODING_GET(str));
8823 int n;
8824
8825 if (len == 0) return 0;
8826 if ((n = rb_enc_mbminlen(enc)) == 1) {
8827 return ptr[len - 1] == c;
8828 }
8829 return rb_enc_ascget(ptr + ((len - 1) / n) * n, ptr + len, &n, enc) == c;
8830}
8831
8832static VALUE
8833io_puts_ary(VALUE ary, VALUE out, int recur)
8834{
8835 VALUE tmp;
8836 long i;
8837
8838 if (recur) {
8839 tmp = rb_str_new2("[...]");
8840 rb_io_puts(1, &tmp, out);
8841 return Qtrue;
8842 }
8843 ary = rb_check_array_type(ary);
8844 if (NIL_P(ary)) return Qfalse;
8845 for (i=0; i<RARRAY_LEN(ary); i++) {
8846 tmp = RARRAY_AREF(ary, i);
8847 rb_io_puts(1, &tmp, out);
8848 }
8849 return Qtrue;
8850}
8851
8852/*
8853 * call-seq:
8854 * puts(*objects) -> nil
8855 *
8856 * Writes the given +objects+ to the stream, which must be open for writing;
8857 * returns +nil+.\
8858 * Writes a newline after each that does not already end with a newline sequence.
8859 * If called without arguments, writes a newline.
8860 * See {Line IO}[rdoc-ref:IO@Line+IO].
8861 *
8862 * Note that each added newline is the character <tt>"\n"<//tt>,
8863 * not the output record separator (<tt>$\</tt>).
8864 *
8865 * Treatment for each object:
8866 *
8867 * - \String: writes the string.
8868 * - Neither string nor array: writes <tt>object.to_s</tt>.
8869 * - \Array: writes each element of the array; arrays may be nested.
8870 *
8871 * To keep these examples brief, we define this helper method:
8872 *
8873 * def show(*objects)
8874 * # Puts objects to file.
8875 * f = File.new('t.tmp', 'w+')
8876 * f.puts(objects)
8877 * # Return file content.
8878 * f.rewind
8879 * p f.read
8880 * f.close
8881 * end
8882 *
8883 * # Strings without newlines.
8884 * show('foo', 'bar', 'baz') # => "foo\nbar\nbaz\n"
8885 * # Strings, some with newlines.
8886 * show("foo\n", 'bar', "baz\n") # => "foo\nbar\nbaz\n"
8887 *
8888 * # Neither strings nor arrays:
8889 * show(0, 0.0, Rational(0, 1), Complex(9, 0), :zero)
8890 * # => "0\n0.0\n0/1\n9+0i\nzero\n"
8891 *
8892 * # Array of strings.
8893 * show(['foo', "bar\n", 'baz']) # => "foo\nbar\nbaz\n"
8894 * # Nested arrays.
8895 * show([[[0, 1], 2, 3], 4, 5]) # => "0\n1\n2\n3\n4\n5\n"
8896 *
8897 */
8898
8899VALUE
8900rb_io_puts(int argc, const VALUE *argv, VALUE out)
8901{
8902 VALUE line, args[2];
8903
8904 /* if no argument given, print newline. */
8905 if (argc == 0) {
8907 return Qnil;
8908 }
8909 for (int i = 0; i < argc; i++) {
8910 // Convert the argument to a string:
8911 if (RB_TYPE_P(argv[i], T_STRING)) {
8912 line = argv[i];
8913 }
8914 else if (rb_exec_recursive(io_puts_ary, argv[i], out)) {
8915 continue;
8916 }
8917 else {
8918 line = rb_obj_as_string(argv[i]);
8919 }
8920
8921 // Write the line:
8922 int n = 0;
8923 if (RSTRING_LEN(line) == 0) {
8924 args[n++] = rb_default_rs;
8925 }
8926 else {
8927 args[n++] = line;
8928 if (!rb_str_end_with_asciichar(line, '\n')) {
8929 args[n++] = rb_default_rs;
8930 }
8931 }
8932
8933 rb_io_writev(out, n, args);
8934 }
8935
8936 return Qnil;
8937}
8938
8939/*
8940 * call-seq:
8941 * puts(*objects) -> nil
8942 *
8943 * Equivalent to
8944 *
8945 * $stdout.puts(objects)
8946 */
8947
8948static VALUE
8949rb_f_puts(int argc, VALUE *argv, VALUE recv)
8950{
8951 VALUE r_stdout = rb_ractor_stdout();
8952 if (recv == r_stdout) {
8953 return rb_io_puts(argc, argv, recv);
8954 }
8955 return forward(r_stdout, rb_intern("puts"), argc, argv);
8956}
8957
8958static VALUE
8959rb_p_write(VALUE str)
8960{
8961 VALUE args[2];
8962 args[0] = str;
8963 args[1] = rb_default_rs;
8964 VALUE r_stdout = rb_ractor_stdout();
8965 if (RB_TYPE_P(r_stdout, T_FILE) &&
8966 rb_method_basic_definition_p(CLASS_OF(r_stdout), id_write)) {
8967 io_writev(2, args, r_stdout);
8968 }
8969 else {
8970 rb_io_writev(r_stdout, 2, args);
8971 }
8972 return Qnil;
8973}
8974
8975void
8976rb_p(VALUE obj) /* for debug print within C code */
8977{
8978 rb_p_write(rb_obj_as_string(rb_inspect(obj)));
8979}
8980
8981static VALUE
8982rb_p_result(int argc, const VALUE *argv)
8983{
8984 VALUE ret = Qnil;
8985
8986 if (argc == 1) {
8987 ret = argv[0];
8988 }
8989 else if (argc > 1) {
8990 ret = rb_ary_new4(argc, argv);
8991 }
8992 VALUE r_stdout = rb_ractor_stdout();
8993 if (RB_TYPE_P(r_stdout, T_FILE)) {
8994 rb_uninterruptible(rb_io_flush, r_stdout);
8995 }
8996 return ret;
8997}
8998
8999/*
9000 * call-seq:
9001 * p(object) -> obj
9002 * p(*objects) -> array of objects
9003 * p -> nil
9004 *
9005 * For each object +obj+, executes:
9006 *
9007 * $stdout.write(obj.inspect, "\n")
9008 *
9009 * With one object given, returns the object;
9010 * with multiple objects given, returns an array containing the objects;
9011 * with no object given, returns +nil+.
9012 *
9013 * Examples:
9014 *
9015 * r = Range.new(0, 4)
9016 * p r # => 0..4
9017 * p [r, r, r] # => [0..4, 0..4, 0..4]
9018 * p # => nil
9019 *
9020 * Output:
9021 *
9022 * 0..4
9023 * [0..4, 0..4, 0..4]
9024 *
9025 */
9026
9027static VALUE
9028rb_f_p(int argc, VALUE *argv, VALUE self)
9029{
9030 int i;
9031 for (i=0; i<argc; i++) {
9032 VALUE inspected = rb_obj_as_string(rb_inspect(argv[i]));
9033 rb_uninterruptible(rb_p_write, inspected);
9034 }
9035 return rb_p_result(argc, argv);
9036}
9037
9038/*
9039 * call-seq:
9040 * display(port = $>) -> nil
9041 *
9042 * Writes +self+ on the given port:
9043 *
9044 * 1.display
9045 * "cat".display
9046 * [ 4, 5, 6 ].display
9047 * puts
9048 *
9049 * Output:
9050 *
9051 * 1cat[4, 5, 6]
9052 *
9053 */
9054
9055static VALUE
9056rb_obj_display(int argc, VALUE *argv, VALUE self)
9057{
9058 VALUE out;
9059
9060 out = (!rb_check_arity(argc, 0, 1) ? rb_ractor_stdout() : argv[0]);
9061 rb_io_write(out, self);
9062
9063 return Qnil;
9064}
9065
9066static int
9067rb_stderr_to_original_p(VALUE err)
9068{
9069 return (err == orig_stderr || RFILE(orig_stderr)->fptr->fd < 0);
9070}
9071
9072void
9073rb_write_error2(const char *mesg, long len)
9074{
9075 VALUE out = rb_ractor_stderr();
9076 if (rb_stderr_to_original_p(out)) {
9077#ifdef _WIN32
9078 if (isatty(fileno(stderr))) {
9079 if (rb_w32_write_console(rb_str_new(mesg, len), fileno(stderr)) > 0) return;
9080 }
9081#endif
9082 if (fwrite(mesg, sizeof(char), (size_t)len, stderr) < (size_t)len) {
9083 /* failed to write to stderr, what can we do? */
9084 return;
9085 }
9086 }
9087 else {
9088 rb_io_write(out, rb_str_new(mesg, len));
9089 }
9090}
9091
9092void
9093rb_write_error(const char *mesg)
9094{
9095 rb_write_error2(mesg, strlen(mesg));
9096}
9097
9098void
9099rb_write_error_str(VALUE mesg)
9100{
9101 VALUE out = rb_ractor_stderr();
9102 /* a stopgap measure for the time being */
9103 if (rb_stderr_to_original_p(out)) {
9104 size_t len = (size_t)RSTRING_LEN(mesg);
9105#ifdef _WIN32
9106 if (isatty(fileno(stderr))) {
9107 if (rb_w32_write_console(mesg, fileno(stderr)) > 0) return;
9108 }
9109#endif
9110 if (fwrite(RSTRING_PTR(mesg), sizeof(char), len, stderr) < len) {
9111 RB_GC_GUARD(mesg);
9112 return;
9113 }
9114 }
9115 else {
9116 /* may unlock GVL, and */
9117 rb_io_write(out, mesg);
9118 }
9119}
9120
9121int
9122rb_stderr_tty_p(void)
9123{
9124 if (rb_stderr_to_original_p(rb_ractor_stderr()))
9125 return isatty(fileno(stderr));
9126 return 0;
9127}
9128
9129static void
9130must_respond_to(ID mid, VALUE val, ID id)
9131{
9132 if (!rb_respond_to(val, mid)) {
9133 rb_raise(rb_eTypeError, "%"PRIsVALUE" must have %"PRIsVALUE" method, %"PRIsVALUE" given",
9134 rb_id2str(id), rb_id2str(mid),
9135 rb_obj_class(val));
9136 }
9137}
9138
9139static void
9140stdin_setter(VALUE val, ID id, VALUE *ptr)
9141{
9143}
9144
9145static VALUE
9146stdin_getter(ID id, VALUE *ptr)
9147{
9148 return rb_ractor_stdin();
9149}
9150
9151static void
9152stdout_setter(VALUE val, ID id, VALUE *ptr)
9153{
9154 must_respond_to(id_write, val, id);
9156}
9157
9158static VALUE
9159stdout_getter(ID id, VALUE *ptr)
9160{
9161 return rb_ractor_stdout();
9162}
9163
9164static void
9165stderr_setter(VALUE val, ID id, VALUE *ptr)
9166{
9167 must_respond_to(id_write, val, id);
9169}
9170
9171static VALUE
9172stderr_getter(ID id, VALUE *ptr)
9173{
9174 return rb_ractor_stderr();
9175}
9176
9177static VALUE
9178prep_io(int fd, int fmode, VALUE klass, const char *path)
9179{
9180 rb_io_t *fp;
9181 VALUE io = io_alloc(klass);
9182
9183 MakeOpenFile(io, fp);
9184 fp->self = io;
9185 fp->fd = fd;
9186 fp->mode = fmode;
9187 fp->timeout = Qnil;
9188 if (!io_check_tty(fp)) {
9189#ifdef __CYGWIN__
9190 fp->mode |= FMODE_BINMODE;
9191 setmode(fd, O_BINARY);
9192#endif
9193 }
9194 if (path) fp->pathv = rb_obj_freeze(rb_str_new_cstr(path));
9195 rb_update_max_fd(fd);
9196
9197 return io;
9198}
9199
9200VALUE
9201rb_io_fdopen(int fd, int oflags, const char *path)
9202{
9203 VALUE klass = rb_cIO;
9204
9205 if (path && strcmp(path, "-")) klass = rb_cFile;
9206 return prep_io(fd, rb_io_oflags_fmode(oflags), klass, path);
9207}
9208
9209static VALUE
9210prep_stdio(FILE *f, int fmode, VALUE klass, const char *path)
9211{
9212 rb_io_t *fptr;
9213 VALUE io = prep_io(fileno(f), fmode|FMODE_PREP|DEFAULT_TEXTMODE, klass, path);
9214
9215 GetOpenFile(io, fptr);
9217#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9218 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
9219 if (fmode & FMODE_READABLE) {
9221 }
9222#endif
9223 fptr->stdio_file = f;
9224
9225 return io;
9226}
9227
9228VALUE
9229rb_io_prep_stdin(void)
9230{
9231 return prep_stdio(stdin, FMODE_READABLE, rb_cIO, "<STDIN>");
9232}
9233
9234VALUE
9235rb_io_prep_stdout(void)
9236{
9237 return prep_stdio(stdout, FMODE_WRITABLE|FMODE_SIGNAL_ON_EPIPE, rb_cIO, "<STDOUT>");
9238}
9239
9240VALUE
9241rb_io_prep_stderr(void)
9242{
9243 return prep_stdio(stderr, FMODE_WRITABLE|FMODE_SYNC, rb_cIO, "<STDERR>");
9244}
9245
9246FILE *
9248{
9249 if (!fptr->stdio_file) {
9250 int oflags = rb_io_fmode_oflags(fptr->mode) & ~O_EXCL;
9251 fptr->stdio_file = rb_fdopen(fptr->fd, rb_io_oflags_modestr(oflags));
9252 }
9253 return fptr->stdio_file;
9254}
9255
9256static inline void
9257rb_io_buffer_init(rb_io_buffer_t *buf)
9258{
9259 buf->ptr = NULL;
9260 buf->off = 0;
9261 buf->len = 0;
9262 buf->capa = 0;
9263}
9264
9265static inline rb_io_t *
9266rb_io_fptr_new(void)
9267{
9268 rb_io_t *fp = ALLOC(rb_io_t);
9269 fp->self = Qnil;
9270 fp->fd = -1;
9271 fp->stdio_file = NULL;
9272 fp->mode = 0;
9273 fp->pid = 0;
9274 fp->lineno = 0;
9275 fp->pathv = Qnil;
9276 fp->finalize = 0;
9277 rb_io_buffer_init(&fp->wbuf);
9278 rb_io_buffer_init(&fp->rbuf);
9279 rb_io_buffer_init(&fp->cbuf);
9280 fp->readconv = NULL;
9281 fp->writeconv = NULL;
9283 fp->writeconv_pre_ecflags = 0;
9285 fp->writeconv_initialized = 0;
9286 fp->tied_io_for_writing = 0;
9287 fp->encs.enc = NULL;
9288 fp->encs.enc2 = NULL;
9289 fp->encs.ecflags = 0;
9290 fp->encs.ecopts = Qnil;
9291 fp->write_lock = Qnil;
9292 fp->timeout = Qnil;
9293 return fp;
9294}
9295
9296rb_io_t *
9297rb_io_make_open_file(VALUE obj)
9298{
9299 rb_io_t *fp = 0;
9300
9301 Check_Type(obj, T_FILE);
9302 if (RFILE(obj)->fptr) {
9303 rb_io_close(obj);
9304 rb_io_fptr_finalize(RFILE(obj)->fptr);
9305 RFILE(obj)->fptr = 0;
9306 }
9307 fp = rb_io_fptr_new();
9308 fp->self = obj;
9309 RFILE(obj)->fptr = fp;
9310 return fp;
9311}
9312
9313/*
9314 * call-seq:
9315 * IO.new(fd, mode = 'r', **opts) -> io
9316 *
9317 * Creates and returns a new \IO object (file stream) from a file descriptor.
9318 *
9319 * \IO.new may be useful for interaction with low-level libraries.
9320 * For higher-level interactions, it may be simpler to create
9321 * the file stream using File.open.
9322 *
9323 * Argument +fd+ must be a valid file descriptor (integer):
9324 *
9325 * path = 't.tmp'
9326 * fd = IO.sysopen(path) # => 3
9327 * IO.new(fd) # => #<IO:fd 3>
9328 *
9329 * The new \IO object does not inherit encoding
9330 * (because the integer file descriptor does not have an encoding):
9331 *
9332 * fd = IO.sysopen('t.rus', 'rb')
9333 * io = IO.new(fd)
9334 * io.external_encoding # => #<Encoding:UTF-8> # Not ASCII-8BIT.
9335 *
9336 * Optional argument +mode+ (defaults to 'r') must specify a valid mode;
9337 * see {Access Modes}[rdoc-ref:File@Access+Modes]:
9338 *
9339 * IO.new(fd, 'w') # => #<IO:fd 3>
9340 * IO.new(fd, File::WRONLY) # => #<IO:fd 3>
9341 *
9342 * Optional keyword arguments +opts+ specify:
9343 *
9344 * - {Open Options}[rdoc-ref:IO@Open+Options].
9345 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
9346 *
9347 * Examples:
9348 *
9349 * IO.new(fd, internal_encoding: nil) # => #<IO:fd 3>
9350 * IO.new(fd, autoclose: true) # => #<IO:fd 3>
9351 *
9352 */
9353
9354static VALUE
9355rb_io_initialize(int argc, VALUE *argv, VALUE io)
9356{
9357 VALUE fnum, vmode;
9358 rb_io_t *fp;
9359 int fd, fmode, oflags = O_RDONLY;
9360 convconfig_t convconfig;
9361 VALUE opt;
9362#if defined(HAVE_FCNTL) && defined(F_GETFL)
9363 int ofmode;
9364#else
9365 struct stat st;
9366#endif
9367
9368
9369 argc = rb_scan_args(argc, argv, "11:", &fnum, &vmode, &opt);
9370 rb_io_extract_modeenc(&vmode, 0, opt, &oflags, &fmode, &convconfig);
9371
9372 fd = NUM2INT(fnum);
9373 if (rb_reserved_fd_p(fd)) {
9374 rb_raise(rb_eArgError, "The given fd is not accessible because RubyVM reserves it");
9375 }
9376#if defined(HAVE_FCNTL) && defined(F_GETFL)
9377 oflags = fcntl(fd, F_GETFL);
9378 if (oflags == -1) rb_sys_fail(0);
9379#else
9380 if (fstat(fd, &st) < 0) rb_sys_fail(0);
9381#endif
9382 rb_update_max_fd(fd);
9383#if defined(HAVE_FCNTL) && defined(F_GETFL)
9384 ofmode = rb_io_oflags_fmode(oflags);
9385 if (NIL_P(vmode)) {
9386 fmode = ofmode;
9387 }
9388 else if ((~ofmode & fmode) & FMODE_READWRITE) {
9389 VALUE error = INT2FIX(EINVAL);
9391 }
9392#endif
9393 VALUE path = Qnil;
9394
9395 if (!NIL_P(opt)) {
9396 if (rb_hash_aref(opt, sym_autoclose) == Qfalse) {
9397 fmode |= FMODE_PREP;
9398 }
9399
9400 path = rb_hash_aref(opt, RB_ID2SYM(idPath));
9401 if (!NIL_P(path)) {
9402 StringValue(path);
9403 path = rb_str_new_frozen(path);
9404 }
9405 }
9406
9407 MakeOpenFile(io, fp);
9408 fp->self = io;
9409 fp->fd = fd;
9410 fp->mode = fmode;
9411 fp->encs = convconfig;
9412 fp->pathv = path;
9413 fp->timeout = Qnil;
9414 clear_codeconv(fp);
9415 io_check_tty(fp);
9416 if (fileno(stdin) == fd)
9417 fp->stdio_file = stdin;
9418 else if (fileno(stdout) == fd)
9419 fp->stdio_file = stdout;
9420 else if (fileno(stderr) == fd)
9421 fp->stdio_file = stderr;
9422
9423 if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
9424 return io;
9425}
9426
9427/*
9428 * call-seq:
9429 * set_encoding_by_bom -> encoding or nil
9430 *
9431 * If the stream begins with a BOM
9432 * ({byte order marker}[https://en.wikipedia.org/wiki/Byte_order_mark]),
9433 * consumes the BOM and sets the external encoding accordingly;
9434 * returns the result encoding if found, or +nil+ otherwise:
9435 *
9436 * File.write('t.tmp', "\u{FEFF}abc")
9437 * io = File.open('t.tmp', 'rb')
9438 * io.set_encoding_by_bom # => #<Encoding:UTF-8>
9439 * io.close
9440 *
9441 * File.write('t.tmp', 'abc')
9442 * io = File.open('t.tmp', 'rb')
9443 * io.set_encoding_by_bom # => nil
9444 * io.close
9445 *
9446 * Raises an exception if the stream is not binmode
9447 * or its encoding has already been set.
9448 *
9449 */
9450
9451static VALUE
9452rb_io_set_encoding_by_bom(VALUE io)
9453{
9454 rb_io_t *fptr;
9455
9456 GetOpenFile(io, fptr);
9457 if (!(fptr->mode & FMODE_BINMODE)) {
9458 rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
9459 }
9460 if (fptr->encs.enc2) {
9461 rb_raise(rb_eArgError, "encoding conversion is set");
9462 }
9463 else if (fptr->encs.enc && fptr->encs.enc != rb_ascii8bit_encoding()) {
9464 rb_raise(rb_eArgError, "encoding is set to %s already",
9465 rb_enc_name(fptr->encs.enc));
9466 }
9467 if (!io_set_encoding_by_bom(io)) return Qnil;
9468 return rb_enc_from_encoding(fptr->encs.enc);
9469}
9470
9471/*
9472 * call-seq:
9473 * File.new(path, mode = 'r', perm = 0666, **opts) -> file
9474 *
9475 * Opens the file at the given +path+ according to the given +mode+;
9476 * creates and returns a new \File object for that file.
9477 *
9478 * The new \File object is buffered mode (or non-sync mode), unless
9479 * +filename+ is a tty.
9480 * See IO#flush, IO#fsync, IO#fdatasync, and IO#sync=.
9481 *
9482 * Argument +path+ must be a valid file path:
9483 *
9484 * f = File.new('/etc/fstab')
9485 * f.close
9486 * f = File.new('t.txt')
9487 * f.close
9488 *
9489 * Optional argument +mode+ (defaults to 'r') must specify a valid mode;
9490 * see {Access Modes}[rdoc-ref:File@Access+Modes]:
9491 *
9492 * f = File.new('t.tmp', 'w')
9493 * f.close
9494 * f = File.new('t.tmp', File::RDONLY)
9495 * f.close
9496 *
9497 * Optional argument +perm+ (defaults to 0666) must specify valid permissions
9498 * see {File Permissions}[rdoc-ref:File@File+Permissions]:
9499 *
9500 * f = File.new('t.tmp', File::CREAT, 0644)
9501 * f.close
9502 * f = File.new('t.tmp', File::CREAT, 0444)
9503 * f.close
9504 *
9505 * Optional keyword arguments +opts+ specify:
9506 *
9507 * - {Open Options}[rdoc-ref:IO@Open+Options].
9508 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
9509 *
9510 */
9511
9512static VALUE
9513rb_file_initialize(int argc, VALUE *argv, VALUE io)
9514{
9515 if (RFILE(io)->fptr) {
9516 rb_raise(rb_eRuntimeError, "reinitializing File");
9517 }
9518 if (0 < argc && argc < 3) {
9519 VALUE fd = rb_check_to_int(argv[0]);
9520
9521 if (!NIL_P(fd)) {
9522 argv[0] = fd;
9523 return rb_io_initialize(argc, argv, io);
9524 }
9525 }
9526 rb_open_file(argc, argv, io);
9527
9528 return io;
9529}
9530
9531/* :nodoc: */
9532static VALUE
9533rb_io_s_new(int argc, VALUE *argv, VALUE klass)
9534{
9535 if (rb_block_given_p()) {
9536 VALUE cname = rb_obj_as_string(klass);
9537
9538 rb_warn("%"PRIsVALUE"::new() does not take block; use %"PRIsVALUE"::open() instead",
9539 cname, cname);
9540 }
9541 return rb_class_new_instance_kw(argc, argv, klass, RB_PASS_CALLED_KEYWORDS);
9542}
9543
9544
9545/*
9546 * call-seq:
9547 * IO.for_fd(fd, mode = 'r', **opts) -> io
9548 *
9549 * Synonym for IO.new.
9550 *
9551 */
9552
9553static VALUE
9554rb_io_s_for_fd(int argc, VALUE *argv, VALUE klass)
9555{
9556 VALUE io = rb_obj_alloc(klass);
9557 rb_io_initialize(argc, argv, io);
9558 return io;
9559}
9560
9561/*
9562 * call-seq:
9563 * ios.autoclose? -> true or false
9564 *
9565 * Returns +true+ if the underlying file descriptor of _ios_ will be
9566 * closed automatically at its finalization, otherwise +false+.
9567 */
9568
9569static VALUE
9570rb_io_autoclose_p(VALUE io)
9571{
9572 rb_io_t *fptr = RFILE(io)->fptr;
9573 rb_io_check_closed(fptr);
9574 return RBOOL(!(fptr->mode & FMODE_PREP));
9575}
9576
9577/*
9578 * call-seq:
9579 * io.autoclose = bool -> true or false
9580 *
9581 * Sets auto-close flag.
9582 *
9583 * f = open("/dev/null")
9584 * IO.for_fd(f.fileno)
9585 * # ...
9586 * f.gets # may cause Errno::EBADF
9587 *
9588 * f = open("/dev/null")
9589 * IO.for_fd(f.fileno).autoclose = false
9590 * # ...
9591 * f.gets # won't cause Errno::EBADF
9592 */
9593
9594static VALUE
9595rb_io_set_autoclose(VALUE io, VALUE autoclose)
9596{
9597 rb_io_t *fptr;
9598 GetOpenFile(io, fptr);
9599 if (!RTEST(autoclose))
9600 fptr->mode |= FMODE_PREP;
9601 else
9602 fptr->mode &= ~FMODE_PREP;
9603 return autoclose;
9604}
9605
9606static VALUE
9607io_wait_event(VALUE io, int event, VALUE timeout, int return_io)
9608{
9609 VALUE result = rb_io_wait(io, RB_INT2NUM(event), timeout);
9610
9611 if (!RB_TEST(result)) {
9612 return Qnil;
9613 }
9614
9615 int mask = RB_NUM2INT(result);
9616
9617 if (mask & event) {
9618 if (return_io)
9619 return io;
9620 else
9621 return result;
9622 }
9623 else {
9624 return Qfalse;
9625 }
9626}
9627
9628/*
9629 * call-seq:
9630 * io.wait_readable -> truthy or falsy
9631 * io.wait_readable(timeout) -> truthy or falsy
9632 *
9633 * Waits until IO is readable and returns a truthy value, or a falsy
9634 * value when times out. Returns a truthy value immediately when
9635 * buffered data is available.
9636 */
9637
9638static VALUE
9639io_wait_readable(int argc, VALUE *argv, VALUE io)
9640{
9641 rb_io_t *fptr;
9642
9643 RB_IO_POINTER(io, fptr);
9645
9646 if (rb_io_read_pending(fptr)) return Qtrue;
9647
9648 rb_check_arity(argc, 0, 1);
9649 VALUE timeout = (argc == 1 ? argv[0] : Qnil);
9650
9651 return io_wait_event(io, RUBY_IO_READABLE, timeout, 1);
9652}
9653
9654/*
9655 * call-seq:
9656 * io.wait_writable -> truthy or falsy
9657 * io.wait_writable(timeout) -> truthy or falsy
9658 *
9659 * Waits until IO is writable and returns a truthy value or a falsy
9660 * value when times out.
9661 */
9662static VALUE
9663io_wait_writable(int argc, VALUE *argv, VALUE io)
9664{
9665 rb_io_t *fptr;
9666
9667 RB_IO_POINTER(io, fptr);
9669
9670 rb_check_arity(argc, 0, 1);
9671 VALUE timeout = (argc == 1 ? argv[0] : Qnil);
9672
9673 return io_wait_event(io, RUBY_IO_WRITABLE, timeout, 1);
9674}
9675
9676/*
9677 * call-seq:
9678 * io.wait_priority -> truthy or falsy
9679 * io.wait_priority(timeout) -> truthy or falsy
9680 *
9681 * Waits until IO is priority and returns a truthy value or a falsy
9682 * value when times out. Priority data is sent and received using
9683 * the Socket::MSG_OOB flag and is typically limited to streams.
9684 */
9685static VALUE
9686io_wait_priority(int argc, VALUE *argv, VALUE io)
9687{
9688 rb_io_t *fptr = NULL;
9689
9690 RB_IO_POINTER(io, fptr);
9692
9693 if (rb_io_read_pending(fptr)) return Qtrue;
9694
9695 rb_check_arity(argc, 0, 1);
9696 VALUE timeout = argc == 1 ? argv[0] : Qnil;
9697
9698 return io_wait_event(io, RUBY_IO_PRIORITY, timeout, 1);
9699}
9700
9701static int
9702wait_mode_sym(VALUE mode)
9703{
9704 if (mode == ID2SYM(rb_intern("r"))) {
9705 return RB_WAITFD_IN;
9706 }
9707 if (mode == ID2SYM(rb_intern("read"))) {
9708 return RB_WAITFD_IN;
9709 }
9710 if (mode == ID2SYM(rb_intern("readable"))) {
9711 return RB_WAITFD_IN;
9712 }
9713 if (mode == ID2SYM(rb_intern("w"))) {
9714 return RB_WAITFD_OUT;
9715 }
9716 if (mode == ID2SYM(rb_intern("write"))) {
9717 return RB_WAITFD_OUT;
9718 }
9719 if (mode == ID2SYM(rb_intern("writable"))) {
9720 return RB_WAITFD_OUT;
9721 }
9722 if (mode == ID2SYM(rb_intern("rw"))) {
9723 return RB_WAITFD_IN|RB_WAITFD_OUT;
9724 }
9725 if (mode == ID2SYM(rb_intern("read_write"))) {
9726 return RB_WAITFD_IN|RB_WAITFD_OUT;
9727 }
9728 if (mode == ID2SYM(rb_intern("readable_writable"))) {
9729 return RB_WAITFD_IN|RB_WAITFD_OUT;
9730 }
9731
9732 rb_raise(rb_eArgError, "unsupported mode: %"PRIsVALUE, mode);
9733}
9734
9735static inline rb_io_event_t
9736io_event_from_value(VALUE value)
9737{
9738 int events = RB_NUM2INT(value);
9739
9740 if (events <= 0) rb_raise(rb_eArgError, "Events must be positive integer!");
9741
9742 return events;
9743}
9744
9745/*
9746 * call-seq:
9747 * io.wait(events, timeout) -> event mask, false or nil
9748 * io.wait(timeout = nil, mode = :read) -> self, true, or false
9749 *
9750 * Waits until the IO becomes ready for the specified events and returns the
9751 * subset of events that become ready, or a falsy value when times out.
9752 *
9753 * The events can be a bit mask of +IO::READABLE+, +IO::WRITABLE+ or
9754 * +IO::PRIORITY+.
9755 *
9756 * Returns an event mask (truthy value) immediately when buffered data is available.
9757 *
9758 * Optional parameter +mode+ is one of +:read+, +:write+, or
9759 * +:read_write+.
9760 */
9761
9762static VALUE
9763io_wait(int argc, VALUE *argv, VALUE io)
9764{
9765 VALUE timeout = Qundef;
9766 rb_io_event_t events = 0;
9767 int return_io = 0;
9768
9769 // The documented signature for this method is actually incorrect.
9770 // A single timeout is allowed in any position, and multiple symbols can be given.
9771 // Whether this is intentional or not, I don't know, and as such I consider this to
9772 // be a legacy/slow path.
9773 if (argc != 2 || (RB_SYMBOL_P(argv[0]) || RB_SYMBOL_P(argv[1]))) {
9774 // We'd prefer to return the actual mask, but this form would return the io itself:
9775 return_io = 1;
9776
9777 // Slow/messy path:
9778 for (int i = 0; i < argc; i += 1) {
9779 if (RB_SYMBOL_P(argv[i])) {
9780 events |= wait_mode_sym(argv[i]);
9781 }
9782 else if (UNDEF_P(timeout)) {
9783 rb_time_interval(timeout = argv[i]);
9784 }
9785 else {
9786 rb_raise(rb_eArgError, "timeout given more than once");
9787 }
9788 }
9789
9790 if (UNDEF_P(timeout)) timeout = Qnil;
9791
9792 if (events == 0) {
9793 events = RUBY_IO_READABLE;
9794 }
9795 }
9796 else /* argc == 2 and neither are symbols */ {
9797 // This is the fast path:
9798 events = io_event_from_value(argv[0]);
9799 timeout = argv[1];
9800 }
9801
9802 if (events & RUBY_IO_READABLE) {
9803 rb_io_t *fptr = NULL;
9804 RB_IO_POINTER(io, fptr);
9805
9806 if (rb_io_read_pending(fptr)) {
9807 // This was the original behaviour:
9808 if (return_io) return Qtrue;
9809 // New behaviour always returns an event mask:
9810 else return RB_INT2NUM(RUBY_IO_READABLE);
9811 }
9812 }
9813
9814 return io_wait_event(io, events, timeout, return_io);
9815}
9816
9817static void
9818argf_mark(void *ptr)
9819{
9820 struct argf *p = ptr;
9821 rb_gc_mark(p->filename);
9822 rb_gc_mark(p->current_file);
9823 rb_gc_mark(p->argv);
9824 rb_gc_mark(p->inplace);
9825 rb_gc_mark(p->encs.ecopts);
9826}
9827
9828static size_t
9829argf_memsize(const void *ptr)
9830{
9831 const struct argf *p = ptr;
9832 size_t size = sizeof(*p);
9833 return size;
9834}
9835
9836static const rb_data_type_t argf_type = {
9837 "ARGF",
9838 {argf_mark, RUBY_TYPED_DEFAULT_FREE, argf_memsize},
9839 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
9840};
9841
9842static inline void
9843argf_init(struct argf *p, VALUE v)
9844{
9845 p->filename = Qnil;
9846 p->current_file = Qnil;
9847 p->lineno = 0;
9848 p->argv = v;
9849}
9850
9851static VALUE
9852argf_alloc(VALUE klass)
9853{
9854 struct argf *p;
9855 VALUE argf = TypedData_Make_Struct(klass, struct argf, &argf_type, p);
9856
9857 argf_init(p, Qnil);
9858 return argf;
9859}
9860
9861#undef rb_argv
9862
9863/* :nodoc: */
9864static VALUE
9865argf_initialize(VALUE argf, VALUE argv)
9866{
9867 memset(&ARGF, 0, sizeof(ARGF));
9868 argf_init(&ARGF, argv);
9869
9870 return argf;
9871}
9872
9873/* :nodoc: */
9874static VALUE
9875argf_initialize_copy(VALUE argf, VALUE orig)
9876{
9877 if (!OBJ_INIT_COPY(argf, orig)) return argf;
9878 ARGF = argf_of(orig);
9879 ARGF.argv = rb_obj_dup(ARGF.argv);
9880 return argf;
9881}
9882
9883/*
9884 * call-seq:
9885 * ARGF.lineno = integer -> integer
9886 *
9887 * Sets the line number of ARGF as a whole to the given Integer.
9888 *
9889 * ARGF sets the line number automatically as you read data, so normally
9890 * you will not need to set it explicitly. To access the current line number
9891 * use ARGF.lineno.
9892 *
9893 * For example:
9894 *
9895 * ARGF.lineno #=> 0
9896 * ARGF.readline #=> "This is line 1\n"
9897 * ARGF.lineno #=> 1
9898 * ARGF.lineno = 0 #=> 0
9899 * ARGF.lineno #=> 0
9900 */
9901static VALUE
9902argf_set_lineno(VALUE argf, VALUE val)
9903{
9904 ARGF.lineno = NUM2INT(val);
9905 ARGF.last_lineno = ARGF.lineno;
9906 return val;
9907}
9908
9909/*
9910 * call-seq:
9911 * ARGF.lineno -> integer
9912 *
9913 * Returns the current line number of ARGF as a whole. This value
9914 * can be set manually with ARGF.lineno=.
9915 *
9916 * For example:
9917 *
9918 * ARGF.lineno #=> 0
9919 * ARGF.readline #=> "This is line 1\n"
9920 * ARGF.lineno #=> 1
9921 */
9922static VALUE
9923argf_lineno(VALUE argf)
9924{
9925 return INT2FIX(ARGF.lineno);
9926}
9927
9928static VALUE
9929argf_forward(int argc, VALUE *argv, VALUE argf)
9930{
9931 return forward_current(rb_frame_this_func(), argc, argv);
9932}
9933
9934#define next_argv() argf_next_argv(argf)
9935#define ARGF_GENERIC_INPUT_P() \
9936 (ARGF.current_file == rb_stdin && !RB_TYPE_P(ARGF.current_file, T_FILE))
9937#define ARGF_FORWARD(argc, argv) do {\
9938 if (ARGF_GENERIC_INPUT_P())\
9939 return argf_forward((argc), (argv), argf);\
9940} while (0)
9941#define NEXT_ARGF_FORWARD(argc, argv) do {\
9942 if (!next_argv()) return Qnil;\
9943 ARGF_FORWARD((argc), (argv));\
9944} while (0)
9945
9946static void
9947argf_close(VALUE argf)
9948{
9949 VALUE file = ARGF.current_file;
9950 if (file == rb_stdin) return;
9951 if (RB_TYPE_P(file, T_FILE)) {
9952 rb_io_set_write_io(file, Qnil);
9953 }
9954 io_close(file);
9955 ARGF.init_p = -1;
9956}
9957
9958static int
9959argf_next_argv(VALUE argf)
9960{
9961 char *fn;
9962 rb_io_t *fptr;
9963 int stdout_binmode = 0;
9964 int fmode;
9965
9966 VALUE r_stdout = rb_ractor_stdout();
9967
9968 if (RB_TYPE_P(r_stdout, T_FILE)) {
9969 GetOpenFile(r_stdout, fptr);
9970 if (fptr->mode & FMODE_BINMODE)
9971 stdout_binmode = 1;
9972 }
9973
9974 if (ARGF.init_p == 0) {
9975 if (!NIL_P(ARGF.argv) && RARRAY_LEN(ARGF.argv) > 0) {
9976 ARGF.next_p = 1;
9977 }
9978 else {
9979 ARGF.next_p = -1;
9980 }
9981 ARGF.init_p = 1;
9982 }
9983 else {
9984 if (NIL_P(ARGF.argv)) {
9985 ARGF.next_p = -1;
9986 }
9987 else if (ARGF.next_p == -1 && RARRAY_LEN(ARGF.argv) > 0) {
9988 ARGF.next_p = 1;
9989 }
9990 }
9991
9992 if (ARGF.next_p == 1) {
9993 if (ARGF.init_p == 1) argf_close(argf);
9994 retry:
9995 if (RARRAY_LEN(ARGF.argv) > 0) {
9996 VALUE filename = rb_ary_shift(ARGF.argv);
9997 FilePathValue(filename);
9998 ARGF.filename = filename;
9999 filename = rb_str_encode_ospath(filename);
10000 fn = StringValueCStr(filename);
10001 if (RSTRING_LEN(filename) == 1 && fn[0] == '-') {
10002 ARGF.current_file = rb_stdin;
10003 if (ARGF.inplace) {
10004 rb_warn("Can't do inplace edit for stdio; skipping");
10005 goto retry;
10006 }
10007 }
10008 else {
10009 VALUE write_io = Qnil;
10010 int fr = rb_sysopen(filename, O_RDONLY, 0);
10011
10012 if (ARGF.inplace) {
10013 struct stat st;
10014#ifndef NO_SAFE_RENAME
10015 struct stat st2;
10016#endif
10017 VALUE str;
10018 int fw;
10019
10020 if (RB_TYPE_P(r_stdout, T_FILE) && r_stdout != orig_stdout) {
10021 rb_io_close(r_stdout);
10022 }
10023 fstat(fr, &st);
10024 str = filename;
10025 if (!NIL_P(ARGF.inplace)) {
10026 VALUE suffix = ARGF.inplace;
10027 str = rb_str_dup(str);
10028 if (NIL_P(rb_str_cat_conv_enc_opts(str, RSTRING_LEN(str),
10029 RSTRING_PTR(suffix), RSTRING_LEN(suffix),
10030 rb_enc_get(suffix), 0, Qnil))) {
10031 rb_str_append(str, suffix);
10032 }
10033#ifdef NO_SAFE_RENAME
10034 (void)close(fr);
10035 (void)unlink(RSTRING_PTR(str));
10036 if (rename(fn, RSTRING_PTR(str)) < 0) {
10037 rb_warn("Can't rename %"PRIsVALUE" to %"PRIsVALUE": %s, skipping file",
10038 filename, str, strerror(errno));
10039 goto retry;
10040 }
10041 fr = rb_sysopen(str, O_RDONLY, 0);
10042#else
10043 if (rename(fn, RSTRING_PTR(str)) < 0) {
10044 rb_warn("Can't rename %"PRIsVALUE" to %"PRIsVALUE": %s, skipping file",
10045 filename, str, strerror(errno));
10046 close(fr);
10047 goto retry;
10048 }
10049#endif
10050 }
10051 else {
10052#ifdef NO_SAFE_RENAME
10053 rb_fatal("Can't do inplace edit without backup");
10054#else
10055 if (unlink(fn) < 0) {
10056 rb_warn("Can't remove %"PRIsVALUE": %s, skipping file",
10057 filename, strerror(errno));
10058 close(fr);
10059 goto retry;
10060 }
10061#endif
10062 }
10063 fw = rb_sysopen(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666);
10064#ifndef NO_SAFE_RENAME
10065 fstat(fw, &st2);
10066#ifdef HAVE_FCHMOD
10067 fchmod(fw, st.st_mode);
10068#else
10069 chmod(fn, st.st_mode);
10070#endif
10071 if (st.st_uid!=st2.st_uid || st.st_gid!=st2.st_gid) {
10072 int err;
10073#ifdef HAVE_FCHOWN
10074 err = fchown(fw, st.st_uid, st.st_gid);
10075#else
10076 err = chown(fn, st.st_uid, st.st_gid);
10077#endif
10078 if (err && getuid() == 0 && st2.st_uid == 0) {
10079 const char *wkfn = RSTRING_PTR(filename);
10080 rb_warn("Can't set owner/group of %"PRIsVALUE" to same as %"PRIsVALUE": %s, skipping file",
10081 filename, str, strerror(errno));
10082 (void)close(fr);
10083 (void)close(fw);
10084 (void)unlink(wkfn);
10085 goto retry;
10086 }
10087 }
10088#endif
10089 write_io = prep_io(fw, FMODE_WRITABLE, rb_cFile, fn);
10090 rb_ractor_stdout_set(write_io);
10091 if (stdout_binmode) rb_io_binmode(rb_stdout);
10092 }
10093 fmode = FMODE_READABLE;
10094 if (!ARGF.binmode) {
10095 fmode |= DEFAULT_TEXTMODE;
10096 }
10097 ARGF.current_file = prep_io(fr, fmode, rb_cFile, fn);
10098 if (!NIL_P(write_io)) {
10099 rb_io_set_write_io(ARGF.current_file, write_io);
10100 }
10101 RB_GC_GUARD(filename);
10102 }
10103 if (ARGF.binmode) rb_io_ascii8bit_binmode(ARGF.current_file);
10104 GetOpenFile(ARGF.current_file, fptr);
10105 if (ARGF.encs.enc) {
10106 fptr->encs = ARGF.encs;
10107 clear_codeconv(fptr);
10108 }
10109 else {
10110 fptr->encs.ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
10111 if (!ARGF.binmode) {
10113#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
10114 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
10115#endif
10116 }
10117 }
10118 ARGF.next_p = 0;
10119 }
10120 else {
10121 ARGF.next_p = 1;
10122 return FALSE;
10123 }
10124 }
10125 else if (ARGF.next_p == -1) {
10126 ARGF.current_file = rb_stdin;
10127 ARGF.filename = rb_str_new2("-");
10128 if (ARGF.inplace) {
10129 rb_warn("Can't do inplace edit for stdio");
10130 rb_ractor_stdout_set(orig_stdout);
10131 }
10132 }
10133 if (ARGF.init_p == -1) ARGF.init_p = 1;
10134 return TRUE;
10135}
10136
10137static VALUE
10138argf_getline(int argc, VALUE *argv, VALUE argf)
10139{
10140 VALUE line;
10141 long lineno = ARGF.lineno;
10142
10143 retry:
10144 if (!next_argv()) return Qnil;
10145 if (ARGF_GENERIC_INPUT_P()) {
10146 line = forward_current(idGets, argc, argv);
10147 }
10148 else {
10149 if (argc == 0 && rb_rs == rb_default_rs) {
10150 line = rb_io_gets(ARGF.current_file);
10151 }
10152 else {
10153 line = rb_io_getline(argc, argv, ARGF.current_file);
10154 }
10155 if (NIL_P(line) && ARGF.next_p != -1) {
10156 argf_close(argf);
10157 ARGF.next_p = 1;
10158 goto retry;
10159 }
10160 }
10161 if (!NIL_P(line)) {
10162 ARGF.lineno = ++lineno;
10163 ARGF.last_lineno = ARGF.lineno;
10164 }
10165 return line;
10166}
10167
10168static VALUE
10169argf_lineno_getter(ID id, VALUE *var)
10170{
10171 VALUE argf = *var;
10172 return INT2FIX(ARGF.last_lineno);
10173}
10174
10175static void
10176argf_lineno_setter(VALUE val, ID id, VALUE *var)
10177{
10178 VALUE argf = *var;
10179 int n = NUM2INT(val);
10180 ARGF.last_lineno = ARGF.lineno = n;
10181}
10182
10183void
10184rb_reset_argf_lineno(long n)
10185{
10186 ARGF.last_lineno = ARGF.lineno = n;
10187}
10188
10189static VALUE argf_gets(int, VALUE *, VALUE);
10190
10191/*
10192 * call-seq:
10193 * gets(sep=$/ [, getline_args]) -> string or nil
10194 * gets(limit [, getline_args]) -> string or nil
10195 * gets(sep, limit [, getline_args]) -> string or nil
10196 *
10197 * Returns (and assigns to <code>$_</code>) the next line from the list
10198 * of files in +ARGV+ (or <code>$*</code>), or from standard input if
10199 * no files are present on the command line. Returns +nil+ at end of
10200 * file. The optional argument specifies the record separator. The
10201 * separator is included with the contents of each record. A separator
10202 * of +nil+ reads the entire contents, and a zero-length separator
10203 * reads the input one paragraph at a time, where paragraphs are
10204 * divided by two consecutive newlines. If the first argument is an
10205 * integer, or optional second argument is given, the returning string
10206 * would not be longer than the given value in bytes. If multiple
10207 * filenames are present in +ARGV+, <code>gets(nil)</code> will read
10208 * the contents one file at a time.
10209 *
10210 * ARGV << "testfile"
10211 * print while gets
10212 *
10213 * <em>produces:</em>
10214 *
10215 * This is line one
10216 * This is line two
10217 * This is line three
10218 * And so on...
10219 *
10220 * The style of programming using <code>$_</code> as an implicit
10221 * parameter is gradually losing favor in the Ruby community.
10222 */
10223
10224static VALUE
10225rb_f_gets(int argc, VALUE *argv, VALUE recv)
10226{
10227 if (recv == argf) {
10228 return argf_gets(argc, argv, argf);
10229 }
10230 return forward(argf, idGets, argc, argv);
10231}
10232
10233/*
10234 * call-seq:
10235 * ARGF.gets(sep=$/ [, getline_args]) -> string or nil
10236 * ARGF.gets(limit [, getline_args]) -> string or nil
10237 * ARGF.gets(sep, limit [, getline_args]) -> string or nil
10238 *
10239 * Returns the next line from the current file in ARGF.
10240 *
10241 * By default lines are assumed to be separated by <code>$/</code>;
10242 * to use a different character as a separator, supply it as a String
10243 * for the _sep_ argument.
10244 *
10245 * The optional _limit_ argument specifies how many characters of each line
10246 * to return. By default all characters are returned.
10247 *
10248 * See IO.readlines for details about getline_args.
10249 *
10250 */
10251static VALUE
10252argf_gets(int argc, VALUE *argv, VALUE argf)
10253{
10254 VALUE line;
10255
10256 line = argf_getline(argc, argv, argf);
10257 rb_lastline_set(line);
10258
10259 return line;
10260}
10261
10262VALUE
10264{
10265 VALUE line;
10266
10267 if (rb_rs != rb_default_rs) {
10268 return rb_f_gets(0, 0, argf);
10269 }
10270
10271 retry:
10272 if (!next_argv()) return Qnil;
10273 line = rb_io_gets(ARGF.current_file);
10274 if (NIL_P(line) && ARGF.next_p != -1) {
10275 rb_io_close(ARGF.current_file);
10276 ARGF.next_p = 1;
10277 goto retry;
10278 }
10279 rb_lastline_set(line);
10280 if (!NIL_P(line)) {
10281 ARGF.lineno++;
10282 ARGF.last_lineno = ARGF.lineno;
10283 }
10284
10285 return line;
10286}
10287
10288static VALUE argf_readline(int, VALUE *, VALUE);
10289
10290/*
10291 * call-seq:
10292 * readline(sep = $/, chomp: false) -> string
10293 * readline(limit, chomp: false) -> string
10294 * readline(sep, limit, chomp: false) -> string
10295 *
10296 * Equivalent to method Kernel#gets, except that it raises an exception
10297 * if called at end-of-stream:
10298 *
10299 * $ cat t.txt | ruby -e "p readlines; readline"
10300 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10301 * in `readline': end of file reached (EOFError)
10302 *
10303 * Optional keyword argument +chomp+ specifies whether line separators
10304 * are to be omitted.
10305 */
10306
10307static VALUE
10308rb_f_readline(int argc, VALUE *argv, VALUE recv)
10309{
10310 if (recv == argf) {
10311 return argf_readline(argc, argv, argf);
10312 }
10313 return forward(argf, rb_intern("readline"), argc, argv);
10314}
10315
10316
10317/*
10318 * call-seq:
10319 * ARGF.readline(sep=$/) -> string
10320 * ARGF.readline(limit) -> string
10321 * ARGF.readline(sep, limit) -> string
10322 *
10323 * Returns the next line from the current file in ARGF.
10324 *
10325 * By default lines are assumed to be separated by <code>$/</code>;
10326 * to use a different character as a separator, supply it as a String
10327 * for the _sep_ argument.
10328 *
10329 * The optional _limit_ argument specifies how many characters of each line
10330 * to return. By default all characters are returned.
10331 *
10332 * An EOFError is raised at the end of the file.
10333 */
10334static VALUE
10335argf_readline(int argc, VALUE *argv, VALUE argf)
10336{
10337 VALUE line;
10338
10339 if (!next_argv()) rb_eof_error();
10340 ARGF_FORWARD(argc, argv);
10341 line = argf_gets(argc, argv, argf);
10342 if (NIL_P(line)) {
10343 rb_eof_error();
10344 }
10345
10346 return line;
10347}
10348
10349static VALUE argf_readlines(int, VALUE *, VALUE);
10350
10351/*
10352 * call-seq:
10353 * readlines(sep = $/, chomp: false, **enc_opts) -> array
10354 * readlines(limit, chomp: false, **enc_opts) -> array
10355 * readlines(sep, limit, chomp: false, **enc_opts) -> array
10356 *
10357 * Returns an array containing the lines returned by calling
10358 * Kernel#gets until the end-of-stream is reached;
10359 * (see {Line IO}[rdoc-ref:IO@Line+IO]).
10360 *
10361 * With only string argument +sep+ given,
10362 * returns the remaining lines as determined by line separator +sep+,
10363 * or +nil+ if none;
10364 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
10365 *
10366 * # Default separator.
10367 * $ cat t.txt | ruby -e "p readlines"
10368 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10369 *
10370 * # Specified separator.
10371 * $ cat t.txt | ruby -e "p readlines 'li'"
10372 * ["First li", "ne\nSecond li", "ne\n\nFourth li", "ne\nFifth li", "ne\n"]
10373 *
10374 * # Get-all separator.
10375 * $ cat t.txt | ruby -e "p readlines nil"
10376 * ["First line\nSecond line\n\nFourth line\nFifth line\n"]
10377 *
10378 * # Get-paragraph separator.
10379 * $ cat t.txt | ruby -e "p readlines ''"
10380 * ["First line\nSecond line\n\n", "Fourth line\nFifth line\n"]
10381 *
10382 * With only integer argument +limit+ given,
10383 * limits the number of bytes in the line;
10384 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
10385 *
10386 * $cat t.txt | ruby -e "p readlines 10"
10387 * ["First line", "\n", "Second lin", "e\n", "\n", "Fourth lin", "e\n", "Fifth line", "\n"]
10388 *
10389 * $cat t.txt | ruby -e "p readlines 11"
10390 * ["First line\n", "Second line", "\n", "\n", "Fourth line", "\n", "Fifth line\n"]
10391 *
10392 * $cat t.txt | ruby -e "p readlines 12"
10393 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10394 *
10395 * With arguments +sep+ and +limit+ given, combines the two behaviors;
10396 * see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit].
10397 *
10398 * Optional keyword argument +chomp+ specifies whether line separators
10399 * are to be omitted:
10400 *
10401 * $ cat t.txt | ruby -e "p readlines(chomp: true)"
10402 * ["First line", "Second line", "", "Fourth line", "Fifth line"]
10403 *
10404 * Optional keyword arguments +enc_opts+ specify encoding options;
10405 * see {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
10406 *
10407 */
10408
10409static VALUE
10410rb_f_readlines(int argc, VALUE *argv, VALUE recv)
10411{
10412 if (recv == argf) {
10413 return argf_readlines(argc, argv, argf);
10414 }
10415 return forward(argf, rb_intern("readlines"), argc, argv);
10416}
10417
10418/*
10419 * call-seq:
10420 * ARGF.readlines(sep = $/) -> array
10421 * ARGF.readlines(limit) -> array
10422 * ARGF.readlines(sep, limit) -> array
10423 *
10424 * ARGF.to_a(sep = $/) -> array
10425 * ARGF.to_a(limit) -> array
10426 * ARGF.to_a(sep, limit) -> array
10427 *
10428 * Reads each file in ARGF in its entirety, returning an Array containing
10429 * lines from the files. Lines are assumed to be separated by _sep_.
10430 *
10431 * lines = ARGF.readlines
10432 * lines[0] #=> "This is line one\n"
10433 */
10434static VALUE
10435argf_readlines(int argc, VALUE *argv, VALUE argf)
10436{
10437 long lineno = ARGF.lineno;
10438 VALUE lines, ary;
10439
10440 ary = rb_ary_new();
10441 while (next_argv()) {
10442 if (ARGF_GENERIC_INPUT_P()) {
10443 lines = forward_current(rb_intern("readlines"), argc, argv);
10444 }
10445 else {
10446 lines = rb_io_readlines(argc, argv, ARGF.current_file);
10447 argf_close(argf);
10448 }
10449 ARGF.next_p = 1;
10450 rb_ary_concat(ary, lines);
10451 ARGF.lineno = lineno + RARRAY_LEN(ary);
10452 ARGF.last_lineno = ARGF.lineno;
10453 }
10454 ARGF.init_p = 0;
10455 return ary;
10456}
10457
10458/*
10459 * call-seq:
10460 * `command` -> string
10461 *
10462 * Returns the <tt>$stdout</tt> output from running +command+ in a subshell;
10463 * sets global variable <tt>$?</tt> to the process status.
10464 *
10465 * This method has potential security vulnerabilities if called with untrusted input;
10466 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
10467 *
10468 * Examples:
10469 *
10470 * $ `date` # => "Wed Apr 9 08:56:30 CDT 2003\n"
10471 * $ `echo oops && exit 99` # => "oops\n"
10472 * $ $? # => #<Process::Status: pid 17088 exit 99>
10473 * $ $?.status # => 99>
10474 *
10475 * The built-in syntax <tt>%x{...}</tt> uses this method.
10476 *
10477 */
10478
10479static VALUE
10480rb_f_backquote(VALUE obj, VALUE str)
10481{
10482 VALUE port;
10483 VALUE result;
10484 rb_io_t *fptr;
10485
10486 SafeStringValue(str);
10487 rb_last_status_clear();
10488 port = pipe_open_s(str, "r", FMODE_READABLE|DEFAULT_TEXTMODE, NULL);
10489 if (NIL_P(port)) return rb_str_new(0,0);
10490
10491 GetOpenFile(port, fptr);
10492 result = read_all(fptr, remain_size(fptr), Qnil);
10493 rb_io_close(port);
10494 RFILE(port)->fptr = NULL;
10495 rb_io_fptr_finalize(fptr);
10496 RB_GC_GUARD(port);
10497
10498 return result;
10499}
10500
10501#ifdef HAVE_SYS_SELECT_H
10502#include <sys/select.h>
10503#endif
10504
10505static VALUE
10506select_internal(VALUE read, VALUE write, VALUE except, struct timeval *tp, rb_fdset_t *fds)
10507{
10508 VALUE res, list;
10509 rb_fdset_t *rp, *wp, *ep;
10510 rb_io_t *fptr;
10511 long i;
10512 int max = 0, n;
10513 int pending = 0;
10514 struct timeval timerec;
10515
10516 if (!NIL_P(read)) {
10517 Check_Type(read, T_ARRAY);
10518 for (i=0; i<RARRAY_LEN(read); i++) {
10519 GetOpenFile(rb_io_get_io(RARRAY_AREF(read, i)), fptr);
10520 rb_fd_set(fptr->fd, &fds[0]);
10521 if (READ_DATA_PENDING(fptr) || READ_CHAR_PENDING(fptr)) { /* check for buffered data */
10522 pending++;
10523 rb_fd_set(fptr->fd, &fds[3]);
10524 }
10525 if (max < fptr->fd) max = fptr->fd;
10526 }
10527 if (pending) { /* no blocking if there's buffered data */
10528 timerec.tv_sec = timerec.tv_usec = 0;
10529 tp = &timerec;
10530 }
10531 rp = &fds[0];
10532 }
10533 else
10534 rp = 0;
10535
10536 if (!NIL_P(write)) {
10537 Check_Type(write, T_ARRAY);
10538 for (i=0; i<RARRAY_LEN(write); i++) {
10539 VALUE write_io = GetWriteIO(rb_io_get_io(RARRAY_AREF(write, i)));
10540 GetOpenFile(write_io, fptr);
10541 rb_fd_set(fptr->fd, &fds[1]);
10542 if (max < fptr->fd) max = fptr->fd;
10543 }
10544 wp = &fds[1];
10545 }
10546 else
10547 wp = 0;
10548
10549 if (!NIL_P(except)) {
10550 Check_Type(except, T_ARRAY);
10551 for (i=0; i<RARRAY_LEN(except); i++) {
10552 VALUE io = rb_io_get_io(RARRAY_AREF(except, i));
10553 VALUE write_io = GetWriteIO(io);
10554 GetOpenFile(io, fptr);
10555 rb_fd_set(fptr->fd, &fds[2]);
10556 if (max < fptr->fd) max = fptr->fd;
10557 if (io != write_io) {
10558 GetOpenFile(write_io, fptr);
10559 rb_fd_set(fptr->fd, &fds[2]);
10560 if (max < fptr->fd) max = fptr->fd;
10561 }
10562 }
10563 ep = &fds[2];
10564 }
10565 else {
10566 ep = 0;
10567 }
10568
10569 max++;
10570
10571 n = rb_thread_fd_select(max, rp, wp, ep, tp);
10572 if (n < 0) {
10573 rb_sys_fail(0);
10574 }
10575 if (!pending && n == 0) return Qnil; /* returns nil on timeout */
10576
10577 res = rb_ary_new2(3);
10578 rb_ary_push(res, rp?rb_ary_new():rb_ary_new2(0));
10579 rb_ary_push(res, wp?rb_ary_new():rb_ary_new2(0));
10580 rb_ary_push(res, ep?rb_ary_new():rb_ary_new2(0));
10581
10582 if (rp) {
10583 list = RARRAY_AREF(res, 0);
10584 for (i=0; i< RARRAY_LEN(read); i++) {
10585 VALUE obj = rb_ary_entry(read, i);
10586 VALUE io = rb_io_get_io(obj);
10587 GetOpenFile(io, fptr);
10588 if (rb_fd_isset(fptr->fd, &fds[0]) ||
10589 rb_fd_isset(fptr->fd, &fds[3])) {
10590 rb_ary_push(list, obj);
10591 }
10592 }
10593 }
10594
10595 if (wp) {
10596 list = RARRAY_AREF(res, 1);
10597 for (i=0; i< RARRAY_LEN(write); i++) {
10598 VALUE obj = rb_ary_entry(write, i);
10599 VALUE io = rb_io_get_io(obj);
10600 VALUE write_io = GetWriteIO(io);
10601 GetOpenFile(write_io, fptr);
10602 if (rb_fd_isset(fptr->fd, &fds[1])) {
10603 rb_ary_push(list, obj);
10604 }
10605 }
10606 }
10607
10608 if (ep) {
10609 list = RARRAY_AREF(res, 2);
10610 for (i=0; i< RARRAY_LEN(except); i++) {
10611 VALUE obj = rb_ary_entry(except, i);
10612 VALUE io = rb_io_get_io(obj);
10613 VALUE write_io = GetWriteIO(io);
10614 GetOpenFile(io, fptr);
10615 if (rb_fd_isset(fptr->fd, &fds[2])) {
10616 rb_ary_push(list, obj);
10617 }
10618 else if (io != write_io) {
10619 GetOpenFile(write_io, fptr);
10620 if (rb_fd_isset(fptr->fd, &fds[2])) {
10621 rb_ary_push(list, obj);
10622 }
10623 }
10624 }
10625 }
10626
10627 return res; /* returns an empty array on interrupt */
10628}
10629
10631 VALUE read, write, except;
10632 struct timeval *timeout;
10633 rb_fdset_t fdsets[4];
10634};
10635
10636static VALUE
10637select_call(VALUE arg)
10638{
10639 struct select_args *p = (struct select_args *)arg;
10640
10641 return select_internal(p->read, p->write, p->except, p->timeout, p->fdsets);
10642}
10643
10644static VALUE
10645select_end(VALUE arg)
10646{
10647 struct select_args *p = (struct select_args *)arg;
10648 int i;
10649
10650 for (i = 0; i < numberof(p->fdsets); ++i)
10651 rb_fd_term(&p->fdsets[i]);
10652 return Qnil;
10653}
10654
10655static VALUE sym_normal, sym_sequential, sym_random,
10656 sym_willneed, sym_dontneed, sym_noreuse;
10657
10658#ifdef HAVE_POSIX_FADVISE
10659struct io_advise_struct {
10660 int fd;
10661 int advice;
10662 rb_off_t offset;
10663 rb_off_t len;
10664};
10665
10666static VALUE
10667io_advise_internal(void *arg)
10668{
10669 struct io_advise_struct *ptr = arg;
10670 return posix_fadvise(ptr->fd, ptr->offset, ptr->len, ptr->advice);
10671}
10672
10673static VALUE
10674io_advise_sym_to_const(VALUE sym)
10675{
10676#ifdef POSIX_FADV_NORMAL
10677 if (sym == sym_normal)
10678 return INT2NUM(POSIX_FADV_NORMAL);
10679#endif
10680
10681#ifdef POSIX_FADV_RANDOM
10682 if (sym == sym_random)
10683 return INT2NUM(POSIX_FADV_RANDOM);
10684#endif
10685
10686#ifdef POSIX_FADV_SEQUENTIAL
10687 if (sym == sym_sequential)
10688 return INT2NUM(POSIX_FADV_SEQUENTIAL);
10689#endif
10690
10691#ifdef POSIX_FADV_WILLNEED
10692 if (sym == sym_willneed)
10693 return INT2NUM(POSIX_FADV_WILLNEED);
10694#endif
10695
10696#ifdef POSIX_FADV_DONTNEED
10697 if (sym == sym_dontneed)
10698 return INT2NUM(POSIX_FADV_DONTNEED);
10699#endif
10700
10701#ifdef POSIX_FADV_NOREUSE
10702 if (sym == sym_noreuse)
10703 return INT2NUM(POSIX_FADV_NOREUSE);
10704#endif
10705
10706 return Qnil;
10707}
10708
10709static VALUE
10710do_io_advise(rb_io_t *fptr, VALUE advice, rb_off_t offset, rb_off_t len)
10711{
10712 int rv;
10713 struct io_advise_struct ias;
10714 VALUE num_adv;
10715
10716 num_adv = io_advise_sym_to_const(advice);
10717
10718 /*
10719 * The platform doesn't support this hint. We don't raise exception, instead
10720 * silently ignore it. Because IO::advise is only hint.
10721 */
10722 if (NIL_P(num_adv))
10723 return Qnil;
10724
10725 ias.fd = fptr->fd;
10726 ias.advice = NUM2INT(num_adv);
10727 ias.offset = offset;
10728 ias.len = len;
10729
10730 rv = (int)rb_thread_io_blocking_region(io_advise_internal, &ias, fptr->fd);
10731 if (rv && rv != ENOSYS) {
10732 /* posix_fadvise(2) doesn't set errno. On success it returns 0; otherwise
10733 it returns the error code. */
10734 VALUE message = rb_sprintf("%"PRIsVALUE" "
10735 "(%"PRI_OFFT_PREFIX"d, "
10736 "%"PRI_OFFT_PREFIX"d, "
10737 "%"PRIsVALUE")",
10738 fptr->pathv, offset, len, advice);
10739 rb_syserr_fail_str(rv, message);
10740 }
10741
10742 return Qnil;
10743}
10744
10745#endif /* HAVE_POSIX_FADVISE */
10746
10747static void
10748advice_arg_check(VALUE advice)
10749{
10750 if (!SYMBOL_P(advice))
10751 rb_raise(rb_eTypeError, "advice must be a Symbol");
10752
10753 if (advice != sym_normal &&
10754 advice != sym_sequential &&
10755 advice != sym_random &&
10756 advice != sym_willneed &&
10757 advice != sym_dontneed &&
10758 advice != sym_noreuse) {
10759 rb_raise(rb_eNotImpError, "Unsupported advice: %+"PRIsVALUE, advice);
10760 }
10761}
10762
10763/*
10764 * call-seq:
10765 * advise(advice, offset = 0, len = 0) -> nil
10766 *
10767 * Invokes Posix system call
10768 * {posix_fadvise(2)}[https://linux.die.net/man/2/posix_fadvise],
10769 * which announces an intention to access data from the current file
10770 * in a particular manner.
10771 *
10772 * The arguments and results are platform-dependent.
10773 *
10774 * The relevant data is specified by:
10775 *
10776 * - +offset+: The offset of the first byte of data.
10777 * - +len+: The number of bytes to be accessed;
10778 * if +len+ is zero, or is larger than the number of bytes remaining,
10779 * all remaining bytes will be accessed.
10780 *
10781 * Argument +advice+ is one of the following symbols:
10782 *
10783 * - +:normal+: The application has no advice to give
10784 * about its access pattern for the specified data.
10785 * If no advice is given for an open file, this is the default assumption.
10786 * - +:sequential+: The application expects to access the specified data sequentially
10787 * (with lower offsets read before higher ones).
10788 * - +:random+: The specified data will be accessed in random order.
10789 * - +:noreuse+: The specified data will be accessed only once.
10790 * - +:willneed+: The specified data will be accessed in the near future.
10791 * - +:dontneed+: The specified data will not be accessed in the near future.
10792 *
10793 * Not implemented on all platforms.
10794 *
10795 */
10796static VALUE
10797rb_io_advise(int argc, VALUE *argv, VALUE io)
10798{
10799 VALUE advice, offset, len;
10800 rb_off_t off, l;
10801 rb_io_t *fptr;
10802
10803 rb_scan_args(argc, argv, "12", &advice, &offset, &len);
10804 advice_arg_check(advice);
10805
10806 io = GetWriteIO(io);
10807 GetOpenFile(io, fptr);
10808
10809 off = NIL_P(offset) ? 0 : NUM2OFFT(offset);
10810 l = NIL_P(len) ? 0 : NUM2OFFT(len);
10811
10812#ifdef HAVE_POSIX_FADVISE
10813 return do_io_advise(fptr, advice, off, l);
10814#else
10815 ((void)off, (void)l); /* Ignore all hint */
10816 return Qnil;
10817#endif
10818}
10819
10820/*
10821 * call-seq:
10822 * IO.select(read_ios, write_ios = [], error_ios = [], timeout = nil) -> array or nil
10823 *
10824 * Invokes system call {select(2)}[https://linux.die.net/man/2/select],
10825 * which monitors multiple file descriptors,
10826 * waiting until one or more of the file descriptors
10827 * becomes ready for some class of I/O operation.
10828 *
10829 * Not implemented on all platforms.
10830 *
10831 * Each of the arguments +read_ios+, +write_ios+, and +error_ios+
10832 * is an array of IO objects.
10833 *
10834 * Argument +timeout+ is an integer timeout interval in seconds.
10835 *
10836 * The method monitors the \IO objects given in all three arrays,
10837 * waiting for some to be ready;
10838 * returns a 3-element array whose elements are:
10839 *
10840 * - An array of the objects in +read_ios+ that are ready for reading.
10841 * - An array of the objects in +write_ios+ that are ready for writing.
10842 * - An array of the objects in +error_ios+ have pending exceptions.
10843 *
10844 * If no object becomes ready within the given +timeout+, +nil+ is returned.
10845 *
10846 * \IO.select peeks the buffer of \IO objects for testing readability.
10847 * If the \IO buffer is not empty, \IO.select immediately notifies
10848 * readability. This "peek" only happens for \IO objects. It does not
10849 * happen for IO-like objects such as OpenSSL::SSL::SSLSocket.
10850 *
10851 * The best way to use \IO.select is invoking it after non-blocking
10852 * methods such as #read_nonblock, #write_nonblock, etc. The methods
10853 * raise an exception which is extended by IO::WaitReadable or
10854 * IO::WaitWritable. The modules notify how the caller should wait
10855 * with \IO.select. If IO::WaitReadable is raised, the caller should
10856 * wait for reading. If IO::WaitWritable is raised, the caller should
10857 * wait for writing.
10858 *
10859 * So, blocking read (#readpartial) can be emulated using
10860 * #read_nonblock and \IO.select as follows:
10861 *
10862 * begin
10863 * result = io_like.read_nonblock(maxlen)
10864 * rescue IO::WaitReadable
10865 * IO.select([io_like])
10866 * retry
10867 * rescue IO::WaitWritable
10868 * IO.select(nil, [io_like])
10869 * retry
10870 * end
10871 *
10872 * Especially, the combination of non-blocking methods and \IO.select is
10873 * preferred for IO like objects such as OpenSSL::SSL::SSLSocket. It
10874 * has #to_io method to return underlying IO object. IO.select calls
10875 * #to_io to obtain the file descriptor to wait.
10876 *
10877 * This means that readability notified by \IO.select doesn't mean
10878 * readability from OpenSSL::SSL::SSLSocket object.
10879 *
10880 * The most likely situation is that OpenSSL::SSL::SSLSocket buffers
10881 * some data. \IO.select doesn't see the buffer. So \IO.select can
10882 * block when OpenSSL::SSL::SSLSocket#readpartial doesn't block.
10883 *
10884 * However, several more complicated situations exist.
10885 *
10886 * SSL is a protocol which is sequence of records.
10887 * The record consists of multiple bytes.
10888 * So, the remote side of SSL sends a partial record, IO.select
10889 * notifies readability but OpenSSL::SSL::SSLSocket cannot decrypt a
10890 * byte and OpenSSL::SSL::SSLSocket#readpartial will block.
10891 *
10892 * Also, the remote side can request SSL renegotiation which forces
10893 * the local SSL engine to write some data.
10894 * This means OpenSSL::SSL::SSLSocket#readpartial may invoke #write
10895 * system call and it can block.
10896 * In such a situation, OpenSSL::SSL::SSLSocket#read_nonblock raises
10897 * IO::WaitWritable instead of blocking.
10898 * So, the caller should wait for ready for writability as above
10899 * example.
10900 *
10901 * The combination of non-blocking methods and \IO.select is also useful
10902 * for streams such as tty, pipe socket socket when multiple processes
10903 * read from a stream.
10904 *
10905 * Finally, Linux kernel developers don't guarantee that
10906 * readability of select(2) means readability of following read(2) even
10907 * for a single process;
10908 * see {select(2)}[https://linux.die.net/man/2/select]
10909 *
10910 * Invoking \IO.select before IO#readpartial works well as usual.
10911 * However it is not the best way to use \IO.select.
10912 *
10913 * The writability notified by select(2) doesn't show
10914 * how many bytes are writable.
10915 * IO#write method blocks until given whole string is written.
10916 * So, <tt>IO#write(two or more bytes)</tt> can block after
10917 * writability is notified by \IO.select. IO#write_nonblock is required
10918 * to avoid the blocking.
10919 *
10920 * Blocking write (#write) can be emulated using #write_nonblock and
10921 * IO.select as follows: IO::WaitReadable should also be rescued for
10922 * SSL renegotiation in OpenSSL::SSL::SSLSocket.
10923 *
10924 * while 0 < string.bytesize
10925 * begin
10926 * written = io_like.write_nonblock(string)
10927 * rescue IO::WaitReadable
10928 * IO.select([io_like])
10929 * retry
10930 * rescue IO::WaitWritable
10931 * IO.select(nil, [io_like])
10932 * retry
10933 * end
10934 * string = string.byteslice(written..-1)
10935 * end
10936 *
10937 * Example:
10938 *
10939 * rp, wp = IO.pipe
10940 * mesg = "ping "
10941 * 100.times {
10942 * # IO.select follows IO#read. Not the best way to use IO.select.
10943 * rs, ws, = IO.select([rp], [wp])
10944 * if r = rs[0]
10945 * ret = r.read(5)
10946 * print ret
10947 * case ret
10948 * when /ping/
10949 * mesg = "pong\n"
10950 * when /pong/
10951 * mesg = "ping "
10952 * end
10953 * end
10954 * if w = ws[0]
10955 * w.write(mesg)
10956 * end
10957 * }
10958 *
10959 * Output:
10960 *
10961 * ping pong
10962 * ping pong
10963 * ping pong
10964 * (snipped)
10965 * ping
10966 *
10967 */
10968
10969static VALUE
10970rb_f_select(int argc, VALUE *argv, VALUE obj)
10971{
10972 VALUE scheduler = rb_fiber_scheduler_current();
10973 if (scheduler != Qnil) {
10974 // It's optionally supported.
10975 VALUE result = rb_fiber_scheduler_io_selectv(scheduler, argc, argv);
10976 if (!UNDEF_P(result)) return result;
10977 }
10978
10979 VALUE timeout;
10980 struct select_args args;
10981 struct timeval timerec;
10982 int i;
10983
10984 rb_scan_args(argc, argv, "13", &args.read, &args.write, &args.except, &timeout);
10985 if (NIL_P(timeout)) {
10986 args.timeout = 0;
10987 }
10988 else {
10989 timerec = rb_time_interval(timeout);
10990 args.timeout = &timerec;
10991 }
10992
10993 for (i = 0; i < numberof(args.fdsets); ++i)
10994 rb_fd_init(&args.fdsets[i]);
10995
10996 return rb_ensure(select_call, (VALUE)&args, select_end, (VALUE)&args);
10997}
10998
10999#ifdef IOCTL_REQ_TYPE
11000 typedef IOCTL_REQ_TYPE ioctl_req_t;
11001#else
11002 typedef int ioctl_req_t;
11003# define NUM2IOCTLREQ(num) ((int)NUM2LONG(num))
11004#endif
11005
11006#ifdef HAVE_IOCTL
11007struct ioctl_arg {
11008 int fd;
11009 ioctl_req_t cmd;
11010 long narg;
11011};
11012
11013static VALUE
11014nogvl_ioctl(void *ptr)
11015{
11016 struct ioctl_arg *arg = ptr;
11017
11018 return (VALUE)ioctl(arg->fd, arg->cmd, arg->narg);
11019}
11020
11021static int
11022do_ioctl(int fd, ioctl_req_t cmd, long narg)
11023{
11024 int retval;
11025 struct ioctl_arg arg;
11026
11027 arg.fd = fd;
11028 arg.cmd = cmd;
11029 arg.narg = narg;
11030
11031 retval = (int)rb_thread_io_blocking_region(nogvl_ioctl, &arg, fd);
11032
11033 return retval;
11034}
11035#endif
11036
11037#define DEFAULT_IOCTL_NARG_LEN (256)
11038
11039#if defined(__linux__) && defined(_IOC_SIZE)
11040static long
11041linux_iocparm_len(ioctl_req_t cmd)
11042{
11043 long len;
11044
11045 if ((cmd & 0xFFFF0000) == 0) {
11046 /* legacy and unstructured ioctl number. */
11047 return DEFAULT_IOCTL_NARG_LEN;
11048 }
11049
11050 len = _IOC_SIZE(cmd);
11051
11052 /* paranoia check for silly drivers which don't keep ioctl convention */
11053 if (len < DEFAULT_IOCTL_NARG_LEN)
11054 len = DEFAULT_IOCTL_NARG_LEN;
11055
11056 return len;
11057}
11058#endif
11059
11060#ifdef HAVE_IOCTL
11061static long
11062ioctl_narg_len(ioctl_req_t cmd)
11063{
11064 long len;
11065
11066#ifdef IOCPARM_MASK
11067#ifndef IOCPARM_LEN
11068#define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK)
11069#endif
11070#endif
11071#ifdef IOCPARM_LEN
11072 len = IOCPARM_LEN(cmd); /* on BSDish systems we're safe */
11073#elif defined(__linux__) && defined(_IOC_SIZE)
11074 len = linux_iocparm_len(cmd);
11075#else
11076 /* otherwise guess at what's safe */
11077 len = DEFAULT_IOCTL_NARG_LEN;
11078#endif
11079
11080 return len;
11081}
11082#endif
11083
11084#ifdef HAVE_FCNTL
11085#ifdef __linux__
11086typedef long fcntl_arg_t;
11087#else
11088/* posix */
11089typedef int fcntl_arg_t;
11090#endif
11091
11092static long
11093fcntl_narg_len(ioctl_req_t cmd)
11094{
11095 long len;
11096
11097 switch (cmd) {
11098#ifdef F_DUPFD
11099 case F_DUPFD:
11100 len = sizeof(fcntl_arg_t);
11101 break;
11102#endif
11103#ifdef F_DUP2FD /* bsd specific */
11104 case F_DUP2FD:
11105 len = sizeof(int);
11106 break;
11107#endif
11108#ifdef F_DUPFD_CLOEXEC /* linux specific */
11109 case F_DUPFD_CLOEXEC:
11110 len = sizeof(fcntl_arg_t);
11111 break;
11112#endif
11113#ifdef F_GETFD
11114 case F_GETFD:
11115 len = 1;
11116 break;
11117#endif
11118#ifdef F_SETFD
11119 case F_SETFD:
11120 len = sizeof(fcntl_arg_t);
11121 break;
11122#endif
11123#ifdef F_GETFL
11124 case F_GETFL:
11125 len = 1;
11126 break;
11127#endif
11128#ifdef F_SETFL
11129 case F_SETFL:
11130 len = sizeof(fcntl_arg_t);
11131 break;
11132#endif
11133#ifdef F_GETOWN
11134 case F_GETOWN:
11135 len = 1;
11136 break;
11137#endif
11138#ifdef F_SETOWN
11139 case F_SETOWN:
11140 len = sizeof(fcntl_arg_t);
11141 break;
11142#endif
11143#ifdef F_GETOWN_EX /* linux specific */
11144 case F_GETOWN_EX:
11145 len = sizeof(struct f_owner_ex);
11146 break;
11147#endif
11148#ifdef F_SETOWN_EX /* linux specific */
11149 case F_SETOWN_EX:
11150 len = sizeof(struct f_owner_ex);
11151 break;
11152#endif
11153#ifdef F_GETLK
11154 case F_GETLK:
11155 len = sizeof(struct flock);
11156 break;
11157#endif
11158#ifdef F_SETLK
11159 case F_SETLK:
11160 len = sizeof(struct flock);
11161 break;
11162#endif
11163#ifdef F_SETLKW
11164 case F_SETLKW:
11165 len = sizeof(struct flock);
11166 break;
11167#endif
11168#ifdef F_READAHEAD /* bsd specific */
11169 case F_READAHEAD:
11170 len = sizeof(int);
11171 break;
11172#endif
11173#ifdef F_RDAHEAD /* Darwin specific */
11174 case F_RDAHEAD:
11175 len = sizeof(int);
11176 break;
11177#endif
11178#ifdef F_GETSIG /* linux specific */
11179 case F_GETSIG:
11180 len = 1;
11181 break;
11182#endif
11183#ifdef F_SETSIG /* linux specific */
11184 case F_SETSIG:
11185 len = sizeof(fcntl_arg_t);
11186 break;
11187#endif
11188#ifdef F_GETLEASE /* linux specific */
11189 case F_GETLEASE:
11190 len = 1;
11191 break;
11192#endif
11193#ifdef F_SETLEASE /* linux specific */
11194 case F_SETLEASE:
11195 len = sizeof(fcntl_arg_t);
11196 break;
11197#endif
11198#ifdef F_NOTIFY /* linux specific */
11199 case F_NOTIFY:
11200 len = sizeof(fcntl_arg_t);
11201 break;
11202#endif
11203
11204 default:
11205 len = 256;
11206 break;
11207 }
11208
11209 return len;
11210}
11211#else /* HAVE_FCNTL */
11212static long
11213fcntl_narg_len(ioctl_req_t cmd)
11214{
11215 return 0;
11216}
11217#endif /* HAVE_FCNTL */
11218
11219#define NARG_SENTINEL 17
11220
11221static long
11222setup_narg(ioctl_req_t cmd, VALUE *argp, long (*narg_len)(ioctl_req_t))
11223{
11224 long narg = 0;
11225 VALUE arg = *argp;
11226
11227 if (!RTEST(arg)) {
11228 narg = 0;
11229 }
11230 else if (FIXNUM_P(arg)) {
11231 narg = FIX2LONG(arg);
11232 }
11233 else if (arg == Qtrue) {
11234 narg = 1;
11235 }
11236 else {
11237 VALUE tmp = rb_check_string_type(arg);
11238
11239 if (NIL_P(tmp)) {
11240 narg = NUM2LONG(arg);
11241 }
11242 else {
11243 char *ptr;
11244 long len, slen;
11245
11246 *argp = arg = tmp;
11247 len = narg_len(cmd);
11248 rb_str_modify(arg);
11249
11250 slen = RSTRING_LEN(arg);
11251 /* expand for data + sentinel. */
11252 if (slen < len+1) {
11253 rb_str_resize(arg, len+1);
11254 MEMZERO(RSTRING_PTR(arg)+slen, char, len-slen);
11255 slen = len+1;
11256 }
11257 /* a little sanity check here */
11258 ptr = RSTRING_PTR(arg);
11259 ptr[slen - 1] = NARG_SENTINEL;
11260 narg = (long)(SIGNED_VALUE)ptr;
11261 }
11262 }
11263
11264 return narg;
11265}
11266
11267static VALUE
11268finish_narg(int retval, VALUE arg, const rb_io_t *fptr)
11269{
11270 if (retval < 0) rb_sys_fail_path(fptr->pathv);
11271 if (RB_TYPE_P(arg, T_STRING)) {
11272 char *ptr;
11273 long slen;
11274 RSTRING_GETMEM(arg, ptr, slen);
11275 if (ptr[slen-1] != NARG_SENTINEL)
11276 rb_raise(rb_eArgError, "return value overflowed string");
11277 ptr[slen-1] = '\0';
11278 }
11279
11280 return INT2NUM(retval);
11281}
11282
11283#ifdef HAVE_IOCTL
11284static VALUE
11285rb_ioctl(VALUE io, VALUE req, VALUE arg)
11286{
11287 ioctl_req_t cmd = NUM2IOCTLREQ(req);
11288 rb_io_t *fptr;
11289 long narg;
11290 int retval;
11291
11292 narg = setup_narg(cmd, &arg, ioctl_narg_len);
11293 GetOpenFile(io, fptr);
11294 retval = do_ioctl(fptr->fd, cmd, narg);
11295 return finish_narg(retval, arg, fptr);
11296}
11297
11298/*
11299 * call-seq:
11300 * ioctl(integer_cmd, argument) -> integer
11301 *
11302 * Invokes Posix system call {ioctl(2)}[https://linux.die.net/man/2/ioctl],
11303 * which issues a low-level command to an I/O device.
11304 *
11305 * Issues a low-level command to an I/O device.
11306 * The arguments and returned value are platform-dependent.
11307 * The effect of the call is platform-dependent.
11308 *
11309 * If argument +argument+ is an integer, it is passed directly;
11310 * if it is a string, it is interpreted as a binary sequence of bytes.
11311 *
11312 * Not implemented on all platforms.
11313 *
11314 */
11315
11316static VALUE
11317rb_io_ioctl(int argc, VALUE *argv, VALUE io)
11318{
11319 VALUE req, arg;
11320
11321 rb_scan_args(argc, argv, "11", &req, &arg);
11322 return rb_ioctl(io, req, arg);
11323}
11324#else
11325#define rb_io_ioctl rb_f_notimplement
11326#endif
11327
11328#ifdef HAVE_FCNTL
11329struct fcntl_arg {
11330 int fd;
11331 int cmd;
11332 long narg;
11333};
11334
11335static VALUE
11336nogvl_fcntl(void *ptr)
11337{
11338 struct fcntl_arg *arg = ptr;
11339
11340#if defined(F_DUPFD)
11341 if (arg->cmd == F_DUPFD)
11342 return (VALUE)rb_cloexec_fcntl_dupfd(arg->fd, (int)arg->narg);
11343#endif
11344 return (VALUE)fcntl(arg->fd, arg->cmd, arg->narg);
11345}
11346
11347static int
11348do_fcntl(int fd, int cmd, long narg)
11349{
11350 int retval;
11351 struct fcntl_arg arg;
11352
11353 arg.fd = fd;
11354 arg.cmd = cmd;
11355 arg.narg = narg;
11356
11357 retval = (int)rb_thread_io_blocking_region(nogvl_fcntl, &arg, fd);
11358 if (retval != -1) {
11359 switch (cmd) {
11360#if defined(F_DUPFD)
11361 case F_DUPFD:
11362#endif
11363#if defined(F_DUPFD_CLOEXEC)
11364 case F_DUPFD_CLOEXEC:
11365#endif
11366 rb_update_max_fd(retval);
11367 }
11368 }
11369
11370 return retval;
11371}
11372
11373static VALUE
11374rb_fcntl(VALUE io, VALUE req, VALUE arg)
11375{
11376 int cmd = NUM2INT(req);
11377 rb_io_t *fptr;
11378 long narg;
11379 int retval;
11380
11381 narg = setup_narg(cmd, &arg, fcntl_narg_len);
11382 GetOpenFile(io, fptr);
11383 retval = do_fcntl(fptr->fd, cmd, narg);
11384 return finish_narg(retval, arg, fptr);
11385}
11386
11387/*
11388 * call-seq:
11389 * fcntl(integer_cmd, argument) -> integer
11390 *
11391 * Invokes Posix system call {fcntl(2)}[https://linux.die.net/man/2/fcntl],
11392 * which provides a mechanism for issuing low-level commands to control or query
11393 * a file-oriented I/O stream. Arguments and results are platform
11394 * dependent.
11395 *
11396 * If +argument is a number, its value is passed directly;
11397 * if it is a string, it is interpreted as a binary sequence of bytes.
11398 * (Array#pack might be a useful way to build this string.)
11399 *
11400 * Not implemented on all platforms.
11401 *
11402 */
11403
11404static VALUE
11405rb_io_fcntl(int argc, VALUE *argv, VALUE io)
11406{
11407 VALUE req, arg;
11408
11409 rb_scan_args(argc, argv, "11", &req, &arg);
11410 return rb_fcntl(io, req, arg);
11411}
11412#else
11413#define rb_io_fcntl rb_f_notimplement
11414#endif
11415
11416#if defined(HAVE_SYSCALL) || defined(HAVE___SYSCALL)
11417/*
11418 * call-seq:
11419 * syscall(integer_callno, *arguments) -> integer
11420 *
11421 * Invokes Posix system call {syscall(2)}[https://linux.die.net/man/2/syscall],
11422 * which calls a specified function.
11423 *
11424 * Calls the operating system function identified by +integer_callno+;
11425 * returns the result of the function or raises SystemCallError if it failed.
11426 * The effect of the call is platform-dependent.
11427 * The arguments and returned value are platform-dependent.
11428 *
11429 * For each of +arguments+: if it is an integer, it is passed directly;
11430 * if it is a string, it is interpreted as a binary sequence of bytes.
11431 * There may be as many as nine such arguments.
11432 *
11433 * Arguments +integer_callno+ and +argument+, as well as the returned value,
11434 * are platform-dependent.
11435 *
11436 * Note: Method +syscall+ is essentially unsafe and unportable.
11437 * The DL (Fiddle) library is preferred for safer and a bit
11438 * more portable programming.
11439 *
11440 * Not implemented on all platforms.
11441 *
11442 */
11443
11444static VALUE
11445rb_f_syscall(int argc, VALUE *argv, VALUE _)
11446{
11447 VALUE arg[8];
11448#if SIZEOF_VOIDP == 8 && defined(HAVE___SYSCALL) && SIZEOF_INT != 8 /* mainly *BSD */
11449# define SYSCALL __syscall
11450# define NUM2SYSCALLID(x) NUM2LONG(x)
11451# define RETVAL2NUM(x) LONG2NUM(x)
11452# if SIZEOF_LONG == 8
11453 long num, retval = -1;
11454# elif SIZEOF_LONG_LONG == 8
11455 long long num, retval = -1;
11456# else
11457# error ---->> it is asserted that __syscall takes the first argument and returns retval in 64bit signed integer. <<----
11458# endif
11459#elif defined(__linux__)
11460# define SYSCALL syscall
11461# define NUM2SYSCALLID(x) NUM2LONG(x)
11462# define RETVAL2NUM(x) LONG2NUM(x)
11463 /*
11464 * Linux man page says, syscall(2) function prototype is below.
11465 *
11466 * int syscall(int number, ...);
11467 *
11468 * But, it's incorrect. Actual one takes and returned long. (see unistd.h)
11469 */
11470 long num, retval = -1;
11471#else
11472# define SYSCALL syscall
11473# define NUM2SYSCALLID(x) NUM2INT(x)
11474# define RETVAL2NUM(x) INT2NUM(x)
11475 int num, retval = -1;
11476#endif
11477 int i;
11478
11479 if (RTEST(ruby_verbose)) {
11481 "We plan to remove a syscall function at future release. DL(Fiddle) provides safer alternative.");
11482 }
11483
11484 if (argc == 0)
11485 rb_raise(rb_eArgError, "too few arguments for syscall");
11486 if (argc > numberof(arg))
11487 rb_raise(rb_eArgError, "too many arguments for syscall");
11488 num = NUM2SYSCALLID(argv[0]); ++argv;
11489 for (i = argc - 1; i--; ) {
11490 VALUE v = rb_check_string_type(argv[i]);
11491
11492 if (!NIL_P(v)) {
11493 SafeStringValue(v);
11494 rb_str_modify(v);
11495 arg[i] = (VALUE)StringValueCStr(v);
11496 }
11497 else {
11498 arg[i] = (VALUE)NUM2LONG(argv[i]);
11499 }
11500 }
11501
11502 switch (argc) {
11503 case 1:
11504 retval = SYSCALL(num);
11505 break;
11506 case 2:
11507 retval = SYSCALL(num, arg[0]);
11508 break;
11509 case 3:
11510 retval = SYSCALL(num, arg[0],arg[1]);
11511 break;
11512 case 4:
11513 retval = SYSCALL(num, arg[0],arg[1],arg[2]);
11514 break;
11515 case 5:
11516 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3]);
11517 break;
11518 case 6:
11519 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4]);
11520 break;
11521 case 7:
11522 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5]);
11523 break;
11524 case 8:
11525 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6]);
11526 break;
11527 }
11528
11529 if (retval == -1)
11530 rb_sys_fail(0);
11531 return RETVAL2NUM(retval);
11532#undef SYSCALL
11533#undef NUM2SYSCALLID
11534#undef RETVAL2NUM
11535}
11536#else
11537#define rb_f_syscall rb_f_notimplement
11538#endif
11539
11540static VALUE
11541io_new_instance(VALUE args)
11542{
11543 return rb_class_new_instance(2, (VALUE*)args+1, *(VALUE*)args);
11544}
11545
11546static rb_encoding *
11547find_encoding(VALUE v)
11548{
11549 rb_encoding *enc = rb_find_encoding(v);
11550 if (!enc) rb_warn("Unsupported encoding %"PRIsVALUE" ignored", v);
11551 return enc;
11552}
11553
11554static void
11555io_encoding_set(rb_io_t *fptr, VALUE v1, VALUE v2, VALUE opt)
11556{
11557 rb_encoding *enc, *enc2;
11558 int ecflags = fptr->encs.ecflags;
11559 VALUE ecopts, tmp;
11560
11561 if (!NIL_P(v2)) {
11562 enc2 = find_encoding(v1);
11563 tmp = rb_check_string_type(v2);
11564 if (!NIL_P(tmp)) {
11565 if (RSTRING_LEN(tmp) == 1 && RSTRING_PTR(tmp)[0] == '-') {
11566 /* Special case - "-" => no transcoding */
11567 enc = enc2;
11568 enc2 = NULL;
11569 }
11570 else
11571 enc = find_encoding(v2);
11572 if (enc == enc2) {
11573 /* Special case - "-" => no transcoding */
11574 enc2 = NULL;
11575 }
11576 }
11577 else {
11578 enc = find_encoding(v2);
11579 if (enc == enc2) {
11580 /* Special case - "-" => no transcoding */
11581 enc2 = NULL;
11582 }
11583 }
11584 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11585 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
11586 }
11587 else {
11588 if (NIL_P(v1)) {
11589 /* Set to default encodings */
11590 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
11591 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11592 ecopts = Qnil;
11593 }
11594 else {
11595 tmp = rb_check_string_type(v1);
11596 if (!NIL_P(tmp) && rb_enc_asciicompat(enc = rb_enc_get(tmp))) {
11597 parse_mode_enc(RSTRING_PTR(tmp), enc, &enc, &enc2, NULL);
11598 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11599 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
11600 }
11601 else {
11602 rb_io_ext_int_to_encs(find_encoding(v1), NULL, &enc, &enc2, 0);
11603 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11604 ecopts = Qnil;
11605 }
11606 }
11607 }
11608 validate_enc_binmode(&fptr->mode, ecflags, enc, enc2);
11609 fptr->encs.enc = enc;
11610 fptr->encs.enc2 = enc2;
11611 fptr->encs.ecflags = ecflags;
11612 fptr->encs.ecopts = ecopts;
11613 clear_codeconv(fptr);
11614
11615}
11616
11618 rb_io_t *fptr;
11619 VALUE v1;
11620 VALUE v2;
11621 VALUE opt;
11622};
11623
11624static VALUE
11625io_encoding_set_v(VALUE v)
11626{
11627 struct io_encoding_set_args *arg = (struct io_encoding_set_args *)v;
11628 io_encoding_set(arg->fptr, arg->v1, arg->v2, arg->opt);
11629 return Qnil;
11630}
11631
11632static VALUE
11633pipe_pair_close(VALUE rw)
11634{
11635 VALUE *rwp = (VALUE *)rw;
11636 return rb_ensure(io_close, rwp[0], io_close, rwp[1]);
11637}
11638
11639/*
11640 * call-seq:
11641 * IO.pipe(**opts) -> [read_io, write_io]
11642 * IO.pipe(enc, **opts) -> [read_io, write_io]
11643 * IO.pipe(ext_enc, int_enc, **opts) -> [read_io, write_io]
11644 * IO.pipe(**opts) {|read_io, write_io] ...} -> object
11645 * IO.pipe(enc, **opts) {|read_io, write_io] ...} -> object
11646 * IO.pipe(ext_enc, int_enc, **opts) {|read_io, write_io] ...} -> object
11647 *
11648 * Creates a pair of pipe endpoints, +read_io+ and +write_io+,
11649 * connected to each other.
11650 *
11651 * If argument +enc_string+ is given, it must be a string containing one of:
11652 *
11653 * - The name of the encoding to be used as the external encoding.
11654 * - The colon-separated names of two encodings to be used as the external
11655 * and internal encodings.
11656 *
11657 * If argument +int_enc+ is given, it must be an Encoding object
11658 * or encoding name string that specifies the internal encoding to be used;
11659 * if argument +ext_enc+ is also given, it must be an Encoding object
11660 * or encoding name string that specifies the external encoding to be used.
11661 *
11662 * The string read from +read_io+ is tagged with the external encoding;
11663 * if an internal encoding is also specified, the string is converted
11664 * to, and tagged with, that encoding.
11665 *
11666 * If any encoding is specified,
11667 * optional hash arguments specify the conversion option.
11668 *
11669 * Optional keyword arguments +opts+ specify:
11670 *
11671 * - {Open Options}[rdoc-ref:IO@Open+Options].
11672 * - {Encoding Options}[rdoc-ref:encodings.rdoc@Encoding+Options].
11673 *
11674 * With no block given, returns the two endpoints in an array:
11675 *
11676 * IO.pipe # => [#<IO:fd 4>, #<IO:fd 5>]
11677 *
11678 * With a block given, calls the block with the two endpoints;
11679 * closes both endpoints and returns the value of the block:
11680 *
11681 * IO.pipe {|read_io, write_io| p read_io; p write_io }
11682 *
11683 * Output:
11684 *
11685 * #<IO:fd 6>
11686 * #<IO:fd 7>
11687 *
11688 * Not available on all platforms.
11689 *
11690 * In the example below, the two processes close the ends of the pipe
11691 * that they are not using. This is not just a cosmetic nicety. The
11692 * read end of a pipe will not generate an end of file condition if
11693 * there are any writers with the pipe still open. In the case of the
11694 * parent process, the <tt>rd.read</tt> will never return if it
11695 * does not first issue a <tt>wr.close</tt>:
11696 *
11697 * rd, wr = IO.pipe
11698 *
11699 * if fork
11700 * wr.close
11701 * puts "Parent got: <#{rd.read}>"
11702 * rd.close
11703 * Process.wait
11704 * else
11705 * rd.close
11706 * puts 'Sending message to parent'
11707 * wr.write "Hi Dad"
11708 * wr.close
11709 * end
11710 *
11711 * <em>produces:</em>
11712 *
11713 * Sending message to parent
11714 * Parent got: <Hi Dad>
11715 *
11716 */
11717
11718static VALUE
11719rb_io_s_pipe(int argc, VALUE *argv, VALUE klass)
11720{
11721 int pipes[2], state;
11722 VALUE r, w, args[3], v1, v2;
11723 VALUE opt;
11724 rb_io_t *fptr, *fptr2;
11725 struct io_encoding_set_args ies_args;
11726 int fmode = 0;
11727 VALUE ret;
11728
11729 argc = rb_scan_args(argc, argv, "02:", &v1, &v2, &opt);
11730 if (rb_pipe(pipes) < 0)
11731 rb_sys_fail(0);
11732
11733 args[0] = klass;
11734 args[1] = INT2NUM(pipes[0]);
11735 args[2] = INT2FIX(O_RDONLY);
11736 r = rb_protect(io_new_instance, (VALUE)args, &state);
11737 if (state) {
11738 close(pipes[0]);
11739 close(pipes[1]);
11740 rb_jump_tag(state);
11741 }
11742 GetOpenFile(r, fptr);
11743
11744 ies_args.fptr = fptr;
11745 ies_args.v1 = v1;
11746 ies_args.v2 = v2;
11747 ies_args.opt = opt;
11748 rb_protect(io_encoding_set_v, (VALUE)&ies_args, &state);
11749 if (state) {
11750 close(pipes[1]);
11751 io_close(r);
11752 rb_jump_tag(state);
11753 }
11754
11755 args[1] = INT2NUM(pipes[1]);
11756 args[2] = INT2FIX(O_WRONLY);
11757 w = rb_protect(io_new_instance, (VALUE)args, &state);
11758 if (state) {
11759 close(pipes[1]);
11760 if (!NIL_P(r)) rb_io_close(r);
11761 rb_jump_tag(state);
11762 }
11763 GetOpenFile(w, fptr2);
11764 rb_io_synchronized(fptr2);
11765
11766 extract_binmode(opt, &fmode);
11767
11768 if ((fmode & FMODE_BINMODE) && NIL_P(v1)) {
11771 }
11772
11773#if DEFAULT_TEXTMODE
11774 if ((fptr->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
11775 fptr->mode &= ~FMODE_TEXTMODE;
11776 setmode(fptr->fd, O_BINARY);
11777 }
11778#if RUBY_CRLF_ENVIRONMENT
11781 }
11782#endif
11783#endif
11784 fptr->mode |= fmode;
11785#if DEFAULT_TEXTMODE
11786 if ((fptr2->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
11787 fptr2->mode &= ~FMODE_TEXTMODE;
11788 setmode(fptr2->fd, O_BINARY);
11789 }
11790#endif
11791 fptr2->mode |= fmode;
11792
11793 ret = rb_assoc_new(r, w);
11794 if (rb_block_given_p()) {
11795 VALUE rw[2];
11796 rw[0] = r;
11797 rw[1] = w;
11798 return rb_ensure(rb_yield, ret, pipe_pair_close, (VALUE)rw);
11799 }
11800 return ret;
11801}
11802
11804 int argc;
11805 VALUE *argv;
11806 VALUE io;
11807};
11808
11809static void
11810open_key_args(VALUE klass, int argc, VALUE *argv, VALUE opt, struct foreach_arg *arg)
11811{
11812 VALUE path, v;
11813 VALUE vmode = Qnil, vperm = Qnil;
11814
11815 path = *argv++;
11816 argc--;
11817 FilePathValue(path);
11818 arg->io = 0;
11819 arg->argc = argc;
11820 arg->argv = argv;
11821 if (NIL_P(opt)) {
11822 vmode = INT2NUM(O_RDONLY);
11823 vperm = INT2FIX(0666);
11824 }
11825 else if (!NIL_P(v = rb_hash_aref(opt, sym_open_args))) {
11826 int n;
11827
11828 v = rb_to_array_type(v);
11829 n = RARRAY_LENINT(v);
11830 rb_check_arity(n, 0, 3); /* rb_io_open */
11831 rb_scan_args_kw(RB_SCAN_ARGS_LAST_HASH_KEYWORDS, n, RARRAY_CONST_PTR(v), "02:", &vmode, &vperm, &opt);
11832 }
11833 arg->io = rb_io_open(klass, path, vmode, vperm, opt);
11834}
11835
11836static VALUE
11837io_s_foreach(VALUE v)
11838{
11839 struct getline_arg *arg = (void *)v;
11840 VALUE str;
11841
11842 if (arg->limit == 0)
11843 rb_raise(rb_eArgError, "invalid limit: 0 for foreach");
11844 while (!NIL_P(str = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, arg->io))) {
11845 rb_lastline_set(str);
11846 rb_yield(str);
11847 }
11849 return Qnil;
11850}
11851
11852/*
11853 * call-seq:
11854 * IO.foreach(path, sep = $/, **opts) {|line| block } -> nil
11855 * IO.foreach(path, limit, **opts) {|line| block } -> nil
11856 * IO.foreach(path, sep, limit, **opts) {|line| block } -> nil
11857 * IO.foreach(command, sep = $/, **opts) {|line| block } -> nil
11858 * IO.foreach(command, limit, **opts) {|line| block } -> nil
11859 * IO.foreach(command, sep, limit, **opts) {|line| block } -> nil
11860 * IO.foreach(...) -> an_enumerator
11861 *
11862 * Calls the block with each successive line read from the stream.
11863 *
11864 * When called from class \IO (but not subclasses of \IO),
11865 * this method has potential security vulnerabilities if called with untrusted input;
11866 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
11867 *
11868 * The first argument must be a string that is one of the following:
11869 *
11870 * - Path: if +self+ is a subclass of \IO (\File, for example),
11871 * or if the string _does_ _not_ start with the pipe character (<tt>'|'</tt>),
11872 * the string is the path to a file.
11873 * - Command: if +self+ is the class \IO,
11874 * and if the string starts with the pipe character,
11875 * the rest of the string is a command to be executed as a subprocess.
11876 * This usage has potential security vulnerabilities if called with untrusted input;
11877 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
11878 *
11879 * With only argument +path+ given, parses lines from the file at the given +path+,
11880 * as determined by the default line separator,
11881 * and calls the block with each successive line:
11882 *
11883 * File.foreach('t.txt') {|line| p line }
11884 *
11885 * Output: the same as above.
11886 *
11887 * For both forms, command and path, the remaining arguments are the same.
11888 *
11889 * With argument +sep+ given, parses lines as determined by that line separator
11890 * (see {Line Separator}[rdoc-ref:IO@Line+Separator]):
11891 *
11892 * File.foreach('t.txt', 'li') {|line| p line }
11893 *
11894 * Output:
11895 *
11896 * "First li"
11897 * "ne\nSecond li"
11898 * "ne\n\nThird li"
11899 * "ne\nFourth li"
11900 * "ne\n"
11901 *
11902 * Each paragraph:
11903 *
11904 * File.foreach('t.txt', '') {|paragraph| p paragraph }
11905 *
11906 * Output:
11907 *
11908 * "First line\nSecond line\n\n"
11909 * "Third line\nFourth line\n"
11910 *
11911 * With argument +limit+ given, parses lines as determined by the default
11912 * line separator and the given line-length limit
11913 * (see {Line Limit}[rdoc-ref:IO@Line+Limit]):
11914 *
11915 * File.foreach('t.txt', 7) {|line| p line }
11916 *
11917 * Output:
11918 *
11919 * "First l"
11920 * "ine\n"
11921 * "Second "
11922 * "line\n"
11923 * "\n"
11924 * "Third l"
11925 * "ine\n"
11926 * "Fourth l"
11927 * "line\n"
11928 *
11929 * With arguments +sep+ and +limit+ given,
11930 * parses lines as determined by the given
11931 * line separator and the given line-length limit
11932 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]):
11933 *
11934 * Optional keyword arguments +opts+ specify:
11935 *
11936 * - {Open Options}[rdoc-ref:IO@Open+Options].
11937 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
11938 * - {Line Options}[rdoc-ref:IO@Line+Options].
11939 *
11940 * Returns an Enumerator if no block is given.
11941 *
11942 */
11943
11944static VALUE
11945rb_io_s_foreach(int argc, VALUE *argv, VALUE self)
11946{
11947 VALUE opt;
11948 int orig_argc = argc;
11949 struct foreach_arg arg;
11950 struct getline_arg garg;
11951
11952 argc = rb_scan_args(argc, argv, "12:", NULL, NULL, NULL, &opt);
11953 RETURN_ENUMERATOR(self, orig_argc, argv);
11954 extract_getline_args(argc-1, argv+1, &garg);
11955 open_key_args(self, argc, argv, opt, &arg);
11956 if (NIL_P(arg.io)) return Qnil;
11957 extract_getline_opts(opt, &garg);
11958 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
11959 return rb_ensure(io_s_foreach, (VALUE)&garg, rb_io_close, arg.io);
11960}
11961
11962static VALUE
11963io_s_readlines(VALUE v)
11964{
11965 struct getline_arg *arg = (void *)v;
11966 return io_readlines(arg, arg->io);
11967}
11968
11969/*
11970 * call-seq:
11971 * IO.readlines(command, sep = $/, **opts) -> array
11972 * IO.readlines(command, limit, **opts) -> array
11973 * IO.readlines(command, sep, limit, **opts) -> array
11974 * IO.readlines(path, sep = $/, **opts) -> array
11975 * IO.readlines(path, limit, **opts) -> array
11976 * IO.readlines(path, sep, limit, **opts) -> array
11977 *
11978 * Returns an array of all lines read from the stream.
11979 *
11980 * When called from class \IO (but not subclasses of \IO),
11981 * this method has potential security vulnerabilities if called with untrusted input;
11982 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
11983 *
11984 * The first argument must be a string;
11985 * its meaning depends on whether it starts with the pipe character (<tt>'|'</tt>):
11986 *
11987 * - If so (and if +self+ is \IO),
11988 * the rest of the string is a command to be executed as a subprocess.
11989 * - Otherwise, the string is the path to a file.
11990 *
11991 * With only argument +command+ given, executes the command in a shell,
11992 * parses its $stdout into lines, as determined by the default line separator,
11993 * and returns those lines in an array:
11994 *
11995 * IO.readlines('| cat t.txt')
11996 * # => ["First line\n", "Second line\n", "\n", "Third line\n", "Fourth line\n"]
11997 *
11998 * With only argument +path+ given, parses lines from the file at the given +path+,
11999 * as determined by the default line separator,
12000 * and returns those lines in an array:
12001 *
12002 * IO.readlines('t.txt')
12003 * # => ["First line\n", "Second line\n", "\n", "Third line\n", "Fourth line\n"]
12004 *
12005 * For both forms, command and path, the remaining arguments are the same.
12006 *
12007 * With argument +sep+ given, parses lines as determined by that line separator
12008 * (see {Line Separator}[rdoc-ref:IO@Line+Separator]):
12009 *
12010 * # Ordinary separator.
12011 * IO.readlines('t.txt', 'li')
12012 * # =>["First li", "ne\nSecond li", "ne\n\nThird li", "ne\nFourth li", "ne\n"]
12013 * # Get-paragraphs separator.
12014 * IO.readlines('t.txt', '')
12015 * # => ["First line\nSecond line\n\n", "Third line\nFourth line\n"]
12016 * # Get-all separator.
12017 * IO.readlines('t.txt', nil)
12018 * # => ["First line\nSecond line\n\nThird line\nFourth line\n"]
12019 *
12020 * With argument +limit+ given, parses lines as determined by the default
12021 * line separator and the given line-length limit
12022 * (see {Line Limit}[rdoc-ref:IO@Line+Limit]):
12023 *
12024 * IO.readlines('t.txt', 7)
12025 * # => ["First l", "ine\n", "Second ", "line\n", "\n", "Third l", "ine\n", "Fourth ", "line\n"]
12026 *
12027 * With arguments +sep+ and +limit+ given,
12028 * parses lines as determined by the given
12029 * line separator and the given line-length limit
12030 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]):
12031 *
12032 * Optional keyword arguments +opts+ specify:
12033 *
12034 * - {Open Options}[rdoc-ref:IO@Open+Options].
12035 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12036 * - {Line Options}[rdoc-ref:IO@Line+Options].
12037 *
12038 */
12039
12040static VALUE
12041rb_io_s_readlines(int argc, VALUE *argv, VALUE io)
12042{
12043 VALUE opt;
12044 struct foreach_arg arg;
12045 struct getline_arg garg;
12046
12047 argc = rb_scan_args(argc, argv, "12:", NULL, NULL, NULL, &opt);
12048 extract_getline_args(argc-1, argv+1, &garg);
12049 open_key_args(io, argc, argv, opt, &arg);
12050 if (NIL_P(arg.io)) return Qnil;
12051 extract_getline_opts(opt, &garg);
12052 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12053 return rb_ensure(io_s_readlines, (VALUE)&garg, rb_io_close, arg.io);
12054}
12055
12056static VALUE
12057io_s_read(VALUE v)
12058{
12059 struct foreach_arg *arg = (void *)v;
12060 return io_read(arg->argc, arg->argv, arg->io);
12061}
12062
12063struct seek_arg {
12064 VALUE io;
12065 VALUE offset;
12066 int mode;
12067};
12068
12069static VALUE
12070seek_before_access(VALUE argp)
12071{
12072 struct seek_arg *arg = (struct seek_arg *)argp;
12073 rb_io_binmode(arg->io);
12074 return rb_io_seek(arg->io, arg->offset, arg->mode);
12075}
12076
12077/*
12078 * call-seq:
12079 * IO.read(command, length = nil, offset = 0, **opts) -> string or nil
12080 * IO.read(path, length = nil, offset = 0, **opts) -> string or nil
12081 *
12082 * Opens the stream, reads and returns some or all of its content,
12083 * and closes the stream; returns +nil+ if no bytes were read.
12084 *
12085 * When called from class \IO (but not subclasses of \IO),
12086 * this method has potential security vulnerabilities if called with untrusted input;
12087 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12088 *
12089 * The first argument must be a string;
12090 * its meaning depends on whether it starts with the pipe character (<tt>'|'</tt>):
12091 *
12092 * - If so (and if +self+ is \IO),
12093 * the rest of the string is a command to be executed as a subprocess.
12094 * - Otherwise, the string is the path to a file.
12095 *
12096 * With only argument +command+ given, executes the command in a shell,
12097 * returns its entire $stdout:
12098 *
12099 * IO.read('| cat t.txt')
12100 * # => "First line\nSecond line\n\nThird line\nFourth line\n"
12101 *
12102 * With only argument +path+ given, reads in text mode and returns the entire content
12103 * of the file at the given path:
12104 *
12105 * IO.read('t.txt')
12106 * # => "First line\nSecond line\n\nThird line\nFourth line\n"
12107 *
12108 * On Windows, text mode can terminate reading and leave bytes in the file
12109 * unread when encountering certain special bytes. Consider using
12110 * IO.binread if all bytes in the file should be read.
12111 *
12112 * For both forms, command and path, the remaining arguments are the same.
12113 *
12114 * With argument +length+, returns +length+ bytes if available:
12115 *
12116 * IO.read('t.txt', 7) # => "First l"
12117 * IO.read('t.txt', 700)
12118 * # => "First line\r\nSecond line\r\n\r\nFourth line\r\nFifth line\r\n"
12119 *
12120 * With arguments +length+ and +offset+, returns +length+ bytes
12121 * if available, beginning at the given +offset+:
12122 *
12123 * IO.read('t.txt', 10, 2) # => "rst line\nS"
12124 * IO.read('t.txt', 10, 200) # => nil
12125 *
12126 * Optional keyword arguments +opts+ specify:
12127 *
12128 * - {Open Options}[rdoc-ref:IO@Open+Options].
12129 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12130 *
12131 */
12132
12133static VALUE
12134rb_io_s_read(int argc, VALUE *argv, VALUE io)
12135{
12136 VALUE opt, offset;
12137 struct foreach_arg arg;
12138
12139 argc = rb_scan_args(argc, argv, "13:", NULL, NULL, &offset, NULL, &opt);
12140 open_key_args(io, argc, argv, opt, &arg);
12141 if (NIL_P(arg.io)) return Qnil;
12142 if (!NIL_P(offset)) {
12143 struct seek_arg sarg;
12144 int state = 0;
12145 sarg.io = arg.io;
12146 sarg.offset = offset;
12147 sarg.mode = SEEK_SET;
12148 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12149 if (state) {
12150 rb_io_close(arg.io);
12151 rb_jump_tag(state);
12152 }
12153 if (arg.argc == 2) arg.argc = 1;
12154 }
12155 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
12156}
12157
12158/*
12159 * call-seq:
12160 * IO.binread(command, length = nil, offset = 0) -> string or nil
12161 * IO.binread(path, length = nil, offset = 0) -> string or nil
12162 *
12163 * Behaves like IO.read, except that the stream is opened in binary mode
12164 * with ASCII-8BIT encoding.
12165 *
12166 * When called from class \IO (but not subclasses of \IO),
12167 * this method has potential security vulnerabilities if called with untrusted input;
12168 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12169 *
12170 */
12171
12172static VALUE
12173rb_io_s_binread(int argc, VALUE *argv, VALUE io)
12174{
12175 VALUE offset;
12176 struct foreach_arg arg;
12177 enum {
12179 oflags = O_RDONLY
12180#ifdef O_BINARY
12181 |O_BINARY
12182#endif
12183 };
12184 convconfig_t convconfig = {NULL, NULL, 0, Qnil};
12185
12186 rb_scan_args(argc, argv, "12", NULL, NULL, &offset);
12187 FilePathValue(argv[0]);
12188 convconfig.enc = rb_ascii8bit_encoding();
12189 arg.io = rb_io_open_generic(io, argv[0], oflags, fmode, &convconfig, 0);
12190 if (NIL_P(arg.io)) return Qnil;
12191 arg.argv = argv+1;
12192 arg.argc = (argc > 1) ? 1 : 0;
12193 if (!NIL_P(offset)) {
12194 struct seek_arg sarg;
12195 int state = 0;
12196 sarg.io = arg.io;
12197 sarg.offset = offset;
12198 sarg.mode = SEEK_SET;
12199 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12200 if (state) {
12201 rb_io_close(arg.io);
12202 rb_jump_tag(state);
12203 }
12204 }
12205 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
12206}
12207
12208static VALUE
12209io_s_write0(VALUE v)
12210{
12211 struct write_arg *arg = (void *)v;
12212 return io_write(arg->io,arg->str,arg->nosync);
12213}
12214
12215static VALUE
12216io_s_write(int argc, VALUE *argv, VALUE klass, int binary)
12217{
12218 VALUE string, offset, opt;
12219 struct foreach_arg arg;
12220 struct write_arg warg;
12221
12222 rb_scan_args(argc, argv, "21:", NULL, &string, &offset, &opt);
12223
12224 if (NIL_P(opt)) opt = rb_hash_new();
12225 else opt = rb_hash_dup(opt);
12226
12227
12228 if (NIL_P(rb_hash_aref(opt,sym_mode))) {
12229 int mode = O_WRONLY|O_CREAT;
12230#ifdef O_BINARY
12231 if (binary) mode |= O_BINARY;
12232#endif
12233 if (NIL_P(offset)) mode |= O_TRUNC;
12234 rb_hash_aset(opt,sym_mode,INT2NUM(mode));
12235 }
12236 open_key_args(klass, argc, argv, opt, &arg);
12237
12238#ifndef O_BINARY
12239 if (binary) rb_io_binmode_m(arg.io);
12240#endif
12241
12242 if (NIL_P(arg.io)) return Qnil;
12243 if (!NIL_P(offset)) {
12244 struct seek_arg sarg;
12245 int state = 0;
12246 sarg.io = arg.io;
12247 sarg.offset = offset;
12248 sarg.mode = SEEK_SET;
12249 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12250 if (state) {
12251 rb_io_close(arg.io);
12252 rb_jump_tag(state);
12253 }
12254 }
12255
12256 warg.io = arg.io;
12257 warg.str = string;
12258 warg.nosync = 0;
12259
12260 return rb_ensure(io_s_write0, (VALUE)&warg, rb_io_close, arg.io);
12261}
12262
12263/*
12264 * call-seq:
12265 * IO.write(command, data, **opts) -> integer
12266 * IO.write(path, data, offset = 0, **opts) -> integer
12267 *
12268 * Opens the stream, writes the given +data+ to it,
12269 * and closes the stream; returns the number of bytes written.
12270 *
12271 * When called from class \IO (but not subclasses of \IO),
12272 * this method has potential security vulnerabilities if called with untrusted input;
12273 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12274 *
12275 * The first argument must be a string;
12276 * its meaning depends on whether it starts with the pipe character (<tt>'|'</tt>):
12277 *
12278 * - If so (and if +self+ is \IO),
12279 * the rest of the string is a command to be executed as a subprocess.
12280 * - Otherwise, the string is the path to a file.
12281 *
12282 * With argument +command+ given, executes the command in a shell,
12283 * passes +data+ through standard input, writes its output to $stdout,
12284 * and returns the length of the given +data+:
12285 *
12286 * IO.write('| cat', 'Hello World!') # => 12
12287 *
12288 * Output:
12289 *
12290 * Hello World!
12291 *
12292 * With argument +path+ given, writes the given +data+ to the file
12293 * at that path:
12294 *
12295 * IO.write('t.tmp', 'abc') # => 3
12296 * File.read('t.tmp') # => "abc"
12297 *
12298 * If +offset+ is zero (the default), the file is overwritten:
12299 *
12300 * IO.write('t.tmp', 'A') # => 1
12301 * File.read('t.tmp') # => "A"
12302 *
12303 * If +offset+ in within the file content, the file is partly overwritten:
12304 *
12305 * IO.write('t.tmp', 'abcdef') # => 3
12306 * File.read('t.tmp') # => "abcdef"
12307 * # Offset within content.
12308 * IO.write('t.tmp', '012', 2) # => 3
12309 * File.read('t.tmp') # => "ab012f"
12310 *
12311 * If +offset+ is outside the file content,
12312 * the file is padded with null characters <tt>"\u0000"</tt>:
12313 *
12314 * IO.write('t.tmp', 'xyz', 10) # => 3
12315 * File.read('t.tmp') # => "ab012f\u0000\u0000\u0000\u0000xyz"
12316 *
12317 * Optional keyword arguments +opts+ specify:
12318 *
12319 * - {Open Options}[rdoc-ref:IO@Open+Options].
12320 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12321 *
12322 */
12323
12324static VALUE
12325rb_io_s_write(int argc, VALUE *argv, VALUE io)
12326{
12327 return io_s_write(argc, argv, io, 0);
12328}
12329
12330/*
12331 * call-seq:
12332 * IO.binwrite(command, string, offset = 0) -> integer
12333 * IO.binwrite(path, string, offset = 0) -> integer
12334 *
12335 * Behaves like IO.write, except that the stream is opened in binary mode
12336 * with ASCII-8BIT encoding.
12337 *
12338 * When called from class \IO (but not subclasses of \IO),
12339 * this method has potential security vulnerabilities if called with untrusted input;
12340 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12341 *
12342 */
12343
12344static VALUE
12345rb_io_s_binwrite(int argc, VALUE *argv, VALUE io)
12346{
12347 return io_s_write(argc, argv, io, 1);
12348}
12349
12351 VALUE src;
12352 VALUE dst;
12353 rb_off_t copy_length; /* (rb_off_t)-1 if not specified */
12354 rb_off_t src_offset; /* (rb_off_t)-1 if not specified */
12355
12356 rb_io_t *src_fptr;
12357 rb_io_t *dst_fptr;
12358 unsigned close_src : 1;
12359 unsigned close_dst : 1;
12360 int error_no;
12361 rb_off_t total;
12362 const char *syserr;
12363 const char *notimp;
12364 VALUE th;
12365 struct stat src_stat;
12366 struct stat dst_stat;
12367#ifdef HAVE_FCOPYFILE
12368 copyfile_state_t copyfile_state;
12369#endif
12370};
12371
12372static void *
12373exec_interrupts(void *arg)
12374{
12375 VALUE th = (VALUE)arg;
12376 rb_thread_execute_interrupts(th);
12377 return NULL;
12378}
12379
12380/*
12381 * returns TRUE if the preceding system call was interrupted
12382 * so we can continue. If the thread was interrupted, we
12383 * reacquire the GVL to execute interrupts before continuing.
12384 */
12385static int
12386maygvl_copy_stream_continue_p(int has_gvl, struct copy_stream_struct *stp)
12387{
12388 switch (errno) {
12389 case EINTR:
12390#if defined(ERESTART)
12391 case ERESTART:
12392#endif
12393 if (rb_thread_interrupted(stp->th)) {
12394 if (has_gvl)
12395 rb_thread_execute_interrupts(stp->th);
12396 else
12397 rb_thread_call_with_gvl(exec_interrupts, (void *)stp->th);
12398 }
12399 return TRUE;
12400 }
12401 return FALSE;
12402}
12403
12405 VALUE scheduler;
12406
12407 rb_io_t *fptr;
12408 short events;
12409
12410 VALUE result;
12411};
12412
12413static void *
12414fiber_scheduler_wait_for(void * _arguments)
12415{
12416 struct fiber_scheduler_wait_for_arguments *arguments = (struct fiber_scheduler_wait_for_arguments *)_arguments;
12417
12418 arguments->result = rb_fiber_scheduler_io_wait(arguments->scheduler, arguments->fptr->self, INT2NUM(arguments->events), RUBY_IO_TIMEOUT_DEFAULT);
12419
12420 return NULL;
12421}
12422
12423#if USE_POLL
12424# define IOWAIT_SYSCALL "poll"
12425STATIC_ASSERT(pollin_expected, POLLIN == RB_WAITFD_IN);
12426STATIC_ASSERT(pollout_expected, POLLOUT == RB_WAITFD_OUT);
12427static int
12428nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout)
12429{
12431 if (scheduler != Qnil) {
12432 struct fiber_scheduler_wait_for_arguments args = {.scheduler = scheduler, .fptr = fptr, .events = events};
12433 rb_thread_call_with_gvl(fiber_scheduler_wait_for, &args);
12434 return RTEST(args.result);
12435 }
12436
12437 int fd = fptr->fd;
12438 if (fd == -1) return 0;
12439
12440 struct pollfd fds;
12441
12442 fds.fd = fd;
12443 fds.events = events;
12444
12445 int timeout_milliseconds = -1;
12446
12447 if (timeout) {
12448 timeout_milliseconds = (int)(timeout->tv_sec * 1000) + (int)(timeout->tv_usec / 1000);
12449 }
12450
12451 return poll(&fds, 1, timeout_milliseconds);
12452}
12453#else /* !USE_POLL */
12454# define IOWAIT_SYSCALL "select"
12455static int
12456nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout)
12457{
12459 if (scheduler != Qnil) {
12460 struct fiber_scheduler_wait_for_arguments args = {.scheduler = scheduler, .fptr = fptr, .events = events};
12461 rb_thread_call_with_gvl(fiber_scheduler_wait_for, &args);
12462 return RTEST(args.result);
12463 }
12464
12465 int fd = fptr->fd;
12466
12467 if (fd == -1) {
12468 errno = EBADF;
12469 return -1;
12470 }
12471
12472 rb_fdset_t fds;
12473 int ret;
12474
12475 rb_fd_init(&fds);
12476 rb_fd_set(fd, &fds);
12477
12478 switch (events) {
12479 case RB_WAITFD_IN:
12480 ret = rb_fd_select(fd + 1, &fds, 0, 0, timeout);
12481 break;
12482 case RB_WAITFD_OUT:
12483 ret = rb_fd_select(fd + 1, 0, &fds, 0, timeout);
12484 break;
12485 default:
12486 VM_UNREACHABLE(nogvl_wait_for);
12487 }
12488
12489 rb_fd_term(&fds);
12490
12491 // On timeout, this returns 0.
12492 return ret;
12493}
12494#endif /* !USE_POLL */
12495
12496static int
12497maygvl_copy_stream_wait_read(int has_gvl, struct copy_stream_struct *stp)
12498{
12499 int ret;
12500
12501 do {
12502 if (has_gvl) {
12504 }
12505 else {
12506 ret = nogvl_wait_for(stp->th, stp->src_fptr, RB_WAITFD_IN, NULL);
12507 }
12508 } while (ret < 0 && maygvl_copy_stream_continue_p(has_gvl, stp));
12509
12510 if (ret < 0) {
12511 stp->syserr = IOWAIT_SYSCALL;
12512 stp->error_no = errno;
12513 return ret;
12514 }
12515 return 0;
12516}
12517
12518static int
12519nogvl_copy_stream_wait_write(struct copy_stream_struct *stp)
12520{
12521 int ret;
12522
12523 do {
12524 ret = nogvl_wait_for(stp->th, stp->dst_fptr, RB_WAITFD_OUT, NULL);
12525 } while (ret < 0 && maygvl_copy_stream_continue_p(0, stp));
12526
12527 if (ret < 0) {
12528 stp->syserr = IOWAIT_SYSCALL;
12529 stp->error_no = errno;
12530 return ret;
12531 }
12532 return 0;
12533}
12534
12535#ifdef USE_COPY_FILE_RANGE
12536
12537static ssize_t
12538simple_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)
12539{
12540#ifdef HAVE_COPY_FILE_RANGE
12541 return copy_file_range(in_fd, in_offset, out_fd, out_offset, count, flags);
12542#else
12543 return syscall(__NR_copy_file_range, in_fd, in_offset, out_fd, out_offset, count, flags);
12544#endif
12545}
12546
12547static int
12548nogvl_copy_file_range(struct copy_stream_struct *stp)
12549{
12550 ssize_t ss;
12551 rb_off_t src_size;
12552 rb_off_t copy_length, src_offset, *src_offset_ptr;
12553
12554 if (!S_ISREG(stp->src_stat.st_mode))
12555 return 0;
12556
12557 src_size = stp->src_stat.st_size;
12558 src_offset = stp->src_offset;
12559 if (src_offset >= (rb_off_t)0) {
12560 src_offset_ptr = &src_offset;
12561 }
12562 else {
12563 src_offset_ptr = NULL; /* if src_offset_ptr is NULL, then bytes are read from in_fd starting from the file offset */
12564 }
12565
12566 copy_length = stp->copy_length;
12567 if (copy_length < (rb_off_t)0) {
12568 if (src_offset < (rb_off_t)0) {
12569 rb_off_t current_offset;
12570 errno = 0;
12571 current_offset = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12572 if (current_offset < (rb_off_t)0 && errno) {
12573 stp->syserr = "lseek";
12574 stp->error_no = errno;
12575 return (int)current_offset;
12576 }
12577 copy_length = src_size - current_offset;
12578 }
12579 else {
12580 copy_length = src_size - src_offset;
12581 }
12582 }
12583
12584 retry_copy_file_range:
12585# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12586 /* we are limited by the 32-bit ssize_t return value on 32-bit */
12587 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12588# else
12589 ss = (ssize_t)copy_length;
12590# endif
12591 ss = simple_copy_file_range(stp->src_fptr->fd, src_offset_ptr, stp->dst_fptr->fd, NULL, ss, 0);
12592 if (0 < ss) {
12593 stp->total += ss;
12594 copy_length -= ss;
12595 if (0 < copy_length) {
12596 goto retry_copy_file_range;
12597 }
12598 }
12599 if (ss < 0) {
12600 if (maygvl_copy_stream_continue_p(0, stp)) {
12601 goto retry_copy_file_range;
12602 }
12603 switch (errno) {
12604 case EINVAL:
12605 case EPERM: /* copy_file_range(2) doesn't exist (may happen in
12606 docker container) */
12607#ifdef ENOSYS
12608 case ENOSYS:
12609#endif
12610#ifdef EXDEV
12611 case EXDEV: /* in_fd and out_fd are not on the same filesystem */
12612#endif
12613 return 0;
12614 case EAGAIN:
12615#if EWOULDBLOCK != EAGAIN
12616 case EWOULDBLOCK:
12617#endif
12618 {
12619 int ret = nogvl_copy_stream_wait_write(stp);
12620 if (ret < 0) return ret;
12621 }
12622 goto retry_copy_file_range;
12623 case EBADF:
12624 {
12625 int e = errno;
12626 int flags = fcntl(stp->dst_fptr->fd, F_GETFL);
12627
12628 if (flags != -1 && flags & O_APPEND) {
12629 return 0;
12630 }
12631 errno = e;
12632 }
12633 }
12634 stp->syserr = "copy_file_range";
12635 stp->error_no = errno;
12636 return (int)ss;
12637 }
12638 return 1;
12639}
12640#endif
12641
12642#ifdef HAVE_FCOPYFILE
12643static int
12644nogvl_fcopyfile(struct copy_stream_struct *stp)
12645{
12646 rb_off_t cur, ss = 0;
12647 const rb_off_t src_offset = stp->src_offset;
12648 int ret;
12649
12650 if (stp->copy_length >= (rb_off_t)0) {
12651 /* copy_length can't be specified in fcopyfile(3) */
12652 return 0;
12653 }
12654
12655 if (!S_ISREG(stp->src_stat.st_mode))
12656 return 0;
12657
12658 if (!S_ISREG(stp->dst_stat.st_mode))
12659 return 0;
12660 if (lseek(stp->dst_fptr->fd, 0, SEEK_CUR) > (rb_off_t)0) /* if dst IO was already written */
12661 return 0;
12662 if (fcntl(stp->dst_fptr->fd, F_GETFL) & O_APPEND) {
12663 /* fcopyfile(3) appends src IO to dst IO and then truncates
12664 * dst IO to src IO's original size. */
12665 rb_off_t end = lseek(stp->dst_fptr->fd, 0, SEEK_END);
12666 lseek(stp->dst_fptr->fd, 0, SEEK_SET);
12667 if (end > (rb_off_t)0) return 0;
12668 }
12669
12670 if (src_offset > (rb_off_t)0) {
12671 rb_off_t r;
12672
12673 /* get current offset */
12674 errno = 0;
12675 cur = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12676 if (cur < (rb_off_t)0 && errno) {
12677 stp->error_no = errno;
12678 return 1;
12679 }
12680
12681 errno = 0;
12682 r = lseek(stp->src_fptr->fd, src_offset, SEEK_SET);
12683 if (r < (rb_off_t)0 && errno) {
12684 stp->error_no = errno;
12685 return 1;
12686 }
12687 }
12688
12689 stp->copyfile_state = copyfile_state_alloc(); /* this will be freed by copy_stream_finalize() */
12690 ret = fcopyfile(stp->src_fptr->fd, stp->dst_fptr->fd, stp->copyfile_state, COPYFILE_DATA);
12691 copyfile_state_get(stp->copyfile_state, COPYFILE_STATE_COPIED, &ss); /* get copied bytes */
12692
12693 if (ret == 0) { /* success */
12694 stp->total = ss;
12695 if (src_offset > (rb_off_t)0) {
12696 rb_off_t r;
12697 errno = 0;
12698 /* reset offset */
12699 r = lseek(stp->src_fptr->fd, cur, SEEK_SET);
12700 if (r < (rb_off_t)0 && errno) {
12701 stp->error_no = errno;
12702 return 1;
12703 }
12704 }
12705 }
12706 else {
12707 switch (errno) {
12708 case ENOTSUP:
12709 case EPERM:
12710 case EINVAL:
12711 return 0;
12712 }
12713 stp->syserr = "fcopyfile";
12714 stp->error_no = errno;
12715 return (int)ret;
12716 }
12717 return 1;
12718}
12719#endif
12720
12721#ifdef HAVE_SENDFILE
12722
12723# ifdef __linux__
12724# define USE_SENDFILE
12725
12726# ifdef HAVE_SYS_SENDFILE_H
12727# include <sys/sendfile.h>
12728# endif
12729
12730static ssize_t
12731simple_sendfile(int out_fd, int in_fd, rb_off_t *offset, rb_off_t count)
12732{
12733 return sendfile(out_fd, in_fd, offset, (size_t)count);
12734}
12735
12736# elif 0 /* defined(__FreeBSD__) || defined(__DragonFly__) */ || defined(__APPLE__)
12737/* This runs on FreeBSD8.1 r30210, but sendfiles blocks its execution
12738 * without cpuset -l 0.
12739 */
12740# define USE_SENDFILE
12741
12742static ssize_t
12743simple_sendfile(int out_fd, int in_fd, rb_off_t *offset, rb_off_t count)
12744{
12745 int r;
12746 rb_off_t pos = offset ? *offset : lseek(in_fd, 0, SEEK_CUR);
12747 rb_off_t sbytes;
12748# ifdef __APPLE__
12749 r = sendfile(in_fd, out_fd, pos, &count, NULL, 0);
12750 sbytes = count;
12751# else
12752 r = sendfile(in_fd, out_fd, pos, (size_t)count, NULL, &sbytes, 0);
12753# endif
12754 if (r != 0 && sbytes == 0) return r;
12755 if (offset) {
12756 *offset += sbytes;
12757 }
12758 else {
12759 lseek(in_fd, sbytes, SEEK_CUR);
12760 }
12761 return (ssize_t)sbytes;
12762}
12763
12764# endif
12765
12766#endif
12767
12768#ifdef USE_SENDFILE
12769static int
12770nogvl_copy_stream_sendfile(struct copy_stream_struct *stp)
12771{
12772 ssize_t ss;
12773 rb_off_t src_size;
12774 rb_off_t copy_length;
12775 rb_off_t src_offset;
12776 int use_pread;
12777
12778 if (!S_ISREG(stp->src_stat.st_mode))
12779 return 0;
12780
12781 src_size = stp->src_stat.st_size;
12782#ifndef __linux__
12783 if ((stp->dst_stat.st_mode & S_IFMT) != S_IFSOCK)
12784 return 0;
12785#endif
12786
12787 src_offset = stp->src_offset;
12788 use_pread = src_offset >= (rb_off_t)0;
12789
12790 copy_length = stp->copy_length;
12791 if (copy_length < (rb_off_t)0) {
12792 if (use_pread)
12793 copy_length = src_size - src_offset;
12794 else {
12795 rb_off_t cur;
12796 errno = 0;
12797 cur = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12798 if (cur < (rb_off_t)0 && errno) {
12799 stp->syserr = "lseek";
12800 stp->error_no = errno;
12801 return (int)cur;
12802 }
12803 copy_length = src_size - cur;
12804 }
12805 }
12806
12807 retry_sendfile:
12808# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12809 /* we are limited by the 32-bit ssize_t return value on 32-bit */
12810 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12811# else
12812 ss = (ssize_t)copy_length;
12813# endif
12814 if (use_pread) {
12815 ss = simple_sendfile(stp->dst_fptr->fd, stp->src_fptr->fd, &src_offset, ss);
12816 }
12817 else {
12818 ss = simple_sendfile(stp->dst_fptr->fd, stp->src_fptr->fd, NULL, ss);
12819 }
12820 if (0 < ss) {
12821 stp->total += ss;
12822 copy_length -= ss;
12823 if (0 < copy_length) {
12824 goto retry_sendfile;
12825 }
12826 }
12827 if (ss < 0) {
12828 if (maygvl_copy_stream_continue_p(0, stp))
12829 goto retry_sendfile;
12830 switch (errno) {
12831 case EINVAL:
12832#ifdef ENOSYS
12833 case ENOSYS:
12834#endif
12835#ifdef EOPNOTSUP
12836 /* some RedHat kernels may return EOPNOTSUP on an NFS mount.
12837 see also: [Feature #16965] */
12838 case EOPNOTSUP:
12839#endif
12840 return 0;
12841 case EAGAIN:
12842#if EWOULDBLOCK != EAGAIN
12843 case EWOULDBLOCK:
12844#endif
12845 {
12846 int ret;
12847#ifndef __linux__
12848 /*
12849 * Linux requires stp->src_fptr->fd to be a mmap-able (regular) file,
12850 * select() reports regular files to always be "ready", so
12851 * there is no need to select() on it.
12852 * Other OSes may have the same limitation for sendfile() which
12853 * allow us to bypass maygvl_copy_stream_wait_read()...
12854 */
12855 ret = maygvl_copy_stream_wait_read(0, stp);
12856 if (ret < 0) return ret;
12857#endif
12858 ret = nogvl_copy_stream_wait_write(stp);
12859 if (ret < 0) return ret;
12860 }
12861 goto retry_sendfile;
12862 }
12863 stp->syserr = "sendfile";
12864 stp->error_no = errno;
12865 return (int)ss;
12866 }
12867 return 1;
12868}
12869#endif
12870
12871static ssize_t
12872maygvl_read(int has_gvl, rb_io_t *fptr, void *buf, size_t count)
12873{
12874 if (has_gvl)
12875 return rb_io_read_memory(fptr, buf, count);
12876 else
12877 return read(fptr->fd, buf, count);
12878}
12879
12880static ssize_t
12881maygvl_copy_stream_read(int has_gvl, struct copy_stream_struct *stp, char *buf, size_t len, rb_off_t offset)
12882{
12883 ssize_t ss;
12884 retry_read:
12885 if (offset < (rb_off_t)0) {
12886 ss = maygvl_read(has_gvl, stp->src_fptr, buf, len);
12887 }
12888 else {
12889#ifdef HAVE_PREAD
12890 ss = pread(stp->src_fptr->fd, buf, len, offset);
12891#else
12892 stp->notimp = "pread";
12893 return -1;
12894#endif
12895 }
12896 if (ss == 0) {
12897 return 0;
12898 }
12899 if (ss < 0) {
12900 if (maygvl_copy_stream_continue_p(has_gvl, stp))
12901 goto retry_read;
12902 switch (errno) {
12903 case EAGAIN:
12904#if EWOULDBLOCK != EAGAIN
12905 case EWOULDBLOCK:
12906#endif
12907 {
12908 int ret = maygvl_copy_stream_wait_read(has_gvl, stp);
12909 if (ret < 0) return ret;
12910 }
12911 goto retry_read;
12912#ifdef ENOSYS
12913 case ENOSYS:
12914 stp->notimp = "pread";
12915 return ss;
12916#endif
12917 }
12918 stp->syserr = offset < (rb_off_t)0 ? "read" : "pread";
12919 stp->error_no = errno;
12920 }
12921 return ss;
12922}
12923
12924static int
12925nogvl_copy_stream_write(struct copy_stream_struct *stp, char *buf, size_t len)
12926{
12927 ssize_t ss;
12928 int off = 0;
12929 while (len) {
12930 ss = write(stp->dst_fptr->fd, buf+off, len);
12931 if (ss < 0) {
12932 if (maygvl_copy_stream_continue_p(0, stp))
12933 continue;
12934 if (io_again_p(errno)) {
12935 int ret = nogvl_copy_stream_wait_write(stp);
12936 if (ret < 0) return ret;
12937 continue;
12938 }
12939 stp->syserr = "write";
12940 stp->error_no = errno;
12941 return (int)ss;
12942 }
12943 off += (int)ss;
12944 len -= (int)ss;
12945 stp->total += ss;
12946 }
12947 return 0;
12948}
12949
12950static void
12951nogvl_copy_stream_read_write(struct copy_stream_struct *stp)
12952{
12953 char buf[1024*16];
12954 size_t len;
12955 ssize_t ss;
12956 int ret;
12957 rb_off_t copy_length;
12958 rb_off_t src_offset;
12959 int use_eof;
12960 int use_pread;
12961
12962 copy_length = stp->copy_length;
12963 use_eof = copy_length < (rb_off_t)0;
12964 src_offset = stp->src_offset;
12965 use_pread = src_offset >= (rb_off_t)0;
12966
12967 if (use_pread && stp->close_src) {
12968 rb_off_t r;
12969 errno = 0;
12970 r = lseek(stp->src_fptr->fd, src_offset, SEEK_SET);
12971 if (r < (rb_off_t)0 && errno) {
12972 stp->syserr = "lseek";
12973 stp->error_no = errno;
12974 return;
12975 }
12976 src_offset = (rb_off_t)-1;
12977 use_pread = 0;
12978 }
12979
12980 while (use_eof || 0 < copy_length) {
12981 if (!use_eof && copy_length < (rb_off_t)sizeof(buf)) {
12982 len = (size_t)copy_length;
12983 }
12984 else {
12985 len = sizeof(buf);
12986 }
12987 if (use_pread) {
12988 ss = maygvl_copy_stream_read(0, stp, buf, len, src_offset);
12989 if (0 < ss)
12990 src_offset += ss;
12991 }
12992 else {
12993 ss = maygvl_copy_stream_read(0, stp, buf, len, (rb_off_t)-1);
12994 }
12995 if (ss <= 0) /* EOF or error */
12996 return;
12997
12998 ret = nogvl_copy_stream_write(stp, buf, ss);
12999 if (ret < 0)
13000 return;
13001
13002 if (!use_eof)
13003 copy_length -= ss;
13004 }
13005}
13006
13007static void *
13008nogvl_copy_stream_func(void *arg)
13009{
13010 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13011#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13012 int ret;
13013#endif
13014
13015#ifdef USE_COPY_FILE_RANGE
13016 ret = nogvl_copy_file_range(stp);
13017 if (ret != 0)
13018 goto finish; /* error or success */
13019#endif
13020
13021#ifdef HAVE_FCOPYFILE
13022 ret = nogvl_fcopyfile(stp);
13023 if (ret != 0)
13024 goto finish; /* error or success */
13025#endif
13026
13027#ifdef USE_SENDFILE
13028 ret = nogvl_copy_stream_sendfile(stp);
13029 if (ret != 0)
13030 goto finish; /* error or success */
13031#endif
13032
13033 nogvl_copy_stream_read_write(stp);
13034
13035#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13036 finish:
13037#endif
13038 return 0;
13039}
13040
13041static VALUE
13042copy_stream_fallback_body(VALUE arg)
13043{
13044 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13045 const int buflen = 16*1024;
13046 VALUE n;
13047 VALUE buf = rb_str_buf_new(buflen);
13048 rb_off_t rest = stp->copy_length;
13049 rb_off_t off = stp->src_offset;
13050 ID read_method = id_readpartial;
13051
13052 if (!stp->src_fptr) {
13053 if (!rb_respond_to(stp->src, read_method)) {
13054 read_method = id_read;
13055 }
13056 }
13057
13058 while (1) {
13059 long numwrote;
13060 long l;
13061 if (stp->copy_length < (rb_off_t)0) {
13062 l = buflen;
13063 }
13064 else {
13065 if (rest == 0) {
13066 rb_str_resize(buf, 0);
13067 break;
13068 }
13069 l = buflen < rest ? buflen : (long)rest;
13070 }
13071 if (!stp->src_fptr) {
13072 VALUE rc = rb_funcall(stp->src, read_method, 2, INT2FIX(l), buf);
13073
13074 if (read_method == id_read && NIL_P(rc))
13075 break;
13076 }
13077 else {
13078 ssize_t ss;
13079 rb_str_resize(buf, buflen);
13080 ss = maygvl_copy_stream_read(1, stp, RSTRING_PTR(buf), l, off);
13081 rb_str_resize(buf, ss > 0 ? ss : 0);
13082 if (ss < 0)
13083 return Qnil;
13084 if (ss == 0)
13085 rb_eof_error();
13086 if (off >= (rb_off_t)0)
13087 off += ss;
13088 }
13089 n = rb_io_write(stp->dst, buf);
13090 numwrote = NUM2LONG(n);
13091 stp->total += numwrote;
13092 rest -= numwrote;
13093 if (read_method == id_read && RSTRING_LEN(buf) == 0) {
13094 break;
13095 }
13096 }
13097
13098 return Qnil;
13099}
13100
13101static VALUE
13102copy_stream_fallback(struct copy_stream_struct *stp)
13103{
13104 if (!stp->src_fptr && stp->src_offset >= (rb_off_t)0) {
13105 rb_raise(rb_eArgError, "cannot specify src_offset for non-IO");
13106 }
13107 rb_rescue2(copy_stream_fallback_body, (VALUE)stp,
13108 (VALUE (*) (VALUE, VALUE))0, (VALUE)0,
13109 rb_eEOFError, (VALUE)0);
13110 return Qnil;
13111}
13112
13113static VALUE
13114copy_stream_body(VALUE arg)
13115{
13116 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13117 VALUE src_io = stp->src, dst_io = stp->dst;
13118 const int common_oflags = 0
13119#ifdef O_NOCTTY
13120 | O_NOCTTY
13121#endif
13122 ;
13123
13124 stp->th = rb_thread_current();
13125
13126 stp->total = 0;
13127
13128 if (src_io == argf ||
13129 !(RB_TYPE_P(src_io, T_FILE) ||
13130 RB_TYPE_P(src_io, T_STRING) ||
13131 rb_respond_to(src_io, rb_intern("to_path")))) {
13132 stp->src_fptr = NULL;
13133 }
13134 else {
13135 int stat_ret;
13136 VALUE tmp_io = rb_io_check_io(src_io);
13137 if (!NIL_P(tmp_io)) {
13138 src_io = tmp_io;
13139 }
13140 else if (!RB_TYPE_P(src_io, T_FILE)) {
13141 VALUE args[2];
13142 FilePathValue(src_io);
13143 args[0] = src_io;
13144 args[1] = INT2NUM(O_RDONLY|common_oflags);
13145 src_io = rb_class_new_instance(2, args, rb_cFile);
13146 stp->src = src_io;
13147 stp->close_src = 1;
13148 }
13149 RB_IO_POINTER(src_io, stp->src_fptr);
13150 rb_io_check_byte_readable(stp->src_fptr);
13151
13152 stat_ret = fstat(stp->src_fptr->fd, &stp->src_stat);
13153 if (stat_ret < 0) {
13154 stp->syserr = "fstat";
13155 stp->error_no = errno;
13156 return Qnil;
13157 }
13158 }
13159
13160 if (dst_io == argf ||
13161 !(RB_TYPE_P(dst_io, T_FILE) ||
13162 RB_TYPE_P(dst_io, T_STRING) ||
13163 rb_respond_to(dst_io, rb_intern("to_path")))) {
13164 stp->dst_fptr = NULL;
13165 }
13166 else {
13167 int stat_ret;
13168 VALUE tmp_io = rb_io_check_io(dst_io);
13169 if (!NIL_P(tmp_io)) {
13170 dst_io = GetWriteIO(tmp_io);
13171 }
13172 else if (!RB_TYPE_P(dst_io, T_FILE)) {
13173 VALUE args[3];
13174 FilePathValue(dst_io);
13175 args[0] = dst_io;
13176 args[1] = INT2NUM(O_WRONLY|O_CREAT|O_TRUNC|common_oflags);
13177 args[2] = INT2FIX(0666);
13178 dst_io = rb_class_new_instance(3, args, rb_cFile);
13179 stp->dst = dst_io;
13180 stp->close_dst = 1;
13181 }
13182 else {
13183 dst_io = GetWriteIO(dst_io);
13184 stp->dst = dst_io;
13185 }
13186 RB_IO_POINTER(dst_io, stp->dst_fptr);
13187 rb_io_check_writable(stp->dst_fptr);
13188
13189 stat_ret = fstat(stp->dst_fptr->fd, &stp->dst_stat);
13190 if (stat_ret < 0) {
13191 stp->syserr = "fstat";
13192 stp->error_no = errno;
13193 return Qnil;
13194 }
13195 }
13196
13197#ifdef O_BINARY
13198 if (stp->src_fptr)
13199 SET_BINARY_MODE_WITH_SEEK_CUR(stp->src_fptr);
13200#endif
13201 if (stp->dst_fptr)
13202 io_ascii8bit_binmode(stp->dst_fptr);
13203
13204 if (stp->src_offset < (rb_off_t)0 && stp->src_fptr && stp->src_fptr->rbuf.len) {
13205 size_t len = stp->src_fptr->rbuf.len;
13206 VALUE str;
13207 if (stp->copy_length >= (rb_off_t)0 && stp->copy_length < (rb_off_t)len) {
13208 len = (size_t)stp->copy_length;
13209 }
13210 str = rb_str_buf_new(len);
13211 rb_str_resize(str,len);
13212 read_buffered_data(RSTRING_PTR(str), len, stp->src_fptr);
13213 if (stp->dst_fptr) { /* IO or filename */
13214 if (io_binwrite(str, RSTRING_PTR(str), RSTRING_LEN(str), stp->dst_fptr, 0) < 0)
13215 rb_sys_fail_on_write(stp->dst_fptr);
13216 }
13217 else /* others such as StringIO */
13218 rb_io_write(dst_io, str);
13219 rb_str_resize(str, 0);
13220 stp->total += len;
13221 if (stp->copy_length >= (rb_off_t)0)
13222 stp->copy_length -= len;
13223 }
13224
13225 if (stp->dst_fptr && io_fflush(stp->dst_fptr) < 0) {
13226 rb_raise(rb_eIOError, "flush failed");
13227 }
13228
13229 if (stp->copy_length == 0)
13230 return Qnil;
13231
13232 if (stp->src_fptr == NULL || stp->dst_fptr == NULL) {
13233 return copy_stream_fallback(stp);
13234 }
13235
13236 rb_thread_call_without_gvl(nogvl_copy_stream_func, (void*)stp, RUBY_UBF_IO, 0);
13237 return Qnil;
13238}
13239
13240static VALUE
13241copy_stream_finalize(VALUE arg)
13242{
13243 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13244
13245#ifdef HAVE_FCOPYFILE
13246 if (stp->copyfile_state) {
13247 copyfile_state_free(stp->copyfile_state);
13248 }
13249#endif
13250
13251 if (stp->close_src) {
13252 rb_io_close_m(stp->src);
13253 }
13254 if (stp->close_dst) {
13255 rb_io_close_m(stp->dst);
13256 }
13257 if (stp->syserr) {
13258 rb_syserr_fail(stp->error_no, stp->syserr);
13259 }
13260 if (stp->notimp) {
13261 rb_raise(rb_eNotImpError, "%s() not implemented", stp->notimp);
13262 }
13263 return Qnil;
13264}
13265
13266/*
13267 * call-seq:
13268 * IO.copy_stream(src, dst, src_length = nil, src_offset = 0) -> integer
13269 *
13270 * Copies from the given +src+ to the given +dst+,
13271 * returning the number of bytes copied.
13272 *
13273 * - The given +src+ must be one of the following:
13274 *
13275 * - The path to a readable file, from which source data is to be read.
13276 * - An \IO-like object, opened for reading and capable of responding
13277 * to method +:readpartial+ or method +:read+.
13278 *
13279 * - The given +dst+ must be one of the following:
13280 *
13281 * - The path to a writable file, to which data is to be written.
13282 * - An \IO-like object, opened for writing and capable of responding
13283 * to method +:write+.
13284 *
13285 * The examples here use file <tt>t.txt</tt> as source:
13286 *
13287 * File.read('t.txt')
13288 * # => "First line\nSecond line\n\nThird line\nFourth line\n"
13289 * File.read('t.txt').size # => 47
13290 *
13291 * If only arguments +src+ and +dst+ are given,
13292 * the entire source stream is copied:
13293 *
13294 * # Paths.
13295 * IO.copy_stream('t.txt', 't.tmp') # => 47
13296 *
13297 * # IOs (recall that a File is also an IO).
13298 * src_io = File.open('t.txt', 'r') # => #<File:t.txt>
13299 * dst_io = File.open('t.tmp', 'w') # => #<File:t.tmp>
13300 * IO.copy_stream(src_io, dst_io) # => 47
13301 * src_io.close
13302 * dst_io.close
13303 *
13304 * With argument +src_length+ a non-negative integer,
13305 * no more than that many bytes are copied:
13306 *
13307 * IO.copy_stream('t.txt', 't.tmp', 10) # => 10
13308 * File.read('t.tmp') # => "First line"
13309 *
13310 * With argument +src_offset+ also given,
13311 * the source stream is read beginning at that offset:
13312 *
13313 * IO.copy_stream('t.txt', 't.tmp', 11, 11) # => 11
13314 * IO.read('t.tmp') # => "Second line"
13315 *
13316 */
13317static VALUE
13318rb_io_s_copy_stream(int argc, VALUE *argv, VALUE io)
13319{
13320 VALUE src, dst, length, src_offset;
13321 struct copy_stream_struct st;
13322
13323 MEMZERO(&st, struct copy_stream_struct, 1);
13324
13325 rb_scan_args(argc, argv, "22", &src, &dst, &length, &src_offset);
13326
13327 st.src = src;
13328 st.dst = dst;
13329
13330 st.src_fptr = NULL;
13331 st.dst_fptr = NULL;
13332
13333 if (NIL_P(length))
13334 st.copy_length = (rb_off_t)-1;
13335 else
13336 st.copy_length = NUM2OFFT(length);
13337
13338 if (NIL_P(src_offset))
13339 st.src_offset = (rb_off_t)-1;
13340 else
13341 st.src_offset = NUM2OFFT(src_offset);
13342
13343 rb_ensure(copy_stream_body, (VALUE)&st, copy_stream_finalize, (VALUE)&st);
13344
13345 return OFFT2NUM(st.total);
13346}
13347
13348/*
13349 * call-seq:
13350 * external_encoding -> encoding or nil
13351 *
13352 * Returns the Encoding object that represents the encoding of the stream,
13353 * or +nil+ if the stream is in write mode and no encoding is specified.
13354 *
13355 * See {Encodings}[rdoc-ref:File@Encodings].
13356 *
13357 */
13358
13359static VALUE
13360rb_io_external_encoding(VALUE io)
13361{
13362 rb_io_t *fptr = RFILE(rb_io_taint_check(io))->fptr;
13363
13364 if (fptr->encs.enc2) {
13365 return rb_enc_from_encoding(fptr->encs.enc2);
13366 }
13367 if (fptr->mode & FMODE_WRITABLE) {
13368 if (fptr->encs.enc)
13369 return rb_enc_from_encoding(fptr->encs.enc);
13370 return Qnil;
13371 }
13372 return rb_enc_from_encoding(io_read_encoding(fptr));
13373}
13374
13375/*
13376 * call-seq:
13377 * internal_encoding -> encoding or nil
13378 *
13379 * Returns the Encoding object that represents the encoding of the internal string,
13380 * if conversion is specified,
13381 * or +nil+ otherwise.
13382 *
13383 * See {Encodings}[rdoc-ref:File@Encodings].
13384 *
13385 */
13386
13387static VALUE
13388rb_io_internal_encoding(VALUE io)
13389{
13390 rb_io_t *fptr = RFILE(rb_io_taint_check(io))->fptr;
13391
13392 if (!fptr->encs.enc2) return Qnil;
13393 return rb_enc_from_encoding(io_read_encoding(fptr));
13394}
13395
13396/*
13397 * call-seq:
13398 * set_encoding(ext_enc) -> self
13399 * set_encoding(ext_enc, int_enc, **enc_opts) -> self
13400 * set_encoding('ext_enc:int_enc', **enc_opts) -> self
13401 *
13402 * See {Encodings}[rdoc-ref:File@Encodings].
13403 *
13404 * Argument +ext_enc+, if given, must be an Encoding object;
13405 * it is assigned as the encoding for the stream.
13406 *
13407 * Argument +int_enc+, if given, must be an Encoding object;
13408 * it is assigned as the encoding for the internal string.
13409 *
13410 * Argument <tt>'ext_enc:int_enc'</tt>, if given, is a string
13411 * containing two colon-separated encoding names;
13412 * corresponding Encoding objects are assigned as the external
13413 * and internal encodings for the stream.
13414 *
13415 * Optional keyword arguments +enc_opts+ specify
13416 * {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
13417 *
13418 */
13419
13420static VALUE
13421rb_io_set_encoding(int argc, VALUE *argv, VALUE io)
13422{
13423 rb_io_t *fptr;
13424 VALUE v1, v2, opt;
13425
13426 if (!RB_TYPE_P(io, T_FILE)) {
13427 return forward(io, id_set_encoding, argc, argv);
13428 }
13429
13430 argc = rb_scan_args(argc, argv, "11:", &v1, &v2, &opt);
13431 GetOpenFile(io, fptr);
13432 io_encoding_set(fptr, v1, v2, opt);
13433 return io;
13434}
13435
13436void
13437rb_stdio_set_default_encoding(void)
13438{
13439 VALUE val = Qnil;
13440
13441#ifdef _WIN32
13442 if (isatty(fileno(stdin))) {
13443 rb_encoding *external = rb_locale_encoding();
13444 rb_encoding *internal = rb_default_internal_encoding();
13445 if (!internal) internal = rb_default_external_encoding();
13446 io_encoding_set(RFILE(rb_stdin)->fptr,
13447 rb_enc_from_encoding(external),
13448 rb_enc_from_encoding(internal),
13449 Qnil);
13450 }
13451 else
13452#endif
13453 rb_io_set_encoding(1, &val, rb_stdin);
13454 rb_io_set_encoding(1, &val, rb_stdout);
13455 rb_io_set_encoding(1, &val, rb_stderr);
13456}
13457
13458static inline int
13459global_argf_p(VALUE arg)
13460{
13461 return arg == argf;
13462}
13463
13464typedef VALUE (*argf_encoding_func)(VALUE io);
13465
13466static VALUE
13467argf_encoding(VALUE argf, argf_encoding_func func)
13468{
13469 if (!RTEST(ARGF.current_file)) {
13470 return rb_enc_default_external();
13471 }
13472 return func(rb_io_check_io(ARGF.current_file));
13473}
13474
13475/*
13476 * call-seq:
13477 * ARGF.external_encoding -> encoding
13478 *
13479 * Returns the external encoding for files read from ARGF as an Encoding
13480 * object. The external encoding is the encoding of the text as stored in a
13481 * file. Contrast with ARGF.internal_encoding, which is the encoding used to
13482 * represent this text within Ruby.
13483 *
13484 * To set the external encoding use ARGF.set_encoding.
13485 *
13486 * For example:
13487 *
13488 * ARGF.external_encoding #=> #<Encoding:UTF-8>
13489 *
13490 */
13491static VALUE
13492argf_external_encoding(VALUE argf)
13493{
13494 return argf_encoding(argf, rb_io_external_encoding);
13495}
13496
13497/*
13498 * call-seq:
13499 * ARGF.internal_encoding -> encoding
13500 *
13501 * Returns the internal encoding for strings read from ARGF as an
13502 * Encoding object.
13503 *
13504 * If ARGF.set_encoding has been called with two encoding names, the second
13505 * is returned. Otherwise, if +Encoding.default_external+ has been set, that
13506 * value is returned. Failing that, if a default external encoding was
13507 * specified on the command-line, that value is used. If the encoding is
13508 * unknown, +nil+ is returned.
13509 */
13510static VALUE
13511argf_internal_encoding(VALUE argf)
13512{
13513 return argf_encoding(argf, rb_io_internal_encoding);
13514}
13515
13516/*
13517 * call-seq:
13518 * ARGF.set_encoding(ext_enc) -> ARGF
13519 * ARGF.set_encoding("ext_enc:int_enc") -> ARGF
13520 * ARGF.set_encoding(ext_enc, int_enc) -> ARGF
13521 * ARGF.set_encoding("ext_enc:int_enc", opt) -> ARGF
13522 * ARGF.set_encoding(ext_enc, int_enc, opt) -> ARGF
13523 *
13524 * If single argument is specified, strings read from ARGF are tagged with
13525 * the encoding specified.
13526 *
13527 * If two encoding names separated by a colon are given, e.g. "ascii:utf-8",
13528 * the read string is converted from the first encoding (external encoding)
13529 * to the second encoding (internal encoding), then tagged with the second
13530 * encoding.
13531 *
13532 * If two arguments are specified, they must be encoding objects or encoding
13533 * names. Again, the first specifies the external encoding; the second
13534 * specifies the internal encoding.
13535 *
13536 * If the external encoding and the internal encoding are specified, the
13537 * optional Hash argument can be used to adjust the conversion process. The
13538 * structure of this hash is explained in the String#encode documentation.
13539 *
13540 * For example:
13541 *
13542 * ARGF.set_encoding('ascii') # Tag the input as US-ASCII text
13543 * ARGF.set_encoding(Encoding::UTF_8) # Tag the input as UTF-8 text
13544 * ARGF.set_encoding('utf-8','ascii') # Transcode the input from US-ASCII
13545 * # to UTF-8.
13546 */
13547static VALUE
13548argf_set_encoding(int argc, VALUE *argv, VALUE argf)
13549{
13550 rb_io_t *fptr;
13551
13552 if (!next_argv()) {
13553 rb_raise(rb_eArgError, "no stream to set encoding");
13554 }
13555 rb_io_set_encoding(argc, argv, ARGF.current_file);
13556 GetOpenFile(ARGF.current_file, fptr);
13557 ARGF.encs = fptr->encs;
13558 return argf;
13559}
13560
13561/*
13562 * call-seq:
13563 * ARGF.tell -> Integer
13564 * ARGF.pos -> Integer
13565 *
13566 * Returns the current offset (in bytes) of the current file in ARGF.
13567 *
13568 * ARGF.pos #=> 0
13569 * ARGF.gets #=> "This is line one\n"
13570 * ARGF.pos #=> 17
13571 *
13572 */
13573static VALUE
13574argf_tell(VALUE argf)
13575{
13576 if (!next_argv()) {
13577 rb_raise(rb_eArgError, "no stream to tell");
13578 }
13579 ARGF_FORWARD(0, 0);
13580 return rb_io_tell(ARGF.current_file);
13581}
13582
13583/*
13584 * call-seq:
13585 * ARGF.seek(amount, whence=IO::SEEK_SET) -> 0
13586 *
13587 * Seeks to offset _amount_ (an Integer) in the ARGF stream according to
13588 * the value of _whence_. See IO#seek for further details.
13589 */
13590static VALUE
13591argf_seek_m(int argc, VALUE *argv, VALUE argf)
13592{
13593 if (!next_argv()) {
13594 rb_raise(rb_eArgError, "no stream to seek");
13595 }
13596 ARGF_FORWARD(argc, argv);
13597 return rb_io_seek_m(argc, argv, ARGF.current_file);
13598}
13599
13600/*
13601 * call-seq:
13602 * ARGF.pos = position -> Integer
13603 *
13604 * Seeks to the position given by _position_ (in bytes) in ARGF.
13605 *
13606 * For example:
13607 *
13608 * ARGF.pos = 17
13609 * ARGF.gets #=> "This is line two\n"
13610 */
13611static VALUE
13612argf_set_pos(VALUE argf, VALUE offset)
13613{
13614 if (!next_argv()) {
13615 rb_raise(rb_eArgError, "no stream to set position");
13616 }
13617 ARGF_FORWARD(1, &offset);
13618 return rb_io_set_pos(ARGF.current_file, offset);
13619}
13620
13621/*
13622 * call-seq:
13623 * ARGF.rewind -> 0
13624 *
13625 * Positions the current file to the beginning of input, resetting
13626 * ARGF.lineno to zero.
13627 *
13628 * ARGF.readline #=> "This is line one\n"
13629 * ARGF.rewind #=> 0
13630 * ARGF.lineno #=> 0
13631 * ARGF.readline #=> "This is line one\n"
13632 */
13633static VALUE
13634argf_rewind(VALUE argf)
13635{
13636 VALUE ret;
13637 int old_lineno;
13638
13639 if (!next_argv()) {
13640 rb_raise(rb_eArgError, "no stream to rewind");
13641 }
13642 ARGF_FORWARD(0, 0);
13643 old_lineno = RFILE(ARGF.current_file)->fptr->lineno;
13644 ret = rb_io_rewind(ARGF.current_file);
13645 if (!global_argf_p(argf)) {
13646 ARGF.last_lineno = ARGF.lineno -= old_lineno;
13647 }
13648 return ret;
13649}
13650
13651/*
13652 * call-seq:
13653 * ARGF.fileno -> integer
13654 * ARGF.to_i -> integer
13655 *
13656 * Returns an integer representing the numeric file descriptor for
13657 * the current file. Raises an ArgumentError if there isn't a current file.
13658 *
13659 * ARGF.fileno #=> 3
13660 */
13661static VALUE
13662argf_fileno(VALUE argf)
13663{
13664 if (!next_argv()) {
13665 rb_raise(rb_eArgError, "no stream");
13666 }
13667 ARGF_FORWARD(0, 0);
13668 return rb_io_fileno(ARGF.current_file);
13669}
13670
13671/*
13672 * call-seq:
13673 * ARGF.to_io -> IO
13674 *
13675 * Returns an IO object representing the current file. This will be a
13676 * File object unless the current file is a stream such as STDIN.
13677 *
13678 * For example:
13679 *
13680 * ARGF.to_io #=> #<File:glark.txt>
13681 * ARGF.to_io #=> #<IO:<STDIN>>
13682 */
13683static VALUE
13684argf_to_io(VALUE argf)
13685{
13686 next_argv();
13687 ARGF_FORWARD(0, 0);
13688 return ARGF.current_file;
13689}
13690
13691/*
13692 * call-seq:
13693 * ARGF.eof? -> true or false
13694 * ARGF.eof -> true or false
13695 *
13696 * Returns true if the current file in ARGF is at end of file, i.e. it has
13697 * no data to read. The stream must be opened for reading or an IOError
13698 * will be raised.
13699 *
13700 * $ echo "eof" | ruby argf.rb
13701 *
13702 * ARGF.eof? #=> false
13703 * 3.times { ARGF.readchar }
13704 * ARGF.eof? #=> false
13705 * ARGF.readchar #=> "\n"
13706 * ARGF.eof? #=> true
13707 */
13708
13709static VALUE
13710argf_eof(VALUE argf)
13711{
13712 next_argv();
13713 if (RTEST(ARGF.current_file)) {
13714 if (ARGF.init_p == 0) return Qtrue;
13715 next_argv();
13716 ARGF_FORWARD(0, 0);
13717 if (rb_io_eof(ARGF.current_file)) {
13718 return Qtrue;
13719 }
13720 }
13721 return Qfalse;
13722}
13723
13724/*
13725 * call-seq:
13726 * ARGF.read([length [, outbuf]]) -> string, outbuf, or nil
13727 *
13728 * Reads _length_ bytes from ARGF. The files named on the command line
13729 * are concatenated and treated as a single file by this method, so when
13730 * called without arguments the contents of this pseudo file are returned in
13731 * their entirety.
13732 *
13733 * _length_ must be a non-negative integer or +nil+.
13734 *
13735 * If _length_ is a positive integer, +read+ tries to read
13736 * _length_ bytes without any conversion (binary mode).
13737 * It returns +nil+ if an EOF is encountered before anything can be read.
13738 * Fewer than _length_ bytes are returned if an EOF is encountered during
13739 * the read.
13740 * In the case of an integer _length_, the resulting string is always
13741 * in ASCII-8BIT encoding.
13742 *
13743 * If _length_ is omitted or is +nil+, it reads until EOF
13744 * and the encoding conversion is applied, if applicable.
13745 * A string is returned even if EOF is encountered before any data is read.
13746 *
13747 * If _length_ is zero, it returns an empty string (<code>""</code>).
13748 *
13749 * If the optional _outbuf_ argument is present,
13750 * it must reference a String, which will receive the data.
13751 * The _outbuf_ will contain only the received data after the method call
13752 * even if it is not empty at the beginning.
13753 *
13754 * For example:
13755 *
13756 * $ echo "small" > small.txt
13757 * $ echo "large" > large.txt
13758 * $ ./glark.rb small.txt large.txt
13759 *
13760 * ARGF.read #=> "small\nlarge"
13761 * ARGF.read(200) #=> "small\nlarge"
13762 * ARGF.read(2) #=> "sm"
13763 * ARGF.read(0) #=> ""
13764 *
13765 * Note that this method behaves like the fread() function in C.
13766 * This means it retries to invoke read(2) system calls to read data
13767 * with the specified length.
13768 * If you need the behavior like a single read(2) system call,
13769 * consider ARGF#readpartial or ARGF#read_nonblock.
13770 */
13771
13772static VALUE
13773argf_read(int argc, VALUE *argv, VALUE argf)
13774{
13775 VALUE tmp, str, length;
13776 long len = 0;
13777
13778 rb_scan_args(argc, argv, "02", &length, &str);
13779 if (!NIL_P(length)) {
13780 len = NUM2LONG(argv[0]);
13781 }
13782 if (!NIL_P(str)) {
13783 StringValue(str);
13784 rb_str_resize(str,0);
13785 argv[1] = Qnil;
13786 }
13787
13788 retry:
13789 if (!next_argv()) {
13790 return str;
13791 }
13792 if (ARGF_GENERIC_INPUT_P()) {
13793 tmp = argf_forward(argc, argv, argf);
13794 }
13795 else {
13796 tmp = io_read(argc, argv, ARGF.current_file);
13797 }
13798 if (NIL_P(str)) str = tmp;
13799 else if (!NIL_P(tmp)) rb_str_append(str, tmp);
13800 if (NIL_P(tmp) || NIL_P(length)) {
13801 if (ARGF.next_p != -1) {
13802 argf_close(argf);
13803 ARGF.next_p = 1;
13804 goto retry;
13805 }
13806 }
13807 else if (argc >= 1) {
13808 long slen = RSTRING_LEN(str);
13809 if (slen < len) {
13810 argv[0] = LONG2NUM(len - slen);
13811 goto retry;
13812 }
13813 }
13814 return str;
13815}
13816
13818 int argc;
13819 VALUE *argv;
13820 VALUE argf;
13821};
13822
13823static VALUE
13824argf_forward_call(VALUE arg)
13825{
13826 struct argf_call_arg *p = (struct argf_call_arg *)arg;
13827 argf_forward(p->argc, p->argv, p->argf);
13828 return Qnil;
13829}
13830
13831static VALUE argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts,
13832 int nonblock);
13833
13834/*
13835 * call-seq:
13836 * ARGF.readpartial(maxlen) -> string
13837 * ARGF.readpartial(maxlen, outbuf) -> outbuf
13838 *
13839 * Reads at most _maxlen_ bytes from the ARGF stream.
13840 *
13841 * If the optional _outbuf_ argument is present,
13842 * it must reference a String, which will receive the data.
13843 * The _outbuf_ will contain only the received data after the method call
13844 * even if it is not empty at the beginning.
13845 *
13846 * It raises EOFError on end of ARGF stream.
13847 * Since ARGF stream is a concatenation of multiple files,
13848 * internally EOF is occur for each file.
13849 * ARGF.readpartial returns empty strings for EOFs except the last one and
13850 * raises EOFError for the last one.
13851 *
13852 */
13853
13854static VALUE
13855argf_readpartial(int argc, VALUE *argv, VALUE argf)
13856{
13857 return argf_getpartial(argc, argv, argf, Qnil, 0);
13858}
13859
13860/*
13861 * call-seq:
13862 * ARGF.read_nonblock(maxlen[, options]) -> string
13863 * ARGF.read_nonblock(maxlen, outbuf[, options]) -> outbuf
13864 *
13865 * Reads at most _maxlen_ bytes from the ARGF stream in non-blocking mode.
13866 */
13867
13868static VALUE
13869argf_read_nonblock(int argc, VALUE *argv, VALUE argf)
13870{
13871 VALUE opts;
13872
13873 rb_scan_args(argc, argv, "11:", NULL, NULL, &opts);
13874
13875 if (!NIL_P(opts))
13876 argc--;
13877
13878 return argf_getpartial(argc, argv, argf, opts, 1);
13879}
13880
13881static VALUE
13882argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts, int nonblock)
13883{
13884 VALUE tmp, str, length;
13885 int no_exception;
13886
13887 rb_scan_args(argc, argv, "11", &length, &str);
13888 if (!NIL_P(str)) {
13889 StringValue(str);
13890 argv[1] = str;
13891 }
13892 no_exception = no_exception_p(opts);
13893
13894 if (!next_argv()) {
13895 if (!NIL_P(str)) {
13896 rb_str_resize(str, 0);
13897 }
13898 rb_eof_error();
13899 }
13900 if (ARGF_GENERIC_INPUT_P()) {
13901 VALUE (*const rescue_does_nothing)(VALUE, VALUE) = 0;
13902 struct argf_call_arg arg;
13903 arg.argc = argc;
13904 arg.argv = argv;
13905 arg.argf = argf;
13906 tmp = rb_rescue2(argf_forward_call, (VALUE)&arg,
13907 rescue_does_nothing, Qnil, rb_eEOFError, (VALUE)0);
13908 }
13909 else {
13910 tmp = io_getpartial(argc, argv, ARGF.current_file, no_exception, nonblock);
13911 }
13912 if (NIL_P(tmp)) {
13913 if (ARGF.next_p == -1) {
13914 return io_nonblock_eof(no_exception);
13915 }
13916 argf_close(argf);
13917 ARGF.next_p = 1;
13918 if (RARRAY_LEN(ARGF.argv) == 0) {
13919 return io_nonblock_eof(no_exception);
13920 }
13921 if (NIL_P(str))
13922 str = rb_str_new(NULL, 0);
13923 return str;
13924 }
13925 return tmp;
13926}
13927
13928/*
13929 * call-seq:
13930 * ARGF.getc -> String or nil
13931 *
13932 * Reads the next character from ARGF and returns it as a String. Returns
13933 * +nil+ at the end of the stream.
13934 *
13935 * ARGF treats the files named on the command line as a single file created
13936 * by concatenating their contents. After returning the last character of the
13937 * first file, it returns the first character of the second file, and so on.
13938 *
13939 * For example:
13940 *
13941 * $ echo "foo" > file
13942 * $ ruby argf.rb file
13943 *
13944 * ARGF.getc #=> "f"
13945 * ARGF.getc #=> "o"
13946 * ARGF.getc #=> "o"
13947 * ARGF.getc #=> "\n"
13948 * ARGF.getc #=> nil
13949 * ARGF.getc #=> nil
13950 */
13951static VALUE
13952argf_getc(VALUE argf)
13953{
13954 VALUE ch;
13955
13956 retry:
13957 if (!next_argv()) return Qnil;
13958 if (ARGF_GENERIC_INPUT_P()) {
13959 ch = forward_current(rb_intern("getc"), 0, 0);
13960 }
13961 else {
13962 ch = rb_io_getc(ARGF.current_file);
13963 }
13964 if (NIL_P(ch) && ARGF.next_p != -1) {
13965 argf_close(argf);
13966 ARGF.next_p = 1;
13967 goto retry;
13968 }
13969
13970 return ch;
13971}
13972
13973/*
13974 * call-seq:
13975 * ARGF.getbyte -> Integer or nil
13976 *
13977 * Gets the next 8-bit byte (0..255) from ARGF. Returns +nil+ if called at
13978 * the end of the stream.
13979 *
13980 * For example:
13981 *
13982 * $ echo "foo" > file
13983 * $ ruby argf.rb file
13984 *
13985 * ARGF.getbyte #=> 102
13986 * ARGF.getbyte #=> 111
13987 * ARGF.getbyte #=> 111
13988 * ARGF.getbyte #=> 10
13989 * ARGF.getbyte #=> nil
13990 */
13991static VALUE
13992argf_getbyte(VALUE argf)
13993{
13994 VALUE ch;
13995
13996 retry:
13997 if (!next_argv()) return Qnil;
13998 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
13999 ch = forward_current(rb_intern("getbyte"), 0, 0);
14000 }
14001 else {
14002 ch = rb_io_getbyte(ARGF.current_file);
14003 }
14004 if (NIL_P(ch) && ARGF.next_p != -1) {
14005 argf_close(argf);
14006 ARGF.next_p = 1;
14007 goto retry;
14008 }
14009
14010 return ch;
14011}
14012
14013/*
14014 * call-seq:
14015 * ARGF.readchar -> String or nil
14016 *
14017 * Reads the next character from ARGF and returns it as a String. Raises
14018 * an EOFError after the last character of the last file has been read.
14019 *
14020 * For example:
14021 *
14022 * $ echo "foo" > file
14023 * $ ruby argf.rb file
14024 *
14025 * ARGF.readchar #=> "f"
14026 * ARGF.readchar #=> "o"
14027 * ARGF.readchar #=> "o"
14028 * ARGF.readchar #=> "\n"
14029 * ARGF.readchar #=> end of file reached (EOFError)
14030 */
14031static VALUE
14032argf_readchar(VALUE argf)
14033{
14034 VALUE ch;
14035
14036 retry:
14037 if (!next_argv()) rb_eof_error();
14038 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
14039 ch = forward_current(rb_intern("getc"), 0, 0);
14040 }
14041 else {
14042 ch = rb_io_getc(ARGF.current_file);
14043 }
14044 if (NIL_P(ch) && ARGF.next_p != -1) {
14045 argf_close(argf);
14046 ARGF.next_p = 1;
14047 goto retry;
14048 }
14049
14050 return ch;
14051}
14052
14053/*
14054 * call-seq:
14055 * ARGF.readbyte -> Integer
14056 *
14057 * Reads the next 8-bit byte from ARGF and returns it as an Integer. Raises
14058 * an EOFError after the last byte of the last file has been read.
14059 *
14060 * For example:
14061 *
14062 * $ echo "foo" > file
14063 * $ ruby argf.rb file
14064 *
14065 * ARGF.readbyte #=> 102
14066 * ARGF.readbyte #=> 111
14067 * ARGF.readbyte #=> 111
14068 * ARGF.readbyte #=> 10
14069 * ARGF.readbyte #=> end of file reached (EOFError)
14070 */
14071static VALUE
14072argf_readbyte(VALUE argf)
14073{
14074 VALUE c;
14075
14076 NEXT_ARGF_FORWARD(0, 0);
14077 c = argf_getbyte(argf);
14078 if (NIL_P(c)) {
14079 rb_eof_error();
14080 }
14081 return c;
14082}
14083
14084#define FOREACH_ARGF() while (next_argv())
14085
14086static VALUE
14087argf_block_call_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
14088{
14089 const VALUE current = ARGF.current_file;
14090 rb_yield_values2(argc, argv);
14091 if (ARGF.init_p == -1 || current != ARGF.current_file) {
14093 }
14094 return Qnil;
14095}
14096
14097#define ARGF_block_call(mid, argc, argv, func, argf) \
14098 rb_block_call_kw(ARGF.current_file, mid, argc, argv, \
14099 func, argf, rb_keyword_given_p())
14100
14101static void
14102argf_block_call(ID mid, int argc, VALUE *argv, VALUE argf)
14103{
14104 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_i, argf);
14105 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14106}
14107
14108static VALUE
14109argf_block_call_line_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
14110{
14111 if (!global_argf_p(argf)) {
14112 ARGF.last_lineno = ++ARGF.lineno;
14113 }
14114 return argf_block_call_i(i, argf, argc, argv, blockarg);
14115}
14116
14117static void
14118argf_block_call_line(ID mid, int argc, VALUE *argv, VALUE argf)
14119{
14120 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_line_i, argf);
14121 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14122}
14123
14124/*
14125 * call-seq:
14126 * ARGF.each(sep=$/) {|line| block } -> ARGF
14127 * ARGF.each(sep=$/, limit) {|line| block } -> ARGF
14128 * ARGF.each(...) -> an_enumerator
14129 *
14130 * ARGF.each_line(sep=$/) {|line| block } -> ARGF
14131 * ARGF.each_line(sep=$/, limit) {|line| block } -> ARGF
14132 * ARGF.each_line(...) -> an_enumerator
14133 *
14134 * Returns an enumerator which iterates over each line (separated by _sep_,
14135 * which defaults to your platform's newline character) of each file in
14136 * +ARGV+. If a block is supplied, each line in turn will be yielded to the
14137 * block, otherwise an enumerator is returned.
14138 * The optional _limit_ argument is an Integer specifying the maximum
14139 * length of each line; longer lines will be split according to this limit.
14140 *
14141 * This method allows you to treat the files supplied on the command line as
14142 * a single file consisting of the concatenation of each named file. After
14143 * the last line of the first file has been returned, the first line of the
14144 * second file is returned. The ARGF.filename and ARGF.lineno methods can be
14145 * used to determine the filename of the current line and line number of the
14146 * whole input, respectively.
14147 *
14148 * For example, the following code prints out each line of each named file
14149 * prefixed with its line number, displaying the filename once per file:
14150 *
14151 * ARGF.each_line do |line|
14152 * puts ARGF.filename if ARGF.file.lineno == 1
14153 * puts "#{ARGF.file.lineno}: #{line}"
14154 * end
14155 *
14156 * While the following code prints only the first file's name at first, and
14157 * the contents with line number counted through all named files.
14158 *
14159 * ARGF.each_line do |line|
14160 * puts ARGF.filename if ARGF.lineno == 1
14161 * puts "#{ARGF.lineno}: #{line}"
14162 * end
14163 */
14164static VALUE
14165argf_each_line(int argc, VALUE *argv, VALUE argf)
14166{
14167 RETURN_ENUMERATOR(argf, argc, argv);
14168 FOREACH_ARGF() {
14169 argf_block_call_line(rb_intern("each_line"), argc, argv, argf);
14170 }
14171 return argf;
14172}
14173
14174/*
14175 * call-seq:
14176 * ARGF.each_byte {|byte| block } -> ARGF
14177 * ARGF.each_byte -> an_enumerator
14178 *
14179 * Iterates over each byte of each file in +ARGV+.
14180 * A byte is returned as an Integer in the range 0..255.
14181 *
14182 * This method allows you to treat the files supplied on the command line as
14183 * a single file consisting of the concatenation of each named file. After
14184 * the last byte of the first file has been returned, the first byte of the
14185 * second file is returned. The ARGF.filename method can be used to
14186 * determine the filename of the current byte.
14187 *
14188 * If no block is given, an enumerator is returned instead.
14189 *
14190 * For example:
14191 *
14192 * ARGF.bytes.to_a #=> [35, 32, ... 95, 10]
14193 *
14194 */
14195static VALUE
14196argf_each_byte(VALUE argf)
14197{
14198 RETURN_ENUMERATOR(argf, 0, 0);
14199 FOREACH_ARGF() {
14200 argf_block_call(rb_intern("each_byte"), 0, 0, argf);
14201 }
14202 return argf;
14203}
14204
14205/*
14206 * call-seq:
14207 * ARGF.each_char {|char| block } -> ARGF
14208 * ARGF.each_char -> an_enumerator
14209 *
14210 * Iterates over each character of each file in ARGF.
14211 *
14212 * This method allows you to treat the files supplied on the command line as
14213 * a single file consisting of the concatenation of each named file. After
14214 * the last character of the first file has been returned, the first
14215 * character of the second file is returned. The ARGF.filename method can
14216 * be used to determine the name of the file in which the current character
14217 * appears.
14218 *
14219 * If no block is given, an enumerator is returned instead.
14220 */
14221static VALUE
14222argf_each_char(VALUE argf)
14223{
14224 RETURN_ENUMERATOR(argf, 0, 0);
14225 FOREACH_ARGF() {
14226 argf_block_call(rb_intern("each_char"), 0, 0, argf);
14227 }
14228 return argf;
14229}
14230
14231/*
14232 * call-seq:
14233 * ARGF.each_codepoint {|codepoint| block } -> ARGF
14234 * ARGF.each_codepoint -> an_enumerator
14235 *
14236 * Iterates over each codepoint of each file in ARGF.
14237 *
14238 * This method allows you to treat the files supplied on the command line as
14239 * a single file consisting of the concatenation of each named file. After
14240 * the last codepoint of the first file has been returned, the first
14241 * codepoint of the second file is returned. The ARGF.filename method can
14242 * be used to determine the name of the file in which the current codepoint
14243 * appears.
14244 *
14245 * If no block is given, an enumerator is returned instead.
14246 */
14247static VALUE
14248argf_each_codepoint(VALUE argf)
14249{
14250 RETURN_ENUMERATOR(argf, 0, 0);
14251 FOREACH_ARGF() {
14252 argf_block_call(rb_intern("each_codepoint"), 0, 0, argf);
14253 }
14254 return argf;
14255}
14256
14257/*
14258 * call-seq:
14259 * ARGF.filename -> String
14260 * ARGF.path -> String
14261 *
14262 * Returns the current filename. "-" is returned when the current file is
14263 * STDIN.
14264 *
14265 * For example:
14266 *
14267 * $ echo "foo" > foo
14268 * $ echo "bar" > bar
14269 * $ echo "glark" > glark
14270 *
14271 * $ ruby argf.rb foo bar glark
14272 *
14273 * ARGF.filename #=> "foo"
14274 * ARGF.read(5) #=> "foo\nb"
14275 * ARGF.filename #=> "bar"
14276 * ARGF.skip
14277 * ARGF.filename #=> "glark"
14278 */
14279static VALUE
14280argf_filename(VALUE argf)
14281{
14282 next_argv();
14283 return ARGF.filename;
14284}
14285
14286static VALUE
14287argf_filename_getter(ID id, VALUE *var)
14288{
14289 return argf_filename(*var);
14290}
14291
14292/*
14293 * call-seq:
14294 * ARGF.file -> IO or File object
14295 *
14296 * Returns the current file as an IO or File object.
14297 * <code>$stdin</code> is returned when the current file is STDIN.
14298 *
14299 * For example:
14300 *
14301 * $ echo "foo" > foo
14302 * $ echo "bar" > bar
14303 *
14304 * $ ruby argf.rb foo bar
14305 *
14306 * ARGF.file #=> #<File:foo>
14307 * ARGF.read(5) #=> "foo\nb"
14308 * ARGF.file #=> #<File:bar>
14309 */
14310static VALUE
14311argf_file(VALUE argf)
14312{
14313 next_argv();
14314 return ARGF.current_file;
14315}
14316
14317/*
14318 * call-seq:
14319 * ARGF.binmode -> ARGF
14320 *
14321 * Puts ARGF into binary mode. Once a stream is in binary mode, it cannot
14322 * be reset to non-binary mode. This option has the following effects:
14323 *
14324 * * Newline conversion is disabled.
14325 * * Encoding conversion is disabled.
14326 * * Content is treated as ASCII-8BIT.
14327 */
14328static VALUE
14329argf_binmode_m(VALUE argf)
14330{
14331 ARGF.binmode = 1;
14332 next_argv();
14333 ARGF_FORWARD(0, 0);
14334 rb_io_ascii8bit_binmode(ARGF.current_file);
14335 return argf;
14336}
14337
14338/*
14339 * call-seq:
14340 * ARGF.binmode? -> true or false
14341 *
14342 * Returns true if ARGF is being read in binary mode; false otherwise.
14343 * To enable binary mode use ARGF.binmode.
14344 *
14345 * For example:
14346 *
14347 * ARGF.binmode? #=> false
14348 * ARGF.binmode
14349 * ARGF.binmode? #=> true
14350 */
14351static VALUE
14352argf_binmode_p(VALUE argf)
14353{
14354 return RBOOL(ARGF.binmode);
14355}
14356
14357/*
14358 * call-seq:
14359 * ARGF.skip -> ARGF
14360 *
14361 * Sets the current file to the next file in ARGV. If there aren't any more
14362 * files it has no effect.
14363 *
14364 * For example:
14365 *
14366 * $ ruby argf.rb foo bar
14367 * ARGF.filename #=> "foo"
14368 * ARGF.skip
14369 * ARGF.filename #=> "bar"
14370 */
14371static VALUE
14372argf_skip(VALUE argf)
14373{
14374 if (ARGF.init_p && ARGF.next_p == 0) {
14375 argf_close(argf);
14376 ARGF.next_p = 1;
14377 }
14378 return argf;
14379}
14380
14381/*
14382 * call-seq:
14383 * ARGF.close -> ARGF
14384 *
14385 * Closes the current file and skips to the next file in ARGV. If there are
14386 * no more files to open, just closes the current file. STDIN will not be
14387 * closed.
14388 *
14389 * For example:
14390 *
14391 * $ ruby argf.rb foo bar
14392 *
14393 * ARGF.filename #=> "foo"
14394 * ARGF.close
14395 * ARGF.filename #=> "bar"
14396 * ARGF.close
14397 */
14398static VALUE
14399argf_close_m(VALUE argf)
14400{
14401 next_argv();
14402 argf_close(argf);
14403 if (ARGF.next_p != -1) {
14404 ARGF.next_p = 1;
14405 }
14406 ARGF.lineno = 0;
14407 return argf;
14408}
14409
14410/*
14411 * call-seq:
14412 * ARGF.closed? -> true or false
14413 *
14414 * Returns _true_ if the current file has been closed; _false_ otherwise. Use
14415 * ARGF.close to actually close the current file.
14416 */
14417static VALUE
14418argf_closed(VALUE argf)
14419{
14420 next_argv();
14421 ARGF_FORWARD(0, 0);
14422 return rb_io_closed(ARGF.current_file);
14423}
14424
14425/*
14426 * call-seq:
14427 * ARGF.to_s -> String
14428 *
14429 * Returns "ARGF".
14430 */
14431static VALUE
14432argf_to_s(VALUE argf)
14433{
14434 return rb_str_new2("ARGF");
14435}
14436
14437/*
14438 * call-seq:
14439 * ARGF.inplace_mode -> String
14440 *
14441 * Returns the file extension appended to the names of backup copies of
14442 * modified files under in-place edit mode. This value can be set using
14443 * ARGF.inplace_mode= or passing the +-i+ switch to the Ruby binary.
14444 */
14445static VALUE
14446argf_inplace_mode_get(VALUE argf)
14447{
14448 if (!ARGF.inplace) return Qnil;
14449 if (NIL_P(ARGF.inplace)) return rb_str_new(0, 0);
14450 return rb_str_dup(ARGF.inplace);
14451}
14452
14453static VALUE
14454opt_i_get(ID id, VALUE *var)
14455{
14456 return argf_inplace_mode_get(*var);
14457}
14458
14459/*
14460 * call-seq:
14461 * ARGF.inplace_mode = ext -> ARGF
14462 *
14463 * Sets the filename extension for in-place editing mode to the given String.
14464 * The backup copy of each file being edited has this value appended to its
14465 * filename.
14466 *
14467 * For example:
14468 *
14469 * $ ruby argf.rb file.txt
14470 *
14471 * ARGF.inplace_mode = '.bak'
14472 * ARGF.each_line do |line|
14473 * print line.sub("foo","bar")
14474 * end
14475 *
14476 * First, _file.txt.bak_ is created as a backup copy of _file.txt_.
14477 * Then, each line of _file.txt_ has the first occurrence of "foo" replaced with
14478 * "bar".
14479 */
14480static VALUE
14481argf_inplace_mode_set(VALUE argf, VALUE val)
14482{
14483 if (!RTEST(val)) {
14484 ARGF.inplace = Qfalse;
14485 }
14486 else if (StringValueCStr(val), !RSTRING_LEN(val)) {
14487 ARGF.inplace = Qnil;
14488 }
14489 else {
14490 ARGF.inplace = rb_str_new_frozen(val);
14491 }
14492 return argf;
14493}
14494
14495static void
14496opt_i_set(VALUE val, ID id, VALUE *var)
14497{
14498 argf_inplace_mode_set(*var, val);
14499}
14500
14501void
14502ruby_set_inplace_mode(const char *suffix)
14503{
14504 ARGF.inplace = !suffix ? Qfalse : !*suffix ? Qnil : rb_str_new(suffix, strlen(suffix));
14505}
14506
14507/*
14508 * call-seq:
14509 * ARGF.argv -> ARGV
14510 *
14511 * Returns the +ARGV+ array, which contains the arguments passed to your
14512 * script, one per element.
14513 *
14514 * For example:
14515 *
14516 * $ ruby argf.rb -v glark.txt
14517 *
14518 * ARGF.argv #=> ["-v", "glark.txt"]
14519 *
14520 */
14521static VALUE
14522argf_argv(VALUE argf)
14523{
14524 return ARGF.argv;
14525}
14526
14527static VALUE
14528argf_argv_getter(ID id, VALUE *var)
14529{
14530 return argf_argv(*var);
14531}
14532
14533VALUE
14535{
14536 return ARGF.argv;
14537}
14538
14539/*
14540 * call-seq:
14541 * ARGF.to_write_io -> io
14542 *
14543 * Returns IO instance tied to _ARGF_ for writing if inplace mode is
14544 * enabled.
14545 */
14546static VALUE
14547argf_write_io(VALUE argf)
14548{
14549 if (!RTEST(ARGF.current_file)) {
14550 rb_raise(rb_eIOError, "not opened for writing");
14551 }
14552 return GetWriteIO(ARGF.current_file);
14553}
14554
14555/*
14556 * call-seq:
14557 * ARGF.write(string) -> integer
14558 *
14559 * Writes _string_ if inplace mode.
14560 */
14561static VALUE
14562argf_write(VALUE argf, VALUE str)
14563{
14564 return rb_io_write(argf_write_io(argf), str);
14565}
14566
14567void
14568rb_readwrite_sys_fail(enum rb_io_wait_readwrite waiting, const char *mesg)
14569{
14570 rb_readwrite_syserr_fail(waiting, errno, mesg);
14571}
14572
14573void
14574rb_readwrite_syserr_fail(enum rb_io_wait_readwrite waiting, int n, const char *mesg)
14575{
14576 VALUE arg, c = Qnil;
14577 arg = mesg ? rb_str_new2(mesg) : Qnil;
14578 switch (waiting) {
14579 case RB_IO_WAIT_WRITABLE:
14580 switch (n) {
14581 case EAGAIN:
14582 c = rb_eEAGAINWaitWritable;
14583 break;
14584#if EAGAIN != EWOULDBLOCK
14585 case EWOULDBLOCK:
14586 c = rb_eEWOULDBLOCKWaitWritable;
14587 break;
14588#endif
14589 case EINPROGRESS:
14590 c = rb_eEINPROGRESSWaitWritable;
14591 break;
14592 default:
14594 }
14595 break;
14596 case RB_IO_WAIT_READABLE:
14597 switch (n) {
14598 case EAGAIN:
14599 c = rb_eEAGAINWaitReadable;
14600 break;
14601#if EAGAIN != EWOULDBLOCK
14602 case EWOULDBLOCK:
14603 c = rb_eEWOULDBLOCKWaitReadable;
14604 break;
14605#endif
14606 case EINPROGRESS:
14607 c = rb_eEINPROGRESSWaitReadable;
14608 break;
14609 default:
14611 }
14612 break;
14613 default:
14614 rb_bug("invalid read/write type passed to rb_readwrite_sys_fail: %d", waiting);
14615 }
14617}
14618
14619static VALUE
14620get_LAST_READ_LINE(ID _x, VALUE *_y)
14621{
14622 return rb_lastline_get();
14623}
14624
14625static void
14626set_LAST_READ_LINE(VALUE val, ID _x, VALUE *_y)
14627{
14628 rb_lastline_set(val);
14629}
14630
14631/*
14632 * Document-class: IOError
14633 *
14634 * Raised when an IO operation fails.
14635 *
14636 * File.open("/etc/hosts") {|f| f << "example"}
14637 * #=> IOError: not opened for writing
14638 *
14639 * File.open("/etc/hosts") {|f| f.close; f.read }
14640 * #=> IOError: closed stream
14641 *
14642 * Note that some IO failures raise <code>SystemCallError</code>s
14643 * and these are not subclasses of IOError:
14644 *
14645 * File.open("does/not/exist")
14646 * #=> Errno::ENOENT: No such file or directory - does/not/exist
14647 */
14648
14649/*
14650 * Document-class: EOFError
14651 *
14652 * Raised by some IO operations when reaching the end of file. Many IO
14653 * methods exist in two forms,
14654 *
14655 * one that returns +nil+ when the end of file is reached, the other
14656 * raises EOFError.
14657 *
14658 * EOFError is a subclass of IOError.
14659 *
14660 * file = File.open("/etc/hosts")
14661 * file.read
14662 * file.gets #=> nil
14663 * file.readline #=> EOFError: end of file reached
14664 * file.close
14665 */
14666
14667/*
14668 * Document-class: ARGF
14669 *
14670 * ARGF is a stream designed for use in scripts that process files given as
14671 * command-line arguments or passed in via STDIN.
14672 *
14673 * The arguments passed to your script are stored in the +ARGV+ Array, one
14674 * argument per element. ARGF assumes that any arguments that aren't
14675 * filenames have been removed from +ARGV+. For example:
14676 *
14677 * $ ruby argf.rb --verbose file1 file2
14678 *
14679 * ARGV #=> ["--verbose", "file1", "file2"]
14680 * option = ARGV.shift #=> "--verbose"
14681 * ARGV #=> ["file1", "file2"]
14682 *
14683 * You can now use ARGF to work with a concatenation of each of these named
14684 * files. For instance, ARGF.read will return the contents of _file1_
14685 * followed by the contents of _file2_.
14686 *
14687 * After a file in +ARGV+ has been read ARGF removes it from the Array.
14688 * Thus, after all files have been read +ARGV+ will be empty.
14689 *
14690 * You can manipulate +ARGV+ yourself to control what ARGF operates on. If
14691 * you remove a file from +ARGV+, it is ignored by ARGF; if you add files to
14692 * +ARGV+, they are treated as if they were named on the command line. For
14693 * example:
14694 *
14695 * ARGV.replace ["file1"]
14696 * ARGF.readlines # Returns the contents of file1 as an Array
14697 * ARGV #=> []
14698 * ARGV.replace ["file2", "file3"]
14699 * ARGF.read # Returns the contents of file2 and file3
14700 *
14701 * If +ARGV+ is empty, ARGF acts as if it contained STDIN, i.e. the data
14702 * piped to your script. For example:
14703 *
14704 * $ echo "glark" | ruby -e 'p ARGF.read'
14705 * "glark\n"
14706 */
14707
14708/*
14709 * An instance of class \IO (commonly called a _stream_)
14710 * represents an input/output stream in the underlying operating system.
14711 * \Class \IO is the basis for input and output in Ruby.
14712 *
14713 * \Class File is the only class in the Ruby core that is a subclass of \IO.
14714 * Some classes in the Ruby standard library are also subclasses of \IO;
14715 * these include TCPSocket and UDPSocket.
14716 *
14717 * The global constant ARGF (also accessible as <tt>$<</tt>)
14718 * provides an IO-like stream that allows access to all file paths
14719 * found in ARGV (or found in STDIN if ARGV is empty).
14720 * ARGF is not itself a subclass of \IO.
14721 *
14722 * \Class StringIO provides an IO-like stream that handles a String.
14723 * \StringIO is not itself a subclass of \IO.
14724 *
14725 * Important objects based on \IO include:
14726 *
14727 * - $stdin.
14728 * - $stdout.
14729 * - $stderr.
14730 * - Instances of class File.
14731 *
14732 * An instance of \IO may be created using:
14733 *
14734 * - IO.new: returns a new \IO object for the given integer file descriptor.
14735 * - IO.open: passes a new \IO object to the given block.
14736 * - IO.popen: returns a new \IO object that is connected to the $stdin and $stdout
14737 * of a newly-launched subprocess.
14738 * - Kernel#open: Returns a new \IO object connected to a given source:
14739 * stream, file, or subprocess.
14740 *
14741 * Like a \File stream, an \IO stream has:
14742 *
14743 * - A read/write mode, which may be read-only, write-only, or read/write;
14744 * see {Read/Write Mode}[rdoc-ref:File@Read-2FWrite+Mode].
14745 * - A data mode, which may be text-only or binary;
14746 * see {Data Mode}[rdoc-ref:File@Data+Mode].
14747 * - Internal and external encodings;
14748 * see {Encodings}[rdoc-ref:File@Encodings].
14749 *
14750 * And like other \IO streams, it has:
14751 *
14752 * - A position, which determines where in the stream the next
14753 * read or write is to occur;
14754 * see {Position}[rdoc-ref:IO@Position].
14755 * - A line number, which is a special, line-oriented, "position"
14756 * (different from the position mentioned above);
14757 * see {Line Number}[rdoc-ref:IO@Line+Number].
14758 *
14759 * == Extension <tt>io/console</tt>
14760 *
14761 * Extension <tt>io/console</tt> provides numerous methods
14762 * for interacting with the console;
14763 * requiring it adds numerous methods to class \IO.
14764 *
14765 * == Example Files
14766 *
14767 * Many examples here use these variables:
14768 *
14769 * :include: doc/examples/files.rdoc
14770 *
14771 * == Open Options
14772 *
14773 * A number of \IO methods accept optional keyword arguments
14774 * that determine how a new stream is to be opened:
14775 *
14776 * - +:mode+: Stream mode.
14777 * - +:flags+: \Integer file open flags;
14778 * If +mode+ is also given, the two are bitwise-ORed.
14779 * - +:external_encoding+: External encoding for the stream.
14780 * - +:internal_encoding+: Internal encoding for the stream.
14781 * <tt>'-'</tt> is a synonym for the default internal encoding.
14782 * If the value is +nil+ no conversion occurs.
14783 * - +:encoding+: Specifies external and internal encodings as <tt>'extern:intern'</tt>.
14784 * - +:textmode+: If a truthy value, specifies the mode as text-only, binary otherwise.
14785 * - +:binmode+: If a truthy value, specifies the mode as binary, text-only otherwise.
14786 * - +:autoclose+: If a truthy value, specifies that the +fd+ will close
14787 * when the stream closes; otherwise it remains open.
14788 * - +:path:+ If a string value is provided, it is used in #inspect and is available as
14789 * #path method.
14790 *
14791 * Also available are the options offered in String#encode,
14792 * which may control conversion between external internal encoding.
14793 *
14794 * == Basic \IO
14795 *
14796 * You can perform basic stream \IO with these methods,
14797 * which typically operate on multi-byte strings:
14798 *
14799 * - IO#read: Reads and returns some or all of the remaining bytes from the stream.
14800 * - IO#write: Writes zero or more strings to the stream;
14801 * each given object that is not already a string is converted via +to_s+.
14802 *
14803 * === Position
14804 *
14805 * An \IO stream has a nonnegative integer _position_,
14806 * which is the byte offset at which the next read or write is to occur.
14807 * A new stream has position zero (and line number zero);
14808 * method +rewind+ resets the position (and line number) to zero.
14809 *
14810 * The relevant methods:
14811 *
14812 * - IO#tell (aliased as +#pos+): Returns the current position (in bytes) in the stream.
14813 * - IO#pos=: Sets the position of the stream to a given integer +new_position+ (in bytes).
14814 * - IO#seek: Sets the position of the stream to a given integer +offset+ (in bytes),
14815 * relative to a given position +whence+
14816 * (indicating the beginning, end, or current position).
14817 * - IO#rewind: Positions the stream at the beginning (also resetting the line number).
14818 *
14819 * === Open and Closed Streams
14820 *
14821 * A new \IO stream may be open for reading, open for writing, or both.
14822 *
14823 * A stream is automatically closed when claimed by the garbage collector.
14824 *
14825 * Attempted reading or writing on a closed stream raises an exception.
14826 *
14827 * The relevant methods:
14828 *
14829 * - IO#close: Closes the stream for both reading and writing.
14830 * - IO#close_read: Closes the stream for reading.
14831 * - IO#close_write: Closes the stream for writing.
14832 * - IO#closed?: Returns whether the stream is closed.
14833 *
14834 * === End-of-Stream
14835 *
14836 * You can query whether a stream is positioned at its end:
14837 *
14838 * - IO#eof? (also aliased as +#eof+): Returns whether the stream is at end-of-stream.
14839 *
14840 * You can reposition to end-of-stream by using method IO#seek:
14841 *
14842 * f = File.new('t.txt')
14843 * f.eof? # => false
14844 * f.seek(0, :END)
14845 * f.eof? # => true
14846 * f.close
14847 *
14848 * Or by reading all stream content (which is slower than using IO#seek):
14849 *
14850 * f.rewind
14851 * f.eof? # => false
14852 * f.read # => "First line\nSecond line\n\nFourth line\nFifth line\n"
14853 * f.eof? # => true
14854 *
14855 * == Line \IO
14856 *
14857 * You can read an \IO stream line-by-line using these methods:
14858 *
14859 * - IO#each_line: Reads each remaining line, passing it to the given block.
14860 * - IO#gets: Returns the next line.
14861 * - IO#readline: Like #gets, but raises an exception at end-of-stream.
14862 * - IO#readlines: Returns all remaining lines in an array.
14863 *
14864 * Each of these reader methods accepts:
14865 *
14866 * - An optional line separator, +sep+;
14867 * see {Line Separator}[rdoc-ref:IO@Line+Separator].
14868 * - An optional line-size limit, +limit+;
14869 * see {Line Limit}[rdoc-ref:IO@Line+Limit].
14870 *
14871 * For each of these reader methods, reading may begin mid-line,
14872 * depending on the stream's position;
14873 * see {Position}[rdoc-ref:IO@Position]:
14874 *
14875 * f = File.new('t.txt')
14876 * f.pos = 27
14877 * f.each_line {|line| p line }
14878 * f.close
14879 *
14880 * Output:
14881 *
14882 * "rth line\n"
14883 * "Fifth line\n"
14884 *
14885 * You can write to an \IO stream line-by-line using this method:
14886 *
14887 * - IO#puts: Writes objects to the stream.
14888 *
14889 * === Line Separator
14890 *
14891 * Each of these methods uses a <i>line separator</i>,
14892 * which is the string that delimits lines:
14893 *
14894 * - IO.foreach.
14895 * - IO.readlines.
14896 * - IO#each_line.
14897 * - IO#gets.
14898 * - IO#readline.
14899 * - IO#readlines.
14900 *
14901 * The default line separator is the given by the global variable <tt>$/</tt>,
14902 * whose value is by default <tt>"\n"</tt>.
14903 * The line to be read next is all data from the current position
14904 * to the next line separator:
14905 *
14906 * f = File.new('t.txt')
14907 * f.gets # => "First line\n"
14908 * f.gets # => "Second line\n"
14909 * f.gets # => "\n"
14910 * f.gets # => "Fourth line\n"
14911 * f.gets # => "Fifth line\n"
14912 * f.close
14913 *
14914 * You can specify a different line separator:
14915 *
14916 * f = File.new('t.txt')
14917 * f.gets('l') # => "First l"
14918 * f.gets('li') # => "ine\nSecond li"
14919 * f.gets('lin') # => "ne\n\nFourth lin"
14920 * f.gets # => "e\n"
14921 * f.close
14922 *
14923 * There are two special line separators:
14924 *
14925 * - +nil+: The entire stream is read into a single string:
14926 *
14927 * f = File.new('t.txt')
14928 * f.gets(nil) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
14929 * f.close
14930 *
14931 * - <tt>''</tt> (the empty string): The next "paragraph" is read
14932 * (paragraphs being separated by two consecutive line separators):
14933 *
14934 * f = File.new('t.txt')
14935 * f.gets('') # => "First line\nSecond line\n\n"
14936 * f.gets('') # => "Fourth line\nFifth line\n"
14937 * f.close
14938 *
14939 * === Line Limit
14940 *
14941 * Each of these methods uses a <i>line limit</i>,
14942 * which specifies that the number of bytes returned may not be (much) longer
14943 * than the given +limit+;
14944 *
14945 * - IO.foreach.
14946 * - IO.readlines.
14947 * - IO#each_line.
14948 * - IO#gets.
14949 * - IO#readline.
14950 * - IO#readlines.
14951 *
14952 * A multi-byte character will not be split, and so a line may be slightly longer
14953 * than the given limit.
14954 *
14955 * If +limit+ is not given, the line is determined only by +sep+.
14956 *
14957 * # Text with 1-byte characters.
14958 * File.open('t.txt') {|f| f.gets(1) } # => "F"
14959 * File.open('t.txt') {|f| f.gets(2) } # => "Fi"
14960 * File.open('t.txt') {|f| f.gets(3) } # => "Fir"
14961 * File.open('t.txt') {|f| f.gets(4) } # => "Firs"
14962 * # No more than one line.
14963 * File.open('t.txt') {|f| f.gets(10) } # => "First line"
14964 * File.open('t.txt') {|f| f.gets(11) } # => "First line\n"
14965 * File.open('t.txt') {|f| f.gets(12) } # => "First line\n"
14966 *
14967 * # Text with 2-byte characters, which will not be split.
14968 * File.open('t.rus') {|f| f.gets(1).size } # => 1
14969 * File.open('t.rus') {|f| f.gets(2).size } # => 1
14970 * File.open('t.rus') {|f| f.gets(3).size } # => 2
14971 * File.open('t.rus') {|f| f.gets(4).size } # => 2
14972 *
14973 * === Line Separator and Line Limit
14974 *
14975 * With arguments +sep+ and +limit+ given,
14976 * combines the two behaviors:
14977 *
14978 * - Returns the next line as determined by line separator +sep+.
14979 * - But returns no more bytes than are allowed by the limit.
14980 *
14981 * Example:
14982 *
14983 * File.open('t.txt') {|f| f.gets('li', 20) } # => "First li"
14984 * File.open('t.txt') {|f| f.gets('li', 2) } # => "Fi"
14985 *
14986 * === Line Number
14987 *
14988 * A readable \IO stream has a non-negative integer <i>line number</i>.
14989 *
14990 * The relevant methods:
14991 *
14992 * - IO#lineno: Returns the line number.
14993 * - IO#lineno=: Resets and returns the line number.
14994 *
14995 * Unless modified by a call to method IO#lineno=,
14996 * the line number is the number of lines read
14997 * by certain line-oriented methods,
14998 * according to the given line separator +sep+:
14999 *
15000 * - IO.foreach: Increments the line number on each call to the block.
15001 * - IO#each_line: Increments the line number on each call to the block.
15002 * - IO#gets: Increments the line number.
15003 * - IO#readline: Increments the line number.
15004 * - IO#readlines: Increments the line number for each line read.
15005 *
15006 * A new stream is initially has line number zero (and position zero);
15007 * method +rewind+ resets the line number (and position) to zero:
15008 *
15009 * f = File.new('t.txt')
15010 * f.lineno # => 0
15011 * f.gets # => "First line\n"
15012 * f.lineno # => 1
15013 * f.rewind
15014 * f.lineno # => 0
15015 * f.close
15016 *
15017 * Reading lines from a stream usually changes its line number:
15018 *
15019 * f = File.new('t.txt', 'r')
15020 * f.lineno # => 0
15021 * f.readline # => "This is line one.\n"
15022 * f.lineno # => 1
15023 * f.readline # => "This is the second line.\n"
15024 * f.lineno # => 2
15025 * f.readline # => "Here's the third line.\n"
15026 * f.lineno # => 3
15027 * f.eof? # => true
15028 * f.close
15029 *
15030 * Iterating over lines in a stream usually changes its line number:
15031 *
15032 * File.open('t.txt') do |f|
15033 * f.each_line do |line|
15034 * p "position=#{f.pos} eof?=#{f.eof?} lineno=#{f.lineno}"
15035 * end
15036 * end
15037 *
15038 * Output:
15039 *
15040 * "position=11 eof?=false lineno=1"
15041 * "position=23 eof?=false lineno=2"
15042 * "position=24 eof?=false lineno=3"
15043 * "position=36 eof?=false lineno=4"
15044 * "position=47 eof?=true lineno=5"
15045 *
15046 * Unlike the stream's {position}[rdoc-ref:IO@Position],
15047 * the line number does not affect where the next read or write will occur:
15048 *
15049 * f = File.new('t.txt')
15050 * f.lineno = 1000
15051 * f.lineno # => 1000
15052 * f.gets # => "First line\n"
15053 * f.lineno # => 1001
15054 * f.close
15055 *
15056 * Associated with the line number is the global variable <tt>$.</tt>:
15057 *
15058 * - When a stream is opened, <tt>$.</tt> is not set;
15059 * its value is left over from previous activity in the process:
15060 *
15061 * $. = 41
15062 * f = File.new('t.txt')
15063 * $. = 41
15064 * # => 41
15065 * f.close
15066 *
15067 * - When a stream is read, <tt>#.</tt> is set to the line number for that stream:
15068 *
15069 * f0 = File.new('t.txt')
15070 * f1 = File.new('t.dat')
15071 * f0.readlines # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
15072 * $. # => 5
15073 * f1.readlines # => ["\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"]
15074 * $. # => 1
15075 * f0.close
15076 * f1.close
15077 *
15078 * - Methods IO#rewind and IO#seek do not affect <tt>$.</tt>:
15079 *
15080 * f = File.new('t.txt')
15081 * f.readlines # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
15082 * $. # => 5
15083 * f.rewind
15084 * f.seek(0, :SET)
15085 * $. # => 5
15086 * f.close
15087 *
15088 * == Character \IO
15089 *
15090 * You can process an \IO stream character-by-character using these methods:
15091 *
15092 * - IO#getc: Reads and returns the next character from the stream.
15093 * - IO#readchar: Like #getc, but raises an exception at end-of-stream.
15094 * - IO#ungetc: Pushes back ("unshifts") a character or integer onto the stream.
15095 * - IO#putc: Writes a character to the stream.
15096 * - IO#each_char: Reads each remaining character in the stream,
15097 * passing the character to the given block.
15098 * == Byte \IO
15099 *
15100 * You can process an \IO stream byte-by-byte using these methods:
15101 *
15102 * - IO#getbyte: Returns the next 8-bit byte as an integer in range 0..255.
15103 * - IO#readbyte: Like #getbyte, but raises an exception if at end-of-stream.
15104 * - IO#ungetbyte: Pushes back ("unshifts") a byte back onto the stream.
15105 * - IO#each_byte: Reads each remaining byte in the stream,
15106 * passing the byte to the given block.
15107 *
15108 * == Codepoint \IO
15109 *
15110 * You can process an \IO stream codepoint-by-codepoint:
15111 *
15112 * - IO#each_codepoint: Reads each remaining codepoint, passing it to the given block.
15113 *
15114 * == What's Here
15115 *
15116 * First, what's elsewhere. \Class \IO:
15117 *
15118 * - Inherits from {class Object}[rdoc-ref:Object@What-27s+Here].
15119 * - Includes {module Enumerable}[rdoc-ref:Enumerable@What-27s+Here],
15120 * which provides dozens of additional methods.
15121 *
15122 * Here, class \IO provides methods that are useful for:
15123 *
15124 * - {Creating}[rdoc-ref:IO@Creating]
15125 * - {Reading}[rdoc-ref:IO@Reading]
15126 * - {Writing}[rdoc-ref:IO@Writing]
15127 * - {Positioning}[rdoc-ref:IO@Positioning]
15128 * - {Iterating}[rdoc-ref:IO@Iterating]
15129 * - {Settings}[rdoc-ref:IO@Settings]
15130 * - {Querying}[rdoc-ref:IO@Querying]
15131 * - {Buffering}[rdoc-ref:IO@Buffering]
15132 * - {Low-Level Access}[rdoc-ref:IO@Low-Level+Access]
15133 * - {Other}[rdoc-ref:IO@Other]
15134 *
15135 * === Creating
15136 *
15137 * - ::new (aliased as ::for_fd): Creates and returns a new \IO object for the given
15138 * integer file descriptor.
15139 * - ::open: Creates a new \IO object.
15140 * - ::pipe: Creates a connected pair of reader and writer \IO objects.
15141 * - ::popen: Creates an \IO object to interact with a subprocess.
15142 * - ::select: Selects which given \IO instances are ready for reading,
15143 * writing, or have pending exceptions.
15144 *
15145 * === Reading
15146 *
15147 * - ::binread: Returns a binary string with all or a subset of bytes
15148 * from the given file.
15149 * - ::read: Returns a string with all or a subset of bytes from the given file.
15150 * - ::readlines: Returns an array of strings, which are the lines from the given file.
15151 * - #getbyte: Returns the next 8-bit byte read from +self+ as an integer.
15152 * - #getc: Returns the next character read from +self+ as a string.
15153 * - #gets: Returns the line read from +self+.
15154 * - #pread: Returns all or the next _n_ bytes read from +self+,
15155 * not updating the receiver's offset.
15156 * - #read: Returns all remaining or the next _n_ bytes read from +self+
15157 * for a given _n_.
15158 * - #read_nonblock: the next _n_ bytes read from +self+ for a given _n_,
15159 * in non-block mode.
15160 * - #readbyte: Returns the next byte read from +self+;
15161 * same as #getbyte, but raises an exception on end-of-stream.
15162 * - #readchar: Returns the next character read from +self+;
15163 * same as #getc, but raises an exception on end-of-stream.
15164 * - #readline: Returns the next line read from +self+;
15165 * same as #getline, but raises an exception of end-of-stream.
15166 * - #readlines: Returns an array of all lines read read from +self+.
15167 * - #readpartial: Returns up to the given number of bytes from +self+.
15168 *
15169 * === Writing
15170 *
15171 * - ::binwrite: Writes the given string to the file at the given filepath,
15172 * in binary mode.
15173 * - ::write: Writes the given string to +self+.
15174 * - #<<: Appends the given string to +self+.
15175 * - #print: Prints last read line or given objects to +self+.
15176 * - #printf: Writes to +self+ based on the given format string and objects.
15177 * - #putc: Writes a character to +self+.
15178 * - #puts: Writes lines to +self+, making sure line ends with a newline.
15179 * - #pwrite: Writes the given string at the given offset,
15180 * not updating the receiver's offset.
15181 * - #write: Writes one or more given strings to +self+.
15182 * - #write_nonblock: Writes one or more given strings to +self+ in non-blocking mode.
15183 *
15184 * === Positioning
15185 *
15186 * - #lineno: Returns the current line number in +self+.
15187 * - #lineno=: Sets the line number is +self+.
15188 * - #pos (aliased as #tell): Returns the current byte offset in +self+.
15189 * - #pos=: Sets the byte offset in +self+.
15190 * - #reopen: Reassociates +self+ with a new or existing \IO stream.
15191 * - #rewind: Positions +self+ to the beginning of input.
15192 * - #seek: Sets the offset for +self+ relative to given position.
15193 *
15194 * === Iterating
15195 *
15196 * - ::foreach: Yields each line of given file to the block.
15197 * - #each (aliased as #each_line): Calls the given block
15198 * with each successive line in +self+.
15199 * - #each_byte: Calls the given block with each successive byte in +self+
15200 * as an integer.
15201 * - #each_char: Calls the given block with each successive character in +self+
15202 * as a string.
15203 * - #each_codepoint: Calls the given block with each successive codepoint in +self+
15204 * as an integer.
15205 *
15206 * === Settings
15207 *
15208 * - #autoclose=: Sets whether +self+ auto-closes.
15209 * - #binmode: Sets +self+ to binary mode.
15210 * - #close: Closes +self+.
15211 * - #close_on_exec=: Sets the close-on-exec flag.
15212 * - #close_read: Closes +self+ for reading.
15213 * - #close_write: Closes +self+ for writing.
15214 * - #set_encoding: Sets the encoding for +self+.
15215 * - #set_encoding_by_bom: Sets the encoding for +self+, based on its
15216 * Unicode byte-order-mark.
15217 * - #sync=: Sets the sync-mode to the given value.
15218 *
15219 * === Querying
15220 *
15221 * - #autoclose?: Returns whether +self+ auto-closes.
15222 * - #binmode?: Returns whether +self+ is in binary mode.
15223 * - #close_on_exec?: Returns the close-on-exec flag for +self+.
15224 * - #closed?: Returns whether +self+ is closed.
15225 * - #eof? (aliased as #eof): Returns whether +self+ is at end-of-stream.
15226 * - #external_encoding: Returns the external encoding object for +self+.
15227 * - #fileno (aliased as #to_i): Returns the integer file descriptor for +self+
15228 * - #internal_encoding: Returns the internal encoding object for +self+.
15229 * - #pid: Returns the process ID of a child process associated with +self+,
15230 * if +self+ was created by ::popen.
15231 * - #stat: Returns the File::Stat object containing status information for +self+.
15232 * - #sync: Returns whether +self+ is in sync-mode.
15233 * - #tty? (aliased as #isatty): Returns whether +self+ is a terminal.
15234 *
15235 * === Buffering
15236 *
15237 * - #fdatasync: Immediately writes all buffered data in +self+ to disk.
15238 * - #flush: Flushes any buffered data within +self+ to the underlying
15239 * operating system.
15240 * - #fsync: Immediately writes all buffered data and attributes in +self+ to disk.
15241 * - #ungetbyte: Prepends buffer for +self+ with given integer byte or string.
15242 * - #ungetc: Prepends buffer for +self+ with given string.
15243 *
15244 * === Low-Level Access
15245 *
15246 * - ::sysopen: Opens the file given by its path,
15247 * returning the integer file descriptor.
15248 * - #advise: Announces the intention to access data from +self+ in a specific way.
15249 * - #fcntl: Passes a low-level command to the file specified
15250 * by the given file descriptor.
15251 * - #ioctl: Passes a low-level command to the device specified
15252 * by the given file descriptor.
15253 * - #sysread: Returns up to the next _n_ bytes read from self using a low-level read.
15254 * - #sysseek: Sets the offset for +self+.
15255 * - #syswrite: Writes the given string to +self+ using a low-level write.
15256 *
15257 * === Other
15258 *
15259 * - ::copy_stream: Copies data from a source to a destination,
15260 * each of which is a filepath or an \IO-like object.
15261 * - ::try_convert: Returns a new \IO object resulting from converting
15262 * the given object.
15263 * - #inspect: Returns the string representation of +self+.
15264 *
15265 */
15266
15267void
15268Init_IO(void)
15269{
15270 VALUE rb_cARGF;
15271#ifdef __CYGWIN__
15272#include <sys/cygwin.h>
15273 static struct __cygwin_perfile pf[] =
15274 {
15275 {"", O_RDONLY | O_BINARY},
15276 {"", O_WRONLY | O_BINARY},
15277 {"", O_RDWR | O_BINARY},
15278 {"", O_APPEND | O_BINARY},
15279 {NULL, 0}
15280 };
15281 cygwin_internal(CW_PERFILE, pf);
15282#endif
15283
15286
15287 id_write = rb_intern_const("write");
15288 id_read = rb_intern_const("read");
15289 id_getc = rb_intern_const("getc");
15290 id_flush = rb_intern_const("flush");
15291 id_readpartial = rb_intern_const("readpartial");
15292 id_set_encoding = rb_intern_const("set_encoding");
15293 id_fileno = rb_intern_const("fileno");
15294
15295 rb_define_global_function("syscall", rb_f_syscall, -1);
15296
15297 rb_define_global_function("open", rb_f_open, -1);
15298 rb_define_global_function("printf", rb_f_printf, -1);
15299 rb_define_global_function("print", rb_f_print, -1);
15300 rb_define_global_function("putc", rb_f_putc, 1);
15301 rb_define_global_function("puts", rb_f_puts, -1);
15302 rb_define_global_function("gets", rb_f_gets, -1);
15303 rb_define_global_function("readline", rb_f_readline, -1);
15304 rb_define_global_function("select", rb_f_select, -1);
15305
15306 rb_define_global_function("readlines", rb_f_readlines, -1);
15307
15308 rb_define_global_function("`", rb_f_backquote, 1);
15309
15310 rb_define_global_function("p", rb_f_p, -1);
15311 rb_define_method(rb_mKernel, "display", rb_obj_display, -1);
15312
15313 rb_cIO = rb_define_class("IO", rb_cObject);
15315
15317
15321
15322 /* exception to wait for reading. see IO.select. */
15324 /* exception to wait for writing. see IO.select. */
15326 /* exception to wait for reading by EAGAIN. see IO.select. */
15327 rb_eEAGAINWaitReadable = rb_define_class_under(rb_cIO, "EAGAINWaitReadable", rb_eEAGAIN);
15328 rb_include_module(rb_eEAGAINWaitReadable, rb_mWaitReadable);
15329 /* exception to wait for writing by EAGAIN. see IO.select. */
15330 rb_eEAGAINWaitWritable = rb_define_class_under(rb_cIO, "EAGAINWaitWritable", rb_eEAGAIN);
15331 rb_include_module(rb_eEAGAINWaitWritable, rb_mWaitWritable);
15332#if EAGAIN == EWOULDBLOCK
15333 rb_eEWOULDBLOCKWaitReadable = rb_eEAGAINWaitReadable;
15334 /* same as IO::EAGAINWaitReadable */
15335 rb_define_const(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEAGAINWaitReadable);
15336 rb_eEWOULDBLOCKWaitWritable = rb_eEAGAINWaitWritable;
15337 /* same as IO::EAGAINWaitWritable */
15338 rb_define_const(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEAGAINWaitWritable);
15339#else
15340 /* exception to wait for reading by EWOULDBLOCK. see IO.select. */
15341 rb_eEWOULDBLOCKWaitReadable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEWOULDBLOCK);
15342 rb_include_module(rb_eEWOULDBLOCKWaitReadable, rb_mWaitReadable);
15343 /* exception to wait for writing by EWOULDBLOCK. see IO.select. */
15344 rb_eEWOULDBLOCKWaitWritable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEWOULDBLOCK);
15345 rb_include_module(rb_eEWOULDBLOCKWaitWritable, rb_mWaitWritable);
15346#endif
15347 /* exception to wait for reading by EINPROGRESS. see IO.select. */
15348 rb_eEINPROGRESSWaitReadable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitReadable", rb_eEINPROGRESS);
15349 rb_include_module(rb_eEINPROGRESSWaitReadable, rb_mWaitReadable);
15350 /* exception to wait for writing by EINPROGRESS. see IO.select. */
15351 rb_eEINPROGRESSWaitWritable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitWritable", rb_eEINPROGRESS);
15352 rb_include_module(rb_eEINPROGRESSWaitWritable, rb_mWaitWritable);
15353
15354#if 0
15355 /* This is necessary only for forcing rdoc handle File::open */
15356 rb_define_singleton_method(rb_cFile, "open", rb_io_s_open, -1);
15357#endif
15358
15359 rb_define_alloc_func(rb_cIO, io_alloc);
15360 rb_define_singleton_method(rb_cIO, "new", rb_io_s_new, -1);
15361 rb_define_singleton_method(rb_cIO, "open", rb_io_s_open, -1);
15362 rb_define_singleton_method(rb_cIO, "sysopen", rb_io_s_sysopen, -1);
15363 rb_define_singleton_method(rb_cIO, "for_fd", rb_io_s_for_fd, -1);
15364 rb_define_singleton_method(rb_cIO, "popen", rb_io_s_popen, -1);
15365 rb_define_singleton_method(rb_cIO, "foreach", rb_io_s_foreach, -1);
15366 rb_define_singleton_method(rb_cIO, "readlines", rb_io_s_readlines, -1);
15367 rb_define_singleton_method(rb_cIO, "read", rb_io_s_read, -1);
15368 rb_define_singleton_method(rb_cIO, "binread", rb_io_s_binread, -1);
15369 rb_define_singleton_method(rb_cIO, "write", rb_io_s_write, -1);
15370 rb_define_singleton_method(rb_cIO, "binwrite", rb_io_s_binwrite, -1);
15371 rb_define_singleton_method(rb_cIO, "select", rb_f_select, -1);
15372 rb_define_singleton_method(rb_cIO, "pipe", rb_io_s_pipe, -1);
15373 rb_define_singleton_method(rb_cIO, "try_convert", rb_io_s_try_convert, 1);
15374 rb_define_singleton_method(rb_cIO, "copy_stream", rb_io_s_copy_stream, -1);
15375
15376 rb_define_method(rb_cIO, "initialize", rb_io_initialize, -1);
15377
15378 rb_output_fs = Qnil;
15379 rb_define_hooked_variable("$,", &rb_output_fs, 0, deprecated_str_setter);
15380
15381 rb_default_rs = rb_fstring_lit("\n"); /* avoid modifying RS_default */
15382 rb_gc_register_mark_object(rb_default_rs);
15383 rb_rs = rb_default_rs;
15385 rb_define_hooked_variable("$/", &rb_rs, 0, deprecated_str_setter);
15386 rb_define_hooked_variable("$-0", &rb_rs, 0, deprecated_str_setter);
15387 rb_define_hooked_variable("$\\", &rb_output_rs, 0, deprecated_str_setter);
15388
15389 rb_define_virtual_variable("$_", get_LAST_READ_LINE, set_LAST_READ_LINE);
15390 rb_gvar_ractor_local("$_");
15391
15392 rb_define_method(rb_cIO, "initialize_copy", rb_io_init_copy, 1);
15393 rb_define_method(rb_cIO, "reopen", rb_io_reopen, -1);
15394
15395 rb_define_method(rb_cIO, "print", rb_io_print, -1);
15396 rb_define_method(rb_cIO, "putc", rb_io_putc, 1);
15397 rb_define_method(rb_cIO, "puts", rb_io_puts, -1);
15398 rb_define_method(rb_cIO, "printf", rb_io_printf, -1);
15399
15400 rb_define_method(rb_cIO, "each", rb_io_each_line, -1);
15401 rb_define_method(rb_cIO, "each_line", rb_io_each_line, -1);
15402 rb_define_method(rb_cIO, "each_byte", rb_io_each_byte, 0);
15403 rb_define_method(rb_cIO, "each_char", rb_io_each_char, 0);
15404 rb_define_method(rb_cIO, "each_codepoint", rb_io_each_codepoint, 0);
15405
15406 rb_define_method(rb_cIO, "syswrite", rb_io_syswrite, 1);
15407 rb_define_method(rb_cIO, "sysread", rb_io_sysread, -1);
15408
15409 rb_define_method(rb_cIO, "pread", rb_io_pread, -1);
15410 rb_define_method(rb_cIO, "pwrite", rb_io_pwrite, 2);
15411
15412 rb_define_method(rb_cIO, "fileno", rb_io_fileno, 0);
15413 rb_define_alias(rb_cIO, "to_i", "fileno");
15414 rb_define_method(rb_cIO, "to_io", rb_io_to_io, 0);
15415
15416 rb_define_method(rb_cIO, "timeout", rb_io_timeout, 0);
15417 rb_define_method(rb_cIO, "timeout=", rb_io_set_timeout, 1);
15418
15419 rb_define_method(rb_cIO, "fsync", rb_io_fsync, 0);
15420 rb_define_method(rb_cIO, "fdatasync", rb_io_fdatasync, 0);
15421 rb_define_method(rb_cIO, "sync", rb_io_sync, 0);
15422 rb_define_method(rb_cIO, "sync=", rb_io_set_sync, 1);
15423
15424 rb_define_method(rb_cIO, "lineno", rb_io_lineno, 0);
15425 rb_define_method(rb_cIO, "lineno=", rb_io_set_lineno, 1);
15426
15427 rb_define_method(rb_cIO, "readlines", rb_io_readlines, -1);
15428
15429 rb_define_method(rb_cIO, "readpartial", io_readpartial, -1);
15430 rb_define_method(rb_cIO, "read", io_read, -1);
15431 rb_define_method(rb_cIO, "write", io_write_m, -1);
15432 rb_define_method(rb_cIO, "gets", rb_io_gets_m, -1);
15433 rb_define_method(rb_cIO, "readline", rb_io_readline, -1);
15434 rb_define_method(rb_cIO, "getc", rb_io_getc, 0);
15435 rb_define_method(rb_cIO, "getbyte", rb_io_getbyte, 0);
15436 rb_define_method(rb_cIO, "readchar", rb_io_readchar, 0);
15437 rb_define_method(rb_cIO, "readbyte", rb_io_readbyte, 0);
15438 rb_define_method(rb_cIO, "ungetbyte",rb_io_ungetbyte, 1);
15439 rb_define_method(rb_cIO, "ungetc",rb_io_ungetc, 1);
15441 rb_define_method(rb_cIO, "flush", rb_io_flush, 0);
15442 rb_define_method(rb_cIO, "tell", rb_io_tell, 0);
15443 rb_define_method(rb_cIO, "seek", rb_io_seek_m, -1);
15444 /* Set I/O position from the beginning */
15445 rb_define_const(rb_cIO, "SEEK_SET", INT2FIX(SEEK_SET));
15446 /* Set I/O position from the current position */
15447 rb_define_const(rb_cIO, "SEEK_CUR", INT2FIX(SEEK_CUR));
15448 /* Set I/O position from the end */
15449 rb_define_const(rb_cIO, "SEEK_END", INT2FIX(SEEK_END));
15450#ifdef SEEK_DATA
15451 /* Set I/O position to the next location containing data */
15452 rb_define_const(rb_cIO, "SEEK_DATA", INT2FIX(SEEK_DATA));
15453#endif
15454#ifdef SEEK_HOLE
15455 /* Set I/O position to the next hole */
15456 rb_define_const(rb_cIO, "SEEK_HOLE", INT2FIX(SEEK_HOLE));
15457#endif
15458 rb_define_method(rb_cIO, "rewind", rb_io_rewind, 0);
15459 rb_define_method(rb_cIO, "pos", rb_io_tell, 0);
15460 rb_define_method(rb_cIO, "pos=", rb_io_set_pos, 1);
15461 rb_define_method(rb_cIO, "eof", rb_io_eof, 0);
15462 rb_define_method(rb_cIO, "eof?", rb_io_eof, 0);
15463
15464 rb_define_method(rb_cIO, "close_on_exec?", rb_io_close_on_exec_p, 0);
15465 rb_define_method(rb_cIO, "close_on_exec=", rb_io_set_close_on_exec, 1);
15466
15467 rb_define_method(rb_cIO, "close", rb_io_close_m, 0);
15468 rb_define_method(rb_cIO, "closed?", rb_io_closed, 0);
15469 rb_define_method(rb_cIO, "close_read", rb_io_close_read, 0);
15470 rb_define_method(rb_cIO, "close_write", rb_io_close_write, 0);
15471
15472 rb_define_method(rb_cIO, "isatty", rb_io_isatty, 0);
15473 rb_define_method(rb_cIO, "tty?", rb_io_isatty, 0);
15474 rb_define_method(rb_cIO, "binmode", rb_io_binmode_m, 0);
15475 rb_define_method(rb_cIO, "binmode?", rb_io_binmode_p, 0);
15476 rb_define_method(rb_cIO, "sysseek", rb_io_sysseek, -1);
15477 rb_define_method(rb_cIO, "advise", rb_io_advise, -1);
15478
15479 rb_define_method(rb_cIO, "ioctl", rb_io_ioctl, -1);
15480 rb_define_method(rb_cIO, "fcntl", rb_io_fcntl, -1);
15481 rb_define_method(rb_cIO, "pid", rb_io_pid, 0);
15482
15483 rb_define_method(rb_cIO, "path", rb_io_path, 0);
15484 rb_define_method(rb_cIO, "to_path", rb_io_path, 0);
15485
15486 rb_define_method(rb_cIO, "inspect", rb_io_inspect, 0);
15487
15488 rb_define_method(rb_cIO, "external_encoding", rb_io_external_encoding, 0);
15489 rb_define_method(rb_cIO, "internal_encoding", rb_io_internal_encoding, 0);
15490 rb_define_method(rb_cIO, "set_encoding", rb_io_set_encoding, -1);
15491 rb_define_method(rb_cIO, "set_encoding_by_bom", rb_io_set_encoding_by_bom, 0);
15492
15493 rb_define_method(rb_cIO, "autoclose?", rb_io_autoclose_p, 0);
15494 rb_define_method(rb_cIO, "autoclose=", rb_io_set_autoclose, 1);
15495
15496 rb_define_method(rb_cIO, "wait", io_wait, -1);
15497
15498 rb_define_method(rb_cIO, "wait_readable", io_wait_readable, -1);
15499 rb_define_method(rb_cIO, "wait_writable", io_wait_writable, -1);
15500 rb_define_method(rb_cIO, "wait_priority", io_wait_priority, -1);
15501
15502 rb_define_virtual_variable("$stdin", stdin_getter, stdin_setter);
15503 rb_define_virtual_variable("$stdout", stdout_getter, stdout_setter);
15504 rb_define_virtual_variable("$>", stdout_getter, stdout_setter);
15505 rb_define_virtual_variable("$stderr", stderr_getter, stderr_setter);
15506
15507 rb_gvar_ractor_local("$stdin");
15508 rb_gvar_ractor_local("$stdout");
15509 rb_gvar_ractor_local("$>");
15510 rb_gvar_ractor_local("$stderr");
15511
15512 rb_stdin = rb_io_prep_stdin();
15513 rb_stdout = rb_io_prep_stdout();
15514 rb_stderr = rb_io_prep_stderr();
15515
15519
15520 orig_stdout = rb_stdout;
15521 orig_stderr = rb_stderr;
15522
15523 /* Holds the original stdin */
15525 /* Holds the original stdout */
15527 /* Holds the original stderr */
15529
15530#if 0
15531 /* Hack to get rdoc to regard ARGF as a class: */
15532 rb_cARGF = rb_define_class("ARGF", rb_cObject);
15533#endif
15534
15535 rb_cARGF = rb_class_new(rb_cObject);
15536 rb_set_class_path(rb_cARGF, rb_cObject, "ARGF.class");
15537 rb_define_alloc_func(rb_cARGF, argf_alloc);
15538
15540
15541 rb_define_method(rb_cARGF, "initialize", argf_initialize, -2);
15542 rb_define_method(rb_cARGF, "initialize_copy", argf_initialize_copy, 1);
15543 rb_define_method(rb_cARGF, "to_s", argf_to_s, 0);
15544 rb_define_alias(rb_cARGF, "inspect", "to_s");
15545 rb_define_method(rb_cARGF, "argv", argf_argv, 0);
15546
15547 rb_define_method(rb_cARGF, "fileno", argf_fileno, 0);
15548 rb_define_method(rb_cARGF, "to_i", argf_fileno, 0);
15549 rb_define_method(rb_cARGF, "to_io", argf_to_io, 0);
15550 rb_define_method(rb_cARGF, "to_write_io", argf_write_io, 0);
15551 rb_define_method(rb_cARGF, "each", argf_each_line, -1);
15552 rb_define_method(rb_cARGF, "each_line", argf_each_line, -1);
15553 rb_define_method(rb_cARGF, "each_byte", argf_each_byte, 0);
15554 rb_define_method(rb_cARGF, "each_char", argf_each_char, 0);
15555 rb_define_method(rb_cARGF, "each_codepoint", argf_each_codepoint, 0);
15556
15557 rb_define_method(rb_cARGF, "read", argf_read, -1);
15558 rb_define_method(rb_cARGF, "readpartial", argf_readpartial, -1);
15559 rb_define_method(rb_cARGF, "read_nonblock", argf_read_nonblock, -1);
15560 rb_define_method(rb_cARGF, "readlines", argf_readlines, -1);
15561 rb_define_method(rb_cARGF, "to_a", argf_readlines, -1);
15562 rb_define_method(rb_cARGF, "gets", argf_gets, -1);
15563 rb_define_method(rb_cARGF, "readline", argf_readline, -1);
15564 rb_define_method(rb_cARGF, "getc", argf_getc, 0);
15565 rb_define_method(rb_cARGF, "getbyte", argf_getbyte, 0);
15566 rb_define_method(rb_cARGF, "readchar", argf_readchar, 0);
15567 rb_define_method(rb_cARGF, "readbyte", argf_readbyte, 0);
15568 rb_define_method(rb_cARGF, "tell", argf_tell, 0);
15569 rb_define_method(rb_cARGF, "seek", argf_seek_m, -1);
15570 rb_define_method(rb_cARGF, "rewind", argf_rewind, 0);
15571 rb_define_method(rb_cARGF, "pos", argf_tell, 0);
15572 rb_define_method(rb_cARGF, "pos=", argf_set_pos, 1);
15573 rb_define_method(rb_cARGF, "eof", argf_eof, 0);
15574 rb_define_method(rb_cARGF, "eof?", argf_eof, 0);
15575 rb_define_method(rb_cARGF, "binmode", argf_binmode_m, 0);
15576 rb_define_method(rb_cARGF, "binmode?", argf_binmode_p, 0);
15577
15578 rb_define_method(rb_cARGF, "write", argf_write, 1);
15579 rb_define_method(rb_cARGF, "print", rb_io_print, -1);
15580 rb_define_method(rb_cARGF, "putc", rb_io_putc, 1);
15581 rb_define_method(rb_cARGF, "puts", rb_io_puts, -1);
15582 rb_define_method(rb_cARGF, "printf", rb_io_printf, -1);
15583
15584 rb_define_method(rb_cARGF, "filename", argf_filename, 0);
15585 rb_define_method(rb_cARGF, "path", argf_filename, 0);
15586 rb_define_method(rb_cARGF, "file", argf_file, 0);
15587 rb_define_method(rb_cARGF, "skip", argf_skip, 0);
15588 rb_define_method(rb_cARGF, "close", argf_close_m, 0);
15589 rb_define_method(rb_cARGF, "closed?", argf_closed, 0);
15590
15591 rb_define_method(rb_cARGF, "lineno", argf_lineno, 0);
15592 rb_define_method(rb_cARGF, "lineno=", argf_set_lineno, 1);
15593
15594 rb_define_method(rb_cARGF, "inplace_mode", argf_inplace_mode_get, 0);
15595 rb_define_method(rb_cARGF, "inplace_mode=", argf_inplace_mode_set, 1);
15596
15597 rb_define_method(rb_cARGF, "external_encoding", argf_external_encoding, 0);
15598 rb_define_method(rb_cARGF, "internal_encoding", argf_internal_encoding, 0);
15599 rb_define_method(rb_cARGF, "set_encoding", argf_set_encoding, -1);
15600
15601 argf = rb_class_new_instance(0, 0, rb_cARGF);
15602
15604 /*
15605 * ARGF is a stream designed for use in scripts that process files given
15606 * as command-line arguments or passed in via STDIN.
15607 *
15608 * See ARGF (the class) for more details.
15609 */
15611
15612 rb_define_hooked_variable("$.", &argf, argf_lineno_getter, argf_lineno_setter);
15613 rb_define_hooked_variable("$FILENAME", &argf, argf_filename_getter, rb_gvar_readonly_setter);
15614 ARGF.filename = rb_str_new2("-");
15615
15616 rb_define_hooked_variable("$-i", &argf, opt_i_get, opt_i_set);
15617 rb_gvar_ractor_local("$-i");
15618
15619 rb_define_hooked_variable("$*", &argf, argf_argv_getter, rb_gvar_readonly_setter);
15620
15621#if defined (_WIN32) || defined(__CYGWIN__)
15622 atexit(pipe_atexit);
15623#endif
15624
15625 Init_File();
15626
15627 rb_define_method(rb_cFile, "initialize", rb_file_initialize, -1);
15628
15629 sym_mode = ID2SYM(rb_intern_const("mode"));
15630 sym_perm = ID2SYM(rb_intern_const("perm"));
15631 sym_flags = ID2SYM(rb_intern_const("flags"));
15632 sym_extenc = ID2SYM(rb_intern_const("external_encoding"));
15633 sym_intenc = ID2SYM(rb_intern_const("internal_encoding"));
15634 sym_encoding = ID2SYM(rb_id_encoding());
15635 sym_open_args = ID2SYM(rb_intern_const("open_args"));
15636 sym_textmode = ID2SYM(rb_intern_const("textmode"));
15637 sym_binmode = ID2SYM(rb_intern_const("binmode"));
15638 sym_autoclose = ID2SYM(rb_intern_const("autoclose"));
15639 sym_normal = ID2SYM(rb_intern_const("normal"));
15640 sym_sequential = ID2SYM(rb_intern_const("sequential"));
15641 sym_random = ID2SYM(rb_intern_const("random"));
15642 sym_willneed = ID2SYM(rb_intern_const("willneed"));
15643 sym_dontneed = ID2SYM(rb_intern_const("dontneed"));
15644 sym_noreuse = ID2SYM(rb_intern_const("noreuse"));
15645 sym_SET = ID2SYM(rb_intern_const("SET"));
15646 sym_CUR = ID2SYM(rb_intern_const("CUR"));
15647 sym_END = ID2SYM(rb_intern_const("END"));
15648#ifdef SEEK_DATA
15649 sym_DATA = ID2SYM(rb_intern_const("DATA"));
15650#endif
15651#ifdef SEEK_HOLE
15652 sym_HOLE = ID2SYM(rb_intern_const("HOLE"));
15653#endif
15654 sym_wait_readable = ID2SYM(rb_intern_const("wait_readable"));
15655 sym_wait_writable = ID2SYM(rb_intern_const("wait_writable"));
15656}
15657
15658#include "io.rbinc"
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:133
#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:1125
VALUE rb_define_class(const char *name, VALUE super)
Defines a top-level class.
Definition class.c:923
VALUE rb_class_new(VALUE super)
Creates a new, anonymous class.
Definition class.c:325
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
Definition class.c:955
VALUE rb_define_module_under(VALUE outer, const char *name)
Defines a module under the namespace of outer.
Definition class.c:1057
void rb_define_alias(VALUE klass, const char *name1, const char *name2)
Defines an alias of a method.
Definition class.c:2284
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:2587
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:2574
int rb_block_given_p(void)
Determines if the current method is given a block.
Definition eval.c:868
int rb_get_kwargs(VALUE keyword_hash, const ID *table, int required, int optional, VALUE *values)
Keyword argument deconstructor.
Definition class.c:2363
#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:1675
#define TYPE(_)
Old name of rb_type.
Definition value_type.h:107
#define NEWOBJ_OF
Old name of RB_NEWOBJ_OF.
Definition newobj.h:61
#define FL_SINGLETON
Old name of RUBY_FL_SINGLETON.
Definition fl_type.h:58
#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 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:394
#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:1683
#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:143
#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:396
#define CLASS_OF
Old name of rb_class_of.
Definition globals.h:203
#define rb_ary_new4
Old name of rb_ary_new_from_values.
Definition array.h:653
#define ENCODING_MAXNAMELEN
Old name of RUBY_ENCODING_MAXNAMELEN.
Definition encoding.h:110
#define MBCLEN_NEEDMORE_LEN(ret)
Old name of ONIGENC_MBCLEN_NEEDMORE_LEN.
Definition encoding.h:536
#define ENCODING_GET(obj)
Old name of RB_ENCODING_GET.
Definition encoding.h:108
#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:393
#define MBCLEN_CHARFOUND_LEN(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_LEN.
Definition encoding.h:533
#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:534
#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:535
#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:399
#define MBCLEN_CHARFOUND_P(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_P.
Definition encoding.h:532
#define NUM2CHR
Old name of RB_NUM2CHR.
Definition char.h:33
#define FL_TEST
Old name of RB_FL_TEST.
Definition fl_type.h:139
#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:651
#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:1677
#define ALLOCV_END
Old name of RB_ALLOCV_END.
Definition memory.h:400
#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_notimplement(void)
Definition error.c:3193
void rb_category_warn(rb_warning_category_t category, const char *fmt,...)
Identical to rb_category_warning(), except it reports always regardless of runtime -W flag.
Definition error.c:421
void rb_raise(VALUE exc, const char *fmt,...)
Exception entry point.
Definition error.c:3150
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:453
VALUE rb_eNotImpError
NotImplementedError exception.
Definition error.c:1101
void rb_exc_raise(VALUE mesg)
Raises an exception in the current thread.
Definition eval.c:688
void rb_syserr_fail(int e, const char *mesg)
Raises appropriate exception that represents a C errno.
Definition error.c:3262
void rb_bug(const char *fmt,...)
Interpreter panic switch.
Definition error.c:794
void rb_sys_fail(const char *mesg)
Converts a C errno into a Ruby exception, then raises it.
Definition error.c:3274
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:14574
VALUE rb_eIOError
IOError exception.
Definition io.c:182
VALUE rb_eStandardError
StandardError exception.
Definition error.c:1088
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:3350
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:3268
#define ruby_verbose
This variable controls whether the interpreter is in debug mode.
Definition error.h:459
VALUE rb_eTypeError
TypeError exception.
Definition error.c:1091
VALUE rb_eEOFError
EOFError exception.
Definition io.c:181
void rb_fatal(const char *fmt,...)
Raises the unsung "fatal" exception.
Definition error.c:3201
void rb_readwrite_sys_fail(enum rb_io_wait_readwrite waiting, const char *mesg)
Raises appropriate exception using the parameters.
Definition io.c:14568
void rb_iter_break_value(VALUE val)
Identical to rb_iter_break(), except it additionally takes the "value" of this breakage.
Definition vm.c:1907
rb_io_wait_readwrite
for rb_readwrite_sys_fail first argument
Definition error.h:57
VALUE rb_eRuntimeError
RuntimeError exception.
Definition error.c:1089
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports always regardless of runtime -W flag.
Definition error.c:411
VALUE rb_eArgError
ArgumentError exception.
Definition error.c:1092
void rb_sys_fail_str(VALUE mesg)
Identical to rb_sys_fail(), except it takes the message in Ruby's String instead of C's.
Definition error.c:3280
VALUE rb_eSystemCallError
SystemCallError exception.
Definition error.c:1111
@ RB_WARN_CATEGORY_DEPRECATED
Warning is for deprecated features.
Definition error.h:48
VALUE rb_mKernel
Kernel module.
Definition object.c:51
VALUE rb_check_to_int(VALUE val)
Identical to rb_check_to_integer(), except it uses #to_int for conversion.
Definition object.c:3032
VALUE rb_any_to_s(VALUE obj)
Generates a textual representation of the given object.
Definition object.c:589
VALUE rb_obj_alloc(VALUE klass)
Allocates an instance of the given class.
Definition object.c:1939
VALUE rb_class_new_instance(int argc, const VALUE *argv, VALUE klass)
Allocates, then initialises an instance of the given class.
Definition object.c:1980
VALUE rb_cIO
IO class.
Definition io.c:180
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:1968
VALUE rb_mEnumerable
Enumerable module.
Definition enum.c:27
VALUE rb_stdin
STDIN constant.
Definition io.c:194
VALUE rb_stderr
STDERR constant.
Definition io.c:194
VALUE rb_obj_class(VALUE obj)
Queries the class of an object.
Definition object.c:190
VALUE rb_obj_dup(VALUE obj)
Duplicates the given object.
Definition object.c:487
VALUE rb_inspect(VALUE obj)
Generates a human-readable textual representation of the given object.
Definition object.c:600
VALUE rb_mWaitReadable
IO::WaitReadable module.
Definition io.c:184
VALUE rb_mWaitWritable
IO::WaitReadable module.
Definition io.c:185
VALUE rb_obj_freeze(VALUE obj)
Just calls rb_obj_freeze_inline() inside.
Definition object.c:1182
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:3013
VALUE rb_cFile
File class.
Definition file.c:176
VALUE rb_stdout
STDOUT constant.
Definition io.c:194
VALUE rb_to_int(VALUE val)
Identical to rb_check_to_int(), except it raises in case of conversion mismatch.
Definition object.c:3026
static const char * rb_enc_name(rb_encoding *enc)
Queries the (canonical) name of the passed encoding.
Definition encoding.h:433
static char * rb_enc_left_char_head(const char *s, const char *p, const char *e, rb_encoding *enc)
Queries the left boundary of a character.
Definition encoding.h:699
static bool rb_enc_asciicompat(rb_encoding *enc)
Queries if the passed encoding is in some sense compatible with ASCII.
Definition encoding.h:784
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:587
static int rb_enc_mbminlen(rb_encoding *enc)
Queries the minimum number of bytes that the passed encoding needs to represent a character.
Definition encoding.h:448
VALUE rb_enc_uint_chr(unsigned int code, rb_encoding *enc)
Encodes the passed code point into a series of bytes.
Definition numeric.c:3747
VALUE rb_enc_str_new(const char *ptr, long len, rb_encoding *enc)
Identical to rb_enc_str_new(), except it additionally takes an encoding.
Definition string.c:981
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:719
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:2579
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:2076
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:1453
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:1749
const char * rb_econv_asciicompat_encoding(const char *encname)
Queries the passed encoding's corresponding ASCII compatible encoding.
Definition transcode.c:1793
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:1910
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:2630
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:1975
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:2884
VALUE rb_econv_make_exception(rb_econv_t *ec)
This function makes sense right after rb_econv_convert() returns.
Definition transcode.c:4245
void rb_econv_check_error(rb_econv_t *ec)
This is a rb_econv_make_exception() + rb_exc_raise() combo.
Definition transcode.c:4251
void rb_econv_close(rb_econv_t *ec)
Destructs a converter.
Definition transcode.c:1709
void rb_econv_putback(rb_econv_t *ec, unsigned char *p, int n)
Puts back the bytes.
Definition transcode.c:1760
VALUE rb_funcall(VALUE recv, ID mid, int n,...)
Calls a method.
Definition vm_eval.c:1102
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:1069
#define RETURN_ENUMERATOR(obj, argc, argv)
Identical to RETURN_SIZED_ENUMERATOR(), except its size is unknown.
Definition enumerator.h:239
#define rb_check_frozen
Just another name of rb_check_frozen.
Definition error.h:264
static int rb_check_arity(int argc, int min, int max)
Ensures that the passed integer is in the passed range.
Definition error.h:280
VALUE rb_io_printf(int argc, const VALUE *argv, VALUE io)
This is a rb_f_sprintf() + rb_io_write() combo.
Definition io.c:8542
VALUE rb_io_gets(VALUE io)
Reads a "line" from the given IO.
Definition io.c:4217
int rb_cloexec_pipe(int fildes[2])
Opens a pipe with closing on exec.
Definition io.c:409
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:8668
VALUE rb_io_addstr(VALUE io, VALUE str)
Identical to rb_io_write(), except it always returns the passed IO.
Definition io.c:2313
void rb_write_error(const char *str)
Writes the given error message to somewhere applicable.
Definition io.c:9093
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:5082
VALUE rb_io_getbyte(VALUE io)
Reads a byte from the given IO.
Definition io.c:4988
VALUE rb_io_puts(int argc, const VALUE *argv, VALUE io)
Iterates over the passed array to apply rb_io_write() individually.
Definition io.c:8900
int rb_cloexec_dup2(int oldfd, int newfd)
Identical to rb_cloexec_dup(), except you can specify the destination file descriptor.
Definition io.c:356
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:9201
void rb_update_max_fd(int fd)
Informs the interpreter that the passed fd can be the max.
Definition io.c:230
VALUE rb_io_write(VALUE io, VALUE str)
Writes the given string to the given IO.
Definition io.c:2265
int rb_cloexec_open(const char *pathname, int flags, mode_t mode)
Opens a file that closes on exec.
Definition io.c:310
VALUE rb_output_rs
The record separator character for outputs, or the $\.
Definition io.c:199
VALUE rb_io_eof(VALUE io)
Queries if the passed IO is at the end of file.
Definition io.c:2664
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:9073
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:280
VALUE rb_io_flush(VALUE io)
Flushes any buffered data within the passed IO to the underlying operating system.
Definition io.c:2369
VALUE rb_io_ascii8bit_binmode(VALUE io)
Forces no conversions be applied to the passed IO.
Definition io.c:6279
VALUE rb_io_binmode(VALUE io)
Sets the binmode.
Definition io.c:6233
VALUE rb_io_ungetc(VALUE io, VALUE c)
"Unget"s a string.
Definition io.c:5146
int rb_pipe(int *pipes)
This is an rb_cloexec_pipe() + rb_update_max_fd() combo.
Definition io.c:7284
VALUE rb_gets(void)
Much like rb_io_gets(), but it reads from the mysterious ARGF object.
Definition io.c:10263
int rb_cloexec_fcntl_dupfd(int fd, int minfd)
Duplicates a file descriptor with closing on exec.
Definition io.c:443
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:7167
int rb_cloexec_dup(int oldfd)
Identical to rb_cloexec_fcntl_dupfd(), except it implies minfd is 3.
Definition io.c:349
VALUE rb_file_open(const char *fname, const char *fmode)
Opens a file located at the given path.
Definition io.c:7174
VALUE rb_io_close(VALUE io)
Closes the IO.
Definition io.c:5669
VALUE rb_default_rs
This is the default value of rb_rs, i.e.
Definition io.c:200
void rb_lastline_set(VALUE str)
Updates $_.
Definition vm.c:1680
VALUE rb_lastline_get(void)
Queries the last line, or the $_.
Definition vm.c:1674
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:2901
rb_pid_t rb_waitpid(rb_pid_t pid, int *status, int flags)
Waits for a process, with releasing GVL.
Definition process.c:1434
void rb_last_status_set(int status, rb_pid_t pid)
Sets the "last status", or the $?.
Definition process.c:686
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:3353
#define rb_str_new(str, len)
Allocates an instance of rb_cString.
Definition string.h:1498
#define rb_str_buf_cat
Just another name of rb_str_cat.
Definition string.h:1681
#define rb_usascii_str_new(str, len)
Identical to rb_str_new, except it generates a string of "US ASCII" encoding.
Definition string.h:1532
size_t rb_str_capacity(VALUE str)
Queries the capacity of the given string.
Definition string.c:871
VALUE rb_str_new_frozen(VALUE str)
Creates a frozen copy of the string, if necessary.
Definition string.c:1382
VALUE rb_str_dup(VALUE str)
Duplicates a string.
Definition string.c:1834
void rb_str_modify(VALUE str)
Declares that the string is about to be modified.
Definition string.c:2437
VALUE rb_str_cat(VALUE dst, const char *src, long srclen)
Destructively appends the passed contents to the string.
Definition string.c:3177
VALUE rb_str_locktmp(VALUE str)
Obtains a "temporary lock" of the string.
rb_gvar_setter_t rb_str_setter
This is a rb_gvar_setter_t that refutes non-string assignments.
Definition string.h:1146
void rb_str_set_len(VALUE str, long len)
Overwrites the length of the string.
Definition string.c:3020
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:3295
VALUE rb_check_string_type(VALUE obj)
Try converting an object to its stringised representation using its to_str method,...
Definition string.c:2640
VALUE rb_str_substr(VALUE str, long beg, long len)
This is the implementation of two-argumented String#slice.
Definition string.c:2921
VALUE rb_str_unlocktmp(VALUE str)
Releases a lock formerly obtained by rb_str_locktmp().
Definition string.c:3003
VALUE rb_str_resize(VALUE str, long len)
Overwrites the length of the string.
Definition string.c:3064
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:2445
VALUE rb_str_buf_new(long capa)
Allocates a "string buffer".
Definition string.c:1532
#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:1514
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:1682
int rb_thread_interrupted(VALUE thval)
Checks if the thread's execution was recently interrupted.
Definition thread.c:1441
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:1566
#define RUBY_UBF_IO
A special UBF for blocking IO operations.
Definition thread.h:382
VALUE rb_exec_recursive(VALUE(*f)(VALUE g, VALUE h, int r), VALUE g, VALUE h)
"Recursion" API entry point.
void rb_thread_fd_close(int fd)
Notifies a closing of a file descriptor to other threads.
Definition thread.c:2515
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:1424
VALUE rb_thread_current(void)
Obtains the "current" thread.
Definition thread.c:2793
int rb_thread_wait_fd(int fd)
Blocks the current thread until the given file descriptor is ready to be read.
Definition io.c:1560
void rb_thread_schedule(void)
Tries to switch to another thread.
Definition thread.c:1472
void rb_thread_sleep(int sec)
Blocks for the given period of time.
Definition thread.c:1447
struct timeval rb_time_interval(VALUE num)
Creates a "time interval".
Definition time.c:2847
VALUE rb_attr_get(VALUE obj, ID name)
Identical to rb_ivar_get()
Definition variable.c:1226
void rb_set_class_path(VALUE klass, VALUE space, const char *name)
Names a class.
Definition variable.c:251
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:1606
VALUE rb_class_name(VALUE obj)
Queries the name of the given object's class.
Definition variable.c:310
int rb_respond_to(VALUE obj, ID mid)
Queries if the object responds to the method.
Definition vm_method.c:2805
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:664
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:276
ID rb_intern(const char *name)
Finds or creates a symbol of the given name.
Definition symbol.c:789
#define RB_ID2SYM
Just another name of rb_id2sym.
Definition symbol.h:42
const char * rb_id2name(ID id)
Retrieves the name mapped to the given id.
Definition symbol.c:959
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:3452
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:604
rb_gvar_setter_t rb_gvar_readonly_setter
This function just raises rb_eNameError.
Definition variable.h:135
void rb_define_const(VALUE klass, const char *name, VALUE val)
Defines a Ruby level constant under a namespace.
Definition variable.c:3440
#define FMODE_READABLE
The IO is opened for reading.
Definition io.h:251
int 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:6365
VALUE rb_io_get_io(VALUE io)
Identical to rb_io_check_io(), except it raises exceptions on conversion failures.
Definition io.c:797
VALUE rb_io_timeout(VALUE io)
Get the timeout associated with the specified io object.
Definition io.c:843
VALUE rb_io_taint_check(VALUE obj)
Definition io.c:767
void rb_io_read_check(rb_io_t *fptr)
Blocks until there is a pending read in the passed IO.
Definition io.c:1051
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:6498
#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:340
#define FMODE_READWRITE
The IO is opened for both read/write.
Definition io.h:257
#define GetOpenFile
This is an old name of RB_IO_POINTER.
Definition io.h:362
void rb_io_check_byte_readable(rb_io_t *fptr)
Asserts that an IO is opened for byte-based reading.
Definition io.c:997
#define FMODE_TTY
The IO is a TTY.
Definition io.h:281
#define FMODE_CREATE
The IO is opened for creating.
Definition io.h:304
void rb_io_check_readable(rb_io_t *fptr)
Just another name of rb_io_check_byte_readable.
Definition io.c:1006
int rb_io_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding **enc2_p, int *fmode_p)
This function breaks down the option hash that IO#initialize takes into components.
Definition io.c:6647
struct rb_io_t rb_io_t
Ruby's IO, metadata and buffers.
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:1554
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:6968
int rb_io_descriptor(VALUE io)
Returns an integer representing the numeric file descriptor for io.
Definition io.c:2867
#define FMODE_WRITABLE
The IO is opened for writing.
Definition io.h:254
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:9247
#define FMODE_APPEND
The IO is opened for appending.
Definition io.h:296
#define MakeOpenFile
This is an old name of RB_IO_OPEN.
Definition io.h:385
#define FMODE_DUPLEX
Ruby eventually detects that the IO is bidirectional.
Definition io.h:289
#define FMODE_BINMODE
The IO is in "binary mode".
Definition io.h:268
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:1613
#define RB_IO_POINTER(obj, fp)
Queries the underlying IO pointer.
Definition io.h:356
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:1572
VALUE rb_eIOTimeoutError
Indicates that a timeout has occurred while performing an IO operation.
Definition io.c:183
#define FMODE_SYNC
The IO is in "sync mode".
Definition io.h:275
void rb_io_check_initialized(rb_io_t *fptr)
Asserts that the passed IO is initialised.
Definition io.c:774
#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:312
#define FMODE_TEXTMODE
The IO is in "text mode".
Definition io.h:332
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:803
VALUE rb_io_set_timeout(VALUE io, VALUE timeout)
Set the timeout associated with the specified io object.
Definition io.c:869
ssize_t rb_io_bufwrite(VALUE io, const void *buf, size_t size)
Buffered write to the passed IO.
Definition io.c:1978
void rb_io_check_char_readable(rb_io_t *fptr)
Asserts that an IO is opened for character-based reading.
Definition io.c:978
#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:318
VALUE rb_io_get_write_io(VALUE io)
Queries the tied IO for writing.
Definition io.c:809
void rb_io_set_nonblock(rb_io_t *fptr)
Instructs the OS to put its internal file structure into "nonblocking mode".
Definition io.c:3377
void rb_io_extract_modeenc(VALUE *vmode_p, VALUE *vperm_p, VALUE opthash, int *oflags_p, int *fmode_p, rb_io_enc_t *convconfig_p)
This function can be seen as an extended version of rb_io_extract_encoding_option() that not only con...
Definition io.c:6774
int rb_io_wait_writable(int fd)
Blocks until the passed file descriptor gets writable.
Definition io.c:1511
VALUE rb_io_set_write_io(VALUE io, VALUE w)
Assigns the tied IO for writing.
Definition io.c:820
void rb_io_check_writable(rb_io_t *fptr)
Asserts that an IO is opened for writing.
Definition io.c:1030
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:1626
void rb_io_check_closed(rb_io_t *fptr)
This badly named function asserts that the passed IO is open.
Definition io.c:782
rb_io_event_t
Type of events that an IO can wait.
Definition io.h:81
@ RUBY_IO_READABLE
IO::READABLE
Definition io.h:82
@ RUBY_IO_PRIORITY
IO::PRIORITY
Definition io.h:84
@ RUBY_IO_WRITABLE
IO::WRITABLE
Definition io.h:83
int rb_io_wait_readable(int fd)
Blocks until the passed file descriptor gets readable.
Definition io.c:1477
void rb_io_synchronized(rb_io_t *fptr)
Sets FMODE_SYNC.
Definition io.c:7271
VALUE rb_io_wait(VALUE io, VALUE events, VALUE timeout)
Blocks until the passed IO is ready for the passed events.
Definition io.c:1416
VALUE rb_ractor_stderr(void)
Queries the standard error of the current Ractor that is calling this function.
Definition ractor.c:2148
VALUE rb_ractor_stdin(void)
Queries the standard input of the current Ractor that is calling this function.
Definition ractor.c:2124
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:2184
VALUE rb_ractor_stdout(void)
Queries the standard output of the current Ractor that is calling this function.
Definition ractor.c:2136
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:2172
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:2160
void * rb_thread_call_with_gvl(void *(*func)(void *), void *data1)
(Re-)acquires the GVL.
Definition thread.c:1761
void * rb_thread_call_without_gvl(void *(*func)(void *), void *data1, rb_unblock_function_t *ubf, void *data2)
Allows the passed function to run in parallel with other Ruby threads.
#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:208
VALUE rb_sprintf(const char *fmt,...)
Ruby's extended sprintf(3).
Definition sprintf.c:1219
VALUE rb_str_catf(VALUE dst, const char *fmt,...)
Identical to rb_sprintf(), except it renders the output to the specified object rather than creating ...
Definition sprintf.c:1242
#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:1391
VALUE rb_yield(VALUE val)
Yields the block.
Definition vm_eval.c:1357
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:354
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
Definition memory.h:161
#define MEMMOVE(p1, p2, type, n)
Handy macro to call memmove.
Definition memory.h:378
#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:68
static int RARRAY_LENINT(VALUE ary)
Identical to rb_array_len(), except it differs for the return type.
Definition rarray.h:343
#define RARRAY_AREF(a, i)
Definition rarray.h:583
#define RARRAY_CONST_PTR
Just another name of rb_array_const_ptr.
Definition rarray.h:69
#define RFILE(obj)
Convenient casting macro.
Definition rfile.h:50
#define SafeStringValue(v)
Definition rstring.h:104
#define StringValue(v)
Ensures that the parameter object is a String.
Definition rstring.h:72
static char * RSTRING_END(VALUE str)
Queries the end of the contents pointer of the string.
Definition rstring.h:528
#define RSTRING_GETMEM(str, ptrvar, lenvar)
Convenient macro to obtain the contents and length at once.
Definition rstring.h:574
static long RSTRING_LEN(VALUE str)
Queries the length of the string.
Definition rstring.h:484
static char * RSTRING_PTR(VALUE str)
Queries the contents pointer of the string.
Definition rstring.h:498
#define StringValueCStr(v)
Identical to StringValuePtr, except it additionally checks for the contents for viability as a C stri...
Definition rstring.h:95
#define RUBY_TYPED_DEFAULT_FREE
This is a value you can set to rb_data_type_struct::dfree.
Definition rtypeddata.h:79
#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:489
VALUE rb_get_argv(void)
Queries the arguments passed to the current process that you can access from Ruby as ARGV.
Definition io.c:14534
void rb_p(VALUE obj)
Inspects an object.
Definition io.c:8976
#define FilePathValue(v)
Ensures that the parameter object is a path.
Definition ruby.h:91
#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
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:203
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:246
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:419
VALUE rb_fiber_scheduler_io_wait(VALUE scheduler, VALUE io, VALUE events, VALUE timeout)
Non-blocking version of rb_io_wait().
Definition scheduler.c:413
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:70
VALUE rb_fiber_scheduler_io_selectv(VALUE scheduler, int argc, VALUE *argv)
Non-blocking version of IO.select, argv variant.
Definition scheduler.c:449
VALUE rb_fiber_scheduler_current_for_thread(VALUE thread)
Identical to rb_fiber_scheduler_current(), except it queries for that of the passed thread instead of...
Definition scheduler.c:208
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:425
VALUE rb_fiber_scheduler_io_write_memory(VALUE scheduler, VALUE io, const void *buffer, size_t size, size_t length)
Non-blocking write to the passed IO using a native buffer.
Definition scheduler.c:582
VALUE rb_fiber_scheduler_io_read_memory(VALUE scheduler, VALUE io, void *buffer, size_t size, size_t length)
Non-blocking read from the passed IO using a native buffer.
Definition scheduler.c:569
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:4186
static bool RB_TEST(VALUE obj)
Emulates Ruby's "if" statement.
#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:218
Definition win32.h:216
This is the struct that holds necessary info for a struct.
Definition rtypeddata.h:190
The data structure which wraps the fd_set bitmap used by select(2).
Definition largesize.h:71
IO buffers.
Definition io.h:104
int len
Length of the buffer.
Definition io.h:104
char * ptr
Pointer to the underlying memory region, of at least capa bytes.
Definition io.h:104
int off
Offset inside of ptr.
Definition io.h:104
int capa
Designed capacity of the buffer.
Definition io.h:104
Decomposed encoding flags (e.g.
Definition io.h:116
int ecflags
Flags.
Definition io.h:126
rb_encoding * enc2
External encoding.
Definition io.h:120
VALUE ecopts
Flags as Ruby hash.
Definition io.h:134
rb_encoding * enc
Internal encoding.
Definition io.h:118
Ruby's IO, metadata and buffers.
Definition io.h:138
int fd
file descriptor.
Definition io.h:147
int lineno
number of lines read
Definition io.h:156
rb_econv_t * writeconv
Encoding converter used when writing to this IO.
Definition io.h:192
rb_pid_t pid
child's pid (for pipes)
Definition io.h:153
rb_io_buffer_t wbuf
Write buffer.
Definition io.h:165
rb_econv_t * readconv
Encoding converter used when reading from this IO.
Definition io.h:183
VALUE writeconv_asciicompat
This is, when set, an instance of rb_cString which holds the "common" encoding.
Definition io.h:200
FILE * stdio_file
stdio ptr for read/write, if available.
Definition io.h:144
int writeconv_initialized
Whether rb_io_t::writeconv is already set up.
Definition io.h:203
VALUE pathv
pathname for file
Definition io.h:159
int mode
mode flags: FMODE_XXXs
Definition io.h:150
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:209
struct rb_io_enc_t encs
Decomposed encoding flags.
Definition io.h:180
VALUE write_lock
This is a Ruby level mutex.
Definition io.h:224
rb_io_buffer_t cbuf
rb_io_ungetc() destination.
Definition io.h:189
VALUE self
The IO's Ruby level counterpart.
Definition io.h:141
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:215
VALUE tied_io_for_writing
Duplex IO object, if set.
Definition io.h:178
void(* finalize)(struct rb_io_t *, int)
finalize proc
Definition io.h:162
VALUE timeout
The timeout associated with this IO when performing blocking operations.
Definition io.h:229
rb_io_buffer_t rbuf
(Byte) read buffer.
Definition io.h:171
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_SYMBOL_P(VALUE obj)
Queries if the object is an instance of rb_cSymbol.
Definition value_type.h:306
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:432
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:375