Ruby  3.4.0dev (2024-12-06 revision 892c46283a5ea4179500d951c9d4866c0051f27b)
io.c (892c46283a5ea4179500d951c9d4866c0051f27b)
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 
16 #include "ruby/fiber/scheduler.h"
17 #include "ruby/io/buffer.h"
18 
19 #include <ctype.h>
20 #include <errno.h>
21 #include <stddef.h>
22 
23 /* non-Linux poll may not work on all FDs */
24 #if defined(HAVE_POLL)
25 # if defined(__linux__)
26 # define USE_POLL 1
27 # endif
28 # if defined(__FreeBSD_version) && __FreeBSD_version >= 1100000
29 # define USE_POLL 1
30 # endif
31 #endif
32 
33 #ifndef USE_POLL
34 # define USE_POLL 0
35 #endif
36 
37 #undef free
38 #define free(x) xfree(x)
39 
40 #if defined(DOSISH) || defined(__CYGWIN__)
41 #include <io.h>
42 #endif
43 
44 #include <sys/types.h>
45 #if defined HAVE_NET_SOCKET_H
46 # include <net/socket.h>
47 #elif defined HAVE_SYS_SOCKET_H
48 # include <sys/socket.h>
49 #endif
50 
51 #if defined(__BOW__) || defined(__CYGWIN__) || defined(_WIN32)
52 # define NO_SAFE_RENAME
53 #endif
54 
55 #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__sun) || defined(_nec_ews)
56 # define USE_SETVBUF
57 #endif
58 
59 #ifdef __QNXNTO__
60 #include <unix.h>
61 #endif
62 
63 #include <sys/types.h>
64 #if defined(HAVE_SYS_IOCTL_H) && !defined(_WIN32)
65 #include <sys/ioctl.h>
66 #endif
67 #if defined(HAVE_FCNTL_H) || defined(_WIN32)
68 #include <fcntl.h>
69 #elif defined(HAVE_SYS_FCNTL_H)
70 #include <sys/fcntl.h>
71 #endif
72 
73 #ifdef HAVE_SYS_TIME_H
74 # include <sys/time.h>
75 #endif
76 
77 #include <sys/stat.h>
78 
79 #if defined(HAVE_SYS_PARAM_H) || defined(__HIUX_MPP__)
80 # include <sys/param.h>
81 #endif
82 
83 #if !defined NOFILE
84 # define NOFILE 64
85 #endif
86 
87 #ifdef HAVE_UNISTD_H
88 #include <unistd.h>
89 #endif
90 
91 #ifdef HAVE_SYSCALL_H
92 #include <syscall.h>
93 #elif defined HAVE_SYS_SYSCALL_H
94 #include <sys/syscall.h>
95 #endif
96 
97 #ifdef HAVE_SYS_UIO_H
98 #include <sys/uio.h>
99 #endif
100 
101 #ifdef HAVE_SYS_WAIT_H
102 # include <sys/wait.h> /* for WNOHANG on BSD */
103 #endif
104 
105 #ifdef HAVE_COPYFILE_H
106 # include <copyfile.h>
107 
108 # ifndef COPYFILE_STATE_COPIED
109 /*
110  * Some OSes (e.g., OSX < 10.6) implement fcopyfile() but not
111  * COPYFILE_STATE_COPIED. Since the only use of the former here
112  * requires the latter, we disable the former when the latter is undefined.
113  */
114 # undef HAVE_FCOPYFILE
115 # endif
116 
117 #endif
118 
119 #include "ruby/internal/stdbool.h"
120 #include "ccan/list/list.h"
121 #include "dln.h"
122 #include "encindex.h"
123 #include "id.h"
124 #include "internal.h"
125 #include "internal/class.h"
126 #include "internal/encoding.h"
127 #include "internal/error.h"
128 #include "internal/inits.h"
129 #include "internal/io.h"
130 #include "internal/numeric.h"
131 #include "internal/object.h"
132 #include "internal/process.h"
133 #include "internal/thread.h"
134 #include "internal/transcode.h"
135 #include "internal/variable.h"
136 #include "ruby/io.h"
137 #include "ruby/io/buffer.h"
138 #include "ruby/missing.h"
139 #include "ruby/thread.h"
140 #include "ruby/util.h"
141 #include "ruby_atomic.h"
142 #include "ruby/ractor.h"
143 
144 #if !USE_POLL
145 # include "vm_core.h"
146 #endif
147 
148 #include "builtin.h"
149 
150 #ifndef O_ACCMODE
151 #define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR)
152 #endif
153 
154 #ifndef PIPE_BUF
155 # ifdef _POSIX_PIPE_BUF
156 # define PIPE_BUF _POSIX_PIPE_BUF
157 # else
158 # define PIPE_BUF 512 /* is this ok? */
159 # endif
160 #endif
161 
162 #ifndef EWOULDBLOCK
163 # define EWOULDBLOCK EAGAIN
164 #endif
165 
166 #if defined(HAVE___SYSCALL) && (defined(__APPLE__) || defined(__OpenBSD__))
167 /* Mac OS X and OpenBSD have __syscall but don't define it in headers */
168 off_t __syscall(quad_t number, ...);
169 #endif
170 
171 #define IO_RBUF_CAPA_MIN 8192
172 #define IO_CBUF_CAPA_MIN (128*1024)
173 #define IO_RBUF_CAPA_FOR(fptr) (NEED_READCONV(fptr) ? IO_CBUF_CAPA_MIN : IO_RBUF_CAPA_MIN)
174 #define IO_WBUF_CAPA_MIN 8192
175 
176 #define IO_MAX_BUFFER_GROWTH 8 * 1024 * 1024 // 8MB
177 
178 /* define system APIs */
179 #ifdef _WIN32
180 #undef open
181 #define open rb_w32_uopen
182 #undef rename
183 #define rename(f, t) rb_w32_urename((f), (t))
184 #include "win32/file.h"
185 #endif
186 
193 
194 static VALUE rb_eEAGAINWaitReadable;
195 static VALUE rb_eEAGAINWaitWritable;
196 static VALUE rb_eEWOULDBLOCKWaitReadable;
197 static VALUE rb_eEWOULDBLOCKWaitWritable;
198 static VALUE rb_eEINPROGRESSWaitWritable;
199 static VALUE rb_eEINPROGRESSWaitReadable;
200 
202 static VALUE orig_stdout, orig_stderr;
203 
208 
209 static VALUE argf;
210 
211 static ID id_write, id_read, id_getc, id_flush, id_readpartial, id_set_encoding, id_fileno;
212 static VALUE sym_mode, sym_perm, sym_flags, sym_extenc, sym_intenc, sym_encoding, sym_open_args;
213 static VALUE sym_textmode, sym_binmode, sym_autoclose;
214 static VALUE sym_SET, sym_CUR, sym_END;
215 static VALUE sym_wait_readable, sym_wait_writable;
216 #ifdef SEEK_DATA
217 static VALUE sym_DATA;
218 #endif
219 #ifdef SEEK_HOLE
220 static VALUE sym_HOLE;
221 #endif
222 
223 static VALUE prep_io(int fd, int fmode, VALUE klass, const char *path);
224 
225 VALUE
226 rb_io_blocking_region_wait(struct rb_io *io, rb_blocking_function_t *function, void *argument, enum rb_io_event events)
227 {
228  return rb_thread_io_blocking_call(function, argument, io->fd, events);
229 }
230 
231 VALUE rb_io_blocking_region(struct rb_io *io, rb_blocking_function_t *function, void *argument)
232 {
233  return rb_io_blocking_region_wait(io, function, argument, 0);
234 }
235 
236 struct argf {
237  VALUE filename, current_file;
238  long last_lineno; /* $. */
239  long lineno;
240  VALUE argv;
241  VALUE inplace;
242  struct rb_io_encoding encs;
243  int8_t init_p, next_p, binmode;
244 };
245 
246 static rb_atomic_t max_file_descriptor = NOFILE;
247 void
249 {
250  rb_atomic_t afd = (rb_atomic_t)fd;
251  rb_atomic_t max_fd = max_file_descriptor;
252  int err;
253 
254  if (fd < 0 || afd <= max_fd)
255  return;
256 
257 #if defined(HAVE_FCNTL) && defined(F_GETFL)
258  err = fcntl(fd, F_GETFL) == -1;
259 #else
260  {
261  struct stat buf;
262  err = fstat(fd, &buf) != 0;
263  }
264 #endif
265  if (err && errno == EBADF) {
266  rb_bug("rb_update_max_fd: invalid fd (%d) given.", fd);
267  }
268 
269  while (max_fd < afd) {
270  max_fd = ATOMIC_CAS(max_file_descriptor, max_fd, afd);
271  }
272 }
273 
274 void
275 rb_maygvl_fd_fix_cloexec(int fd)
276 {
277  /* MinGW don't have F_GETFD and FD_CLOEXEC. [ruby-core:40281] */
278 #if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
279  int flags, flags2, ret;
280  flags = fcntl(fd, F_GETFD); /* should not fail except EBADF. */
281  if (flags == -1) {
282  rb_bug("rb_maygvl_fd_fix_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(errno));
283  }
284  if (fd <= 2)
285  flags2 = flags & ~FD_CLOEXEC; /* Clear CLOEXEC for standard file descriptors: 0, 1, 2. */
286  else
287  flags2 = flags | FD_CLOEXEC; /* Set CLOEXEC for non-standard file descriptors: 3, 4, 5, ... */
288  if (flags != flags2) {
289  ret = fcntl(fd, F_SETFD, flags2);
290  if (ret != 0) {
291  rb_bug("rb_maygvl_fd_fix_cloexec: fcntl(%d, F_SETFD, %d) failed: %s", fd, flags2, strerror(errno));
292  }
293  }
294 #endif
295 }
296 
297 void
299 {
300  rb_maygvl_fd_fix_cloexec(fd);
301  rb_update_max_fd(fd);
302 }
303 
304 /* this is only called once */
305 static int
306 rb_fix_detect_o_cloexec(int fd)
307 {
308 #if defined(O_CLOEXEC) && defined(F_GETFD)
309  int flags = fcntl(fd, F_GETFD);
310 
311  if (flags == -1)
312  rb_bug("rb_fix_detect_o_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(errno));
313 
314  if (flags & FD_CLOEXEC)
315  return 1;
316 #endif /* fall through if O_CLOEXEC does not work: */
317  rb_maygvl_fd_fix_cloexec(fd);
318  return 0;
319 }
320 
321 static inline bool
322 io_again_p(int e)
323 {
324  return (e == EWOULDBLOCK) || (e == EAGAIN);
325 }
326 
327 int
328 rb_cloexec_open(const char *pathname, int flags, mode_t mode)
329 {
330  int ret;
331  static int o_cloexec_state = -1; /* <0: unknown, 0: ignored, >0: working */
332 
333  static const int retry_interval = 0;
334  static const int retry_max_count = 10000;
335 
336  int retry_count = 0;
337 
338 #ifdef O_CLOEXEC
339  /* O_CLOEXEC is available since Linux 2.6.23. Linux 2.6.18 silently ignore it. */
340  flags |= O_CLOEXEC;
341 #elif defined O_NOINHERIT
342  flags |= O_NOINHERIT;
343 #endif
344 
345  while ((ret = open(pathname, flags, mode)) == -1) {
346  int e = errno;
347  if (!io_again_p(e)) break;
348  if (retry_count++ >= retry_max_count) break;
349 
350  sleep(retry_interval);
351  }
352 
353  if (ret < 0) return ret;
354  if (ret <= 2 || o_cloexec_state == 0) {
355  rb_maygvl_fd_fix_cloexec(ret);
356  }
357  else if (o_cloexec_state > 0) {
358  return ret;
359  }
360  else {
361  o_cloexec_state = rb_fix_detect_o_cloexec(ret);
362  }
363  return ret;
364 }
365 
366 int
367 rb_cloexec_dup(int oldfd)
368 {
369  /* Don't allocate standard file descriptors: 0, 1, 2 */
370  return rb_cloexec_fcntl_dupfd(oldfd, 3);
371 }
372 
373 int
374 rb_cloexec_dup2(int oldfd, int newfd)
375 {
376  int ret;
377 
378  /* When oldfd == newfd, dup2 succeeds but dup3 fails with EINVAL.
379  * rb_cloexec_dup2 succeeds as dup2. */
380  if (oldfd == newfd) {
381  ret = newfd;
382  }
383  else {
384 #if defined(HAVE_DUP3) && defined(O_CLOEXEC)
385  static int try_dup3 = 1;
386  if (2 < newfd && try_dup3) {
387  ret = dup3(oldfd, newfd, O_CLOEXEC);
388  if (ret != -1)
389  return ret;
390  /* dup3 is available since Linux 2.6.27, glibc 2.9. */
391  if (errno == ENOSYS) {
392  try_dup3 = 0;
393  ret = dup2(oldfd, newfd);
394  }
395  }
396  else {
397  ret = dup2(oldfd, newfd);
398  }
399 #else
400  ret = dup2(oldfd, newfd);
401 #endif
402  if (ret < 0) return ret;
403  }
404  rb_maygvl_fd_fix_cloexec(ret);
405  return ret;
406 }
407 
408 static int
409 rb_fd_set_nonblock(int fd)
410 {
411 #ifdef _WIN32
412  return rb_w32_set_nonblock(fd);
413 #elif defined(F_GETFL)
414  int oflags = fcntl(fd, F_GETFL);
415 
416  if (oflags == -1)
417  return -1;
418  if (oflags & O_NONBLOCK)
419  return 0;
420  oflags |= O_NONBLOCK;
421  return fcntl(fd, F_SETFL, oflags);
422 #endif
423  return 0;
424 }
425 
426 int
427 rb_cloexec_pipe(int descriptors[2])
428 {
429 #ifdef HAVE_PIPE2
430  int result = pipe2(descriptors, O_CLOEXEC | O_NONBLOCK);
431 #else
432  int result = pipe(descriptors);
433 #endif
434 
435  if (result < 0)
436  return result;
437 
438 #ifdef __CYGWIN__
439  if (result == 0 && descriptors[1] == -1) {
440  close(descriptors[0]);
441  descriptors[0] = -1;
442  errno = ENFILE;
443  return -1;
444  }
445 #endif
446 
447 #ifndef HAVE_PIPE2
448  rb_maygvl_fd_fix_cloexec(descriptors[0]);
449  rb_maygvl_fd_fix_cloexec(descriptors[1]);
450 
451 #ifndef _WIN32
452  rb_fd_set_nonblock(descriptors[0]);
453  rb_fd_set_nonblock(descriptors[1]);
454 #endif
455 #endif
456 
457  return result;
458 }
459 
460 int
461 rb_cloexec_fcntl_dupfd(int fd, int minfd)
462 {
463  int ret;
464 
465 #if defined(HAVE_FCNTL) && defined(F_DUPFD_CLOEXEC) && defined(F_DUPFD)
466  static int try_dupfd_cloexec = 1;
467  if (try_dupfd_cloexec) {
468  ret = fcntl(fd, F_DUPFD_CLOEXEC, minfd);
469  if (ret != -1) {
470  if (ret <= 2)
471  rb_maygvl_fd_fix_cloexec(ret);
472  return ret;
473  }
474  /* F_DUPFD_CLOEXEC is available since Linux 2.6.24. Linux 2.6.18 fails with EINVAL */
475  if (errno == EINVAL) {
476  ret = fcntl(fd, F_DUPFD, minfd);
477  if (ret != -1) {
478  try_dupfd_cloexec = 0;
479  }
480  }
481  }
482  else {
483  ret = fcntl(fd, F_DUPFD, minfd);
484  }
485 #elif defined(HAVE_FCNTL) && defined(F_DUPFD)
486  ret = fcntl(fd, F_DUPFD, minfd);
487 #else
488  ret = dup(fd);
489  if (ret >= 0 && ret < minfd) {
490  const int prev_fd = ret;
491  ret = rb_cloexec_fcntl_dupfd(fd, minfd);
492  close(prev_fd);
493  }
494  return ret;
495 #endif
496  if (ret < 0) return ret;
497  rb_maygvl_fd_fix_cloexec(ret);
498  return ret;
499 }
500 
501 #define argf_of(obj) (*(struct argf *)DATA_PTR(obj))
502 #define ARGF argf_of(argf)
503 
504 #define GetWriteIO(io) rb_io_get_write_io(io)
505 
506 #define READ_DATA_PENDING(fptr) ((fptr)->rbuf.len)
507 #define READ_DATA_PENDING_COUNT(fptr) ((fptr)->rbuf.len)
508 #define READ_DATA_PENDING_PTR(fptr) ((fptr)->rbuf.ptr+(fptr)->rbuf.off)
509 #define READ_DATA_BUFFERED(fptr) READ_DATA_PENDING(fptr)
510 
511 #define READ_CHAR_PENDING(fptr) ((fptr)->cbuf.len)
512 #define READ_CHAR_PENDING_COUNT(fptr) ((fptr)->cbuf.len)
513 #define READ_CHAR_PENDING_PTR(fptr) ((fptr)->cbuf.ptr+(fptr)->cbuf.off)
514 
515 #if defined(_WIN32)
516 #define WAIT_FD_IN_WIN32(fptr) \
517  (rb_w32_io_cancelable_p((fptr)->fd) ? Qnil : rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), RUBY_IO_TIMEOUT_DEFAULT))
518 #else
519 #define WAIT_FD_IN_WIN32(fptr)
520 #endif
521 
522 #define READ_CHECK(fptr) do {\
523  if (!READ_DATA_PENDING(fptr)) {\
524  WAIT_FD_IN_WIN32(fptr);\
525  rb_io_check_closed(fptr);\
526  }\
527 } while(0)
528 
529 #ifndef S_ISSOCK
530 # ifdef _S_ISSOCK
531 # define S_ISSOCK(m) _S_ISSOCK(m)
532 # else
533 # ifdef _S_IFSOCK
534 # define S_ISSOCK(m) (((m) & S_IFMT) == _S_IFSOCK)
535 # else
536 # ifdef S_IFSOCK
537 # define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
538 # endif
539 # endif
540 # endif
541 #endif
542 
543 static int io_fflush(rb_io_t *);
544 static rb_io_t *flush_before_seek(rb_io_t *fptr, bool discard_rbuf);
545 static void clear_codeconv(rb_io_t *fptr);
546 
547 #define FMODE_SIGNAL_ON_EPIPE (1<<17)
548 
549 #define fptr_signal_on_epipe(fptr) \
550  (((fptr)->mode & FMODE_SIGNAL_ON_EPIPE) != 0)
551 
552 #define fptr_set_signal_on_epipe(fptr, flag) \
553  ((flag) ? \
554  (fptr)->mode |= FMODE_SIGNAL_ON_EPIPE : \
555  (fptr)->mode &= ~FMODE_SIGNAL_ON_EPIPE)
556 
557 extern ID ruby_static_id_signo;
558 
559 NORETURN(static void rb_sys_fail_on_write(rb_io_t *fptr));
560 static void
561 rb_sys_fail_on_write(rb_io_t *fptr)
562 {
563  int e = errno;
564  VALUE errinfo = rb_syserr_new_path(e, (fptr)->pathv);
565 #if defined EPIPE
566  if (fptr_signal_on_epipe(fptr) && (e == EPIPE)) {
567  const VALUE sig =
568 # if defined SIGPIPE
569  INT2FIX(SIGPIPE) - INT2FIX(0) +
570 # endif
571  INT2FIX(0);
572  rb_ivar_set(errinfo, ruby_static_id_signo, sig);
573  }
574 #endif
575  rb_exc_raise(errinfo);
576 }
577 
578 #define NEED_NEWLINE_DECORATOR_ON_READ(fptr) ((fptr)->mode & FMODE_TEXTMODE)
579 #define NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) ((fptr)->mode & FMODE_TEXTMODE)
580 #if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)
581 # define RUBY_CRLF_ENVIRONMENT 1
582 #else
583 # define RUBY_CRLF_ENVIRONMENT 0
584 #endif
585 
586 #if RUBY_CRLF_ENVIRONMENT
587 /* Windows */
588 # define DEFAULT_TEXTMODE FMODE_TEXTMODE
589 # define TEXTMODE_NEWLINE_DECORATOR_ON_WRITE ECONV_CRLF_NEWLINE_DECORATOR
590 /*
591  * CRLF newline is set as default newline decorator.
592  * If only CRLF newline conversion is needed, we use binary IO process
593  * with OS's text mode for IO performance improvement.
594  * If encoding conversion is needed or a user sets text mode, we use encoding
595  * conversion IO process and universal newline decorator by default.
596  */
597 #define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || (fptr)->encs.ecflags & ~ECONV_CRLF_NEWLINE_DECORATOR)
598 #define WRITECONV_MASK ( \
599  (ECONV_DECORATOR_MASK & ~ECONV_CRLF_NEWLINE_DECORATOR)|\
600  ECONV_STATEFUL_DECORATOR_MASK|\
601  0)
602 #define NEED_WRITECONV(fptr) ( \
603  ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
604  ((fptr)->encs.ecflags & WRITECONV_MASK) || \
605  0)
606 #define SET_BINARY_MODE(fptr) setmode((fptr)->fd, O_BINARY)
607 
608 #define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) do {\
609  if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {\
610  if (((fptr)->mode & FMODE_READABLE) &&\
611  !((fptr)->encs.ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {\
612  setmode((fptr)->fd, O_BINARY);\
613  }\
614  else {\
615  setmode((fptr)->fd, O_TEXT);\
616  }\
617  }\
618 } while(0)
619 
620 #define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) do {\
621  if ((enc2) && ((ecflags) & ECONV_DEFAULT_NEWLINE_DECORATOR)) {\
622  (ecflags) |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;\
623  }\
624 } while(0)
625 
626 /*
627  * IO unread with taking care of removed '\r' in text mode.
628  */
629 static void
630 io_unread(rb_io_t *fptr, bool discard_rbuf)
631 {
632  rb_off_t r, pos;
633  ssize_t read_size;
634  long i;
635  long newlines = 0;
636  long extra_max;
637  char *p;
638  char *buf;
639 
640  rb_io_check_closed(fptr);
641  if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX) {
642  return;
643  }
644 
645  errno = 0;
646  if (!rb_w32_fd_is_text(fptr->fd)) {
647  r = lseek(fptr->fd, -fptr->rbuf.len, SEEK_CUR);
648  if (r < 0 && errno) {
649  if (errno == ESPIPE)
650  fptr->mode |= FMODE_DUPLEX;
651  if (!discard_rbuf) return;
652  }
653 
654  goto end;
655  }
656 
657  pos = lseek(fptr->fd, 0, SEEK_CUR);
658  if (pos < 0 && errno) {
659  if (errno == ESPIPE)
660  fptr->mode |= FMODE_DUPLEX;
661  if (!discard_rbuf) goto end;
662  }
663 
664  /* add extra offset for removed '\r' in rbuf */
665  extra_max = (long)(pos - fptr->rbuf.len);
666  p = fptr->rbuf.ptr + fptr->rbuf.off;
667 
668  /* if the end of rbuf is '\r', rbuf doesn't have '\r' within rbuf.len */
669  if (*(fptr->rbuf.ptr + fptr->rbuf.capa - 1) == '\r') {
670  newlines++;
671  }
672 
673  for (i = 0; i < fptr->rbuf.len; i++) {
674  if (*p == '\n') newlines++;
675  if (extra_max == newlines) break;
676  p++;
677  }
678 
679  buf = ALLOC_N(char, fptr->rbuf.len + newlines);
680  while (newlines >= 0) {
681  r = lseek(fptr->fd, pos - fptr->rbuf.len - newlines, SEEK_SET);
682  if (newlines == 0) break;
683  if (r < 0) {
684  newlines--;
685  continue;
686  }
687  read_size = _read(fptr->fd, buf, fptr->rbuf.len + newlines);
688  if (read_size < 0) {
689  int e = errno;
690  free(buf);
691  rb_syserr_fail_path(e, fptr->pathv);
692  }
693  if (read_size == fptr->rbuf.len) {
694  lseek(fptr->fd, r, SEEK_SET);
695  break;
696  }
697  else {
698  newlines--;
699  }
700  }
701  free(buf);
702  end:
703  fptr->rbuf.off = 0;
704  fptr->rbuf.len = 0;
705  clear_codeconv(fptr);
706  return;
707 }
708 
709 /*
710  * We use io_seek to back cursor position when changing mode from text to binary,
711  * but stdin and pipe cannot seek back. Stdin and pipe read should use encoding
712  * conversion for working properly with mode change.
713  *
714  * Return previous translation mode.
715  */
716 static inline int
717 set_binary_mode_with_seek_cur(rb_io_t *fptr)
718 {
719  if (!rb_w32_fd_is_text(fptr->fd)) return O_BINARY;
720 
721  if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX) {
722  return setmode(fptr->fd, O_BINARY);
723  }
724  flush_before_seek(fptr, false);
725  return setmode(fptr->fd, O_BINARY);
726 }
727 #define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) set_binary_mode_with_seek_cur(fptr)
728 
729 #else
730 /* Unix */
731 # define DEFAULT_TEXTMODE 0
732 #define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || NEED_NEWLINE_DECORATOR_ON_READ(fptr))
733 #define NEED_WRITECONV(fptr) ( \
734  ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
735  NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) || \
736  ((fptr)->encs.ecflags & (ECONV_DECORATOR_MASK|ECONV_STATEFUL_DECORATOR_MASK)) || \
737  0)
738 #define SET_BINARY_MODE(fptr) (void)(fptr)
739 #define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) (void)(fptr)
740 #define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) ((void)(enc2), (void)(ecflags))
741 #define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) (void)(fptr)
742 #endif
743 
744 #if !defined HAVE_SHUTDOWN && !defined shutdown
745 #define shutdown(a,b) 0
746 #endif
747 
748 #if defined(_WIN32)
749 #define is_socket(fd, path) rb_w32_is_socket(fd)
750 #elif !defined(S_ISSOCK)
751 #define is_socket(fd, path) 0
752 #else
753 static int
754 is_socket(int fd, VALUE path)
755 {
756  struct stat sbuf;
757  if (fstat(fd, &sbuf) < 0)
758  rb_sys_fail_path(path);
759  return S_ISSOCK(sbuf.st_mode);
760 }
761 #endif
762 
763 static const char closed_stream[] = "closed stream";
764 
765 static void
766 io_fd_check_closed(int fd)
767 {
768  if (fd < 0) {
769  rb_thread_check_ints(); /* check for ruby_error_stream_closed */
770  rb_raise(rb_eIOError, closed_stream);
771  }
772 }
773 
774 void
775 rb_eof_error(void)
776 {
777  rb_raise(rb_eEOFError, "end of file reached");
778 }
779 
780 VALUE
782 {
783  rb_check_frozen(io);
784  return io;
785 }
786 
787 void
789 {
790  if (!fptr) {
791  rb_raise(rb_eIOError, "uninitialized stream");
792  }
793 }
794 
795 void
797 {
799  io_fd_check_closed(fptr->fd);
800 }
801 
802 static rb_io_t *
803 rb_io_get_fptr(VALUE io)
804 {
805  rb_io_t *fptr = RFILE(io)->fptr;
807  return fptr;
808 }
809 
810 VALUE
812 {
813  return rb_convert_type_with_id(io, T_FILE, "IO", idTo_io);
814 }
815 
816 VALUE
818 {
819  return rb_check_convert_type_with_id(io, T_FILE, "IO", idTo_io);
820 }
821 
822 VALUE
824 {
825  VALUE write_io;
826  write_io = rb_io_get_fptr(io)->tied_io_for_writing;
827  if (write_io) {
828  return write_io;
829  }
830  return io;
831 }
832 
833 VALUE
835 {
836  VALUE write_io;
837  rb_io_t *fptr = rb_io_get_fptr(io);
838  if (!RTEST(w)) {
839  w = 0;
840  }
841  else {
842  GetWriteIO(w);
843  }
844  write_io = fptr->tied_io_for_writing;
845  fptr->tied_io_for_writing = w;
846  return write_io ? write_io : Qnil;
847 }
848 
849 /*
850  * call-seq:
851  * timeout -> duration or nil
852  *
853  * Get the internal timeout duration or nil if it was not set.
854  *
855  */
856 VALUE
858 {
859  rb_io_t *fptr = rb_io_get_fptr(self);
860 
861  return fptr->timeout;
862 }
863 
864 /*
865  * call-seq:
866  * timeout = duration -> duration
867  * timeout = nil -> nil
868  *
869  * Sets the internal timeout to the specified duration or nil. The timeout
870  * applies to all blocking operations where possible.
871  *
872  * When the operation performs longer than the timeout set, IO::TimeoutError
873  * is raised.
874  *
875  * This affects the following methods (but is not limited to): #gets, #puts,
876  * #read, #write, #wait_readable and #wait_writable. This also affects
877  * blocking socket operations like Socket#accept and Socket#connect.
878  *
879  * Some operations like File#open and IO#close are not affected by the
880  * timeout. A timeout during a write operation may leave the IO in an
881  * inconsistent state, e.g. data was partially written. Generally speaking, a
882  * timeout is a last ditch effort to prevent an application from hanging on
883  * slow I/O operations, such as those that occur during a slowloris attack.
884  */
885 VALUE
887 {
888  // Validate it:
889  if (RTEST(timeout)) {
890  rb_time_interval(timeout);
891  }
892 
893  rb_io_t *fptr = rb_io_get_fptr(self);
894 
895  fptr->timeout = timeout;
896 
897  return self;
898 }
899 
900 /*
901  * call-seq:
902  * IO.try_convert(object) -> new_io or nil
903  *
904  * Attempts to convert +object+ into an \IO object via method +to_io+;
905  * returns the new \IO object if successful, or +nil+ otherwise:
906  *
907  * IO.try_convert(STDOUT) # => #<IO:<STDOUT>>
908  * IO.try_convert(ARGF) # => #<IO:<STDIN>>
909  * IO.try_convert('STDOUT') # => nil
910  *
911  */
912 static VALUE
913 rb_io_s_try_convert(VALUE dummy, VALUE io)
914 {
915  return rb_io_check_io(io);
916 }
917 
918 #if !RUBY_CRLF_ENVIRONMENT
919 static void
920 io_unread(rb_io_t *fptr, bool discard_rbuf)
921 {
922  rb_off_t r;
923  rb_io_check_closed(fptr);
924  if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX)
925  return;
926  /* xxx: target position may be negative if buffer is filled by ungetc */
927  errno = 0;
928  r = lseek(fptr->fd, -fptr->rbuf.len, SEEK_CUR);
929  if (r < 0 && errno) {
930  if (errno == ESPIPE)
931  fptr->mode |= FMODE_DUPLEX;
932  if (!discard_rbuf) return;
933  }
934  fptr->rbuf.off = 0;
935  fptr->rbuf.len = 0;
936  clear_codeconv(fptr);
937  return;
938 }
939 #endif
940 
941 static rb_encoding *io_input_encoding(rb_io_t *fptr);
942 
943 static void
944 io_ungetbyte(VALUE str, rb_io_t *fptr)
945 {
946  long len = RSTRING_LEN(str);
947 
948  if (fptr->rbuf.ptr == NULL) {
949  const int min_capa = IO_RBUF_CAPA_FOR(fptr);
950  fptr->rbuf.off = 0;
951  fptr->rbuf.len = 0;
952 #if SIZEOF_LONG > SIZEOF_INT
953  if (len > INT_MAX)
954  rb_raise(rb_eIOError, "ungetbyte failed");
955 #endif
956  if (len > min_capa)
957  fptr->rbuf.capa = (int)len;
958  else
959  fptr->rbuf.capa = min_capa;
960  fptr->rbuf.ptr = ALLOC_N(char, fptr->rbuf.capa);
961  }
962  if (fptr->rbuf.capa < len + fptr->rbuf.len) {
963  rb_raise(rb_eIOError, "ungetbyte failed");
964  }
965  if (fptr->rbuf.off < len) {
966  MEMMOVE(fptr->rbuf.ptr+fptr->rbuf.capa-fptr->rbuf.len,
967  fptr->rbuf.ptr+fptr->rbuf.off,
968  char, fptr->rbuf.len);
969  fptr->rbuf.off = fptr->rbuf.capa-fptr->rbuf.len;
970  }
971  fptr->rbuf.off-=(int)len;
972  fptr->rbuf.len+=(int)len;
973  MEMMOVE(fptr->rbuf.ptr+fptr->rbuf.off, RSTRING_PTR(str), char, len);
974 }
975 
976 static rb_io_t *
977 flush_before_seek(rb_io_t *fptr, bool discard_rbuf)
978 {
979  if (io_fflush(fptr) < 0)
980  rb_sys_fail_on_write(fptr);
981  io_unread(fptr, discard_rbuf);
982  errno = 0;
983  return fptr;
984 }
985 
986 #define io_seek(fptr, ofs, whence) (errno = 0, lseek(flush_before_seek(fptr, true)->fd, (ofs), (whence)))
987 #define io_tell(fptr) lseek(flush_before_seek(fptr, false)->fd, 0, SEEK_CUR)
988 
989 #ifndef SEEK_CUR
990 # define SEEK_SET 0
991 # define SEEK_CUR 1
992 # define SEEK_END 2
993 #endif
994 
995 void
997 {
998  rb_io_check_closed(fptr);
999  if (!(fptr->mode & FMODE_READABLE)) {
1000  rb_raise(rb_eIOError, "not opened for reading");
1001  }
1002  if (fptr->wbuf.len) {
1003  if (io_fflush(fptr) < 0)
1004  rb_sys_fail_on_write(fptr);
1005  }
1006  if (fptr->tied_io_for_writing) {
1007  rb_io_t *wfptr;
1008  GetOpenFile(fptr->tied_io_for_writing, wfptr);
1009  if (io_fflush(wfptr) < 0)
1010  rb_sys_fail_on_write(wfptr);
1011  }
1012 }
1013 
1014 void
1016 {
1018  if (READ_CHAR_PENDING(fptr)) {
1019  rb_raise(rb_eIOError, "byte oriented read for character buffered IO");
1020  }
1021 }
1022 
1023 void
1025 {
1027 }
1028 
1029 static rb_encoding*
1030 io_read_encoding(rb_io_t *fptr)
1031 {
1032  if (fptr->encs.enc) {
1033  return fptr->encs.enc;
1034  }
1036 }
1037 
1038 static rb_encoding*
1039 io_input_encoding(rb_io_t *fptr)
1040 {
1041  if (fptr->encs.enc2) {
1042  return fptr->encs.enc2;
1043  }
1044  return io_read_encoding(fptr);
1045 }
1046 
1047 void
1049 {
1050  rb_io_check_closed(fptr);
1051  if (!(fptr->mode & FMODE_WRITABLE)) {
1052  rb_raise(rb_eIOError, "not opened for writing");
1053  }
1054  if (fptr->rbuf.len) {
1055  io_unread(fptr, true);
1056  }
1057 }
1058 
1059 int
1060 rb_io_read_pending(rb_io_t *fptr)
1061 {
1062  /* This function is used for bytes and chars. Confusing. */
1063  if (READ_CHAR_PENDING(fptr))
1064  return 1; /* should raise? */
1065  return READ_DATA_PENDING(fptr);
1066 }
1067 
1068 void
1070 {
1071  if (!READ_DATA_PENDING(fptr)) {
1072  rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), RUBY_IO_TIMEOUT_DEFAULT);
1073  }
1074  return;
1075 }
1076 
1077 int
1078 rb_gc_for_fd(int err)
1079 {
1080  if (err == EMFILE || err == ENFILE || err == ENOMEM) {
1081  rb_gc();
1082  return 1;
1083  }
1084  return 0;
1085 }
1086 
1087 /* try `expr` upto twice while it returns false and `errno`
1088  * is to GC. Each `errno`s are available as `first_errno` and
1089  * `retried_errno` respectively */
1090 #define TRY_WITH_GC(expr) \
1091  for (int first_errno, retried_errno = 0, retried = 0; \
1092  (!retried && \
1093  !(expr) && \
1094  (!rb_gc_for_fd(first_errno = errno) || !(expr)) && \
1095  (retried_errno = errno, 1)); \
1096  (void)retried_errno, retried = 1)
1097 
1098 static int
1099 ruby_dup(int orig)
1100 {
1101  int fd = -1;
1102 
1103  TRY_WITH_GC((fd = rb_cloexec_dup(orig)) >= 0) {
1104  rb_syserr_fail(first_errno, 0);
1105  }
1106  rb_update_max_fd(fd);
1107  return fd;
1108 }
1109 
1110 static VALUE
1111 io_alloc(VALUE klass)
1112 {
1113  NEWOBJ_OF(io, struct RFile, klass, T_FILE, sizeof(struct RFile), 0);
1114 
1115  io->fptr = 0;
1116 
1117  return (VALUE)io;
1118 }
1119 
1120 #ifndef S_ISREG
1121 # define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
1122 #endif
1123 
1125  VALUE th;
1126  rb_io_t *fptr;
1127  int nonblock;
1128  int fd;
1129 
1130  void *buf;
1131  size_t capa;
1132  struct timeval *timeout;
1133 };
1134 
1136  VALUE th;
1137  rb_io_t *fptr;
1138  int nonblock;
1139  int fd;
1140 
1141  const void *buf;
1142  size_t capa;
1143  struct timeval *timeout;
1144 };
1145 
1146 #ifdef HAVE_WRITEV
1147 struct io_internal_writev_struct {
1148  VALUE th;
1149  rb_io_t *fptr;
1150  int nonblock;
1151  int fd;
1152 
1153  int iovcnt;
1154  const struct iovec *iov;
1155  struct timeval *timeout;
1156 };
1157 #endif
1158 
1159 static int nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout);
1160 
1166 static inline int
1167 io_internal_wait(VALUE thread, rb_io_t *fptr, int error, int events, struct timeval *timeout)
1168 {
1169  if (!timeout && rb_thread_mn_schedulable(thread)) {
1170  RUBY_ASSERT(errno == EWOULDBLOCK || errno == EAGAIN);
1171  return -1;
1172  }
1173 
1174  int ready = nogvl_wait_for(thread, fptr, events, timeout);
1175 
1176  if (ready > 0) {
1177  return ready;
1178  }
1179  else if (ready == 0) {
1180  errno = ETIMEDOUT;
1181  return -1;
1182  }
1183 
1184  errno = error;
1185  return -1;
1186 }
1187 
1188 static VALUE
1189 internal_read_func(void *ptr)
1190 {
1191  struct io_internal_read_struct *iis = ptr;
1192  ssize_t result;
1193 
1194  if (iis->timeout && !iis->nonblock) {
1195  if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_IN, iis->timeout) == -1) {
1196  return -1;
1197  }
1198  }
1199 
1200  retry:
1201  result = read(iis->fd, iis->buf, iis->capa);
1202 
1203  if (result < 0 && !iis->nonblock) {
1204  if (io_again_p(errno)) {
1205  if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_IN, iis->timeout) == -1) {
1206  return -1;
1207  }
1208  else {
1209  goto retry;
1210  }
1211  }
1212  }
1213 
1214  return result;
1215 }
1216 
1217 #if defined __APPLE__
1218 # define do_write_retry(code) do {result = code;} while (result == -1 && errno == EPROTOTYPE)
1219 #else
1220 # define do_write_retry(code) result = code
1221 #endif
1222 
1223 static VALUE
1224 internal_write_func(void *ptr)
1225 {
1226  struct io_internal_write_struct *iis = ptr;
1227  ssize_t result;
1228 
1229  if (iis->timeout && !iis->nonblock) {
1230  if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1231  return -1;
1232  }
1233  }
1234 
1235  retry:
1236  do_write_retry(write(iis->fd, iis->buf, iis->capa));
1237 
1238  if (result < 0 && !iis->nonblock) {
1239  int e = errno;
1240  if (io_again_p(e)) {
1241  if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1242  return -1;
1243  }
1244  else {
1245  goto retry;
1246  }
1247  }
1248  }
1249 
1250  return result;
1251 }
1252 
1253 #ifdef HAVE_WRITEV
1254 static VALUE
1255 internal_writev_func(void *ptr)
1256 {
1257  struct io_internal_writev_struct *iis = ptr;
1258  ssize_t result;
1259 
1260  if (iis->timeout && !iis->nonblock) {
1261  if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1262  return -1;
1263  }
1264  }
1265 
1266  retry:
1267  do_write_retry(writev(iis->fd, iis->iov, iis->iovcnt));
1268 
1269  if (result < 0 && !iis->nonblock) {
1270  if (io_again_p(errno)) {
1271  if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1272  return -1;
1273  }
1274  else {
1275  goto retry;
1276  }
1277  }
1278  }
1279 
1280  return result;
1281 }
1282 #endif
1283 
1284 static ssize_t
1285 rb_io_read_memory(rb_io_t *fptr, void *buf, size_t count)
1286 {
1287  VALUE scheduler = rb_fiber_scheduler_current();
1288  if (scheduler != Qnil) {
1289  VALUE result = rb_fiber_scheduler_io_read_memory(scheduler, fptr->self, buf, count, 0);
1290 
1291  if (!UNDEF_P(result)) {
1292  return rb_fiber_scheduler_io_result_apply(result);
1293  }
1294  }
1295 
1296  struct io_internal_read_struct iis = {
1297  .th = rb_thread_current(),
1298  .fptr = fptr,
1299  .nonblock = 0,
1300  .fd = fptr->fd,
1301 
1302  .buf = buf,
1303  .capa = count,
1304  .timeout = NULL,
1305  };
1306 
1307  struct timeval timeout_storage;
1308 
1309  if (fptr->timeout != Qnil) {
1310  timeout_storage = rb_time_interval(fptr->timeout);
1311  iis.timeout = &timeout_storage;
1312  }
1313 
1314  return (ssize_t)rb_io_blocking_region_wait(fptr, internal_read_func, &iis, RUBY_IO_READABLE);
1315 }
1316 
1317 static ssize_t
1318 rb_io_write_memory(rb_io_t *fptr, const void *buf, size_t count)
1319 {
1320  VALUE scheduler = rb_fiber_scheduler_current();
1321  if (scheduler != Qnil) {
1322  VALUE result = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, buf, count, 0);
1323 
1324  if (!UNDEF_P(result)) {
1325  return rb_fiber_scheduler_io_result_apply(result);
1326  }
1327  }
1328 
1329  struct io_internal_write_struct iis = {
1330  .th = rb_thread_current(),
1331  .fptr = fptr,
1332  .nonblock = 0,
1333  .fd = fptr->fd,
1334 
1335  .buf = buf,
1336  .capa = count,
1337  .timeout = NULL
1338  };
1339 
1340  struct timeval timeout_storage;
1341 
1342  if (fptr->timeout != Qnil) {
1343  timeout_storage = rb_time_interval(fptr->timeout);
1344  iis.timeout = &timeout_storage;
1345  }
1346 
1347  return (ssize_t)rb_io_blocking_region_wait(fptr, internal_write_func, &iis, RUBY_IO_WRITABLE);
1348 }
1349 
1350 #ifdef HAVE_WRITEV
1351 static ssize_t
1352 rb_writev_internal(rb_io_t *fptr, const struct iovec *iov, int iovcnt)
1353 {
1354  if (!iovcnt) return 0;
1355 
1356  VALUE scheduler = rb_fiber_scheduler_current();
1357  if (scheduler != Qnil) {
1358  // This path assumes at least one `iov`:
1359  VALUE result = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, iov[0].iov_base, iov[0].iov_len, 0);
1360 
1361  if (!UNDEF_P(result)) {
1362  return rb_fiber_scheduler_io_result_apply(result);
1363  }
1364  }
1365 
1366  struct io_internal_writev_struct iis = {
1367  .th = rb_thread_current(),
1368  .fptr = fptr,
1369  .nonblock = 0,
1370  .fd = fptr->fd,
1371 
1372  .iov = iov,
1373  .iovcnt = iovcnt,
1374  .timeout = NULL
1375  };
1376 
1377  struct timeval timeout_storage;
1378 
1379  if (fptr->timeout != Qnil) {
1380  timeout_storage = rb_time_interval(fptr->timeout);
1381  iis.timeout = &timeout_storage;
1382  }
1383 
1384  return (ssize_t)rb_io_blocking_region_wait(fptr, internal_writev_func, &iis, RUBY_IO_WRITABLE);
1385 }
1386 #endif
1387 
1388 static VALUE
1389 io_flush_buffer_sync(void *arg)
1390 {
1391  rb_io_t *fptr = arg;
1392  long l = fptr->wbuf.len;
1393  ssize_t r = write(fptr->fd, fptr->wbuf.ptr+fptr->wbuf.off, (size_t)l);
1394 
1395  if (fptr->wbuf.len <= r) {
1396  fptr->wbuf.off = 0;
1397  fptr->wbuf.len = 0;
1398  return 0;
1399  }
1400 
1401  if (0 <= r) {
1402  fptr->wbuf.off += (int)r;
1403  fptr->wbuf.len -= (int)r;
1404  errno = EAGAIN;
1405  }
1406 
1407  return (VALUE)-1;
1408 }
1409 
1410 static VALUE
1411 io_flush_buffer_async(VALUE arg)
1412 {
1413  rb_io_t *fptr = (rb_io_t *)arg;
1414  return rb_io_blocking_region_wait(fptr, io_flush_buffer_sync, fptr, RUBY_IO_WRITABLE);
1415 }
1416 
1417 static inline int
1418 io_flush_buffer(rb_io_t *fptr)
1419 {
1420  if (!NIL_P(fptr->write_lock) && rb_mutex_owned_p(fptr->write_lock)) {
1421  return (int)io_flush_buffer_async((VALUE)fptr);
1422  }
1423  else {
1424  return (int)rb_mutex_synchronize(fptr->write_lock, io_flush_buffer_async, (VALUE)fptr);
1425  }
1426 }
1427 
1428 static int
1429 io_fflush(rb_io_t *fptr)
1430 {
1431  rb_io_check_closed(fptr);
1432 
1433  if (fptr->wbuf.len == 0)
1434  return 0;
1435 
1436  while (fptr->wbuf.len > 0 && io_flush_buffer(fptr) != 0) {
1437  if (!rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT))
1438  return -1;
1439 
1440  rb_io_check_closed(fptr);
1441  }
1442 
1443  return 0;
1444 }
1445 
1446 VALUE
1447 rb_io_wait(VALUE io, VALUE events, VALUE timeout)
1448 {
1449  VALUE scheduler = rb_fiber_scheduler_current();
1450 
1451  if (scheduler != Qnil) {
1452  return rb_fiber_scheduler_io_wait(scheduler, io, events, timeout);
1453  }
1454 
1455  rb_io_t * fptr = NULL;
1456  RB_IO_POINTER(io, fptr);
1457 
1458  struct timeval tv_storage;
1459  struct timeval *tv = NULL;
1460 
1461  if (NIL_OR_UNDEF_P(timeout)) {
1462  timeout = fptr->timeout;
1463  }
1464 
1465  if (timeout != Qnil) {
1466  tv_storage = rb_time_interval(timeout);
1467  tv = &tv_storage;
1468  }
1469 
1470  int ready = rb_thread_wait_for_single_fd(fptr->fd, RB_NUM2INT(events), tv);
1471 
1472  if (ready < 0) {
1473  rb_sys_fail(0);
1474  }
1475 
1476  // Not sure if this is necessary:
1477  rb_io_check_closed(fptr);
1478 
1479  if (ready) {
1480  return RB_INT2NUM(ready);
1481  }
1482  else {
1483  return Qfalse;
1484  }
1485 }
1486 
1487 static VALUE
1488 io_from_fd(int fd)
1489 {
1490  return prep_io(fd, FMODE_EXTERNAL, rb_cIO, NULL);
1491 }
1492 
1493 static int
1494 io_wait_for_single_fd(int fd, int events, struct timeval *timeout)
1495 {
1496  VALUE scheduler = rb_fiber_scheduler_current();
1497 
1498  if (scheduler != Qnil) {
1499  return RTEST(
1500  rb_fiber_scheduler_io_wait(scheduler, io_from_fd(fd), RB_INT2NUM(events), rb_fiber_scheduler_make_timeout(timeout))
1501  );
1502  }
1503 
1504  return rb_thread_wait_for_single_fd(fd, events, timeout);
1505 }
1506 
1507 int
1509 {
1510  io_fd_check_closed(f);
1511 
1512  VALUE scheduler = rb_fiber_scheduler_current();
1513 
1514  switch (errno) {
1515  case EINTR:
1516 #if defined(ERESTART)
1517  case ERESTART:
1518 #endif
1520  return TRUE;
1521 
1522  case EAGAIN:
1523 #if EWOULDBLOCK != EAGAIN
1524  case EWOULDBLOCK:
1525 #endif
1526  if (scheduler != Qnil) {
1527  return RTEST(
1528  rb_fiber_scheduler_io_wait_readable(scheduler, io_from_fd(f))
1529  );
1530  }
1531  else {
1532  io_wait_for_single_fd(f, RUBY_IO_READABLE, NULL);
1533  }
1534  return TRUE;
1535 
1536  default:
1537  return FALSE;
1538  }
1539 }
1540 
1541 int
1543 {
1544  io_fd_check_closed(f);
1545 
1546  VALUE scheduler = rb_fiber_scheduler_current();
1547 
1548  switch (errno) {
1549  case EINTR:
1550 #if defined(ERESTART)
1551  case ERESTART:
1552 #endif
1553  /*
1554  * In old Linux, several special files under /proc and /sys don't handle
1555  * select properly. Thus we need avoid to call if don't use O_NONBLOCK.
1556  * Otherwise, we face nasty hang up. Sigh.
1557  * e.g. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1558  * https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1559  * In EINTR case, we only need to call RUBY_VM_CHECK_INTS_BLOCKING().
1560  * Then rb_thread_check_ints() is enough.
1561  */
1563  return TRUE;
1564 
1565  case EAGAIN:
1566 #if EWOULDBLOCK != EAGAIN
1567  case EWOULDBLOCK:
1568 #endif
1569  if (scheduler != Qnil) {
1570  return RTEST(
1571  rb_fiber_scheduler_io_wait_writable(scheduler, io_from_fd(f))
1572  );
1573  }
1574  else {
1575  io_wait_for_single_fd(f, RUBY_IO_WRITABLE, NULL);
1576  }
1577  return TRUE;
1578 
1579  default:
1580  return FALSE;
1581  }
1582 }
1583 
1584 int
1585 rb_wait_for_single_fd(int fd, int events, struct timeval *timeout)
1586 {
1587  return io_wait_for_single_fd(fd, events, timeout);
1588 }
1589 
1590 int
1592 {
1593  return rb_wait_for_single_fd(fd, RUBY_IO_READABLE, NULL);
1594 }
1595 
1596 int
1598 {
1599  return rb_wait_for_single_fd(fd, RUBY_IO_WRITABLE, NULL);
1600 }
1601 
1602 VALUE
1603 rb_io_maybe_wait(int error, VALUE io, VALUE events, VALUE timeout)
1604 {
1605  // fptr->fd can be set to -1 at any time by another thread when the GVL is
1606  // released. Many code, e.g. `io_bufread` didn't check this correctly and
1607  // instead relies on `read(-1) -> -1` which causes this code path. We then
1608  // check here whether the IO was in fact closed. Probably it's better to
1609  // check that `fptr->fd != -1` before using it in syscall.
1610  rb_io_check_closed(RFILE(io)->fptr);
1611 
1612  switch (error) {
1613  // In old Linux, several special files under /proc and /sys don't handle
1614  // select properly. Thus we need avoid to call if don't use O_NONBLOCK.
1615  // Otherwise, we face nasty hang up. Sigh.
1616  // e.g. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1617  // https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1618  // In EINTR case, we only need to call RUBY_VM_CHECK_INTS_BLOCKING().
1619  // Then rb_thread_check_ints() is enough.
1620  case EINTR:
1621 #if defined(ERESTART)
1622  case ERESTART:
1623 #endif
1624  // We might have pending interrupts since the previous syscall was interrupted:
1626 
1627  // The operation was interrupted, so retry it immediately:
1628  return events;
1629 
1630  case EAGAIN:
1631 #if EWOULDBLOCK != EAGAIN
1632  case EWOULDBLOCK:
1633 #endif
1634  // The operation would block, so wait for the specified events:
1635  return rb_io_wait(io, events, timeout);
1636 
1637  default:
1638  // Non-specific error, no event is ready:
1639  return Qnil;
1640  }
1641 }
1642 
1643 int
1644 rb_io_maybe_wait_readable(int error, VALUE io, VALUE timeout)
1645 {
1646  VALUE result = rb_io_maybe_wait(error, io, RB_INT2NUM(RUBY_IO_READABLE), timeout);
1647 
1648  if (RTEST(result)) {
1649  return RB_NUM2INT(result);
1650  }
1651  else if (result == RUBY_Qfalse) {
1652  rb_raise(rb_eIOTimeoutError, "Timed out waiting for IO to become readable!");
1653  }
1654 
1655  return 0;
1656 }
1657 
1658 int
1659 rb_io_maybe_wait_writable(int error, VALUE io, VALUE timeout)
1660 {
1661  VALUE result = rb_io_maybe_wait(error, io, RB_INT2NUM(RUBY_IO_WRITABLE), timeout);
1662 
1663  if (RTEST(result)) {
1664  return RB_NUM2INT(result);
1665  }
1666  else if (result == RUBY_Qfalse) {
1667  rb_raise(rb_eIOTimeoutError, "Timed out waiting for IO to become writable!");
1668  }
1669 
1670  return 0;
1671 }
1672 
1673 static void
1674 make_writeconv(rb_io_t *fptr)
1675 {
1676  if (!fptr->writeconv_initialized) {
1677  const char *senc, *denc;
1678  rb_encoding *enc;
1679  int ecflags;
1680  VALUE ecopts;
1681 
1682  fptr->writeconv_initialized = 1;
1683 
1684  ecflags = fptr->encs.ecflags & ~ECONV_NEWLINE_DECORATOR_READ_MASK;
1685  ecopts = fptr->encs.ecopts;
1686 
1687  if (!fptr->encs.enc || (rb_is_ascii8bit_enc(fptr->encs.enc) && !fptr->encs.enc2)) {
1688  /* no encoding conversion */
1689  fptr->writeconv_pre_ecflags = 0;
1690  fptr->writeconv_pre_ecopts = Qnil;
1691  fptr->writeconv = rb_econv_open_opts("", "", ecflags, ecopts);
1692  if (!fptr->writeconv)
1693  rb_exc_raise(rb_econv_open_exc("", "", ecflags));
1694  fptr->writeconv_asciicompat = Qnil;
1695  }
1696  else {
1697  enc = fptr->encs.enc2 ? fptr->encs.enc2 : fptr->encs.enc;
1699  if (!senc && !(fptr->encs.ecflags & ECONV_STATEFUL_DECORATOR_MASK)) {
1700  /* single conversion */
1701  fptr->writeconv_pre_ecflags = ecflags;
1702  fptr->writeconv_pre_ecopts = ecopts;
1703  fptr->writeconv = NULL;
1704  fptr->writeconv_asciicompat = Qnil;
1705  }
1706  else {
1707  /* double conversion */
1709  fptr->writeconv_pre_ecopts = ecopts;
1710  if (senc) {
1711  denc = rb_enc_name(enc);
1712  fptr->writeconv_asciicompat = rb_str_new2(senc);
1713  }
1714  else {
1715  senc = denc = "";
1717  }
1719  ecopts = fptr->encs.ecopts;
1720  fptr->writeconv = rb_econv_open_opts(senc, denc, ecflags, ecopts);
1721  if (!fptr->writeconv)
1722  rb_exc_raise(rb_econv_open_exc(senc, denc, ecflags));
1723  }
1724  }
1725  }
1726 }
1727 
1728 /* writing functions */
1730  rb_io_t *fptr;
1731  const char *ptr;
1732  long length;
1733 };
1734 
1735 struct write_arg {
1736  VALUE io;
1737  VALUE str;
1738  int nosync;
1739 };
1740 
1741 #ifdef HAVE_WRITEV
1742 static ssize_t
1743 io_binwrite_string_internal(rb_io_t *fptr, const char *ptr, long length)
1744 {
1745  if (fptr->wbuf.len) {
1746  struct iovec iov[2];
1747 
1748  iov[0].iov_base = fptr->wbuf.ptr+fptr->wbuf.off;
1749  iov[0].iov_len = fptr->wbuf.len;
1750  iov[1].iov_base = (void*)ptr;
1751  iov[1].iov_len = length;
1752 
1753  ssize_t result = rb_writev_internal(fptr, iov, 2);
1754 
1755  if (result < 0)
1756  return result;
1757 
1758  if (result >= fptr->wbuf.len) {
1759  // We wrote more than the internal buffer:
1760  result -= fptr->wbuf.len;
1761  fptr->wbuf.off = 0;
1762  fptr->wbuf.len = 0;
1763  }
1764  else {
1765  // We only wrote less data than the internal buffer:
1766  fptr->wbuf.off += (int)result;
1767  fptr->wbuf.len -= (int)result;
1768 
1769  result = 0;
1770  }
1771 
1772  return result;
1773  }
1774  else {
1775  return rb_io_write_memory(fptr, ptr, length);
1776  }
1777 }
1778 #else
1779 static ssize_t
1780 io_binwrite_string_internal(rb_io_t *fptr, const char *ptr, long length)
1781 {
1782  long remaining = length;
1783 
1784  if (fptr->wbuf.len) {
1785  if (fptr->wbuf.len+length <= fptr->wbuf.capa) {
1786  if (fptr->wbuf.capa < fptr->wbuf.off+fptr->wbuf.len+length) {
1787  MEMMOVE(fptr->wbuf.ptr, fptr->wbuf.ptr+fptr->wbuf.off, char, fptr->wbuf.len);
1788  fptr->wbuf.off = 0;
1789  }
1790 
1791  MEMMOVE(fptr->wbuf.ptr+fptr->wbuf.off+fptr->wbuf.len, ptr, char, length);
1792  fptr->wbuf.len += (int)length;
1793 
1794  // We copied the entire incoming data to the internal buffer:
1795  remaining = 0;
1796  }
1797 
1798  // Flush the internal buffer:
1799  if (io_fflush(fptr) < 0) {
1800  return -1;
1801  }
1802 
1803  // If all the data was buffered, we are done:
1804  if (remaining == 0) {
1805  return length;
1806  }
1807  }
1808 
1809  // Otherwise, we should write the data directly:
1810  return rb_io_write_memory(fptr, ptr, length);
1811 }
1812 #endif
1813 
1814 static VALUE
1815 io_binwrite_string(VALUE arg)
1816 {
1817  struct binwrite_arg *p = (struct binwrite_arg *)arg;
1818 
1819  const char *ptr = p->ptr;
1820  size_t remaining = p->length;
1821 
1822  while (remaining) {
1823  // Write as much as possible:
1824  ssize_t result = io_binwrite_string_internal(p->fptr, ptr, remaining);
1825 
1826  if (result == 0) {
1827  // If only the internal buffer is written, result will be zero [bytes of given data written]. This means we
1828  // should try again immediately.
1829  }
1830  else if (result > 0) {
1831  if ((size_t)result == remaining) break;
1832  ptr += result;
1833  remaining -= result;
1834  }
1835  // Wait for it to become writable:
1836  else if (rb_io_maybe_wait_writable(errno, p->fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
1837  rb_io_check_closed(p->fptr);
1838  }
1839  else {
1840  // The error was unrelated to waiting for it to become writable, so we fail:
1841  return -1;
1842  }
1843  }
1844 
1845  return p->length;
1846 }
1847 
1848 inline static void
1849 io_allocate_write_buffer(rb_io_t *fptr, int sync)
1850 {
1851  if (fptr->wbuf.ptr == NULL && !(sync && (fptr->mode & FMODE_SYNC))) {
1852  fptr->wbuf.off = 0;
1853  fptr->wbuf.len = 0;
1854  fptr->wbuf.capa = IO_WBUF_CAPA_MIN;
1855  fptr->wbuf.ptr = ALLOC_N(char, fptr->wbuf.capa);
1856  }
1857 
1858  if (NIL_P(fptr->write_lock)) {
1859  fptr->write_lock = rb_mutex_new();
1860  rb_mutex_allow_trap(fptr->write_lock, 1);
1861  }
1862 }
1863 
1864 static inline int
1865 io_binwrite_requires_flush_write(rb_io_t *fptr, long len, int nosync)
1866 {
1867  // If the requested operation was synchronous and the output mode is synchronous or a TTY:
1868  if (!nosync && (fptr->mode & (FMODE_SYNC|FMODE_TTY)))
1869  return 1;
1870 
1871  // If the amount of data we want to write exceeds the internal buffer:
1872  if (fptr->wbuf.ptr && fptr->wbuf.capa <= fptr->wbuf.len + len)
1873  return 1;
1874 
1875  // Otherwise, we can append to the internal buffer:
1876  return 0;
1877 }
1878 
1879 static long
1880 io_binwrite(const char *ptr, long len, rb_io_t *fptr, int nosync)
1881 {
1882  if (len <= 0) return len;
1883 
1884  // Don't write anything if current thread has a pending interrupt:
1886 
1887  io_allocate_write_buffer(fptr, !nosync);
1888 
1889  if (io_binwrite_requires_flush_write(fptr, len, nosync)) {
1890  struct binwrite_arg arg;
1891 
1892  arg.fptr = fptr;
1893  arg.ptr = ptr;
1894  arg.length = len;
1895 
1896  if (!NIL_P(fptr->write_lock)) {
1897  return rb_mutex_synchronize(fptr->write_lock, io_binwrite_string, (VALUE)&arg);
1898  }
1899  else {
1900  return io_binwrite_string((VALUE)&arg);
1901  }
1902  }
1903  else {
1904  if (fptr->wbuf.off) {
1905  if (fptr->wbuf.len)
1906  MEMMOVE(fptr->wbuf.ptr, fptr->wbuf.ptr+fptr->wbuf.off, char, fptr->wbuf.len);
1907  fptr->wbuf.off = 0;
1908  }
1909 
1910  MEMMOVE(fptr->wbuf.ptr+fptr->wbuf.off+fptr->wbuf.len, ptr, char, len);
1911  fptr->wbuf.len += (int)len;
1912 
1913  return len;
1914  }
1915 }
1916 
1917 # define MODE_BTMODE(a,b,c) ((fmode & FMODE_BINMODE) ? (b) : \
1918  (fmode & FMODE_TEXTMODE) ? (c) : (a))
1919 
1920 #define MODE_BTXMODE(a, b, c, d, e, f) ((fmode & FMODE_EXCL) ? \
1921  MODE_BTMODE(d, e, f) : \
1922  MODE_BTMODE(a, b, c))
1923 
1924 static VALUE
1925 do_writeconv(VALUE str, rb_io_t *fptr, int *converted)
1926 {
1927  if (NEED_WRITECONV(fptr)) {
1928  VALUE common_encoding = Qnil;
1929  SET_BINARY_MODE(fptr);
1930 
1931  make_writeconv(fptr);
1932 
1933  if (fptr->writeconv) {
1934 #define fmode (fptr->mode)
1935  if (!NIL_P(fptr->writeconv_asciicompat))
1936  common_encoding = fptr->writeconv_asciicompat;
1937  else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1) && !rb_enc_asciicompat(rb_enc_get(str))) {
1938  rb_raise(rb_eArgError, "ASCII incompatible string written for text mode IO without encoding conversion: %s",
1939  rb_enc_name(rb_enc_get(str)));
1940  }
1941 #undef fmode
1942  }
1943  else {
1944  if (fptr->encs.enc2)
1945  common_encoding = rb_enc_from_encoding(fptr->encs.enc2);
1946  else if (fptr->encs.enc != rb_ascii8bit_encoding())
1947  common_encoding = rb_enc_from_encoding(fptr->encs.enc);
1948  }
1949 
1950  if (!NIL_P(common_encoding)) {
1951  str = rb_str_encode(str, common_encoding,
1953  *converted = 1;
1954  }
1955 
1956  if (fptr->writeconv) {
1958  *converted = 1;
1959  }
1960  }
1961 #if RUBY_CRLF_ENVIRONMENT
1962 #define fmode (fptr->mode)
1963  else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1)) {
1964  if ((fptr->mode & FMODE_READABLE) &&
1966  setmode(fptr->fd, O_BINARY);
1967  }
1968  else {
1969  setmode(fptr->fd, O_TEXT);
1970  }
1971  if (!rb_enc_asciicompat(rb_enc_get(str))) {
1972  rb_raise(rb_eArgError, "ASCII incompatible string written for text mode IO without encoding conversion: %s",
1973  rb_enc_name(rb_enc_get(str)));
1974  }
1975  }
1976 #undef fmode
1977 #endif
1978  return str;
1979 }
1980 
1981 static long
1982 io_fwrite(VALUE str, rb_io_t *fptr, int nosync)
1983 {
1984  int converted = 0;
1985  VALUE tmp;
1986  long n, len;
1987  const char *ptr;
1988 
1989 #ifdef _WIN32
1990  if (fptr->mode & FMODE_TTY) {
1991  long len = rb_w32_write_console(str, fptr->fd);
1992  if (len > 0) return len;
1993  }
1994 #endif
1995 
1996  str = do_writeconv(str, fptr, &converted);
1997  if (converted)
1998  OBJ_FREEZE(str);
1999 
2000  tmp = rb_str_tmp_frozen_no_embed_acquire(str);
2001  RSTRING_GETMEM(tmp, ptr, len);
2002  n = io_binwrite(ptr, len, fptr, nosync);
2003  rb_str_tmp_frozen_release(str, tmp);
2004 
2005  return n;
2006 }
2007 
2008 ssize_t
2009 rb_io_bufwrite(VALUE io, const void *buf, size_t size)
2010 {
2011  rb_io_t *fptr;
2012 
2013  GetOpenFile(io, fptr);
2014  rb_io_check_writable(fptr);
2015  return (ssize_t)io_binwrite(buf, (long)size, fptr, 0);
2016 }
2017 
2018 static VALUE
2019 io_write(VALUE io, VALUE str, int nosync)
2020 {
2021  rb_io_t *fptr;
2022  long n;
2023  VALUE tmp;
2024 
2025  io = GetWriteIO(io);
2026  str = rb_obj_as_string(str);
2027  tmp = rb_io_check_io(io);
2028 
2029  if (NIL_P(tmp)) {
2030  /* port is not IO, call write method for it. */
2031  return rb_funcall(io, id_write, 1, str);
2032  }
2033 
2034  io = tmp;
2035  if (RSTRING_LEN(str) == 0) return INT2FIX(0);
2036 
2037  GetOpenFile(io, fptr);
2038  rb_io_check_writable(fptr);
2039 
2040  n = io_fwrite(str, fptr, nosync);
2041  if (n < 0L) rb_sys_fail_on_write(fptr);
2042 
2043  return LONG2FIX(n);
2044 }
2045 
2046 #ifdef HAVE_WRITEV
2047 struct binwritev_arg {
2048  rb_io_t *fptr;
2049  struct iovec *iov;
2050  int iovcnt;
2051  size_t total;
2052 };
2053 
2054 static VALUE
2055 io_binwritev_internal(VALUE arg)
2056 {
2057  struct binwritev_arg *p = (struct binwritev_arg *)arg;
2058 
2059  size_t remaining = p->total;
2060  size_t offset = 0;
2061 
2062  rb_io_t *fptr = p->fptr;
2063  struct iovec *iov = p->iov;
2064  int iovcnt = p->iovcnt;
2065 
2066  while (remaining) {
2067  long result = rb_writev_internal(fptr, iov, iovcnt);
2068 
2069  if (result >= 0) {
2070  offset += result;
2071  if (fptr->wbuf.ptr && fptr->wbuf.len) {
2072  if (offset < (size_t)fptr->wbuf.len) {
2073  fptr->wbuf.off += result;
2074  fptr->wbuf.len -= result;
2075  }
2076  else {
2077  offset -= (size_t)fptr->wbuf.len;
2078  fptr->wbuf.off = 0;
2079  fptr->wbuf.len = 0;
2080  }
2081  }
2082 
2083  if (offset == p->total) {
2084  return p->total;
2085  }
2086 
2087  while (result >= (ssize_t)iov->iov_len) {
2088  /* iovcnt > 0 */
2089  result -= iov->iov_len;
2090  iov->iov_len = 0;
2091  iov++;
2092 
2093  if (!--iovcnt) {
2094  // I don't believe this code path can ever occur.
2095  return offset;
2096  }
2097  }
2098 
2099  iov->iov_base = (char *)iov->iov_base + result;
2100  iov->iov_len -= result;
2101  }
2102  else if (rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
2103  rb_io_check_closed(fptr);
2104  }
2105  else {
2106  return -1;
2107  }
2108  }
2109 
2110  return offset;
2111 }
2112 
2113 static long
2114 io_binwritev(struct iovec *iov, int iovcnt, rb_io_t *fptr)
2115 {
2116  // Don't write anything if current thread has a pending interrupt:
2118 
2119  if (iovcnt == 0) return 0;
2120 
2121  size_t total = 0;
2122  for (int i = 1; i < iovcnt; i++) total += iov[i].iov_len;
2123 
2124  io_allocate_write_buffer(fptr, 1);
2125 
2126  if (fptr->wbuf.ptr && fptr->wbuf.len) {
2127  // The end of the buffered data:
2128  size_t offset = fptr->wbuf.off + fptr->wbuf.len;
2129 
2130  if (offset + total <= (size_t)fptr->wbuf.capa) {
2131  for (int i = 1; i < iovcnt; i++) {
2132  memcpy(fptr->wbuf.ptr+offset, iov[i].iov_base, iov[i].iov_len);
2133  offset += iov[i].iov_len;
2134  }
2135 
2136  fptr->wbuf.len += total;
2137 
2138  return total;
2139  }
2140  else {
2141  iov[0].iov_base = fptr->wbuf.ptr + fptr->wbuf.off;
2142  iov[0].iov_len = fptr->wbuf.len;
2143  }
2144  }
2145  else {
2146  // The first iov is reserved for the internal buffer, and it's empty.
2147  iov++;
2148 
2149  if (!--iovcnt) {
2150  // If there are no other io vectors we are done.
2151  return 0;
2152  }
2153  }
2154 
2155  struct binwritev_arg arg;
2156  arg.fptr = fptr;
2157  arg.iov = iov;
2158  arg.iovcnt = iovcnt;
2159  arg.total = total;
2160 
2161  if (!NIL_P(fptr->write_lock)) {
2162  return rb_mutex_synchronize(fptr->write_lock, io_binwritev_internal, (VALUE)&arg);
2163  }
2164  else {
2165  return io_binwritev_internal((VALUE)&arg);
2166  }
2167 }
2168 
2169 static long
2170 io_fwritev(int argc, const VALUE *argv, rb_io_t *fptr)
2171 {
2172  int i, converted, iovcnt = argc + 1;
2173  long n;
2174  VALUE v1, v2, str, tmp, *tmp_array;
2175  struct iovec *iov;
2176 
2177  iov = ALLOCV_N(struct iovec, v1, iovcnt);
2178  tmp_array = ALLOCV_N(VALUE, v2, argc);
2179 
2180  for (i = 0; i < argc; i++) {
2181  str = rb_obj_as_string(argv[i]);
2182  converted = 0;
2183  str = do_writeconv(str, fptr, &converted);
2184 
2185  if (converted)
2186  OBJ_FREEZE(str);
2187 
2188  tmp = rb_str_tmp_frozen_acquire(str);
2189  tmp_array[i] = tmp;
2190 
2191  /* iov[0] is reserved for buffer of fptr */
2192  iov[i+1].iov_base = RSTRING_PTR(tmp);
2193  iov[i+1].iov_len = RSTRING_LEN(tmp);
2194  }
2195 
2196  n = io_binwritev(iov, iovcnt, fptr);
2197  if (v1) ALLOCV_END(v1);
2198 
2199  for (i = 0; i < argc; i++) {
2200  rb_str_tmp_frozen_release(argv[i], tmp_array[i]);
2201  }
2202 
2203  if (v2) ALLOCV_END(v2);
2204 
2205  return n;
2206 }
2207 
2208 static int
2209 iovcnt_ok(int iovcnt)
2210 {
2211 #ifdef IOV_MAX
2212  return iovcnt < IOV_MAX;
2213 #else /* GNU/Hurd has writev, but no IOV_MAX */
2214  return 1;
2215 #endif
2216 }
2217 #endif /* HAVE_WRITEV */
2218 
2219 static VALUE
2220 io_writev(int argc, const VALUE *argv, VALUE io)
2221 {
2222  rb_io_t *fptr;
2223  long n;
2224  VALUE tmp, total = INT2FIX(0);
2225  int i, cnt = 1;
2226 
2227  io = GetWriteIO(io);
2228  tmp = rb_io_check_io(io);
2229 
2230  if (NIL_P(tmp)) {
2231  /* port is not IO, call write method for it. */
2232  return rb_funcallv(io, id_write, argc, argv);
2233  }
2234 
2235  io = tmp;
2236 
2237  GetOpenFile(io, fptr);
2238  rb_io_check_writable(fptr);
2239 
2240  for (i = 0; i < argc; i += cnt) {
2241 #ifdef HAVE_WRITEV
2242  if ((fptr->mode & (FMODE_SYNC|FMODE_TTY)) && iovcnt_ok(cnt = argc - i)) {
2243  n = io_fwritev(cnt, &argv[i], fptr);
2244  }
2245  else
2246 #endif
2247  {
2248  cnt = 1;
2249  /* sync at last item */
2250  n = io_fwrite(rb_obj_as_string(argv[i]), fptr, (i < argc-1));
2251  }
2252 
2253  if (n < 0L)
2254  rb_sys_fail_on_write(fptr);
2255 
2256  total = rb_fix_plus(LONG2FIX(n), total);
2257  }
2258 
2259  return total;
2260 }
2261 
2262 /*
2263  * call-seq:
2264  * write(*objects) -> integer
2265  *
2266  * Writes each of the given +objects+ to +self+,
2267  * which must be opened for writing
2268  * (see {Access Modes}[rdoc-ref:File@Access+Modes]);
2269  * returns the total number bytes written;
2270  * each of +objects+ that is not a string is converted via method +to_s+:
2271  *
2272  * $stdout.write('Hello', ', ', 'World!', "\n") # => 14
2273  * $stdout.write('foo', :bar, 2, "\n") # => 8
2274  *
2275  * Output:
2276  *
2277  * Hello, World!
2278  * foobar2
2279  *
2280  * Related: IO#read.
2281  */
2282 
2283 static VALUE
2284 io_write_m(int argc, VALUE *argv, VALUE io)
2285 {
2286  if (argc != 1) {
2287  return io_writev(argc, argv, io);
2288  }
2289  else {
2290  VALUE str = argv[0];
2291  return io_write(io, str, 0);
2292  }
2293 }
2294 
2295 VALUE
2297 {
2298  return rb_funcallv(io, id_write, 1, &str);
2299 }
2300 
2301 static VALUE
2302 rb_io_writev(VALUE io, int argc, const VALUE *argv)
2303 {
2304  if (argc > 1 && rb_obj_method_arity(io, id_write) == 1) {
2305  if (io != rb_ractor_stderr() && RTEST(ruby_verbose)) {
2306  VALUE klass = CLASS_OF(io);
2307  char sep = RCLASS_SINGLETON_P(klass) ? (klass = io, '.') : '#';
2309  RB_WARN_CATEGORY_DEPRECATED, "%+"PRIsVALUE"%c""write is outdated interface"
2310  " which accepts just one argument",
2311  klass, sep
2312  );
2313  }
2314 
2315  do rb_io_write(io, *argv++); while (--argc);
2316 
2317  return Qnil;
2318  }
2319 
2320  return rb_funcallv(io, id_write, argc, argv);
2321 }
2322 
2323 /*
2324  * call-seq:
2325  * self << object -> self
2326  *
2327  * Writes the given +object+ to +self+,
2328  * which must be opened for writing (see {Access Modes}[rdoc-ref:File@Access+Modes]);
2329  * returns +self+;
2330  * if +object+ is not a string, it is converted via method +to_s+:
2331  *
2332  * $stdout << 'Hello' << ', ' << 'World!' << "\n"
2333  * $stdout << 'foo' << :bar << 2 << "\n"
2334  *
2335  * Output:
2336  *
2337  * Hello, World!
2338  * foobar2
2339  *
2340  */
2341 
2342 
2343 VALUE
2345 {
2346  rb_io_write(io, str);
2347  return io;
2348 }
2349 
2350 #ifdef HAVE_FSYNC
2351 static VALUE
2352 nogvl_fsync(void *ptr)
2353 {
2354  rb_io_t *fptr = ptr;
2355 
2356 #ifdef _WIN32
2357  if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->fd)) != FILE_TYPE_DISK)
2358  return 0;
2359 #endif
2360  return (VALUE)fsync(fptr->fd);
2361 }
2362 #endif
2363 
2364 VALUE
2365 rb_io_flush_raw(VALUE io, int sync)
2366 {
2367  rb_io_t *fptr;
2368 
2369  if (!RB_TYPE_P(io, T_FILE)) {
2370  return rb_funcall(io, id_flush, 0);
2371  }
2372 
2373  io = GetWriteIO(io);
2374  GetOpenFile(io, fptr);
2375 
2376  if (fptr->mode & FMODE_WRITABLE) {
2377  if (io_fflush(fptr) < 0)
2378  rb_sys_fail_on_write(fptr);
2379  }
2380  if (fptr->mode & FMODE_READABLE) {
2381  io_unread(fptr, true);
2382  }
2383 
2384  return io;
2385 }
2386 
2387 /*
2388  * call-seq:
2389  * flush -> self
2390  *
2391  * Flushes data buffered in +self+ to the operating system
2392  * (but does not necessarily flush data buffered in the operating system):
2393  *
2394  * $stdout.print 'no newline' # Not necessarily flushed.
2395  * $stdout.flush # Flushed.
2396  *
2397  */
2398 
2399 VALUE
2401 {
2402  return rb_io_flush_raw(io, 1);
2403 }
2404 
2405 /*
2406  * call-seq:
2407  * tell -> integer
2408  *
2409  * Returns the current position (in bytes) in +self+
2410  * (see {Position}[rdoc-ref:IO@Position]):
2411  *
2412  * f = File.open('t.txt')
2413  * f.tell # => 0
2414  * f.gets # => "First line\n"
2415  * f.tell # => 12
2416  * f.close
2417  *
2418  * Related: IO#pos=, IO#seek.
2419  */
2420 
2421 static VALUE
2422 rb_io_tell(VALUE io)
2423 {
2424  rb_io_t *fptr;
2425  rb_off_t pos;
2426 
2427  GetOpenFile(io, fptr);
2428  pos = io_tell(fptr);
2429  if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2430  pos -= fptr->rbuf.len;
2431  return OFFT2NUM(pos);
2432 }
2433 
2434 static VALUE
2435 rb_io_seek(VALUE io, VALUE offset, int whence)
2436 {
2437  rb_io_t *fptr;
2438  rb_off_t pos;
2439 
2440  pos = NUM2OFFT(offset);
2441  GetOpenFile(io, fptr);
2442  pos = io_seek(fptr, pos, whence);
2443  if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2444 
2445  return INT2FIX(0);
2446 }
2447 
2448 static int
2449 interpret_seek_whence(VALUE vwhence)
2450 {
2451  if (vwhence == sym_SET)
2452  return SEEK_SET;
2453  if (vwhence == sym_CUR)
2454  return SEEK_CUR;
2455  if (vwhence == sym_END)
2456  return SEEK_END;
2457 #ifdef SEEK_DATA
2458  if (vwhence == sym_DATA)
2459  return SEEK_DATA;
2460 #endif
2461 #ifdef SEEK_HOLE
2462  if (vwhence == sym_HOLE)
2463  return SEEK_HOLE;
2464 #endif
2465  return NUM2INT(vwhence);
2466 }
2467 
2468 /*
2469  * call-seq:
2470  * seek(offset, whence = IO::SEEK_SET) -> 0
2471  *
2472  * Seeks to the position given by integer +offset+
2473  * (see {Position}[rdoc-ref:IO@Position])
2474  * and constant +whence+, which is one of:
2475  *
2476  * - +:CUR+ or <tt>IO::SEEK_CUR</tt>:
2477  * Repositions the stream to its current position plus the given +offset+:
2478  *
2479  * f = File.open('t.txt')
2480  * f.tell # => 0
2481  * f.seek(20, :CUR) # => 0
2482  * f.tell # => 20
2483  * f.seek(-10, :CUR) # => 0
2484  * f.tell # => 10
2485  * f.close
2486  *
2487  * - +:END+ or <tt>IO::SEEK_END</tt>:
2488  * Repositions the stream to its end plus the given +offset+:
2489  *
2490  * f = File.open('t.txt')
2491  * f.tell # => 0
2492  * f.seek(0, :END) # => 0 # Repositions to stream end.
2493  * f.tell # => 52
2494  * f.seek(-20, :END) # => 0
2495  * f.tell # => 32
2496  * f.seek(-40, :END) # => 0
2497  * f.tell # => 12
2498  * f.close
2499  *
2500  * - +:SET+ or <tt>IO:SEEK_SET</tt>:
2501  * Repositions the stream to the given +offset+:
2502  *
2503  * f = File.open('t.txt')
2504  * f.tell # => 0
2505  * f.seek(20, :SET) # => 0
2506  * f.tell # => 20
2507  * f.seek(40, :SET) # => 0
2508  * f.tell # => 40
2509  * f.close
2510  *
2511  * Related: IO#pos=, IO#tell.
2512  *
2513  */
2514 
2515 static VALUE
2516 rb_io_seek_m(int argc, VALUE *argv, VALUE io)
2517 {
2518  VALUE offset, ptrname;
2519  int whence = SEEK_SET;
2520 
2521  if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
2522  whence = interpret_seek_whence(ptrname);
2523  }
2524 
2525  return rb_io_seek(io, offset, whence);
2526 }
2527 
2528 /*
2529  * call-seq:
2530  * pos = new_position -> new_position
2531  *
2532  * Seeks to the given +new_position+ (in bytes);
2533  * see {Position}[rdoc-ref:IO@Position]:
2534  *
2535  * f = File.open('t.txt')
2536  * f.tell # => 0
2537  * f.pos = 20 # => 20
2538  * f.tell # => 20
2539  * f.close
2540  *
2541  * Related: IO#seek, IO#tell.
2542  *
2543  */
2544 
2545 static VALUE
2546 rb_io_set_pos(VALUE io, VALUE offset)
2547 {
2548  rb_io_t *fptr;
2549  rb_off_t pos;
2550 
2551  pos = NUM2OFFT(offset);
2552  GetOpenFile(io, fptr);
2553  pos = io_seek(fptr, pos, SEEK_SET);
2554  if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2555 
2556  return OFFT2NUM(pos);
2557 }
2558 
2559 static void clear_readconv(rb_io_t *fptr);
2560 
2561 /*
2562  * call-seq:
2563  * rewind -> 0
2564  *
2565  * Repositions the stream to its beginning,
2566  * setting both the position and the line number to zero;
2567  * see {Position}[rdoc-ref:IO@Position]
2568  * and {Line Number}[rdoc-ref:IO@Line+Number]:
2569  *
2570  * f = File.open('t.txt')
2571  * f.tell # => 0
2572  * f.lineno # => 0
2573  * f.gets # => "First line\n"
2574  * f.tell # => 12
2575  * f.lineno # => 1
2576  * f.rewind # => 0
2577  * f.tell # => 0
2578  * f.lineno # => 0
2579  * f.close
2580  *
2581  * Note that this method cannot be used with streams such as pipes, ttys, and sockets.
2582  *
2583  */
2584 
2585 static VALUE
2586 rb_io_rewind(VALUE io)
2587 {
2588  rb_io_t *fptr;
2589 
2590  GetOpenFile(io, fptr);
2591  if (io_seek(fptr, 0L, 0) < 0 && errno) rb_sys_fail_path(fptr->pathv);
2592  if (io == ARGF.current_file) {
2593  ARGF.lineno -= fptr->lineno;
2594  }
2595  fptr->lineno = 0;
2596  if (fptr->readconv) {
2597  clear_readconv(fptr);
2598  }
2599 
2600  return INT2FIX(0);
2601 }
2602 
2603 static int
2604 fptr_wait_readable(rb_io_t *fptr)
2605 {
2606  int result = rb_io_maybe_wait_readable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT);
2607 
2608  if (result)
2609  rb_io_check_closed(fptr);
2610 
2611  return result;
2612 }
2613 
2614 static int
2615 io_fillbuf(rb_io_t *fptr)
2616 {
2617  ssize_t r;
2618 
2619  if (fptr->rbuf.ptr == NULL) {
2620  fptr->rbuf.off = 0;
2621  fptr->rbuf.len = 0;
2622  fptr->rbuf.capa = IO_RBUF_CAPA_FOR(fptr);
2623  fptr->rbuf.ptr = ALLOC_N(char, fptr->rbuf.capa);
2624 #ifdef _WIN32
2625  fptr->rbuf.capa--;
2626 #endif
2627  }
2628  if (fptr->rbuf.len == 0) {
2629  retry:
2630  r = rb_io_read_memory(fptr, fptr->rbuf.ptr, fptr->rbuf.capa);
2631 
2632  if (r < 0) {
2633  if (fptr_wait_readable(fptr))
2634  goto retry;
2635 
2636  int e = errno;
2637  VALUE path = rb_sprintf("fd:%d ", fptr->fd);
2638  if (!NIL_P(fptr->pathv)) {
2639  rb_str_append(path, fptr->pathv);
2640  }
2641 
2642  rb_syserr_fail_path(e, path);
2643  }
2644  if (r > 0) rb_io_check_closed(fptr);
2645  fptr->rbuf.off = 0;
2646  fptr->rbuf.len = (int)r; /* r should be <= rbuf_capa */
2647  if (r == 0)
2648  return -1; /* EOF */
2649  }
2650  return 0;
2651 }
2652 
2653 /*
2654  * call-seq:
2655  * eof -> true or false
2656  *
2657  * Returns +true+ if the stream is positioned at its end, +false+ otherwise;
2658  * see {Position}[rdoc-ref:IO@Position]:
2659  *
2660  * f = File.open('t.txt')
2661  * f.eof # => false
2662  * f.seek(0, :END) # => 0
2663  * f.eof # => true
2664  * f.close
2665  *
2666  * Raises an exception unless the stream is opened for reading;
2667  * see {Mode}[rdoc-ref:File@Access+Modes].
2668  *
2669  * If +self+ is a stream such as pipe or socket, this method
2670  * blocks until the other end sends some data or closes it:
2671  *
2672  * r, w = IO.pipe
2673  * Thread.new { sleep 1; w.close }
2674  * r.eof? # => true # After 1-second wait.
2675  *
2676  * r, w = IO.pipe
2677  * Thread.new { sleep 1; w.puts "a" }
2678  * r.eof? # => false # After 1-second wait.
2679  *
2680  * r, w = IO.pipe
2681  * r.eof? # blocks forever
2682  *
2683  * Note that this method reads data to the input byte buffer. So
2684  * IO#sysread may not behave as you intend with IO#eof?, unless you
2685  * call IO#rewind first (which is not available for some streams).
2686  */
2687 
2688 VALUE
2690 {
2691  rb_io_t *fptr;
2692 
2693  GetOpenFile(io, fptr);
2695 
2696  if (READ_CHAR_PENDING(fptr)) return Qfalse;
2697  if (READ_DATA_PENDING(fptr)) return Qfalse;
2698  READ_CHECK(fptr);
2699 #if RUBY_CRLF_ENVIRONMENT
2700  if (!NEED_READCONV(fptr) && NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
2701  return RBOOL(eof(fptr->fd));
2702  }
2703 #endif
2704  return RBOOL(io_fillbuf(fptr) < 0);
2705 }
2706 
2707 /*
2708  * call-seq:
2709  * sync -> true or false
2710  *
2711  * Returns the current sync mode of the stream.
2712  * When sync mode is true, all output is immediately flushed to the underlying
2713  * operating system and is not buffered by Ruby internally. See also #fsync.
2714  *
2715  * f = File.open('t.tmp', 'w')
2716  * f.sync # => false
2717  * f.sync = true
2718  * f.sync # => true
2719  * f.close
2720  *
2721  */
2722 
2723 static VALUE
2724 rb_io_sync(VALUE io)
2725 {
2726  rb_io_t *fptr;
2727 
2728  io = GetWriteIO(io);
2729  GetOpenFile(io, fptr);
2730  return RBOOL(fptr->mode & FMODE_SYNC);
2731 }
2732 
2733 #ifdef HAVE_FSYNC
2734 
2735 /*
2736  * call-seq:
2737  * sync = boolean -> boolean
2738  *
2739  * Sets the _sync_ _mode_ for the stream to the given value;
2740  * returns the given value.
2741  *
2742  * Values for the sync mode:
2743  *
2744  * - +true+: All output is immediately flushed to the
2745  * underlying operating system and is not buffered internally.
2746  * - +false+: Output may be buffered internally.
2747  *
2748  * Example;
2749  *
2750  * f = File.open('t.tmp', 'w')
2751  * f.sync # => false
2752  * f.sync = true
2753  * f.sync # => true
2754  * f.close
2755  *
2756  * Related: IO#fsync.
2757  *
2758  */
2759 
2760 static VALUE
2761 rb_io_set_sync(VALUE io, VALUE sync)
2762 {
2763  rb_io_t *fptr;
2764 
2765  io = GetWriteIO(io);
2766  GetOpenFile(io, fptr);
2767  if (RTEST(sync)) {
2768  fptr->mode |= FMODE_SYNC;
2769  }
2770  else {
2771  fptr->mode &= ~FMODE_SYNC;
2772  }
2773  return sync;
2774 }
2775 
2776 /*
2777  * call-seq:
2778  * fsync -> 0
2779  *
2780  * Immediately writes to disk all data buffered in the stream,
2781  * via the operating system's <tt>fsync(2)</tt>.
2782 
2783  * Note this difference:
2784  *
2785  * - IO#sync=: Ensures that data is flushed from the stream's internal buffers,
2786  * but does not guarantee that the operating system actually writes the data to disk.
2787  * - IO#fsync: Ensures both that data is flushed from internal buffers,
2788  * and that data is written to disk.
2789  *
2790  * Raises an exception if the operating system does not support <tt>fsync(2)</tt>.
2791  *
2792  */
2793 
2794 static VALUE
2795 rb_io_fsync(VALUE io)
2796 {
2797  rb_io_t *fptr;
2798 
2799  io = GetWriteIO(io);
2800  GetOpenFile(io, fptr);
2801 
2802  if (io_fflush(fptr) < 0)
2803  rb_sys_fail_on_write(fptr);
2804 
2805  if ((int)rb_io_blocking_region(fptr, nogvl_fsync, fptr))
2806  rb_sys_fail_path(fptr->pathv);
2807 
2808  return INT2FIX(0);
2809 }
2810 #else
2811 # define rb_io_fsync rb_f_notimplement
2812 # define rb_io_sync rb_f_notimplement
2813 static VALUE
2814 rb_io_set_sync(VALUE io, VALUE sync)
2815 {
2816  rb_notimplement();
2817  UNREACHABLE;
2818 }
2819 #endif
2820 
2821 #ifdef HAVE_FDATASYNC
2822 static VALUE
2823 nogvl_fdatasync(void *ptr)
2824 {
2825  rb_io_t *fptr = ptr;
2826 
2827 #ifdef _WIN32
2828  if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->fd)) != FILE_TYPE_DISK)
2829  return 0;
2830 #endif
2831  return (VALUE)fdatasync(fptr->fd);
2832 }
2833 
2834 /*
2835  * call-seq:
2836  * fdatasync -> 0
2837  *
2838  * Immediately writes to disk all data buffered in the stream,
2839  * via the operating system's: <tt>fdatasync(2)</tt>, if supported,
2840  * otherwise via <tt>fsync(2)</tt>, if supported;
2841  * otherwise raises an exception.
2842  *
2843  */
2844 
2845 static VALUE
2846 rb_io_fdatasync(VALUE io)
2847 {
2848  rb_io_t *fptr;
2849 
2850  io = GetWriteIO(io);
2851  GetOpenFile(io, fptr);
2852 
2853  if (io_fflush(fptr) < 0)
2854  rb_sys_fail_on_write(fptr);
2855 
2856  if ((int)rb_io_blocking_region(fptr, nogvl_fdatasync, fptr) == 0)
2857  return INT2FIX(0);
2858 
2859  /* fall back */
2860  return rb_io_fsync(io);
2861 }
2862 #else
2863 #define rb_io_fdatasync rb_io_fsync
2864 #endif
2865 
2866 /*
2867  * call-seq:
2868  * fileno -> integer
2869  *
2870  * Returns the integer file descriptor for the stream:
2871  *
2872  * $stdin.fileno # => 0
2873  * $stdout.fileno # => 1
2874  * $stderr.fileno # => 2
2875  * File.open('t.txt').fileno # => 10
2876  * f.close
2877  *
2878  */
2879 
2880 static VALUE
2881 rb_io_fileno(VALUE io)
2882 {
2883  rb_io_t *fptr = RFILE(io)->fptr;
2884  int fd;
2885 
2886  rb_io_check_closed(fptr);
2887  fd = fptr->fd;
2888  return INT2FIX(fd);
2889 }
2890 
2891 int
2893 {
2894  if (RB_TYPE_P(io, T_FILE)) {
2895  rb_io_t *fptr = RFILE(io)->fptr;
2896  rb_io_check_closed(fptr);
2897  return fptr->fd;
2898  }
2899  else {
2900  VALUE fileno = rb_check_funcall(io, id_fileno, 0, NULL);
2901  if (!UNDEF_P(fileno)) {
2902  return RB_NUM2INT(fileno);
2903  }
2904  }
2905 
2906  rb_raise(rb_eTypeError, "expected IO or #fileno, %"PRIsVALUE" given", rb_obj_class(io));
2907 
2908  UNREACHABLE_RETURN(-1);
2909 }
2910 
2911 int
2913 {
2914  rb_io_t *fptr;
2915  GetOpenFile(io, fptr);
2916  return fptr->mode;
2917 }
2918 
2919 /*
2920  * call-seq:
2921  * pid -> integer or nil
2922  *
2923  * Returns the process ID of a child process associated with the stream,
2924  * which will have been set by IO#popen, or +nil+ if the stream was not
2925  * created by IO#popen:
2926  *
2927  * pipe = IO.popen("-")
2928  * if pipe
2929  * $stderr.puts "In parent, child pid is #{pipe.pid}"
2930  * else
2931  * $stderr.puts "In child, pid is #{$$}"
2932  * end
2933  *
2934  * Output:
2935  *
2936  * In child, pid is 26209
2937  * In parent, child pid is 26209
2938  *
2939  */
2940 
2941 static VALUE
2942 rb_io_pid(VALUE io)
2943 {
2944  rb_io_t *fptr;
2945 
2946  GetOpenFile(io, fptr);
2947  if (!fptr->pid)
2948  return Qnil;
2949  return PIDT2NUM(fptr->pid);
2950 }
2951 
2952 /*
2953  * call-seq:
2954  * path -> string or nil
2955  *
2956  * Returns the path associated with the IO, or +nil+ if there is no path
2957  * associated with the IO. It is not guaranteed that the path exists on
2958  * the filesystem.
2959  *
2960  * $stdin.path # => "<STDIN>"
2961  *
2962  * File.open("testfile") {|f| f.path} # => "testfile"
2963  */
2964 
2965 VALUE
2967 {
2968  rb_io_t *fptr = RFILE(io)->fptr;
2969 
2970  if (!fptr)
2971  return Qnil;
2972 
2973  return rb_obj_dup(fptr->pathv);
2974 }
2975 
2976 /*
2977  * call-seq:
2978  * inspect -> string
2979  *
2980  * Returns a string representation of +self+:
2981  *
2982  * f = File.open('t.txt')
2983  * f.inspect # => "#<File:t.txt>"
2984  * f.close
2985  *
2986  */
2987 
2988 static VALUE
2989 rb_io_inspect(VALUE obj)
2990 {
2991  rb_io_t *fptr;
2992  VALUE result;
2993  static const char closed[] = " (closed)";
2994 
2995  fptr = RFILE(obj)->fptr;
2996  if (!fptr) return rb_any_to_s(obj);
2997  result = rb_str_new_cstr("#<");
2998  rb_str_append(result, rb_class_name(CLASS_OF(obj)));
2999  rb_str_cat2(result, ":");
3000  if (NIL_P(fptr->pathv)) {
3001  if (fptr->fd < 0) {
3002  rb_str_cat(result, closed+1, strlen(closed)-1);
3003  }
3004  else {
3005  rb_str_catf(result, "fd %d", fptr->fd);
3006  }
3007  }
3008  else {
3009  rb_str_append(result, fptr->pathv);
3010  if (fptr->fd < 0) {
3011  rb_str_cat(result, closed, strlen(closed));
3012  }
3013  }
3014  return rb_str_cat2(result, ">");
3015 }
3016 
3017 /*
3018  * call-seq:
3019  * to_io -> self
3020  *
3021  * Returns +self+.
3022  *
3023  */
3024 
3025 static VALUE
3026 rb_io_to_io(VALUE io)
3027 {
3028  return io;
3029 }
3030 
3031 /* reading functions */
3032 static long
3033 read_buffered_data(char *ptr, long len, rb_io_t *fptr)
3034 {
3035  int n;
3036 
3037  n = READ_DATA_PENDING_COUNT(fptr);
3038  if (n <= 0) return 0;
3039  if (n > len) n = (int)len;
3040  MEMMOVE(ptr, fptr->rbuf.ptr+fptr->rbuf.off, char, n);
3041  fptr->rbuf.off += n;
3042  fptr->rbuf.len -= n;
3043  return n;
3044 }
3045 
3046 static long
3047 io_bufread(char *ptr, long len, rb_io_t *fptr)
3048 {
3049  long offset = 0;
3050  long n = len;
3051  long c;
3052 
3053  if (READ_DATA_PENDING(fptr) == 0) {
3054  while (n > 0) {
3055  again:
3056  rb_io_check_closed(fptr);
3057  c = rb_io_read_memory(fptr, ptr+offset, n);
3058  if (c == 0) break;
3059  if (c < 0) {
3060  if (fptr_wait_readable(fptr))
3061  goto again;
3062  return -1;
3063  }
3064  offset += c;
3065  if ((n -= c) <= 0) break;
3066  }
3067  return len - n;
3068  }
3069 
3070  while (n > 0) {
3071  c = read_buffered_data(ptr+offset, n, fptr);
3072  if (c > 0) {
3073  offset += c;
3074  if ((n -= c) <= 0) break;
3075  }
3076  rb_io_check_closed(fptr);
3077  if (io_fillbuf(fptr) < 0) {
3078  break;
3079  }
3080  }
3081  return len - n;
3082 }
3083 
3084 static int io_setstrbuf(VALUE *str, long len);
3085 
3086 struct bufread_arg {
3087  char *str_ptr;
3088  long len;
3089  rb_io_t *fptr;
3090 };
3091 
3092 static VALUE
3093 bufread_call(VALUE arg)
3094 {
3095  struct bufread_arg *p = (struct bufread_arg *)arg;
3096  p->len = io_bufread(p->str_ptr, p->len, p->fptr);
3097  return Qundef;
3098 }
3099 
3100 static long
3101 io_fread(VALUE str, long offset, long size, rb_io_t *fptr)
3102 {
3103  long len;
3104  struct bufread_arg arg;
3105 
3106  io_setstrbuf(&str, offset + size);
3107  arg.str_ptr = RSTRING_PTR(str) + offset;
3108  arg.len = size;
3109  arg.fptr = fptr;
3110  rb_str_locktmp_ensure(str, bufread_call, (VALUE)&arg);
3111  len = arg.len;
3112  if (len < 0) rb_sys_fail_path(fptr->pathv);
3113  return len;
3114 }
3115 
3116 static long
3117 remain_size(rb_io_t *fptr)
3118 {
3119  struct stat st;
3120  rb_off_t siz = READ_DATA_PENDING_COUNT(fptr);
3121  rb_off_t pos;
3122 
3123  if (fstat(fptr->fd, &st) == 0 && S_ISREG(st.st_mode)
3124 #if defined(__HAIKU__)
3125  && (st.st_dev > 3)
3126 #endif
3127  )
3128  {
3129  if (io_fflush(fptr) < 0)
3130  rb_sys_fail_on_write(fptr);
3131  pos = lseek(fptr->fd, 0, SEEK_CUR);
3132  if (st.st_size >= pos && pos >= 0) {
3133  siz += st.st_size - pos;
3134  if (siz > LONG_MAX) {
3135  rb_raise(rb_eIOError, "file too big for single read");
3136  }
3137  }
3138  }
3139  else {
3140  siz += BUFSIZ;
3141  }
3142  return (long)siz;
3143 }
3144 
3145 static VALUE
3146 io_enc_str(VALUE str, rb_io_t *fptr)
3147 {
3148  rb_enc_associate(str, io_read_encoding(fptr));
3149  return str;
3150 }
3151 
3152 static rb_encoding *io_read_encoding(rb_io_t *fptr);
3153 
3154 static void
3155 make_readconv(rb_io_t *fptr, int size)
3156 {
3157  if (!fptr->readconv) {
3158  int ecflags;
3159  VALUE ecopts;
3160  const char *sname, *dname;
3161  ecflags = fptr->encs.ecflags & ~ECONV_NEWLINE_DECORATOR_WRITE_MASK;
3162  ecopts = fptr->encs.ecopts;
3163  if (fptr->encs.enc2) {
3164  sname = rb_enc_name(fptr->encs.enc2);
3165  dname = rb_enc_name(io_read_encoding(fptr));
3166  }
3167  else {
3168  sname = dname = "";
3169  }
3170  fptr->readconv = rb_econv_open_opts(sname, dname, ecflags, ecopts);
3171  if (!fptr->readconv)
3172  rb_exc_raise(rb_econv_open_exc(sname, dname, ecflags));
3173  fptr->cbuf.off = 0;
3174  fptr->cbuf.len = 0;
3175  if (size < IO_CBUF_CAPA_MIN) size = IO_CBUF_CAPA_MIN;
3176  fptr->cbuf.capa = size;
3177  fptr->cbuf.ptr = ALLOC_N(char, fptr->cbuf.capa);
3178  }
3179 }
3180 
3181 #define MORE_CHAR_SUSPENDED Qtrue
3182 #define MORE_CHAR_FINISHED Qnil
3183 static VALUE
3184 fill_cbuf(rb_io_t *fptr, int ec_flags)
3185 {
3186  const unsigned char *ss, *sp, *se;
3187  unsigned char *ds, *dp, *de;
3188  rb_econv_result_t res;
3189  int putbackable;
3190  int cbuf_len0;
3191  VALUE exc;
3192 
3193  ec_flags |= ECONV_PARTIAL_INPUT;
3194 
3195  if (fptr->cbuf.len == fptr->cbuf.capa)
3196  return MORE_CHAR_SUSPENDED; /* cbuf full */
3197  if (fptr->cbuf.len == 0)
3198  fptr->cbuf.off = 0;
3199  else if (fptr->cbuf.off + fptr->cbuf.len == fptr->cbuf.capa) {
3200  memmove(fptr->cbuf.ptr, fptr->cbuf.ptr+fptr->cbuf.off, fptr->cbuf.len);
3201  fptr->cbuf.off = 0;
3202  }
3203 
3204  cbuf_len0 = fptr->cbuf.len;
3205 
3206  while (1) {
3207  ss = sp = (const unsigned char *)fptr->rbuf.ptr + fptr->rbuf.off;
3208  se = sp + fptr->rbuf.len;
3209  ds = dp = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.off + fptr->cbuf.len;
3210  de = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.capa;
3211  res = rb_econv_convert(fptr->readconv, &sp, se, &dp, de, ec_flags);
3212  fptr->rbuf.off += (int)(sp - ss);
3213  fptr->rbuf.len -= (int)(sp - ss);
3214  fptr->cbuf.len += (int)(dp - ds);
3215 
3216  putbackable = rb_econv_putbackable(fptr->readconv);
3217  if (putbackable) {
3218  rb_econv_putback(fptr->readconv, (unsigned char *)fptr->rbuf.ptr + fptr->rbuf.off - putbackable, putbackable);
3219  fptr->rbuf.off -= putbackable;
3220  fptr->rbuf.len += putbackable;
3221  }
3222 
3223  exc = rb_econv_make_exception(fptr->readconv);
3224  if (!NIL_P(exc))
3225  return exc;
3226 
3227  if (cbuf_len0 != fptr->cbuf.len)
3228  return MORE_CHAR_SUSPENDED;
3229 
3230  if (res == econv_finished) {
3231  return MORE_CHAR_FINISHED;
3232  }
3233 
3234  if (res == econv_source_buffer_empty) {
3235  if (fptr->rbuf.len == 0) {
3236  READ_CHECK(fptr);
3237  if (io_fillbuf(fptr) < 0) {
3238  if (!fptr->readconv) {
3239  return MORE_CHAR_FINISHED;
3240  }
3241  ds = dp = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.off + fptr->cbuf.len;
3242  de = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.capa;
3243  res = rb_econv_convert(fptr->readconv, NULL, NULL, &dp, de, 0);
3244  fptr->cbuf.len += (int)(dp - ds);
3246  break;
3247  }
3248  }
3249  }
3250  }
3251  if (cbuf_len0 != fptr->cbuf.len)
3252  return MORE_CHAR_SUSPENDED;
3253 
3254  return MORE_CHAR_FINISHED;
3255 }
3256 
3257 static VALUE
3258 more_char(rb_io_t *fptr)
3259 {
3260  VALUE v;
3261  v = fill_cbuf(fptr, ECONV_AFTER_OUTPUT);
3262  if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED)
3263  rb_exc_raise(v);
3264  return v;
3265 }
3266 
3267 static VALUE
3268 io_shift_cbuf(rb_io_t *fptr, int len, VALUE *strp)
3269 {
3270  VALUE str = Qnil;
3271  if (strp) {
3272  str = *strp;
3273  if (NIL_P(str)) {
3274  *strp = str = rb_str_new(fptr->cbuf.ptr+fptr->cbuf.off, len);
3275  }
3276  else {
3277  rb_str_cat(str, fptr->cbuf.ptr+fptr->cbuf.off, len);
3278  }
3279  rb_enc_associate(str, fptr->encs.enc);
3280  }
3281  fptr->cbuf.off += len;
3282  fptr->cbuf.len -= len;
3283  /* xxx: set coderange */
3284  if (fptr->cbuf.len == 0)
3285  fptr->cbuf.off = 0;
3286  else if (fptr->cbuf.capa/2 < fptr->cbuf.off) {
3287  memmove(fptr->cbuf.ptr, fptr->cbuf.ptr+fptr->cbuf.off, fptr->cbuf.len);
3288  fptr->cbuf.off = 0;
3289  }
3290  return str;
3291 }
3292 
3293 static int
3294 io_setstrbuf(VALUE *str, long len)
3295 {
3296 #ifdef _WIN32
3297  if (len > 0)
3298  len = (len + 1) & ~1L; /* round up for wide char */
3299 #endif
3300  if (NIL_P(*str)) {
3301  *str = rb_str_new(0, len);
3302  return TRUE;
3303  }
3304  else {
3305  VALUE s = StringValue(*str);
3306  rb_str_modify(s);
3307 
3308  long clen = RSTRING_LEN(s);
3309  if (clen >= len) {
3310  return FALSE;
3311  }
3312  len -= clen;
3313  }
3314  if ((rb_str_capacity(*str) - (size_t)RSTRING_LEN(*str)) < (size_t)len) {
3315  rb_str_modify_expand(*str, len);
3316  }
3317  return FALSE;
3318 }
3319 
3320 #define MAX_REALLOC_GAP 4096
3321 static void
3322 io_shrink_read_string(VALUE str, long n)
3323 {
3324  if (rb_str_capacity(str) - n > MAX_REALLOC_GAP) {
3325  rb_str_resize(str, n);
3326  }
3327 }
3328 
3329 static void
3330 io_set_read_length(VALUE str, long n, int shrinkable)
3331 {
3332  if (RSTRING_LEN(str) != n) {
3333  rb_str_modify(str);
3334  rb_str_set_len(str, n);
3335  if (shrinkable) io_shrink_read_string(str, n);
3336  }
3337 }
3338 
3339 static VALUE
3340 read_all(rb_io_t *fptr, long siz, VALUE str)
3341 {
3342  long bytes;
3343  long n;
3344  long pos;
3345  rb_encoding *enc;
3346  int cr;
3347  int shrinkable;
3348 
3349  if (NEED_READCONV(fptr)) {
3350  int first = !NIL_P(str);
3351  SET_BINARY_MODE(fptr);
3352  shrinkable = io_setstrbuf(&str,0);
3353  make_readconv(fptr, 0);
3354  while (1) {
3355  VALUE v;
3356  if (fptr->cbuf.len) {
3357  if (first) rb_str_set_len(str, first = 0);
3358  io_shift_cbuf(fptr, fptr->cbuf.len, &str);
3359  }
3360  v = fill_cbuf(fptr, 0);
3361  if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED) {
3362  if (fptr->cbuf.len) {
3363  if (first) rb_str_set_len(str, first = 0);
3364  io_shift_cbuf(fptr, fptr->cbuf.len, &str);
3365  }
3366  rb_exc_raise(v);
3367  }
3368  if (v == MORE_CHAR_FINISHED) {
3369  clear_readconv(fptr);
3370  if (first) rb_str_set_len(str, first = 0);
3371  if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3372  return io_enc_str(str, fptr);
3373  }
3374  }
3375  }
3376 
3377  NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3378  bytes = 0;
3379  pos = 0;
3380 
3381  enc = io_read_encoding(fptr);
3382  cr = 0;
3383 
3384  if (siz == 0) siz = BUFSIZ;
3385  shrinkable = io_setstrbuf(&str, siz);
3386  for (;;) {
3387  READ_CHECK(fptr);
3388  n = io_fread(str, bytes, siz - bytes, fptr);
3389  if (n == 0 && bytes == 0) {
3390  rb_str_set_len(str, 0);
3391  break;
3392  }
3393  bytes += n;
3394  rb_str_set_len(str, bytes);
3395  if (cr != ENC_CODERANGE_BROKEN)
3396  pos += rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + bytes, enc, &cr);
3397  if (bytes < siz) break;
3398  siz += BUFSIZ;
3399 
3400  size_t capa = rb_str_capacity(str);
3401  if (capa < (size_t)RSTRING_LEN(str) + BUFSIZ) {
3402  if (capa < BUFSIZ) {
3403  capa = BUFSIZ;
3404  }
3405  else if (capa > IO_MAX_BUFFER_GROWTH) {
3406  capa = IO_MAX_BUFFER_GROWTH;
3407  }
3408  rb_str_modify_expand(str, capa);
3409  }
3410  }
3411  if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3412  str = io_enc_str(str, fptr);
3413  ENC_CODERANGE_SET(str, cr);
3414  return str;
3415 }
3416 
3417 void
3419 {
3420  if (rb_fd_set_nonblock(fptr->fd) != 0) {
3421  rb_sys_fail_path(fptr->pathv);
3422  }
3423 }
3424 
3425 static VALUE
3426 io_read_memory_call(VALUE arg)
3427 {
3428  struct io_internal_read_struct *iis = (struct io_internal_read_struct *)arg;
3429 
3430  VALUE scheduler = rb_fiber_scheduler_current();
3431  if (scheduler != Qnil) {
3432  VALUE result = rb_fiber_scheduler_io_read_memory(scheduler, iis->fptr->self, iis->buf, iis->capa, 0);
3433 
3434  if (!UNDEF_P(result)) {
3435  // This is actually returned as a pseudo-VALUE and later cast to a long:
3436  return (VALUE)rb_fiber_scheduler_io_result_apply(result);
3437  }
3438  }
3439 
3440  if (iis->nonblock) {
3441  return rb_io_blocking_region(iis->fptr, internal_read_func, iis);
3442  }
3443  else {
3444  return rb_io_blocking_region_wait(iis->fptr, internal_read_func, iis, RUBY_IO_READABLE);
3445  }
3446 }
3447 
3448 static long
3449 io_read_memory_locktmp(VALUE str, struct io_internal_read_struct *iis)
3450 {
3451  return (long)rb_str_locktmp_ensure(str, io_read_memory_call, (VALUE)iis);
3452 }
3453 
3454 #define no_exception_p(opts) !rb_opts_exception_p((opts), TRUE)
3455 
3456 static VALUE
3457 io_getpartial(int argc, VALUE *argv, VALUE io, int no_exception, int nonblock)
3458 {
3459  rb_io_t *fptr;
3460  VALUE length, str;
3461  long n, len;
3462  struct io_internal_read_struct iis;
3463  int shrinkable;
3464 
3465  rb_scan_args(argc, argv, "11", &length, &str);
3466 
3467  if ((len = NUM2LONG(length)) < 0) {
3468  rb_raise(rb_eArgError, "negative length %ld given", len);
3469  }
3470 
3471  shrinkable = io_setstrbuf(&str, len);
3472 
3473  GetOpenFile(io, fptr);
3475 
3476  if (len == 0) {
3477  io_set_read_length(str, 0, shrinkable);
3478  return str;
3479  }
3480 
3481  if (!nonblock)
3482  READ_CHECK(fptr);
3483  n = read_buffered_data(RSTRING_PTR(str), len, fptr);
3484  if (n <= 0) {
3485  again:
3486  if (nonblock) {
3487  rb_io_set_nonblock(fptr);
3488  }
3489  io_setstrbuf(&str, len);
3490  iis.th = rb_thread_current();
3491  iis.fptr = fptr;
3492  iis.nonblock = nonblock;
3493  iis.fd = fptr->fd;
3494  iis.buf = RSTRING_PTR(str);
3495  iis.capa = len;
3496  iis.timeout = NULL;
3497  n = io_read_memory_locktmp(str, &iis);
3498  if (n < 0) {
3499  int e = errno;
3500  if (!nonblock && fptr_wait_readable(fptr))
3501  goto again;
3502  if (nonblock && (io_again_p(e))) {
3503  if (no_exception)
3504  return sym_wait_readable;
3505  else
3506  rb_readwrite_syserr_fail(RB_IO_WAIT_READABLE,
3507  e, "read would block");
3508  }
3509  rb_syserr_fail_path(e, fptr->pathv);
3510  }
3511  }
3512  io_set_read_length(str, n, shrinkable);
3513 
3514  if (n == 0)
3515  return Qnil;
3516  else
3517  return str;
3518 }
3519 
3520 /*
3521  * call-seq:
3522  * readpartial(maxlen) -> string
3523  * readpartial(maxlen, out_string) -> out_string
3524  *
3525  * Reads up to +maxlen+ bytes from the stream;
3526  * returns a string (either a new string or the given +out_string+).
3527  * Its encoding is:
3528  *
3529  * - The unchanged encoding of +out_string+, if +out_string+ is given.
3530  * - ASCII-8BIT, otherwise.
3531  *
3532  * - Contains +maxlen+ bytes from the stream, if available.
3533  * - Otherwise contains all available bytes, if any available.
3534  * - Otherwise is an empty string.
3535  *
3536  * With the single non-negative integer argument +maxlen+ given,
3537  * returns a new string:
3538  *
3539  * f = File.new('t.txt')
3540  * f.readpartial(20) # => "First line\nSecond l"
3541  * f.readpartial(20) # => "ine\n\nFourth line\n"
3542  * f.readpartial(20) # => "Fifth line\n"
3543  * f.readpartial(20) # Raises EOFError.
3544  * f.close
3545  *
3546  * With both argument +maxlen+ and string argument +out_string+ given,
3547  * returns modified +out_string+:
3548  *
3549  * f = File.new('t.txt')
3550  * s = 'foo'
3551  * f.readpartial(20, s) # => "First line\nSecond l"
3552  * s = 'bar'
3553  * f.readpartial(0, s) # => ""
3554  * f.close
3555  *
3556  * This method is useful for a stream such as a pipe, a socket, or a tty.
3557  * It blocks only when no data is immediately available.
3558  * This means that it blocks only when _all_ of the following are true:
3559  *
3560  * - The byte buffer in the stream is empty.
3561  * - The content of the stream is empty.
3562  * - The stream is not at EOF.
3563  *
3564  * When blocked, the method waits for either more data or EOF on the stream:
3565  *
3566  * - If more data is read, the method returns the data.
3567  * - If EOF is reached, the method raises EOFError.
3568  *
3569  * When not blocked, the method responds immediately:
3570  *
3571  * - Returns data from the buffer if there is any.
3572  * - Otherwise returns data from the stream if there is any.
3573  * - Otherwise raises EOFError if the stream has reached EOF.
3574  *
3575  * Note that this method is similar to sysread. The differences are:
3576  *
3577  * - If the byte buffer is not empty, read from the byte buffer
3578  * instead of "sysread for buffered IO (IOError)".
3579  * - It doesn't cause Errno::EWOULDBLOCK and Errno::EINTR. When
3580  * readpartial meets EWOULDBLOCK and EINTR by read system call,
3581  * readpartial retries the system call.
3582  *
3583  * The latter means that readpartial is non-blocking-flag insensitive.
3584  * It blocks on the situation IO#sysread causes Errno::EWOULDBLOCK as
3585  * if the fd is blocking mode.
3586  *
3587  * Examples:
3588  *
3589  * # # Returned Buffer Content Pipe Content
3590  * r, w = IO.pipe #
3591  * w << 'abc' # "" "abc".
3592  * r.readpartial(4096) # => "abc" "" ""
3593  * r.readpartial(4096) # (Blocks because buffer and pipe are empty.)
3594  *
3595  * # # Returned Buffer Content Pipe Content
3596  * r, w = IO.pipe #
3597  * w << 'abc' # "" "abc"
3598  * w.close # "" "abc" EOF
3599  * r.readpartial(4096) # => "abc" "" EOF
3600  * r.readpartial(4096) # raises EOFError
3601  *
3602  * # # Returned Buffer Content Pipe Content
3603  * r, w = IO.pipe #
3604  * w << "abc\ndef\n" # "" "abc\ndef\n"
3605  * r.gets # => "abc\n" "def\n" ""
3606  * w << "ghi\n" # "def\n" "ghi\n"
3607  * r.readpartial(4096) # => "def\n" "" "ghi\n"
3608  * r.readpartial(4096) # => "ghi\n" "" ""
3609  *
3610  */
3611 
3612 static VALUE
3613 io_readpartial(int argc, VALUE *argv, VALUE io)
3614 {
3615  VALUE ret;
3616 
3617  ret = io_getpartial(argc, argv, io, Qnil, 0);
3618  if (NIL_P(ret))
3619  rb_eof_error();
3620  return ret;
3621 }
3622 
3623 static VALUE
3624 io_nonblock_eof(int no_exception)
3625 {
3626  if (!no_exception) {
3627  rb_eof_error();
3628  }
3629  return Qnil;
3630 }
3631 
3632 /* :nodoc: */
3633 static VALUE
3634 io_read_nonblock(rb_execution_context_t *ec, VALUE io, VALUE length, VALUE str, VALUE ex)
3635 {
3636  rb_io_t *fptr;
3637  long n, len;
3638  struct io_internal_read_struct iis;
3639  int shrinkable;
3640 
3641  if ((len = NUM2LONG(length)) < 0) {
3642  rb_raise(rb_eArgError, "negative length %ld given", len);
3643  }
3644 
3645  shrinkable = io_setstrbuf(&str, len);
3646  rb_bool_expected(ex, "exception", TRUE);
3647 
3648  GetOpenFile(io, fptr);
3650 
3651  if (len == 0) {
3652  io_set_read_length(str, 0, shrinkable);
3653  return str;
3654  }
3655 
3656  n = read_buffered_data(RSTRING_PTR(str), len, fptr);
3657  if (n <= 0) {
3658  rb_fd_set_nonblock(fptr->fd);
3659  shrinkable |= io_setstrbuf(&str, len);
3660  iis.fptr = fptr;
3661  iis.nonblock = 1;
3662  iis.fd = fptr->fd;
3663  iis.buf = RSTRING_PTR(str);
3664  iis.capa = len;
3665  iis.timeout = NULL;
3666  n = io_read_memory_locktmp(str, &iis);
3667  if (n < 0) {
3668  int e = errno;
3669  if (io_again_p(e)) {
3670  if (!ex) return sym_wait_readable;
3671  rb_readwrite_syserr_fail(RB_IO_WAIT_READABLE,
3672  e, "read would block");
3673  }
3674  rb_syserr_fail_path(e, fptr->pathv);
3675  }
3676  }
3677  io_set_read_length(str, n, shrinkable);
3678 
3679  if (n == 0) {
3680  if (!ex) return Qnil;
3681  rb_eof_error();
3682  }
3683 
3684  return str;
3685 }
3686 
3687 /* :nodoc: */
3688 static VALUE
3689 io_write_nonblock(rb_execution_context_t *ec, VALUE io, VALUE str, VALUE ex)
3690 {
3691  rb_io_t *fptr;
3692  long n;
3693 
3694  if (!RB_TYPE_P(str, T_STRING))
3695  str = rb_obj_as_string(str);
3696  rb_bool_expected(ex, "exception", TRUE);
3697 
3698  io = GetWriteIO(io);
3699  GetOpenFile(io, fptr);
3700  rb_io_check_writable(fptr);
3701 
3702  if (io_fflush(fptr) < 0)
3703  rb_sys_fail_on_write(fptr);
3704 
3705  rb_fd_set_nonblock(fptr->fd);
3706  n = write(fptr->fd, RSTRING_PTR(str), RSTRING_LEN(str));
3707  RB_GC_GUARD(str);
3708 
3709  if (n < 0) {
3710  int e = errno;
3711  if (io_again_p(e)) {
3712  if (!ex) {
3713  return sym_wait_writable;
3714  }
3715  else {
3716  rb_readwrite_syserr_fail(RB_IO_WAIT_WRITABLE, e, "write would block");
3717  }
3718  }
3719  rb_syserr_fail_path(e, fptr->pathv);
3720  }
3721 
3722  return LONG2FIX(n);
3723 }
3724 
3725 /*
3726  * call-seq:
3727  * read(maxlen = nil, out_string = nil) -> new_string, out_string, or nil
3728  *
3729  * Reads bytes from the stream; the stream must be opened for reading
3730  * (see {Access Modes}[rdoc-ref:File@Access+Modes]):
3731  *
3732  * - If +maxlen+ is +nil+, reads all bytes using the stream's data mode.
3733  * - Otherwise reads up to +maxlen+ bytes in binary mode.
3734  *
3735  * Returns a string (either a new string or the given +out_string+)
3736  * containing the bytes read.
3737  * The encoding of the string depends on both +maxLen+ and +out_string+:
3738  *
3739  * - +maxlen+ is +nil+: uses internal encoding of +self+
3740  * (regardless of whether +out_string+ was given).
3741  * - +maxlen+ not +nil+:
3742  *
3743  * - +out_string+ given: encoding of +out_string+ not modified.
3744  * - +out_string+ not given: ASCII-8BIT is used.
3745  *
3746  * <b>Without Argument +out_string+</b>
3747  *
3748  * When argument +out_string+ is omitted,
3749  * the returned value is a new string:
3750  *
3751  * f = File.new('t.txt')
3752  * f.read
3753  * # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3754  * f.rewind
3755  * f.read(30) # => "First line\r\nSecond line\r\n\r\nFou"
3756  * f.read(30) # => "rth line\r\nFifth line\r\n"
3757  * f.read(30) # => nil
3758  * f.close
3759  *
3760  * If +maxlen+ is zero, returns an empty string.
3761  *
3762  * <b> With Argument +out_string+</b>
3763  *
3764  * When argument +out_string+ is given,
3765  * the returned value is +out_string+, whose content is replaced:
3766  *
3767  * f = File.new('t.txt')
3768  * s = 'foo' # => "foo"
3769  * f.read(nil, s) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3770  * s # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3771  * f.rewind
3772  * s = 'bar'
3773  * f.read(30, s) # => "First line\r\nSecond line\r\n\r\nFou"
3774  * s # => "First line\r\nSecond line\r\n\r\nFou"
3775  * s = 'baz'
3776  * f.read(30, s) # => "rth line\r\nFifth line\r\n"
3777  * s # => "rth line\r\nFifth line\r\n"
3778  * s = 'bat'
3779  * f.read(30, s) # => nil
3780  * s # => ""
3781  * f.close
3782  *
3783  * Note that this method behaves like the fread() function in C.
3784  * This means it retries to invoke read(2) system calls to read data
3785  * with the specified maxlen (or until EOF).
3786  *
3787  * This behavior is preserved even if the stream is in non-blocking mode.
3788  * (This method is non-blocking-flag insensitive as other methods.)
3789  *
3790  * If you need the behavior like a single read(2) system call,
3791  * consider #readpartial, #read_nonblock, and #sysread.
3792  *
3793  * Related: IO#write.
3794  */
3795 
3796 static VALUE
3797 io_read(int argc, VALUE *argv, VALUE io)
3798 {
3799  rb_io_t *fptr;
3800  long n, len;
3801  VALUE length, str;
3802  int shrinkable;
3803 #if RUBY_CRLF_ENVIRONMENT
3804  int previous_mode;
3805 #endif
3806 
3807  rb_scan_args(argc, argv, "02", &length, &str);
3808 
3809  if (NIL_P(length)) {
3810  GetOpenFile(io, fptr);
3812  return read_all(fptr, remain_size(fptr), str);
3813  }
3814  len = NUM2LONG(length);
3815  if (len < 0) {
3816  rb_raise(rb_eArgError, "negative length %ld given", len);
3817  }
3818 
3819  shrinkable = io_setstrbuf(&str,len);
3820 
3821  GetOpenFile(io, fptr);
3823  if (len == 0) {
3824  io_set_read_length(str, 0, shrinkable);
3825  return str;
3826  }
3827 
3828  READ_CHECK(fptr);
3829 #if RUBY_CRLF_ENVIRONMENT
3830  previous_mode = set_binary_mode_with_seek_cur(fptr);
3831 #endif
3832  n = io_fread(str, 0, len, fptr);
3833  io_set_read_length(str, n, shrinkable);
3834 #if RUBY_CRLF_ENVIRONMENT
3835  if (previous_mode == O_TEXT) {
3836  setmode(fptr->fd, O_TEXT);
3837  }
3838 #endif
3839  if (n == 0) return Qnil;
3840 
3841  return str;
3842 }
3843 
3844 static void
3845 rscheck(const char *rsptr, long rslen, VALUE rs)
3846 {
3847  if (!rs) return;
3848  if (RSTRING_PTR(rs) != rsptr && RSTRING_LEN(rs) != rslen)
3849  rb_raise(rb_eRuntimeError, "rs modified");
3850 }
3851 
3852 static int
3853 appendline(rb_io_t *fptr, int delim, VALUE *strp, long *lp)
3854 {
3855  VALUE str = *strp;
3856  long limit = *lp;
3857 
3858  if (NEED_READCONV(fptr)) {
3859  SET_BINARY_MODE(fptr);
3860  make_readconv(fptr, 0);
3861  do {
3862  const char *p, *e;
3863  int searchlen = READ_CHAR_PENDING_COUNT(fptr);
3864  if (searchlen) {
3865  p = READ_CHAR_PENDING_PTR(fptr);
3866  if (0 < limit && limit < searchlen)
3867  searchlen = (int)limit;
3868  e = memchr(p, delim, searchlen);
3869  if (e) {
3870  int len = (int)(e-p+1);
3871  if (NIL_P(str))
3872  *strp = str = rb_str_new(p, len);
3873  else
3874  rb_str_buf_cat(str, p, len);
3875  fptr->cbuf.off += len;
3876  fptr->cbuf.len -= len;
3877  limit -= len;
3878  *lp = limit;
3879  return delim;
3880  }
3881 
3882  if (NIL_P(str))
3883  *strp = str = rb_str_new(p, searchlen);
3884  else
3885  rb_str_buf_cat(str, p, searchlen);
3886  fptr->cbuf.off += searchlen;
3887  fptr->cbuf.len -= searchlen;
3888  limit -= searchlen;
3889 
3890  if (limit == 0) {
3891  *lp = limit;
3892  return (unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
3893  }
3894  }
3895  } while (more_char(fptr) != MORE_CHAR_FINISHED);
3896  clear_readconv(fptr);
3897  *lp = limit;
3898  return EOF;
3899  }
3900 
3901  NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3902  do {
3903  long pending = READ_DATA_PENDING_COUNT(fptr);
3904  if (pending > 0) {
3905  const char *p = READ_DATA_PENDING_PTR(fptr);
3906  const char *e;
3907  long last;
3908 
3909  if (limit > 0 && pending > limit) pending = limit;
3910  e = memchr(p, delim, pending);
3911  if (e) pending = e - p + 1;
3912  if (!NIL_P(str)) {
3913  last = RSTRING_LEN(str);
3914  rb_str_resize(str, last + pending);
3915  }
3916  else {
3917  last = 0;
3918  *strp = str = rb_str_buf_new(pending);
3919  rb_str_set_len(str, pending);
3920  }
3921  read_buffered_data(RSTRING_PTR(str) + last, pending, fptr); /* must not fail */
3922  limit -= pending;
3923  *lp = limit;
3924  if (e) return delim;
3925  if (limit == 0)
3926  return (unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
3927  }
3928  READ_CHECK(fptr);
3929  } while (io_fillbuf(fptr) >= 0);
3930  *lp = limit;
3931  return EOF;
3932 }
3933 
3934 static inline int
3935 swallow(rb_io_t *fptr, int term)
3936 {
3937  if (NEED_READCONV(fptr)) {
3938  rb_encoding *enc = io_read_encoding(fptr);
3939  int needconv = rb_enc_mbminlen(enc) != 1;
3940  SET_BINARY_MODE(fptr);
3941  make_readconv(fptr, 0);
3942  do {
3943  size_t cnt;
3944  while ((cnt = READ_CHAR_PENDING_COUNT(fptr)) > 0) {
3945  const char *p = READ_CHAR_PENDING_PTR(fptr);
3946  int i;
3947  if (!needconv) {
3948  if (*p != term) return TRUE;
3949  i = (int)cnt;
3950  while (--i && *++p == term);
3951  }
3952  else {
3953  const char *e = p + cnt;
3954  if (rb_enc_ascget(p, e, &i, enc) != term) return TRUE;
3955  while ((p += i) < e && rb_enc_ascget(p, e, &i, enc) == term);
3956  i = (int)(e - p);
3957  }
3958  io_shift_cbuf(fptr, (int)cnt - i, NULL);
3959  }
3960  } while (more_char(fptr) != MORE_CHAR_FINISHED);
3961  return FALSE;
3962  }
3963 
3964  NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3965  do {
3966  size_t cnt;
3967  while ((cnt = READ_DATA_PENDING_COUNT(fptr)) > 0) {
3968  char buf[1024];
3969  const char *p = READ_DATA_PENDING_PTR(fptr);
3970  int i;
3971  if (cnt > sizeof buf) cnt = sizeof buf;
3972  if (*p != term) return TRUE;
3973  i = (int)cnt;
3974  while (--i && *++p == term);
3975  if (!read_buffered_data(buf, cnt - i, fptr)) /* must not fail */
3976  rb_sys_fail_path(fptr->pathv);
3977  }
3978  READ_CHECK(fptr);
3979  } while (io_fillbuf(fptr) == 0);
3980  return FALSE;
3981 }
3982 
3983 static VALUE
3984 rb_io_getline_fast(rb_io_t *fptr, rb_encoding *enc, int chomp)
3985 {
3986  VALUE str = Qnil;
3987  int len = 0;
3988  long pos = 0;
3989  int cr = 0;
3990 
3991  do {
3992  int pending = READ_DATA_PENDING_COUNT(fptr);
3993 
3994  if (pending > 0) {
3995  const char *p = READ_DATA_PENDING_PTR(fptr);
3996  const char *e;
3997  int chomplen = 0;
3998 
3999  e = memchr(p, '\n', pending);
4000  if (e) {
4001  pending = (int)(e - p + 1);
4002  if (chomp) {
4003  chomplen = (pending > 1 && *(e-1) == '\r') + 1;
4004  }
4005  }
4006  if (NIL_P(str)) {
4007  str = rb_str_new(p, pending - chomplen);
4008  fptr->rbuf.off += pending;
4009  fptr->rbuf.len -= pending;
4010  }
4011  else {
4012  rb_str_resize(str, len + pending - chomplen);
4013  read_buffered_data(RSTRING_PTR(str)+len, pending - chomplen, fptr);
4014  fptr->rbuf.off += chomplen;
4015  fptr->rbuf.len -= chomplen;
4016  if (pending == 1 && chomplen == 1 && len > 0) {
4017  if (RSTRING_PTR(str)[len-1] == '\r') {
4018  rb_str_resize(str, --len);
4019  break;
4020  }
4021  }
4022  }
4023  len += pending - chomplen;
4024  if (cr != ENC_CODERANGE_BROKEN)
4025  pos += rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + len, enc, &cr);
4026  if (e) break;
4027  }
4028  READ_CHECK(fptr);
4029  } while (io_fillbuf(fptr) >= 0);
4030  if (NIL_P(str)) return Qnil;
4031 
4032  str = io_enc_str(str, fptr);
4033  ENC_CODERANGE_SET(str, cr);
4034  fptr->lineno++;
4035 
4036  return str;
4037 }
4038 
4039 struct getline_arg {
4040  VALUE io;
4041  VALUE rs;
4042  long limit;
4043  unsigned int chomp: 1;
4044 };
4045 
4046 static void
4047 extract_getline_opts(VALUE opts, struct getline_arg *args)
4048 {
4049  int chomp = FALSE;
4050  if (!NIL_P(opts)) {
4051  static ID kwds[1];
4052  VALUE vchomp;
4053  if (!kwds[0]) {
4054  kwds[0] = rb_intern_const("chomp");
4055  }
4056  rb_get_kwargs(opts, kwds, 0, -2, &vchomp);
4057  chomp = (!UNDEF_P(vchomp)) && RTEST(vchomp);
4058  }
4059  args->chomp = chomp;
4060 }
4061 
4062 static void
4063 extract_getline_args(int argc, VALUE *argv, struct getline_arg *args)
4064 {
4065  VALUE rs = rb_rs, lim = Qnil;
4066 
4067  if (argc == 1) {
4068  VALUE tmp = Qnil;
4069 
4070  if (NIL_P(argv[0]) || !NIL_P(tmp = rb_check_string_type(argv[0]))) {
4071  rs = tmp;
4072  }
4073  else {
4074  lim = argv[0];
4075  }
4076  }
4077  else if (2 <= argc) {
4078  rs = argv[0], lim = argv[1];
4079  if (!NIL_P(rs))
4080  StringValue(rs);
4081  }
4082  args->rs = rs;
4083  args->limit = NIL_P(lim) ? -1L : NUM2LONG(lim);
4084 }
4085 
4086 static void
4087 check_getline_args(VALUE *rsp, long *limit, VALUE io)
4088 {
4089  rb_io_t *fptr;
4090  VALUE rs = *rsp;
4091 
4092  if (!NIL_P(rs)) {
4093  rb_encoding *enc_rs, *enc_io;
4094 
4095  GetOpenFile(io, fptr);
4096  enc_rs = rb_enc_get(rs);
4097  enc_io = io_read_encoding(fptr);
4098  if (enc_io != enc_rs &&
4099  (!is_ascii_string(rs) ||
4100  (RSTRING_LEN(rs) > 0 && !rb_enc_asciicompat(enc_io)))) {
4101  if (rs == rb_default_rs) {
4102  rs = rb_enc_str_new(0, 0, enc_io);
4103  rb_str_buf_cat_ascii(rs, "\n");
4104  *rsp = rs;
4105  }
4106  else {
4107  rb_raise(rb_eArgError, "encoding mismatch: %s IO with %s RS",
4108  rb_enc_name(enc_io),
4109  rb_enc_name(enc_rs));
4110  }
4111  }
4112  }
4113 }
4114 
4115 static void
4116 prepare_getline_args(int argc, VALUE *argv, struct getline_arg *args, VALUE io)
4117 {
4118  VALUE opts;
4119  argc = rb_scan_args(argc, argv, "02:", NULL, NULL, &opts);
4120  extract_getline_args(argc, argv, args);
4121  extract_getline_opts(opts, args);
4122  check_getline_args(&args->rs, &args->limit, io);
4123 }
4124 
4125 static VALUE
4126 rb_io_getline_0(VALUE rs, long limit, int chomp, rb_io_t *fptr)
4127 {
4128  VALUE str = Qnil;
4129  int nolimit = 0;
4130  rb_encoding *enc;
4131 
4133  if (NIL_P(rs) && limit < 0) {
4134  str = read_all(fptr, 0, Qnil);
4135  if (RSTRING_LEN(str) == 0) return Qnil;
4136  }
4137  else if (limit == 0) {
4138  return rb_enc_str_new(0, 0, io_read_encoding(fptr));
4139  }
4140  else if (rs == rb_default_rs && limit < 0 && !NEED_READCONV(fptr) &&
4141  rb_enc_asciicompat(enc = io_read_encoding(fptr))) {
4142  NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4143  return rb_io_getline_fast(fptr, enc, chomp);
4144  }
4145  else {
4146  int c, newline = -1;
4147  const char *rsptr = 0;
4148  long rslen = 0;
4149  int rspara = 0;
4150  int extra_limit = 16;
4151  int chomp_cr = chomp;
4152 
4153  SET_BINARY_MODE(fptr);
4154  enc = io_read_encoding(fptr);
4155 
4156  if (!NIL_P(rs)) {
4157  rslen = RSTRING_LEN(rs);
4158  if (rslen == 0) {
4159  rsptr = "\n\n";
4160  rslen = 2;
4161  rspara = 1;
4162  swallow(fptr, '\n');
4163  rs = 0;
4164  if (!rb_enc_asciicompat(enc)) {
4165  rs = rb_usascii_str_new(rsptr, rslen);
4166  rs = rb_str_encode(rs, rb_enc_from_encoding(enc), 0, Qnil);
4167  OBJ_FREEZE(rs);
4168  rsptr = RSTRING_PTR(rs);
4169  rslen = RSTRING_LEN(rs);
4170  }
4171  }
4172  else {
4173  rsptr = RSTRING_PTR(rs);
4174  }
4175  newline = (unsigned char)rsptr[rslen - 1];
4176  chomp_cr = chomp && rslen == 1 && newline == '\n';
4177  }
4178 
4179  /* MS - Optimization */
4180  while ((c = appendline(fptr, newline, &str, &limit)) != EOF) {
4181  const char *s, *p, *pp, *e;
4182 
4183  if (c == newline) {
4184  if (RSTRING_LEN(str) < rslen) continue;
4185  s = RSTRING_PTR(str);
4186  e = RSTRING_END(str);
4187  p = e - rslen;
4188  if (!at_char_boundary(s, p, e, enc)) continue;
4189  if (!rspara) rscheck(rsptr, rslen, rs);
4190  if (memcmp(p, rsptr, rslen) == 0) {
4191  if (chomp) {
4192  if (chomp_cr && p > s && *(p-1) == '\r') --p;
4193  rb_str_set_len(str, p - s);
4194  }
4195  break;
4196  }
4197  }
4198  if (limit == 0) {
4199  s = RSTRING_PTR(str);
4200  p = RSTRING_END(str);
4201  pp = rb_enc_left_char_head(s, p-1, p, enc);
4202  if (extra_limit &&
4204  /* relax the limit while incomplete character.
4205  * extra_limit limits the relax length */
4206  limit = 1;
4207  extra_limit--;
4208  }
4209  else {
4210  nolimit = 1;
4211  break;
4212  }
4213  }
4214  }
4215 
4216  if (rspara && c != EOF)
4217  swallow(fptr, '\n');
4218  if (!NIL_P(str))
4219  str = io_enc_str(str, fptr);
4220  }
4221 
4222  if (!NIL_P(str) && !nolimit) {
4223  fptr->lineno++;
4224  }
4225 
4226  return str;
4227 }
4228 
4229 static VALUE
4230 rb_io_getline_1(VALUE rs, long limit, int chomp, VALUE io)
4231 {
4232  rb_io_t *fptr;
4233  int old_lineno, new_lineno;
4234  VALUE str;
4235 
4236  GetOpenFile(io, fptr);
4237  old_lineno = fptr->lineno;
4238  str = rb_io_getline_0(rs, limit, chomp, fptr);
4239  if (!NIL_P(str) && (new_lineno = fptr->lineno) != old_lineno) {
4240  if (io == ARGF.current_file) {
4241  ARGF.lineno += new_lineno - old_lineno;
4242  ARGF.last_lineno = ARGF.lineno;
4243  }
4244  else {
4245  ARGF.last_lineno = new_lineno;
4246  }
4247  }
4248 
4249  return str;
4250 }
4251 
4252 static VALUE
4253 rb_io_getline(int argc, VALUE *argv, VALUE io)
4254 {
4255  struct getline_arg args;
4256 
4257  prepare_getline_args(argc, argv, &args, io);
4258  return rb_io_getline_1(args.rs, args.limit, args.chomp, io);
4259 }
4260 
4261 VALUE
4263 {
4264  return rb_io_getline_1(rb_default_rs, -1, FALSE, io);
4265 }
4266 
4267 VALUE
4268 rb_io_gets_internal(VALUE io)
4269 {
4270  rb_io_t *fptr;
4271  GetOpenFile(io, fptr);
4272  return rb_io_getline_0(rb_default_rs, -1, FALSE, fptr);
4273 }
4274 
4275 /*
4276  * call-seq:
4277  * gets(sep = $/, chomp: false) -> string or nil
4278  * gets(limit, chomp: false) -> string or nil
4279  * gets(sep, limit, chomp: false) -> string or nil
4280  *
4281  * Reads and returns a line from the stream;
4282  * assigns the return value to <tt>$_</tt>.
4283  * See {Line IO}[rdoc-ref:IO@Line+IO].
4284  *
4285  * With no arguments given, returns the next line
4286  * as determined by line separator <tt>$/</tt>, or +nil+ if none:
4287  *
4288  * f = File.open('t.txt')
4289  * f.gets # => "First line\n"
4290  * $_ # => "First line\n"
4291  * f.gets # => "\n"
4292  * f.gets # => "Fourth line\n"
4293  * f.gets # => "Fifth line\n"
4294  * f.gets # => nil
4295  * f.close
4296  *
4297  * With only string argument +sep+ given,
4298  * returns the next line as determined by line separator +sep+,
4299  * or +nil+ if none;
4300  * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4301  *
4302  * f = File.new('t.txt')
4303  * f.gets('l') # => "First l"
4304  * f.gets('li') # => "ine\nSecond li"
4305  * f.gets('lin') # => "ne\n\nFourth lin"
4306  * f.gets # => "e\n"
4307  * f.close
4308  *
4309  * The two special values for +sep+ are honored:
4310  *
4311  * f = File.new('t.txt')
4312  * # Get all.
4313  * f.gets(nil) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
4314  * f.rewind
4315  * # Get paragraph (up to two line separators).
4316  * f.gets('') # => "First line\nSecond line\n\n"
4317  * f.close
4318  *
4319  * With only integer argument +limit+ given,
4320  * limits the number of bytes in the line;
4321  * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4322  *
4323  * # No more than one line.
4324  * File.open('t.txt') {|f| f.gets(10) } # => "First line"
4325  * File.open('t.txt') {|f| f.gets(11) } # => "First line\n"
4326  * File.open('t.txt') {|f| f.gets(12) } # => "First line\n"
4327  *
4328  * With arguments +sep+ and +limit+ given,
4329  * combines the two behaviors
4330  * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
4331  *
4332  * Optional keyword argument +chomp+ specifies whether line separators
4333  * are to be omitted:
4334  *
4335  * f = File.open('t.txt')
4336  * # Chomp the lines.
4337  * f.gets(chomp: true) # => "First line"
4338  * f.gets(chomp: true) # => "Second line"
4339  * f.gets(chomp: true) # => ""
4340  * f.gets(chomp: true) # => "Fourth line"
4341  * f.gets(chomp: true) # => "Fifth line"
4342  * f.gets(chomp: true) # => nil
4343  * f.close
4344  *
4345  */
4346 
4347 static VALUE
4348 rb_io_gets_m(int argc, VALUE *argv, VALUE io)
4349 {
4350  VALUE str;
4351 
4352  str = rb_io_getline(argc, argv, io);
4353  rb_lastline_set(str);
4354 
4355  return str;
4356 }
4357 
4358 /*
4359  * call-seq:
4360  * lineno -> integer
4361  *
4362  * Returns the current line number for the stream;
4363  * see {Line Number}[rdoc-ref:IO@Line+Number].
4364  *
4365  */
4366 
4367 static VALUE
4368 rb_io_lineno(VALUE io)
4369 {
4370  rb_io_t *fptr;
4371 
4372  GetOpenFile(io, fptr);
4374  return INT2NUM(fptr->lineno);
4375 }
4376 
4377 /*
4378  * call-seq:
4379  * lineno = integer -> integer
4380  *
4381  * Sets and returns the line number for the stream;
4382  * see {Line Number}[rdoc-ref:IO@Line+Number].
4383  *
4384  */
4385 
4386 static VALUE
4387 rb_io_set_lineno(VALUE io, VALUE lineno)
4388 {
4389  rb_io_t *fptr;
4390 
4391  GetOpenFile(io, fptr);
4393  fptr->lineno = NUM2INT(lineno);
4394  return lineno;
4395 }
4396 
4397 /* :nodoc: */
4398 static VALUE
4399 io_readline(rb_execution_context_t *ec, VALUE io, VALUE sep, VALUE lim, VALUE chomp)
4400 {
4401  long limit = -1;
4402  if (NIL_P(lim)) {
4403  VALUE tmp = Qnil;
4404  // If sep is specified, but it's not a string and not nil, then assume
4405  // it's the limit (it should be an integer)
4406  if (!NIL_P(sep) && NIL_P(tmp = rb_check_string_type(sep))) {
4407  // If the user has specified a non-nil / non-string value
4408  // for the separator, we assume it's the limit and set the
4409  // separator to default: rb_rs.
4410  lim = sep;
4411  limit = NUM2LONG(lim);
4412  sep = rb_rs;
4413  }
4414  else {
4415  sep = tmp;
4416  }
4417  }
4418  else {
4419  if (!NIL_P(sep)) StringValue(sep);
4420  limit = NUM2LONG(lim);
4421  }
4422 
4423  check_getline_args(&sep, &limit, io);
4424 
4425  VALUE line = rb_io_getline_1(sep, limit, RTEST(chomp), io);
4426  rb_lastline_set_up(line, 1);
4427 
4428  if (NIL_P(line)) {
4429  rb_eof_error();
4430  }
4431  return line;
4432 }
4433 
4434 static VALUE io_readlines(const struct getline_arg *arg, VALUE io);
4435 
4436 /*
4437  * call-seq:
4438  * readlines(sep = $/, chomp: false) -> array
4439  * readlines(limit, chomp: false) -> array
4440  * readlines(sep, limit, chomp: false) -> array
4441  *
4442  * Reads and returns all remaining line from the stream;
4443  * does not modify <tt>$_</tt>.
4444  * See {Line IO}[rdoc-ref:IO@Line+IO].
4445  *
4446  * With no arguments given, returns lines
4447  * as determined by line separator <tt>$/</tt>, or +nil+ if none:
4448  *
4449  * f = File.new('t.txt')
4450  * f.readlines
4451  * # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
4452  * f.readlines # => []
4453  * f.close
4454  *
4455  * With only string argument +sep+ given,
4456  * returns lines as determined by line separator +sep+,
4457  * or +nil+ if none;
4458  * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4459  *
4460  * f = File.new('t.txt')
4461  * f.readlines('li')
4462  * # => ["First li", "ne\nSecond li", "ne\n\nFourth li", "ne\nFifth li", "ne\n"]
4463  * f.close
4464  *
4465  * The two special values for +sep+ are honored:
4466  *
4467  * f = File.new('t.txt')
4468  * # Get all into one string.
4469  * f.readlines(nil)
4470  * # => ["First line\nSecond line\n\nFourth line\nFifth line\n"]
4471  * # Get paragraphs (up to two line separators).
4472  * f.rewind
4473  * f.readlines('')
4474  * # => ["First line\nSecond line\n\n", "Fourth line\nFifth line\n"]
4475  * f.close
4476  *
4477  * With only integer argument +limit+ given,
4478  * limits the number of bytes in each line;
4479  * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4480  *
4481  * f = File.new('t.txt')
4482  * f.readlines(8)
4483  * # => ["First li", "ne\n", "Second l", "ine\n", "\n", "Fourth l", "ine\n", "Fifth li", "ne\n"]
4484  * f.close
4485  *
4486  * With arguments +sep+ and +limit+ given,
4487  * combines the two behaviors
4488  * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
4489  *
4490  * Optional keyword argument +chomp+ specifies whether line separators
4491  * are to be omitted:
4492  *
4493  * f = File.new('t.txt')
4494  * f.readlines(chomp: true)
4495  * # => ["First line", "Second line", "", "Fourth line", "Fifth line"]
4496  * f.close
4497  *
4498  */
4499 
4500 static VALUE
4501 rb_io_readlines(int argc, VALUE *argv, VALUE io)
4502 {
4503  struct getline_arg args;
4504 
4505  prepare_getline_args(argc, argv, &args, io);
4506  return io_readlines(&args, io);
4507 }
4508 
4509 static VALUE
4510 io_readlines(const struct getline_arg *arg, VALUE io)
4511 {
4512  VALUE line, ary;
4513 
4514  if (arg->limit == 0)
4515  rb_raise(rb_eArgError, "invalid limit: 0 for readlines");
4516  ary = rb_ary_new();
4517  while (!NIL_P(line = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, io))) {
4518  rb_ary_push(ary, line);
4519  }
4520  return ary;
4521 }
4522 
4523 /*
4524  * call-seq:
4525  * each_line(sep = $/, chomp: false) {|line| ... } -> self
4526  * each_line(limit, chomp: false) {|line| ... } -> self
4527  * each_line(sep, limit, chomp: false) {|line| ... } -> self
4528  * each_line -> enumerator
4529  *
4530  * Calls the block with each remaining line read from the stream;
4531  * returns +self+.
4532  * Does nothing if already at end-of-stream;
4533  * See {Line IO}[rdoc-ref:IO@Line+IO].
4534  *
4535  * With no arguments given, reads lines
4536  * as determined by line separator <tt>$/</tt>:
4537  *
4538  * f = File.new('t.txt')
4539  * f.each_line {|line| p line }
4540  * f.each_line {|line| fail 'Cannot happen' }
4541  * f.close
4542  *
4543  * Output:
4544  *
4545  * "First line\n"
4546  * "Second line\n"
4547  * "\n"
4548  * "Fourth line\n"
4549  * "Fifth line\n"
4550  *
4551  * With only string argument +sep+ given,
4552  * reads lines as determined by line separator +sep+;
4553  * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4554  *
4555  * f = File.new('t.txt')
4556  * f.each_line('li') {|line| p line }
4557  * f.close
4558  *
4559  * Output:
4560  *
4561  * "First li"
4562  * "ne\nSecond li"
4563  * "ne\n\nFourth li"
4564  * "ne\nFifth li"
4565  * "ne\n"
4566  *
4567  * The two special values for +sep+ are honored:
4568  *
4569  * f = File.new('t.txt')
4570  * # Get all into one string.
4571  * f.each_line(nil) {|line| p line }
4572  * f.close
4573  *
4574  * Output:
4575  *
4576  * "First line\nSecond line\n\nFourth line\nFifth line\n"
4577  *
4578  * f.rewind
4579  * # Get paragraphs (up to two line separators).
4580  * f.each_line('') {|line| p line }
4581  *
4582  * Output:
4583  *
4584  * "First line\nSecond line\n\n"
4585  * "Fourth line\nFifth line\n"
4586  *
4587  * With only integer argument +limit+ given,
4588  * limits the number of bytes in each line;
4589  * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4590  *
4591  * f = File.new('t.txt')
4592  * f.each_line(8) {|line| p line }
4593  * f.close
4594  *
4595  * Output:
4596  *
4597  * "First li"
4598  * "ne\n"
4599  * "Second l"
4600  * "ine\n"
4601  * "\n"
4602  * "Fourth l"
4603  * "ine\n"
4604  * "Fifth li"
4605  * "ne\n"
4606  *
4607  * With arguments +sep+ and +limit+ given,
4608  * combines the two behaviors
4609  * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
4610  *
4611  * Optional keyword argument +chomp+ specifies whether line separators
4612  * are to be omitted:
4613  *
4614  * f = File.new('t.txt')
4615  * f.each_line(chomp: true) {|line| p line }
4616  * f.close
4617  *
4618  * Output:
4619  *
4620  * "First line"
4621  * "Second line"
4622  * ""
4623  * "Fourth line"
4624  * "Fifth line"
4625  *
4626  * Returns an Enumerator if no block is given.
4627  */
4628 
4629 static VALUE
4630 rb_io_each_line(int argc, VALUE *argv, VALUE io)
4631 {
4632  VALUE str;
4633  struct getline_arg args;
4634 
4635  RETURN_ENUMERATOR(io, argc, argv);
4636  prepare_getline_args(argc, argv, &args, io);
4637  if (args.limit == 0)
4638  rb_raise(rb_eArgError, "invalid limit: 0 for each_line");
4639  while (!NIL_P(str = rb_io_getline_1(args.rs, args.limit, args.chomp, io))) {
4640  rb_yield(str);
4641  }
4642  return io;
4643 }
4644 
4645 /*
4646  * call-seq:
4647  * each_byte {|byte| ... } -> self
4648  * each_byte -> enumerator
4649  *
4650  * Calls the given block with each byte (0..255) in the stream; returns +self+.
4651  * See {Byte IO}[rdoc-ref:IO@Byte+IO].
4652  *
4653  * f = File.new('t.rus')
4654  * a = []
4655  * f.each_byte {|b| a << b }
4656  * a # => [209, 130, 208, 181, 209, 129, 209, 130]
4657  * f.close
4658  *
4659  * Returns an Enumerator if no block is given.
4660  *
4661  * Related: IO#each_char, IO#each_codepoint.
4662  *
4663  */
4664 
4665 static VALUE
4666 rb_io_each_byte(VALUE io)
4667 {
4668  rb_io_t *fptr;
4669 
4670  RETURN_ENUMERATOR(io, 0, 0);
4671  GetOpenFile(io, fptr);
4672 
4673  do {
4674  while (fptr->rbuf.len > 0) {
4675  char *p = fptr->rbuf.ptr + fptr->rbuf.off++;
4676  fptr->rbuf.len--;
4677  rb_yield(INT2FIX(*p & 0xff));
4679  errno = 0;
4680  }
4681  READ_CHECK(fptr);
4682  } while (io_fillbuf(fptr) >= 0);
4683  return io;
4684 }
4685 
4686 static VALUE
4687 io_getc(rb_io_t *fptr, rb_encoding *enc)
4688 {
4689  int r, n, cr = 0;
4690  VALUE str;
4691 
4692  if (NEED_READCONV(fptr)) {
4693  rb_encoding *read_enc = io_read_encoding(fptr);
4694 
4695  str = Qnil;
4696  SET_BINARY_MODE(fptr);
4697  make_readconv(fptr, 0);
4698 
4699  while (1) {
4700  if (fptr->cbuf.len) {
4701  r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4702  fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4703  read_enc);
4704  if (!MBCLEN_NEEDMORE_P(r))
4705  break;
4706  if (fptr->cbuf.len == fptr->cbuf.capa) {
4707  rb_raise(rb_eIOError, "too long character");
4708  }
4709  }
4710 
4711  if (more_char(fptr) == MORE_CHAR_FINISHED) {
4712  if (fptr->cbuf.len == 0) {
4713  clear_readconv(fptr);
4714  return Qnil;
4715  }
4716  /* return an unit of an incomplete character just before EOF */
4717  str = rb_enc_str_new(fptr->cbuf.ptr+fptr->cbuf.off, 1, read_enc);
4718  fptr->cbuf.off += 1;
4719  fptr->cbuf.len -= 1;
4720  if (fptr->cbuf.len == 0) clear_readconv(fptr);
4722  return str;
4723  }
4724  }
4725  if (MBCLEN_INVALID_P(r)) {
4726  r = rb_enc_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4727  fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4728  read_enc);
4729  io_shift_cbuf(fptr, r, &str);
4730  cr = ENC_CODERANGE_BROKEN;
4731  }
4732  else {
4733  io_shift_cbuf(fptr, MBCLEN_CHARFOUND_LEN(r), &str);
4734  cr = ENC_CODERANGE_VALID;
4735  if (MBCLEN_CHARFOUND_LEN(r) == 1 && rb_enc_asciicompat(read_enc) &&
4736  ISASCII(RSTRING_PTR(str)[0])) {
4737  cr = ENC_CODERANGE_7BIT;
4738  }
4739  }
4740  str = io_enc_str(str, fptr);
4741  ENC_CODERANGE_SET(str, cr);
4742  return str;
4743  }
4744 
4745  NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4746  if (io_fillbuf(fptr) < 0) {
4747  return Qnil;
4748  }
4749  if (rb_enc_asciicompat(enc) && ISASCII(fptr->rbuf.ptr[fptr->rbuf.off])) {
4750  str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, 1);
4751  fptr->rbuf.off += 1;
4752  fptr->rbuf.len -= 1;
4753  cr = ENC_CODERANGE_7BIT;
4754  }
4755  else {
4756  r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off, fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4757  if (MBCLEN_CHARFOUND_P(r) &&
4758  (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
4759  str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, n);
4760  fptr->rbuf.off += n;
4761  fptr->rbuf.len -= n;
4762  cr = ENC_CODERANGE_VALID;
4763  }
4764  else if (MBCLEN_NEEDMORE_P(r)) {
4765  str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, fptr->rbuf.len);
4766  fptr->rbuf.len = 0;
4767  getc_needmore:
4768  if (io_fillbuf(fptr) != -1) {
4769  rb_str_cat(str, fptr->rbuf.ptr+fptr->rbuf.off, 1);
4770  fptr->rbuf.off++;
4771  fptr->rbuf.len--;
4772  r = rb_enc_precise_mbclen(RSTRING_PTR(str), RSTRING_PTR(str)+RSTRING_LEN(str), enc);
4773  if (MBCLEN_NEEDMORE_P(r)) {
4774  goto getc_needmore;
4775  }
4776  else if (MBCLEN_CHARFOUND_P(r)) {
4777  cr = ENC_CODERANGE_VALID;
4778  }
4779  }
4780  }
4781  else {
4782  str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, 1);
4783  fptr->rbuf.off++;
4784  fptr->rbuf.len--;
4785  }
4786  }
4787  if (!cr) cr = ENC_CODERANGE_BROKEN;
4788  str = io_enc_str(str, fptr);
4789  ENC_CODERANGE_SET(str, cr);
4790  return str;
4791 }
4792 
4793 /*
4794  * call-seq:
4795  * each_char {|c| ... } -> self
4796  * each_char -> enumerator
4797  *
4798  * Calls the given block with each character in the stream; returns +self+.
4799  * See {Character IO}[rdoc-ref:IO@Character+IO].
4800  *
4801  * f = File.new('t.rus')
4802  * a = []
4803  * f.each_char {|c| a << c.ord }
4804  * a # => [1090, 1077, 1089, 1090]
4805  * f.close
4806  *
4807  * Returns an Enumerator if no block is given.
4808  *
4809  * Related: IO#each_byte, IO#each_codepoint.
4810  *
4811  */
4812 
4813 static VALUE
4814 rb_io_each_char(VALUE io)
4815 {
4816  rb_io_t *fptr;
4817  rb_encoding *enc;
4818  VALUE c;
4819 
4820  RETURN_ENUMERATOR(io, 0, 0);
4821  GetOpenFile(io, fptr);
4823 
4824  enc = io_input_encoding(fptr);
4825  READ_CHECK(fptr);
4826  while (!NIL_P(c = io_getc(fptr, enc))) {
4827  rb_yield(c);
4828  }
4829  return io;
4830 }
4831 
4832 /*
4833  * call-seq:
4834  * each_codepoint {|c| ... } -> self
4835  * each_codepoint -> enumerator
4836  *
4837  * Calls the given block with each codepoint in the stream; returns +self+:
4838  *
4839  * f = File.new('t.rus')
4840  * a = []
4841  * f.each_codepoint {|c| a << c }
4842  * a # => [1090, 1077, 1089, 1090]
4843  * f.close
4844  *
4845  * Returns an Enumerator if no block is given.
4846  *
4847  * Related: IO#each_byte, IO#each_char.
4848  *
4849  */
4850 
4851 static VALUE
4852 rb_io_each_codepoint(VALUE io)
4853 {
4854  rb_io_t *fptr;
4855  rb_encoding *enc;
4856  unsigned int c;
4857  int r, n;
4858 
4859  RETURN_ENUMERATOR(io, 0, 0);
4860  GetOpenFile(io, fptr);
4862 
4863  READ_CHECK(fptr);
4864  if (NEED_READCONV(fptr)) {
4865  SET_BINARY_MODE(fptr);
4866  r = 1; /* no invalid char yet */
4867  for (;;) {
4868  make_readconv(fptr, 0);
4869  for (;;) {
4870  if (fptr->cbuf.len) {
4871  if (fptr->encs.enc)
4872  r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4873  fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4874  fptr->encs.enc);
4875  else
4876  r = ONIGENC_CONSTRUCT_MBCLEN_CHARFOUND(1);
4877  if (!MBCLEN_NEEDMORE_P(r))
4878  break;
4879  if (fptr->cbuf.len == fptr->cbuf.capa) {
4880  rb_raise(rb_eIOError, "too long character");
4881  }
4882  }
4883  if (more_char(fptr) == MORE_CHAR_FINISHED) {
4884  clear_readconv(fptr);
4885  if (!MBCLEN_CHARFOUND_P(r)) {
4886  enc = fptr->encs.enc;
4887  goto invalid;
4888  }
4889  return io;
4890  }
4891  }
4892  if (MBCLEN_INVALID_P(r)) {
4893  enc = fptr->encs.enc;
4894  goto invalid;
4895  }
4896  n = MBCLEN_CHARFOUND_LEN(r);
4897  if (fptr->encs.enc) {
4898  c = rb_enc_codepoint(fptr->cbuf.ptr+fptr->cbuf.off,
4899  fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4900  fptr->encs.enc);
4901  }
4902  else {
4903  c = (unsigned char)fptr->cbuf.ptr[fptr->cbuf.off];
4904  }
4905  fptr->cbuf.off += n;
4906  fptr->cbuf.len -= n;
4907  rb_yield(UINT2NUM(c));
4909  }
4910  }
4911  NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4912  enc = io_input_encoding(fptr);
4913  while (io_fillbuf(fptr) >= 0) {
4914  r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off,
4915  fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4916  if (MBCLEN_CHARFOUND_P(r) &&
4917  (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
4918  c = rb_enc_codepoint(fptr->rbuf.ptr+fptr->rbuf.off,
4919  fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4920  fptr->rbuf.off += n;
4921  fptr->rbuf.len -= n;
4922  rb_yield(UINT2NUM(c));
4923  }
4924  else if (MBCLEN_INVALID_P(r)) {
4925  goto invalid;
4926  }
4927  else if (MBCLEN_NEEDMORE_P(r)) {
4928  char cbuf[8], *p = cbuf;
4929  int more = MBCLEN_NEEDMORE_LEN(r);
4930  if (more > numberof(cbuf)) goto invalid;
4931  more += n = fptr->rbuf.len;
4932  if (more > numberof(cbuf)) goto invalid;
4933  while ((n = (int)read_buffered_data(p, more, fptr)) > 0 &&
4934  (p += n, (more -= n) > 0)) {
4935  if (io_fillbuf(fptr) < 0) goto invalid;
4936  if ((n = fptr->rbuf.len) > more) n = more;
4937  }
4938  r = rb_enc_precise_mbclen(cbuf, p, enc);
4939  if (!MBCLEN_CHARFOUND_P(r)) goto invalid;
4940  c = rb_enc_codepoint(cbuf, p, enc);
4941  rb_yield(UINT2NUM(c));
4942  }
4943  else {
4944  continue;
4945  }
4947  }
4948  return io;
4949 
4950  invalid:
4951  rb_raise(rb_eArgError, "invalid byte sequence in %s", rb_enc_name(enc));
4953 }
4954 
4955 /*
4956  * call-seq:
4957  * getc -> character or nil
4958  *
4959  * Reads and returns the next 1-character string from the stream;
4960  * returns +nil+ if already at end-of-stream.
4961  * See {Character IO}[rdoc-ref:IO@Character+IO].
4962  *
4963  * f = File.open('t.txt')
4964  * f.getc # => "F"
4965  * f.close
4966  * f = File.open('t.rus')
4967  * f.getc.ord # => 1090
4968  * f.close
4969  *
4970  * Related: IO#readchar (may raise EOFError).
4971  *
4972  */
4973 
4974 static VALUE
4975 rb_io_getc(VALUE io)
4976 {
4977  rb_io_t *fptr;
4978  rb_encoding *enc;
4979 
4980  GetOpenFile(io, fptr);
4982 
4983  enc = io_input_encoding(fptr);
4984  READ_CHECK(fptr);
4985  return io_getc(fptr, enc);
4986 }
4987 
4988 /*
4989  * call-seq:
4990  * readchar -> string
4991  *
4992  * Reads and returns the next 1-character string from the stream;
4993  * raises EOFError if already at end-of-stream.
4994  * See {Character IO}[rdoc-ref:IO@Character+IO].
4995  *
4996  * f = File.open('t.txt')
4997  * f.readchar # => "F"
4998  * f.close
4999  * f = File.open('t.rus')
5000  * f.readchar.ord # => 1090
5001  * f.close
5002  *
5003  * Related: IO#getc (will not raise EOFError).
5004  *
5005  */
5006 
5007 static VALUE
5008 rb_io_readchar(VALUE io)
5009 {
5010  VALUE c = rb_io_getc(io);
5011 
5012  if (NIL_P(c)) {
5013  rb_eof_error();
5014  }
5015  return c;
5016 }
5017 
5018 /*
5019  * call-seq:
5020  * getbyte -> integer or nil
5021  *
5022  * Reads and returns the next byte (in range 0..255) from the stream;
5023  * returns +nil+ if already at end-of-stream.
5024  * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5025  *
5026  * f = File.open('t.txt')
5027  * f.getbyte # => 70
5028  * f.close
5029  * f = File.open('t.rus')
5030  * f.getbyte # => 209
5031  * f.close
5032  *
5033  * Related: IO#readbyte (may raise EOFError).
5034  */
5035 
5036 VALUE
5038 {
5039  rb_io_t *fptr;
5040  int c;
5041 
5042  GetOpenFile(io, fptr);
5044  READ_CHECK(fptr);
5045  VALUE r_stdout = rb_ractor_stdout();
5046  if (fptr->fd == 0 && (fptr->mode & FMODE_TTY) && RB_TYPE_P(r_stdout, T_FILE)) {
5047  rb_io_t *ofp;
5048  GetOpenFile(r_stdout, ofp);
5049  if (ofp->mode & FMODE_TTY) {
5050  rb_io_flush(r_stdout);
5051  }
5052  }
5053  if (io_fillbuf(fptr) < 0) {
5054  return Qnil;
5055  }
5056  fptr->rbuf.off++;
5057  fptr->rbuf.len--;
5058  c = (unsigned char)fptr->rbuf.ptr[fptr->rbuf.off-1];
5059  return INT2FIX(c & 0xff);
5060 }
5061 
5062 /*
5063  * call-seq:
5064  * readbyte -> integer
5065  *
5066  * Reads and returns the next byte (in range 0..255) from the stream;
5067  * raises EOFError if already at end-of-stream.
5068  * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5069  *
5070  * f = File.open('t.txt')
5071  * f.readbyte # => 70
5072  * f.close
5073  * f = File.open('t.rus')
5074  * f.readbyte # => 209
5075  * f.close
5076  *
5077  * Related: IO#getbyte (will not raise EOFError).
5078  *
5079  */
5080 
5081 static VALUE
5082 rb_io_readbyte(VALUE io)
5083 {
5084  VALUE c = rb_io_getbyte(io);
5085 
5086  if (NIL_P(c)) {
5087  rb_eof_error();
5088  }
5089  return c;
5090 }
5091 
5092 /*
5093  * call-seq:
5094  * ungetbyte(integer) -> nil
5095  * ungetbyte(string) -> nil
5096  *
5097  * Pushes back ("unshifts") the given data onto the stream's buffer,
5098  * placing the data so that it is next to be read; returns +nil+.
5099  * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5100  *
5101  * Note that:
5102  *
5103  * - Calling the method has no effect with unbuffered reads (such as IO#sysread).
5104  * - Calling #rewind on the stream discards the pushed-back data.
5105  *
5106  * When argument +integer+ is given, uses only its low-order byte:
5107  *
5108  * File.write('t.tmp', '012')
5109  * f = File.open('t.tmp')
5110  * f.ungetbyte(0x41) # => nil
5111  * f.read # => "A012"
5112  * f.rewind
5113  * f.ungetbyte(0x4243) # => nil
5114  * f.read # => "C012"
5115  * f.close
5116  *
5117  * When argument +string+ is given, uses all bytes:
5118  *
5119  * File.write('t.tmp', '012')
5120  * f = File.open('t.tmp')
5121  * f.ungetbyte('A') # => nil
5122  * f.read # => "A012"
5123  * f.rewind
5124  * f.ungetbyte('BCDE') # => nil
5125  * f.read # => "BCDE012"
5126  * f.close
5127  *
5128  */
5129 
5130 VALUE
5132 {
5133  rb_io_t *fptr;
5134 
5135  GetOpenFile(io, fptr);
5137  switch (TYPE(b)) {
5138  case T_NIL:
5139  return Qnil;
5140  case T_FIXNUM:
5141  case T_BIGNUM: ;
5142  VALUE v = rb_int_modulo(b, INT2FIX(256));
5143  unsigned char c = NUM2INT(v) & 0xFF;
5144  b = rb_str_new((const char *)&c, 1);
5145  break;
5146  default:
5147  StringValue(b);
5148  }
5149  io_ungetbyte(b, fptr);
5150  return Qnil;
5151 }
5152 
5153 /*
5154  * call-seq:
5155  * ungetc(integer) -> nil
5156  * ungetc(string) -> nil
5157  *
5158  * Pushes back ("unshifts") the given data onto the stream's buffer,
5159  * placing the data so that it is next to be read; returns +nil+.
5160  * See {Character IO}[rdoc-ref:IO@Character+IO].
5161  *
5162  * Note that:
5163  *
5164  * - Calling the method has no effect with unbuffered reads (such as IO#sysread).
5165  * - Calling #rewind on the stream discards the pushed-back data.
5166  *
5167  * When argument +integer+ is given, interprets the integer as a character:
5168  *
5169  * File.write('t.tmp', '012')
5170  * f = File.open('t.tmp')
5171  * f.ungetc(0x41) # => nil
5172  * f.read # => "A012"
5173  * f.rewind
5174  * f.ungetc(0x0442) # => nil
5175  * f.getc.ord # => 1090
5176  * f.close
5177  *
5178  * When argument +string+ is given, uses all characters:
5179  *
5180  * File.write('t.tmp', '012')
5181  * f = File.open('t.tmp')
5182  * f.ungetc('A') # => nil
5183  * f.read # => "A012"
5184  * f.rewind
5185  * f.ungetc("\u0442\u0435\u0441\u0442") # => nil
5186  * f.getc.ord # => 1090
5187  * f.getc.ord # => 1077
5188  * f.getc.ord # => 1089
5189  * f.getc.ord # => 1090
5190  * f.close
5191  *
5192  */
5193 
5194 VALUE
5196 {
5197  rb_io_t *fptr;
5198  long len;
5199 
5200  GetOpenFile(io, fptr);
5202  if (FIXNUM_P(c)) {
5203  c = rb_enc_uint_chr(FIX2UINT(c), io_read_encoding(fptr));
5204  }
5205  else if (RB_BIGNUM_TYPE_P(c)) {
5206  c = rb_enc_uint_chr(NUM2UINT(c), io_read_encoding(fptr));
5207  }
5208  else {
5209  StringValue(c);
5210  }
5211  if (NEED_READCONV(fptr)) {
5212  SET_BINARY_MODE(fptr);
5213  len = RSTRING_LEN(c);
5214 #if SIZEOF_LONG > SIZEOF_INT
5215  if (len > INT_MAX)
5216  rb_raise(rb_eIOError, "ungetc failed");
5217 #endif
5218  make_readconv(fptr, (int)len);
5219  if (fptr->cbuf.capa - fptr->cbuf.len < len)
5220  rb_raise(rb_eIOError, "ungetc failed");
5221  if (fptr->cbuf.off < len) {
5222  MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.capa-fptr->cbuf.len,
5223  fptr->cbuf.ptr+fptr->cbuf.off,
5224  char, fptr->cbuf.len);
5225  fptr->cbuf.off = fptr->cbuf.capa-fptr->cbuf.len;
5226  }
5227  fptr->cbuf.off -= (int)len;
5228  fptr->cbuf.len += (int)len;
5229  MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.off, RSTRING_PTR(c), char, len);
5230  }
5231  else {
5232  NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
5233  io_ungetbyte(c, fptr);
5234  }
5235  return Qnil;
5236 }
5237 
5238 /*
5239  * call-seq:
5240  * isatty -> true or false
5241  *
5242  * Returns +true+ if the stream is associated with a terminal device (tty),
5243  * +false+ otherwise:
5244  *
5245  * f = File.new('t.txt').isatty #=> false
5246  * f.close
5247  * f = File.new('/dev/tty').isatty #=> true
5248  * f.close
5249  *
5250  */
5251 
5252 static VALUE
5253 rb_io_isatty(VALUE io)
5254 {
5255  rb_io_t *fptr;
5256 
5257  GetOpenFile(io, fptr);
5258  return RBOOL(isatty(fptr->fd) != 0);
5259 }
5260 
5261 #if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5262 /*
5263  * call-seq:
5264  * close_on_exec? -> true or false
5265  *
5266  * Returns +true+ if the stream will be closed on exec, +false+ otherwise:
5267  *
5268  * f = File.open('t.txt')
5269  * f.close_on_exec? # => true
5270  * f.close_on_exec = false
5271  * f.close_on_exec? # => false
5272  * f.close
5273  *
5274  */
5275 
5276 static VALUE
5277 rb_io_close_on_exec_p(VALUE io)
5278 {
5279  rb_io_t *fptr;
5280  VALUE write_io;
5281  int fd, ret;
5282 
5283  write_io = GetWriteIO(io);
5284  if (io != write_io) {
5285  GetOpenFile(write_io, fptr);
5286  if (fptr && 0 <= (fd = fptr->fd)) {
5287  if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5288  if (!(ret & FD_CLOEXEC)) return Qfalse;
5289  }
5290  }
5291 
5292  GetOpenFile(io, fptr);
5293  if (fptr && 0 <= (fd = fptr->fd)) {
5294  if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5295  if (!(ret & FD_CLOEXEC)) return Qfalse;
5296  }
5297  return Qtrue;
5298 }
5299 #else
5300 #define rb_io_close_on_exec_p rb_f_notimplement
5301 #endif
5302 
5303 #if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5304 /*
5305  * call-seq:
5306  * self.close_on_exec = bool -> true or false
5307  *
5308  * Sets a close-on-exec flag.
5309  *
5310  * f = File.open(File::NULL)
5311  * f.close_on_exec = true
5312  * system("cat", "/proc/self/fd/#{f.fileno}") # cat: /proc/self/fd/3: No such file or directory
5313  * f.closed? #=> false
5314  *
5315  * Ruby sets close-on-exec flags of all file descriptors by default
5316  * since Ruby 2.0.0.
5317  * So you don't need to set by yourself.
5318  * Also, unsetting a close-on-exec flag can cause file descriptor leak
5319  * if another thread use fork() and exec() (via system() method for example).
5320  * If you really needs file descriptor inheritance to child process,
5321  * use spawn()'s argument such as fd=>fd.
5322  */
5323 
5324 static VALUE
5325 rb_io_set_close_on_exec(VALUE io, VALUE arg)
5326 {
5327  int flag = RTEST(arg) ? FD_CLOEXEC : 0;
5328  rb_io_t *fptr;
5329  VALUE write_io;
5330  int fd, ret;
5331 
5332  write_io = GetWriteIO(io);
5333  if (io != write_io) {
5334  GetOpenFile(write_io, fptr);
5335  if (fptr && 0 <= (fd = fptr->fd)) {
5336  if ((ret = fcntl(fptr->fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5337  if ((ret & FD_CLOEXEC) != flag) {
5338  ret = (ret & ~FD_CLOEXEC) | flag;
5339  ret = fcntl(fd, F_SETFD, ret);
5340  if (ret != 0) rb_sys_fail_path(fptr->pathv);
5341  }
5342  }
5343 
5344  }
5345 
5346  GetOpenFile(io, fptr);
5347  if (fptr && 0 <= (fd = fptr->fd)) {
5348  if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5349  if ((ret & FD_CLOEXEC) != flag) {
5350  ret = (ret & ~FD_CLOEXEC) | flag;
5351  ret = fcntl(fd, F_SETFD, ret);
5352  if (ret != 0) rb_sys_fail_path(fptr->pathv);
5353  }
5354  }
5355  return Qnil;
5356 }
5357 #else
5358 #define rb_io_set_close_on_exec rb_f_notimplement
5359 #endif
5360 
5361 #define RUBY_IO_EXTERNAL_P(f) ((f)->mode & FMODE_EXTERNAL)
5362 #define PREP_STDIO_NAME(f) (RSTRING_PTR((f)->pathv))
5363 
5364 static VALUE
5365 finish_writeconv(rb_io_t *fptr, int noalloc)
5366 {
5367  unsigned char *ds, *dp, *de;
5368  rb_econv_result_t res;
5369 
5370  if (!fptr->wbuf.ptr) {
5371  unsigned char buf[1024];
5372 
5374  while (res == econv_destination_buffer_full) {
5375  ds = dp = buf;
5376  de = buf + sizeof(buf);
5377  res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
5378  while (dp-ds) {
5379  size_t remaining = dp-ds;
5380  long result = rb_io_write_memory(fptr, ds, remaining);
5381 
5382  if (result > 0) {
5383  ds += result;
5384  if ((size_t)result == remaining) break;
5385  }
5386  else if (rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
5387  if (fptr->fd < 0)
5388  return noalloc ? Qtrue : rb_exc_new3(rb_eIOError, rb_str_new_cstr(closed_stream));
5389  }
5390  else {
5391  return noalloc ? Qtrue : INT2NUM(errno);
5392  }
5393  }
5394  if (res == econv_invalid_byte_sequence ||
5395  res == econv_incomplete_input ||
5396  res == econv_undefined_conversion) {
5397  return noalloc ? Qtrue : rb_econv_make_exception(fptr->writeconv);
5398  }
5399  }
5400 
5401  return Qnil;
5402  }
5403 
5405  while (res == econv_destination_buffer_full) {
5406  if (fptr->wbuf.len == fptr->wbuf.capa) {
5407  if (io_fflush(fptr) < 0) {
5408  return noalloc ? Qtrue : INT2NUM(errno);
5409  }
5410  }
5411 
5412  ds = dp = (unsigned char *)fptr->wbuf.ptr + fptr->wbuf.off + fptr->wbuf.len;
5413  de = (unsigned char *)fptr->wbuf.ptr + fptr->wbuf.capa;
5414  res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
5415  fptr->wbuf.len += (int)(dp - ds);
5416  if (res == econv_invalid_byte_sequence ||
5417  res == econv_incomplete_input ||
5418  res == econv_undefined_conversion) {
5419  return noalloc ? Qtrue : rb_econv_make_exception(fptr->writeconv);
5420  }
5421  }
5422  return Qnil;
5423 }
5424 
5426  rb_io_t *fptr;
5427  int noalloc;
5428 };
5429 
5430 static VALUE
5431 finish_writeconv_sync(VALUE arg)
5432 {
5433  struct finish_writeconv_arg *p = (struct finish_writeconv_arg *)arg;
5434  return finish_writeconv(p->fptr, p->noalloc);
5435 }
5436 
5437 static void*
5438 nogvl_close(void *ptr)
5439 {
5440  int *fd = ptr;
5441 
5442  return (void*)(intptr_t)close(*fd);
5443 }
5444 
5445 static int
5446 maygvl_close(int fd, int keepgvl)
5447 {
5448  if (keepgvl)
5449  return close(fd);
5450 
5451  /*
5452  * close() may block for certain file types (NFS, SO_LINGER sockets,
5453  * inotify), so let other threads run.
5454  */
5455  return IO_WITHOUT_GVL_INT(nogvl_close, &fd);
5456 }
5457 
5458 static void*
5459 nogvl_fclose(void *ptr)
5460 {
5461  FILE *file = ptr;
5462 
5463  return (void*)(intptr_t)fclose(file);
5464 }
5465 
5466 static int
5467 maygvl_fclose(FILE *file, int keepgvl)
5468 {
5469  if (keepgvl)
5470  return fclose(file);
5471 
5472  return IO_WITHOUT_GVL_INT(nogvl_fclose, file);
5473 }
5474 
5475 static void free_io_buffer(rb_io_buffer_t *buf);
5476 
5477 static void
5478 fptr_finalize_flush(rb_io_t *fptr, int noraise, int keepgvl,
5479  struct rb_io_close_wait_list *busy)
5480 {
5481  VALUE error = Qnil;
5482  int fd = fptr->fd;
5483  FILE *stdio_file = fptr->stdio_file;
5484  int mode = fptr->mode;
5485 
5486  if (fptr->writeconv) {
5487  if (!NIL_P(fptr->write_lock) && !noraise) {
5488  struct finish_writeconv_arg arg;
5489  arg.fptr = fptr;
5490  arg.noalloc = noraise;
5491  error = rb_mutex_synchronize(fptr->write_lock, finish_writeconv_sync, (VALUE)&arg);
5492  }
5493  else {
5494  error = finish_writeconv(fptr, noraise);
5495  }
5496  }
5497  if (fptr->wbuf.len) {
5498  if (noraise) {
5499  io_flush_buffer_sync(fptr);
5500  }
5501  else {
5502  if (io_fflush(fptr) < 0 && NIL_P(error)) {
5503  error = INT2NUM(errno);
5504  }
5505  }
5506  }
5507 
5508  int done = 0;
5509 
5510  if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2) {
5511  // Need to keep FILE objects of stdin, stdout and stderr, so we are done:
5512  done = 1;
5513  }
5514 
5515  fptr->fd = -1;
5516  fptr->stdio_file = 0;
5517  fptr->mode &= ~(FMODE_READABLE|FMODE_WRITABLE);
5518 
5519  // Ensure waiting_fd users do not hit EBADF.
5520  if (busy) {
5521  // Wait for them to exit before we call close().
5522  rb_notify_fd_close_wait(busy);
5523  }
5524 
5525  // Disable for now.
5526  // if (!done && fd >= 0) {
5527  // VALUE scheduler = rb_fiber_scheduler_current();
5528  // if (scheduler != Qnil) {
5529  // VALUE result = rb_fiber_scheduler_io_close(scheduler, fptr->self);
5530  // if (!UNDEF_P(result)) done = 1;
5531  // }
5532  // }
5533 
5534  if (!done && stdio_file) {
5535  // stdio_file is deallocated anyway even if fclose failed.
5536  if ((maygvl_fclose(stdio_file, noraise) < 0) && NIL_P(error)) {
5537  if (!noraise) {
5538  error = INT2NUM(errno);
5539  }
5540  }
5541 
5542  done = 1;
5543  }
5544 
5545  if (!done && fd >= 0) {
5546  // fptr->fd may be closed even if close fails. POSIX doesn't specify it.
5547  // We assumes it is closed.
5548 
5549  keepgvl |= !(mode & FMODE_WRITABLE);
5550  keepgvl |= noraise;
5551  if ((maygvl_close(fd, keepgvl) < 0) && NIL_P(error)) {
5552  if (!noraise) {
5553  error = INT2NUM(errno);
5554  }
5555  }
5556 
5557  done = 1;
5558  }
5559 
5560  if (!NIL_P(error) && !noraise) {
5561  if (RB_INTEGER_TYPE_P(error))
5562  rb_syserr_fail_path(NUM2INT(error), fptr->pathv);
5563  else
5564  rb_exc_raise(error);
5565  }
5566 }
5567 
5568 static void
5569 fptr_finalize(rb_io_t *fptr, int noraise)
5570 {
5571  fptr_finalize_flush(fptr, noraise, FALSE, 0);
5572  free_io_buffer(&fptr->rbuf);
5573  free_io_buffer(&fptr->wbuf);
5574  clear_codeconv(fptr);
5575 }
5576 
5577 static void
5578 rb_io_fptr_cleanup(rb_io_t *fptr, int noraise)
5579 {
5580  if (fptr->finalize) {
5581  (*fptr->finalize)(fptr, noraise);
5582  }
5583  else {
5584  fptr_finalize(fptr, noraise);
5585  }
5586 }
5587 
5588 static void
5589 free_io_buffer(rb_io_buffer_t *buf)
5590 {
5591  if (buf->ptr) {
5592  ruby_sized_xfree(buf->ptr, (size_t)buf->capa);
5593  buf->ptr = NULL;
5594  }
5595 }
5596 
5597 static void
5598 clear_readconv(rb_io_t *fptr)
5599 {
5600  if (fptr->readconv) {
5601  rb_econv_close(fptr->readconv);
5602  fptr->readconv = NULL;
5603  }
5604  free_io_buffer(&fptr->cbuf);
5605 }
5606 
5607 static void
5608 clear_writeconv(rb_io_t *fptr)
5609 {
5610  if (fptr->writeconv) {
5611  rb_econv_close(fptr->writeconv);
5612  fptr->writeconv = NULL;
5613  }
5614  fptr->writeconv_initialized = 0;
5615 }
5616 
5617 static void
5618 clear_codeconv(rb_io_t *fptr)
5619 {
5620  clear_readconv(fptr);
5621  clear_writeconv(fptr);
5622 }
5623 
5624 static void
5625 rb_io_fptr_cleanup_all(rb_io_t *fptr)
5626 {
5627  fptr->pathv = Qnil;
5628  if (0 <= fptr->fd)
5629  rb_io_fptr_cleanup(fptr, TRUE);
5630  fptr->write_lock = Qnil;
5631  free_io_buffer(&fptr->rbuf);
5632  free_io_buffer(&fptr->wbuf);
5633  clear_codeconv(fptr);
5634 }
5635 
5636 void
5637 rb_io_fptr_finalize_internal(void *ptr)
5638 {
5639  if (!ptr) return;
5640  rb_io_fptr_cleanup_all(ptr);
5641  free(ptr);
5642 }
5643 
5644 #undef rb_io_fptr_finalize
5645 int
5647 {
5648  if (!fptr) {
5649  return 0;
5650  }
5651  else {
5652  rb_io_fptr_finalize_internal(fptr);
5653  return 1;
5654  }
5655 }
5656 #define rb_io_fptr_finalize(fptr) rb_io_fptr_finalize_internal(fptr)
5657 
5658 size_t
5659 rb_io_memsize(const rb_io_t *fptr)
5660 {
5661  size_t size = sizeof(rb_io_t);
5662  size += fptr->rbuf.capa;
5663  size += fptr->wbuf.capa;
5664  size += fptr->cbuf.capa;
5665  if (fptr->readconv) size += rb_econv_memsize(fptr->readconv);
5666  if (fptr->writeconv) size += rb_econv_memsize(fptr->writeconv);
5667  return size;
5668 }
5669 
5670 #ifdef _WIN32
5671 /* keep GVL while closing to prevent crash on Windows */
5672 # define KEEPGVL TRUE
5673 #else
5674 # define KEEPGVL FALSE
5675 #endif
5676 
5677 static rb_io_t *
5678 io_close_fptr(VALUE io)
5679 {
5680  rb_io_t *fptr;
5681  VALUE write_io;
5682  rb_io_t *write_fptr;
5683  struct rb_io_close_wait_list busy;
5684 
5685  write_io = GetWriteIO(io);
5686  if (io != write_io) {
5687  write_fptr = RFILE(write_io)->fptr;
5688  if (write_fptr && 0 <= write_fptr->fd) {
5689  rb_io_fptr_cleanup(write_fptr, TRUE);
5690  }
5691  }
5692 
5693  fptr = RFILE(io)->fptr;
5694  if (!fptr) return 0;
5695  if (fptr->fd < 0) return 0;
5696 
5697  if (rb_notify_fd_close(fptr->fd, &busy)) {
5698  /* calls close(fptr->fd): */
5699  fptr_finalize_flush(fptr, FALSE, KEEPGVL, &busy);
5700  }
5701  rb_io_fptr_cleanup(fptr, FALSE);
5702  return fptr;
5703 }
5704 
5705 static void
5706 fptr_waitpid(rb_io_t *fptr, int nohang)
5707 {
5708  int status;
5709  if (fptr->pid) {
5710  rb_last_status_clear();
5711  rb_waitpid(fptr->pid, &status, nohang ? WNOHANG : 0);
5712  fptr->pid = 0;
5713  }
5714 }
5715 
5716 VALUE
5718 {
5719  rb_io_t *fptr = io_close_fptr(io);
5720  if (fptr) fptr_waitpid(fptr, 0);
5721  return Qnil;
5722 }
5723 
5724 /*
5725  * call-seq:
5726  * close -> nil
5727  *
5728  * Closes the stream for both reading and writing
5729  * if open for either or both; returns +nil+.
5730  * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5731  *
5732  * If the stream is open for writing, flushes any buffered writes
5733  * to the operating system before closing.
5734  *
5735  * If the stream was opened by IO.popen, sets global variable <tt>$?</tt>
5736  * (child exit status).
5737  *
5738  * It is not an error to close an IO object that has already been closed.
5739  * It just returns nil.
5740  *
5741  * Example:
5742  *
5743  * IO.popen('ruby', 'r+') do |pipe|
5744  * puts pipe.closed?
5745  * pipe.close
5746  * puts $?
5747  * puts pipe.closed?
5748  * end
5749  *
5750  * Output:
5751  *
5752  * false
5753  * pid 13760 exit 0
5754  * true
5755  *
5756  * Related: IO#close_read, IO#close_write, IO#closed?.
5757  */
5758 
5759 static VALUE
5760 rb_io_close_m(VALUE io)
5761 {
5762  rb_io_t *fptr = rb_io_get_fptr(io);
5763  if (fptr->fd < 0) {
5764  return Qnil;
5765  }
5766  rb_io_close(io);
5767  return Qnil;
5768 }
5769 
5770 static VALUE
5771 io_call_close(VALUE io)
5772 {
5773  rb_check_funcall(io, rb_intern("close"), 0, 0);
5774  return io;
5775 }
5776 
5777 static VALUE
5778 ignore_closed_stream(VALUE io, VALUE exc)
5779 {
5780  enum {mesg_len = sizeof(closed_stream)-1};
5781  VALUE mesg = rb_attr_get(exc, idMesg);
5782  if (!RB_TYPE_P(mesg, T_STRING) ||
5783  RSTRING_LEN(mesg) != mesg_len ||
5784  memcmp(RSTRING_PTR(mesg), closed_stream, mesg_len)) {
5785  rb_exc_raise(exc);
5786  }
5787  return io;
5788 }
5789 
5790 static VALUE
5791 io_close(VALUE io)
5792 {
5793  VALUE closed = rb_check_funcall(io, rb_intern("closed?"), 0, 0);
5794  if (!UNDEF_P(closed) && RTEST(closed)) return io;
5795  rb_rescue2(io_call_close, io, ignore_closed_stream, io,
5796  rb_eIOError, (VALUE)0);
5797  return io;
5798 }
5799 
5800 /*
5801  * call-seq:
5802  * closed? -> true or false
5803  *
5804  * Returns +true+ if the stream is closed for both reading and writing,
5805  * +false+ otherwise.
5806  * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5807  *
5808  * IO.popen('ruby', 'r+') do |pipe|
5809  * puts pipe.closed?
5810  * pipe.close_read
5811  * puts pipe.closed?
5812  * pipe.close_write
5813  * puts pipe.closed?
5814  * end
5815  *
5816  * Output:
5817  *
5818  * false
5819  * false
5820  * true
5821  *
5822  * Related: IO#close_read, IO#close_write, IO#close.
5823  */
5824 VALUE
5826 {
5827  rb_io_t *fptr;
5828  VALUE write_io;
5829  rb_io_t *write_fptr;
5830 
5831  write_io = GetWriteIO(io);
5832  if (io != write_io) {
5833  write_fptr = RFILE(write_io)->fptr;
5834  if (write_fptr && 0 <= write_fptr->fd) {
5835  return Qfalse;
5836  }
5837  }
5838 
5839  fptr = rb_io_get_fptr(io);
5840  return RBOOL(0 > fptr->fd);
5841 }
5842 
5843 /*
5844  * call-seq:
5845  * close_read -> nil
5846  *
5847  * Closes the stream for reading if open for reading;
5848  * returns +nil+.
5849  * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5850  *
5851  * If the stream was opened by IO.popen and is also closed for writing,
5852  * sets global variable <tt>$?</tt> (child exit status).
5853  *
5854  * Example:
5855  *
5856  * IO.popen('ruby', 'r+') do |pipe|
5857  * puts pipe.closed?
5858  * pipe.close_write
5859  * puts pipe.closed?
5860  * pipe.close_read
5861  * puts $?
5862  * puts pipe.closed?
5863  * end
5864  *
5865  * Output:
5866  *
5867  * false
5868  * false
5869  * pid 14748 exit 0
5870  * true
5871  *
5872  * Related: IO#close, IO#close_write, IO#closed?.
5873  */
5874 
5875 static VALUE
5876 rb_io_close_read(VALUE io)
5877 {
5878  rb_io_t *fptr;
5879  VALUE write_io;
5880 
5881  fptr = rb_io_get_fptr(rb_io_taint_check(io));
5882  if (fptr->fd < 0) return Qnil;
5883  if (is_socket(fptr->fd, fptr->pathv)) {
5884 #ifndef SHUT_RD
5885 # define SHUT_RD 0
5886 #endif
5887  if (shutdown(fptr->fd, SHUT_RD) < 0)
5888  rb_sys_fail_path(fptr->pathv);
5889  fptr->mode &= ~FMODE_READABLE;
5890  if (!(fptr->mode & FMODE_WRITABLE))
5891  return rb_io_close(io);
5892  return Qnil;
5893  }
5894 
5895  write_io = GetWriteIO(io);
5896  if (io != write_io) {
5897  rb_io_t *wfptr;
5898  wfptr = rb_io_get_fptr(rb_io_taint_check(write_io));
5899  wfptr->pid = fptr->pid;
5900  fptr->pid = 0;
5901  RFILE(io)->fptr = wfptr;
5902  /* bind to write_io temporarily to get rid of memory/fd leak */
5903  fptr->tied_io_for_writing = 0;
5904  RFILE(write_io)->fptr = fptr;
5905  rb_io_fptr_cleanup(fptr, FALSE);
5906  /* should not finalize fptr because another thread may be reading it */
5907  return Qnil;
5908  }
5909 
5910  if ((fptr->mode & (FMODE_DUPLEX|FMODE_WRITABLE)) == FMODE_WRITABLE) {
5911  rb_raise(rb_eIOError, "closing non-duplex IO for reading");
5912  }
5913  return rb_io_close(io);
5914 }
5915 
5916 /*
5917  * call-seq:
5918  * close_write -> nil
5919  *
5920  * Closes the stream for writing if open for writing;
5921  * returns +nil+.
5922  * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5923  *
5924  * Flushes any buffered writes to the operating system before closing.
5925  *
5926  * If the stream was opened by IO.popen and is also closed for reading,
5927  * sets global variable <tt>$?</tt> (child exit status).
5928  *
5929  * IO.popen('ruby', 'r+') do |pipe|
5930  * puts pipe.closed?
5931  * pipe.close_read
5932  * puts pipe.closed?
5933  * pipe.close_write
5934  * puts $?
5935  * puts pipe.closed?
5936  * end
5937  *
5938  * Output:
5939  *
5940  * false
5941  * false
5942  * pid 15044 exit 0
5943  * true
5944  *
5945  * Related: IO#close, IO#close_read, IO#closed?.
5946  */
5947 
5948 static VALUE
5949 rb_io_close_write(VALUE io)
5950 {
5951  rb_io_t *fptr;
5952  VALUE write_io;
5953 
5954  write_io = GetWriteIO(io);
5955  fptr = rb_io_get_fptr(rb_io_taint_check(write_io));
5956  if (fptr->fd < 0) return Qnil;
5957  if (is_socket(fptr->fd, fptr->pathv)) {
5958 #ifndef SHUT_WR
5959 # define SHUT_WR 1
5960 #endif
5961  if (shutdown(fptr->fd, SHUT_WR) < 0)
5962  rb_sys_fail_path(fptr->pathv);
5963  fptr->mode &= ~FMODE_WRITABLE;
5964  if (!(fptr->mode & FMODE_READABLE))
5965  return rb_io_close(write_io);
5966  return Qnil;
5967  }
5968 
5969  if ((fptr->mode & (FMODE_DUPLEX|FMODE_READABLE)) == FMODE_READABLE) {
5970  rb_raise(rb_eIOError, "closing non-duplex IO for writing");
5971  }
5972 
5973  if (io != write_io) {
5974  fptr = rb_io_get_fptr(rb_io_taint_check(io));
5975  fptr->tied_io_for_writing = 0;
5976  }
5977  rb_io_close(write_io);
5978  return Qnil;
5979 }
5980 
5981 /*
5982  * call-seq:
5983  * sysseek(offset, whence = IO::SEEK_SET) -> integer
5984  *
5985  * Behaves like IO#seek, except that it:
5986  *
5987  * - Uses low-level system functions.
5988  * - Returns the new position.
5989  *
5990  */
5991 
5992 static VALUE
5993 rb_io_sysseek(int argc, VALUE *argv, VALUE io)
5994 {
5995  VALUE offset, ptrname;
5996  int whence = SEEK_SET;
5997  rb_io_t *fptr;
5998  rb_off_t pos;
5999 
6000  if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
6001  whence = interpret_seek_whence(ptrname);
6002  }
6003  pos = NUM2OFFT(offset);
6004  GetOpenFile(io, fptr);
6005  if ((fptr->mode & FMODE_READABLE) &&
6006  (READ_DATA_BUFFERED(fptr) || READ_CHAR_PENDING(fptr))) {
6007  rb_raise(rb_eIOError, "sysseek for buffered IO");
6008  }
6009  if ((fptr->mode & FMODE_WRITABLE) && fptr->wbuf.len) {
6010  rb_warn("sysseek for buffered IO");
6011  }
6012  errno = 0;
6013  pos = lseek(fptr->fd, pos, whence);
6014  if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
6015 
6016  return OFFT2NUM(pos);
6017 }
6018 
6019 /*
6020  * call-seq:
6021  * syswrite(object) -> integer
6022  *
6023  * Writes the given +object+ to self, which must be opened for writing (see Modes);
6024  * returns the number bytes written.
6025  * If +object+ is not a string is converted via method to_s:
6026  *
6027  * f = File.new('t.tmp', 'w')
6028  * f.syswrite('foo') # => 3
6029  * f.syswrite(30) # => 2
6030  * f.syswrite(:foo) # => 3
6031  * f.close
6032  *
6033  * This methods should not be used with other stream-writer methods.
6034  *
6035  */
6036 
6037 static VALUE
6038 rb_io_syswrite(VALUE io, VALUE str)
6039 {
6040  VALUE tmp;
6041  rb_io_t *fptr;
6042  long n, len;
6043  const char *ptr;
6044 
6045  if (!RB_TYPE_P(str, T_STRING))
6046  str = rb_obj_as_string(str);
6047 
6048  io = GetWriteIO(io);
6049  GetOpenFile(io, fptr);
6050  rb_io_check_writable(fptr);
6051 
6052  if (fptr->wbuf.len) {
6053  rb_warn("syswrite for buffered IO");
6054  }
6055 
6056  tmp = rb_str_tmp_frozen_acquire(str);
6057  RSTRING_GETMEM(tmp, ptr, len);
6058  n = rb_io_write_memory(fptr, ptr, len);
6059  if (n < 0) rb_sys_fail_path(fptr->pathv);
6060  rb_str_tmp_frozen_release(str, tmp);
6061 
6062  return LONG2FIX(n);
6063 }
6064 
6065 /*
6066  * call-seq:
6067  * sysread(maxlen) -> string
6068  * sysread(maxlen, out_string) -> string
6069  *
6070  * Behaves like IO#readpartial, except that it uses low-level system functions.
6071  *
6072  * This method should not be used with other stream-reader methods.
6073  *
6074  */
6075 
6076 static VALUE
6077 rb_io_sysread(int argc, VALUE *argv, VALUE io)
6078 {
6079  VALUE len, str;
6080  rb_io_t *fptr;
6081  long n, ilen;
6082  struct io_internal_read_struct iis;
6083  int shrinkable;
6084 
6085  rb_scan_args(argc, argv, "11", &len, &str);
6086  ilen = NUM2LONG(len);
6087 
6088  shrinkable = io_setstrbuf(&str, ilen);
6089  if (ilen == 0) return str;
6090 
6091  GetOpenFile(io, fptr);
6093 
6094  if (READ_DATA_BUFFERED(fptr)) {
6095  rb_raise(rb_eIOError, "sysread for buffered IO");
6096  }
6097 
6098  rb_io_check_closed(fptr);
6099 
6100  io_setstrbuf(&str, ilen);
6101  iis.th = rb_thread_current();
6102  iis.fptr = fptr;
6103  iis.nonblock = 0;
6104  iis.fd = fptr->fd;
6105  iis.buf = RSTRING_PTR(str);
6106  iis.capa = ilen;
6107  iis.timeout = NULL;
6108  n = io_read_memory_locktmp(str, &iis);
6109 
6110  if (n < 0) {
6111  rb_sys_fail_path(fptr->pathv);
6112  }
6113 
6114  io_set_read_length(str, n, shrinkable);
6115 
6116  if (n == 0 && ilen > 0) {
6117  rb_eof_error();
6118  }
6119 
6120  return str;
6121 }
6122 
6124  struct rb_io *io;
6125  int fd;
6126  void *buf;
6127  size_t count;
6128  rb_off_t offset;
6129 };
6130 
6131 static VALUE
6132 internal_pread_func(void *_arg)
6133 {
6134  struct prdwr_internal_arg *arg = _arg;
6135 
6136  return (VALUE)pread(arg->fd, arg->buf, arg->count, arg->offset);
6137 }
6138 
6139 static VALUE
6140 pread_internal_call(VALUE _arg)
6141 {
6142  struct prdwr_internal_arg *arg = (struct prdwr_internal_arg *)_arg;
6143 
6144  VALUE scheduler = rb_fiber_scheduler_current();
6145  if (scheduler != Qnil) {
6146  VALUE result = rb_fiber_scheduler_io_pread_memory(scheduler, arg->io->self, arg->offset, arg->buf, arg->count, 0);
6147 
6148  if (!UNDEF_P(result)) {
6149  return rb_fiber_scheduler_io_result_apply(result);
6150  }
6151  }
6152 
6153  return rb_io_blocking_region_wait(arg->io, internal_pread_func, arg, RUBY_IO_READABLE);
6154 }
6155 
6156 /*
6157  * call-seq:
6158  * pread(maxlen, offset) -> string
6159  * pread(maxlen, offset, out_string) -> string
6160  *
6161  * Behaves like IO#readpartial, except that it:
6162  *
6163  * - Reads at the given +offset+ (in bytes).
6164  * - Disregards, and does not modify, the stream's position
6165  * (see {Position}[rdoc-ref:IO@Position]).
6166  * - Bypasses any user space buffering in the stream.
6167  *
6168  * Because this method does not disturb the stream's state
6169  * (its position, in particular), +pread+ allows multiple threads and processes
6170  * to use the same \IO object for reading at various offsets.
6171  *
6172  * f = File.open('t.txt')
6173  * f.read # => "First line\nSecond line\n\nFourth line\nFifth line\n"
6174  * f.pos # => 52
6175  * # Read 12 bytes at offset 0.
6176  * f.pread(12, 0) # => "First line\n"
6177  * # Read 9 bytes at offset 8.
6178  * f.pread(9, 8) # => "ne\nSecon"
6179  * f.close
6180  *
6181  * Not available on some platforms.
6182  *
6183  */
6184 static VALUE
6185 rb_io_pread(int argc, VALUE *argv, VALUE io)
6186 {
6187  VALUE len, offset, str;
6188  rb_io_t *fptr;
6189  ssize_t n;
6190  struct prdwr_internal_arg arg;
6191  int shrinkable;
6192 
6193  rb_scan_args(argc, argv, "21", &len, &offset, &str);
6194  arg.count = NUM2SIZET(len);
6195  arg.offset = NUM2OFFT(offset);
6196 
6197  shrinkable = io_setstrbuf(&str, (long)arg.count);
6198  if (arg.count == 0) return str;
6199  arg.buf = RSTRING_PTR(str);
6200 
6201  GetOpenFile(io, fptr);
6203 
6204  arg.io = fptr;
6205  arg.fd = fptr->fd;
6206  rb_io_check_closed(fptr);
6207 
6208  rb_str_locktmp(str);
6209  n = (ssize_t)rb_ensure(pread_internal_call, (VALUE)&arg, rb_str_unlocktmp, str);
6210 
6211  if (n < 0) {
6212  rb_sys_fail_path(fptr->pathv);
6213  }
6214  io_set_read_length(str, n, shrinkable);
6215  if (n == 0 && arg.count > 0) {
6216  rb_eof_error();
6217  }
6218 
6219  return str;
6220 }
6221 
6222 static VALUE
6223 internal_pwrite_func(void *_arg)
6224 {
6225  struct prdwr_internal_arg *arg = _arg;
6226 
6227  VALUE scheduler = rb_fiber_scheduler_current();
6228  if (scheduler != Qnil) {
6229  VALUE result = rb_fiber_scheduler_io_pwrite_memory(scheduler, arg->io->self, arg->offset, arg->buf, arg->count, 0);
6230 
6231  if (!UNDEF_P(result)) {
6232  return rb_fiber_scheduler_io_result_apply(result);
6233  }
6234  }
6235 
6236 
6237  return (VALUE)pwrite(arg->fd, arg->buf, arg->count, arg->offset);
6238 }
6239 
6240 /*
6241  * call-seq:
6242  * pwrite(object, offset) -> integer
6243  *
6244  * Behaves like IO#write, except that it:
6245  *
6246  * - Writes at the given +offset+ (in bytes).
6247  * - Disregards, and does not modify, the stream's position
6248  * (see {Position}[rdoc-ref:IO@Position]).
6249  * - Bypasses any user space buffering in the stream.
6250  *
6251  * Because this method does not disturb the stream's state
6252  * (its position, in particular), +pwrite+ allows multiple threads and processes
6253  * to use the same \IO object for writing at various offsets.
6254  *
6255  * f = File.open('t.tmp', 'w+')
6256  * # Write 6 bytes at offset 3.
6257  * f.pwrite('ABCDEF', 3) # => 6
6258  * f.rewind
6259  * f.read # => "\u0000\u0000\u0000ABCDEF"
6260  * f.close
6261  *
6262  * Not available on some platforms.
6263  *
6264  */
6265 static VALUE
6266 rb_io_pwrite(VALUE io, VALUE str, VALUE offset)
6267 {
6268  rb_io_t *fptr;
6269  ssize_t n;
6270  struct prdwr_internal_arg arg;
6271  VALUE tmp;
6272 
6273  if (!RB_TYPE_P(str, T_STRING))
6274  str = rb_obj_as_string(str);
6275 
6276  arg.offset = NUM2OFFT(offset);
6277 
6278  io = GetWriteIO(io);
6279  GetOpenFile(io, fptr);
6280  rb_io_check_writable(fptr);
6281 
6282  arg.io = fptr;
6283  arg.fd = fptr->fd;
6284 
6285  tmp = rb_str_tmp_frozen_acquire(str);
6286  arg.buf = RSTRING_PTR(tmp);
6287  arg.count = (size_t)RSTRING_LEN(tmp);
6288 
6289  n = (ssize_t)rb_io_blocking_region_wait(fptr, internal_pwrite_func, &arg, RUBY_IO_WRITABLE);
6290  if (n < 0) rb_sys_fail_path(fptr->pathv);
6291  rb_str_tmp_frozen_release(str, tmp);
6292 
6293  return SSIZET2NUM(n);
6294 }
6295 
6296 VALUE
6298 {
6299  rb_io_t *fptr;
6300 
6301  GetOpenFile(io, fptr);
6302  if (fptr->readconv)
6303  rb_econv_binmode(fptr->readconv);
6304  if (fptr->writeconv)
6305  rb_econv_binmode(fptr->writeconv);
6306  fptr->mode |= FMODE_BINMODE;
6307  fptr->mode &= ~FMODE_TEXTMODE;
6309 #ifdef O_BINARY
6310  if (!fptr->readconv) {
6311  SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6312  }
6313  else {
6314  setmode(fptr->fd, O_BINARY);
6315  }
6316 #endif
6317  return io;
6318 }
6319 
6320 static void
6321 io_ascii8bit_binmode(rb_io_t *fptr)
6322 {
6323  if (fptr->readconv) {
6324  rb_econv_close(fptr->readconv);
6325  fptr->readconv = NULL;
6326  }
6327  if (fptr->writeconv) {
6328  rb_econv_close(fptr->writeconv);
6329  fptr->writeconv = NULL;
6330  }
6331  fptr->mode |= FMODE_BINMODE;
6332  fptr->mode &= ~FMODE_TEXTMODE;
6333  SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6334 
6335  fptr->encs.enc = rb_ascii8bit_encoding();
6336  fptr->encs.enc2 = NULL;
6337  fptr->encs.ecflags = 0;
6338  fptr->encs.ecopts = Qnil;
6339  clear_codeconv(fptr);
6340 }
6341 
6342 VALUE
6344 {
6345  rb_io_t *fptr;
6346 
6347  GetOpenFile(io, fptr);
6348  io_ascii8bit_binmode(fptr);
6349 
6350  return io;
6351 }
6352 
6353 /*
6354  * call-seq:
6355  * binmode -> self
6356  *
6357  * Sets the stream's data mode as binary
6358  * (see {Data Mode}[rdoc-ref:File@Data+Mode]).
6359  *
6360  * A stream's data mode may not be changed from binary to text.
6361  *
6362  */
6363 
6364 static VALUE
6365 rb_io_binmode_m(VALUE io)
6366 {
6367  VALUE write_io;
6368 
6370 
6371  write_io = GetWriteIO(io);
6372  if (write_io != io)
6373  rb_io_ascii8bit_binmode(write_io);
6374  return io;
6375 }
6376 
6377 /*
6378  * call-seq:
6379  * binmode? -> true or false
6380  *
6381  * Returns +true+ if the stream is on binary mode, +false+ otherwise.
6382  * See {Data Mode}[rdoc-ref:File@Data+Mode].
6383  *
6384  */
6385 static VALUE
6386 rb_io_binmode_p(VALUE io)
6387 {
6388  rb_io_t *fptr;
6389  GetOpenFile(io, fptr);
6390  return RBOOL(fptr->mode & FMODE_BINMODE);
6391 }
6392 
6393 static const char*
6394 rb_io_fmode_modestr(int fmode)
6395 {
6396  if (fmode & FMODE_APPEND) {
6397  if ((fmode & FMODE_READWRITE) == FMODE_READWRITE) {
6398  return MODE_BTMODE("a+", "ab+", "at+");
6399  }
6400  return MODE_BTMODE("a", "ab", "at");
6401  }
6402  switch (fmode & FMODE_READWRITE) {
6403  default:
6404  rb_raise(rb_eArgError, "invalid access fmode 0x%x", fmode);
6405  case FMODE_READABLE:
6406  return MODE_BTMODE("r", "rb", "rt");
6407  case FMODE_WRITABLE:
6408  return MODE_BTXMODE("w", "wb", "wt", "wx", "wbx", "wtx");
6409  case FMODE_READWRITE:
6410  if (fmode & FMODE_CREATE) {
6411  return MODE_BTXMODE("w+", "wb+", "wt+", "w+x", "wb+x", "wt+x");
6412  }
6413  return MODE_BTMODE("r+", "rb+", "rt+");
6414  }
6415 }
6416 
6417 static const char bom_prefix[] = "bom|";
6418 static const char utf_prefix[] = "utf-";
6419 enum {bom_prefix_len = (int)sizeof(bom_prefix) - 1};
6420 enum {utf_prefix_len = (int)sizeof(utf_prefix) - 1};
6421 
6422 static int
6423 io_encname_bom_p(const char *name, long len)
6424 {
6425  return len > bom_prefix_len && STRNCASECMP(name, bom_prefix, bom_prefix_len) == 0;
6426 }
6427 
6428 int
6429 rb_io_modestr_fmode(const char *modestr)
6430 {
6431  int fmode = 0;
6432  const char *m = modestr, *p = NULL;
6433 
6434  switch (*m++) {
6435  case 'r':
6436  fmode |= FMODE_READABLE;
6437  break;
6438  case 'w':
6440  break;
6441  case 'a':
6443  break;
6444  default:
6445  goto error;
6446  }
6447 
6448  while (*m) {
6449  switch (*m++) {
6450  case 'b':
6451  fmode |= FMODE_BINMODE;
6452  break;
6453  case 't':
6454  fmode |= FMODE_TEXTMODE;
6455  break;
6456  case '+':
6457  fmode |= FMODE_READWRITE;
6458  break;
6459  case 'x':
6460  if (modestr[0] != 'w')
6461  goto error;
6462  fmode |= FMODE_EXCL;
6463  break;
6464  default:
6465  goto error;
6466  case ':':
6467  p = strchr(m, ':');
6468  if (io_encname_bom_p(m, p ? (long)(p - m) : (long)strlen(m)))
6469  fmode |= FMODE_SETENC_BY_BOM;
6470  goto finished;
6471  }
6472  }
6473 
6474  finished:
6475  if ((fmode & FMODE_BINMODE) && (fmode & FMODE_TEXTMODE))
6476  goto error;
6477 
6478  return fmode;
6479 
6480  error:
6481  rb_raise(rb_eArgError, "invalid access mode %s", modestr);
6483 }
6484 
6485 int
6486 rb_io_oflags_fmode(int oflags)
6487 {
6488  int fmode = 0;
6489 
6490  switch (oflags & O_ACCMODE) {
6491  case O_RDONLY:
6492  fmode = FMODE_READABLE;
6493  break;
6494  case O_WRONLY:
6495  fmode = FMODE_WRITABLE;
6496  break;
6497  case O_RDWR:
6498  fmode = FMODE_READWRITE;
6499  break;
6500  }
6501 
6502  if (oflags & O_APPEND) {
6503  fmode |= FMODE_APPEND;
6504  }
6505  if (oflags & O_TRUNC) {
6506  fmode |= FMODE_TRUNC;
6507  }
6508  if (oflags & O_CREAT) {
6509  fmode |= FMODE_CREATE;
6510  }
6511  if (oflags & O_EXCL) {
6512  fmode |= FMODE_EXCL;
6513  }
6514 #ifdef O_BINARY
6515  if (oflags & O_BINARY) {
6516  fmode |= FMODE_BINMODE;
6517  }
6518 #endif
6519 
6520  return fmode;
6521 }
6522 
6523 static int
6524 rb_io_fmode_oflags(int fmode)
6525 {
6526  int oflags = 0;
6527 
6528  switch (fmode & FMODE_READWRITE) {
6529  case FMODE_READABLE:
6530  oflags |= O_RDONLY;
6531  break;
6532  case FMODE_WRITABLE:
6533  oflags |= O_WRONLY;
6534  break;
6535  case FMODE_READWRITE:
6536  oflags |= O_RDWR;
6537  break;
6538  }
6539 
6540  if (fmode & FMODE_APPEND) {
6541  oflags |= O_APPEND;
6542  }
6543  if (fmode & FMODE_TRUNC) {
6544  oflags |= O_TRUNC;
6545  }
6546  if (fmode & FMODE_CREATE) {
6547  oflags |= O_CREAT;
6548  }
6549  if (fmode & FMODE_EXCL) {
6550  oflags |= O_EXCL;
6551  }
6552 #ifdef O_BINARY
6553  if (fmode & FMODE_BINMODE) {
6554  oflags |= O_BINARY;
6555  }
6556 #endif
6557 
6558  return oflags;
6559 }
6560 
6561 int
6562 rb_io_modestr_oflags(const char *modestr)
6563 {
6564  return rb_io_fmode_oflags(rb_io_modestr_fmode(modestr));
6565 }
6566 
6567 static const char*
6568 rb_io_oflags_modestr(int oflags)
6569 {
6570 #ifdef O_BINARY
6571 # define MODE_BINARY(a,b) ((oflags & O_BINARY) ? (b) : (a))
6572 #else
6573 # define MODE_BINARY(a,b) (a)
6574 #endif
6575  int accmode;
6576  if (oflags & O_EXCL) {
6577  rb_raise(rb_eArgError, "exclusive access mode is not supported");
6578  }
6579  accmode = oflags & (O_RDONLY|O_WRONLY|O_RDWR);
6580  if (oflags & O_APPEND) {
6581  if (accmode == O_WRONLY) {
6582  return MODE_BINARY("a", "ab");
6583  }
6584  if (accmode == O_RDWR) {
6585  return MODE_BINARY("a+", "ab+");
6586  }
6587  }
6588  switch (accmode) {
6589  default:
6590  rb_raise(rb_eArgError, "invalid access oflags 0x%x", oflags);
6591  case O_RDONLY:
6592  return MODE_BINARY("r", "rb");
6593  case O_WRONLY:
6594  return MODE_BINARY("w", "wb");
6595  case O_RDWR:
6596  if (oflags & O_TRUNC) {
6597  return MODE_BINARY("w+", "wb+");
6598  }
6599  return MODE_BINARY("r+", "rb+");
6600  }
6601 }
6602 
6603 /*
6604  * Convert external/internal encodings to enc/enc2
6605  * NULL => use default encoding
6606  * Qnil => no encoding specified (internal only)
6607  */
6608 static void
6609 rb_io_ext_int_to_encs(rb_encoding *ext, rb_encoding *intern, rb_encoding **enc, rb_encoding **enc2, int fmode)
6610 {
6611  int default_ext = 0;
6612 
6613  if (ext == NULL) {
6615  default_ext = 1;
6616  }
6617  if (rb_is_ascii8bit_enc(ext)) {
6618  /* If external is ASCII-8BIT, no transcoding */
6619  intern = NULL;
6620  }
6621  else if (intern == NULL) {
6622  intern = rb_default_internal_encoding();
6623  }
6624  if (intern == NULL || intern == (rb_encoding *)Qnil ||
6625  (!(fmode & FMODE_SETENC_BY_BOM) && (intern == ext))) {
6626  /* No internal encoding => use external + no transcoding */
6627  *enc = (default_ext && intern != ext) ? NULL : ext;
6628  *enc2 = NULL;
6629  }
6630  else {
6631  *enc = intern;
6632  *enc2 = ext;
6633  }
6634 }
6635 
6636 static void
6637 unsupported_encoding(const char *name, rb_encoding *enc)
6638 {
6639  rb_enc_warn(enc, "Unsupported encoding %s ignored", name);
6640 }
6641 
6642 static void
6643 parse_mode_enc(const char *estr, rb_encoding *estr_enc,
6644  rb_encoding **enc_p, rb_encoding **enc2_p, int *fmode_p)
6645 {
6646  const char *p;
6647  char encname[ENCODING_MAXNAMELEN+1];
6648  int idx, idx2;
6649  int fmode = fmode_p ? *fmode_p : 0;
6650  rb_encoding *ext_enc, *int_enc;
6651  long len;
6652 
6653  /* parse estr as "enc" or "enc2:enc" or "enc:-" */
6654 
6655  p = strrchr(estr, ':');
6656  len = p ? (p++ - estr) : (long)strlen(estr);
6657  if ((fmode & FMODE_SETENC_BY_BOM) || io_encname_bom_p(estr, len)) {
6658  estr += bom_prefix_len;
6659  len -= bom_prefix_len;
6660  if (!STRNCASECMP(estr, utf_prefix, utf_prefix_len)) {
6661  fmode |= FMODE_SETENC_BY_BOM;
6662  }
6663  else {
6664  rb_enc_warn(estr_enc, "BOM with non-UTF encoding %s is nonsense", estr);
6665  fmode &= ~FMODE_SETENC_BY_BOM;
6666  }
6667  }
6668  if (len == 0 || len > ENCODING_MAXNAMELEN) {
6669  idx = -1;
6670  }
6671  else {
6672  if (p) {
6673  memcpy(encname, estr, len);
6674  encname[len] = '\0';
6675  estr = encname;
6676  }
6677  idx = rb_enc_find_index(estr);
6678  }
6679  if (fmode_p) *fmode_p = fmode;
6680 
6681  if (idx >= 0)
6682  ext_enc = rb_enc_from_index(idx);
6683  else {
6684  if (idx != -2)
6685  unsupported_encoding(estr, estr_enc);
6686  ext_enc = NULL;
6687  }
6688 
6689  int_enc = NULL;
6690  if (p) {
6691  if (*p == '-' && *(p+1) == '\0') {
6692  /* Special case - "-" => no transcoding */
6693  int_enc = (rb_encoding *)Qnil;
6694  }
6695  else {
6696  idx2 = rb_enc_find_index(p);
6697  if (idx2 < 0)
6698  unsupported_encoding(p, estr_enc);
6699  else if (!(fmode & FMODE_SETENC_BY_BOM) && (idx2 == idx)) {
6700  int_enc = (rb_encoding *)Qnil;
6701  }
6702  else
6703  int_enc = rb_enc_from_index(idx2);
6704  }
6705  }
6706 
6707  rb_io_ext_int_to_encs(ext_enc, int_enc, enc_p, enc2_p, fmode);
6708 }
6709 
6710 int
6711 rb_io_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding **enc2_p, int *fmode_p)
6712 {
6713  VALUE encoding=Qnil, extenc=Qundef, intenc=Qundef, tmp;
6714  int extracted = 0;
6715  rb_encoding *extencoding = NULL;
6716  rb_encoding *intencoding = NULL;
6717 
6718  if (!NIL_P(opt)) {
6719  VALUE v;
6720  v = rb_hash_lookup2(opt, sym_encoding, Qnil);
6721  if (v != Qnil) encoding = v;
6722  v = rb_hash_lookup2(opt, sym_extenc, Qundef);
6723  if (v != Qnil) extenc = v;
6724  v = rb_hash_lookup2(opt, sym_intenc, Qundef);
6725  if (!UNDEF_P(v)) intenc = v;
6726  }
6727  if ((!UNDEF_P(extenc) || !UNDEF_P(intenc)) && !NIL_P(encoding)) {
6728  if (!NIL_P(ruby_verbose)) {
6729  int idx = rb_to_encoding_index(encoding);
6730  if (idx >= 0) encoding = rb_enc_from_encoding(rb_enc_from_index(idx));
6731  rb_warn("Ignoring encoding parameter '%"PRIsVALUE"': %s_encoding is used",
6732  encoding, UNDEF_P(extenc) ? "internal" : "external");
6733  }
6734  encoding = Qnil;
6735  }
6736  if (!UNDEF_P(extenc) && !NIL_P(extenc)) {
6737  extencoding = rb_to_encoding(extenc);
6738  }
6739  if (!UNDEF_P(intenc)) {
6740  if (NIL_P(intenc)) {
6741  /* internal_encoding: nil => no transcoding */
6742  intencoding = (rb_encoding *)Qnil;
6743  }
6744  else if (!NIL_P(tmp = rb_check_string_type(intenc))) {
6745  char *p = StringValueCStr(tmp);
6746 
6747  if (*p == '-' && *(p+1) == '\0') {
6748  /* Special case - "-" => no transcoding */
6749  intencoding = (rb_encoding *)Qnil;
6750  }
6751  else {
6752  intencoding = rb_to_encoding(intenc);
6753  }
6754  }
6755  else {
6756  intencoding = rb_to_encoding(intenc);
6757  }
6758  if (extencoding == intencoding) {
6759  intencoding = (rb_encoding *)Qnil;
6760  }
6761  }
6762  if (!NIL_P(encoding)) {
6763  extracted = 1;
6764  if (!NIL_P(tmp = rb_check_string_type(encoding))) {
6765  parse_mode_enc(StringValueCStr(tmp), rb_enc_get(tmp),
6766  enc_p, enc2_p, fmode_p);
6767  }
6768  else {
6769  rb_io_ext_int_to_encs(rb_to_encoding(encoding), NULL, enc_p, enc2_p, 0);
6770  }
6771  }
6772  else if (!UNDEF_P(extenc) || !UNDEF_P(intenc)) {
6773  extracted = 1;
6774  rb_io_ext_int_to_encs(extencoding, intencoding, enc_p, enc2_p, 0);
6775  }
6776  return extracted;
6777 }
6778 
6779 static void
6780 validate_enc_binmode(int *fmode_p, int ecflags, rb_encoding *enc, rb_encoding *enc2)
6781 {
6782  int fmode = *fmode_p;
6783 
6784  if ((fmode & FMODE_READABLE) &&
6785  !enc2 &&
6786  !(fmode & FMODE_BINMODE) &&
6788  rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
6789 
6790  if ((fmode & FMODE_BINMODE) && (ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
6791  rb_raise(rb_eArgError, "newline decorator with binary mode");
6792  }
6793  if (!(fmode & FMODE_BINMODE) &&
6794  (DEFAULT_TEXTMODE || (ecflags & ECONV_NEWLINE_DECORATOR_MASK))) {
6795  fmode |= FMODE_TEXTMODE;
6796  *fmode_p = fmode;
6797  }
6798 #if !DEFAULT_TEXTMODE
6799  else if (!(ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
6800  fmode &= ~FMODE_TEXTMODE;
6801  *fmode_p = fmode;
6802  }
6803 #endif
6804 }
6805 
6806 static void
6807 extract_binmode(VALUE opthash, int *fmode)
6808 {
6809  if (!NIL_P(opthash)) {
6810  VALUE v;
6811  v = rb_hash_aref(opthash, sym_textmode);
6812  if (!NIL_P(v)) {
6813  if (*fmode & FMODE_TEXTMODE)
6814  rb_raise(rb_eArgError, "textmode specified twice");
6815  if (*fmode & FMODE_BINMODE)
6816  rb_raise(rb_eArgError, "both textmode and binmode specified");
6817  if (RTEST(v))
6818  *fmode |= FMODE_TEXTMODE;
6819  }
6820  v = rb_hash_aref(opthash, sym_binmode);
6821  if (!NIL_P(v)) {
6822  if (*fmode & FMODE_BINMODE)
6823  rb_raise(rb_eArgError, "binmode specified twice");
6824  if (*fmode & FMODE_TEXTMODE)
6825  rb_raise(rb_eArgError, "both textmode and binmode specified");
6826  if (RTEST(v))
6827  *fmode |= FMODE_BINMODE;
6828  }
6829 
6830  if ((*fmode & FMODE_BINMODE) && (*fmode & FMODE_TEXTMODE))
6831  rb_raise(rb_eArgError, "both textmode and binmode specified");
6832  }
6833 }
6834 
6835 void
6836 rb_io_extract_modeenc(VALUE *vmode_p, VALUE *vperm_p, VALUE opthash,
6837  int *oflags_p, int *fmode_p, struct rb_io_encoding *convconfig_p)
6838 {
6839  VALUE vmode;
6840  int oflags, fmode;
6841  rb_encoding *enc, *enc2;
6842  int ecflags;
6843  VALUE ecopts;
6844  int has_enc = 0, has_vmode = 0;
6845  VALUE intmode;
6846 
6847  vmode = *vmode_p;
6848 
6849  /* Set to defaults */
6850  rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
6851 
6852  vmode_handle:
6853  if (NIL_P(vmode)) {
6854  fmode = FMODE_READABLE;
6855  oflags = O_RDONLY;
6856  }
6857  else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int"))) {
6858  vmode = intmode;
6859  oflags = NUM2INT(intmode);
6860  fmode = rb_io_oflags_fmode(oflags);
6861  }
6862  else {
6863  const char *p;
6864 
6865  StringValue(vmode);
6866  p = StringValueCStr(vmode);
6867  fmode = rb_io_modestr_fmode(p);
6868  oflags = rb_io_fmode_oflags(fmode);
6869  p = strchr(p, ':');
6870  if (p) {
6871  has_enc = 1;
6872  parse_mode_enc(p+1, rb_enc_get(vmode), &enc, &enc2, &fmode);
6873  }
6874  else {
6875  rb_encoding *e;
6876 
6877  e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
6878  rb_io_ext_int_to_encs(e, NULL, &enc, &enc2, fmode);
6879  }
6880  }
6881 
6882  if (NIL_P(opthash)) {
6883  ecflags = (fmode & FMODE_READABLE) ?
6884  MODE_BTMODE(ECONV_DEFAULT_NEWLINE_DECORATOR,
6886 #ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
6887  ecflags |= (fmode & FMODE_WRITABLE) ?
6888  MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
6889  0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
6890 #endif
6891  SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
6892  ecopts = Qnil;
6893  if (fmode & FMODE_BINMODE) {
6894 #ifdef O_BINARY
6895  oflags |= O_BINARY;
6896 #endif
6897  if (!has_enc)
6898  rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
6899  }
6900 #if DEFAULT_TEXTMODE
6901  else if (NIL_P(vmode)) {
6902  fmode |= DEFAULT_TEXTMODE;
6903  }
6904 #endif
6905  }
6906  else {
6907  VALUE v;
6908  if (!has_vmode) {
6909  v = rb_hash_aref(opthash, sym_mode);
6910  if (!NIL_P(v)) {
6911  if (!NIL_P(vmode)) {
6912  rb_raise(rb_eArgError, "mode specified twice");
6913  }
6914  has_vmode = 1;
6915  vmode = v;
6916  goto vmode_handle;
6917  }
6918  }
6919  v = rb_hash_aref(opthash, sym_flags);
6920  if (!NIL_P(v)) {
6921  v = rb_to_int(v);
6922  oflags |= NUM2INT(v);
6923  vmode = INT2NUM(oflags);
6924  fmode = rb_io_oflags_fmode(oflags);
6925  }
6926  extract_binmode(opthash, &fmode);
6927  if (fmode & FMODE_BINMODE) {
6928 #ifdef O_BINARY
6929  oflags |= O_BINARY;
6930 #endif
6931  if (!has_enc)
6932  rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
6933  }
6934 #if DEFAULT_TEXTMODE
6935  else if (NIL_P(vmode)) {
6936  fmode |= DEFAULT_TEXTMODE;
6937  }
6938 #endif
6939  v = rb_hash_aref(opthash, sym_perm);
6940  if (!NIL_P(v)) {
6941  if (vperm_p) {
6942  if (!NIL_P(*vperm_p)) {
6943  rb_raise(rb_eArgError, "perm specified twice");
6944  }
6945  *vperm_p = v;
6946  }
6947  else {
6948  /* perm no use, just ignore */
6949  }
6950  }
6951  ecflags = (fmode & FMODE_READABLE) ?
6952  MODE_BTMODE(ECONV_DEFAULT_NEWLINE_DECORATOR,
6954 #ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
6955  ecflags |= (fmode & FMODE_WRITABLE) ?
6956  MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
6957  0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
6958 #endif
6959 
6960  if (rb_io_extract_encoding_option(opthash, &enc, &enc2, &fmode)) {
6961  if (has_enc) {
6962  rb_raise(rb_eArgError, "encoding specified twice");
6963  }
6964  }
6965  SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
6966  ecflags = rb_econv_prepare_options(opthash, &ecopts, ecflags);
6967  }
6968 
6969  validate_enc_binmode(&fmode, ecflags, enc, enc2);
6970 
6971  *vmode_p = vmode;
6972 
6973  *oflags_p = oflags;
6974  *fmode_p = fmode;
6975  convconfig_p->enc = enc;
6976  convconfig_p->enc2 = enc2;
6977  convconfig_p->ecflags = ecflags;
6978  convconfig_p->ecopts = ecopts;
6979 }
6980 
6982  VALUE fname;
6983  int oflags;
6984  mode_t perm;
6985 };
6986 
6987 static void *
6988 sysopen_func(void *ptr)
6989 {
6990  const struct sysopen_struct *data = ptr;
6991  const char *fname = RSTRING_PTR(data->fname);
6992  return (void *)(VALUE)rb_cloexec_open(fname, data->oflags, data->perm);
6993 }
6994 
6995 static inline int
6996 rb_sysopen_internal(struct sysopen_struct *data)
6997 {
6998  int fd;
6999  do {
7000  fd = IO_WITHOUT_GVL_INT(sysopen_func, data);
7001  } while (fd < 0 && errno == EINTR);
7002  if (0 <= fd)
7003  rb_update_max_fd(fd);
7004  return fd;
7005 }
7006 
7007 static int
7008 rb_sysopen(VALUE fname, int oflags, mode_t perm)
7009 {
7010  int fd = -1;
7011  struct sysopen_struct data;
7012 
7013  data.fname = rb_str_encode_ospath(fname);
7014  StringValueCStr(data.fname);
7015  data.oflags = oflags;
7016  data.perm = perm;
7017 
7018  TRY_WITH_GC((fd = rb_sysopen_internal(&data)) >= 0) {
7019  rb_syserr_fail_path(first_errno, fname);
7020  }
7021  return fd;
7022 }
7023 
7024 static inline FILE *
7025 fdopen_internal(int fd, const char *modestr)
7026 {
7027  FILE *file;
7028 
7029 #if defined(__sun)
7030  errno = 0;
7031 #endif
7032  file = fdopen(fd, modestr);
7033  if (!file) {
7034 #ifdef _WIN32
7035  if (errno == 0) errno = EINVAL;
7036 #elif defined(__sun)
7037  if (errno == 0) errno = EMFILE;
7038 #endif
7039  }
7040  return file;
7041 }
7042 
7043 FILE *
7044 rb_fdopen(int fd, const char *modestr)
7045 {
7046  FILE *file = 0;
7047 
7048  TRY_WITH_GC((file = fdopen_internal(fd, modestr)) != 0) {
7049  rb_syserr_fail(first_errno, 0);
7050  }
7051 
7052  /* xxx: should be _IONBF? A buffer in FILE may have trouble. */
7053 #ifdef USE_SETVBUF
7054  if (setvbuf(file, NULL, _IOFBF, 0) != 0)
7055  rb_warn("setvbuf() can't be honoured (fd=%d)", fd);
7056 #endif
7057  return file;
7058 }
7059 
7060 static int
7061 io_check_tty(rb_io_t *fptr)
7062 {
7063  int t = isatty(fptr->fd);
7064  if (t)
7065  fptr->mode |= FMODE_TTY|FMODE_DUPLEX;
7066  return t;
7067 }
7068 
7069 static VALUE rb_io_internal_encoding(VALUE);
7070 static void io_encoding_set(rb_io_t *, VALUE, VALUE, VALUE);
7071 
7072 static int
7073 io_strip_bom(VALUE io)
7074 {
7075  VALUE b1, b2, b3, b4;
7076  rb_io_t *fptr;
7077 
7078  GetOpenFile(io, fptr);
7079  if (!(fptr->mode & FMODE_READABLE)) return 0;
7080  if (NIL_P(b1 = rb_io_getbyte(io))) return 0;
7081  switch (b1) {
7082  case INT2FIX(0xEF):
7083  if (NIL_P(b2 = rb_io_getbyte(io))) break;
7084  if (b2 == INT2FIX(0xBB) && !NIL_P(b3 = rb_io_getbyte(io))) {
7085  if (b3 == INT2FIX(0xBF)) {
7086  return rb_utf8_encindex();
7087  }
7088  rb_io_ungetbyte(io, b3);
7089  }
7090  rb_io_ungetbyte(io, b2);
7091  break;
7092 
7093  case INT2FIX(0xFE):
7094  if (NIL_P(b2 = rb_io_getbyte(io))) break;
7095  if (b2 == INT2FIX(0xFF)) {
7096  return ENCINDEX_UTF_16BE;
7097  }
7098  rb_io_ungetbyte(io, b2);
7099  break;
7100 
7101  case INT2FIX(0xFF):
7102  if (NIL_P(b2 = rb_io_getbyte(io))) break;
7103  if (b2 == INT2FIX(0xFE)) {
7104  b3 = rb_io_getbyte(io);
7105  if (b3 == INT2FIX(0) && !NIL_P(b4 = rb_io_getbyte(io))) {
7106  if (b4 == INT2FIX(0)) {
7107  return ENCINDEX_UTF_32LE;
7108  }
7109  rb_io_ungetbyte(io, b4);
7110  }
7111  rb_io_ungetbyte(io, b3);
7112  return ENCINDEX_UTF_16LE;
7113  }
7114  rb_io_ungetbyte(io, b2);
7115  break;
7116 
7117  case INT2FIX(0):
7118  if (NIL_P(b2 = rb_io_getbyte(io))) break;
7119  if (b2 == INT2FIX(0) && !NIL_P(b3 = rb_io_getbyte(io))) {
7120  if (b3 == INT2FIX(0xFE) && !NIL_P(b4 = rb_io_getbyte(io))) {
7121  if (b4 == INT2FIX(0xFF)) {
7122  return ENCINDEX_UTF_32BE;
7123  }
7124  rb_io_ungetbyte(io, b4);
7125  }
7126  rb_io_ungetbyte(io, b3);
7127  }
7128  rb_io_ungetbyte(io, b2);
7129  break;
7130  }
7131  rb_io_ungetbyte(io, b1);
7132  return 0;
7133 }
7134 
7135 static rb_encoding *
7136 io_set_encoding_by_bom(VALUE io)
7137 {
7138  int idx = io_strip_bom(io);
7139  rb_io_t *fptr;
7140  rb_encoding *extenc = NULL;
7141 
7142  GetOpenFile(io, fptr);
7143  if (idx) {
7144  extenc = rb_enc_from_index(idx);
7145  io_encoding_set(fptr, rb_enc_from_encoding(extenc),
7146  rb_io_internal_encoding(io), Qnil);
7147  }
7148  else {
7149  fptr->encs.enc2 = NULL;
7150  }
7151  return extenc;
7152 }
7153 
7154 static VALUE
7155 rb_file_open_generic(VALUE io, VALUE filename, int oflags, int fmode,
7156  const struct rb_io_encoding *convconfig, mode_t perm)
7157 {
7158  VALUE pathv;
7159  rb_io_t *fptr;
7160  struct rb_io_encoding cc;
7161  if (!convconfig) {
7162  /* Set to default encodings */
7163  rb_io_ext_int_to_encs(NULL, NULL, &cc.enc, &cc.enc2, fmode);
7164  cc.ecflags = 0;
7165  cc.ecopts = Qnil;
7166  convconfig = &cc;
7167  }
7168  validate_enc_binmode(&fmode, convconfig->ecflags,
7169  convconfig->enc, convconfig->enc2);
7170 
7171  MakeOpenFile(io, fptr);
7172  fptr->mode = fmode;
7173  fptr->encs = *convconfig;
7174  pathv = rb_str_new_frozen(filename);
7175 #ifdef O_TMPFILE
7176  if (!(oflags & O_TMPFILE)) {
7177  fptr->pathv = pathv;
7178  }
7179 #else
7180  fptr->pathv = pathv;
7181 #endif
7182  fptr->fd = rb_sysopen(pathv, oflags, perm);
7183  io_check_tty(fptr);
7184  if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
7185 
7186  return io;
7187 }
7188 
7189 static VALUE
7190 rb_file_open_internal(VALUE io, VALUE filename, const char *modestr)
7191 {
7192  int fmode = rb_io_modestr_fmode(modestr);
7193  const char *p = strchr(modestr, ':');
7194  struct rb_io_encoding convconfig;
7195 
7196  if (p) {
7197  parse_mode_enc(p+1, rb_usascii_encoding(),
7198  &convconfig.enc, &convconfig.enc2, &fmode);
7199  }
7200  else {
7201  rb_encoding *e;
7202  /* Set to default encodings */
7203 
7204  e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
7205  rb_io_ext_int_to_encs(e, NULL, &convconfig.enc, &convconfig.enc2, fmode);
7206  }
7207 
7208  convconfig.ecflags = (fmode & FMODE_READABLE) ?
7209  MODE_BTMODE(ECONV_DEFAULT_NEWLINE_DECORATOR,
7211 #ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7212  convconfig.ecflags |= (fmode & FMODE_WRITABLE) ?
7213  MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7214  0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7215 #endif
7216  SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.enc2, convconfig.ecflags);
7217  convconfig.ecopts = Qnil;
7218 
7219  return rb_file_open_generic(io, filename,
7220  rb_io_fmode_oflags(fmode),
7221  fmode,
7222  &convconfig,
7223  0666);
7224 }
7225 
7226 VALUE
7227 rb_file_open_str(VALUE fname, const char *modestr)
7228 {
7229  FilePathValue(fname);
7230  return rb_file_open_internal(io_alloc(rb_cFile), fname, modestr);
7231 }
7232 
7233 VALUE
7234 rb_file_open(const char *fname, const char *modestr)
7235 {
7236  return rb_file_open_internal(io_alloc(rb_cFile), rb_str_new_cstr(fname), modestr);
7237 }
7238 
7239 #if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7240 static struct pipe_list {
7241  rb_io_t *fptr;
7242  struct pipe_list *next;
7243 } *pipe_list;
7244 
7245 static void
7246 pipe_add_fptr(rb_io_t *fptr)
7247 {
7248  struct pipe_list *list;
7249 
7250  list = ALLOC(struct pipe_list);
7251  list->fptr = fptr;
7252  list->next = pipe_list;
7253  pipe_list = list;
7254 }
7255 
7256 static void
7257 pipe_del_fptr(rb_io_t *fptr)
7258 {
7259  struct pipe_list **prev = &pipe_list;
7260  struct pipe_list *tmp;
7261 
7262  while ((tmp = *prev) != 0) {
7263  if (tmp->fptr == fptr) {
7264  *prev = tmp->next;
7265  free(tmp);
7266  return;
7267  }
7268  prev = &tmp->next;
7269  }
7270 }
7271 
7272 #if defined (_WIN32) || defined(__CYGWIN__)
7273 static void
7274 pipe_atexit(void)
7275 {
7276  struct pipe_list *list = pipe_list;
7277  struct pipe_list *tmp;
7278 
7279  while (list) {
7280  tmp = list->next;
7281  rb_io_fptr_finalize(list->fptr);
7282  list = tmp;
7283  }
7284 }
7285 #endif
7286 
7287 static void
7288 pipe_finalize(rb_io_t *fptr, int noraise)
7289 {
7290 #if !defined(HAVE_WORKING_FORK) && !defined(_WIN32)
7291  int status = 0;
7292  if (fptr->stdio_file) {
7293  status = pclose(fptr->stdio_file);
7294  }
7295  fptr->fd = -1;
7296  fptr->stdio_file = 0;
7297  rb_last_status_set(status, fptr->pid);
7298 #else
7299  fptr_finalize(fptr, noraise);
7300 #endif
7301  pipe_del_fptr(fptr);
7302 }
7303 #endif
7304 
7305 static void
7306 fptr_copy_finalizer(rb_io_t *fptr, const rb_io_t *orig)
7307 {
7308 #if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7309  void (*const old_finalize)(struct rb_io*,int) = fptr->finalize;
7310 
7311  if (old_finalize == orig->finalize) return;
7312 #endif
7313 
7314  fptr->finalize = orig->finalize;
7315 
7316 #if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7317  if (old_finalize != pipe_finalize) {
7318  struct pipe_list *list;
7319  for (list = pipe_list; list; list = list->next) {
7320  if (list->fptr == fptr) break;
7321  }
7322  if (!list) pipe_add_fptr(fptr);
7323  }
7324  else {
7325  pipe_del_fptr(fptr);
7326  }
7327 #endif
7328 }
7329 
7330 void
7332 {
7334  fptr->mode |= FMODE_SYNC;
7335 }
7336 
7337 void
7338 rb_io_unbuffered(rb_io_t *fptr)
7339 {
7340  rb_io_synchronized(fptr);
7341 }
7342 
7343 int
7344 rb_pipe(int *pipes)
7345 {
7346  int ret;
7347  TRY_WITH_GC((ret = rb_cloexec_pipe(pipes)) >= 0);
7348  if (ret == 0) {
7349  rb_update_max_fd(pipes[0]);
7350  rb_update_max_fd(pipes[1]);
7351  }
7352  return ret;
7353 }
7354 
7355 #ifdef _WIN32
7356 #define HAVE_SPAWNV 1
7357 #define spawnv(mode, cmd, args) rb_w32_uaspawn((mode), (cmd), (args))
7358 #define spawn(mode, cmd) rb_w32_uspawn((mode), (cmd), 0)
7359 #endif
7360 
7361 #if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7362 struct popen_arg {
7363  VALUE execarg_obj;
7364  struct rb_execarg *eargp;
7365  int modef;
7366  int pair[2];
7367  int write_pair[2];
7368 };
7369 #endif
7370 
7371 #ifdef HAVE_WORKING_FORK
7372 # ifndef __EMSCRIPTEN__
7373 static void
7374 popen_redirect(struct popen_arg *p)
7375 {
7376  if ((p->modef & FMODE_READABLE) && (p->modef & FMODE_WRITABLE)) {
7377  close(p->write_pair[1]);
7378  if (p->write_pair[0] != 0) {
7379  dup2(p->write_pair[0], 0);
7380  close(p->write_pair[0]);
7381  }
7382  close(p->pair[0]);
7383  if (p->pair[1] != 1) {
7384  dup2(p->pair[1], 1);
7385  close(p->pair[1]);
7386  }
7387  }
7388  else if (p->modef & FMODE_READABLE) {
7389  close(p->pair[0]);
7390  if (p->pair[1] != 1) {
7391  dup2(p->pair[1], 1);
7392  close(p->pair[1]);
7393  }
7394  }
7395  else {
7396  close(p->pair[1]);
7397  if (p->pair[0] != 0) {
7398  dup2(p->pair[0], 0);
7399  close(p->pair[0]);
7400  }
7401  }
7402 }
7403 # endif
7404 
7405 #if defined(__linux__)
7406 /* Linux /proc/self/status contains a line: "FDSize:\t<nnn>\n"
7407  * Since /proc may not be available, linux_get_maxfd is just a hint.
7408  * This function, linux_get_maxfd, must be async-signal-safe.
7409  * I.e. opendir() is not usable.
7410  *
7411  * Note that memchr() and memcmp is *not* async-signal-safe in POSIX.
7412  * However they are easy to re-implement in async-signal-safe manner.
7413  * (Also note that there is missing/memcmp.c.)
7414  */
7415 static int
7416 linux_get_maxfd(void)
7417 {
7418  int fd;
7419  char buf[4096], *p, *np, *e;
7420  ssize_t ss;
7421  fd = rb_cloexec_open("/proc/self/status", O_RDONLY|O_NOCTTY, 0);
7422  if (fd < 0) return fd;
7423  ss = read(fd, buf, sizeof(buf));
7424  if (ss < 0) goto err;
7425  p = buf;
7426  e = buf + ss;
7427  while ((int)sizeof("FDSize:\t0\n")-1 <= e-p &&
7428  (np = memchr(p, '\n', e-p)) != NULL) {
7429  if (memcmp(p, "FDSize:", sizeof("FDSize:")-1) == 0) {
7430  int fdsize;
7431  p += sizeof("FDSize:")-1;
7432  *np = '\0';
7433  fdsize = (int)ruby_strtoul(p, (char **)NULL, 10);
7434  close(fd);
7435  return fdsize;
7436  }
7437  p = np+1;
7438  }
7439  /* fall through */
7440 
7441  err:
7442  close(fd);
7443  return (int)ss;
7444 }
7445 #endif
7446 
7447 /* This function should be async-signal-safe. */
7448 void
7449 rb_close_before_exec(int lowfd, int maxhint, VALUE noclose_fds)
7450 {
7451 #if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
7452  int fd, ret;
7453  int max = (int)max_file_descriptor;
7454 # ifdef F_MAXFD
7455  /* F_MAXFD is available since NetBSD 2.0. */
7456  ret = fcntl(0, F_MAXFD); /* async-signal-safe */
7457  if (ret != -1)
7458  maxhint = max = ret;
7459 # elif defined(__linux__)
7460  ret = linux_get_maxfd();
7461  if (maxhint < ret)
7462  maxhint = ret;
7463  /* maxhint = max = ret; if (ret == -1) abort(); // test */
7464 # endif
7465  if (max < maxhint)
7466  max = maxhint;
7467  for (fd = lowfd; fd <= max; fd++) {
7468  if (!NIL_P(noclose_fds) &&
7469  RTEST(rb_hash_lookup(noclose_fds, INT2FIX(fd)))) /* async-signal-safe */
7470  continue;
7471  ret = fcntl(fd, F_GETFD); /* async-signal-safe */
7472  if (ret != -1 && !(ret & FD_CLOEXEC)) {
7473  fcntl(fd, F_SETFD, ret|FD_CLOEXEC); /* async-signal-safe */
7474  }
7475 # define CONTIGUOUS_CLOSED_FDS 20
7476  if (ret != -1) {
7477  if (max < fd + CONTIGUOUS_CLOSED_FDS)
7478  max = fd + CONTIGUOUS_CLOSED_FDS;
7479  }
7480  }
7481 #endif
7482 }
7483 
7484 # ifndef __EMSCRIPTEN__
7485 static int
7486 popen_exec(void *pp, char *errmsg, size_t errmsg_len)
7487 {
7488  struct popen_arg *p = (struct popen_arg*)pp;
7489 
7490  return rb_exec_async_signal_safe(p->eargp, errmsg, errmsg_len);
7491 }
7492 # endif
7493 #endif
7494 
7495 #if (defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)) && !defined __EMSCRIPTEN__
7496 static VALUE
7497 rb_execarg_fixup_v(VALUE execarg_obj)
7498 {
7499  rb_execarg_parent_start(execarg_obj);
7500  return Qnil;
7501 }
7502 #else
7503 char *rb_execarg_commandline(const struct rb_execarg *eargp, VALUE *prog);
7504 #endif
7505 
7506 #ifndef __EMSCRIPTEN__
7507 static VALUE
7508 pipe_open(VALUE execarg_obj, const char *modestr, int fmode,
7509  const struct rb_io_encoding *convconfig)
7510 {
7511  struct rb_execarg *eargp = NIL_P(execarg_obj) ? NULL : rb_execarg_get(execarg_obj);
7512  VALUE prog = eargp ? (eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name) : Qfalse ;
7513  rb_pid_t pid = 0;
7514  rb_io_t *fptr;
7515  VALUE port;
7516  rb_io_t *write_fptr;
7517  VALUE write_port;
7518 #if defined(HAVE_WORKING_FORK)
7519  int status;
7520  char errmsg[80] = { '\0' };
7521 #endif
7522 #if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7523  int state;
7524  struct popen_arg arg;
7525 #endif
7526  int e = 0;
7527 #if defined(HAVE_SPAWNV)
7528 # if defined(HAVE_SPAWNVE)
7529 # define DO_SPAWN(cmd, args, envp) ((args) ? \
7530  spawnve(P_NOWAIT, (cmd), (args), (envp)) : \
7531  spawne(P_NOWAIT, (cmd), (envp)))
7532 # else
7533 # define DO_SPAWN(cmd, args, envp) ((args) ? \
7534  spawnv(P_NOWAIT, (cmd), (args)) : \
7535  spawn(P_NOWAIT, (cmd)))
7536 # endif
7537 # if !defined(HAVE_WORKING_FORK)
7538  char **args = NULL;
7539 # if defined(HAVE_SPAWNVE)
7540  char **envp = NULL;
7541 # endif
7542 # endif
7543 #endif
7544 #if !defined(HAVE_WORKING_FORK)
7545  struct rb_execarg sarg, *sargp = &sarg;
7546 #endif
7547  FILE *fp = 0;
7548  int fd = -1;
7549  int write_fd = -1;
7550 #if !defined(HAVE_WORKING_FORK)
7551  const char *cmd = 0;
7552 
7553  if (prog)
7554  cmd = StringValueCStr(prog);
7555 #endif
7556 
7557 #if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7558  arg.execarg_obj = execarg_obj;
7559  arg.eargp = eargp;
7560  arg.modef = fmode;
7561  arg.pair[0] = arg.pair[1] = -1;
7562  arg.write_pair[0] = arg.write_pair[1] = -1;
7563 # if !defined(HAVE_WORKING_FORK)
7564  if (eargp && !eargp->use_shell) {
7565  args = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
7566  }
7567 # endif
7568  switch (fmode & (FMODE_READABLE|FMODE_WRITABLE)) {
7570  if (rb_pipe(arg.write_pair) < 0)
7571  rb_sys_fail_str(prog);
7572  if (rb_pipe(arg.pair) < 0) {
7573  e = errno;
7574  close(arg.write_pair[0]);
7575  close(arg.write_pair[1]);
7576  rb_syserr_fail_str(e, prog);
7577  }
7578  if (eargp) {
7579  rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.write_pair[0]));
7580  rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
7581  }
7582  break;
7583  case FMODE_READABLE:
7584  if (rb_pipe(arg.pair) < 0)
7585  rb_sys_fail_str(prog);
7586  if (eargp)
7587  rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
7588  break;
7589  case FMODE_WRITABLE:
7590  if (rb_pipe(arg.pair) < 0)
7591  rb_sys_fail_str(prog);
7592  if (eargp)
7593  rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.pair[0]));
7594  break;
7595  default:
7596  rb_sys_fail_str(prog);
7597  }
7598  if (!NIL_P(execarg_obj)) {
7599  rb_protect(rb_execarg_fixup_v, execarg_obj, &state);
7600  if (state) {
7601  if (0 <= arg.write_pair[0]) close(arg.write_pair[0]);
7602  if (0 <= arg.write_pair[1]) close(arg.write_pair[1]);
7603  if (0 <= arg.pair[0]) close(arg.pair[0]);
7604  if (0 <= arg.pair[1]) close(arg.pair[1]);
7605  rb_execarg_parent_end(execarg_obj);
7606  rb_jump_tag(state);
7607  }
7608 
7609 # if defined(HAVE_WORKING_FORK)
7610  pid = rb_fork_async_signal_safe(&status, popen_exec, &arg, arg.eargp->redirect_fds, errmsg, sizeof(errmsg));
7611 # else
7612  rb_execarg_run_options(eargp, sargp, NULL, 0);
7613 # if defined(HAVE_SPAWNVE)
7614  if (eargp->envp_str) envp = (char **)RSTRING_PTR(eargp->envp_str);
7615 # endif
7616  while ((pid = DO_SPAWN(cmd, args, envp)) < 0) {
7617  /* exec failed */
7618  switch (e = errno) {
7619  case EAGAIN:
7620 # if EWOULDBLOCK != EAGAIN
7621  case EWOULDBLOCK:
7622 # endif
7623  rb_thread_sleep(1);
7624  continue;
7625  }
7626  break;
7627  }
7628  if (eargp)
7629  rb_execarg_run_options(sargp, NULL, NULL, 0);
7630 # endif
7631  rb_execarg_parent_end(execarg_obj);
7632  }
7633  else {
7634 # if defined(HAVE_WORKING_FORK)
7635  pid = rb_call_proc__fork();
7636  if (pid == 0) { /* child */
7637  popen_redirect(&arg);
7638  rb_io_synchronized(RFILE(orig_stdout)->fptr);
7639  rb_io_synchronized(RFILE(orig_stderr)->fptr);
7640  return Qnil;
7641  }
7642 # else
7643  rb_notimplement();
7644 # endif
7645  }
7646 
7647  /* parent */
7648  if (pid < 0) {
7649 # if defined(HAVE_WORKING_FORK)
7650  e = errno;
7651 # endif
7652  close(arg.pair[0]);
7653  close(arg.pair[1]);
7655  close(arg.write_pair[0]);
7656  close(arg.write_pair[1]);
7657  }
7658 # if defined(HAVE_WORKING_FORK)
7659  if (errmsg[0])
7660  rb_syserr_fail(e, errmsg);
7661 # endif
7662  rb_syserr_fail_str(e, prog);
7663  }
7664  if ((fmode & FMODE_READABLE) && (fmode & FMODE_WRITABLE)) {
7665  close(arg.pair[1]);
7666  fd = arg.pair[0];
7667  close(arg.write_pair[0]);
7668  write_fd = arg.write_pair[1];
7669  }
7670  else if (fmode & FMODE_READABLE) {
7671  close(arg.pair[1]);
7672  fd = arg.pair[0];
7673  }
7674  else {
7675  close(arg.pair[0]);
7676  fd = arg.pair[1];
7677  }
7678 #else
7679  cmd = rb_execarg_commandline(eargp, &prog);
7680  if (!NIL_P(execarg_obj)) {
7681  rb_execarg_parent_start(execarg_obj);
7682  rb_execarg_run_options(eargp, sargp, NULL, 0);
7683  }
7684  fp = popen(cmd, modestr);
7685  e = errno;
7686  if (eargp) {
7687  rb_execarg_parent_end(execarg_obj);
7688  rb_execarg_run_options(sargp, NULL, NULL, 0);
7689  }
7690  if (!fp) rb_syserr_fail_path(e, prog);
7691  fd = fileno(fp);
7692 #endif
7693 
7694  port = io_alloc(rb_cIO);
7695  MakeOpenFile(port, fptr);
7696  fptr->fd = fd;
7697  fptr->stdio_file = fp;
7698  fptr->mode = fmode | FMODE_SYNC|FMODE_DUPLEX;
7699  if (convconfig) {
7700  fptr->encs = *convconfig;
7701 #if RUBY_CRLF_ENVIRONMENT
7704  }
7705 #endif
7706  }
7707  else {
7708  if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
7710  }
7711 #ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7712  if (NEED_NEWLINE_DECORATOR_ON_WRITE(fptr)) {
7713  fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
7714  }
7715 #endif
7716  }
7717  fptr->pid = pid;
7718 
7719  if (0 <= write_fd) {
7720  write_port = io_alloc(rb_cIO);
7721  MakeOpenFile(write_port, write_fptr);
7722  write_fptr->fd = write_fd;
7723  write_fptr->mode = (fmode & ~FMODE_READABLE)| FMODE_SYNC|FMODE_DUPLEX;
7724  fptr->mode &= ~FMODE_WRITABLE;
7725  fptr->tied_io_for_writing = write_port;
7726  rb_ivar_set(port, rb_intern("@tied_io_for_writing"), write_port);
7727  }
7728 
7729 #if defined (__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7730  fptr->finalize = pipe_finalize;
7731  pipe_add_fptr(fptr);
7732 #endif
7733  return port;
7734 }
7735 #else
7736 static VALUE
7737 pipe_open(VALUE execarg_obj, const char *modestr, int fmode,
7738  const struct rb_io_encoding *convconfig)
7739 {
7740  rb_raise(rb_eNotImpError, "popen() is not available");
7741 }
7742 #endif
7743 
7744 static int
7745 is_popen_fork(VALUE prog)
7746 {
7747  if (RSTRING_LEN(prog) == 1 && RSTRING_PTR(prog)[0] == '-') {
7748 #if !defined(HAVE_WORKING_FORK)
7750  "fork() function is unimplemented on this machine");
7751 #else
7752  return TRUE;
7753 #endif
7754  }
7755  return FALSE;
7756 }
7757 
7758 static VALUE
7759 pipe_open_s(VALUE prog, const char *modestr, int fmode,
7760  const struct rb_io_encoding *convconfig)
7761 {
7762  int argc = 1;
7763  VALUE *argv = &prog;
7764  VALUE execarg_obj = Qnil;
7765 
7766  if (!is_popen_fork(prog))
7767  execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
7768  return pipe_open(execarg_obj, modestr, fmode, convconfig);
7769 }
7770 
7771 static VALUE
7772 pipe_close(VALUE io)
7773 {
7774  rb_io_t *fptr = io_close_fptr(io);
7775  if (fptr) {
7776  fptr_waitpid(fptr, rb_thread_to_be_killed(rb_thread_current()));
7777  }
7778  return Qnil;
7779 }
7780 
7781 static VALUE popen_finish(VALUE port, VALUE klass);
7782 
7783 /*
7784  * call-seq:
7785  * IO.popen(env = {}, cmd, mode = 'r', **opts) -> io
7786  * IO.popen(env = {}, cmd, mode = 'r', **opts) {|io| ... } -> object
7787  *
7788  * Executes the given command +cmd+ as a subprocess
7789  * whose $stdin and $stdout are connected to a new stream +io+.
7790  *
7791  * This method has potential security vulnerabilities if called with untrusted input;
7792  * see {Command Injection}[rdoc-ref:command_injection.rdoc].
7793  *
7794  * If no block is given, returns the new stream,
7795  * which depending on given +mode+ may be open for reading, writing, or both.
7796  * The stream should be explicitly closed (eventually) to avoid resource leaks.
7797  *
7798  * If a block is given, the stream is passed to the block
7799  * (again, open for reading, writing, or both);
7800  * when the block exits, the stream is closed,
7801  * and the block's value is assigned to global variable <tt>$?</tt> and returned.
7802  *
7803  * Optional argument +mode+ may be any valid \IO mode.
7804  * See {Access Modes}[rdoc-ref:File@Access+Modes].
7805  *
7806  * Required argument +cmd+ determines which of the following occurs:
7807  *
7808  * - The process forks.
7809  * - A specified program runs in a shell.
7810  * - A specified program runs with specified arguments.
7811  * - A specified program runs with specified arguments and a specified +argv0+.
7812  *
7813  * Each of these is detailed below.
7814  *
7815  * The optional hash argument +env+ specifies name/value pairs that are to be added
7816  * to the environment variables for the subprocess:
7817  *
7818  * IO.popen({'FOO' => 'bar'}, 'ruby', 'r+') do |pipe|
7819  * pipe.puts 'puts ENV["FOO"]'
7820  * pipe.close_write
7821  * pipe.gets
7822  * end => "bar\n"
7823  *
7824  * Optional keyword arguments +opts+ specify:
7825  *
7826  * - {Open options}[rdoc-ref:IO@Open+Options].
7827  * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
7828  * - Options for Kernel#spawn.
7829  *
7830  * <b>Forked \Process</b>
7831  *
7832  * When argument +cmd+ is the 1-character string <tt>'-'</tt>, causes the process to fork:
7833  * IO.popen('-') do |pipe|
7834  * if pipe
7835  * $stderr.puts "In parent, child pid is #{pipe.pid}\n"
7836  * else
7837  * $stderr.puts "In child, pid is #{$$}\n"
7838  * end
7839  * end
7840  *
7841  * Output:
7842  *
7843  * In parent, child pid is 26253
7844  * In child, pid is 26253
7845  *
7846  * Note that this is not supported on all platforms.
7847  *
7848  * <b>Shell Subprocess</b>
7849  *
7850  * When argument +cmd+ is a single string (but not <tt>'-'</tt>),
7851  * the program named +cmd+ is run as a shell command:
7852  *
7853  * IO.popen('uname') do |pipe|
7854  * pipe.readlines
7855  * end
7856  *
7857  * Output:
7858  *
7859  * ["Linux\n"]
7860  *
7861  * Another example:
7862  *
7863  * IO.popen('/bin/sh', 'r+') do |pipe|
7864  * pipe.puts('ls')
7865  * pipe.close_write
7866  * $stderr.puts pipe.readlines.size
7867  * end
7868  *
7869  * Output:
7870  *
7871  * 213
7872  *
7873  * <b>Program Subprocess</b>
7874  *
7875  * When argument +cmd+ is an array of strings,
7876  * the program named <tt>cmd[0]</tt> is run with all elements of +cmd+ as its arguments:
7877  *
7878  * IO.popen(['du', '..', '.']) do |pipe|
7879  * $stderr.puts pipe.readlines.size
7880  * end
7881  *
7882  * Output:
7883  *
7884  * 1111
7885  *
7886  * <b>Program Subprocess with <tt>argv0</tt></b>
7887  *
7888  * When argument +cmd+ is an array whose first element is a 2-element string array
7889  * and whose remaining elements (if any) are strings:
7890  *
7891  * - <tt>cmd[0][0]</tt> (the first string in the nested array) is the name of a program that is run.
7892  * - <tt>cmd[0][1]</tt> (the second string in the nested array) is set as the program's <tt>argv[0]</tt>.
7893  * - <tt>cmd[1..-1]</tt> (the strings in the outer array) are the program's arguments.
7894  *
7895  * Example (sets <tt>$0</tt> to 'foo'):
7896  *
7897  * IO.popen([['/bin/sh', 'foo'], '-c', 'echo $0']).read # => "foo\n"
7898  *
7899  * <b>Some Special Examples</b>
7900  *
7901  * # Set IO encoding.
7902  * IO.popen("nkf -e filename", :external_encoding=>"EUC-JP") {|nkf_io|
7903  * euc_jp_string = nkf_io.read
7904  * }
7905  *
7906  * # Merge standard output and standard error using Kernel#spawn option. See Kernel#spawn.
7907  * IO.popen(["ls", "/", :err=>[:child, :out]]) do |io|
7908  * ls_result_with_error = io.read
7909  * end
7910  *
7911  * # Use mixture of spawn options and IO options.
7912  * IO.popen(["ls", "/"], :err=>[:child, :out]) do |io|
7913  * ls_result_with_error = io.read
7914  * end
7915  *
7916  * f = IO.popen("uname")
7917  * p f.readlines
7918  * f.close
7919  * puts "Parent is #{Process.pid}"
7920  * IO.popen("date") {|f| puts f.gets }
7921  * IO.popen("-") {|f| $stderr.puts "#{Process.pid} is here, f is #{f.inspect}"}
7922  * p $?
7923  * IO.popen(%w"sed -e s|^|<foo>| -e s&$&;zot;&", "r+") {|f|
7924  * f.puts "bar"; f.close_write; puts f.gets
7925  * }
7926  *
7927  * Output (from last section):
7928  *
7929  * ["Linux\n"]
7930  * Parent is 21346
7931  * Thu Jan 15 22:41:19 JST 2009
7932  * 21346 is here, f is #<IO:fd 3>
7933  * 21352 is here, f is nil
7934  * #<Process::Status: pid 21352 exit 0>
7935  * <foo>bar;zot;
7936  *
7937  * Raises exceptions that IO.pipe and Kernel.spawn raise.
7938  *
7939  */
7940 
7941 static VALUE
7942 rb_io_s_popen(int argc, VALUE *argv, VALUE klass)
7943 {
7944  VALUE pname, pmode = Qnil, opt = Qnil, env = Qnil;
7945 
7946  if (argc > 1 && !NIL_P(opt = rb_check_hash_type(argv[argc-1]))) --argc;
7947  if (argc > 1 && !NIL_P(env = rb_check_hash_type(argv[0]))) --argc, ++argv;
7948  switch (argc) {
7949  case 2:
7950  pmode = argv[1];
7951  case 1:
7952  pname = argv[0];
7953  break;
7954  default:
7955  {
7956  int ex = !NIL_P(opt);
7957  rb_error_arity(argc + ex, 1 + ex, 2 + ex);
7958  }
7959  }
7960  return popen_finish(rb_io_popen(pname, pmode, env, opt), klass);
7961 }
7962 
7963 VALUE
7964 rb_io_popen(VALUE pname, VALUE pmode, VALUE env, VALUE opt)
7965 {
7966  const char *modestr;
7967  VALUE tmp, execarg_obj = Qnil;
7968  int oflags, fmode;
7969  struct rb_io_encoding convconfig;
7970 
7971  tmp = rb_check_array_type(pname);
7972  if (!NIL_P(tmp)) {
7973  long len = RARRAY_LEN(tmp);
7974 #if SIZEOF_LONG > SIZEOF_INT
7975  if (len > INT_MAX) {
7976  rb_raise(rb_eArgError, "too many arguments");
7977  }
7978 #endif
7979  execarg_obj = rb_execarg_new((int)len, RARRAY_CONST_PTR(tmp), FALSE, FALSE);
7980  RB_GC_GUARD(tmp);
7981  }
7982  else {
7983  StringValue(pname);
7984  execarg_obj = Qnil;
7985  if (!is_popen_fork(pname))
7986  execarg_obj = rb_execarg_new(1, &pname, TRUE, FALSE);
7987  }
7988  if (!NIL_P(execarg_obj)) {
7989  if (!NIL_P(opt))
7990  opt = rb_execarg_extract_options(execarg_obj, opt);
7991  if (!NIL_P(env))
7992  rb_execarg_setenv(execarg_obj, env);
7993  }
7994  rb_io_extract_modeenc(&pmode, 0, opt, &oflags, &fmode, &convconfig);
7995  modestr = rb_io_oflags_modestr(oflags);
7996 
7997  return pipe_open(execarg_obj, modestr, fmode, &convconfig);
7998 }
7999 
8000 static VALUE
8001 popen_finish(VALUE port, VALUE klass)
8002 {
8003  if (NIL_P(port)) {
8004  /* child */
8005  if (rb_block_given_p()) {
8006  rb_yield(Qnil);
8009  _exit(0);
8010  }
8011  return Qnil;
8012  }
8013  RBASIC_SET_CLASS(port, klass);
8014  if (rb_block_given_p()) {
8015  return rb_ensure(rb_yield, port, pipe_close, port);
8016  }
8017  return port;
8018 }
8019 
8020 #if defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)
8021 struct popen_writer_arg {
8022  char *const *argv;
8023  struct popen_arg popen;
8024 };
8025 
8026 static int
8027 exec_popen_writer(void *arg, char *errmsg, size_t buflen)
8028 {
8029  struct popen_writer_arg *pw = arg;
8030  pw->popen.modef = FMODE_WRITABLE;
8031  popen_redirect(&pw->popen);
8032  execv(pw->argv[0], pw->argv);
8033  strlcpy(errmsg, strerror(errno), buflen);
8034  return -1;
8035 }
8036 #endif
8037 
8038 FILE *
8039 ruby_popen_writer(char *const *argv, rb_pid_t *pid)
8040 {
8041 #if (defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)) || defined(_WIN32)
8042 # ifdef HAVE_WORKING_FORK
8043  struct popen_writer_arg pw;
8044  int *const write_pair = pw.popen.pair;
8045 # else
8046  int write_pair[2];
8047 # endif
8048 
8049  int result = rb_cloexec_pipe(write_pair);
8050  *pid = -1;
8051  if (result == 0) {
8052 # ifdef HAVE_WORKING_FORK
8053  pw.argv = argv;
8054  int status;
8055  char errmsg[80] = {'\0'};
8056  *pid = rb_fork_async_signal_safe(&status, exec_popen_writer, &pw, Qnil, errmsg, sizeof(errmsg));
8057 # else
8058  *pid = rb_w32_uspawn_process(P_NOWAIT, argv[0], argv, write_pair[0], -1, -1, 0);
8059  const char *errmsg = (*pid < 0) ? strerror(errno) : NULL;
8060 # endif
8061  close(write_pair[0]);
8062  if (*pid < 0) {
8063  close(write_pair[1]);
8064  fprintf(stderr, "ruby_popen_writer(%s): %s\n", argv[0], errmsg);
8065  }
8066  else {
8067  return fdopen(write_pair[1], "w");
8068  }
8069  }
8070 #endif
8071  return NULL;
8072 }
8073 
8074 static VALUE
8075 rb_open_file(VALUE io, VALUE fname, VALUE vmode, VALUE vperm, VALUE opt)
8076 {
8077  struct rb_io_encoding convconfig;
8078  int oflags, fmode;
8079  mode_t perm;
8080 
8081  FilePathValue(fname);
8082 
8083  rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, &convconfig);
8084  perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
8085 
8086  rb_file_open_generic(io, fname, oflags, fmode, &convconfig, perm);
8087 
8088  return io;
8089 }
8090 
8091 /*
8092  * Document-method: File::open
8093  *
8094  * call-seq:
8095  * File.open(path, mode = 'r', perm = 0666, **opts) -> file
8096  * File.open(path, mode = 'r', perm = 0666, **opts) {|f| ... } -> object
8097  *
8098  * Creates a new File object, via File.new with the given arguments.
8099  *
8100  * With no block given, returns the File object.
8101  *
8102  * With a block given, calls the block with the File object
8103  * and returns the block's value.
8104  *
8105  */
8106 
8107 /*
8108  * Document-method: IO::open
8109  *
8110  * call-seq:
8111  * IO.open(fd, mode = 'r', **opts) -> io
8112  * IO.open(fd, mode = 'r', **opts) {|io| ... } -> object
8113  *
8114  * Creates a new \IO object, via IO.new with the given arguments.
8115  *
8116  * With no block given, returns the \IO object.
8117  *
8118  * With a block given, calls the block with the \IO object
8119  * and returns the block's value.
8120  *
8121  */
8122 
8123 static VALUE
8124 rb_io_s_open(int argc, VALUE *argv, VALUE klass)
8125 {
8126  VALUE io = rb_class_new_instance_kw(argc, argv, klass, RB_PASS_CALLED_KEYWORDS);
8127 
8128  if (rb_block_given_p()) {
8129  return rb_ensure(rb_yield, io, io_close, io);
8130  }
8131 
8132  return io;
8133 }
8134 
8135 /*
8136  * call-seq:
8137  * IO.sysopen(path, mode = 'r', perm = 0666) -> integer
8138  *
8139  * Opens the file at the given path with the given mode and permissions;
8140  * returns the integer file descriptor.
8141  *
8142  * If the file is to be readable, it must exist;
8143  * if the file is to be writable and does not exist,
8144  * it is created with the given permissions:
8145  *
8146  * File.write('t.tmp', '') # => 0
8147  * IO.sysopen('t.tmp') # => 8
8148  * IO.sysopen('t.tmp', 'w') # => 9
8149  *
8150  *
8151  */
8152 
8153 static VALUE
8154 rb_io_s_sysopen(int argc, VALUE *argv, VALUE _)
8155 {
8156  VALUE fname, vmode, vperm;
8157  VALUE intmode;
8158  int oflags, fd;
8159  mode_t perm;
8160 
8161  rb_scan_args(argc, argv, "12", &fname, &vmode, &vperm);
8162  FilePathValue(fname);
8163 
8164  if (NIL_P(vmode))
8165  oflags = O_RDONLY;
8166  else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int")))
8167  oflags = NUM2INT(intmode);
8168  else {
8169  StringValue(vmode);
8170  oflags = rb_io_modestr_oflags(StringValueCStr(vmode));
8171  }
8172  if (NIL_P(vperm)) perm = 0666;
8173  else perm = NUM2MODET(vperm);
8174 
8175  RB_GC_GUARD(fname) = rb_str_new4(fname);
8176  fd = rb_sysopen(fname, oflags, perm);
8177  return INT2NUM(fd);
8178 }
8179 
8180 static VALUE
8181 check_pipe_command(VALUE filename_or_command)
8182 {
8183  char *s = RSTRING_PTR(filename_or_command);
8184  long l = RSTRING_LEN(filename_or_command);
8185  char *e = s + l;
8186  int chlen;
8187 
8188  if (rb_enc_ascget(s, e, &chlen, rb_enc_get(filename_or_command)) == '|') {
8189  VALUE cmd = rb_str_new(s+chlen, l-chlen);
8190  return cmd;
8191  }
8192  return Qnil;
8193 }
8194 
8195 /*
8196  * call-seq:
8197  * open(path, mode = 'r', perm = 0666, **opts) -> io or nil
8198  * open(path, mode = 'r', perm = 0666, **opts) {|io| ... } -> obj
8199  *
8200  * Creates an IO object connected to the given file.
8201  *
8202  * This method has potential security vulnerabilities if called with untrusted input;
8203  * see {Command Injection}[rdoc-ref:command_injection.rdoc].
8204  *
8205  * With no block given, file stream is returned:
8206  *
8207  * open('t.txt') # => #<File:t.txt>
8208  *
8209  * With a block given, calls the block with the open file stream,
8210  * then closes the stream:
8211  *
8212  * open('t.txt') {|f| p f } # => #<File:t.txt (closed)>
8213  *
8214  * Output:
8215  *
8216  * #<File:t.txt>
8217  *
8218  * See File.open for details.
8219  *
8220  */
8221 
8222 static VALUE
8223 rb_f_open(int argc, VALUE *argv, VALUE _)
8224 {
8225  ID to_open = 0;
8226  int redirect = FALSE;
8227 
8228  if (argc >= 1) {
8229  CONST_ID(to_open, "to_open");
8230  if (rb_respond_to(argv[0], to_open)) {
8231  redirect = TRUE;
8232  }
8233  else {
8234  VALUE tmp = argv[0];
8235  FilePathValue(tmp);
8236  if (NIL_P(tmp)) {
8237  redirect = TRUE;
8238  }
8239  else {
8240  VALUE cmd = check_pipe_command(tmp);
8241  if (!NIL_P(cmd)) {
8242  // TODO: when removed in 4.0, update command_injection.rdoc
8243  rb_warn_deprecated_to_remove_at(4.0, "Calling Kernel#open with a leading '|'", "IO.popen");
8244  argv[0] = cmd;
8245  return rb_io_s_popen(argc, argv, rb_cIO);
8246  }
8247  }
8248  }
8249  }
8250  if (redirect) {
8251  VALUE io = rb_funcallv_kw(argv[0], to_open, argc-1, argv+1, RB_PASS_CALLED_KEYWORDS);
8252 
8253  if (rb_block_given_p()) {
8254  return rb_ensure(rb_yield, io, io_close, io);
8255  }
8256  return io;
8257  }
8258  return rb_io_s_open(argc, argv, rb_cFile);
8259 }
8260 
8261 static VALUE rb_io_open_generic(VALUE, VALUE, int, int, const struct rb_io_encoding *, mode_t);
8262 
8263 static VALUE
8264 rb_io_open(VALUE io, VALUE filename, VALUE vmode, VALUE vperm, VALUE opt)
8265 {
8266  int oflags, fmode;
8267  struct rb_io_encoding convconfig;
8268  mode_t perm;
8269 
8270  rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, &convconfig);
8271  perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
8272  return rb_io_open_generic(io, filename, oflags, fmode, &convconfig, perm);
8273 }
8274 
8275 static VALUE
8276 rb_io_open_generic(VALUE klass, VALUE filename, int oflags, int fmode,
8277  const struct rb_io_encoding *convconfig, mode_t perm)
8278 {
8279  VALUE cmd;
8280  if (klass == rb_cIO && !NIL_P(cmd = check_pipe_command(filename))) {
8281  // TODO: when removed in 4.0, update command_injection.rdoc
8282  rb_warn_deprecated_to_remove_at(4.0, "IO process creation with a leading '|'", "IO.popen");
8283  return pipe_open_s(cmd, rb_io_oflags_modestr(oflags), fmode, convconfig);
8284  }
8285  else {
8286  return rb_file_open_generic(io_alloc(klass), filename,
8287  oflags, fmode, convconfig, perm);
8288  }
8289 }
8290 
8291 static VALUE
8292 io_reopen(VALUE io, VALUE nfile)
8293 {
8294  rb_io_t *fptr, *orig;
8295  int fd, fd2;
8296  rb_off_t pos = 0;
8297 
8298  nfile = rb_io_get_io(nfile);
8299  GetOpenFile(io, fptr);
8300  GetOpenFile(nfile, orig);
8301 
8302  if (fptr == orig) return io;
8303  if (RUBY_IO_EXTERNAL_P(fptr)) {
8304  if ((fptr->stdio_file == stdin && !(orig->mode & FMODE_READABLE)) ||
8305  (fptr->stdio_file == stdout && !(orig->mode & FMODE_WRITABLE)) ||
8306  (fptr->stdio_file == stderr && !(orig->mode & FMODE_WRITABLE))) {
8308  "%s can't change access mode from \"%s\" to \"%s\"",
8309  PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
8310  rb_io_fmode_modestr(orig->mode));
8311  }
8312  }
8313  if (fptr->mode & FMODE_WRITABLE) {
8314  if (io_fflush(fptr) < 0)
8315  rb_sys_fail_on_write(fptr);
8316  }
8317  else {
8318  flush_before_seek(fptr, true);
8319  }
8320  if (orig->mode & FMODE_READABLE) {
8321  pos = io_tell(orig);
8322  }
8323  if (orig->mode & FMODE_WRITABLE) {
8324  if (io_fflush(orig) < 0)
8325  rb_sys_fail_on_write(fptr);
8326  }
8327 
8328  /* copy rb_io_t structure */
8329  fptr->mode = orig->mode | (fptr->mode & FMODE_EXTERNAL);
8330  fptr->encs = orig->encs;
8331  fptr->pid = orig->pid;
8332  fptr->lineno = orig->lineno;
8333  if (RTEST(orig->pathv)) fptr->pathv = orig->pathv;
8334  else if (!RUBY_IO_EXTERNAL_P(fptr)) fptr->pathv = Qnil;
8335  fptr_copy_finalizer(fptr, orig);
8336 
8337  fd = fptr->fd;
8338  fd2 = orig->fd;
8339  if (fd != fd2) {
8340  if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2 || !fptr->stdio_file) {
8341  /* need to keep FILE objects of stdin, stdout and stderr */
8342  if (rb_cloexec_dup2(fd2, fd) < 0)
8343  rb_sys_fail_path(orig->pathv);
8344  rb_update_max_fd(fd);
8345  }
8346  else {
8347  fclose(fptr->stdio_file);
8348  fptr->stdio_file = 0;
8349  fptr->fd = -1;
8350  if (rb_cloexec_dup2(fd2, fd) < 0)
8351  rb_sys_fail_path(orig->pathv);
8352  rb_update_max_fd(fd);
8353  fptr->fd = fd;
8354  }
8355  rb_thread_fd_close(fd);
8356  if ((orig->mode & FMODE_READABLE) && pos >= 0) {
8357  if (io_seek(fptr, pos, SEEK_SET) < 0 && errno) {
8358  rb_sys_fail_path(fptr->pathv);
8359  }
8360  if (io_seek(orig, pos, SEEK_SET) < 0 && errno) {
8361  rb_sys_fail_path(orig->pathv);
8362  }
8363  }
8364  }
8365 
8366  if (fptr->mode & FMODE_BINMODE) {
8367  rb_io_binmode(io);
8368  }
8369 
8370  RBASIC_SET_CLASS(io, rb_obj_class(nfile));
8371  return io;
8372 }
8373 
8374 #ifdef _WIN32
8375 int rb_freopen(VALUE fname, const char *mode, FILE *fp);
8376 #else
8377 static int
8378 rb_freopen(VALUE fname, const char *mode, FILE *fp)
8379 {
8380  if (!freopen(RSTRING_PTR(fname), mode, fp)) {
8381  RB_GC_GUARD(fname);
8382  return errno;
8383  }
8384  return 0;
8385 }
8386 #endif
8387 
8388 /*
8389  * call-seq:
8390  * reopen(other_io) -> self
8391  * reopen(path, mode = 'r', **opts) -> self
8392  *
8393  * Reassociates the stream with another stream,
8394  * which may be of a different class.
8395  * This method may be used to redirect an existing stream
8396  * to a new destination.
8397  *
8398  * With argument +other_io+ given, reassociates with that stream:
8399  *
8400  * # Redirect $stdin from a file.
8401  * f = File.open('t.txt')
8402  * $stdin.reopen(f)
8403  * f.close
8404  *
8405  * # Redirect $stdout to a file.
8406  * f = File.open('t.tmp', 'w')
8407  * $stdout.reopen(f)
8408  * f.close
8409  *
8410  * With argument +path+ given, reassociates with a new stream to that file path:
8411  *
8412  * $stdin.reopen('t.txt')
8413  * $stdout.reopen('t.tmp', 'w')
8414  *
8415  * Optional keyword arguments +opts+ specify:
8416  *
8417  * - {Open Options}[rdoc-ref:IO@Open+Options].
8418  * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
8419  *
8420  */
8421 
8422 static VALUE
8423 rb_io_reopen(int argc, VALUE *argv, VALUE file)
8424 {
8425  VALUE fname, nmode, opt;
8426  int oflags;
8427  rb_io_t *fptr;
8428 
8429  if (rb_scan_args(argc, argv, "11:", &fname, &nmode, &opt) == 1) {
8430  VALUE tmp = rb_io_check_io(fname);
8431  if (!NIL_P(tmp)) {
8432  return io_reopen(file, tmp);
8433  }
8434  }
8435 
8436  FilePathValue(fname);
8437  rb_io_taint_check(file);
8438  fptr = RFILE(file)->fptr;
8439  if (!fptr) {
8440  fptr = RFILE(file)->fptr = ZALLOC(rb_io_t);
8441  }
8442 
8443  if (!NIL_P(nmode) || !NIL_P(opt)) {
8444  int fmode;
8445  struct rb_io_encoding convconfig;
8446 
8447  rb_io_extract_modeenc(&nmode, 0, opt, &oflags, &fmode, &convconfig);
8448  if (RUBY_IO_EXTERNAL_P(fptr) &&
8449  ((fptr->mode & FMODE_READWRITE) & (fmode & FMODE_READWRITE)) !=
8450  (fptr->mode & FMODE_READWRITE)) {
8452  "%s can't change access mode from \"%s\" to \"%s\"",
8453  PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
8454  rb_io_fmode_modestr(fmode));
8455  }
8456  fptr->mode = fmode;
8457  fptr->encs = convconfig;
8458  }
8459  else {
8460  oflags = rb_io_fmode_oflags(fptr->mode);
8461  }
8462 
8463  fptr->pathv = fname;
8464  if (fptr->fd < 0) {
8465  fptr->fd = rb_sysopen(fptr->pathv, oflags, 0666);
8466  fptr->stdio_file = 0;
8467  return file;
8468  }
8469 
8470  if (fptr->mode & FMODE_WRITABLE) {
8471  if (io_fflush(fptr) < 0)
8472  rb_sys_fail_on_write(fptr);
8473  }
8474  fptr->rbuf.off = fptr->rbuf.len = 0;
8475 
8476  if (fptr->stdio_file) {
8477  int e = rb_freopen(rb_str_encode_ospath(fptr->pathv),
8478  rb_io_oflags_modestr(oflags),
8479  fptr->stdio_file);
8480  if (e) rb_syserr_fail_path(e, fptr->pathv);
8481  fptr->fd = fileno(fptr->stdio_file);
8482  rb_fd_fix_cloexec(fptr->fd);
8483 #ifdef USE_SETVBUF
8484  if (setvbuf(fptr->stdio_file, NULL, _IOFBF, 0) != 0)
8485  rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8486 #endif
8487  if (fptr->stdio_file == stderr) {
8488  if (setvbuf(fptr->stdio_file, NULL, _IONBF, BUFSIZ) != 0)
8489  rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8490  }
8491  else if (fptr->stdio_file == stdout && isatty(fptr->fd)) {
8492  if (setvbuf(fptr->stdio_file, NULL, _IOLBF, BUFSIZ) != 0)
8493  rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8494  }
8495  }
8496  else {
8497  int tmpfd = rb_sysopen(fptr->pathv, oflags, 0666);
8498  int err = 0;
8499  if (rb_cloexec_dup2(tmpfd, fptr->fd) < 0)
8500  err = errno;
8501  (void)close(tmpfd);
8502  if (err) {
8503  rb_syserr_fail_path(err, fptr->pathv);
8504  }
8505  }
8506 
8507  return file;
8508 }
8509 
8510 /* :nodoc: */
8511 static VALUE
8512 rb_io_init_copy(VALUE dest, VALUE io)
8513 {
8514  rb_io_t *fptr, *orig;
8515  int fd;
8516  VALUE write_io;
8517  rb_off_t pos;
8518 
8519  io = rb_io_get_io(io);
8520  if (!OBJ_INIT_COPY(dest, io)) return dest;
8521  GetOpenFile(io, orig);
8522  MakeOpenFile(dest, fptr);
8523 
8524  rb_io_flush(io);
8525 
8526  /* copy rb_io_t structure */
8527  fptr->mode = orig->mode & ~FMODE_EXTERNAL;
8528  fptr->encs = orig->encs;
8529  fptr->pid = orig->pid;
8530  fptr->lineno = orig->lineno;
8531  fptr->timeout = orig->timeout;
8532  if (!NIL_P(orig->pathv)) fptr->pathv = orig->pathv;
8533  fptr_copy_finalizer(fptr, orig);
8534 
8535  fd = ruby_dup(orig->fd);
8536  fptr->fd = fd;
8537  pos = io_tell(orig);
8538  if (0 <= pos)
8539  io_seek(fptr, pos, SEEK_SET);
8540  if (fptr->mode & FMODE_BINMODE) {
8541  rb_io_binmode(dest);
8542  }
8543 
8544  write_io = GetWriteIO(io);
8545  if (io != write_io) {
8546  write_io = rb_obj_dup(write_io);
8547  fptr->tied_io_for_writing = write_io;
8548  rb_ivar_set(dest, rb_intern("@tied_io_for_writing"), write_io);
8549  }
8550 
8551  return dest;
8552 }
8553 
8554 /*
8555  * call-seq:
8556  * printf(format_string, *objects) -> nil
8557  *
8558  * Formats and writes +objects+ to the stream.
8559  *
8560  * For details on +format_string+, see
8561  * {Format Specifications}[rdoc-ref:format_specifications.rdoc].
8562  *
8563  */
8564 
8565 VALUE
8566 rb_io_printf(int argc, const VALUE *argv, VALUE out)
8567 {
8568  rb_io_write(out, rb_f_sprintf(argc, argv));
8569  return Qnil;
8570 }
8571 
8572 /*
8573  * call-seq:
8574  * printf(format_string, *objects) -> nil
8575  * printf(io, format_string, *objects) -> nil
8576  *
8577  * Equivalent to:
8578  *
8579  * io.write(sprintf(format_string, *objects))
8580  *
8581  * For details on +format_string+, see
8582  * {Format Specifications}[rdoc-ref:format_specifications.rdoc].
8583  *
8584  * With the single argument +format_string+, formats +objects+ into the string,
8585  * then writes the formatted string to $stdout:
8586  *
8587  * printf('%4.4d %10s %2.2f', 24, 24, 24.0)
8588  *
8589  * Output (on $stdout):
8590  *
8591  * 0024 24 24.00#
8592  *
8593  * With arguments +io+ and +format_string+, formats +objects+ into the string,
8594  * then writes the formatted string to +io+:
8595  *
8596  * printf($stderr, '%4.4d %10s %2.2f', 24, 24, 24.0)
8597  *
8598  * Output (on $stderr):
8599  *
8600  * 0024 24 24.00# => nil
8601  *
8602  * With no arguments, does nothing.
8603  *
8604  */
8605 
8606 static VALUE
8607 rb_f_printf(int argc, VALUE *argv, VALUE _)
8608 {
8609  VALUE out;
8610 
8611  if (argc == 0) return Qnil;
8612  if (RB_TYPE_P(argv[0], T_STRING)) {
8613  out = rb_ractor_stdout();
8614  }
8615  else {
8616  out = argv[0];
8617  argv++;
8618  argc--;
8619  }
8620  rb_io_write(out, rb_f_sprintf(argc, argv));
8621 
8622  return Qnil;
8623 }
8624 
8625 static void
8626 deprecated_str_setter(VALUE val, ID id, VALUE *var)
8627 {
8628  rb_str_setter(val, id, &val);
8629  if (!NIL_P(val)) {
8630  rb_warn_deprecated("'%s'", NULL, rb_id2name(id));
8631  }
8632  *var = val;
8633 }
8634 
8635 /*
8636  * call-seq:
8637  * print(*objects) -> nil
8638  *
8639  * Writes the given objects to the stream; returns +nil+.
8640  * Appends the output record separator <tt>$OUTPUT_RECORD_SEPARATOR</tt>
8641  * (<tt>$\</tt>), if it is not +nil+.
8642  * See {Line IO}[rdoc-ref:IO@Line+IO].
8643  *
8644  * With argument +objects+ given, for each object:
8645  *
8646  * - Converts via its method +to_s+ if not a string.
8647  * - Writes to the stream.
8648  * - If not the last object, writes the output field separator
8649  * <tt>$OUTPUT_FIELD_SEPARATOR</tt> (<tt>$,</tt>) if it is not +nil+.
8650  *
8651  * With default separators:
8652  *
8653  * f = File.open('t.tmp', 'w+')
8654  * objects = [0, 0.0, Rational(0, 1), Complex(0, 0), :zero, 'zero']
8655  * p $OUTPUT_RECORD_SEPARATOR
8656  * p $OUTPUT_FIELD_SEPARATOR
8657  * f.print(*objects)
8658  * f.rewind
8659  * p f.read
8660  * f.close
8661  *
8662  * Output:
8663  *
8664  * nil
8665  * nil
8666  * "00.00/10+0izerozero"
8667  *
8668  * With specified separators:
8669  *
8670  * $\ = "\n"
8671  * $, = ','
8672  * f.rewind
8673  * f.print(*objects)
8674  * f.rewind
8675  * p f.read
8676  *
8677  * Output:
8678  *
8679  * "0,0.0,0/1,0+0i,zero,zero\n"
8680  *
8681  * With no argument given, writes the content of <tt>$_</tt>
8682  * (which is usually the most recent user input):
8683  *
8684  * f = File.open('t.tmp', 'w+')
8685  * gets # Sets $_ to the most recent user input.
8686  * f.print
8687  * f.close
8688  *
8689  */
8690 
8691 VALUE
8692 rb_io_print(int argc, const VALUE *argv, VALUE out)
8693 {
8694  int i;
8695  VALUE line;
8696 
8697  /* if no argument given, print `$_' */
8698  if (argc == 0) {
8699  argc = 1;
8700  line = rb_lastline_get();
8701  argv = &line;
8702  }
8703  if (argc > 1 && !NIL_P(rb_output_fs)) {
8704  rb_category_warn(RB_WARN_CATEGORY_DEPRECATED, "$, is set to non-nil value");
8705  }
8706  for (i=0; i<argc; i++) {
8707  if (!NIL_P(rb_output_fs) && i>0) {
8708  rb_io_write(out, rb_output_fs);
8709  }
8710  rb_io_write(out, argv[i]);
8711  }
8712  if (argc > 0 && !NIL_P(rb_output_rs)) {
8713  rb_io_write(out, rb_output_rs);
8714  }
8715 
8716  return Qnil;
8717 }
8718 
8719 /*
8720  * call-seq:
8721  * print(*objects) -> nil
8722  *
8723  * Equivalent to <tt>$stdout.print(*objects)</tt>,
8724  * this method is the straightforward way to write to <tt>$stdout</tt>.
8725  *
8726  * Writes the given objects to <tt>$stdout</tt>; returns +nil+.
8727  * Appends the output record separator <tt>$OUTPUT_RECORD_SEPARATOR</tt>
8728  * <tt>$\</tt>), if it is not +nil+.
8729  *
8730  * With argument +objects+ given, for each object:
8731  *
8732  * - Converts via its method +to_s+ if not a string.
8733  * - Writes to <tt>stdout</tt>.
8734  * - If not the last object, writes the output field separator
8735  * <tt>$OUTPUT_FIELD_SEPARATOR</tt> (<tt>$,</tt> if it is not +nil+.
8736  *
8737  * With default separators:
8738  *
8739  * objects = [0, 0.0, Rational(0, 1), Complex(0, 0), :zero, 'zero']
8740  * $OUTPUT_RECORD_SEPARATOR
8741  * $OUTPUT_FIELD_SEPARATOR
8742  * print(*objects)
8743  *
8744  * Output:
8745  *
8746  * nil
8747  * nil
8748  * 00.00/10+0izerozero
8749  *
8750  * With specified separators:
8751  *
8752  * $OUTPUT_RECORD_SEPARATOR = "\n"
8753  * $OUTPUT_FIELD_SEPARATOR = ','
8754  * print(*objects)
8755  *
8756  * Output:
8757  *
8758  * 0,0.0,0/1,0+0i,zero,zero
8759  *
8760  * With no argument given, writes the content of <tt>$_</tt>
8761  * (which is usually the most recent user input):
8762  *
8763  * gets # Sets $_ to the most recent user input.
8764  * print # Prints $_.
8765  *
8766  */
8767 
8768 static VALUE
8769 rb_f_print(int argc, const VALUE *argv, VALUE _)
8770 {
8771  rb_io_print(argc, argv, rb_ractor_stdout());
8772  return Qnil;
8773 }
8774 
8775 /*
8776  * call-seq:
8777  * putc(object) -> object
8778  *
8779  * Writes a character to the stream.
8780  * See {Character IO}[rdoc-ref:IO@Character+IO].
8781  *
8782  * If +object+ is numeric, converts to integer if necessary,
8783  * then writes the character whose code is the
8784  * least significant byte;
8785  * if +object+ is a string, writes the first character:
8786  *
8787  * $stdout.putc "A"
8788  * $stdout.putc 65
8789  *
8790  * Output:
8791  *
8792  * AA
8793  *
8794  */
8795 
8796 static VALUE
8797 rb_io_putc(VALUE io, VALUE ch)
8798 {
8799  VALUE str;
8800  if (RB_TYPE_P(ch, T_STRING)) {
8801  str = rb_str_substr(ch, 0, 1);
8802  }
8803  else {
8804  char c = NUM2CHR(ch);
8805  str = rb_str_new(&c, 1);
8806  }
8807  rb_io_write(io, str);
8808  return ch;
8809 }
8810 
8811 #define forward(obj, id, argc, argv) \
8812  rb_funcallv_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8813 #define forward_public(obj, id, argc, argv) \
8814  rb_funcallv_public_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8815 #define forward_current(id, argc, argv) \
8816  forward_public(ARGF.current_file, id, argc, argv)
8817 
8818 /*
8819  * call-seq:
8820  * putc(int) -> int
8821  *
8822  * Equivalent to:
8823  *
8824  * $stdout.putc(int)
8825  *
8826  * See IO#putc for important information regarding multi-byte characters.
8827  *
8828  */
8829 
8830 static VALUE
8831 rb_f_putc(VALUE recv, VALUE ch)
8832 {
8833  VALUE r_stdout = rb_ractor_stdout();
8834  if (recv == r_stdout) {
8835  return rb_io_putc(recv, ch);
8836  }
8837  return forward(r_stdout, rb_intern("putc"), 1, &ch);
8838 }
8839 
8840 
8841 int
8842 rb_str_end_with_asciichar(VALUE str, int c)
8843 {
8844  long len = RSTRING_LEN(str);
8845  const char *ptr = RSTRING_PTR(str);
8847  int n;
8848 
8849  if (len == 0) return 0;
8850  if ((n = rb_enc_mbminlen(enc)) == 1) {
8851  return ptr[len - 1] == c;
8852  }
8853  return rb_enc_ascget(ptr + ((len - 1) / n) * n, ptr + len, &n, enc) == c;
8854 }
8855 
8856 static VALUE
8857 io_puts_ary(VALUE ary, VALUE out, int recur)
8858 {
8859  VALUE tmp;
8860  long i;
8861 
8862  if (recur) {
8863  tmp = rb_str_new2("[...]");
8864  rb_io_puts(1, &tmp, out);
8865  return Qtrue;
8866  }
8867  ary = rb_check_array_type(ary);
8868  if (NIL_P(ary)) return Qfalse;
8869  for (i=0; i<RARRAY_LEN(ary); i++) {
8870  tmp = RARRAY_AREF(ary, i);
8871  rb_io_puts(1, &tmp, out);
8872  }
8873  return Qtrue;
8874 }
8875 
8876 /*
8877  * call-seq:
8878  * puts(*objects) -> nil
8879  *
8880  * Writes the given +objects+ to the stream, which must be open for writing;
8881  * returns +nil+.\
8882  * Writes a newline after each that does not already end with a newline sequence.
8883  * If called without arguments, writes a newline.
8884  * See {Line IO}[rdoc-ref:IO@Line+IO].
8885  *
8886  * Note that each added newline is the character <tt>"\n"<//tt>,
8887  * not the output record separator (<tt>$\</tt>).
8888  *
8889  * Treatment for each object:
8890  *
8891  * - String: writes the string.
8892  * - Neither string nor array: writes <tt>object.to_s</tt>.
8893  * - Array: writes each element of the array; arrays may be nested.
8894  *
8895  * To keep these examples brief, we define this helper method:
8896  *
8897  * def show(*objects)
8898  * # Puts objects to file.
8899  * f = File.new('t.tmp', 'w+')
8900  * f.puts(objects)
8901  * # Return file content.
8902  * f.rewind
8903  * p f.read
8904  * f.close
8905  * end
8906  *
8907  * # Strings without newlines.
8908  * show('foo', 'bar', 'baz') # => "foo\nbar\nbaz\n"
8909  * # Strings, some with newlines.
8910  * show("foo\n", 'bar', "baz\n") # => "foo\nbar\nbaz\n"
8911  *
8912  * # Neither strings nor arrays:
8913  * show(0, 0.0, Rational(0, 1), Complex(9, 0), :zero)
8914  * # => "0\n0.0\n0/1\n9+0i\nzero\n"
8915  *
8916  * # Array of strings.
8917  * show(['foo', "bar\n", 'baz']) # => "foo\nbar\nbaz\n"
8918  * # Nested arrays.
8919  * show([[[0, 1], 2, 3], 4, 5]) # => "0\n1\n2\n3\n4\n5\n"
8920  *
8921  */
8922 
8923 VALUE
8924 rb_io_puts(int argc, const VALUE *argv, VALUE out)
8925 {
8926  VALUE line, args[2];
8927 
8928  /* if no argument given, print newline. */
8929  if (argc == 0) {
8930  rb_io_write(out, rb_default_rs);
8931  return Qnil;
8932  }
8933  for (int i = 0; i < argc; i++) {
8934  // Convert the argument to a string:
8935  if (RB_TYPE_P(argv[i], T_STRING)) {
8936  line = argv[i];
8937  }
8938  else if (rb_exec_recursive(io_puts_ary, argv[i], out)) {
8939  continue;
8940  }
8941  else {
8942  line = rb_obj_as_string(argv[i]);
8943  }
8944 
8945  // Write the line:
8946  int n = 0;
8947  if (RSTRING_LEN(line) == 0) {
8948  args[n++] = rb_default_rs;
8949  }
8950  else {
8951  args[n++] = line;
8952  if (!rb_str_end_with_asciichar(line, '\n')) {
8953  args[n++] = rb_default_rs;
8954  }
8955  }
8956 
8957  rb_io_writev(out, n, args);
8958  }
8959 
8960  return Qnil;
8961 }
8962 
8963 /*
8964  * call-seq:
8965  * puts(*objects) -> nil
8966  *
8967  * Equivalent to
8968  *
8969  * $stdout.puts(objects)
8970  */
8971 
8972 static VALUE
8973 rb_f_puts(int argc, VALUE *argv, VALUE recv)
8974 {
8975  VALUE r_stdout = rb_ractor_stdout();
8976  if (recv == r_stdout) {
8977  return rb_io_puts(argc, argv, recv);
8978  }
8979  return forward(r_stdout, rb_intern("puts"), argc, argv);
8980 }
8981 
8982 static VALUE
8983 rb_p_write(VALUE str)
8984 {
8985  VALUE args[2];
8986  args[0] = str;
8987  args[1] = rb_default_rs;
8988  VALUE r_stdout = rb_ractor_stdout();
8989  if (RB_TYPE_P(r_stdout, T_FILE) &&
8990  rb_method_basic_definition_p(CLASS_OF(r_stdout), id_write)) {
8991  io_writev(2, args, r_stdout);
8992  }
8993  else {
8994  rb_io_writev(r_stdout, 2, args);
8995  }
8996  return Qnil;
8997 }
8998 
8999 void
9000 rb_p(VALUE obj) /* for debug print within C code */
9001 {
9002  rb_p_write(rb_obj_as_string(rb_inspect(obj)));
9003 }
9004 
9005 static VALUE
9006 rb_p_result(int argc, const VALUE *argv)
9007 {
9008  VALUE ret = Qnil;
9009 
9010  if (argc == 1) {
9011  ret = argv[0];
9012  }
9013  else if (argc > 1) {
9014  ret = rb_ary_new4(argc, argv);
9015  }
9016  VALUE r_stdout = rb_ractor_stdout();
9017  if (RB_TYPE_P(r_stdout, T_FILE)) {
9018  rb_uninterruptible(rb_io_flush, r_stdout);
9019  }
9020  return ret;
9021 }
9022 
9023 /*
9024  * call-seq:
9025  * p(object) -> obj
9026  * p(*objects) -> array of objects
9027  * p -> nil
9028  *
9029  * For each object +obj+, executes:
9030  *
9031  * $stdout.write(obj.inspect, "\n")
9032  *
9033  * With one object given, returns the object;
9034  * with multiple objects given, returns an array containing the objects;
9035  * with no object given, returns +nil+.
9036  *
9037  * Examples:
9038  *
9039  * r = Range.new(0, 4)
9040  * p r # => 0..4
9041  * p [r, r, r] # => [0..4, 0..4, 0..4]
9042  * p # => nil
9043  *
9044  * Output:
9045  *
9046  * 0..4
9047  * [0..4, 0..4, 0..4]
9048  *
9049  * Kernel#p is designed for debugging purposes.
9050  * Ruby implementations may define Kernel#p to be uninterruptible
9051  * in whole or in part.
9052  * On CRuby, Kernel#p's writing of data is uninterruptible.
9053  */
9054 
9055 static VALUE
9056 rb_f_p(int argc, VALUE *argv, VALUE self)
9057 {
9058  int i;
9059  for (i=0; i<argc; i++) {
9060  VALUE inspected = rb_obj_as_string(rb_inspect(argv[i]));
9061  rb_uninterruptible(rb_p_write, inspected);
9062  }
9063  return rb_p_result(argc, argv);
9064 }
9065 
9066 /*
9067  * call-seq:
9068  * display(port = $>) -> nil
9069  *
9070  * Writes +self+ on the given port:
9071  *
9072  * 1.display
9073  * "cat".display
9074  * [ 4, 5, 6 ].display
9075  * puts
9076  *
9077  * Output:
9078  *
9079  * 1cat[4, 5, 6]
9080  *
9081  */
9082 
9083 static VALUE
9084 rb_obj_display(int argc, VALUE *argv, VALUE self)
9085 {
9086  VALUE out;
9087 
9088  out = (!rb_check_arity(argc, 0, 1) ? rb_ractor_stdout() : argv[0]);
9089  rb_io_write(out, self);
9090 
9091  return Qnil;
9092 }
9093 
9094 static int
9095 rb_stderr_to_original_p(VALUE err)
9096 {
9097  return (err == orig_stderr || RFILE(orig_stderr)->fptr->fd < 0);
9098 }
9099 
9100 void
9101 rb_write_error2(const char *mesg, long len)
9102 {
9103  VALUE out = rb_ractor_stderr();
9104  if (rb_stderr_to_original_p(out)) {
9105 #ifdef _WIN32
9106  if (isatty(fileno(stderr))) {
9107  if (rb_w32_write_console(rb_str_new(mesg, len), fileno(stderr)) > 0) return;
9108  }
9109 #endif
9110  if (fwrite(mesg, sizeof(char), (size_t)len, stderr) < (size_t)len) {
9111  /* failed to write to stderr, what can we do? */
9112  return;
9113  }
9114  }
9115  else {
9116  rb_io_write(out, rb_str_new(mesg, len));
9117  }
9118 }
9119 
9120 void
9121 rb_write_error(const char *mesg)
9122 {
9123  rb_write_error2(mesg, strlen(mesg));
9124 }
9125 
9126 void
9127 rb_write_error_str(VALUE mesg)
9128 {
9129  VALUE out = rb_ractor_stderr();
9130  /* a stopgap measure for the time being */
9131  if (rb_stderr_to_original_p(out)) {
9132  size_t len = (size_t)RSTRING_LEN(mesg);
9133 #ifdef _WIN32
9134  if (isatty(fileno(stderr))) {
9135  if (rb_w32_write_console(mesg, fileno(stderr)) > 0) return;
9136  }
9137 #endif
9138  if (fwrite(RSTRING_PTR(mesg), sizeof(char), len, stderr) < len) {
9139  RB_GC_GUARD(mesg);
9140  return;
9141  }
9142  }
9143  else {
9144  /* may unlock GVL, and */
9145  rb_io_write(out, mesg);
9146  }
9147 }
9148 
9149 int
9150 rb_stderr_tty_p(void)
9151 {
9152  if (rb_stderr_to_original_p(rb_ractor_stderr()))
9153  return isatty(fileno(stderr));
9154  return 0;
9155 }
9156 
9157 static void
9158 must_respond_to(ID mid, VALUE val, ID id)
9159 {
9160  if (!rb_respond_to(val, mid)) {
9161  rb_raise(rb_eTypeError, "%"PRIsVALUE" must have %"PRIsVALUE" method, %"PRIsVALUE" given",
9162  rb_id2str(id), rb_id2str(mid),
9163  rb_obj_class(val));
9164  }
9165 }
9166 
9167 static void
9168 stdin_setter(VALUE val, ID id, VALUE *ptr)
9169 {
9170  rb_ractor_stdin_set(val);
9171 }
9172 
9173 static VALUE
9174 stdin_getter(ID id, VALUE *ptr)
9175 {
9176  return rb_ractor_stdin();
9177 }
9178 
9179 static void
9180 stdout_setter(VALUE val, ID id, VALUE *ptr)
9181 {
9182  must_respond_to(id_write, val, id);
9183  rb_ractor_stdout_set(val);
9184 }
9185 
9186 static VALUE
9187 stdout_getter(ID id, VALUE *ptr)
9188 {
9189  return rb_ractor_stdout();
9190 }
9191 
9192 static void
9193 stderr_setter(VALUE val, ID id, VALUE *ptr)
9194 {
9195  must_respond_to(id_write, val, id);
9196  rb_ractor_stderr_set(val);
9197 }
9198 
9199 static VALUE
9200 stderr_getter(ID id, VALUE *ptr)
9201 {
9202  return rb_ractor_stderr();
9203 }
9204 
9205 static VALUE
9206 allocate_and_open_new_file(VALUE klass)
9207 {
9208  VALUE self = io_alloc(klass);
9209  rb_io_make_open_file(self);
9210  return self;
9211 }
9212 
9213 VALUE
9214 rb_io_open_descriptor(VALUE klass, int descriptor, int mode, VALUE path, VALUE timeout, struct rb_io_encoding *encoding)
9215 {
9216  int state;
9217  VALUE self = rb_protect(allocate_and_open_new_file, klass, &state);
9218  if (state) {
9219  /* if we raised an exception allocating an IO object, but the caller
9220  intended to transfer ownership of this FD to us, close the fd before
9221  raising the exception. Otherwise, we would leak a FD - the caller
9222  expects GC to close the file, but we never got around to assigning
9223  it to a rb_io. */
9224  if (!(mode & FMODE_EXTERNAL)) {
9225  maygvl_close(descriptor, 0);
9226  }
9227  rb_jump_tag(state);
9228  }
9229 
9230 
9231  rb_io_t *io = RFILE(self)->fptr;
9232  io->self = self;
9233  io->fd = descriptor;
9234  io->mode = mode;
9235 
9236  /* At this point, Ruby fully owns the descriptor, and will close it when
9237  the IO gets GC'd (unless FMODE_EXTERNAL was set), no matter what happens
9238  in the rest of this method. */
9239 
9240  if (NIL_P(path)) {
9241  io->pathv = Qnil;
9242  }
9243  else {
9244  StringValue(path);
9245  io->pathv = rb_str_new_frozen(path);
9246  }
9247 
9248  io->timeout = timeout;
9249 
9250  if (encoding) {
9251  io->encs = *encoding;
9252  }
9253 
9254  rb_update_max_fd(descriptor);
9255 
9256  return self;
9257 }
9258 
9259 static VALUE
9260 prep_io(int fd, int fmode, VALUE klass, const char *path)
9261 {
9262  VALUE path_value = Qnil;
9263  rb_encoding *e;
9264  struct rb_io_encoding convconfig;
9265 
9266  if (path) {
9267  path_value = rb_obj_freeze(rb_str_new_cstr(path));
9268  }
9269 
9270  e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
9271  rb_io_ext_int_to_encs(e, NULL, &convconfig.enc, &convconfig.enc2, fmode);
9272  convconfig.ecflags = (fmode & FMODE_READABLE) ?
9273  MODE_BTMODE(ECONV_DEFAULT_NEWLINE_DECORATOR,
9275 #ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9276  convconfig.ecflags |= (fmode & FMODE_WRITABLE) ?
9277  MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
9278  0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
9279 #endif
9280  SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.enc2, convconfig.ecflags);
9281  convconfig.ecopts = Qnil;
9282 
9283  VALUE self = rb_io_open_descriptor(klass, fd, fmode, path_value, Qnil, &convconfig);
9284  rb_io_t*io = RFILE(self)->fptr;
9285 
9286  if (!io_check_tty(io)) {
9287 #ifdef __CYGWIN__
9288  io->mode |= FMODE_BINMODE;
9289  setmode(fd, O_BINARY);
9290 #endif
9291  }
9292 
9293  return self;
9294 }
9295 
9296 VALUE
9297 rb_io_fdopen(int fd, int oflags, const char *path)
9298 {
9299  VALUE klass = rb_cIO;
9300 
9301  if (path && strcmp(path, "-")) klass = rb_cFile;
9302  return prep_io(fd, rb_io_oflags_fmode(oflags), klass, path);
9303 }
9304 
9305 static VALUE
9306 prep_stdio(FILE *f, int fmode, VALUE klass, const char *path)
9307 {
9308  rb_io_t *fptr;
9309  VALUE io = prep_io(fileno(f), fmode|FMODE_EXTERNAL|DEFAULT_TEXTMODE, klass, path);
9310 
9311  GetOpenFile(io, fptr);
9313 #ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9314  fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
9315  if (fmode & FMODE_READABLE) {
9317  }
9318 #endif
9319  fptr->stdio_file = f;
9320 
9321  return io;
9322 }
9323 
9324 VALUE
9325 rb_io_prep_stdin(void)
9326 {
9327  return prep_stdio(stdin, FMODE_READABLE, rb_cIO, "<STDIN>");
9328 }
9329 
9330 VALUE
9331 rb_io_prep_stdout(void)
9332 {
9333  return prep_stdio(stdout, FMODE_WRITABLE|FMODE_SIGNAL_ON_EPIPE, rb_cIO, "<STDOUT>");
9334 }
9335 
9336 VALUE
9337 rb_io_prep_stderr(void)
9338 {
9339  return prep_stdio(stderr, FMODE_WRITABLE|FMODE_SYNC, rb_cIO, "<STDERR>");
9340 }
9341 
9342 FILE *
9344 {
9345  if (!fptr->stdio_file) {
9346  int oflags = rb_io_fmode_oflags(fptr->mode) & ~O_EXCL;
9347  fptr->stdio_file = rb_fdopen(fptr->fd, rb_io_oflags_modestr(oflags));
9348  }
9349  return fptr->stdio_file;
9350 }
9351 
9352 static inline void
9353 rb_io_buffer_init(struct rb_io_internal_buffer *buf)
9354 {
9355  buf->ptr = NULL;
9356  buf->off = 0;
9357  buf->len = 0;
9358  buf->capa = 0;
9359 }
9360 
9361 static inline rb_io_t *
9362 rb_io_fptr_new(void)
9363 {
9364  rb_io_t *fp = ALLOC(rb_io_t);
9365  fp->self = Qnil;
9366  fp->fd = -1;
9367  fp->stdio_file = NULL;
9368  fp->mode = 0;
9369  fp->pid = 0;
9370  fp->lineno = 0;
9371  fp->pathv = Qnil;
9372  fp->finalize = 0;
9373  rb_io_buffer_init(&fp->wbuf);
9374  rb_io_buffer_init(&fp->rbuf);
9375  rb_io_buffer_init(&fp->cbuf);
9376  fp->readconv = NULL;
9377  fp->writeconv = NULL;
9379  fp->writeconv_pre_ecflags = 0;
9380  fp->writeconv_pre_ecopts = Qnil;
9381  fp->writeconv_initialized = 0;
9382  fp->tied_io_for_writing = 0;
9383  fp->encs.enc = NULL;
9384  fp->encs.enc2 = NULL;
9385  fp->encs.ecflags = 0;
9386  fp->encs.ecopts = Qnil;
9387  fp->write_lock = Qnil;
9388  fp->timeout = Qnil;
9389  return fp;
9390 }
9391 
9392 rb_io_t *
9393 rb_io_make_open_file(VALUE obj)
9394 {
9395  rb_io_t *fp = 0;
9396 
9397  Check_Type(obj, T_FILE);
9398  if (RFILE(obj)->fptr) {
9399  rb_io_close(obj);
9400  rb_io_fptr_finalize(RFILE(obj)->fptr);
9401  RFILE(obj)->fptr = 0;
9402  }
9403  fp = rb_io_fptr_new();
9404  fp->self = obj;
9405  RFILE(obj)->fptr = fp;
9406  return fp;
9407 }
9408 
9409 static VALUE io_initialize(VALUE io, VALUE fnum, VALUE vmode, VALUE opt);
9410 
9411 /*
9412  * call-seq:
9413  * IO.new(fd, mode = 'r', **opts) -> io
9414  *
9415  * Creates and returns a new \IO object (file stream) from a file descriptor.
9416  *
9417  * \IO.new may be useful for interaction with low-level libraries.
9418  * For higher-level interactions, it may be simpler to create
9419  * the file stream using File.open.
9420  *
9421  * Argument +fd+ must be a valid file descriptor (integer):
9422  *
9423  * path = 't.tmp'
9424  * fd = IO.sysopen(path) # => 3
9425  * IO.new(fd) # => #<IO:fd 3>
9426  *
9427  * The new \IO object does not inherit encoding
9428  * (because the integer file descriptor does not have an encoding):
9429  *
9430  * fd = IO.sysopen('t.rus', 'rb')
9431  * io = IO.new(fd)
9432  * io.external_encoding # => #<Encoding:UTF-8> # Not ASCII-8BIT.
9433  *
9434  * Optional argument +mode+ (defaults to 'r') must specify a valid mode;
9435  * see {Access Modes}[rdoc-ref:File@Access+Modes]:
9436  *
9437  * IO.new(fd, 'w') # => #<IO:fd 3>
9438  * IO.new(fd, File::WRONLY) # => #<IO:fd 3>
9439  *
9440  * Optional keyword arguments +opts+ specify:
9441  *
9442  * - {Open Options}[rdoc-ref:IO@Open+Options].
9443  * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
9444  *
9445  * Examples:
9446  *
9447  * IO.new(fd, internal_encoding: nil) # => #<IO:fd 3>
9448  * IO.new(fd, autoclose: true) # => #<IO:fd 3>
9449  *
9450  */
9451 
9452 static VALUE
9453 rb_io_initialize(int argc, VALUE *argv, VALUE io)
9454 {
9455  VALUE fnum, vmode;
9456  VALUE opt;
9457 
9458  rb_scan_args(argc, argv, "11:", &fnum, &vmode, &opt);
9459  return io_initialize(io, fnum, vmode, opt);
9460 }
9461 
9462 static VALUE
9463 io_initialize(VALUE io, VALUE fnum, VALUE vmode, VALUE opt)
9464 {
9465  rb_io_t *fp;
9466  int fd, fmode, oflags = O_RDONLY;
9467  struct rb_io_encoding convconfig;
9468 #if defined(HAVE_FCNTL) && defined(F_GETFL)
9469  int ofmode;
9470 #else
9471  struct stat st;
9472 #endif
9473 
9474  rb_io_extract_modeenc(&vmode, 0, opt, &oflags, &fmode, &convconfig);
9475 
9476  fd = NUM2INT(fnum);
9477  if (rb_reserved_fd_p(fd)) {
9478  rb_raise(rb_eArgError, "The given fd is not accessible because RubyVM reserves it");
9479  }
9480 #if defined(HAVE_FCNTL) && defined(F_GETFL)
9481  oflags = fcntl(fd, F_GETFL);
9482  if (oflags == -1) rb_sys_fail(0);
9483 #else
9484  if (fstat(fd, &st) < 0) rb_sys_fail(0);
9485 #endif
9486  rb_update_max_fd(fd);
9487 #if defined(HAVE_FCNTL) && defined(F_GETFL)
9488  ofmode = rb_io_oflags_fmode(oflags);
9489  if (NIL_P(vmode)) {
9490  fmode = ofmode;
9491  }
9492  else if ((~ofmode & fmode) & FMODE_READWRITE) {
9493  VALUE error = INT2FIX(EINVAL);
9495  }
9496 #endif
9497  VALUE path = Qnil;
9498 
9499  if (!NIL_P(opt)) {
9500  if (rb_hash_aref(opt, sym_autoclose) == Qfalse) {
9501  fmode |= FMODE_EXTERNAL;
9502  }
9503 
9504  path = rb_hash_aref(opt, RB_ID2SYM(idPath));
9505  if (!NIL_P(path)) {
9506  StringValue(path);
9507  path = rb_str_new_frozen(path);
9508  }
9509  }
9510 
9511  MakeOpenFile(io, fp);
9512  fp->self = io;
9513  fp->fd = fd;
9514  fp->mode = fmode;
9515  fp->encs = convconfig;
9516  fp->pathv = path;
9517  fp->timeout = Qnil;
9518  clear_codeconv(fp);
9519  io_check_tty(fp);
9520  if (fileno(stdin) == fd)
9521  fp->stdio_file = stdin;
9522  else if (fileno(stdout) == fd)
9523  fp->stdio_file = stdout;
9524  else if (fileno(stderr) == fd)
9525  fp->stdio_file = stderr;
9526 
9527  if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
9528  return io;
9529 }
9530 
9531 /*
9532  * call-seq:
9533  * set_encoding_by_bom -> encoding or nil
9534  *
9535  * If the stream begins with a BOM
9536  * ({byte order marker}[https://en.wikipedia.org/wiki/Byte_order_mark]),
9537  * consumes the BOM and sets the external encoding accordingly;
9538  * returns the result encoding if found, or +nil+ otherwise:
9539  *
9540  * File.write('t.tmp', "\u{FEFF}abc")
9541  * io = File.open('t.tmp', 'rb')
9542  * io.set_encoding_by_bom # => #<Encoding:UTF-8>
9543  * io.close
9544  *
9545  * File.write('t.tmp', 'abc')
9546  * io = File.open('t.tmp', 'rb')
9547  * io.set_encoding_by_bom # => nil
9548  * io.close
9549  *
9550  * Raises an exception if the stream is not binmode
9551  * or its encoding has already been set.
9552  *
9553  */
9554 
9555 static VALUE
9556 rb_io_set_encoding_by_bom(VALUE io)
9557 {
9558  rb_io_t *fptr;
9559 
9560  GetOpenFile(io, fptr);
9561  if (!(fptr->mode & FMODE_BINMODE)) {
9562  rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
9563  }
9564  if (fptr->encs.enc2) {
9565  rb_raise(rb_eArgError, "encoding conversion is set");
9566  }
9567  else if (fptr->encs.enc && fptr->encs.enc != rb_ascii8bit_encoding()) {
9568  rb_raise(rb_eArgError, "encoding is set to %s already",
9569  rb_enc_name(fptr->encs.enc));
9570  }
9571  if (!io_set_encoding_by_bom(io)) return Qnil;
9572  return rb_enc_from_encoding(fptr->encs.enc);
9573 }
9574 
9575 /*
9576  * call-seq:
9577  * File.new(path, mode = 'r', perm = 0666, **opts) -> file
9578  *
9579  * Opens the file at the given +path+ according to the given +mode+;
9580  * creates and returns a new File object for that file.
9581  *
9582  * The new File object is buffered mode (or non-sync mode), unless
9583  * +filename+ is a tty.
9584  * See IO#flush, IO#fsync, IO#fdatasync, and IO#sync=.
9585  *
9586  * Argument +path+ must be a valid file path:
9587  *
9588  * f = File.new('/etc/fstab')
9589  * f.close
9590  * f = File.new('t.txt')
9591  * f.close
9592  *
9593  * Optional argument +mode+ (defaults to 'r') must specify a valid mode;
9594  * see {Access Modes}[rdoc-ref:File@Access+Modes]:
9595  *
9596  * f = File.new('t.tmp', 'w')
9597  * f.close
9598  * f = File.new('t.tmp', File::RDONLY)
9599  * f.close
9600  *
9601  * Optional argument +perm+ (defaults to 0666) must specify valid permissions
9602  * see {File Permissions}[rdoc-ref:File@File+Permissions]:
9603  *
9604  * f = File.new('t.tmp', File::CREAT, 0644)
9605  * f.close
9606  * f = File.new('t.tmp', File::CREAT, 0444)
9607  * f.close
9608  *
9609  * Optional keyword arguments +opts+ specify:
9610  *
9611  * - {Open Options}[rdoc-ref:IO@Open+Options].
9612  * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
9613  *
9614  */
9615 
9616 static VALUE
9617 rb_file_initialize(int argc, VALUE *argv, VALUE io)
9618 {
9619  if (RFILE(io)->fptr) {
9620  rb_raise(rb_eRuntimeError, "reinitializing File");
9621  }
9622  VALUE fname, vmode, vperm, opt;
9623  int posargc = rb_scan_args(argc, argv, "12:", &fname, &vmode, &vperm, &opt);
9624  if (posargc < 3) { /* perm is File only */
9625  VALUE fd = rb_check_to_int(fname);
9626 
9627  if (!NIL_P(fd)) {
9628  return io_initialize(io, fd, vmode, opt);
9629  }
9630  }
9631  return rb_open_file(io, fname, vmode, vperm, opt);
9632 }
9633 
9634 /* :nodoc: */
9635 static VALUE
9636 rb_io_s_new(int argc, VALUE *argv, VALUE klass)
9637 {
9638  if (rb_block_given_p()) {
9639  VALUE cname = rb_obj_as_string(klass);
9640 
9641  rb_warn("%"PRIsVALUE"::new() does not take block; use %"PRIsVALUE"::open() instead",
9642  cname, cname);
9643  }
9644  return rb_class_new_instance_kw(argc, argv, klass, RB_PASS_CALLED_KEYWORDS);
9645 }
9646 
9647 
9648 /*
9649  * call-seq:
9650  * IO.for_fd(fd, mode = 'r', **opts) -> io
9651  *
9652  * Synonym for IO.new.
9653  *
9654  */
9655 
9656 static VALUE
9657 rb_io_s_for_fd(int argc, VALUE *argv, VALUE klass)
9658 {
9659  VALUE io = rb_obj_alloc(klass);
9660  rb_io_initialize(argc, argv, io);
9661  return io;
9662 }
9663 
9664 /*
9665  * call-seq:
9666  * ios.autoclose? -> true or false
9667  *
9668  * Returns +true+ if the underlying file descriptor of _ios_ will be
9669  * closed at its finalization or at calling #close, otherwise +false+.
9670  */
9671 
9672 static VALUE
9673 rb_io_autoclose_p(VALUE io)
9674 {
9675  rb_io_t *fptr = RFILE(io)->fptr;
9676  rb_io_check_closed(fptr);
9677  return RBOOL(!(fptr->mode & FMODE_EXTERNAL));
9678 }
9679 
9680 /*
9681  * call-seq:
9682  * io.autoclose = bool -> true or false
9683  *
9684  * Sets auto-close flag.
9685  *
9686  * f = File.open(File::NULL)
9687  * IO.for_fd(f.fileno).close
9688  * f.gets # raises Errno::EBADF
9689  *
9690  * f = File.open(File::NULL)
9691  * g = IO.for_fd(f.fileno)
9692  * g.autoclose = false
9693  * g.close
9694  * f.gets # won't cause Errno::EBADF
9695  */
9696 
9697 static VALUE
9698 rb_io_set_autoclose(VALUE io, VALUE autoclose)
9699 {
9700  rb_io_t *fptr;
9701  GetOpenFile(io, fptr);
9702  if (!RTEST(autoclose))
9703  fptr->mode |= FMODE_EXTERNAL;
9704  else
9705  fptr->mode &= ~FMODE_EXTERNAL;
9706  return autoclose;
9707 }
9708 
9709 static VALUE
9710 io_wait_event(VALUE io, int event, VALUE timeout, int return_io)
9711 {
9712  VALUE result = rb_io_wait(io, RB_INT2NUM(event), timeout);
9713 
9714  if (!RB_TEST(result)) {
9715  return Qnil;
9716  }
9717 
9718  int mask = RB_NUM2INT(result);
9719 
9720  if (mask & event) {
9721  if (return_io)
9722  return io;
9723  else
9724  return result;
9725  }
9726  else {
9727  return Qfalse;
9728  }
9729 }
9730 
9731 /*
9732  * call-seq:
9733  * io.wait_readable -> truthy or falsy
9734  * io.wait_readable(timeout) -> truthy or falsy
9735  *
9736  * Waits until IO is readable and returns a truthy value, or a falsy
9737  * value when times out. Returns a truthy value immediately when
9738  * buffered data is available.
9739  */
9740 
9741 static VALUE
9742 io_wait_readable(int argc, VALUE *argv, VALUE io)
9743 {
9744  rb_io_t *fptr;
9745 
9746  RB_IO_POINTER(io, fptr);
9747  rb_io_check_readable(fptr);
9748 
9749  if (rb_io_read_pending(fptr)) return Qtrue;
9750 
9751  rb_check_arity(argc, 0, 1);
9752  VALUE timeout = (argc == 1 ? argv[0] : Qnil);
9753 
9754  return io_wait_event(io, RUBY_IO_READABLE, timeout, 1);
9755 }
9756 
9757 /*
9758  * call-seq:
9759  * io.wait_writable -> truthy or falsy
9760  * io.wait_writable(timeout) -> truthy or falsy
9761  *
9762  * Waits until IO is writable and returns a truthy value or a falsy
9763  * value when times out.
9764  */
9765 static VALUE
9766 io_wait_writable(int argc, VALUE *argv, VALUE io)
9767 {
9768  rb_io_t *fptr;
9769 
9770  RB_IO_POINTER(io, fptr);
9771  rb_io_check_writable(fptr);
9772 
9773  rb_check_arity(argc, 0, 1);
9774  VALUE timeout = (argc == 1 ? argv[0] : Qnil);
9775 
9776  return io_wait_event(io, RUBY_IO_WRITABLE, timeout, 1);
9777 }
9778 
9779 /*
9780  * call-seq:
9781  * io.wait_priority -> truthy or falsy
9782  * io.wait_priority(timeout) -> truthy or falsy
9783  *
9784  * Waits until IO is priority and returns a truthy value or a falsy
9785  * value when times out. Priority data is sent and received using
9786  * the Socket::MSG_OOB flag and is typically limited to streams.
9787  */
9788 static VALUE
9789 io_wait_priority(int argc, VALUE *argv, VALUE io)
9790 {
9791  rb_io_t *fptr = NULL;
9792 
9793  RB_IO_POINTER(io, fptr);
9794  rb_io_check_readable(fptr);
9795 
9796  if (rb_io_read_pending(fptr)) return Qtrue;
9797 
9798  rb_check_arity(argc, 0, 1);
9799  VALUE timeout = argc == 1 ? argv[0] : Qnil;
9800 
9801  return io_wait_event(io, RUBY_IO_PRIORITY, timeout, 1);
9802 }
9803 
9804 static int
9805 wait_mode_sym(VALUE mode)
9806 {
9807  if (mode == ID2SYM(rb_intern("r"))) {
9808  return RB_WAITFD_IN;
9809  }
9810  if (mode == ID2SYM(rb_intern("read"))) {
9811  return RB_WAITFD_IN;
9812  }
9813  if (mode == ID2SYM(rb_intern("readable"))) {
9814  return RB_WAITFD_IN;
9815  }
9816  if (mode == ID2SYM(rb_intern("w"))) {
9817  return RB_WAITFD_OUT;
9818  }
9819  if (mode == ID2SYM(rb_intern("write"))) {
9820  return RB_WAITFD_OUT;
9821  }
9822  if (mode == ID2SYM(rb_intern("writable"))) {
9823  return RB_WAITFD_OUT;
9824  }
9825  if (mode == ID2SYM(rb_intern("rw"))) {
9826  return RB_WAITFD_IN|RB_WAITFD_OUT;
9827  }
9828  if (mode == ID2SYM(rb_intern("read_write"))) {
9829  return RB_WAITFD_IN|RB_WAITFD_OUT;
9830  }
9831  if (mode == ID2SYM(rb_intern("readable_writable"))) {
9832  return RB_WAITFD_IN|RB_WAITFD_OUT;
9833  }
9834 
9835  rb_raise(rb_eArgError, "unsupported mode: %"PRIsVALUE, mode);
9836 }
9837 
9838 static inline enum rb_io_event
9839 io_event_from_value(VALUE value)
9840 {
9841  int events = RB_NUM2INT(value);
9842 
9843  if (events <= 0) rb_raise(rb_eArgError, "Events must be positive integer!");
9844 
9845  return events;
9846 }
9847 
9848 /*
9849  * call-seq:
9850  * io.wait(events, timeout) -> event mask, false or nil
9851  * io.wait(timeout = nil, mode = :read) -> self, true, or false
9852  *
9853  * Waits until the IO becomes ready for the specified events and returns the
9854  * subset of events that become ready, or a falsy value when times out.
9855  *
9856  * The events can be a bit mask of +IO::READABLE+, +IO::WRITABLE+ or
9857  * +IO::PRIORITY+.
9858  *
9859  * Returns an event mask (truthy value) immediately when buffered data is available.
9860  *
9861  * Optional parameter +mode+ is one of +:read+, +:write+, or
9862  * +:read_write+.
9863  */
9864 
9865 static VALUE
9866 io_wait(int argc, VALUE *argv, VALUE io)
9867 {
9868  VALUE timeout = Qundef;
9869  enum rb_io_event events = 0;
9870  int return_io = 0;
9871 
9872  // The documented signature for this method is actually incorrect.
9873  // A single timeout is allowed in any position, and multiple symbols can be given.
9874  // Whether this is intentional or not, I don't know, and as such I consider this to
9875  // be a legacy/slow path.
9876  if (argc != 2 || (RB_SYMBOL_P(argv[0]) || RB_SYMBOL_P(argv[1]))) {
9877  // We'd prefer to return the actual mask, but this form would return the io itself:
9878  return_io = 1;
9879 
9880  // Slow/messy path:
9881  for (int i = 0; i < argc; i += 1) {
9882  if (RB_SYMBOL_P(argv[i])) {
9883  events |= wait_mode_sym(argv[i]);
9884  }
9885  else if (UNDEF_P(timeout)) {
9886  rb_time_interval(timeout = argv[i]);
9887  }
9888  else {
9889  rb_raise(rb_eArgError, "timeout given more than once");
9890  }
9891  }
9892 
9893  if (UNDEF_P(timeout)) timeout = Qnil;
9894 
9895  if (events == 0) {
9896  events = RUBY_IO_READABLE;
9897  }
9898  }
9899  else /* argc == 2 and neither are symbols */ {
9900  // This is the fast path:
9901  events = io_event_from_value(argv[0]);
9902  timeout = argv[1];
9903  }
9904 
9905  if (events & RUBY_IO_READABLE) {
9906  rb_io_t *fptr = NULL;
9907  RB_IO_POINTER(io, fptr);
9908 
9909  if (rb_io_read_pending(fptr)) {
9910  // This was the original behaviour:
9911  if (return_io) return Qtrue;
9912  // New behaviour always returns an event mask:
9913  else return RB_INT2NUM(RUBY_IO_READABLE);
9914  }
9915  }
9916 
9917  return io_wait_event(io, events, timeout, return_io);
9918 }
9919 
9920 static void
9921 argf_mark(void *ptr)
9922 {
9923  struct argf *p = ptr;
9924  rb_gc_mark(p->filename);
9925  rb_gc_mark(p->current_file);
9926  rb_gc_mark(p->argv);
9927  rb_gc_mark(p->inplace);
9928  rb_gc_mark(p->encs.ecopts);
9929 }
9930 
9931 static size_t
9932 argf_memsize(const void *ptr)
9933 {
9934  const struct argf *p = ptr;
9935  size_t size = sizeof(*p);
9936  return size;
9937 }
9938 
9939 static const rb_data_type_t argf_type = {
9940  "ARGF",
9941  {argf_mark, RUBY_TYPED_DEFAULT_FREE, argf_memsize},
9942  0, 0, RUBY_TYPED_FREE_IMMEDIATELY
9943 };
9944 
9945 static inline void
9946 argf_init(struct argf *p, VALUE v)
9947 {
9948  p->filename = Qnil;
9949  p->current_file = Qnil;
9950  p->lineno = 0;
9951  p->argv = v;
9952 }
9953 
9954 static VALUE
9955 argf_alloc(VALUE klass)
9956 {
9957  struct argf *p;
9958  VALUE argf = TypedData_Make_Struct(klass, struct argf, &argf_type, p);
9959 
9960  argf_init(p, Qnil);
9961  return argf;
9962 }
9963 
9964 #undef rb_argv
9965 
9966 /* :nodoc: */
9967 static VALUE
9968 argf_initialize(VALUE argf, VALUE argv)
9969 {
9970  memset(&ARGF, 0, sizeof(ARGF));
9971  argf_init(&ARGF, argv);
9972 
9973  return argf;
9974 }
9975 
9976 /* :nodoc: */
9977 static VALUE
9978 argf_initialize_copy(VALUE argf, VALUE orig)
9979 {
9980  if (!OBJ_INIT_COPY(argf, orig)) return argf;
9981  ARGF = argf_of(orig);
9982  ARGF.argv = rb_obj_dup(ARGF.argv);
9983  return argf;
9984 }
9985 
9986 /*
9987  * call-seq:
9988  * ARGF.lineno = integer -> integer
9989  *
9990  * Sets the line number of ARGF as a whole to the given Integer.
9991  *
9992  * ARGF sets the line number automatically as you read data, so normally
9993  * you will not need to set it explicitly. To access the current line number
9994  * use ARGF.lineno.
9995  *
9996  * For example:
9997  *
9998  * ARGF.lineno #=> 0
9999  * ARGF.readline #=> "This is line 1\n"
10000  * ARGF.lineno #=> 1
10001  * ARGF.lineno = 0 #=> 0
10002  * ARGF.lineno #=> 0
10003  */
10004 static VALUE
10005 argf_set_lineno(VALUE argf, VALUE val)
10006 {
10007  ARGF.lineno = NUM2INT(val);
10008  ARGF.last_lineno = ARGF.lineno;
10009  return val;
10010 }
10011 
10012 /*
10013  * call-seq:
10014  * ARGF.lineno -> integer
10015  *
10016  * Returns the current line number of ARGF as a whole. This value
10017  * can be set manually with ARGF.lineno=.
10018  *
10019  * For example:
10020  *
10021  * ARGF.lineno #=> 0
10022  * ARGF.readline #=> "This is line 1\n"
10023  * ARGF.lineno #=> 1
10024  */
10025 static VALUE
10026 argf_lineno(VALUE argf)
10027 {
10028  return INT2FIX(ARGF.lineno);
10029 }
10030 
10031 static VALUE
10032 argf_forward(int argc, VALUE *argv, VALUE argf)
10033 {
10034  return forward_current(rb_frame_this_func(), argc, argv);
10035 }
10036 
10037 #define next_argv() argf_next_argv(argf)
10038 #define ARGF_GENERIC_INPUT_P() \
10039  (ARGF.current_file == rb_stdin && !RB_TYPE_P(ARGF.current_file, T_FILE))
10040 #define ARGF_FORWARD(argc, argv) do {\
10041  if (ARGF_GENERIC_INPUT_P())\
10042  return argf_forward((argc), (argv), argf);\
10043 } while (0)
10044 #define NEXT_ARGF_FORWARD(argc, argv) do {\
10045  if (!next_argv()) return Qnil;\
10046  ARGF_FORWARD((argc), (argv));\
10047 } while (0)
10048 
10049 static void
10050 argf_close(VALUE argf)
10051 {
10052  VALUE file = ARGF.current_file;
10053  if (file == rb_stdin) return;
10054  if (RB_TYPE_P(file, T_FILE)) {
10055  rb_io_set_write_io(file, Qnil);
10056  }
10057  io_close(file);
10058  ARGF.init_p = -1;
10059 }
10060 
10061 static int
10062 argf_next_argv(VALUE argf)
10063 {
10064  char *fn;
10065  rb_io_t *fptr;
10066  int stdout_binmode = 0;
10067  int fmode;
10068 
10069  VALUE r_stdout = rb_ractor_stdout();
10070 
10071  if (RB_TYPE_P(r_stdout, T_FILE)) {
10072  GetOpenFile(r_stdout, fptr);
10073  if (fptr->mode & FMODE_BINMODE)
10074  stdout_binmode = 1;
10075  }
10076 
10077  if (ARGF.init_p == 0) {
10078  if (!NIL_P(ARGF.argv) && RARRAY_LEN(ARGF.argv) > 0) {
10079  ARGF.next_p = 1;
10080  }
10081  else {
10082  ARGF.next_p = -1;
10083  }
10084  ARGF.init_p = 1;
10085  }
10086  else {
10087  if (NIL_P(ARGF.argv)) {
10088  ARGF.next_p = -1;
10089  }
10090  else if (ARGF.next_p == -1 && RARRAY_LEN(ARGF.argv) > 0) {
10091  ARGF.next_p = 1;
10092  }
10093  }
10094 
10095  if (ARGF.next_p == 1) {
10096  if (ARGF.init_p == 1) argf_close(argf);
10097  retry:
10098  if (RARRAY_LEN(ARGF.argv) > 0) {
10099  VALUE filename = rb_ary_shift(ARGF.argv);
10100  FilePathValue(filename);
10101  ARGF.filename = filename;
10102  filename = rb_str_encode_ospath(filename);
10103  fn = StringValueCStr(filename);
10104  if (RSTRING_LEN(filename) == 1 && fn[0] == '-') {
10105  ARGF.current_file = rb_stdin;
10106  if (ARGF.inplace) {
10107  rb_warn("Can't do inplace edit for stdio; skipping");
10108  goto retry;
10109  }
10110  }
10111  else {
10112  VALUE write_io = Qnil;
10113  int fr = rb_sysopen(filename, O_RDONLY, 0);
10114 
10115  if (ARGF.inplace) {
10116  struct stat st;
10117 #ifndef NO_SAFE_RENAME
10118  struct stat st2;
10119 #endif
10120  VALUE str;
10121  int fw;
10122 
10123  if (RB_TYPE_P(r_stdout, T_FILE) && r_stdout != orig_stdout) {
10124  rb_io_close(r_stdout);
10125  }
10126  fstat(fr, &st);
10127  str = filename;
10128  if (!NIL_P(ARGF.inplace)) {
10129  VALUE suffix = ARGF.inplace;
10130  str = rb_str_dup(str);
10131  if (NIL_P(rb_str_cat_conv_enc_opts(str, RSTRING_LEN(str),
10132  RSTRING_PTR(suffix), RSTRING_LEN(suffix),
10133  rb_enc_get(suffix), 0, Qnil))) {
10134  rb_str_append(str, suffix);
10135  }
10136 #ifdef NO_SAFE_RENAME
10137  (void)close(fr);
10138  (void)unlink(RSTRING_PTR(str));
10139  if (rename(fn, RSTRING_PTR(str)) < 0) {
10140  rb_warn("Can't rename %"PRIsVALUE" to %"PRIsVALUE": %s, skipping file",
10141  filename, str, strerror(errno));
10142  goto retry;
10143  }
10144  fr = rb_sysopen(str, O_RDONLY, 0);
10145 #else
10146  if (rename(fn, RSTRING_PTR(str)) < 0) {
10147  rb_warn("Can't rename %"PRIsVALUE" to %"PRIsVALUE": %s, skipping file",
10148  filename, str, strerror(errno));
10149  close(fr);
10150  goto retry;
10151  }
10152 #endif
10153  }
10154  else {
10155 #ifdef NO_SAFE_RENAME
10156  rb_fatal("Can't do inplace edit without backup");
10157 #else
10158  if (unlink(fn) < 0) {
10159  rb_warn("Can't remove %"PRIsVALUE": %s, skipping file",
10160  filename, strerror(errno));
10161  close(fr);
10162  goto retry;
10163  }
10164 #endif
10165  }
10166  fw = rb_sysopen(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666);
10167 #ifndef NO_SAFE_RENAME
10168  fstat(fw, &st2);
10169 #ifdef HAVE_FCHMOD
10170  fchmod(fw, st.st_mode);
10171 #else
10172  chmod(fn, st.st_mode);
10173 #endif
10174  if (st.st_uid!=st2.st_uid || st.st_gid!=st2.st_gid) {
10175  int err;
10176 #ifdef HAVE_FCHOWN
10177  err = fchown(fw, st.st_uid, st.st_gid);
10178 #else
10179  err = chown(fn, st.st_uid, st.st_gid);
10180 #endif
10181  if (err && getuid() == 0 && st2.st_uid == 0) {
10182  const char *wkfn = RSTRING_PTR(filename);
10183  rb_warn("Can't set owner/group of %"PRIsVALUE" to same as %"PRIsVALUE": %s, skipping file",
10184  filename, str, strerror(errno));
10185  (void)close(fr);
10186  (void)close(fw);
10187  (void)unlink(wkfn);
10188  goto retry;
10189  }
10190  }
10191 #endif
10192  write_io = prep_io(fw, FMODE_WRITABLE, rb_cFile, fn);
10193  rb_ractor_stdout_set(write_io);
10194  if (stdout_binmode) rb_io_binmode(rb_stdout);
10195  }
10196  fmode = FMODE_READABLE;
10197  if (!ARGF.binmode) {
10198  fmode |= DEFAULT_TEXTMODE;
10199  }
10200  ARGF.current_file = prep_io(fr, fmode, rb_cFile, fn);
10201  if (!NIL_P(write_io)) {
10202  rb_io_set_write_io(ARGF.current_file, write_io);
10203  }
10204  RB_GC_GUARD(filename);
10205  }
10206  if (ARGF.binmode) rb_io_ascii8bit_binmode(ARGF.current_file);
10207  GetOpenFile(ARGF.current_file, fptr);
10208  if (ARGF.encs.enc) {
10209  fptr->encs = ARGF.encs;
10210  clear_codeconv(fptr);
10211  }
10212  else {
10214  if (!ARGF.binmode) {
10216 #ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
10217  fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
10218 #endif
10219  }
10220  }
10221  ARGF.next_p = 0;
10222  }
10223  else {
10224  ARGF.next_p = 1;
10225  return FALSE;
10226  }
10227  }
10228  else if (ARGF.next_p == -1) {
10229  ARGF.current_file = rb_stdin;
10230  ARGF.filename = rb_str_new2("-");
10231  if (ARGF.inplace) {
10232  rb_warn("Can't do inplace edit for stdio");
10233  rb_ractor_stdout_set(orig_stdout);
10234  }
10235  }
10236  if (ARGF.init_p == -1) ARGF.init_p = 1;
10237  return TRUE;
10238 }
10239 
10240 static VALUE
10241 argf_getline(int argc, VALUE *argv, VALUE argf)
10242 {
10243  VALUE line;
10244  long lineno = ARGF.lineno;
10245 
10246  retry:
10247  if (!next_argv()) return Qnil;
10248  if (ARGF_GENERIC_INPUT_P()) {
10249  line = forward_current(idGets, argc, argv);
10250  }
10251  else {
10252  if (argc == 0 && rb_rs == rb_default_rs) {
10253  line = rb_io_gets(ARGF.current_file);
10254  }
10255  else {
10256  line = rb_io_getline(argc, argv, ARGF.current_file);
10257  }
10258  if (NIL_P(line) && ARGF.next_p != -1) {
10259  argf_close(argf);
10260  ARGF.next_p = 1;
10261  goto retry;
10262  }
10263  }
10264  if (!NIL_P(line)) {
10265  ARGF.lineno = ++lineno;
10266  ARGF.last_lineno = ARGF.lineno;
10267  }
10268  return line;
10269 }
10270 
10271 static VALUE
10272 argf_lineno_getter(ID id, VALUE *var)
10273 {
10274  VALUE argf = *var;
10275  return INT2FIX(ARGF.last_lineno);
10276 }
10277 
10278 static void
10279 argf_lineno_setter(VALUE val, ID id, VALUE *var)
10280 {
10281  VALUE argf = *var;
10282  int n = NUM2INT(val);
10283  ARGF.last_lineno = ARGF.lineno = n;
10284 }
10285 
10286 void
10287 rb_reset_argf_lineno(long n)
10288 {
10289  ARGF.last_lineno = ARGF.lineno = n;
10290 }
10291 
10292 static VALUE argf_gets(int, VALUE *, VALUE);
10293 
10294 /*
10295  * call-seq:
10296  * gets(sep=$/ [, getline_args]) -> string or nil
10297  * gets(limit [, getline_args]) -> string or nil
10298  * gets(sep, limit [, getline_args]) -> string or nil
10299  *
10300  * Returns (and assigns to <code>$_</code>) the next line from the list
10301  * of files in +ARGV+ (or <code>$*</code>), or from standard input if
10302  * no files are present on the command line. Returns +nil+ at end of
10303  * file. The optional argument specifies the record separator. The
10304  * separator is included with the contents of each record. A separator
10305  * of +nil+ reads the entire contents, and a zero-length separator
10306  * reads the input one paragraph at a time, where paragraphs are
10307  * divided by two consecutive newlines. If the first argument is an
10308  * integer, or optional second argument is given, the returning string
10309  * would not be longer than the given value in bytes. If multiple
10310  * filenames are present in +ARGV+, <code>gets(nil)</code> will read
10311  * the contents one file at a time.
10312  *
10313  * ARGV << "testfile"
10314  * print while gets
10315  *
10316  * <em>produces:</em>
10317  *
10318  * This is line one
10319  * This is line two
10320  * This is line three
10321  * And so on...
10322  *
10323  * The style of programming using <code>$_</code> as an implicit
10324  * parameter is gradually losing favor in the Ruby community.
10325  */
10326 
10327 static VALUE
10328 rb_f_gets(int argc, VALUE *argv, VALUE recv)
10329 {
10330  if (recv == argf) {
10331  return argf_gets(argc, argv, argf);
10332  }
10333  return forward(argf, idGets, argc, argv);
10334 }
10335 
10336 /*
10337  * call-seq:
10338  * ARGF.gets(sep=$/ [, getline_args]) -> string or nil
10339  * ARGF.gets(limit [, getline_args]) -> string or nil
10340  * ARGF.gets(sep, limit [, getline_args]) -> string or nil
10341  *
10342  * Returns the next line from the current file in ARGF.
10343  *
10344  * By default lines are assumed to be separated by <code>$/</code>;
10345  * to use a different character as a separator, supply it as a String
10346  * for the _sep_ argument.
10347  *
10348  * The optional _limit_ argument specifies how many characters of each line
10349  * to return. By default all characters are returned.
10350  *
10351  * See IO.readlines for details about getline_args.
10352  *
10353  */
10354 static VALUE
10355 argf_gets(int argc, VALUE *argv, VALUE argf)
10356 {
10357  VALUE line;
10358 
10359  line = argf_getline(argc, argv, argf);
10360  rb_lastline_set(line);
10361 
10362  return line;
10363 }
10364 
10365 VALUE
10366 rb_gets(void)
10367 {
10368  VALUE line;
10369 
10370  if (rb_rs != rb_default_rs) {
10371  return rb_f_gets(0, 0, argf);
10372  }
10373 
10374  retry:
10375  if (!next_argv()) return Qnil;
10376  line = rb_io_gets(ARGF.current_file);
10377  if (NIL_P(line) && ARGF.next_p != -1) {
10378  rb_io_close(ARGF.current_file);
10379  ARGF.next_p = 1;
10380  goto retry;
10381  }
10382  rb_lastline_set(line);
10383  if (!NIL_P(line)) {
10384  ARGF.lineno++;
10385  ARGF.last_lineno = ARGF.lineno;
10386  }
10387 
10388  return line;
10389 }
10390 
10391 static VALUE argf_readline(int, VALUE *, VALUE);
10392 
10393 /*
10394  * call-seq:
10395  * readline(sep = $/, chomp: false) -> string
10396  * readline(limit, chomp: false) -> string
10397  * readline(sep, limit, chomp: false) -> string
10398  *
10399  * Equivalent to method Kernel#gets, except that it raises an exception
10400  * if called at end-of-stream:
10401  *
10402  * $ cat t.txt | ruby -e "p readlines; readline"
10403  * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10404  * in `readline': end of file reached (EOFError)
10405  *
10406  * Optional keyword argument +chomp+ specifies whether line separators
10407  * are to be omitted.
10408  */
10409 
10410 static VALUE
10411 rb_f_readline(int argc, VALUE *argv, VALUE recv)
10412 {
10413  if (recv == argf) {
10414  return argf_readline(argc, argv, argf);
10415  }
10416  return forward(argf, rb_intern("readline"), argc, argv);
10417 }
10418 
10419 
10420 /*
10421  * call-seq:
10422  * ARGF.readline(sep=$/) -> string
10423  * ARGF.readline(limit) -> string
10424  * ARGF.readline(sep, limit) -> string
10425  *
10426  * Returns the next line from the current file in ARGF.
10427  *
10428  * By default lines are assumed to be separated by <code>$/</code>;
10429  * to use a different character as a separator, supply it as a String
10430  * for the _sep_ argument.
10431  *
10432  * The optional _limit_ argument specifies how many characters of each line
10433  * to return. By default all characters are returned.
10434  *
10435  * An EOFError is raised at the end of the file.
10436  */
10437 static VALUE
10438 argf_readline(int argc, VALUE *argv, VALUE argf)
10439 {
10440  VALUE line;
10441 
10442  if (!next_argv()) rb_eof_error();
10443  ARGF_FORWARD(argc, argv);
10444  line = argf_gets(argc, argv, argf);
10445  if (NIL_P(line)) {
10446  rb_eof_error();
10447  }
10448 
10449  return line;
10450 }
10451 
10452 static VALUE argf_readlines(int, VALUE *, VALUE);
10453 
10454 /*
10455  * call-seq:
10456  * readlines(sep = $/, chomp: false, **enc_opts) -> array
10457  * readlines(limit, chomp: false, **enc_opts) -> array
10458  * readlines(sep, limit, chomp: false, **enc_opts) -> array
10459  *
10460  * Returns an array containing the lines returned by calling
10461  * Kernel#gets until the end-of-stream is reached;
10462  * (see {Line IO}[rdoc-ref:IO@Line+IO]).
10463  *
10464  * With only string argument +sep+ given,
10465  * returns the remaining lines as determined by line separator +sep+,
10466  * or +nil+ if none;
10467  * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
10468  *
10469  * # Default separator.
10470  * $ cat t.txt | ruby -e "p readlines"
10471  * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10472  *
10473  * # Specified separator.
10474  * $ cat t.txt | ruby -e "p readlines 'li'"
10475  * ["First li", "ne\nSecond li", "ne\n\nFourth li", "ne\nFifth li", "ne\n"]
10476  *
10477  * # Get-all separator.
10478  * $ cat t.txt | ruby -e "p readlines nil"
10479  * ["First line\nSecond line\n\nFourth line\nFifth line\n"]
10480  *
10481  * # Get-paragraph separator.
10482  * $ cat t.txt | ruby -e "p readlines ''"
10483  * ["First line\nSecond line\n\n", "Fourth line\nFifth line\n"]
10484  *
10485  * With only integer argument +limit+ given,
10486  * limits the number of bytes in the line;
10487  * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
10488  *
10489  * $cat t.txt | ruby -e "p readlines 10"
10490  * ["First line", "\n", "Second lin", "e\n", "\n", "Fourth lin", "e\n", "Fifth line", "\n"]
10491  *
10492  * $cat t.txt | ruby -e "p readlines 11"
10493  * ["First line\n", "Second line", "\n", "\n", "Fourth line", "\n", "Fifth line\n"]
10494  *
10495  * $cat t.txt | ruby -e "p readlines 12"
10496  * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10497  *
10498  * With arguments +sep+ and +limit+ given,
10499  * combines the two behaviors
10500  * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
10501  *
10502  * Optional keyword argument +chomp+ specifies whether line separators
10503  * are to be omitted:
10504  *
10505  * $ cat t.txt | ruby -e "p readlines(chomp: true)"
10506  * ["First line", "Second line", "", "Fourth line", "Fifth line"]
10507  *
10508  * Optional keyword arguments +enc_opts+ specify encoding options;
10509  * see {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
10510  *
10511  */
10512 
10513 static VALUE
10514 rb_f_readlines(int argc, VALUE *argv, VALUE recv)
10515 {
10516  if (recv == argf) {
10517  return argf_readlines(argc, argv, argf);
10518  }
10519  return forward(argf, rb_intern("readlines"), argc, argv);
10520 }
10521 
10522 /*
10523  * call-seq:
10524  * ARGF.readlines(sep = $/, chomp: false) -> array
10525  * ARGF.readlines(limit, chomp: false) -> array
10526  * ARGF.readlines(sep, limit, chomp: false) -> array
10527  *
10528  * ARGF.to_a(sep = $/, chomp: false) -> array
10529  * ARGF.to_a(limit, chomp: false) -> array
10530  * ARGF.to_a(sep, limit, chomp: false) -> array
10531  *
10532  * Reads each file in ARGF in its entirety, returning an Array containing
10533  * lines from the files. Lines are assumed to be separated by _sep_.
10534  *
10535  * lines = ARGF.readlines
10536  * lines[0] #=> "This is line one\n"
10537  *
10538  * See +IO.readlines+ for a full description of all options.
10539  */
10540 static VALUE
10541 argf_readlines(int argc, VALUE *argv, VALUE argf)
10542 {
10543  long lineno = ARGF.lineno;
10544  VALUE lines, ary;
10545 
10546  ary = rb_ary_new();
10547  while (next_argv()) {
10548  if (ARGF_GENERIC_INPUT_P()) {
10549  lines = forward_current(rb_intern("readlines"), argc, argv);
10550  }
10551  else {
10552  lines = rb_io_readlines(argc, argv, ARGF.current_file);
10553  argf_close(argf);
10554  }
10555  ARGF.next_p = 1;
10556  rb_ary_concat(ary, lines);
10557  ARGF.lineno = lineno + RARRAY_LEN(ary);
10558  ARGF.last_lineno = ARGF.lineno;
10559  }
10560  ARGF.init_p = 0;
10561  return ary;
10562 }
10563 
10564 /*
10565  * call-seq:
10566  * `command` -> string
10567  *
10568  * Returns the <tt>$stdout</tt> output from running +command+ in a subshell;
10569  * sets global variable <tt>$?</tt> to the process status.
10570  *
10571  * This method has potential security vulnerabilities if called with untrusted input;
10572  * see {Command Injection}[rdoc-ref:command_injection.rdoc].
10573  *
10574  * Examples:
10575  *
10576  * $ `date` # => "Wed Apr 9 08:56:30 CDT 2003\n"
10577  * $ `echo oops && exit 99` # => "oops\n"
10578  * $ $? # => #<Process::Status: pid 17088 exit 99>
10579  * $ $?.status # => 99>
10580  *
10581  * The built-in syntax <tt>%x{...}</tt> uses this method.
10582  *
10583  */
10584 
10585 static VALUE
10586 rb_f_backquote(VALUE obj, VALUE str)
10587 {
10588  VALUE port;
10589  VALUE result;
10590  rb_io_t *fptr;
10591 
10592  StringValue(str);
10593  rb_last_status_clear();
10594  port = pipe_open_s(str, "r", FMODE_READABLE|DEFAULT_TEXTMODE, NULL);
10595  if (NIL_P(port)) return rb_str_new(0,0);
10596 
10597  GetOpenFile(port, fptr);
10598  result = read_all(fptr, remain_size(fptr), Qnil);
10599  rb_io_close(port);
10600  rb_io_fptr_cleanup_all(fptr);
10601  RB_GC_GUARD(port);
10602 
10603  return result;
10604 }
10605 
10606 #ifdef HAVE_SYS_SELECT_H
10607 #include <sys/select.h>
10608 #endif
10609 
10610 static VALUE
10611 select_internal(VALUE read, VALUE write, VALUE except, struct timeval *tp, rb_fdset_t *fds)
10612 {
10613  VALUE res, list;
10614  rb_fdset_t *rp, *wp, *ep;
10615  rb_io_t *fptr;
10616  long i;
10617  int max = 0, n;
10618  int pending = 0;
10619  struct timeval timerec;
10620 
10621  if (!NIL_P(read)) {
10622  Check_Type(read, T_ARRAY);
10623  for (i=0; i<RARRAY_LEN(read); i++) {
10624  GetOpenFile(rb_io_get_io(RARRAY_AREF(read, i)), fptr);
10625  rb_fd_set(fptr->fd, &fds[0]);
10626  if (READ_DATA_PENDING(fptr) || READ_CHAR_PENDING(fptr)) { /* check for buffered data */
10627  pending++;
10628  rb_fd_set(fptr->fd, &fds[3]);
10629  }
10630  if (max < fptr->fd) max = fptr->fd;
10631  }
10632  if (pending) { /* no blocking if there's buffered data */
10633  timerec.tv_sec = timerec.tv_usec = 0;
10634  tp = &timerec;
10635  }
10636  rp = &fds[0];
10637  }
10638  else
10639  rp = 0;
10640 
10641  if (!NIL_P(write)) {
10642  Check_Type(write, T_ARRAY);
10643  for (i=0; i<RARRAY_LEN(write); i++) {
10644  VALUE write_io = GetWriteIO(rb_io_get_io(RARRAY_AREF(write, i)));
10645  GetOpenFile(write_io, fptr);
10646  rb_fd_set(fptr->fd, &fds[1]);
10647  if (max < fptr->fd) max = fptr->fd;
10648  }
10649  wp = &fds[1];
10650  }
10651  else
10652  wp = 0;
10653 
10654  if (!NIL_P(except)) {
10655  Check_Type(except, T_ARRAY);
10656  for (i=0; i<RARRAY_LEN(except); i++) {
10657  VALUE io = rb_io_get_io(RARRAY_AREF(except, i));
10658  VALUE write_io = GetWriteIO(io);
10659  GetOpenFile(io, fptr);
10660  rb_fd_set(fptr->fd, &fds[2]);
10661  if (max < fptr->fd) max = fptr->fd;
10662  if (io != write_io) {
10663  GetOpenFile(write_io, fptr);
10664  rb_fd_set(fptr->fd, &fds[2]);
10665  if (max < fptr->fd) max = fptr->fd;
10666  }
10667  }
10668  ep = &fds[2];
10669  }
10670  else {
10671  ep = 0;
10672  }
10673 
10674  max++;
10675 
10676  n = rb_thread_fd_select(max, rp, wp, ep, tp);
10677  if (n < 0) {
10678  rb_sys_fail(0);
10679  }
10680  if (!pending && n == 0) return Qnil; /* returns nil on timeout */
10681 
10682  res = rb_ary_new2(3);
10683  rb_ary_push(res, rp?rb_ary_new():rb_ary_new2(0));
10684  rb_ary_push(res, wp?rb_ary_new():rb_ary_new2(0));
10685  rb_ary_push(res, ep?rb_ary_new():rb_ary_new2(0));
10686 
10687  if (rp) {
10688  list = RARRAY_AREF(res, 0);
10689  for (i=0; i< RARRAY_LEN(read); i++) {
10690  VALUE obj = rb_ary_entry(read, i);
10691  VALUE io = rb_io_get_io(obj);
10692  GetOpenFile(io, fptr);
10693  if (rb_fd_isset(fptr->fd, &fds[0]) ||
10694  rb_fd_isset(fptr->fd, &fds[3])) {
10695  rb_ary_push(list, obj);
10696  }
10697  }
10698  }
10699 
10700  if (wp) {
10701  list = RARRAY_AREF(res, 1);
10702  for (i=0; i< RARRAY_LEN(write); i++) {
10703  VALUE obj = rb_ary_entry(write, i);
10704  VALUE io = rb_io_get_io(obj);
10705  VALUE write_io = GetWriteIO(io);
10706  GetOpenFile(write_io, fptr);
10707  if (rb_fd_isset(fptr->fd, &fds[1])) {
10708  rb_ary_push(list, obj);
10709  }
10710  }
10711  }
10712 
10713  if (ep) {
10714  list = RARRAY_AREF(res, 2);
10715  for (i=0; i< RARRAY_LEN(except); i++) {
10716  VALUE obj = rb_ary_entry(except, i);
10717  VALUE io = rb_io_get_io(obj);
10718  VALUE write_io = GetWriteIO(io);
10719  GetOpenFile(io, fptr);
10720  if (rb_fd_isset(fptr->fd, &fds[2])) {
10721  rb_ary_push(list, obj);
10722  }
10723  else if (io != write_io) {
10724  GetOpenFile(write_io, fptr);
10725  if (rb_fd_isset(fptr->fd, &fds[2])) {
10726  rb_ary_push(list, obj);
10727  }
10728  }
10729  }
10730  }
10731 
10732  return res; /* returns an empty array on interrupt */
10733 }
10734 
10735 struct select_args {
10736  VALUE read, write, except;
10737  struct timeval *timeout;
10738  rb_fdset_t fdsets[4];
10739 };
10740 
10741 static VALUE
10742 select_call(VALUE arg)
10743 {
10744  struct select_args *p = (struct select_args *)arg;
10745 
10746  return select_internal(p->read, p->write, p->except, p->timeout, p->fdsets);
10747 }
10748 
10749 static VALUE
10750 select_end(VALUE arg)
10751 {
10752  struct select_args *p = (struct select_args *)arg;
10753  int i;
10754 
10755  for (i = 0; i < numberof(p->fdsets); ++i)
10756  rb_fd_term(&p->fdsets[i]);
10757  return Qnil;
10758 }
10759 
10760 static VALUE sym_normal, sym_sequential, sym_random,
10761  sym_willneed, sym_dontneed, sym_noreuse;
10762 
10763 #ifdef HAVE_POSIX_FADVISE
10764 struct io_advise_struct {
10765  int fd;
10766  int advice;
10767  rb_off_t offset;
10768  rb_off_t len;
10769 };
10770 
10771 static VALUE
10772 io_advise_internal(void *arg)
10773 {
10774  struct io_advise_struct *ptr = arg;
10775  return posix_fadvise(ptr->fd, ptr->offset, ptr->len, ptr->advice);
10776 }
10777 
10778 static VALUE
10779 io_advise_sym_to_const(VALUE sym)
10780 {
10781 #ifdef POSIX_FADV_NORMAL
10782  if (sym == sym_normal)
10783  return INT2NUM(POSIX_FADV_NORMAL);
10784 #endif
10785 
10786 #ifdef POSIX_FADV_RANDOM
10787  if (sym == sym_random)
10788  return INT2NUM(POSIX_FADV_RANDOM);
10789 #endif
10790 
10791 #ifdef POSIX_FADV_SEQUENTIAL
10792  if (sym == sym_sequential)
10793  return INT2NUM(POSIX_FADV_SEQUENTIAL);
10794 #endif
10795 
10796 #ifdef POSIX_FADV_WILLNEED
10797  if (sym == sym_willneed)
10798  return INT2NUM(POSIX_FADV_WILLNEED);
10799 #endif
10800 
10801 #ifdef POSIX_FADV_DONTNEED
10802  if (sym == sym_dontneed)
10803  return INT2NUM(POSIX_FADV_DONTNEED);
10804 #endif
10805 
10806 #ifdef POSIX_FADV_NOREUSE
10807  if (sym == sym_noreuse)
10808  return INT2NUM(POSIX_FADV_NOREUSE);
10809 #endif
10810 
10811  return Qnil;
10812 }
10813 
10814 static VALUE
10815 do_io_advise(rb_io_t *fptr, VALUE advice, rb_off_t offset, rb_off_t len)
10816 {
10817  int rv;
10818  struct io_advise_struct ias;
10819  VALUE num_adv;
10820 
10821  num_adv = io_advise_sym_to_const(advice);
10822 
10823  /*
10824  * The platform doesn't support this hint. We don't raise exception, instead
10825  * silently ignore it. Because IO::advise is only hint.
10826  */
10827  if (NIL_P(num_adv))
10828  return Qnil;
10829 
10830  ias.fd = fptr->fd;
10831  ias.advice = NUM2INT(num_adv);
10832  ias.offset = offset;
10833  ias.len = len;
10834 
10835  rv = (int)rb_io_blocking_region(fptr, io_advise_internal, &ias);
10836  if (rv && rv != ENOSYS) {
10837  /* posix_fadvise(2) doesn't set errno. On success it returns 0; otherwise
10838  it returns the error code. */
10839  VALUE message = rb_sprintf("%"PRIsVALUE" "
10840  "(%"PRI_OFFT_PREFIX"d, "
10841  "%"PRI_OFFT_PREFIX"d, "
10842  "%"PRIsVALUE")",
10843  fptr->pathv, offset, len, advice);
10844  rb_syserr_fail_str(rv, message);
10845  }
10846 
10847  return Qnil;
10848 }
10849 
10850 #endif /* HAVE_POSIX_FADVISE */
10851 
10852 static void
10853 advice_arg_check(VALUE advice)
10854 {
10855  if (!SYMBOL_P(advice))
10856  rb_raise(rb_eTypeError, "advice must be a Symbol");
10857 
10858  if (advice != sym_normal &&
10859  advice != sym_sequential &&
10860  advice != sym_random &&
10861  advice != sym_willneed &&
10862  advice != sym_dontneed &&
10863  advice != sym_noreuse) {
10864  rb_raise(rb_eNotImpError, "Unsupported advice: %+"PRIsVALUE, advice);
10865  }
10866 }
10867 
10868 /*
10869  * call-seq:
10870  * advise(advice, offset = 0, len = 0) -> nil
10871  *
10872  * Invokes Posix system call
10873  * {posix_fadvise(2)}[https://linux.die.net/man/2/posix_fadvise],
10874  * which announces an intention to access data from the current file
10875  * in a particular manner.
10876  *
10877  * The arguments and results are platform-dependent.
10878  *
10879  * The relevant data is specified by:
10880  *
10881  * - +offset+: The offset of the first byte of data.
10882  * - +len+: The number of bytes to be accessed;
10883  * if +len+ is zero, or is larger than the number of bytes remaining,
10884  * all remaining bytes will be accessed.
10885  *
10886  * Argument +advice+ is one of the following symbols:
10887  *
10888  * - +:normal+: The application has no advice to give
10889  * about its access pattern for the specified data.
10890  * If no advice is given for an open file, this is the default assumption.
10891  * - +:sequential+: The application expects to access the specified data sequentially
10892  * (with lower offsets read before higher ones).
10893  * - +:random+: The specified data will be accessed in random order.
10894  * - +:noreuse+: The specified data will be accessed only once.
10895  * - +:willneed+: The specified data will be accessed in the near future.
10896  * - +:dontneed+: The specified data will not be accessed in the near future.
10897  *
10898  * Not implemented on all platforms.
10899  *
10900  */
10901 static VALUE
10902 rb_io_advise(int argc, VALUE *argv, VALUE io)
10903 {
10904  VALUE advice, offset, len;
10905  rb_off_t off, l;
10906  rb_io_t *fptr;
10907 
10908  rb_scan_args(argc, argv, "12", &advice, &offset, &len);
10909  advice_arg_check(advice);
10910 
10911  io = GetWriteIO(io);
10912  GetOpenFile(io, fptr);
10913 
10914  off = NIL_P(offset) ? 0 : NUM2OFFT(offset);
10915  l = NIL_P(len) ? 0 : NUM2OFFT(len);
10916 
10917 #ifdef HAVE_POSIX_FADVISE
10918  return do_io_advise(fptr, advice, off, l);
10919 #else
10920  ((void)off, (void)l); /* Ignore all hint */
10921  return Qnil;
10922 #endif
10923 }
10924 
10925 /*
10926  * call-seq:
10927  * IO.select(read_ios, write_ios = [], error_ios = [], timeout = nil) -> array or nil
10928  *
10929  * Invokes system call {select(2)}[https://linux.die.net/man/2/select],
10930  * which monitors multiple file descriptors,
10931  * waiting until one or more of the file descriptors
10932  * becomes ready for some class of I/O operation.
10933  *
10934  * Not implemented on all platforms.
10935  *
10936  * Each of the arguments +read_ios+, +write_ios+, and +error_ios+
10937  * is an array of IO objects.
10938  *
10939  * Argument +timeout+ is a numeric value (such as integer or float) timeout
10940  * interval in seconds.
10941  *
10942  * The method monitors the \IO objects given in all three arrays,
10943  * waiting for some to be ready;
10944  * returns a 3-element array whose elements are:
10945  *
10946  * - An array of the objects in +read_ios+ that are ready for reading.
10947  * - An array of the objects in +write_ios+ that are ready for writing.
10948  * - An array of the objects in +error_ios+ have pending exceptions.
10949  *
10950  * If no object becomes ready within the given +timeout+, +nil+ is returned.
10951  *
10952  * \IO.select peeks the buffer of \IO objects for testing readability.
10953  * If the \IO buffer is not empty, \IO.select immediately notifies
10954  * readability. This "peek" only happens for \IO objects. It does not
10955  * happen for IO-like objects such as OpenSSL::SSL::SSLSocket.
10956  *
10957  * The best way to use \IO.select is invoking it after non-blocking
10958  * methods such as #read_nonblock, #write_nonblock, etc. The methods
10959  * raise an exception which is extended by IO::WaitReadable or
10960  * IO::WaitWritable. The modules notify how the caller should wait
10961  * with \IO.select. If IO::WaitReadable is raised, the caller should
10962  * wait for reading. If IO::WaitWritable is raised, the caller should
10963  * wait for writing.
10964  *
10965  * So, blocking read (#readpartial) can be emulated using
10966  * #read_nonblock and \IO.select as follows:
10967  *
10968  * begin
10969  * result = io_like.read_nonblock(maxlen)
10970  * rescue IO::WaitReadable
10971  * IO.select([io_like])
10972  * retry
10973  * rescue IO::WaitWritable
10974  * IO.select(nil, [io_like])
10975  * retry
10976  * end
10977  *
10978  * Especially, the combination of non-blocking methods and \IO.select is
10979  * preferred for IO like objects such as OpenSSL::SSL::SSLSocket. It
10980  * has #to_io method to return underlying IO object. IO.select calls
10981  * #to_io to obtain the file descriptor to wait.
10982  *
10983  * This means that readability notified by \IO.select doesn't mean
10984  * readability from OpenSSL::SSL::SSLSocket object.
10985  *
10986  * The most likely situation is that OpenSSL::SSL::SSLSocket buffers
10987  * some data. \IO.select doesn't see the buffer. So \IO.select can
10988  * block when OpenSSL::SSL::SSLSocket#readpartial doesn't block.
10989  *
10990  * However, several more complicated situations exist.
10991  *
10992  * SSL is a protocol which is sequence of records.
10993  * The record consists of multiple bytes.
10994  * So, the remote side of SSL sends a partial record, IO.select
10995  * notifies readability but OpenSSL::SSL::SSLSocket cannot decrypt a
10996  * byte and OpenSSL::SSL::SSLSocket#readpartial will block.
10997  *
10998  * Also, the remote side can request SSL renegotiation which forces
10999  * the local SSL engine to write some data.
11000  * This means OpenSSL::SSL::SSLSocket#readpartial may invoke #write
11001  * system call and it can block.
11002  * In such a situation, OpenSSL::SSL::SSLSocket#read_nonblock raises
11003  * IO::WaitWritable instead of blocking.
11004  * So, the caller should wait for ready for writability as above
11005  * example.
11006  *
11007  * The combination of non-blocking methods and \IO.select is also useful
11008  * for streams such as tty, pipe socket socket when multiple processes
11009  * read from a stream.
11010  *
11011  * Finally, Linux kernel developers don't guarantee that
11012  * readability of select(2) means readability of following read(2) even
11013  * for a single process;
11014  * see {select(2)}[https://linux.die.net/man/2/select]
11015  *
11016  * Invoking \IO.select before IO#readpartial works well as usual.
11017  * However it is not the best way to use \IO.select.
11018  *
11019  * The writability notified by select(2) doesn't show
11020  * how many bytes are writable.
11021  * IO#write method blocks until given whole string is written.
11022  * So, <tt>IO#write(two or more bytes)</tt> can block after
11023  * writability is notified by \IO.select. IO#write_nonblock is required
11024  * to avoid the blocking.
11025  *
11026  * Blocking write (#write) can be emulated using #write_nonblock and
11027  * IO.select as follows: IO::WaitReadable should also be rescued for
11028  * SSL renegotiation in OpenSSL::SSL::SSLSocket.
11029  *
11030  * while 0 < string.bytesize
11031  * begin
11032  * written = io_like.write_nonblock(string)
11033  * rescue IO::WaitReadable
11034  * IO.select([io_like])
11035  * retry
11036  * rescue IO::WaitWritable
11037  * IO.select(nil, [io_like])
11038  * retry
11039  * end
11040  * string = string.byteslice(written..-1)
11041  * end
11042  *
11043  * Example:
11044  *
11045  * rp, wp = IO.pipe
11046  * mesg = "ping "
11047  * 100.times {
11048  * # IO.select follows IO#read. Not the best way to use IO.select.
11049  * rs, ws, = IO.select([rp], [wp])
11050  * if r = rs[0]
11051  * ret = r.read(5)
11052  * print ret
11053  * case ret
11054  * when /ping/
11055  * mesg = "pong\n"
11056  * when /pong/
11057  * mesg = "ping "
11058  * end
11059  * end
11060  * if w = ws[0]
11061  * w.write(mesg)
11062  * end
11063  * }
11064  *
11065  * Output:
11066  *
11067  * ping pong
11068  * ping pong
11069  * ping pong
11070  * (snipped)
11071  * ping
11072  *
11073  */
11074 
11075 static VALUE
11076 rb_f_select(int argc, VALUE *argv, VALUE obj)
11077 {
11078  VALUE scheduler = rb_fiber_scheduler_current();
11079  if (scheduler != Qnil) {
11080  // It's optionally supported.
11081  VALUE result = rb_fiber_scheduler_io_selectv(scheduler, argc, argv);
11082  if (!UNDEF_P(result)) return result;
11083  }
11084 
11085  VALUE timeout;
11086  struct select_args args;
11087  struct timeval timerec;
11088  int i;
11089 
11090  rb_scan_args(argc, argv, "13", &args.read, &args.write, &args.except, &timeout);
11091  if (NIL_P(timeout)) {
11092  args.timeout = 0;
11093  }
11094  else {
11095  timerec = rb_time_interval(timeout);
11096  args.timeout = &timerec;
11097  }
11098 
11099  for (i = 0; i < numberof(args.fdsets); ++i)
11100  rb_fd_init(&args.fdsets[i]);
11101 
11102  return rb_ensure(select_call, (VALUE)&args, select_end, (VALUE)&args);
11103 }
11104 
11105 #ifdef IOCTL_REQ_TYPE
11106  typedef IOCTL_REQ_TYPE ioctl_req_t;
11107 #else
11108  typedef int ioctl_req_t;
11109 # define NUM2IOCTLREQ(num) ((int)NUM2LONG(num))
11110 #endif
11111 
11112 #ifdef HAVE_IOCTL
11113 struct ioctl_arg {
11114  int fd;
11115  ioctl_req_t cmd;
11116  long narg;
11117 };
11118 
11119 static VALUE
11120 nogvl_ioctl(void *ptr)
11121 {
11122  struct ioctl_arg *arg = ptr;
11123 
11124  return (VALUE)ioctl(arg->fd, arg->cmd, arg->narg);
11125 }
11126 
11127 static int
11128 do_ioctl(struct rb_io *io, ioctl_req_t cmd, long narg)
11129 {
11130  int retval;
11131  struct ioctl_arg arg;
11132 
11133  arg.fd = io->fd;
11134  arg.cmd = cmd;
11135  arg.narg = narg;
11136 
11137  retval = (int)rb_io_blocking_region(io, nogvl_ioctl, &arg);
11138 
11139  return retval;
11140 }
11141 #endif
11142 
11143 #define DEFAULT_IOCTL_NARG_LEN (256)
11144 
11145 #if defined(__linux__) && defined(_IOC_SIZE)
11146 static long
11147 linux_iocparm_len(ioctl_req_t cmd)
11148 {
11149  long len;
11150 
11151  if ((cmd & 0xFFFF0000) == 0) {
11152  /* legacy and unstructured ioctl number. */
11153  return DEFAULT_IOCTL_NARG_LEN;
11154  }
11155 
11156  len = _IOC_SIZE(cmd);
11157 
11158  /* paranoia check for silly drivers which don't keep ioctl convention */
11159  if (len < DEFAULT_IOCTL_NARG_LEN)
11160  len = DEFAULT_IOCTL_NARG_LEN;
11161 
11162  return len;
11163 }
11164 #endif
11165 
11166 #ifdef HAVE_IOCTL
11167 static long
11168 ioctl_narg_len(ioctl_req_t cmd)
11169 {
11170  long len;
11171 
11172 #ifdef IOCPARM_MASK
11173 #ifndef IOCPARM_LEN
11174 #define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK)
11175 #endif
11176 #endif
11177 #ifdef IOCPARM_LEN
11178  len = IOCPARM_LEN(cmd); /* on BSDish systems we're safe */
11179 #elif defined(__linux__) && defined(_IOC_SIZE)
11180  len = linux_iocparm_len(cmd);
11181 #else
11182  /* otherwise guess at what's safe */
11183  len = DEFAULT_IOCTL_NARG_LEN;
11184 #endif
11185 
11186  return len;
11187 }
11188 #endif
11189 
11190 #ifdef HAVE_FCNTL
11191 #ifdef __linux__
11192 typedef long fcntl_arg_t;
11193 #else
11194 /* posix */
11195 typedef int fcntl_arg_t;
11196 #endif
11197 
11198 static long
11199 fcntl_narg_len(ioctl_req_t cmd)
11200 {
11201  long len;
11202 
11203  switch (cmd) {
11204 #ifdef F_DUPFD
11205  case F_DUPFD:
11206  len = sizeof(fcntl_arg_t);
11207  break;
11208 #endif
11209 #ifdef F_DUP2FD /* bsd specific */
11210  case F_DUP2FD:
11211  len = sizeof(int);
11212  break;
11213 #endif
11214 #ifdef F_DUPFD_CLOEXEC /* linux specific */
11215  case F_DUPFD_CLOEXEC:
11216  len = sizeof(fcntl_arg_t);
11217  break;
11218 #endif
11219 #ifdef F_GETFD
11220  case F_GETFD:
11221  len = 1;
11222  break;
11223 #endif
11224 #ifdef F_SETFD
11225  case F_SETFD:
11226  len = sizeof(fcntl_arg_t);
11227  break;
11228 #endif
11229 #ifdef F_GETFL
11230  case F_GETFL:
11231  len = 1;
11232  break;
11233 #endif
11234 #ifdef F_SETFL
11235  case F_SETFL:
11236  len = sizeof(fcntl_arg_t);
11237  break;
11238 #endif
11239 #ifdef F_GETOWN
11240  case F_GETOWN:
11241  len = 1;
11242  break;
11243 #endif
11244 #ifdef F_SETOWN
11245  case F_SETOWN:
11246  len = sizeof(fcntl_arg_t);
11247  break;
11248 #endif
11249 #ifdef F_GETOWN_EX /* linux specific */
11250  case F_GETOWN_EX:
11251  len = sizeof(struct f_owner_ex);
11252  break;
11253 #endif
11254 #ifdef F_SETOWN_EX /* linux specific */
11255  case F_SETOWN_EX:
11256  len = sizeof(struct f_owner_ex);
11257  break;
11258 #endif
11259 #ifdef F_GETLK
11260  case F_GETLK:
11261  len = sizeof(struct flock);
11262  break;
11263 #endif
11264 #ifdef F_SETLK
11265  case F_SETLK:
11266  len = sizeof(struct flock);
11267  break;
11268 #endif
11269 #ifdef F_SETLKW
11270  case F_SETLKW:
11271  len = sizeof(struct flock);
11272  break;
11273 #endif
11274 #ifdef F_READAHEAD /* bsd specific */
11275  case F_READAHEAD:
11276  len = sizeof(int);
11277  break;
11278 #endif
11279 #ifdef F_RDAHEAD /* Darwin specific */
11280  case F_RDAHEAD:
11281  len = sizeof(int);
11282  break;
11283 #endif
11284 #ifdef F_GETSIG /* linux specific */
11285  case F_GETSIG:
11286  len = 1;
11287  break;
11288 #endif
11289 #ifdef F_SETSIG /* linux specific */
11290  case F_SETSIG:
11291  len = sizeof(fcntl_arg_t);
11292  break;
11293 #endif
11294 #ifdef F_GETLEASE /* linux specific */
11295  case F_GETLEASE:
11296  len = 1;
11297  break;
11298 #endif
11299 #ifdef F_SETLEASE /* linux specific */
11300  case F_SETLEASE:
11301  len = sizeof(fcntl_arg_t);
11302  break;
11303 #endif
11304 #ifdef F_NOTIFY /* linux specific */
11305  case F_NOTIFY:
11306  len = sizeof(fcntl_arg_t);
11307  break;
11308 #endif
11309 
11310  default:
11311  len = 256;
11312  break;
11313  }
11314 
11315  return len;
11316 }
11317 #else /* HAVE_FCNTL */
11318 static long
11319 fcntl_narg_len(ioctl_req_t cmd)
11320 {
11321  return 0;
11322 }
11323 #endif /* HAVE_FCNTL */
11324 
11325 #define NARG_SENTINEL 17
11326 
11327 static long
11328 setup_narg(ioctl_req_t cmd, VALUE *argp, long (*narg_len)(ioctl_req_t))
11329 {
11330  long narg = 0;
11331  VALUE arg = *argp;
11332 
11333  if (!RTEST(arg)) {
11334  narg = 0;
11335  }
11336  else if (FIXNUM_P(arg)) {
11337  narg = FIX2LONG(arg);
11338  }
11339  else if (arg == Qtrue) {
11340  narg = 1;
11341  }
11342  else {
11343  VALUE tmp = rb_check_string_type(arg);
11344 
11345  if (NIL_P(tmp)) {
11346  narg = NUM2LONG(arg);
11347  }
11348  else {
11349  char *ptr;
11350  long len, slen;
11351 
11352  *argp = arg = tmp;
11353  len = narg_len(cmd);
11354  rb_str_modify(arg);
11355 
11356  slen = RSTRING_LEN(arg);
11357  /* expand for data + sentinel. */
11358  if (slen < len+1) {
11359  rb_str_resize(arg, len+1);
11360  MEMZERO(RSTRING_PTR(arg)+slen, char, len-slen);
11361  slen = len+1;
11362  }
11363  /* a little sanity check here */
11364  ptr = RSTRING_PTR(arg);
11365  ptr[slen - 1] = NARG_SENTINEL;
11366  narg = (long)(SIGNED_VALUE)ptr;
11367  }
11368  }
11369 
11370  return narg;
11371 }
11372 
11373 static VALUE
11374 finish_narg(int retval, VALUE arg, const rb_io_t *fptr)
11375 {
11376  if (retval < 0) rb_sys_fail_path(fptr->pathv);
11377  if (RB_TYPE_P(arg, T_STRING)) {
11378  char *ptr;
11379  long slen;
11380  RSTRING_GETMEM(arg, ptr, slen);
11381  if (ptr[slen-1] != NARG_SENTINEL)
11382  rb_raise(rb_eArgError, "return value overflowed string");
11383  ptr[slen-1] = '\0';
11384  }
11385 
11386  return INT2NUM(retval);
11387 }
11388 
11389 #ifdef HAVE_IOCTL
11390 static VALUE
11391 rb_ioctl(VALUE io, VALUE req, VALUE arg)
11392 {
11393  ioctl_req_t cmd = NUM2IOCTLREQ(req);
11394  rb_io_t *fptr;
11395  long narg;
11396  int retval;
11397 
11398  narg = setup_narg(cmd, &arg, ioctl_narg_len);
11399  GetOpenFile(io, fptr);
11400  retval = do_ioctl(fptr, cmd, narg);
11401  return finish_narg(retval, arg, fptr);
11402 }
11403 
11404 /*
11405  * call-seq:
11406  * ioctl(integer_cmd, argument) -> integer
11407  *
11408  * Invokes Posix system call {ioctl(2)}[https://linux.die.net/man/2/ioctl],
11409  * which issues a low-level command to an I/O device.
11410  *
11411  * Issues a low-level command to an I/O device.
11412  * The arguments and returned value are platform-dependent.
11413  * The effect of the call is platform-dependent.
11414  *
11415  * If argument +argument+ is an integer, it is passed directly;
11416  * if it is a string, it is interpreted as a binary sequence of bytes.
11417  *
11418  * Not implemented on all platforms.
11419  *
11420  */
11421 
11422 static VALUE
11423 rb_io_ioctl(int argc, VALUE *argv, VALUE io)
11424 {
11425  VALUE req, arg;
11426 
11427  rb_scan_args(argc, argv, "11", &req, &arg);
11428  return rb_ioctl(io, req, arg);
11429 }
11430 #else
11431 #define rb_io_ioctl rb_f_notimplement
11432 #endif
11433 
11434 #ifdef HAVE_FCNTL
11435 struct fcntl_arg {
11436  int fd;
11437  int cmd;
11438  long narg;
11439 };
11440 
11441 static VALUE
11442 nogvl_fcntl(void *ptr)
11443 {
11444  struct fcntl_arg *arg = ptr;
11445 
11446 #if defined(F_DUPFD)
11447  if (arg->cmd == F_DUPFD)
11448  return (VALUE)rb_cloexec_fcntl_dupfd(arg->fd, (int)arg->narg);
11449 #endif
11450  return (VALUE)fcntl(arg->fd, arg->cmd, arg->narg);
11451 }
11452 
11453 static int
11454 do_fcntl(struct rb_io *io, int cmd, long narg)
11455 {
11456  int retval;
11457  struct fcntl_arg arg;
11458 
11459  arg.fd = io->fd;
11460  arg.cmd = cmd;
11461  arg.narg = narg;
11462 
11463  retval = (int)rb_io_blocking_region(io, nogvl_fcntl, &arg);
11464  if (retval != -1) {
11465  switch (cmd) {
11466 #if defined(F_DUPFD)
11467  case F_DUPFD:
11468 #endif
11469 #if defined(F_DUPFD_CLOEXEC)
11470  case F_DUPFD_CLOEXEC:
11471 #endif
11472  rb_update_max_fd(retval);
11473  }
11474  }
11475 
11476  return retval;
11477 }
11478 
11479 static VALUE
11480 rb_fcntl(VALUE io, VALUE req, VALUE arg)
11481 {
11482  int cmd = NUM2INT(req);
11483  rb_io_t *fptr;
11484  long narg;
11485  int retval;
11486 
11487  narg = setup_narg(cmd, &arg, fcntl_narg_len);
11488  GetOpenFile(io, fptr);
11489  retval = do_fcntl(fptr, cmd, narg);
11490  return finish_narg(retval, arg, fptr);
11491 }
11492 
11493 /*
11494  * call-seq:
11495  * fcntl(integer_cmd, argument) -> integer
11496  *
11497  * Invokes Posix system call {fcntl(2)}[https://linux.die.net/man/2/fcntl],
11498  * which provides a mechanism for issuing low-level commands to control or query
11499  * a file-oriented I/O stream. Arguments and results are platform
11500  * dependent.
11501  *
11502  * If +argument+ is a number, its value is passed directly;
11503  * if it is a string, it is interpreted as a binary sequence of bytes.
11504  * (Array#pack might be a useful way to build this string.)
11505  *
11506  * Not implemented on all platforms.
11507  *
11508  */
11509 
11510 static VALUE
11511 rb_io_fcntl(int argc, VALUE *argv, VALUE io)
11512 {
11513  VALUE req, arg;
11514 
11515  rb_scan_args(argc, argv, "11", &req, &arg);
11516  return rb_fcntl(io, req, arg);
11517 }
11518 #else
11519 #define rb_io_fcntl rb_f_notimplement
11520 #endif
11521 
11522 #if defined(HAVE_SYSCALL) || defined(HAVE___SYSCALL)
11523 /*
11524  * call-seq:
11525  * syscall(integer_callno, *arguments) -> integer
11526  *
11527  * Invokes Posix system call {syscall(2)}[https://linux.die.net/man/2/syscall],
11528  * which calls a specified function.
11529  *
11530  * Calls the operating system function identified by +integer_callno+;
11531  * returns the result of the function or raises SystemCallError if it failed.
11532  * The effect of the call is platform-dependent.
11533  * The arguments and returned value are platform-dependent.
11534  *
11535  * For each of +arguments+: if it is an integer, it is passed directly;
11536  * if it is a string, it is interpreted as a binary sequence of bytes.
11537  * There may be as many as nine such arguments.
11538  *
11539  * Arguments +integer_callno+ and +argument+, as well as the returned value,
11540  * are platform-dependent.
11541  *
11542  * Note: Method +syscall+ is essentially unsafe and unportable.
11543  * The DL (Fiddle) library is preferred for safer and a bit
11544  * more portable programming.
11545  *
11546  * Not implemented on all platforms.
11547  *
11548  */
11549 
11550 static VALUE
11551 rb_f_syscall(int argc, VALUE *argv, VALUE _)
11552 {
11553  VALUE arg[8];
11554 #if SIZEOF_VOIDP == 8 && defined(HAVE___SYSCALL) && SIZEOF_INT != 8 /* mainly *BSD */
11555 # define SYSCALL __syscall
11556 # define NUM2SYSCALLID(x) NUM2LONG(x)
11557 # define RETVAL2NUM(x) LONG2NUM(x)
11558 # if SIZEOF_LONG == 8
11559  long num, retval = -1;
11560 # elif SIZEOF_LONG_LONG == 8
11561  long long num, retval = -1;
11562 # else
11563 # error ---->> it is asserted that __syscall takes the first argument and returns retval in 64bit signed integer. <<----
11564 # endif
11565 #elif defined(__linux__)
11566 # define SYSCALL syscall
11567 # define NUM2SYSCALLID(x) NUM2LONG(x)
11568 # define RETVAL2NUM(x) LONG2NUM(x)
11569  /*
11570  * Linux man page says, syscall(2) function prototype is below.
11571  *
11572  * int syscall(int number, ...);
11573  *
11574  * But, it's incorrect. Actual one takes and returned long. (see unistd.h)
11575  */
11576  long num, retval = -1;
11577 #else
11578 # define SYSCALL syscall
11579 # define NUM2SYSCALLID(x) NUM2INT(x)
11580 # define RETVAL2NUM(x) INT2NUM(x)
11581  int num, retval = -1;
11582 #endif
11583  int i;
11584 
11585  if (RTEST(ruby_verbose)) {
11587  "We plan to remove a syscall function at future release. DL(Fiddle) provides safer alternative.");
11588  }
11589 
11590  if (argc == 0)
11591  rb_raise(rb_eArgError, "too few arguments for syscall");
11592  if (argc > numberof(arg))
11593  rb_raise(rb_eArgError, "too many arguments for syscall");
11594  num = NUM2SYSCALLID(argv[0]); ++argv;
11595  for (i = argc - 1; i--; ) {
11596  VALUE v = rb_check_string_type(argv[i]);
11597 
11598  if (!NIL_P(v)) {
11599  StringValue(v);
11600  rb_str_modify(v);
11601  arg[i] = (VALUE)StringValueCStr(v);
11602  }
11603  else {
11604  arg[i] = (VALUE)NUM2LONG(argv[i]);
11605  }
11606  }
11607 
11608  switch (argc) {
11609  case 1:
11610  retval = SYSCALL(num);
11611  break;
11612  case 2:
11613  retval = SYSCALL(num, arg[0]);
11614  break;
11615  case 3:
11616  retval = SYSCALL(num, arg[0],arg[1]);
11617  break;
11618  case 4:
11619  retval = SYSCALL(num, arg[0],arg[1],arg[2]);
11620  break;
11621  case 5:
11622  retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3]);
11623  break;
11624  case 6:
11625  retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4]);
11626  break;
11627  case 7:
11628  retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5]);
11629  break;
11630  case 8:
11631  retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6]);
11632  break;
11633  }
11634 
11635  if (retval == -1)
11636  rb_sys_fail(0);
11637  return RETVAL2NUM(retval);
11638 #undef SYSCALL
11639 #undef NUM2SYSCALLID
11640 #undef RETVAL2NUM
11641 }
11642 #else
11643 #define rb_f_syscall rb_f_notimplement
11644 #endif
11645 
11646 static VALUE
11647 io_new_instance(VALUE args)
11648 {
11649  return rb_class_new_instance(2, (VALUE*)args+1, *(VALUE*)args);
11650 }
11651 
11652 static rb_encoding *
11653 find_encoding(VALUE v)
11654 {
11655  rb_encoding *enc = rb_find_encoding(v);
11656  if (!enc) rb_warn("Unsupported encoding %"PRIsVALUE" ignored", v);
11657  return enc;
11658 }
11659 
11660 static void
11661 io_encoding_set(rb_io_t *fptr, VALUE v1, VALUE v2, VALUE opt)
11662 {
11663  rb_encoding *enc, *enc2;
11664  int ecflags = fptr->encs.ecflags;
11665  VALUE ecopts, tmp;
11666 
11667  if (!NIL_P(v2)) {
11668  enc2 = find_encoding(v1);
11669  tmp = rb_check_string_type(v2);
11670  if (!NIL_P(tmp)) {
11671  if (RSTRING_LEN(tmp) == 1 && RSTRING_PTR(tmp)[0] == '-') {
11672  /* Special case - "-" => no transcoding */
11673  enc = enc2;
11674  enc2 = NULL;
11675  }
11676  else
11677  enc = find_encoding(v2);
11678  if (enc == enc2) {
11679  /* Special case - "-" => no transcoding */
11680  enc2 = NULL;
11681  }
11682  }
11683  else {
11684  enc = find_encoding(v2);
11685  if (enc == enc2) {
11686  /* Special case - "-" => no transcoding */
11687  enc2 = NULL;
11688  }
11689  }
11690  if (enc2 == rb_ascii8bit_encoding()) {
11691  /* If external is ASCII-8BIT, no transcoding */
11692  enc = enc2;
11693  enc2 = NULL;
11694  }
11695  SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11696  ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
11697  }
11698  else {
11699  if (NIL_P(v1)) {
11700  /* Set to default encodings */
11701  rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
11702  SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11703  ecopts = Qnil;
11704  }
11705  else {
11706  tmp = rb_check_string_type(v1);
11707  if (!NIL_P(tmp) && rb_enc_asciicompat(enc = rb_enc_get(tmp))) {
11708  parse_mode_enc(RSTRING_PTR(tmp), enc, &enc, &enc2, NULL);
11709  SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11710  ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
11711  }
11712  else {
11713  rb_io_ext_int_to_encs(find_encoding(v1), NULL, &enc, &enc2, 0);
11714  SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11715  ecopts = Qnil;
11716  }
11717  }
11718  }
11719  validate_enc_binmode(&fptr->mode, ecflags, enc, enc2);
11720  fptr->encs.enc = enc;
11721  fptr->encs.enc2 = enc2;
11722  fptr->encs.ecflags = ecflags;
11723  fptr->encs.ecopts = ecopts;
11724  clear_codeconv(fptr);
11725 
11726 }
11727 
11729  rb_io_t *fptr;
11730  VALUE v1;
11731  VALUE v2;
11732  VALUE opt;
11733 };
11734 
11735 static VALUE
11736 io_encoding_set_v(VALUE v)
11737 {
11738  struct io_encoding_set_args *arg = (struct io_encoding_set_args *)v;
11739  io_encoding_set(arg->fptr, arg->v1, arg->v2, arg->opt);
11740  return Qnil;
11741 }
11742 
11743 static VALUE
11744 pipe_pair_close(VALUE rw)
11745 {
11746  VALUE *rwp = (VALUE *)rw;
11747  return rb_ensure(io_close, rwp[0], io_close, rwp[1]);
11748 }
11749 
11750 /*
11751  * call-seq:
11752  * IO.pipe(**opts) -> [read_io, write_io]
11753  * IO.pipe(enc, **opts) -> [read_io, write_io]
11754  * IO.pipe(ext_enc, int_enc, **opts) -> [read_io, write_io]
11755  * IO.pipe(**opts) {|read_io, write_io| ...} -> object
11756  * IO.pipe(enc, **opts) {|read_io, write_io| ...} -> object
11757  * IO.pipe(ext_enc, int_enc, **opts) {|read_io, write_io| ...} -> object
11758  *
11759  * Creates a pair of pipe endpoints, +read_io+ and +write_io+,
11760  * connected to each other.
11761  *
11762  * If argument +enc_string+ is given, it must be a string containing one of:
11763  *
11764  * - The name of the encoding to be used as the external encoding.
11765  * - The colon-separated names of two encodings to be used as the external
11766  * and internal encodings.
11767  *
11768  * If argument +int_enc+ is given, it must be an Encoding object
11769  * or encoding name string that specifies the internal encoding to be used;
11770  * if argument +ext_enc+ is also given, it must be an Encoding object
11771  * or encoding name string that specifies the external encoding to be used.
11772  *
11773  * The string read from +read_io+ is tagged with the external encoding;
11774  * if an internal encoding is also specified, the string is converted
11775  * to, and tagged with, that encoding.
11776  *
11777  * If any encoding is specified,
11778  * optional hash arguments specify the conversion option.
11779  *
11780  * Optional keyword arguments +opts+ specify:
11781  *
11782  * - {Open Options}[rdoc-ref:IO@Open+Options].
11783  * - {Encoding Options}[rdoc-ref:encodings.rdoc@Encoding+Options].
11784  *
11785  * With no block given, returns the two endpoints in an array:
11786  *
11787  * IO.pipe # => [#<IO:fd 4>, #<IO:fd 5>]
11788  *
11789  * With a block given, calls the block with the two endpoints;
11790  * closes both endpoints and returns the value of the block:
11791  *
11792  * IO.pipe {|read_io, write_io| p read_io; p write_io }
11793  *
11794  * Output:
11795  *
11796  * #<IO:fd 6>
11797  * #<IO:fd 7>
11798  *
11799  * Not available on all platforms.
11800  *
11801  * In the example below, the two processes close the ends of the pipe
11802  * that they are not using. This is not just a cosmetic nicety. The
11803  * read end of a pipe will not generate an end of file condition if
11804  * there are any writers with the pipe still open. In the case of the
11805  * parent process, the <tt>rd.read</tt> will never return if it
11806  * does not first issue a <tt>wr.close</tt>:
11807  *
11808  * rd, wr = IO.pipe
11809  *
11810  * if fork
11811  * wr.close
11812  * puts "Parent got: <#{rd.read}>"
11813  * rd.close
11814  * Process.wait
11815  * else
11816  * rd.close
11817  * puts 'Sending message to parent'
11818  * wr.write "Hi Dad"
11819  * wr.close
11820  * end
11821  *
11822  * <em>produces:</em>
11823  *
11824  * Sending message to parent
11825  * Parent got: <Hi Dad>
11826  *
11827  */
11828 
11829 static VALUE
11830 rb_io_s_pipe(int argc, VALUE *argv, VALUE klass)
11831 {
11832  int pipes[2], state;
11833  VALUE r, w, args[3], v1, v2;
11834  VALUE opt;
11835  rb_io_t *fptr, *fptr2;
11836  struct io_encoding_set_args ies_args;
11837  int fmode = 0;
11838  VALUE ret;
11839 
11840  argc = rb_scan_args(argc, argv, "02:", &v1, &v2, &opt);
11841  if (rb_pipe(pipes) < 0)
11842  rb_sys_fail(0);
11843 
11844  args[0] = klass;
11845  args[1] = INT2NUM(pipes[0]);
11846  args[2] = INT2FIX(O_RDONLY);
11847  r = rb_protect(io_new_instance, (VALUE)args, &state);
11848  if (state) {
11849  close(pipes[0]);
11850  close(pipes[1]);
11851  rb_jump_tag(state);
11852  }
11853  GetOpenFile(r, fptr);
11854 
11855  ies_args.fptr = fptr;
11856  ies_args.v1 = v1;
11857  ies_args.v2 = v2;
11858  ies_args.opt = opt;
11859  rb_protect(io_encoding_set_v, (VALUE)&ies_args, &state);
11860  if (state) {
11861  close(pipes[1]);
11862  io_close(r);
11863  rb_jump_tag(state);
11864  }
11865 
11866  args[1] = INT2NUM(pipes[1]);
11867  args[2] = INT2FIX(O_WRONLY);
11868  w = rb_protect(io_new_instance, (VALUE)args, &state);
11869  if (state) {
11870  close(pipes[1]);
11871  if (!NIL_P(r)) rb_io_close(r);
11872  rb_jump_tag(state);
11873  }
11874  GetOpenFile(w, fptr2);
11875  rb_io_synchronized(fptr2);
11876 
11877  extract_binmode(opt, &fmode);
11878 
11879  if ((fmode & FMODE_BINMODE) && NIL_P(v1)) {
11882  }
11883 
11884 #if DEFAULT_TEXTMODE
11885  if ((fptr->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
11886  fptr->mode &= ~FMODE_TEXTMODE;
11887  setmode(fptr->fd, O_BINARY);
11888  }
11889 #if RUBY_CRLF_ENVIRONMENT
11892  }
11893 #endif
11894 #endif
11895  fptr->mode |= fmode;
11896 #if DEFAULT_TEXTMODE
11897  if ((fptr2->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
11898  fptr2->mode &= ~FMODE_TEXTMODE;
11899  setmode(fptr2->fd, O_BINARY);
11900  }
11901 #endif
11902  fptr2->mode |= fmode;
11903 
11904  ret = rb_assoc_new(r, w);
11905  if (rb_block_given_p()) {
11906  VALUE rw[2];
11907  rw[0] = r;
11908  rw[1] = w;
11909  return rb_ensure(rb_yield, ret, pipe_pair_close, (VALUE)rw);
11910  }
11911  return ret;
11912 }
11913 
11914 struct foreach_arg {
11915  int argc;
11916  VALUE *argv;
11917  VALUE io;
11918 };
11919 
11920 static void
11921 open_key_args(VALUE klass, int argc, VALUE *argv, VALUE opt, struct foreach_arg *arg)
11922 {
11923  VALUE path, v;
11924  VALUE vmode = Qnil, vperm = Qnil;
11925 
11926  path = *argv++;
11927  argc--;
11928  FilePathValue(path);
11929  arg->io = 0;
11930  arg->argc = argc;
11931  arg->argv = argv;
11932  if (NIL_P(opt)) {
11933  vmode = INT2NUM(O_RDONLY);
11934  vperm = INT2FIX(0666);
11935  }
11936  else if (!NIL_P(v = rb_hash_aref(opt, sym_open_args))) {
11937  int n;
11938 
11939  v = rb_to_array_type(v);
11940  n = RARRAY_LENINT(v);
11941  rb_check_arity(n, 0, 3); /* rb_io_open */
11942  rb_scan_args_kw(RB_SCAN_ARGS_LAST_HASH_KEYWORDS, n, RARRAY_CONST_PTR(v), "02:", &vmode, &vperm, &opt);
11943  }
11944  arg->io = rb_io_open(klass, path, vmode, vperm, opt);
11945 }
11946 
11947 static VALUE
11948 io_s_foreach(VALUE v)
11949 {
11950  struct getline_arg *arg = (void *)v;
11951  VALUE str;
11952 
11953  if (arg->limit == 0)
11954  rb_raise(rb_eArgError, "invalid limit: 0 for foreach");
11955  while (!NIL_P(str = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, arg->io))) {
11956  rb_lastline_set(str);
11957  rb_yield(str);
11958  }
11960  return Qnil;
11961 }
11962 
11963 /*
11964  * call-seq:
11965  * IO.foreach(path, sep = $/, **opts) {|line| block } -> nil
11966  * IO.foreach(path, limit, **opts) {|line| block } -> nil
11967  * IO.foreach(path, sep, limit, **opts) {|line| block } -> nil
11968  * IO.foreach(...) -> an_enumerator
11969  *
11970  * Calls the block with each successive line read from the stream.
11971  *
11972  * When called from class \IO (but not subclasses of \IO),
11973  * this method has potential security vulnerabilities if called with untrusted input;
11974  * see {Command Injection}[rdoc-ref:command_injection.rdoc].
11975  *
11976  * The first argument must be a string that is the path to a file.
11977  *
11978  * With only argument +path+ given, parses lines from the file at the given +path+,
11979  * as determined by the default line separator,
11980  * and calls the block with each successive line:
11981  *
11982  * File.foreach('t.txt') {|line| p line }
11983  *
11984  * Output: the same as above.
11985  *
11986  * For both forms, command and path, the remaining arguments are the same.
11987  *
11988  * With argument +sep+ given, parses lines as determined by that line separator
11989  * (see {Line Separator}[rdoc-ref:IO@Line+Separator]):
11990  *
11991  * File.foreach('t.txt', 'li') {|line| p line }
11992  *
11993  * Output:
11994  *
11995  * "First li"
11996  * "ne\nSecond li"
11997  * "ne\n\nThird li"
11998  * "ne\nFourth li"
11999  * "ne\n"
12000  *
12001  * Each paragraph:
12002  *
12003  * File.foreach('t.txt', '') {|paragraph| p paragraph }
12004  *
12005  * Output:
12006  *
12007  * "First line\nSecond line\n\n"
12008  * "Third line\nFourth line\n"
12009  *
12010  * With argument +limit+ given, parses lines as determined by the default
12011  * line separator and the given line-length limit
12012  * (see {Line Separator}[rdoc-ref:IO@Line+Separator] and {Line Limit}[rdoc-ref:IO@Line+Limit]):
12013  *
12014  * File.foreach('t.txt', 7) {|line| p line }
12015  *
12016  * Output:
12017  *
12018  * "First l"
12019  * "ine\n"
12020  * "Second "
12021  * "line\n"
12022  * "\n"
12023  * "Third l"
12024  * "ine\n"
12025  * "Fourth l"
12026  * "line\n"
12027  *
12028  * With arguments +sep+ and +limit+ given,
12029  * combines the two behaviors
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+IO].
12037  *
12038  * Returns an Enumerator if no block is given.
12039  *
12040  */
12041 
12042 static VALUE
12043 rb_io_s_foreach(int argc, VALUE *argv, VALUE self)
12044 {
12045  VALUE opt;
12046  int orig_argc = argc;
12047  struct foreach_arg arg;
12048  struct getline_arg garg;
12049 
12050  argc = rb_scan_args(argc, argv, "12:", NULL, NULL, NULL, &opt);
12051  RETURN_ENUMERATOR(self, orig_argc, argv);
12052  extract_getline_args(argc-1, argv+1, &garg);
12053  open_key_args(self, argc, argv, opt, &arg);
12054  if (NIL_P(arg.io)) return Qnil;
12055  extract_getline_opts(opt, &garg);
12056  check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12057  return rb_ensure(io_s_foreach, (VALUE)&garg, rb_io_close, arg.io);
12058 }
12059 
12060 static VALUE
12061 io_s_readlines(VALUE v)
12062 {
12063  struct getline_arg *arg = (void *)v;
12064  return io_readlines(arg, arg->io);
12065 }
12066 
12067 /*
12068  * call-seq:
12069  * IO.readlines(path, sep = $/, **opts) -> array
12070  * IO.readlines(path, limit, **opts) -> array
12071  * IO.readlines(path, sep, limit, **opts) -> array
12072  *
12073  * Returns an array of all lines read from the stream.
12074  *
12075  * When called from class \IO (but not subclasses of \IO),
12076  * this method has potential security vulnerabilities if called with untrusted input;
12077  * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12078  *
12079  * The first argument must be a string that is the path to a file.
12080  *
12081  * With only argument +path+ given, parses lines from the file at the given +path+,
12082  * as determined by the default line separator,
12083  * and returns those lines in an array:
12084  *
12085  * IO.readlines('t.txt')
12086  * # => ["First line\n", "Second line\n", "\n", "Third line\n", "Fourth line\n"]
12087  *
12088  * With argument +sep+ given, parses lines as determined by that line separator
12089  * (see {Line Separator}[rdoc-ref:IO@Line+Separator]):
12090  *
12091  * # Ordinary separator.
12092  * IO.readlines('t.txt', 'li')
12093  * # =>["First li", "ne\nSecond li", "ne\n\nThird li", "ne\nFourth li", "ne\n"]
12094  * # Get-paragraphs separator.
12095  * IO.readlines('t.txt', '')
12096  * # => ["First line\nSecond line\n\n", "Third line\nFourth line\n"]
12097  * # Get-all separator.
12098  * IO.readlines('t.txt', nil)
12099  * # => ["First line\nSecond line\n\nThird line\nFourth line\n"]
12100  *
12101  * With argument +limit+ given, parses lines as determined by the default
12102  * line separator and the given line-length limit
12103  * (see {Line Separator}[rdoc-ref:IO@Line+Separator] and {Line Limit}[rdoc-ref:IO@Line+Limit]:
12104  *
12105  * IO.readlines('t.txt', 7)
12106  * # => ["First l", "ine\n", "Second ", "line\n", "\n", "Third l", "ine\n", "Fourth ", "line\n"]
12107  *
12108  * With arguments +sep+ and +limit+ given,
12109  * combines the two behaviors
12110  * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
12111  *
12112  * Optional keyword arguments +opts+ specify:
12113  *
12114  * - {Open Options}[rdoc-ref:IO@Open+Options].
12115  * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12116  * - {Line Options}[rdoc-ref:IO@Line+IO].
12117  *
12118  */
12119 
12120 static VALUE
12121 rb_io_s_readlines(int argc, VALUE *argv, VALUE io)
12122 {
12123  VALUE opt;
12124  struct foreach_arg arg;
12125  struct getline_arg garg;
12126 
12127  argc = rb_scan_args(argc, argv, "12:", NULL, NULL, NULL, &opt);
12128  extract_getline_args(argc-1, argv+1, &garg);
12129  open_key_args(io, argc, argv, opt, &arg);
12130  if (NIL_P(arg.io)) return Qnil;
12131  extract_getline_opts(opt, &garg);
12132  check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12133  return rb_ensure(io_s_readlines, (VALUE)&garg, rb_io_close, arg.io);
12134 }
12135 
12136 static VALUE
12137 io_s_read(VALUE v)
12138 {
12139  struct foreach_arg *arg = (void *)v;
12140  return io_read(arg->argc, arg->argv, arg->io);
12141 }
12142 
12143 struct seek_arg {
12144  VALUE io;
12145  VALUE offset;
12146  int mode;
12147 };
12148 
12149 static VALUE
12150 seek_before_access(VALUE argp)
12151 {
12152  struct seek_arg *arg = (struct seek_arg *)argp;
12153  rb_io_binmode(arg->io);
12154  return rb_io_seek(arg->io, arg->offset, arg->mode);
12155 }
12156 
12157 /*
12158  * call-seq:
12159  * IO.read(path, length = nil, offset = 0, **opts) -> string or nil
12160  *
12161  * Opens the stream, reads and returns some or all of its content,
12162  * and closes the stream; returns +nil+ if no bytes were read.
12163  *
12164  * When called from class \IO (but not subclasses of \IO),
12165  * this method has potential security vulnerabilities if called with untrusted input;
12166  * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12167  *
12168  * The first argument must be a string that is the path to a file.
12169  *
12170  * With only argument +path+ given, reads in text mode and returns the entire content
12171  * of the file at the given path:
12172  *
12173  * IO.read('t.txt')
12174  * # => "First line\nSecond line\n\nThird line\nFourth line\n"
12175  *
12176  * On Windows, text mode can terminate reading and leave bytes in the file
12177  * unread when encountering certain special bytes. Consider using
12178  * IO.binread if all bytes in the file should be read.
12179  *
12180  * With argument +length+, returns +length+ bytes if available:
12181  *
12182  * IO.read('t.txt', 7) # => "First l"
12183  * IO.read('t.txt', 700)
12184  * # => "First line\r\nSecond line\r\n\r\nFourth line\r\nFifth line\r\n"
12185  *
12186  * With arguments +length+ and +offset+, returns +length+ bytes
12187  * if available, beginning at the given +offset+:
12188  *
12189  * IO.read('t.txt', 10, 2) # => "rst line\nS"
12190  * IO.read('t.txt', 10, 200) # => nil
12191  *
12192  * Optional keyword arguments +opts+ specify:
12193  *
12194  * - {Open Options}[rdoc-ref:IO@Open+Options].
12195  * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12196  *
12197  */
12198 
12199 static VALUE
12200 rb_io_s_read(int argc, VALUE *argv, VALUE io)
12201 {
12202  VALUE opt, offset;
12203  long off;
12204  struct foreach_arg arg;
12205 
12206  argc = rb_scan_args(argc, argv, "13:", NULL, NULL, &offset, NULL, &opt);
12207  if (!NIL_P(offset) && (off = NUM2LONG(offset)) < 0) {
12208  rb_raise(rb_eArgError, "negative offset %ld given", off);
12209  }
12210  open_key_args(io, argc, argv, opt, &arg);
12211  if (NIL_P(arg.io)) return Qnil;
12212  if (!NIL_P(offset)) {
12213  struct seek_arg sarg;
12214  int state = 0;
12215  sarg.io = arg.io;
12216  sarg.offset = offset;
12217  sarg.mode = SEEK_SET;
12218  rb_protect(seek_before_access, (VALUE)&sarg, &state);
12219  if (state) {
12220  rb_io_close(arg.io);
12221  rb_jump_tag(state);
12222  }
12223  if (arg.argc == 2) arg.argc = 1;
12224  }
12225  return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
12226 }
12227 
12228 /*
12229  * call-seq:
12230  * IO.binread(path, length = nil, offset = 0) -> string or nil
12231  *
12232  * Behaves like IO.read, except that the stream is opened in binary mode
12233  * with ASCII-8BIT encoding.
12234  *
12235  * When called from class \IO (but not subclasses of \IO),
12236  * this method has potential security vulnerabilities if called with untrusted input;
12237  * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12238  *
12239  */
12240 
12241 static VALUE
12242 rb_io_s_binread(int argc, VALUE *argv, VALUE io)
12243 {
12244  VALUE offset;
12245  struct foreach_arg arg;
12246  enum {
12247  fmode = FMODE_READABLE|FMODE_BINMODE,
12248  oflags = O_RDONLY
12249 #ifdef O_BINARY
12250  |O_BINARY
12251 #endif
12252  };
12253  struct rb_io_encoding convconfig = {NULL, NULL, 0, Qnil};
12254 
12255  rb_scan_args(argc, argv, "12", NULL, NULL, &offset);
12256  FilePathValue(argv[0]);
12257  convconfig.enc = rb_ascii8bit_encoding();
12258  arg.io = rb_io_open_generic(io, argv[0], oflags, fmode, &convconfig, 0);
12259  if (NIL_P(arg.io)) return Qnil;
12260  arg.argv = argv+1;
12261  arg.argc = (argc > 1) ? 1 : 0;
12262  if (!NIL_P(offset)) {
12263  struct seek_arg sarg;
12264  int state = 0;
12265  sarg.io = arg.io;
12266  sarg.offset = offset;
12267  sarg.mode = SEEK_SET;
12268  rb_protect(seek_before_access, (VALUE)&sarg, &state);
12269  if (state) {
12270  rb_io_close(arg.io);
12271  rb_jump_tag(state);
12272  }
12273  }
12274  return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
12275 }
12276 
12277 static VALUE
12278 io_s_write0(VALUE v)
12279 {
12280  struct write_arg *arg = (void *)v;
12281  return io_write(arg->io,arg->str,arg->nosync);
12282 }
12283 
12284 static VALUE
12285 io_s_write(int argc, VALUE *argv, VALUE klass, int binary)
12286 {
12287  VALUE string, offset, opt;
12288  struct foreach_arg arg;
12289  struct write_arg warg;
12290 
12291  rb_scan_args(argc, argv, "21:", NULL, &string, &offset, &opt);
12292 
12293  if (NIL_P(opt)) opt = rb_hash_new();
12294  else opt = rb_hash_dup(opt);
12295 
12296 
12297  if (NIL_P(rb_hash_aref(opt,sym_mode))) {
12298  int mode = O_WRONLY|O_CREAT;
12299 #ifdef O_BINARY
12300  if (binary) mode |= O_BINARY;
12301 #endif
12302  if (NIL_P(offset)) mode |= O_TRUNC;
12303  rb_hash_aset(opt,sym_mode,INT2NUM(mode));
12304  }
12305  open_key_args(klass, argc, argv, opt, &arg);
12306 
12307 #ifndef O_BINARY
12308  if (binary) rb_io_binmode_m(arg.io);
12309 #endif
12310 
12311  if (NIL_P(arg.io)) return Qnil;
12312  if (!NIL_P(offset)) {
12313  struct seek_arg sarg;
12314  int state = 0;
12315  sarg.io = arg.io;
12316  sarg.offset = offset;
12317  sarg.mode = SEEK_SET;
12318  rb_protect(seek_before_access, (VALUE)&sarg, &state);
12319  if (state) {
12320  rb_io_close(arg.io);
12321  rb_jump_tag(state);
12322  }
12323  }
12324 
12325  warg.io = arg.io;
12326  warg.str = string;
12327  warg.nosync = 0;
12328 
12329  return rb_ensure(io_s_write0, (VALUE)&warg, rb_io_close, arg.io);
12330 }
12331 
12332 /*
12333  * call-seq:
12334  * IO.write(path, data, offset = 0, **opts) -> integer
12335  *
12336  * Opens the stream, writes the given +data+ to it,
12337  * and closes the stream; returns the number of bytes written.
12338  *
12339  * When called from class \IO (but not subclasses of \IO),
12340  * this method has potential security vulnerabilities if called with untrusted input;
12341  * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12342  *
12343  * The first argument must be a string that is the path to a file.
12344  *
12345  * With only argument +path+ given, writes the given +data+ to the file at that path:
12346  *
12347  * IO.write('t.tmp', 'abc') # => 3
12348  * File.read('t.tmp') # => "abc"
12349  *
12350  * If +offset+ is zero (the default), the file is overwritten:
12351  *
12352  * IO.write('t.tmp', 'A') # => 1
12353  * File.read('t.tmp') # => "A"
12354  *
12355  * If +offset+ in within the file content, the file is partly overwritten:
12356  *
12357  * IO.write('t.tmp', 'abcdef') # => 3
12358  * File.read('t.tmp') # => "abcdef"
12359  * # Offset within content.
12360  * IO.write('t.tmp', '012', 2) # => 3
12361  * File.read('t.tmp') # => "ab012f"
12362  *
12363  * If +offset+ is outside the file content,
12364  * the file is padded with null characters <tt>"\u0000"</tt>:
12365  *
12366  * IO.write('t.tmp', 'xyz', 10) # => 3
12367  * File.read('t.tmp') # => "ab012f\u0000\u0000\u0000\u0000xyz"
12368  *
12369  * Optional keyword arguments +opts+ specify:
12370  *
12371  * - {Open Options}[rdoc-ref:IO@Open+Options].
12372  * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12373  *
12374  */
12375 
12376 static VALUE
12377 rb_io_s_write(int argc, VALUE *argv, VALUE io)
12378 {
12379  return io_s_write(argc, argv, io, 0);
12380 }
12381 
12382 /*
12383  * call-seq:
12384  * IO.binwrite(path, string, offset = 0) -> integer
12385  *
12386  * Behaves like IO.write, except that the stream is opened in binary mode
12387  * with ASCII-8BIT encoding.
12388  *
12389  * When called from class \IO (but not subclasses of \IO),
12390  * this method has potential security vulnerabilities if called with untrusted input;
12391  * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12392  *
12393  */
12394 
12395 static VALUE
12396 rb_io_s_binwrite(int argc, VALUE *argv, VALUE io)
12397 {
12398  return io_s_write(argc, argv, io, 1);
12399 }
12400 
12402  VALUE src;
12403  VALUE dst;
12404  rb_off_t copy_length; /* (rb_off_t)-1 if not specified */
12405  rb_off_t src_offset; /* (rb_off_t)-1 if not specified */
12406 
12407  rb_io_t *src_fptr;
12408  rb_io_t *dst_fptr;
12409  unsigned close_src : 1;
12410  unsigned close_dst : 1;
12411  int error_no;
12412  rb_off_t total;
12413  const char *syserr;
12414  const char *notimp;
12415  VALUE th;
12416  struct stat src_stat;
12417  struct stat dst_stat;
12418 #ifdef HAVE_FCOPYFILE
12419  copyfile_state_t copyfile_state;
12420 #endif
12421 };
12422 
12423 static void *
12424 exec_interrupts(void *arg)
12425 {
12426  VALUE th = (VALUE)arg;
12427  rb_thread_execute_interrupts(th);
12428  return NULL;
12429 }
12430 
12431 /*
12432  * returns TRUE if the preceding system call was interrupted
12433  * so we can continue. If the thread was interrupted, we
12434  * reacquire the GVL to execute interrupts before continuing.
12435  */
12436 static int
12437 maygvl_copy_stream_continue_p(int has_gvl, struct copy_stream_struct *stp)
12438 {
12439  switch (errno) {
12440  case EINTR:
12441 #if defined(ERESTART)
12442  case ERESTART:
12443 #endif
12444  if (rb_thread_interrupted(stp->th)) {
12445  if (has_gvl)
12446  rb_thread_execute_interrupts(stp->th);
12447  else
12448  rb_thread_call_with_gvl(exec_interrupts, (void *)stp->th);
12449  }
12450  return TRUE;
12451  }
12452  return FALSE;
12453 }
12454 
12456  VALUE scheduler;
12457 
12458  rb_io_t *fptr;
12459  short events;
12460 
12461  VALUE result;
12462 };
12463 
12464 static void *
12465 fiber_scheduler_wait_for(void * _arguments)
12466 {
12467  struct fiber_scheduler_wait_for_arguments *arguments = (struct fiber_scheduler_wait_for_arguments *)_arguments;
12468 
12469  arguments->result = rb_fiber_scheduler_io_wait(arguments->scheduler, arguments->fptr->self, INT2NUM(arguments->events), RUBY_IO_TIMEOUT_DEFAULT);
12470 
12471  return NULL;
12472 }
12473 
12474 #if USE_POLL
12475 # define IOWAIT_SYSCALL "poll"
12476 STATIC_ASSERT(pollin_expected, POLLIN == RB_WAITFD_IN);
12477 STATIC_ASSERT(pollout_expected, POLLOUT == RB_WAITFD_OUT);
12478 static int
12479 nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout)
12480 {
12482  if (scheduler != Qnil) {
12483  struct fiber_scheduler_wait_for_arguments args = {.scheduler = scheduler, .fptr = fptr, .events = events};
12484  rb_thread_call_with_gvl(fiber_scheduler_wait_for, &args);
12485  return RTEST(args.result);
12486  }
12487 
12488  int fd = fptr->fd;
12489  if (fd == -1) return 0;
12490 
12491  struct pollfd fds;
12492 
12493  fds.fd = fd;
12494  fds.events = events;
12495 
12496  int timeout_milliseconds = -1;
12497 
12498  if (timeout) {
12499  timeout_milliseconds = (int)(timeout->tv_sec * 1000) + (int)(timeout->tv_usec / 1000);
12500  }
12501 
12502  return poll(&fds, 1, timeout_milliseconds);
12503 }
12504 #else /* !USE_POLL */
12505 # define IOWAIT_SYSCALL "select"
12506 static int
12507 nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout)
12508 {
12510  if (scheduler != Qnil) {
12511  struct fiber_scheduler_wait_for_arguments args = {.scheduler = scheduler, .fptr = fptr, .events = events};
12512  rb_thread_call_with_gvl(fiber_scheduler_wait_for, &args);
12513  return RTEST(args.result);
12514  }
12515 
12516  int fd = fptr->fd;
12517 
12518  if (fd == -1) {
12519  errno = EBADF;
12520  return -1;
12521  }
12522 
12523  rb_fdset_t fds;
12524  int ret;
12525 
12526  rb_fd_init(&fds);
12527  rb_fd_set(fd, &fds);
12528 
12529  switch (events) {
12530  case RB_WAITFD_IN:
12531  ret = rb_fd_select(fd + 1, &fds, 0, 0, timeout);
12532  break;
12533  case RB_WAITFD_OUT:
12534  ret = rb_fd_select(fd + 1, 0, &fds, 0, timeout);
12535  break;
12536  default:
12537  VM_UNREACHABLE(nogvl_wait_for);
12538  }
12539 
12540  rb_fd_term(&fds);
12541 
12542  // On timeout, this returns 0.
12543  return ret;
12544 }
12545 #endif /* !USE_POLL */
12546 
12547 static int
12548 maygvl_copy_stream_wait_read(int has_gvl, struct copy_stream_struct *stp)
12549 {
12550  int ret;
12551 
12552  do {
12553  if (has_gvl) {
12555  }
12556  else {
12557  ret = nogvl_wait_for(stp->th, stp->src_fptr, RB_WAITFD_IN, NULL);
12558  }
12559  } while (ret < 0 && maygvl_copy_stream_continue_p(has_gvl, stp));
12560 
12561  if (ret < 0) {
12562  stp->syserr = IOWAIT_SYSCALL;
12563  stp->error_no = errno;
12564  return ret;
12565  }
12566  return 0;
12567 }
12568 
12569 static int
12570 nogvl_copy_stream_wait_write(struct copy_stream_struct *stp)
12571 {
12572  int ret;
12573 
12574  do {
12575  ret = nogvl_wait_for(stp->th, stp->dst_fptr, RB_WAITFD_OUT, NULL);
12576  } while (ret < 0 && maygvl_copy_stream_continue_p(0, stp));
12577 
12578  if (ret < 0) {
12579  stp->syserr = IOWAIT_SYSCALL;
12580  stp->error_no = errno;
12581  return ret;
12582  }
12583  return 0;
12584 }
12585 
12586 #ifdef USE_COPY_FILE_RANGE
12587 
12588 static ssize_t
12589 simple_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)
12590 {
12591 #ifdef HAVE_COPY_FILE_RANGE
12592  return copy_file_range(in_fd, in_offset, out_fd, out_offset, count, flags);
12593 #else
12594  return syscall(__NR_copy_file_range, in_fd, in_offset, out_fd, out_offset, count, flags);
12595 #endif
12596 }
12597 
12598 static int
12599 nogvl_copy_file_range(struct copy_stream_struct *stp)
12600 {
12601  ssize_t ss;
12602  rb_off_t src_size;
12603  rb_off_t copy_length, src_offset, *src_offset_ptr;
12604 
12605  if (!S_ISREG(stp->src_stat.st_mode))
12606  return 0;
12607 
12608  src_size = stp->src_stat.st_size;
12609  src_offset = stp->src_offset;
12610  if (src_offset >= (rb_off_t)0) {
12611  src_offset_ptr = &src_offset;
12612  }
12613  else {
12614  src_offset_ptr = NULL; /* if src_offset_ptr is NULL, then bytes are read from in_fd starting from the file offset */
12615  }
12616 
12617  copy_length = stp->copy_length;
12618  if (copy_length < (rb_off_t)0) {
12619  if (src_offset < (rb_off_t)0) {
12620  rb_off_t current_offset;
12621  errno = 0;
12622  current_offset = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12623  if (current_offset < (rb_off_t)0 && errno) {
12624  stp->syserr = "lseek";
12625  stp->error_no = errno;
12626  return (int)current_offset;
12627  }
12628  copy_length = src_size - current_offset;
12629  }
12630  else {
12631  copy_length = src_size - src_offset;
12632  }
12633  }
12634 
12635  retry_copy_file_range:
12636 # if SIZEOF_OFF_T > SIZEOF_SIZE_T
12637  /* we are limited by the 32-bit ssize_t return value on 32-bit */
12638  ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12639 # else
12640  ss = (ssize_t)copy_length;
12641 # endif
12642  ss = simple_copy_file_range(stp->src_fptr->fd, src_offset_ptr, stp->dst_fptr->fd, NULL, ss, 0);
12643  if (0 < ss) {
12644  stp->total += ss;
12645  copy_length -= ss;
12646  if (0 < copy_length) {
12647  goto retry_copy_file_range;
12648  }
12649  }
12650  if (ss < 0) {
12651  if (maygvl_copy_stream_continue_p(0, stp)) {
12652  goto retry_copy_file_range;
12653  }
12654  switch (errno) {
12655  case EINVAL:
12656  case EPERM: /* copy_file_range(2) doesn't exist (may happen in
12657  docker container) */
12658 #ifdef ENOSYS
12659  case ENOSYS:
12660 #endif
12661 #ifdef EXDEV
12662  case EXDEV: /* in_fd and out_fd are not on the same filesystem */
12663 #endif
12664  return 0;
12665  case EAGAIN:
12666 #if EWOULDBLOCK != EAGAIN
12667  case EWOULDBLOCK:
12668 #endif
12669  {
12670  int ret = nogvl_copy_stream_wait_write(stp);
12671  if (ret < 0) return ret;
12672  }
12673  goto retry_copy_file_range;
12674  case EBADF:
12675  {
12676  int e = errno;
12677  int flags = fcntl(stp->dst_fptr->fd, F_GETFL);
12678 
12679  if (flags != -1 && flags & O_APPEND) {
12680  return 0;
12681  }
12682  errno = e;
12683  }
12684  }
12685  stp->syserr = "copy_file_range";
12686  stp->error_no = errno;
12687  return (int)ss;
12688  }
12689  return 1;
12690 }
12691 #endif
12692 
12693 #ifdef HAVE_FCOPYFILE
12694 static int
12695 nogvl_fcopyfile(struct copy_stream_struct *stp)
12696 {
12697  rb_off_t cur, ss = 0;
12698  const rb_off_t src_offset = stp->src_offset;
12699  int ret;
12700 
12701  if (stp->copy_length >= (rb_off_t)0) {
12702  /* copy_length can't be specified in fcopyfile(3) */
12703  return 0;
12704  }
12705 
12706  if (!S_ISREG(stp->src_stat.st_mode))
12707  return 0;
12708 
12709  if (!S_ISREG(stp->dst_stat.st_mode))
12710  return 0;
12711  if (lseek(stp->dst_fptr->fd, 0, SEEK_CUR) > (rb_off_t)0) /* if dst IO was already written */
12712  return 0;
12713  if (fcntl(stp->dst_fptr->fd, F_GETFL) & O_APPEND) {
12714  /* fcopyfile(3) appends src IO to dst IO and then truncates
12715  * dst IO to src IO's original size. */
12716  rb_off_t end = lseek(stp->dst_fptr->fd, 0, SEEK_END);
12717  lseek(stp->dst_fptr->fd, 0, SEEK_SET);
12718  if (end > (rb_off_t)0) return 0;
12719  }
12720 
12721  if (src_offset > (rb_off_t)0) {
12722  rb_off_t r;
12723 
12724  /* get current offset */
12725  errno = 0;
12726  cur = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12727  if (cur < (rb_off_t)0 && errno) {
12728  stp->error_no = errno;
12729  return 1;
12730  }
12731 
12732  errno = 0;
12733  r = lseek(stp->src_fptr->fd, src_offset, SEEK_SET);
12734  if (r < (rb_off_t)0 && errno) {
12735  stp->error_no = errno;
12736  return 1;
12737  }
12738  }
12739 
12740  stp->copyfile_state = copyfile_state_alloc(); /* this will be freed by copy_stream_finalize() */
12741  ret = fcopyfile(stp->src_fptr->fd, stp->dst_fptr->fd, stp->copyfile_state, COPYFILE_DATA);
12742  copyfile_state_get(stp->copyfile_state, COPYFILE_STATE_COPIED, &ss); /* get copied bytes */
12743 
12744  if (ret == 0) { /* success */
12745  stp->total = ss;
12746  if (src_offset > (rb_off_t)0) {
12747  rb_off_t r;
12748  errno = 0;
12749  /* reset offset */
12750  r = lseek(stp->src_fptr->fd, cur, SEEK_SET);
12751  if (r < (rb_off_t)0 && errno) {
12752  stp->error_no = errno;
12753  return 1;
12754  }
12755  }
12756  }
12757  else {
12758  switch (errno) {
12759  case ENOTSUP:
12760  case EPERM:
12761  case EINVAL:
12762  return 0;
12763  }
12764  stp->syserr = "fcopyfile";
12765  stp->error_no = errno;
12766  return (int)ret;
12767  }
12768  return 1;
12769 }
12770 #endif
12771 
12772 #ifdef HAVE_SENDFILE
12773 
12774 # ifdef __linux__
12775 # define USE_SENDFILE
12776 
12777 # ifdef HAVE_SYS_SENDFILE_H
12778 # include <sys/sendfile.h>
12779 # endif
12780 
12781 static ssize_t
12782 simple_sendfile(int out_fd, int in_fd, rb_off_t *offset, rb_off_t count)
12783 {
12784  return sendfile(out_fd, in_fd, offset, (size_t)count);
12785 }
12786 
12787 # elif 0 /* defined(__FreeBSD__) || defined(__DragonFly__) */ || defined(__APPLE__)
12788 /* This runs on FreeBSD8.1 r30210, but sendfiles blocks its execution
12789  * without cpuset -l 0.
12790  */
12791 # define USE_SENDFILE
12792 
12793 static ssize_t
12794 simple_sendfile(int out_fd, int in_fd, rb_off_t *offset, rb_off_t count)
12795 {
12796  int r;
12797  rb_off_t pos = offset ? *offset : lseek(in_fd, 0, SEEK_CUR);
12798  rb_off_t sbytes;
12799 # ifdef __APPLE__
12800  r = sendfile(in_fd, out_fd, pos, &count, NULL, 0);
12801  sbytes = count;
12802 # else
12803  r = sendfile(in_fd, out_fd, pos, (size_t)count, NULL, &sbytes, 0);
12804 # endif
12805  if (r != 0 && sbytes == 0) return r;
12806  if (offset) {
12807  *offset += sbytes;
12808  }
12809  else {
12810  lseek(in_fd, sbytes, SEEK_CUR);
12811  }
12812  return (ssize_t)sbytes;
12813 }
12814 
12815 # endif
12816 
12817 #endif
12818 
12819 #ifdef USE_SENDFILE
12820 static int
12821 nogvl_copy_stream_sendfile(struct copy_stream_struct *stp)
12822 {
12823  ssize_t ss;
12824  rb_off_t src_size;
12825  rb_off_t copy_length;
12826  rb_off_t src_offset;
12827  int use_pread;
12828 
12829  if (!S_ISREG(stp->src_stat.st_mode))
12830  return 0;
12831 
12832  src_size = stp->src_stat.st_size;
12833 #ifndef __linux__
12834  if ((stp->dst_stat.st_mode & S_IFMT) != S_IFSOCK)
12835  return 0;
12836 #endif
12837 
12838  src_offset = stp->src_offset;
12839  use_pread = src_offset >= (rb_off_t)0;
12840 
12841  copy_length = stp->copy_length;
12842  if (copy_length < (rb_off_t)0) {
12843  if (use_pread)
12844  copy_length = src_size - src_offset;
12845  else {
12846  rb_off_t cur;
12847  errno = 0;
12848  cur = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12849  if (cur < (rb_off_t)0 && errno) {
12850  stp->syserr = "lseek";
12851  stp->error_no = errno;
12852  return (int)cur;
12853  }
12854  copy_length = src_size - cur;
12855  }
12856  }
12857 
12858  retry_sendfile:
12859 # if SIZEOF_OFF_T > SIZEOF_SIZE_T
12860  /* we are limited by the 32-bit ssize_t return value on 32-bit */
12861  ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12862 # else
12863  ss = (ssize_t)copy_length;
12864 # endif
12865  if (use_pread) {
12866  ss = simple_sendfile(stp->dst_fptr->fd, stp->src_fptr->fd, &src_offset, ss);
12867  }
12868  else {
12869  ss = simple_sendfile(stp->dst_fptr->fd, stp->src_fptr->fd, NULL, ss);
12870  }
12871  if (0 < ss) {
12872  stp->total += ss;
12873  copy_length -= ss;
12874  if (0 < copy_length) {
12875  goto retry_sendfile;
12876  }
12877  }
12878  if (ss < 0) {
12879  if (maygvl_copy_stream_continue_p(0, stp))
12880  goto retry_sendfile;
12881  switch (errno) {
12882  case EINVAL:
12883 #ifdef ENOSYS
12884  case ENOSYS:
12885 #endif
12886 #ifdef EOPNOTSUP
12887  /* some RedHat kernels may return EOPNOTSUP on an NFS mount.
12888  see also: [Feature #16965] */
12889  case EOPNOTSUP:
12890 #endif
12891  return 0;
12892  case EAGAIN:
12893 #if EWOULDBLOCK != EAGAIN
12894  case EWOULDBLOCK:
12895 #endif
12896  {
12897  int ret;
12898 #ifndef __linux__
12899  /*
12900  * Linux requires stp->src_fptr->fd to be a mmap-able (regular) file,
12901  * select() reports regular files to always be "ready", so
12902  * there is no need to select() on it.
12903  * Other OSes may have the same limitation for sendfile() which
12904  * allow us to bypass maygvl_copy_stream_wait_read()...
12905  */
12906  ret = maygvl_copy_stream_wait_read(0, stp);
12907  if (ret < 0) return ret;
12908 #endif
12909  ret = nogvl_copy_stream_wait_write(stp);
12910  if (ret < 0) return ret;
12911  }
12912  goto retry_sendfile;
12913  }
12914  stp->syserr = "sendfile";
12915  stp->error_no = errno;
12916  return (int)ss;
12917  }
12918  return 1;
12919 }
12920 #endif
12921 
12922 static ssize_t
12923 maygvl_read(int has_gvl, rb_io_t *fptr, void *buf, size_t count)
12924 {
12925  if (has_gvl)
12926  return rb_io_read_memory(fptr, buf, count);
12927  else
12928  return read(fptr->fd, buf, count);
12929 }
12930 
12931 static ssize_t
12932 maygvl_copy_stream_read(int has_gvl, struct copy_stream_struct *stp, char *buf, size_t len, rb_off_t offset)
12933 {
12934  ssize_t ss;
12935  retry_read:
12936  if (offset < (rb_off_t)0) {
12937  ss = maygvl_read(has_gvl, stp->src_fptr, buf, len);
12938  }
12939  else {
12940  ss = pread(stp->src_fptr->fd, buf, len, offset);
12941  }
12942  if (ss == 0) {
12943  return 0;
12944  }
12945  if (ss < 0) {
12946  if (maygvl_copy_stream_continue_p(has_gvl, stp))
12947  goto retry_read;
12948  switch (errno) {
12949  case EAGAIN:
12950 #if EWOULDBLOCK != EAGAIN
12951  case EWOULDBLOCK:
12952 #endif
12953  {
12954  int ret = maygvl_copy_stream_wait_read(has_gvl, stp);
12955  if (ret < 0) return ret;
12956  }
12957  goto retry_read;
12958 #ifdef ENOSYS
12959  case ENOSYS:
12960  stp->notimp = "pread";
12961  return ss;
12962 #endif
12963  }
12964  stp->syserr = offset < (rb_off_t)0 ? "read" : "pread";
12965  stp->error_no = errno;
12966  }
12967  return ss;
12968 }
12969 
12970 static int
12971 nogvl_copy_stream_write(struct copy_stream_struct *stp, char *buf, size_t len)
12972 {
12973  ssize_t ss;
12974  int off = 0;
12975  while (len) {
12976  ss = write(stp->dst_fptr->fd, buf+off, len);
12977  if (ss < 0) {
12978  if (maygvl_copy_stream_continue_p(0, stp))
12979  continue;
12980  if (io_again_p(errno)) {
12981  int ret = nogvl_copy_stream_wait_write(stp);
12982  if (ret < 0) return ret;
12983  continue;
12984  }
12985  stp->syserr = "write";
12986  stp->error_no = errno;
12987  return (int)ss;
12988  }
12989  off += (int)ss;
12990  len -= (int)ss;
12991  stp->total += ss;
12992  }
12993  return 0;
12994 }
12995 
12996 static void
12997 nogvl_copy_stream_read_write(struct copy_stream_struct *stp)
12998 {
12999  char buf[1024*16];
13000  size_t len;
13001  ssize_t ss;
13002  int ret;
13003  rb_off_t copy_length;
13004  rb_off_t src_offset;
13005  int use_eof;
13006  int use_pread;
13007 
13008  copy_length = stp->copy_length;
13009  use_eof = copy_length < (rb_off_t)0;
13010  src_offset = stp->src_offset;
13011  use_pread = src_offset >= (rb_off_t)0;
13012 
13013  if (use_pread && stp->close_src) {
13014  rb_off_t r;
13015  errno = 0;
13016  r = lseek(stp->src_fptr->fd, src_offset, SEEK_SET);
13017  if (r < (rb_off_t)0 && errno) {
13018  stp->syserr = "lseek";
13019  stp->error_no = errno;
13020  return;
13021  }
13022  src_offset = (rb_off_t)-1;
13023  use_pread = 0;
13024  }
13025 
13026  while (use_eof || 0 < copy_length) {
13027  if (!use_eof && copy_length < (rb_off_t)sizeof(buf)) {
13028  len = (size_t)copy_length;
13029  }
13030  else {
13031  len = sizeof(buf);
13032  }
13033  if (use_pread) {
13034  ss = maygvl_copy_stream_read(0, stp, buf, len, src_offset);
13035  if (0 < ss)
13036  src_offset += ss;
13037  }
13038  else {
13039  ss = maygvl_copy_stream_read(0, stp, buf, len, (rb_off_t)-1);
13040  }
13041  if (ss <= 0) /* EOF or error */
13042  return;
13043 
13044  ret = nogvl_copy_stream_write(stp, buf, ss);
13045  if (ret < 0)
13046  return;
13047 
13048  if (!use_eof)
13049  copy_length -= ss;
13050  }
13051 }
13052 
13053 static void *
13054 nogvl_copy_stream_func(void *arg)
13055 {
13056  struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13057 #if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13058  int ret;
13059 #endif
13060 
13061 #ifdef USE_COPY_FILE_RANGE
13062  ret = nogvl_copy_file_range(stp);
13063  if (ret != 0)
13064  goto finish; /* error or success */
13065 #endif
13066 
13067 #ifdef HAVE_FCOPYFILE
13068  ret = nogvl_fcopyfile(stp);
13069  if (ret != 0)
13070  goto finish; /* error or success */
13071 #endif
13072 
13073 #ifdef USE_SENDFILE
13074  ret = nogvl_copy_stream_sendfile(stp);
13075  if (ret != 0)
13076  goto finish; /* error or success */
13077 #endif
13078 
13079  nogvl_copy_stream_read_write(stp);
13080 
13081 #if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13082  finish:
13083 #endif
13084  return 0;
13085 }
13086 
13087 static VALUE
13088 copy_stream_fallback_body(VALUE arg)
13089 {
13090  struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13091  const int buflen = 16*1024;
13092  VALUE n;
13093  VALUE buf = rb_str_buf_new(buflen);
13094  rb_off_t rest = stp->copy_length;
13095  rb_off_t off = stp->src_offset;
13096  ID read_method = id_readpartial;
13097 
13098  if (!stp->src_fptr) {
13099  if (!rb_respond_to(stp->src, read_method)) {
13100  read_method = id_read;
13101  }
13102  }
13103 
13104  while (1) {
13105  long numwrote;
13106  long l;
13107  if (stp->copy_length < (rb_off_t)0) {
13108  l = buflen;
13109  }
13110  else {
13111  if (rest == 0) {
13112  rb_str_resize(buf, 0);
13113  break;
13114  }
13115  l = buflen < rest ? buflen : (long)rest;
13116  }
13117  if (!stp->src_fptr) {
13118  VALUE rc = rb_funcall(stp->src, read_method, 2, INT2FIX(l), buf);
13119 
13120  if (read_method == id_read && NIL_P(rc))
13121  break;
13122  }
13123  else {
13124  ssize_t ss;
13125  rb_str_resize(buf, buflen);
13126  ss = maygvl_copy_stream_read(1, stp, RSTRING_PTR(buf), l, off);
13127  rb_str_resize(buf, ss > 0 ? ss : 0);
13128  if (ss < 0)
13129  return Qnil;
13130  if (ss == 0)
13131  rb_eof_error();
13132  if (off >= (rb_off_t)0)
13133  off += ss;
13134  }
13135  n = rb_io_write(stp->dst, buf);
13136  numwrote = NUM2LONG(n);
13137  stp->total += numwrote;
13138  rest -= numwrote;
13139  if (read_method == id_read && RSTRING_LEN(buf) == 0) {
13140  break;
13141  }
13142  }
13143 
13144  return Qnil;
13145 }
13146 
13147 static VALUE
13148 copy_stream_fallback(struct copy_stream_struct *stp)
13149 {
13150  if (!stp->src_fptr && stp->src_offset >= (rb_off_t)0) {
13151  rb_raise(rb_eArgError, "cannot specify src_offset for non-IO");
13152  }
13153  rb_rescue2(copy_stream_fallback_body, (VALUE)stp,
13154  (VALUE (*) (VALUE, VALUE))0, (VALUE)0,
13155  rb_eEOFError, (VALUE)0);
13156  return Qnil;
13157 }
13158 
13159 static VALUE
13160 copy_stream_body(VALUE arg)
13161 {
13162  struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13163  VALUE src_io = stp->src, dst_io = stp->dst;
13164  const int common_oflags = 0
13165 #ifdef O_NOCTTY
13166  | O_NOCTTY
13167 #endif
13168  ;
13169 
13170  stp->th = rb_thread_current();
13171 
13172  stp->total = 0;
13173 
13174  if (src_io == argf ||
13175  !(RB_TYPE_P(src_io, T_FILE) ||
13176  RB_TYPE_P(src_io, T_STRING) ||
13177  rb_respond_to(src_io, rb_intern("to_path")))) {
13178  stp->src_fptr = NULL;
13179  }
13180  else {
13181  int stat_ret;
13182  VALUE tmp_io = rb_io_check_io(src_io);
13183  if (!NIL_P(tmp_io)) {
13184  src_io = tmp_io;
13185  }
13186  else if (!RB_TYPE_P(src_io, T_FILE)) {
13187  VALUE args[2];
13188  FilePathValue(src_io);
13189  args[0] = src_io;
13190  args[1] = INT2NUM(O_RDONLY|common_oflags);
13191  src_io = rb_class_new_instance(2, args, rb_cFile);
13192  stp->src = src_io;
13193  stp->close_src = 1;
13194  }
13195  RB_IO_POINTER(src_io, stp->src_fptr);
13196  rb_io_check_byte_readable(stp->src_fptr);
13197 
13198  stat_ret = fstat(stp->src_fptr->fd, &stp->src_stat);
13199  if (stat_ret < 0) {
13200  stp->syserr = "fstat";
13201  stp->error_no = errno;
13202  return Qnil;
13203  }
13204  }
13205 
13206  if (dst_io == argf ||
13207  !(RB_TYPE_P(dst_io, T_FILE) ||
13208  RB_TYPE_P(dst_io, T_STRING) ||
13209  rb_respond_to(dst_io, rb_intern("to_path")))) {
13210  stp->dst_fptr = NULL;
13211  }
13212  else {
13213  int stat_ret;
13214  VALUE tmp_io = rb_io_check_io(dst_io);
13215  if (!NIL_P(tmp_io)) {
13216  dst_io = GetWriteIO(tmp_io);
13217  }
13218  else if (!RB_TYPE_P(dst_io, T_FILE)) {
13219  VALUE args[3];
13220  FilePathValue(dst_io);
13221  args[0] = dst_io;
13222  args[1] = INT2NUM(O_WRONLY|O_CREAT|O_TRUNC|common_oflags);
13223  args[2] = INT2FIX(0666);
13224  dst_io = rb_class_new_instance(3, args, rb_cFile);
13225  stp->dst = dst_io;
13226  stp->close_dst = 1;
13227  }
13228  else {
13229  dst_io = GetWriteIO(dst_io);
13230  stp->dst = dst_io;
13231  }
13232  RB_IO_POINTER(dst_io, stp->dst_fptr);
13233  rb_io_check_writable(stp->dst_fptr);
13234 
13235  stat_ret = fstat(stp->dst_fptr->fd, &stp->dst_stat);
13236  if (stat_ret < 0) {
13237  stp->syserr = "fstat";
13238  stp->error_no = errno;
13239  return Qnil;
13240  }
13241  }
13242 
13243 #ifdef O_BINARY
13244  if (stp->src_fptr)
13245  SET_BINARY_MODE_WITH_SEEK_CUR(stp->src_fptr);
13246 #endif
13247  if (stp->dst_fptr)
13248  io_ascii8bit_binmode(stp->dst_fptr);
13249 
13250  if (stp->src_offset < (rb_off_t)0 && stp->src_fptr && stp->src_fptr->rbuf.len) {
13251  size_t len = stp->src_fptr->rbuf.len;
13252  VALUE str;
13253  if (stp->copy_length >= (rb_off_t)0 && stp->copy_length < (rb_off_t)len) {
13254  len = (size_t)stp->copy_length;
13255  }
13256  str = rb_str_buf_new(len);
13257  rb_str_resize(str,len);
13258  read_buffered_data(RSTRING_PTR(str), len, stp->src_fptr);
13259  if (stp->dst_fptr) { /* IO or filename */
13260  if (io_binwrite(RSTRING_PTR(str), RSTRING_LEN(str), stp->dst_fptr, 0) < 0)
13261  rb_sys_fail_on_write(stp->dst_fptr);
13262  }
13263  else /* others such as StringIO */
13264  rb_io_write(dst_io, str);
13265  rb_str_resize(str, 0);
13266  stp->total += len;
13267  if (stp->copy_length >= (rb_off_t)0)
13268  stp->copy_length -= len;
13269  }
13270 
13271  if (stp->dst_fptr && io_fflush(stp->dst_fptr) < 0) {
13272  rb_raise(rb_eIOError, "flush failed");
13273  }
13274 
13275  if (stp->copy_length == 0)
13276  return Qnil;
13277 
13278  if (stp->src_fptr == NULL || stp->dst_fptr == NULL) {
13279  return copy_stream_fallback(stp);
13280  }
13281 
13282  IO_WITHOUT_GVL(nogvl_copy_stream_func, stp);
13283  return Qnil;
13284 }
13285 
13286 static VALUE
13287 copy_stream_finalize(VALUE arg)
13288 {
13289  struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13290 
13291 #ifdef HAVE_FCOPYFILE
13292  if (stp->copyfile_state) {
13293  copyfile_state_free(stp->copyfile_state);
13294  }
13295 #endif
13296 
13297  if (stp->close_src) {
13298  rb_io_close_m(stp->src);
13299  }
13300  if (stp->close_dst) {
13301  rb_io_close_m(stp->dst);
13302  }
13303  if (stp->syserr) {
13304  rb_syserr_fail(stp->error_no, stp->syserr);
13305  }
13306  if (stp->notimp) {
13307  rb_raise(rb_eNotImpError, "%s() not implemented", stp->notimp);
13308  }
13309  return Qnil;
13310 }
13311 
13312 /*
13313  * call-seq:
13314  * IO.copy_stream(src, dst, src_length = nil, src_offset = 0) -> integer
13315  *
13316  * Copies from the given +src+ to the given +dst+,
13317  * returning the number of bytes copied.
13318  *
13319  * - The given +src+ must be one of the following:
13320  *
13321  * - The path to a readable file, from which source data is to be read.
13322  * - An \IO-like object, opened for reading and capable of responding
13323  * to method +:readpartial+ or method +:read+.
13324  *
13325  * - The given +dst+ must be one of the following:
13326  *
13327  * - The path to a writable file, to which data is to be written.
13328  * - An \IO-like object, opened for writing and capable of responding
13329  * to method +:write+.
13330  *
13331  * The examples here use file <tt>t.txt</tt> as source:
13332  *
13333  * File.read('t.txt')
13334  * # => "First line\nSecond line\n\nThird line\nFourth line\n"
13335  * File.read('t.txt').size # => 47
13336  *
13337  * If only arguments +src+ and +dst+ are given,
13338  * the entire source stream is copied:
13339  *
13340  * # Paths.
13341  * IO.copy_stream('t.txt', 't.tmp') # => 47
13342  *
13343  * # IOs (recall that a File is also an IO).
13344  * src_io = File.open('t.txt', 'r') # => #<File:t.txt>
13345  * dst_io = File.open('t.tmp', 'w') # => #<File:t.tmp>
13346  * IO.copy_stream(src_io, dst_io) # => 47
13347  * src_io.close
13348  * dst_io.close
13349  *
13350  * With argument +src_length+ a non-negative integer,
13351  * no more than that many bytes are copied:
13352  *
13353  * IO.copy_stream('t.txt', 't.tmp', 10) # => 10
13354  * File.read('t.tmp') # => "First line"
13355  *
13356  * With argument +src_offset+ also given,
13357  * the source stream is read beginning at that offset:
13358  *
13359  * IO.copy_stream('t.txt', 't.tmp', 11, 11) # => 11
13360  * IO.read('t.tmp') # => "Second line"
13361  *
13362  */
13363 static VALUE
13364 rb_io_s_copy_stream(int argc, VALUE *argv, VALUE io)
13365 {
13366  VALUE src, dst, length, src_offset;
13367  struct copy_stream_struct st;
13368 
13369  MEMZERO(&st, struct copy_stream_struct, 1);
13370 
13371  rb_scan_args(argc, argv, "22", &src, &dst, &length, &src_offset);
13372 
13373  st.src = src;
13374  st.dst = dst;
13375 
13376  st.src_fptr = NULL;
13377  st.dst_fptr = NULL;
13378 
13379  if (NIL_P(length))
13380  st.copy_length = (rb_off_t)-1;
13381  else
13382  st.copy_length = NUM2OFFT(length);
13383 
13384  if (NIL_P(src_offset))
13385  st.src_offset = (rb_off_t)-1;
13386  else
13387  st.src_offset = NUM2OFFT(src_offset);
13388 
13389  rb_ensure(copy_stream_body, (VALUE)&st, copy_stream_finalize, (VALUE)&st);
13390 
13391  return OFFT2NUM(st.total);
13392 }
13393 
13394 /*
13395  * call-seq:
13396  * external_encoding -> encoding or nil
13397  *
13398  * Returns the Encoding object that represents the encoding of the stream,
13399  * or +nil+ if the stream is in write mode and no encoding is specified.
13400  *
13401  * See {Encodings}[rdoc-ref:File@Encodings].
13402  *
13403  */
13404 
13405 static VALUE
13406 rb_io_external_encoding(VALUE io)
13407 {
13408  rb_io_t *fptr = RFILE(rb_io_taint_check(io))->fptr;
13409 
13410  if (fptr->encs.enc2) {
13411  return rb_enc_from_encoding(fptr->encs.enc2);
13412  }
13413  if (fptr->mode & FMODE_WRITABLE) {
13414  if (fptr->encs.enc)
13415  return rb_enc_from_encoding(fptr->encs.enc);
13416  return Qnil;
13417  }
13418  return rb_enc_from_encoding(io_read_encoding(fptr));
13419 }
13420 
13421 /*
13422  * call-seq:
13423  * internal_encoding -> encoding or nil
13424  *
13425  * Returns the Encoding object that represents the encoding of the internal string,
13426  * if conversion is specified,
13427  * or +nil+ otherwise.
13428  *
13429  * See {Encodings}[rdoc-ref:File@Encodings].
13430  *
13431  */
13432 
13433 static VALUE
13434 rb_io_internal_encoding(VALUE io)
13435 {
13436  rb_io_t *fptr = RFILE(rb_io_taint_check(io))->fptr;
13437 
13438  if (!fptr->encs.enc2) return Qnil;
13439  return rb_enc_from_encoding(io_read_encoding(fptr));
13440 }
13441 
13442 /*
13443  * call-seq:
13444  * set_encoding(ext_enc) -> self
13445  * set_encoding(ext_enc, int_enc, **enc_opts) -> self
13446  * set_encoding('ext_enc:int_enc', **enc_opts) -> self
13447  *
13448  * See {Encodings}[rdoc-ref:File@Encodings].
13449  *
13450  * Argument +ext_enc+, if given, must be an Encoding object
13451  * or a String with the encoding name;
13452  * it is assigned as the encoding for the stream.
13453  *
13454  * Argument +int_enc+, if given, must be an Encoding object
13455  * or a String with the encoding name;
13456  * it is assigned as the encoding for the internal string.
13457  *
13458  * Argument <tt>'ext_enc:int_enc'</tt>, if given, is a string
13459  * containing two colon-separated encoding names;
13460  * corresponding Encoding objects are assigned as the external
13461  * and internal encodings for the stream.
13462  *
13463  * If the external encoding of a string is binary/ASCII-8BIT,
13464  * the internal encoding of the string is set to nil, since no
13465  * transcoding is needed.
13466  *
13467  * Optional keyword arguments +enc_opts+ specify
13468  * {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
13469  *
13470  */
13471 
13472 static VALUE
13473 rb_io_set_encoding(int argc, VALUE *argv, VALUE io)
13474 {
13475  rb_io_t *fptr;
13476  VALUE v1, v2, opt;
13477 
13478  if (!RB_TYPE_P(io, T_FILE)) {
13479  return forward(io, id_set_encoding, argc, argv);
13480  }
13481 
13482  argc = rb_scan_args(argc, argv, "11:", &v1, &v2, &opt);
13483  GetOpenFile(io, fptr);
13484  io_encoding_set(fptr, v1, v2, opt);
13485  return io;
13486 }
13487 
13488 void
13489 rb_stdio_set_default_encoding(void)
13490 {
13491  VALUE val = Qnil;
13492 
13493 #ifdef _WIN32
13494  if (isatty(fileno(stdin))) {
13495  rb_encoding *external = rb_locale_encoding();
13497  if (!internal) internal = rb_default_external_encoding();
13498  io_encoding_set(RFILE(rb_stdin)->fptr,
13499  rb_enc_from_encoding(external),
13500  rb_enc_from_encoding(internal),
13501  Qnil);
13502  }
13503  else
13504 #endif
13505  rb_io_set_encoding(1, &val, rb_stdin);
13506  rb_io_set_encoding(1, &val, rb_stdout);
13507  rb_io_set_encoding(1, &val, rb_stderr);
13508 }
13509 
13510 static inline int
13511 global_argf_p(VALUE arg)
13512 {
13513  return arg == argf;
13514 }
13515 
13516 typedef VALUE (*argf_encoding_func)(VALUE io);
13517 
13518 static VALUE
13519 argf_encoding(VALUE argf, argf_encoding_func func)
13520 {
13521  if (!RTEST(ARGF.current_file)) {
13522  return rb_enc_default_external();
13523  }
13524  return func(rb_io_check_io(ARGF.current_file));
13525 }
13526 
13527 /*
13528  * call-seq:
13529  * ARGF.external_encoding -> encoding
13530  *
13531  * Returns the external encoding for files read from ARGF as an Encoding
13532  * object. The external encoding is the encoding of the text as stored in a
13533  * file. Contrast with ARGF.internal_encoding, which is the encoding used to
13534  * represent this text within Ruby.
13535  *
13536  * To set the external encoding use ARGF.set_encoding.
13537  *
13538  * For example:
13539  *
13540  * ARGF.external_encoding #=> #<Encoding:UTF-8>
13541  *
13542  */
13543 static VALUE
13544 argf_external_encoding(VALUE argf)
13545 {
13546  return argf_encoding(argf, rb_io_external_encoding);
13547 }
13548 
13549 /*
13550  * call-seq:
13551  * ARGF.internal_encoding -> encoding
13552  *
13553  * Returns the internal encoding for strings read from ARGF as an
13554  * Encoding object.
13555  *
13556  * If ARGF.set_encoding has been called with two encoding names, the second
13557  * is returned. Otherwise, if +Encoding.default_external+ has been set, that
13558  * value is returned. Failing that, if a default external encoding was
13559  * specified on the command-line, that value is used. If the encoding is
13560  * unknown, +nil+ is returned.
13561  */
13562 static VALUE
13563 argf_internal_encoding(VALUE argf)
13564 {
13565  return argf_encoding(argf, rb_io_internal_encoding);
13566 }
13567 
13568 /*
13569  * call-seq:
13570  * ARGF.set_encoding(ext_enc) -> ARGF
13571  * ARGF.set_encoding("ext_enc:int_enc") -> ARGF
13572  * ARGF.set_encoding(ext_enc, int_enc) -> ARGF
13573  * ARGF.set_encoding("ext_enc:int_enc", opt) -> ARGF
13574  * ARGF.set_encoding(ext_enc, int_enc, opt) -> ARGF
13575  *
13576  * If single argument is specified, strings read from ARGF are tagged with
13577  * the encoding specified.
13578  *
13579  * If two encoding names separated by a colon are given, e.g. "ascii:utf-8",
13580  * the read string is converted from the first encoding (external encoding)
13581  * to the second encoding (internal encoding), then tagged with the second
13582  * encoding.
13583  *
13584  * If two arguments are specified, they must be encoding objects or encoding
13585  * names. Again, the first specifies the external encoding; the second
13586  * specifies the internal encoding.
13587  *
13588  * If the external encoding and the internal encoding are specified, the
13589  * optional Hash argument can be used to adjust the conversion process. The
13590  * structure of this hash is explained in the String#encode documentation.
13591  *
13592  * For example:
13593  *
13594  * ARGF.set_encoding('ascii') # Tag the input as US-ASCII text
13595  * ARGF.set_encoding(Encoding::UTF_8) # Tag the input as UTF-8 text
13596  * ARGF.set_encoding('utf-8','ascii') # Transcode the input from US-ASCII
13597  * # to UTF-8.
13598  */
13599 static VALUE
13600 argf_set_encoding(int argc, VALUE *argv, VALUE argf)
13601 {
13602  rb_io_t *fptr;
13603 
13604  if (!next_argv()) {
13605  rb_raise(rb_eArgError, "no stream to set encoding");
13606  }
13607  rb_io_set_encoding(argc, argv, ARGF.current_file);
13608  GetOpenFile(ARGF.current_file, fptr);
13609  ARGF.encs = fptr->encs;
13610  return argf;
13611 }
13612 
13613 /*
13614  * call-seq:
13615  * ARGF.tell -> Integer
13616  * ARGF.pos -> Integer
13617  *
13618  * Returns the current offset (in bytes) of the current file in ARGF.
13619  *
13620  * ARGF.pos #=> 0
13621  * ARGF.gets #=> "This is line one\n"
13622  * ARGF.pos #=> 17
13623  *
13624  */
13625 static VALUE
13626 argf_tell(VALUE argf)
13627 {
13628  if (!next_argv()) {
13629  rb_raise(rb_eArgError, "no stream to tell");
13630  }
13631  ARGF_FORWARD(0, 0);
13632  return rb_io_tell(ARGF.current_file);
13633 }
13634 
13635 /*
13636  * call-seq:
13637  * ARGF.seek(amount, whence=IO::SEEK_SET) -> 0
13638  *
13639  * Seeks to offset _amount_ (an Integer) in the ARGF stream according to
13640  * the value of _whence_. See IO#seek for further details.
13641  */
13642 static VALUE
13643 argf_seek_m(int argc, VALUE *argv, VALUE argf)
13644 {
13645  if (!next_argv()) {
13646  rb_raise(rb_eArgError, "no stream to seek");
13647  }
13648  ARGF_FORWARD(argc, argv);
13649  return rb_io_seek_m(argc, argv, ARGF.current_file);
13650 }
13651 
13652 /*
13653  * call-seq:
13654  * ARGF.pos = position -> Integer
13655  *
13656  * Seeks to the position given by _position_ (in bytes) in ARGF.
13657  *
13658  * For example:
13659  *
13660  * ARGF.pos = 17
13661  * ARGF.gets #=> "This is line two\n"
13662  */
13663 static VALUE
13664 argf_set_pos(VALUE argf, VALUE offset)
13665 {
13666  if (!next_argv()) {
13667  rb_raise(rb_eArgError, "no stream to set position");
13668  }
13669  ARGF_FORWARD(1, &offset);
13670  return rb_io_set_pos(ARGF.current_file, offset);
13671 }
13672 
13673 /*
13674  * call-seq:
13675  * ARGF.rewind -> 0
13676  *
13677  * Positions the current file to the beginning of input, resetting
13678  * ARGF.lineno to zero.
13679  *
13680  * ARGF.readline #=> "This is line one\n"
13681  * ARGF.rewind #=> 0
13682  * ARGF.lineno #=> 0
13683  * ARGF.readline #=> "This is line one\n"
13684  */
13685 static VALUE
13686 argf_rewind(VALUE argf)
13687 {
13688  VALUE ret;
13689  int old_lineno;
13690 
13691  if (!next_argv()) {
13692  rb_raise(rb_eArgError, "no stream to rewind");
13693  }
13694  ARGF_FORWARD(0, 0);
13695  old_lineno = RFILE(ARGF.current_file)->fptr->lineno;
13696  ret = rb_io_rewind(ARGF.current_file);
13697  if (!global_argf_p(argf)) {
13698  ARGF.last_lineno = ARGF.lineno -= old_lineno;
13699  }
13700  return ret;
13701 }
13702 
13703 /*
13704  * call-seq:
13705  * ARGF.fileno -> integer
13706  * ARGF.to_i -> integer
13707  *
13708  * Returns an integer representing the numeric file descriptor for
13709  * the current file. Raises an ArgumentError if there isn't a current file.
13710  *
13711  * ARGF.fileno #=> 3
13712  */
13713 static VALUE
13714 argf_fileno(VALUE argf)
13715 {
13716  if (!next_argv()) {
13717  rb_raise(rb_eArgError, "no stream");
13718  }
13719  ARGF_FORWARD(0, 0);
13720  return rb_io_fileno(ARGF.current_file);
13721 }
13722 
13723 /*
13724  * call-seq:
13725  * ARGF.to_io -> IO
13726  *
13727  * Returns an IO object representing the current file. This will be a
13728  * File object unless the current file is a stream such as STDIN.
13729  *
13730  * For example:
13731  *
13732  * ARGF.to_io #=> #<File:glark.txt>
13733  * ARGF.to_io #=> #<IO:<STDIN>>
13734  */
13735 static VALUE
13736 argf_to_io(VALUE argf)
13737 {
13738  next_argv();
13739  ARGF_FORWARD(0, 0);
13740  return ARGF.current_file;
13741 }
13742 
13743 /*
13744  * call-seq:
13745  * ARGF.eof? -> true or false
13746  * ARGF.eof -> true or false
13747  *
13748  * Returns true if the current file in ARGF is at end of file, i.e. it has
13749  * no data to read. The stream must be opened for reading or an IOError
13750  * will be raised.
13751  *
13752  * $ echo "eof" | ruby argf.rb
13753  *
13754  * ARGF.eof? #=> false
13755  * 3.times { ARGF.readchar }
13756  * ARGF.eof? #=> false
13757  * ARGF.readchar #=> "\n"
13758  * ARGF.eof? #=> true
13759  */
13760 
13761 static VALUE
13762 argf_eof(VALUE argf)
13763 {
13764  next_argv();
13765  if (RTEST(ARGF.current_file)) {
13766  if (ARGF.init_p == 0) return Qtrue;
13767  next_argv();
13768  ARGF_FORWARD(0, 0);
13769  if (rb_io_eof(ARGF.current_file)) {
13770  return Qtrue;
13771  }
13772  }
13773  return Qfalse;
13774 }
13775 
13776 /*
13777  * call-seq:
13778  * ARGF.read([length [, outbuf]]) -> string, outbuf, or nil
13779  *
13780  * Reads _length_ bytes from ARGF. The files named on the command line
13781  * are concatenated and treated as a single file by this method, so when
13782  * called without arguments the contents of this pseudo file are returned in
13783  * their entirety.
13784  *
13785  * _length_ must be a non-negative integer or +nil+.
13786  *
13787  * If _length_ is a positive integer, +read+ tries to read
13788  * _length_ bytes without any conversion (binary mode).
13789  * It returns +nil+ if an EOF is encountered before anything can be read.
13790  * Fewer than _length_ bytes are returned if an EOF is encountered during
13791  * the read.
13792  * In the case of an integer _length_, the resulting string is always
13793  * in ASCII-8BIT encoding.
13794  *
13795  * If _length_ is omitted or is +nil+, it reads until EOF
13796  * and the encoding conversion is applied, if applicable.
13797  * A string is returned even if EOF is encountered before any data is read.
13798  *
13799  * If _length_ is zero, it returns an empty string (<code>""</code>).
13800  *
13801  * If the optional _outbuf_ argument is present,
13802  * it must reference a String, which will receive the data.
13803  * The _outbuf_ will contain only the received data after the method call
13804  * even if it is not empty at the beginning.
13805  *
13806  * For example:
13807  *
13808  * $ echo "small" > small.txt
13809  * $ echo "large" > large.txt
13810  * $ ./glark.rb small.txt large.txt
13811  *
13812  * ARGF.read #=> "small\nlarge"
13813  * ARGF.read(200) #=> "small\nlarge"
13814  * ARGF.read(2) #=> "sm"
13815  * ARGF.read(0) #=> ""
13816  *
13817  * Note that this method behaves like the fread() function in C.
13818  * This means it retries to invoke read(2) system calls to read data
13819  * with the specified length.
13820  * If you need the behavior like a single read(2) system call,
13821  * consider ARGF#readpartial or ARGF#read_nonblock.
13822  */
13823 
13824 static VALUE
13825 argf_read(int argc, VALUE *argv, VALUE argf)
13826 {
13827  VALUE tmp, str, length;
13828  long len = 0;
13829 
13830  rb_scan_args(argc, argv, "02", &length, &str);
13831  if (!NIL_P(length)) {
13832  len = NUM2LONG(argv[0]);
13833  }
13834  if (!NIL_P(str)) {
13835  StringValue(str);
13836  rb_str_resize(str,0);
13837  argv[1] = Qnil;
13838  }
13839 
13840  retry:
13841  if (!next_argv()) {
13842  return str;
13843  }
13844  if (ARGF_GENERIC_INPUT_P()) {
13845  tmp = argf_forward(argc, argv, argf);
13846  }
13847  else {
13848  tmp = io_read(argc, argv, ARGF.current_file);
13849  }
13850  if (NIL_P(str)) str = tmp;
13851  else if (!NIL_P(tmp)) rb_str_append(str, tmp);
13852  if (NIL_P(tmp) || NIL_P(length)) {
13853  if (ARGF.next_p != -1) {
13854  argf_close(argf);
13855  ARGF.next_p = 1;
13856  goto retry;
13857  }
13858  }
13859  else if (argc >= 1) {
13860  long slen = RSTRING_LEN(str);
13861  if (slen < len) {
13862  argv[0] = LONG2NUM(len - slen);
13863  goto retry;
13864  }
13865  }
13866  return str;
13867 }
13868 
13870  int argc;
13871  VALUE *argv;
13872  VALUE argf;
13873 };
13874 
13875 static VALUE
13876 argf_forward_call(VALUE arg)
13877 {
13878  struct argf_call_arg *p = (struct argf_call_arg *)arg;
13879  argf_forward(p->argc, p->argv, p->argf);
13880  return Qnil;
13881 }
13882 
13883 static VALUE argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts,
13884  int nonblock);
13885 
13886 /*
13887  * call-seq:
13888  * ARGF.readpartial(maxlen) -> string
13889  * ARGF.readpartial(maxlen, outbuf) -> outbuf
13890  *
13891  * Reads at most _maxlen_ bytes from the ARGF stream.
13892  *
13893  * If the optional _outbuf_ argument is present,
13894  * it must reference a String, which will receive the data.
13895  * The _outbuf_ will contain only the received data after the method call
13896  * even if it is not empty at the beginning.
13897  *
13898  * It raises EOFError on end of ARGF stream.
13899  * Since ARGF stream is a concatenation of multiple files,
13900  * internally EOF is occur for each file.
13901  * ARGF.readpartial returns empty strings for EOFs except the last one and
13902  * raises EOFError for the last one.
13903  *
13904  */
13905 
13906 static VALUE
13907 argf_readpartial(int argc, VALUE *argv, VALUE argf)
13908 {
13909  return argf_getpartial(argc, argv, argf, Qnil, 0);
13910 }
13911 
13912 /*
13913  * call-seq:
13914  * ARGF.read_nonblock(maxlen[, options]) -> string
13915  * ARGF.read_nonblock(maxlen, outbuf[, options]) -> outbuf
13916  *
13917  * Reads at most _maxlen_ bytes from the ARGF stream in non-blocking mode.
13918  */
13919 
13920 static VALUE
13921 argf_read_nonblock(int argc, VALUE *argv, VALUE argf)
13922 {
13923  VALUE opts;
13924 
13925  rb_scan_args(argc, argv, "11:", NULL, NULL, &opts);
13926 
13927  if (!NIL_P(opts))
13928  argc--;
13929 
13930  return argf_getpartial(argc, argv, argf, opts, 1);
13931 }
13932 
13933 static VALUE
13934 argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts, int nonblock)
13935 {
13936  VALUE tmp, str, length;
13937  int no_exception;
13938 
13939  rb_scan_args(argc, argv, "11", &length, &str);
13940  if (!NIL_P(str)) {
13941  StringValue(str);
13942  argv[1] = str;
13943  }
13944  no_exception = no_exception_p(opts);
13945 
13946  if (!next_argv()) {
13947  if (!NIL_P(str)) {
13948  rb_str_resize(str, 0);
13949  }
13950  rb_eof_error();
13951  }
13952  if (ARGF_GENERIC_INPUT_P()) {
13953  VALUE (*const rescue_does_nothing)(VALUE, VALUE) = 0;
13954  struct argf_call_arg arg;
13955  arg.argc = argc;
13956  arg.argv = argv;
13957  arg.argf = argf;
13958  tmp = rb_rescue2(argf_forward_call, (VALUE)&arg,
13959  rescue_does_nothing, Qnil, rb_eEOFError, (VALUE)0);
13960  }
13961  else {
13962  tmp = io_getpartial(argc, argv, ARGF.current_file, no_exception, nonblock);
13963  }
13964  if (NIL_P(tmp)) {
13965  if (ARGF.next_p == -1) {
13966  return io_nonblock_eof(no_exception);
13967  }
13968  argf_close(argf);
13969  ARGF.next_p = 1;
13970  if (RARRAY_LEN(ARGF.argv) == 0) {
13971  return io_nonblock_eof(no_exception);
13972  }
13973  if (NIL_P(str))
13974  str = rb_str_new(NULL, 0);
13975  return str;
13976  }
13977  return tmp;
13978 }
13979 
13980 /*
13981  * call-seq:
13982  * ARGF.getc -> String or nil
13983  *
13984  * Reads the next character from ARGF and returns it as a String. Returns
13985  * +nil+ at the end of the stream.
13986  *
13987  * ARGF treats the files named on the command line as a single file created
13988  * by concatenating their contents. After returning the last character of the
13989  * first file, it returns the first character of the second file, and so on.
13990  *
13991  * For example:
13992  *
13993  * $ echo "foo" > file
13994  * $ ruby argf.rb file
13995  *
13996  * ARGF.getc #=> "f"
13997  * ARGF.getc #=> "o"
13998  * ARGF.getc #=> "o"
13999  * ARGF.getc #=> "\n"
14000  * ARGF.getc #=> nil
14001  * ARGF.getc #=> nil
14002  */
14003 static VALUE
14004 argf_getc(VALUE argf)
14005 {
14006  VALUE ch;
14007 
14008  retry:
14009  if (!next_argv()) return Qnil;
14010  if (ARGF_GENERIC_INPUT_P()) {
14011  ch = forward_current(rb_intern("getc"), 0, 0);
14012  }
14013  else {
14014  ch = rb_io_getc(ARGF.current_file);
14015  }
14016  if (NIL_P(ch) && ARGF.next_p != -1) {
14017  argf_close(argf);
14018  ARGF.next_p = 1;
14019  goto retry;
14020  }
14021 
14022  return ch;
14023 }
14024 
14025 /*
14026  * call-seq:
14027  * ARGF.getbyte -> Integer or nil
14028  *
14029  * Gets the next 8-bit byte (0..255) from ARGF. Returns +nil+ if called at
14030  * the end of the stream.
14031  *
14032  * For example:
14033  *
14034  * $ echo "foo" > file
14035  * $ ruby argf.rb file
14036  *
14037  * ARGF.getbyte #=> 102
14038  * ARGF.getbyte #=> 111
14039  * ARGF.getbyte #=> 111
14040  * ARGF.getbyte #=> 10
14041  * ARGF.getbyte #=> nil
14042  */
14043 static VALUE
14044 argf_getbyte(VALUE argf)
14045 {
14046  VALUE ch;
14047 
14048  retry:
14049  if (!next_argv()) return Qnil;
14050  if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
14051  ch = forward_current(rb_intern("getbyte"), 0, 0);
14052  }
14053  else {
14054  ch = rb_io_getbyte(ARGF.current_file);
14055  }
14056  if (NIL_P(ch) && ARGF.next_p != -1) {
14057  argf_close(argf);
14058  ARGF.next_p = 1;
14059  goto retry;
14060  }
14061 
14062  return ch;
14063 }
14064 
14065 /*
14066  * call-seq:
14067  * ARGF.readchar -> String or nil
14068  *
14069  * Reads the next character from ARGF and returns it as a String. Raises
14070  * an EOFError after the last character of the last file has been read.
14071  *
14072  * For example:
14073  *
14074  * $ echo "foo" > file
14075  * $ ruby argf.rb file
14076  *
14077  * ARGF.readchar #=> "f"
14078  * ARGF.readchar #=> "o"
14079  * ARGF.readchar #=> "o"
14080  * ARGF.readchar #=> "\n"
14081  * ARGF.readchar #=> end of file reached (EOFError)
14082  */
14083 static VALUE
14084 argf_readchar(VALUE argf)
14085 {
14086  VALUE ch;
14087 
14088  retry:
14089  if (!next_argv()) rb_eof_error();
14090  if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
14091  ch = forward_current(rb_intern("getc"), 0, 0);
14092  }
14093  else {
14094  ch = rb_io_getc(ARGF.current_file);
14095  }
14096  if (NIL_P(ch) && ARGF.next_p != -1) {
14097  argf_close(argf);
14098  ARGF.next_p = 1;
14099  goto retry;
14100  }
14101 
14102  return ch;
14103 }
14104 
14105 /*
14106  * call-seq:
14107  * ARGF.readbyte -> Integer
14108  *
14109  * Reads the next 8-bit byte from ARGF and returns it as an Integer. Raises
14110  * an EOFError after the last byte of the last file has been read.
14111  *
14112  * For example:
14113  *
14114  * $ echo "foo" > file
14115  * $ ruby argf.rb file
14116  *
14117  * ARGF.readbyte #=> 102
14118  * ARGF.readbyte #=> 111
14119  * ARGF.readbyte #=> 111
14120  * ARGF.readbyte #=> 10
14121  * ARGF.readbyte #=> end of file reached (EOFError)
14122  */
14123 static VALUE
14124 argf_readbyte(VALUE argf)
14125 {
14126  VALUE c;
14127 
14128  NEXT_ARGF_FORWARD(0, 0);
14129  c = argf_getbyte(argf);
14130  if (NIL_P(c)) {
14131  rb_eof_error();
14132  }
14133  return c;
14134 }
14135 
14136 #define FOREACH_ARGF() while (next_argv())
14137 
14138 static VALUE
14139 argf_block_call_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
14140 {
14141  const VALUE current = ARGF.current_file;
14142  rb_yield_values2(argc, argv);
14143  if (ARGF.init_p == -1 || current != ARGF.current_file) {
14145  }
14146  return Qnil;
14147 }
14148 
14149 #define ARGF_block_call(mid, argc, argv, func, argf) \
14150  rb_block_call_kw(ARGF.current_file, mid, argc, argv, \
14151  func, argf, rb_keyword_given_p())
14152 
14153 static void
14154 argf_block_call(ID mid, int argc, VALUE *argv, VALUE argf)
14155 {
14156  VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_i, argf);
14157  if (!UNDEF_P(ret)) ARGF.next_p = 1;
14158 }
14159 
14160 static VALUE
14161 argf_block_call_line_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
14162 {
14163  if (!global_argf_p(argf)) {
14164  ARGF.last_lineno = ++ARGF.lineno;
14165  }
14166  return argf_block_call_i(i, argf, argc, argv, blockarg);
14167 }
14168 
14169 static void
14170 argf_block_call_line(ID mid, int argc, VALUE *argv, VALUE argf)
14171 {
14172  VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_line_i, argf);
14173  if (!UNDEF_P(ret)) ARGF.next_p = 1;
14174 }
14175 
14176 /*
14177  * call-seq:
14178  * ARGF.each(sep=$/) {|line| block } -> ARGF
14179  * ARGF.each(sep=$/, limit) {|line| block } -> ARGF
14180  * ARGF.each(...) -> an_enumerator
14181  *
14182  * ARGF.each_line(sep=$/) {|line| block } -> ARGF
14183  * ARGF.each_line(sep=$/, limit) {|line| block } -> ARGF
14184  * ARGF.each_line(...) -> an_enumerator
14185  *
14186  * Returns an enumerator which iterates over each line (separated by _sep_,
14187  * which defaults to your platform's newline character) of each file in
14188  * +ARGV+. If a block is supplied, each line in turn will be yielded to the
14189  * block, otherwise an enumerator is returned.
14190  * The optional _limit_ argument is an Integer specifying the maximum
14191  * length of each line; longer lines will be split according to this limit.
14192  *
14193  * This method allows you to treat the files supplied on the command line as
14194  * a single file consisting of the concatenation of each named file. After
14195  * the last line of the first file has been returned, the first line of the
14196  * second file is returned. The ARGF.filename and ARGF.lineno methods can be
14197  * used to determine the filename of the current line and line number of the
14198  * whole input, respectively.
14199  *
14200  * For example, the following code prints out each line of each named file
14201  * prefixed with its line number, displaying the filename once per file:
14202  *
14203  * ARGF.each_line do |line|
14204  * puts ARGF.filename if ARGF.file.lineno == 1
14205  * puts "#{ARGF.file.lineno}: #{line}"
14206  * end
14207  *
14208  * While the following code prints only the first file's name at first, and
14209  * the contents with line number counted through all named files.
14210  *
14211  * ARGF.each_line do |line|
14212  * puts ARGF.filename if ARGF.lineno == 1
14213  * puts "#{ARGF.lineno}: #{line}"
14214  * end
14215  */
14216 static VALUE
14217 argf_each_line(int argc, VALUE *argv, VALUE argf)
14218 {
14219  RETURN_ENUMERATOR(argf, argc, argv);
14220  FOREACH_ARGF() {
14221  argf_block_call_line(rb_intern("each_line"), argc, argv, argf);
14222  }
14223  return argf;
14224 }
14225 
14226 /*
14227  * call-seq:
14228  * ARGF.each_byte {|byte| block } -> ARGF
14229  * ARGF.each_byte -> an_enumerator
14230  *
14231  * Iterates over each byte of each file in +ARGV+.
14232  * A byte is returned as an Integer in the range 0..255.
14233  *
14234  * This method allows you to treat the files supplied on the command line as
14235  * a single file consisting of the concatenation of each named file. After
14236  * the last byte of the first file has been returned, the first byte of the
14237  * second file is returned. The ARGF.filename method can be used to
14238  * determine the filename of the current byte.
14239  *
14240  * If no block is given, an enumerator is returned instead.
14241  *
14242  * For example:
14243  *
14244  * ARGF.bytes.to_a #=> [35, 32, ... 95, 10]
14245  *
14246  */
14247 static VALUE
14248 argf_each_byte(VALUE argf)
14249 {
14250  RETURN_ENUMERATOR(argf, 0, 0);
14251  FOREACH_ARGF() {
14252  argf_block_call(rb_intern("each_byte"), 0, 0, argf);
14253  }
14254  return argf;
14255 }
14256 
14257 /*
14258  * call-seq:
14259  * ARGF.each_char {|char| block } -> ARGF
14260  * ARGF.each_char -> an_enumerator
14261  *
14262  * Iterates over each character of each file in ARGF.
14263  *
14264  * This method allows you to treat the files supplied on the command line as
14265  * a single file consisting of the concatenation of each named file. After
14266  * the last character of the first file has been returned, the first
14267  * character of the second file is returned. The ARGF.filename method can
14268  * be used to determine the name of the file in which the current character
14269  * appears.
14270  *
14271  * If no block is given, an enumerator is returned instead.
14272  */
14273 static VALUE
14274 argf_each_char(VALUE argf)
14275 {
14276  RETURN_ENUMERATOR(argf, 0, 0);
14277  FOREACH_ARGF() {
14278  argf_block_call(rb_intern("each_char"), 0, 0, argf);
14279  }
14280  return argf;
14281 }
14282 
14283 /*
14284  * call-seq:
14285  * ARGF.each_codepoint {|codepoint| block } -> ARGF
14286  * ARGF.each_codepoint -> an_enumerator
14287  *
14288  * Iterates over each codepoint of each file in ARGF.
14289  *
14290  * This method allows you to treat the files supplied on the command line as
14291  * a single file consisting of the concatenation of each named file. After
14292  * the last codepoint of the first file has been returned, the first
14293  * codepoint of the second file is returned. The ARGF.filename method can
14294  * be used to determine the name of the file in which the current codepoint
14295  * appears.
14296  *
14297  * If no block is given, an enumerator is returned instead.
14298  */
14299 static VALUE
14300 argf_each_codepoint(VALUE argf)
14301 {
14302  RETURN_ENUMERATOR(argf, 0, 0);
14303  FOREACH_ARGF() {
14304  argf_block_call(rb_intern("each_codepoint"), 0, 0, argf);
14305  }
14306  return argf;
14307 }
14308 
14309 /*
14310  * call-seq:
14311  * ARGF.filename -> String
14312  * ARGF.path -> String
14313  *
14314  * Returns the current filename. "-" is returned when the current file is
14315  * STDIN.
14316  *
14317  * For example:
14318  *
14319  * $ echo "foo" > foo
14320  * $ echo "bar" > bar
14321  * $ echo "glark" > glark
14322  *
14323  * $ ruby argf.rb foo bar glark
14324  *
14325  * ARGF.filename #=> "foo"
14326  * ARGF.read(5) #=> "foo\nb"
14327  * ARGF.filename #=> "bar"
14328  * ARGF.skip
14329  * ARGF.filename #=> "glark"
14330  */
14331 static VALUE
14332 argf_filename(VALUE argf)
14333 {
14334  next_argv();
14335  return ARGF.filename;
14336 }
14337 
14338 static VALUE
14339 argf_filename_getter(ID id, VALUE *var)
14340 {
14341  return argf_filename(*var);
14342 }
14343 
14344 /*
14345  * call-seq:
14346  * ARGF.file -> IO or File object
14347  *
14348  * Returns the current file as an IO or File object.
14349  * <code>$stdin</code> is returned when the current file is STDIN.
14350  *
14351  * For example:
14352  *
14353  * $ echo "foo" > foo
14354  * $ echo "bar" > bar
14355  *
14356  * $ ruby argf.rb foo bar
14357  *
14358  * ARGF.file #=> #<File:foo>
14359  * ARGF.read(5) #=> "foo\nb"
14360  * ARGF.file #=> #<File:bar>
14361  */
14362 static VALUE
14363 argf_file(VALUE argf)
14364 {
14365  next_argv();
14366  return ARGF.current_file;
14367 }
14368 
14369 /*
14370  * call-seq:
14371  * ARGF.binmode -> ARGF
14372  *
14373  * Puts ARGF into binary mode. Once a stream is in binary mode, it cannot
14374  * be reset to non-binary mode. This option has the following effects:
14375  *
14376  * * Newline conversion is disabled.
14377  * * Encoding conversion is disabled.
14378  * * Content is treated as ASCII-8BIT.
14379  */
14380 static VALUE
14381 argf_binmode_m(VALUE argf)
14382 {
14383  ARGF.binmode = 1;
14384  next_argv();
14385  ARGF_FORWARD(0, 0);
14386  rb_io_ascii8bit_binmode(ARGF.current_file);
14387  return argf;
14388 }
14389 
14390 /*
14391  * call-seq:
14392  * ARGF.binmode? -> true or false
14393  *
14394  * Returns true if ARGF is being read in binary mode; false otherwise.
14395  * To enable binary mode use ARGF.binmode.
14396  *
14397  * For example:
14398  *
14399  * ARGF.binmode? #=> false
14400  * ARGF.binmode
14401  * ARGF.binmode? #=> true
14402  */
14403 static VALUE
14404 argf_binmode_p(VALUE argf)
14405 {
14406  return RBOOL(ARGF.binmode);
14407 }
14408 
14409 /*
14410  * call-seq:
14411  * ARGF.skip -> ARGF
14412  *
14413  * Sets the current file to the next file in ARGV. If there aren't any more
14414  * files it has no effect.
14415  *
14416  * For example:
14417  *
14418  * $ ruby argf.rb foo bar
14419  * ARGF.filename #=> "foo"
14420  * ARGF.skip
14421  * ARGF.filename #=> "bar"
14422  */
14423 static VALUE
14424 argf_skip(VALUE argf)
14425 {
14426  if (ARGF.init_p && ARGF.next_p == 0) {
14427  argf_close(argf);
14428  ARGF.next_p = 1;
14429  }
14430  return argf;
14431 }
14432 
14433 /*
14434  * call-seq:
14435  * ARGF.close -> ARGF
14436  *
14437  * Closes the current file and skips to the next file in ARGV. If there are
14438  * no more files to open, just closes the current file. STDIN will not be
14439  * closed.
14440  *
14441  * For example:
14442  *
14443  * $ ruby argf.rb foo bar
14444  *
14445  * ARGF.filename #=> "foo"
14446  * ARGF.close
14447  * ARGF.filename #=> "bar"
14448  * ARGF.close
14449  */
14450 static VALUE
14451 argf_close_m(VALUE argf)
14452 {
14453  next_argv();
14454  argf_close(argf);
14455  if (ARGF.next_p != -1) {
14456  ARGF.next_p = 1;
14457  }
14458  ARGF.lineno = 0;
14459  return argf;
14460 }
14461 
14462 /*
14463  * call-seq:
14464  * ARGF.closed? -> true or false
14465  *
14466  * Returns _true_ if the current file has been closed; _false_ otherwise. Use
14467  * ARGF.close to actually close the current file.
14468  */
14469 static VALUE
14470 argf_closed(VALUE argf)
14471 {
14472  next_argv();
14473  ARGF_FORWARD(0, 0);
14474  return rb_io_closed_p(ARGF.current_file);
14475 }
14476 
14477 /*
14478  * call-seq:
14479  * ARGF.to_s -> String
14480  *
14481  * Returns "ARGF".
14482  */
14483 static VALUE
14484 argf_to_s(VALUE argf)
14485 {
14486  return rb_str_new2("ARGF");
14487 }
14488 
14489 /*
14490  * call-seq:
14491  * ARGF.inplace_mode -> String
14492  *
14493  * Returns the file extension appended to the names of backup copies of
14494  * modified files under in-place edit mode. This value can be set using
14495  * ARGF.inplace_mode= or passing the +-i+ switch to the Ruby binary.
14496  */
14497 static VALUE
14498 argf_inplace_mode_get(VALUE argf)
14499 {
14500  if (!ARGF.inplace) return Qnil;
14501  if (NIL_P(ARGF.inplace)) return rb_str_new(0, 0);
14502  return rb_str_dup(ARGF.inplace);
14503 }
14504 
14505 static VALUE
14506 opt_i_get(ID id, VALUE *var)
14507 {
14508  return argf_inplace_mode_get(*var);
14509 }
14510 
14511 /*
14512  * call-seq:
14513  * ARGF.inplace_mode = ext -> ARGF
14514  *
14515  * Sets the filename extension for in-place editing mode to the given String.
14516  * The backup copy of each file being edited has this value appended to its
14517  * filename.
14518  *
14519  * For example:
14520  *
14521  * $ ruby argf.rb file.txt
14522  *
14523  * ARGF.inplace_mode = '.bak'
14524  * ARGF.each_line do |line|
14525  * print line.sub("foo","bar")
14526  * end
14527  *
14528  * First, _file.txt.bak_ is created as a backup copy of _file.txt_.
14529  * Then, each line of _file.txt_ has the first occurrence of "foo" replaced with
14530  * "bar".
14531  */
14532 static VALUE
14533 argf_inplace_mode_set(VALUE argf, VALUE val)
14534 {
14535  if (!RTEST(val)) {
14536  ARGF.inplace = Qfalse;
14537  }
14538  else if (StringValueCStr(val), !RSTRING_LEN(val)) {
14539  ARGF.inplace = Qnil;
14540  }
14541  else {
14542  ARGF.inplace = rb_str_new_frozen(val);
14543  }
14544  return argf;
14545 }
14546 
14547 static void
14548 opt_i_set(VALUE val, ID id, VALUE *var)
14549 {
14550  argf_inplace_mode_set(*var, val);
14551 }
14552 
14553 void
14554 ruby_set_inplace_mode(const char *suffix)
14555 {
14556  ARGF.inplace = !suffix ? Qfalse : !*suffix ? Qnil : rb_str_new(suffix, strlen(suffix));
14557 }
14558 
14559 /*
14560  * call-seq:
14561  * ARGF.argv -> ARGV
14562  *
14563  * Returns the +ARGV+ array, which contains the arguments passed to your
14564  * script, one per element.
14565  *
14566  * For example:
14567  *
14568  * $ ruby argf.rb -v glark.txt
14569  *
14570  * ARGF.argv #=> ["-v", "glark.txt"]
14571  *
14572  */
14573 static VALUE
14574 argf_argv(VALUE argf)
14575 {
14576  return ARGF.argv;
14577 }
14578 
14579 static VALUE
14580 argf_argv_getter(ID id, VALUE *var)
14581 {
14582  return argf_argv(*var);
14583 }
14584 
14585 VALUE
14587 {
14588  return ARGF.argv;
14589 }
14590 
14591 /*
14592  * call-seq:
14593  * ARGF.to_write_io -> io
14594  *
14595  * Returns IO instance tied to _ARGF_ for writing if inplace mode is
14596  * enabled.
14597  */
14598 static VALUE
14599 argf_write_io(VALUE argf)
14600 {
14601  if (!RTEST(ARGF.current_file)) {
14602  rb_raise(rb_eIOError, "not opened for writing");
14603  }
14604  return GetWriteIO(ARGF.current_file);
14605 }
14606 
14607 /*
14608  * call-seq:
14609  * ARGF.write(*objects) -> integer
14610  *
14611  * Writes each of the given +objects+ if inplace mode.
14612  */
14613 static VALUE
14614 argf_write(int argc, VALUE *argv, VALUE argf)
14615 {
14616  return rb_io_writev(argf_write_io(argf), argc, argv);
14617 }
14618 
14619 void
14620 rb_readwrite_sys_fail(enum rb_io_wait_readwrite waiting, const char *mesg)
14621 {
14622  rb_readwrite_syserr_fail(waiting, errno, mesg);
14623 }
14624 
14625 void
14626 rb_readwrite_syserr_fail(enum rb_io_wait_readwrite waiting, int n, const char *mesg)
14627 {
14628  VALUE arg, c = Qnil;
14629  arg = mesg ? rb_str_new2(mesg) : Qnil;
14630  switch (waiting) {
14631  case RB_IO_WAIT_WRITABLE:
14632  switch (n) {
14633  case EAGAIN:
14634  c = rb_eEAGAINWaitWritable;
14635  break;
14636 #if EAGAIN != EWOULDBLOCK
14637  case EWOULDBLOCK:
14638  c = rb_eEWOULDBLOCKWaitWritable;
14639  break;
14640 #endif
14641  case EINPROGRESS:
14642  c = rb_eEINPROGRESSWaitWritable;
14643  break;
14644  default:
14646  }
14647  break;
14648  case RB_IO_WAIT_READABLE:
14649  switch (n) {
14650  case EAGAIN:
14651  c = rb_eEAGAINWaitReadable;
14652  break;
14653 #if EAGAIN != EWOULDBLOCK
14654  case EWOULDBLOCK:
14655  c = rb_eEWOULDBLOCKWaitReadable;
14656  break;
14657 #endif
14658  case EINPROGRESS:
14659  c = rb_eEINPROGRESSWaitReadable;
14660  break;
14661  default:
14663  }
14664  break;
14665  default:
14666  rb_bug("invalid read/write type passed to rb_readwrite_sys_fail: %d", waiting);
14667  }
14668  rb_exc_raise(rb_class_new_instance(1, &arg, c));
14669 }
14670 
14671 static VALUE
14672 get_LAST_READ_LINE(ID _x, VALUE *_y)
14673 {
14674  return rb_lastline_get();
14675 }
14676 
14677 static void
14678 set_LAST_READ_LINE(VALUE val, ID _x, VALUE *_y)
14679 {
14680  rb_lastline_set(val);
14681 }
14682 
14683 /*
14684  * Document-class: IOError
14685  *
14686  * Raised when an IO operation fails.
14687  *
14688  * File.open("/etc/hosts") {|f| f << "example"}
14689  * #=> IOError: not opened for writing
14690  *
14691  * File.open("/etc/hosts") {|f| f.close; f.read }
14692  * #=> IOError: closed stream
14693  *
14694  * Note that some IO failures raise <code>SystemCallError</code>s
14695  * and these are not subclasses of IOError:
14696  *
14697  * File.open("does/not/exist")
14698  * #=> Errno::ENOENT: No such file or directory - does/not/exist
14699  */
14700 
14701 /*
14702  * Document-class: EOFError
14703  *
14704  * Raised by some IO operations when reaching the end of file. Many IO
14705  * methods exist in two forms,
14706  *
14707  * one that returns +nil+ when the end of file is reached, the other
14708  * raises EOFError.
14709  *
14710  * EOFError is a subclass of IOError.
14711  *
14712  * file = File.open("/etc/hosts")
14713  * file.read
14714  * file.gets #=> nil
14715  * file.readline #=> EOFError: end of file reached
14716  * file.close
14717  */
14718 
14719 /*
14720  * Document-class: ARGF
14721  *
14722  * == \ARGF and +ARGV+
14723  *
14724  * The \ARGF object works with the array at global variable +ARGV+
14725  * to make <tt>$stdin</tt> and file streams available in the Ruby program:
14726  *
14727  * - **ARGV** may be thought of as the <b>argument vector</b> array.
14728  *
14729  * Initially, it contains the command-line arguments and options
14730  * that are passed to the Ruby program;
14731  * the program can modify that array as it likes.
14732  *
14733  * - **ARGF** may be thought of as the <b>argument files</b> object.
14734  *
14735  * It can access file streams and/or the <tt>$stdin</tt> stream,
14736  * based on what it finds in +ARGV+.
14737  * This provides a convenient way for the command line
14738  * to specify streams for a Ruby program to read.
14739  *
14740  * == Reading
14741  *
14742  * \ARGF may read from _source_ streams,
14743  * which at any particular time are determined by the content of +ARGV+.
14744  *
14745  * === Simplest Case
14746  *
14747  * When the <i>very first</i> \ARGF read occurs with an empty +ARGV+ (<tt>[]</tt>),
14748  * the source is <tt>$stdin</tt>:
14749  *
14750  * - \File +t.rb+:
14751  *
14752  * p ['ARGV', ARGV]
14753  * p ['ARGF.read', ARGF.read]
14754  *
14755  * - Commands and outputs
14756  * (see below for the content of files +foo.txt+ and +bar.txt+):
14757  *
14758  * $ echo "Open the pod bay doors, Hal." | ruby t.rb
14759  * ["ARGV", []]
14760  * ["ARGF.read", "Open the pod bay doors, Hal.\n"]
14761  *
14762  * $ cat foo.txt bar.txt | ruby t.rb
14763  * ["ARGV", []]
14764  * ["ARGF.read", "Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"]
14765  *
14766  * === About the Examples
14767  *
14768  * Many examples here assume the existence of files +foo.txt+ and +bar.txt+:
14769  *
14770  * $ cat foo.txt
14771  * Foo 0
14772  * Foo 1
14773  * $ cat bar.txt
14774  * Bar 0
14775  * Bar 1
14776  * Bar 2
14777  * Bar 3
14778  *
14779  * === Sources in +ARGV+
14780  *
14781  * For any \ARGF read _except_ the {simplest case}[rdoc-ref:ARGF@Simplest+Case]
14782  * (that is, _except_ for the <i>very first</i> \ARGF read with an empty +ARGV+),
14783  * the sources are found in +ARGV+.
14784  *
14785  * \ARGF assumes that each element in array +ARGV+ is a potential source,
14786  * and is one of:
14787  *
14788  * - The string path to a file that may be opened as a stream.
14789  * - The character <tt>'-'</tt>, meaning stream <tt>$stdin</tt>.
14790  *
14791  * Each element that is _not_ one of these
14792  * should be removed from +ARGV+ before \ARGF accesses that source.
14793  *
14794  * In the following example:
14795  *
14796  * - Filepaths +foo.txt+ and +bar.txt+ may be retained as potential sources.
14797  * - Options <tt>--xyzzy</tt> and <tt>--mojo</tt> should be removed.
14798  *
14799  * Example:
14800  *
14801  * - \File +t.rb+:
14802  *
14803  * # Print arguments (and options, if any) found on command line.
14804  * p ['ARGV', ARGV]
14805  *
14806  * - Command and output:
14807  *
14808  * $ ruby t.rb --xyzzy --mojo foo.txt bar.txt
14809  * ["ARGV", ["--xyzzy", "--mojo", "foo.txt", "bar.txt"]]
14810  *
14811  * \ARGF's stream access considers the elements of +ARGV+, left to right:
14812  *
14813  * - \File +t.rb+:
14814  *
14815  * p "ARGV: #{ARGV}"
14816  * p "Line: #{ARGF.read}" # Read everything from all specified streams.
14817  *
14818  * - Command and output:
14819  *
14820  * $ ruby t.rb foo.txt bar.txt
14821  * "ARGV: [\"foo.txt\", \"bar.txt\"]"
14822  * "Read: Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"
14823  *
14824  * Because the value at +ARGV+ is an ordinary array,
14825  * you can manipulate it to control which sources \ARGF considers:
14826  *
14827  * - If you remove an element from +ARGV+, \ARGF will not consider the corresponding source.
14828  * - If you add an element to +ARGV+, \ARGF will consider the corresponding source.
14829  *
14830  * Each element in +ARGV+ is removed when its corresponding source is accessed;
14831  * when all sources have been accessed, the array is empty:
14832  *
14833  * - \File +t.rb+:
14834  *
14835  * until ARGV.empty? && ARGF.eof?
14836  * p "ARGV: #{ARGV}"
14837  * p "Line: #{ARGF.readline}" # Read each line from each specified stream.
14838  * end
14839  *
14840  * - Command and output:
14841  *
14842  * $ ruby t.rb foo.txt bar.txt
14843  * "ARGV: [\"foo.txt\", \"bar.txt\"]"
14844  * "Line: Foo 0\n"
14845  * "ARGV: [\"bar.txt\"]"
14846  * "Line: Foo 1\n"
14847  * "ARGV: [\"bar.txt\"]"
14848  * "Line: Bar 0\n"
14849  * "ARGV: []"
14850  * "Line: Bar 1\n"
14851  * "ARGV: []"
14852  * "Line: Bar 2\n"
14853  * "ARGV: []"
14854  * "Line: Bar 3\n"
14855  *
14856  * ==== Filepaths in +ARGV+
14857  *
14858  * The +ARGV+ array may contain filepaths the specify sources for \ARGF reading.
14859  *
14860  * This program prints what it reads from files at the paths specified
14861  * on the command line:
14862  *
14863  * - \File +t.rb+:
14864  *
14865  * p ['ARGV', ARGV]
14866  * # Read and print all content from the specified sources.
14867  * p ['ARGF.read', ARGF.read]
14868  *
14869  * - Command and output:
14870  *
14871  * $ ruby t.rb foo.txt bar.txt
14872  * ["ARGV", [foo.txt, bar.txt]
14873  * ["ARGF.read", "Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"]
14874  *
14875  * ==== Specifying <tt>$stdin</tt> in +ARGV+
14876  *
14877  * To specify stream <tt>$stdin</tt> in +ARGV+, us the character <tt>'-'</tt>:
14878  *
14879  * - \File +t.rb+:
14880  *
14881  * p ['ARGV', ARGV]
14882  * p ['ARGF.read', ARGF.read]
14883  *
14884  * - Command and output:
14885  *
14886  * $ echo "Open the pod bay doors, Hal." | ruby t.rb -
14887  * ["ARGV", ["-"]]
14888  * ["ARGF.read", "Open the pod bay doors, Hal.\n"]
14889  *
14890  * When no character <tt>'-'</tt> is given, stream <tt>$stdin</tt> is ignored
14891  * (exception:
14892  * see {Specifying $stdin in ARGV}[rdoc-ref:ARGF@Specifying+-24stdin+in+ARGV]):
14893  *
14894  * - Command and output:
14895  *
14896  * $ echo "Open the pod bay doors, Hal." | ruby t.rb foo.txt bar.txt
14897  * "ARGV: [\"foo.txt\", \"bar.txt\"]"
14898  * "Read: Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"
14899  *
14900  * ==== Mixtures and Repetitions in +ARGV+
14901  *
14902  * For an \ARGF reader, +ARGV+ may contain any mixture of filepaths
14903  * and character <tt>'-'</tt>, including repetitions.
14904  *
14905  * ==== Modifications to +ARGV+
14906  *
14907  * The running Ruby program may make any modifications to the +ARGV+ array;
14908  * the current value of +ARGV+ affects \ARGF reading.
14909  *
14910  * ==== Empty +ARGV+
14911  *
14912  * For an empty +ARGV+, an \ARGF read method either returns +nil+
14913  * or raises an exception, depending on the specific method.
14914  *
14915  * === More Read Methods
14916  *
14917  * As seen above, method ARGF#read reads the content of all sources
14918  * into a single string.
14919  * Other \ARGF methods provide other ways to access that content;
14920  * these include:
14921  *
14922  * - Byte access: #each_byte, #getbyte, #readbyte.
14923  * - Character access: #each_char, #getc, #readchar.
14924  * - Codepoint access: #each_codepoint.
14925  * - Line access: #each_line, #gets, #readline, #readlines.
14926  * - Source access: #read, #read_nonblock, #readpartial.
14927  *
14928  * === About \Enumerable
14929  *
14930  * \ARGF includes module Enumerable.
14931  * Virtually all methods in \Enumerable call method <tt>#each</tt> in the including class.
14932  *
14933  * <b>Note well</b>: In \ARGF, method #each returns data from the _sources_,
14934  * _not_ from +ARGV+;
14935  * therefore, for example, <tt>ARGF#entries</tt> returns an array of lines from the sources,
14936  * not an array of the strings from +ARGV+:
14937  *
14938  * - \File +t.rb+:
14939  *
14940  * p ['ARGV', ARGV]
14941  * p ['ARGF.entries', ARGF.entries]
14942  *
14943  * - Command and output:
14944  *
14945  * $ ruby t.rb foo.txt bar.txt
14946  * ["ARGV", ["foo.txt", "bar.txt"]]
14947  * ["ARGF.entries", ["Foo 0\n", "Foo 1\n", "Bar 0\n", "Bar 1\n", "Bar 2\n", "Bar 3\n"]]
14948  *
14949  * == Writing
14950  *
14951  * If <i>inplace mode</i> is in effect,
14952  * \ARGF may write to target streams,
14953  * which at any particular time are determined by the content of ARGV.
14954  *
14955  * Methods about inplace mode:
14956  *
14957  * - #inplace_mode
14958  * - #inplace_mode=
14959  * - #to_write_io
14960  *
14961  * Methods for writing:
14962  *
14963  * - #print
14964  * - #printf
14965  * - #putc
14966  * - #puts
14967  * - #write
14968  *
14969  */
14970 
14971 /*
14972  * An instance of class \IO (commonly called a _stream_)
14973  * represents an input/output stream in the underlying operating system.
14974  * \Class \IO is the basis for input and output in Ruby.
14975  *
14976  * \Class File is the only class in the Ruby core that is a subclass of \IO.
14977  * Some classes in the Ruby standard library are also subclasses of \IO;
14978  * these include TCPSocket and UDPSocket.
14979  *
14980  * The global constant ARGF (also accessible as <tt>$<</tt>)
14981  * provides an IO-like stream that allows access to all file paths
14982  * found in ARGV (or found in STDIN if ARGV is empty).
14983  * ARGF is not itself a subclass of \IO.
14984  *
14985  * \Class StringIO provides an IO-like stream that handles a String.
14986  * StringIO is not itself a subclass of \IO.
14987  *
14988  * Important objects based on \IO include:
14989  *
14990  * - $stdin.
14991  * - $stdout.
14992  * - $stderr.
14993  * - Instances of class File.
14994  *
14995  * An instance of \IO may be created using:
14996  *
14997  * - IO.new: returns a new \IO object for the given integer file descriptor.
14998  * - IO.open: passes a new \IO object to the given block.
14999  * - IO.popen: returns a new \IO object that is connected to the $stdin and $stdout
15000  * of a newly-launched subprocess.
15001  * - Kernel#open: Returns a new \IO object connected to a given source:
15002  * stream, file, or subprocess.
15003  *
15004  * Like a File stream, an \IO stream has:
15005  *
15006  * - A read/write mode, which may be read-only, write-only, or read/write;
15007  * see {Read/Write Mode}[rdoc-ref:File@Read-2FWrite+Mode].
15008  * - A data mode, which may be text-only or binary;
15009  * see {Data Mode}[rdoc-ref:File@Data+Mode].
15010  * - Internal and external encodings;
15011  * see {Encodings}[rdoc-ref:File@Encodings].
15012  *
15013  * And like other \IO streams, it has:
15014  *
15015  * - A position, which determines where in the stream the next
15016  * read or write is to occur;
15017  * see {Position}[rdoc-ref:IO@Position].
15018  * - A line number, which is a special, line-oriented, "position"
15019  * (different from the position mentioned above);
15020  * see {Line Number}[rdoc-ref:IO@Line+Number].
15021  *
15022  * == Extension <tt>io/console</tt>
15023  *
15024  * Extension <tt>io/console</tt> provides numerous methods
15025  * for interacting with the console;
15026  * requiring it adds numerous methods to class \IO.
15027  *
15028  * == Example Files
15029  *
15030  * Many examples here use these variables:
15031  *
15032  * :include: doc/examples/files.rdoc
15033  *
15034  * == Open Options
15035  *
15036  * A number of \IO methods accept optional keyword arguments
15037  * that determine how a new stream is to be opened:
15038  *
15039  * - +:mode+: Stream mode.
15040  * - +:flags+: Integer file open flags;
15041  * If +mode+ is also given, the two are bitwise-ORed.
15042  * - +:external_encoding+: External encoding for the stream.
15043  * - +:internal_encoding+: Internal encoding for the stream.
15044  * <tt>'-'</tt> is a synonym for the default internal encoding.
15045  * If the value is +nil+ no conversion occurs.
15046  * - +:encoding+: Specifies external and internal encodings as <tt>'extern:intern'</tt>.
15047  * - +:textmode+: If a truthy value, specifies the mode as text-only, binary otherwise.
15048  * - +:binmode+: If a truthy value, specifies the mode as binary, text-only otherwise.
15049  * - +:autoclose+: If a truthy value, specifies that the +fd+ will close
15050  * when the stream closes; otherwise it remains open.
15051  * - +:path:+ If a string value is provided, it is used in #inspect and is available as
15052  * #path method.
15053  *
15054  * Also available are the options offered in String#encode,
15055  * which may control conversion between external and internal encoding.
15056  *
15057  * == Basic \IO
15058  *
15059  * You can perform basic stream \IO with these methods,
15060  * which typically operate on multi-byte strings:
15061  *
15062  * - IO#read: Reads and returns some or all of the remaining bytes from the stream.
15063  * - IO#write: Writes zero or more strings to the stream;
15064  * each given object that is not already a string is converted via +to_s+.
15065  *
15066  * === Position
15067  *
15068  * An \IO stream has a nonnegative integer _position_,
15069  * which is the byte offset at which the next read or write is to occur.
15070  * A new stream has position zero (and line number zero);
15071  * method +rewind+ resets the position (and line number) to zero.
15072  *
15073  * These methods discard {buffers}[rdoc-ref:IO@Buffering] and the
15074  * Encoding::Converter instances used for that \IO.
15075  *
15076  * The relevant methods:
15077  *
15078  * - IO#tell (aliased as +#pos+): Returns the current position (in bytes) in the stream.
15079  * - IO#pos=: Sets the position of the stream to a given integer +new_position+ (in bytes).
15080  * - IO#seek: Sets the position of the stream to a given integer +offset+ (in bytes),
15081  * relative to a given position +whence+
15082  * (indicating the beginning, end, or current position).
15083  * - IO#rewind: Positions the stream at the beginning (also resetting the line number).
15084  *
15085  * === Open and Closed Streams
15086  *
15087  * A new \IO stream may be open for reading, open for writing, or both.
15088  *
15089  * A stream is automatically closed when claimed by the garbage collector.
15090  *
15091  * Attempted reading or writing on a closed stream raises an exception.
15092  *
15093  * The relevant methods:
15094  *
15095  * - IO#close: Closes the stream for both reading and writing.
15096  * - IO#close_read: Closes the stream for reading.
15097  * - IO#close_write: Closes the stream for writing.
15098  * - IO#closed?: Returns whether the stream is closed.
15099  *
15100  * === End-of-Stream
15101  *
15102  * You can query whether a stream is positioned at its end:
15103  *
15104  * - IO#eof? (also aliased as +#eof+): Returns whether the stream is at end-of-stream.
15105  *
15106  * You can reposition to end-of-stream by using method IO#seek:
15107  *
15108  * f = File.new('t.txt')
15109  * f.eof? # => false
15110  * f.seek(0, :END)
15111  * f.eof? # => true
15112  * f.close
15113  *
15114  * Or by reading all stream content (which is slower than using IO#seek):
15115  *
15116  * f.rewind
15117  * f.eof? # => false
15118  * f.read # => "First line\nSecond line\n\nFourth line\nFifth line\n"
15119  * f.eof? # => true
15120  *
15121  * == Line \IO
15122  *
15123  * \Class \IO supports line-oriented
15124  * {input}[rdoc-ref:IO@Line+Input] and {output}[rdoc-ref:IO@Line+Output]
15125  *
15126  * === Line Input
15127  *
15128  * \Class \IO supports line-oriented input for
15129  * {files}[rdoc-ref:IO@File+Line+Input] and {IO streams}[rdoc-ref:IO@Stream+Line+Input]
15130  *
15131  * ==== \File Line Input
15132  *
15133  * You can read lines from a file using these methods:
15134  *
15135  * - IO.foreach: Reads each line and passes it to the given block.
15136  * - IO.readlines: Reads and returns all lines in an array.
15137  *
15138  * For each of these methods:
15139  *
15140  * - You can specify {open options}[rdoc-ref:IO@Open+Options].
15141  * - Line parsing depends on the effective <i>line separator</i>;
15142  * see {Line Separator}[rdoc-ref:IO@Line+Separator].
15143  * - The length of each returned line depends on the effective <i>line limit</i>;
15144  * see {Line Limit}[rdoc-ref:IO@Line+Limit].
15145  *
15146  * ==== Stream Line Input
15147  *
15148  * You can read lines from an \IO stream using these methods:
15149  *
15150  * - IO#each_line: Reads each remaining line, passing it to the given block.
15151  * - IO#gets: Returns the next line.
15152  * - IO#readline: Like #gets, but raises an exception at end-of-stream.
15153  * - IO#readlines: Returns all remaining lines in an array.
15154  *
15155  * For each of these methods:
15156  *
15157  * - Reading may begin mid-line,
15158  * depending on the stream's _position_;
15159  * see {Position}[rdoc-ref:IO@Position].
15160  * - Line parsing depends on the effective <i>line separator</i>;
15161  * see {Line Separator}[rdoc-ref:IO@Line+Separator].
15162  * - The length of each returned line depends on the effective <i>line limit</i>;
15163  * see {Line Limit}[rdoc-ref:IO@Line+Limit].
15164  *
15165  * ===== Line Separator
15166  *
15167  * Each of the {line input methods}[rdoc-ref:IO@Line+Input] uses a <i>line separator</i>:
15168  * the string that determines what is considered a line;
15169  * it is sometimes called the <i>input record separator</i>.
15170  *
15171  * The default line separator is taken from global variable <tt>$/</tt>,
15172  * whose initial value is <tt>"\n"</tt>.
15173  *
15174  * Generally, the line to be read next is all data
15175  * from the current {position}[rdoc-ref:IO@Position]
15176  * to the next line separator
15177  * (but see {Special Line Separator Values}[rdoc-ref:IO@Special+Line+Separator+Values]):
15178  *
15179  * f = File.new('t.txt')
15180  * # Method gets with no sep argument returns the next line, according to $/.
15181  * f.gets # => "First line\n"
15182  * f.gets # => "Second line\n"
15183  * f.gets # => "\n"
15184  * f.gets # => "Fourth line\n"
15185  * f.gets # => "Fifth line\n"
15186  * f.close
15187  *
15188  * You can use a different line separator by passing argument +sep+:
15189  *
15190  * f = File.new('t.txt')
15191  * f.gets('l') # => "First l"
15192  * f.gets('li') # => "ine\nSecond li"
15193  * f.gets('lin') # => "ne\n\nFourth lin"
15194  * f.gets # => "e\n"
15195  * f.close
15196  *
15197  * Or by setting global variable <tt>$/</tt>:
15198  *
15199  * f = File.new('t.txt')
15200  * $/ = 'l'
15201  * f.gets # => "First l"
15202  * f.gets # => "ine\nSecond l"
15203  * f.gets # => "ine\n\nFourth l"
15204  * f.close
15205  *
15206  * ===== Special Line Separator Values
15207  *
15208  * Each of the {line input methods}[rdoc-ref:IO@Line+Input]
15209  * accepts two special values for parameter +sep+:
15210  *
15211  * - +nil+: The entire stream is to be read ("slurped") into a single string:
15212  *
15213  * f = File.new('t.txt')
15214  * f.gets(nil) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
15215  * f.close
15216  *
15217  * - <tt>''</tt> (the empty string): The next "paragraph" is to be read
15218  * (paragraphs being separated by two consecutive line separators):
15219  *
15220  * f = File.new('t.txt')
15221  * f.gets('') # => "First line\nSecond line\n\n"
15222  * f.gets('') # => "Fourth line\nFifth line\n"
15223  * f.close
15224  *
15225  * ===== Line Limit
15226  *
15227  * Each of the {line input methods}[rdoc-ref:IO@Line+Input]
15228  * uses an integer <i>line limit</i>,
15229  * which restricts the number of bytes that may be returned.
15230  * (A multi-byte character will not be split, and so a returned line may be slightly longer
15231  * than the limit).
15232  *
15233  * The default limit value is <tt>-1</tt>;
15234  * any negative limit value means that there is no limit.
15235  *
15236  * If there is no limit, the line is determined only by +sep+.
15237  *
15238  * # Text with 1-byte characters.
15239  * File.open('t.txt') {|f| f.gets(1) } # => "F"
15240  * File.open('t.txt') {|f| f.gets(2) } # => "Fi"
15241  * File.open('t.txt') {|f| f.gets(3) } # => "Fir"
15242  * File.open('t.txt') {|f| f.gets(4) } # => "Firs"
15243  * # No more than one line.
15244  * File.open('t.txt') {|f| f.gets(10) } # => "First line"
15245  * File.open('t.txt') {|f| f.gets(11) } # => "First line\n"
15246  * File.open('t.txt') {|f| f.gets(12) } # => "First line\n"
15247  *
15248  * # Text with 2-byte characters, which will not be split.
15249  * File.open('t.rus') {|f| f.gets(1).size } # => 1
15250  * File.open('t.rus') {|f| f.gets(2).size } # => 1
15251  * File.open('t.rus') {|f| f.gets(3).size } # => 2
15252  * File.open('t.rus') {|f| f.gets(4).size } # => 2
15253  *
15254  * ===== Line Separator and Line Limit
15255  *
15256  * With arguments +sep+ and +limit+ given, combines the two behaviors:
15257  *
15258  * - Returns the next line as determined by line separator +sep+.
15259  * - But returns no more bytes than are allowed by the limit +limit+.
15260  *
15261  * Example:
15262  *
15263  * File.open('t.txt') {|f| f.gets('li', 20) } # => "First li"
15264  * File.open('t.txt') {|f| f.gets('li', 2) } # => "Fi"
15265  *
15266  * ===== Line Number
15267  *
15268  * A readable \IO stream has a non-negative integer <i>line number</i>:
15269  *
15270  * - IO#lineno: Returns the line number.
15271  * - IO#lineno=: Resets and returns the line number.
15272  *
15273  * Unless modified by a call to method IO#lineno=,
15274  * the line number is the number of lines read
15275  * by certain line-oriented methods,
15276  * according to the effective {line separator}[rdoc-ref:IO@Line+Separator]:
15277  *
15278  * - IO.foreach: Increments the line number on each call to the block.
15279  * - IO#each_line: Increments the line number on each call to the block.
15280  * - IO#gets: Increments the line number.
15281  * - IO#readline: Increments the line number.
15282  * - IO#readlines: Increments the line number for each line read.
15283  *
15284  * A new stream is initially has line number zero (and position zero);
15285  * method +rewind+ resets the line number (and position) to zero:
15286  *
15287  * f = File.new('t.txt')
15288  * f.lineno # => 0
15289  * f.gets # => "First line\n"
15290  * f.lineno # => 1
15291  * f.rewind
15292  * f.lineno # => 0
15293  * f.close
15294  *
15295  * Reading lines from a stream usually changes its line number:
15296  *
15297  * f = File.new('t.txt', 'r')
15298  * f.lineno # => 0
15299  * f.readline # => "This is line one.\n"
15300  * f.lineno # => 1
15301  * f.readline # => "This is the second line.\n"
15302  * f.lineno # => 2
15303  * f.readline # => "Here's the third line.\n"
15304  * f.lineno # => 3
15305  * f.eof? # => true
15306  * f.close
15307  *
15308  * Iterating over lines in a stream usually changes its line number:
15309  *
15310  * File.open('t.txt') do |f|
15311  * f.each_line do |line|
15312  * p "position=#{f.pos} eof?=#{f.eof?} lineno=#{f.lineno}"
15313  * end
15314  * end
15315  *
15316  * Output:
15317  *
15318  * "position=11 eof?=false lineno=1"
15319  * "position=23 eof?=false lineno=2"
15320  * "position=24 eof?=false lineno=3"
15321  * "position=36 eof?=false lineno=4"
15322  * "position=47 eof?=true lineno=5"
15323  *
15324  * Unlike the stream's {position}[rdoc-ref:IO@Position],
15325  * the line number does not affect where the next read or write will occur:
15326  *
15327  * f = File.new('t.txt')
15328  * f.lineno = 1000
15329  * f.lineno # => 1000
15330  * f.gets # => "First line\n"
15331  * f.lineno # => 1001
15332  * f.close
15333  *
15334  * Associated with the line number is the global variable <tt>$.</tt>:
15335  *
15336  * - When a stream is opened, <tt>$.</tt> is not set;
15337  * its value is left over from previous activity in the process:
15338  *
15339  * $. = 41
15340  * f = File.new('t.txt')
15341  * $. = 41
15342  * # => 41
15343  * f.close
15344  *
15345  * - When a stream is read, <tt>$.</tt> is set to the line number for that stream:
15346  *
15347  * f0 = File.new('t.txt')
15348  * f1 = File.new('t.dat')
15349  * f0.readlines # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
15350  * $. # => 5
15351  * f1.readlines # => ["\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"]
15352  * $. # => 1
15353  * f0.close
15354  * f1.close
15355  *
15356  * - Methods IO#rewind and IO#seek do not affect <tt>$.</tt>:
15357  *
15358  * f = File.new('t.txt')
15359  * f.readlines # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
15360  * $. # => 5
15361  * f.rewind
15362  * f.seek(0, :SET)
15363  * $. # => 5
15364  * f.close
15365  *
15366  * === Line Output
15367  *
15368  * You can write to an \IO stream line-by-line using this method:
15369  *
15370  * - IO#puts: Writes objects to the stream.
15371  *
15372  * == Character \IO
15373  *
15374  * You can process an \IO stream character-by-character using these methods:
15375  *
15376  * - IO#getc: Reads and returns the next character from the stream.
15377  * - IO#readchar: Like #getc, but raises an exception at end-of-stream.
15378  * - IO#ungetc: Pushes back ("unshifts") a character or integer onto the stream.
15379  * - IO#putc: Writes a character to the stream.
15380  * - IO#each_char: Reads each remaining character in the stream,
15381  * passing the character to the given block.
15382  *
15383  * == Byte \IO
15384  *
15385  * You can process an \IO stream byte-by-byte using these methods:
15386  *
15387  * - IO#getbyte: Returns the next 8-bit byte as an integer in range 0..255.
15388  * - IO#readbyte: Like #getbyte, but raises an exception if at end-of-stream.
15389  * - IO#ungetbyte: Pushes back ("unshifts") a byte back onto the stream.
15390  * - IO#each_byte: Reads each remaining byte in the stream,
15391  * passing the byte to the given block.
15392  *
15393  * == Codepoint \IO
15394  *
15395  * You can process an \IO stream codepoint-by-codepoint:
15396  *
15397  * - IO#each_codepoint: Reads each remaining codepoint, passing it to the given block.
15398  *
15399  * == What's Here
15400  *
15401  * First, what's elsewhere. \Class \IO:
15402  *
15403  * - Inherits from {class Object}[rdoc-ref:Object@What-27s+Here].
15404  * - Includes {module Enumerable}[rdoc-ref:Enumerable@What-27s+Here],
15405  * which provides dozens of additional methods.
15406  *
15407  * Here, class \IO provides methods that are useful for:
15408  *
15409  * - {Creating}[rdoc-ref:IO@Creating]
15410  * - {Reading}[rdoc-ref:IO@Reading]
15411  * - {Writing}[rdoc-ref:IO@Writing]
15412  * - {Positioning}[rdoc-ref:IO@Positioning]
15413  * - {Iterating}[rdoc-ref:IO@Iterating]
15414  * - {Settings}[rdoc-ref:IO@Settings]
15415  * - {Querying}[rdoc-ref:IO@Querying]
15416  * - {Buffering}[rdoc-ref:IO@Buffering]
15417  * - {Low-Level Access}[rdoc-ref:IO@Low-Level+Access]
15418  * - {Other}[rdoc-ref:IO@Other]
15419  *
15420  * === Creating
15421  *
15422  * - ::new (aliased as ::for_fd): Creates and returns a new \IO object for the given
15423  * integer file descriptor.
15424  * - ::open: Creates a new \IO object.
15425  * - ::pipe: Creates a connected pair of reader and writer \IO objects.
15426  * - ::popen: Creates an \IO object to interact with a subprocess.
15427  * - ::select: Selects which given \IO instances are ready for reading,
15428  * writing, or have pending exceptions.
15429  *
15430  * === Reading
15431  *
15432  * - ::binread: Returns a binary string with all or a subset of bytes
15433  * from the given file.
15434  * - ::read: Returns a string with all or a subset of bytes from the given file.
15435  * - ::readlines: Returns an array of strings, which are the lines from the given file.
15436  * - #getbyte: Returns the next 8-bit byte read from +self+ as an integer.
15437  * - #getc: Returns the next character read from +self+ as a string.
15438  * - #gets: Returns the line read from +self+.
15439  * - #pread: Returns all or the next _n_ bytes read from +self+,
15440  * not updating the receiver's offset.
15441  * - #read: Returns all remaining or the next _n_ bytes read from +self+
15442  * for a given _n_.
15443  * - #read_nonblock: the next _n_ bytes read from +self+ for a given _n_,
15444  * in non-block mode.
15445  * - #readbyte: Returns the next byte read from +self+;
15446  * same as #getbyte, but raises an exception on end-of-stream.
15447  * - #readchar: Returns the next character read from +self+;
15448  * same as #getc, but raises an exception on end-of-stream.
15449  * - #readline: Returns the next line read from +self+;
15450  * same as #getline, but raises an exception of end-of-stream.
15451  * - #readlines: Returns an array of all lines read read from +self+.
15452  * - #readpartial: Returns up to the given number of bytes from +self+.
15453  *
15454  * === Writing
15455  *
15456  * - ::binwrite: Writes the given string to the file at the given filepath,
15457  * in binary mode.
15458  * - ::write: Writes the given string to +self+.
15459  * - #<<: Appends the given string to +self+.
15460  * - #print: Prints last read line or given objects to +self+.
15461  * - #printf: Writes to +self+ based on the given format string and objects.
15462  * - #putc: Writes a character to +self+.
15463  * - #puts: Writes lines to +self+, making sure line ends with a newline.
15464  * - #pwrite: Writes the given string at the given offset,
15465  * not updating the receiver's offset.
15466  * - #write: Writes one or more given strings to +self+.
15467  * - #write_nonblock: Writes one or more given strings to +self+ in non-blocking mode.
15468  *
15469  * === Positioning
15470  *
15471  * - #lineno: Returns the current line number in +self+.
15472  * - #lineno=: Sets the line number is +self+.
15473  * - #pos (aliased as #tell): Returns the current byte offset in +self+.
15474  * - #pos=: Sets the byte offset in +self+.
15475  * - #reopen: Reassociates +self+ with a new or existing \IO stream.
15476  * - #rewind: Positions +self+ to the beginning of input.
15477  * - #seek: Sets the offset for +self+ relative to given position.
15478  *
15479  * === Iterating
15480  *
15481  * - ::foreach: Yields each line of given file to the block.
15482  * - #each (aliased as #each_line): Calls the given block
15483  * with each successive line in +self+.
15484  * - #each_byte: Calls the given block with each successive byte in +self+
15485  * as an integer.
15486  * - #each_char: Calls the given block with each successive character in +self+
15487  * as a string.
15488  * - #each_codepoint: Calls the given block with each successive codepoint in +self+
15489  * as an integer.
15490  *
15491  * === Settings
15492  *
15493  * - #autoclose=: Sets whether +self+ auto-closes.
15494  * - #binmode: Sets +self+ to binary mode.
15495  * - #close: Closes +self+.
15496  * - #close_on_exec=: Sets the close-on-exec flag.
15497  * - #close_read: Closes +self+ for reading.
15498  * - #close_write: Closes +self+ for writing.
15499  * - #set_encoding: Sets the encoding for +self+.
15500  * - #set_encoding_by_bom: Sets the encoding for +self+, based on its
15501  * Unicode byte-order-mark.
15502  * - #sync=: Sets the sync-mode to the given value.
15503  *
15504  * === Querying
15505  *
15506  * - #autoclose?: Returns whether +self+ auto-closes.
15507  * - #binmode?: Returns whether +self+ is in binary mode.
15508  * - #close_on_exec?: Returns the close-on-exec flag for +self+.
15509  * - #closed?: Returns whether +self+ is closed.
15510  * - #eof? (aliased as #eof): Returns whether +self+ is at end-of-stream.
15511  * - #external_encoding: Returns the external encoding object for +self+.
15512  * - #fileno (aliased as #to_i): Returns the integer file descriptor for +self+
15513  * - #internal_encoding: Returns the internal encoding object for +self+.
15514  * - #pid: Returns the process ID of a child process associated with +self+,
15515  * if +self+ was created by ::popen.
15516  * - #stat: Returns the File::Stat object containing status information for +self+.
15517  * - #sync: Returns whether +self+ is in sync-mode.
15518  * - #tty? (aliased as #isatty): Returns whether +self+ is a terminal.
15519  *
15520  * === Buffering
15521  *
15522  * - #fdatasync: Immediately writes all buffered data in +self+ to disk.
15523  * - #flush: Flushes any buffered data within +self+ to the underlying
15524  * operating system.
15525  * - #fsync: Immediately writes all buffered data and attributes in +self+ to disk.
15526  * - #ungetbyte: Prepends buffer for +self+ with given integer byte or string.
15527  * - #ungetc: Prepends buffer for +self+ with given string.
15528  *
15529  * === Low-Level Access
15530  *
15531  * - ::sysopen: Opens the file given by its path,
15532  * returning the integer file descriptor.
15533  * - #advise: Announces the intention to access data from +self+ in a specific way.
15534  * - #fcntl: Passes a low-level command to the file specified
15535  * by the given file descriptor.
15536  * - #ioctl: Passes a low-level command to the device specified
15537  * by the given file descriptor.
15538  * - #sysread: Returns up to the next _n_ bytes read from self using a low-level read.
15539  * - #sysseek: Sets the offset for +self+.
15540  * - #syswrite: Writes the given string to +self+ using a low-level write.
15541  *
15542  * === Other
15543  *
15544  * - ::copy_stream: Copies data from a source to a destination,
15545  * each of which is a filepath or an \IO-like object.
15546  * - ::try_convert: Returns a new \IO object resulting from converting
15547  * the given object.
15548  * - #inspect: Returns the string representation of +self+.
15549  *
15550  */
15551 
15552 void
15553 Init_IO(void)
15554 {
15555  VALUE rb_cARGF;
15556 #ifdef __CYGWIN__
15557 #include <sys/cygwin.h>
15558  static struct __cygwin_perfile pf[] =
15559  {
15560  {"", O_RDONLY | O_BINARY},
15561  {"", O_WRONLY | O_BINARY},
15562  {"", O_RDWR | O_BINARY},
15563  {"", O_APPEND | O_BINARY},
15564  {NULL, 0}
15565  };
15566  cygwin_internal(CW_PERFILE, pf);
15567 #endif
15568 
15570  rb_eEOFError = rb_define_class("EOFError", rb_eIOError);
15571 
15572  id_write = rb_intern_const("write");
15573  id_read = rb_intern_const("read");
15574  id_getc = rb_intern_const("getc");
15575  id_flush = rb_intern_const("flush");
15576  id_readpartial = rb_intern_const("readpartial");
15577  id_set_encoding = rb_intern_const("set_encoding");
15578  id_fileno = rb_intern_const("fileno");
15579 
15580  rb_define_global_function("syscall", rb_f_syscall, -1);
15581 
15582  rb_define_global_function("open", rb_f_open, -1);
15583  rb_define_global_function("printf", rb_f_printf, -1);
15584  rb_define_global_function("print", rb_f_print, -1);
15585  rb_define_global_function("putc", rb_f_putc, 1);
15586  rb_define_global_function("puts", rb_f_puts, -1);
15587  rb_define_global_function("gets", rb_f_gets, -1);
15588  rb_define_global_function("readline", rb_f_readline, -1);
15589  rb_define_global_function("select", rb_f_select, -1);
15590 
15591  rb_define_global_function("readlines", rb_f_readlines, -1);
15592 
15593  rb_define_global_function("`", rb_f_backquote, 1);
15594 
15595  rb_define_global_function("p", rb_f_p, -1);
15596  rb_define_method(rb_mKernel, "display", rb_obj_display, -1);
15597 
15598  rb_cIO = rb_define_class("IO", rb_cObject);
15600 
15601  /* Can be raised by IO operations when IO#timeout= is set. */
15603 
15604  /* Readable event mask for IO#wait. */
15606  /* Writable event mask for IO#wait. */
15608  /* Priority event mask for IO#wait. */
15610 
15611  /* exception to wait for reading. see IO.select. */
15612  rb_mWaitReadable = rb_define_module_under(rb_cIO, "WaitReadable");
15613  /* exception to wait for writing. see IO.select. */
15614  rb_mWaitWritable = rb_define_module_under(rb_cIO, "WaitWritable");
15615  /* exception to wait for reading by EAGAIN. see IO.select. */
15616  rb_eEAGAINWaitReadable = rb_define_class_under(rb_cIO, "EAGAINWaitReadable", rb_eEAGAIN);
15617  rb_include_module(rb_eEAGAINWaitReadable, rb_mWaitReadable);
15618  /* exception to wait for writing by EAGAIN. see IO.select. */
15619  rb_eEAGAINWaitWritable = rb_define_class_under(rb_cIO, "EAGAINWaitWritable", rb_eEAGAIN);
15620  rb_include_module(rb_eEAGAINWaitWritable, rb_mWaitWritable);
15621 #if EAGAIN == EWOULDBLOCK
15622  rb_eEWOULDBLOCKWaitReadable = rb_eEAGAINWaitReadable;
15623  /* same as IO::EAGAINWaitReadable */
15624  rb_define_const(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEAGAINWaitReadable);
15625  rb_eEWOULDBLOCKWaitWritable = rb_eEAGAINWaitWritable;
15626  /* same as IO::EAGAINWaitWritable */
15627  rb_define_const(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEAGAINWaitWritable);
15628 #else
15629  /* exception to wait for reading by EWOULDBLOCK. see IO.select. */
15630  rb_eEWOULDBLOCKWaitReadable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEWOULDBLOCK);
15631  rb_include_module(rb_eEWOULDBLOCKWaitReadable, rb_mWaitReadable);
15632  /* exception to wait for writing by EWOULDBLOCK. see IO.select. */
15633  rb_eEWOULDBLOCKWaitWritable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEWOULDBLOCK);
15634  rb_include_module(rb_eEWOULDBLOCKWaitWritable, rb_mWaitWritable);
15635 #endif
15636  /* exception to wait for reading by EINPROGRESS. see IO.select. */
15637  rb_eEINPROGRESSWaitReadable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitReadable", rb_eEINPROGRESS);
15638  rb_include_module(rb_eEINPROGRESSWaitReadable, rb_mWaitReadable);
15639  /* exception to wait for writing by EINPROGRESS. see IO.select. */
15640  rb_eEINPROGRESSWaitWritable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitWritable", rb_eEINPROGRESS);
15641  rb_include_module(rb_eEINPROGRESSWaitWritable, rb_mWaitWritable);
15642 
15643 #if 0
15644  /* This is necessary only for forcing rdoc handle File::open */
15645  rb_define_singleton_method(rb_cFile, "open", rb_io_s_open, -1);
15646 #endif
15647 
15648  rb_define_alloc_func(rb_cIO, io_alloc);
15649  rb_define_singleton_method(rb_cIO, "new", rb_io_s_new, -1);
15650  rb_define_singleton_method(rb_cIO, "open", rb_io_s_open, -1);
15651  rb_define_singleton_method(rb_cIO, "sysopen", rb_io_s_sysopen, -1);
15652  rb_define_singleton_method(rb_cIO, "for_fd", rb_io_s_for_fd, -1);
15653  rb_define_singleton_method(rb_cIO, "popen", rb_io_s_popen, -1);
15654  rb_define_singleton_method(rb_cIO, "foreach", rb_io_s_foreach, -1);
15655  rb_define_singleton_method(rb_cIO, "readlines", rb_io_s_readlines, -1);
15656  rb_define_singleton_method(rb_cIO, "read", rb_io_s_read, -1);
15657  rb_define_singleton_method(rb_cIO, "binread", rb_io_s_binread, -1);
15658  rb_define_singleton_method(rb_cIO, "write", rb_io_s_write, -1);
15659  rb_define_singleton_method(rb_cIO, "binwrite", rb_io_s_binwrite, -1);
15660  rb_define_singleton_method(rb_cIO, "select", rb_f_select, -1);
15661  rb_define_singleton_method(rb_cIO, "pipe", rb_io_s_pipe, -1);
15662  rb_define_singleton_method(rb_cIO, "try_convert", rb_io_s_try_convert, 1);
15663  rb_define_singleton_method(rb_cIO, "copy_stream", rb_io_s_copy_stream, -1);
15664 
15665  rb_define_method(rb_cIO, "initialize", rb_io_initialize, -1);
15666 
15667  rb_output_fs = Qnil;
15668  rb_define_hooked_variable("$,", &rb_output_fs, 0, deprecated_str_setter);
15669 
15670  rb_default_rs = rb_fstring_lit("\n"); /* avoid modifying RS_default */
15671  rb_vm_register_global_object(rb_default_rs);
15672  rb_rs = rb_default_rs;
15673  rb_output_rs = Qnil;
15674  rb_define_hooked_variable("$/", &rb_rs, 0, deprecated_str_setter);
15675  rb_define_hooked_variable("$-0", &rb_rs, 0, deprecated_str_setter);
15676  rb_define_hooked_variable("$\\", &rb_output_rs, 0, deprecated_str_setter);
15677 
15678  rb_define_virtual_variable("$_", get_LAST_READ_LINE, set_LAST_READ_LINE);
15679  rb_gvar_ractor_local("$_");
15680 
15681  rb_define_method(rb_cIO, "initialize_copy", rb_io_init_copy, 1);
15682  rb_define_method(rb_cIO, "reopen", rb_io_reopen, -1);
15683 
15684  rb_define_method(rb_cIO, "print", rb_io_print, -1);
15685  rb_define_method(rb_cIO, "putc", rb_io_putc, 1);
15686  rb_define_method(rb_cIO, "puts", rb_io_puts, -1);
15687  rb_define_method(rb_cIO, "printf", rb_io_printf, -1);
15688 
15689  rb_define_method(rb_cIO, "each", rb_io_each_line, -1);
15690  rb_define_method(rb_cIO, "each_line", rb_io_each_line, -1);
15691  rb_define_method(rb_cIO, "each_byte", rb_io_each_byte, 0);
15692  rb_define_method(rb_cIO, "each_char", rb_io_each_char, 0);
15693  rb_define_method(rb_cIO, "each_codepoint", rb_io_each_codepoint, 0);
15694 
15695  rb_define_method(rb_cIO, "syswrite", rb_io_syswrite, 1);
15696  rb_define_method(rb_cIO, "sysread", rb_io_sysread, -1);
15697 
15698  rb_define_method(rb_cIO, "pread", rb_io_pread, -1);
15699  rb_define_method(rb_cIO, "pwrite", rb_io_pwrite, 2);
15700 
15701  rb_define_method(rb_cIO, "fileno", rb_io_fileno, 0);
15702  rb_define_alias(rb_cIO, "to_i", "fileno");
15703  rb_define_method(rb_cIO, "to_io", rb_io_to_io, 0);
15704 
15705  rb_define_method(rb_cIO, "timeout", rb_io_timeout, 0);
15706  rb_define_method(rb_cIO, "timeout=", rb_io_set_timeout, 1);
15707 
15708  rb_define_method(rb_cIO, "fsync", rb_io_fsync, 0);
15709  rb_define_method(rb_cIO, "fdatasync", rb_io_fdatasync, 0);
15710  rb_define_method(rb_cIO, "sync", rb_io_sync, 0);
15711  rb_define_method(rb_cIO, "sync=", rb_io_set_sync, 1);
15712 
15713  rb_define_method(rb_cIO, "lineno", rb_io_lineno, 0);
15714  rb_define_method(rb_cIO, "lineno=", rb_io_set_lineno, 1);
15715 
15716  rb_define_method(rb_cIO, "readlines", rb_io_readlines, -1);
15717 
15718  rb_define_method(rb_cIO, "readpartial", io_readpartial, -1);
15719  rb_define_method(rb_cIO, "read", io_read, -1);
15720  rb_define_method(rb_cIO, "write", io_write_m, -1);
15721  rb_define_method(rb_cIO, "gets", rb_io_gets_m, -1);
15722  rb_define_method(rb_cIO, "getc", rb_io_getc, 0);
15723  rb_define_method(rb_cIO, "getbyte", rb_io_getbyte, 0);
15724  rb_define_method(rb_cIO, "readchar", rb_io_readchar, 0);
15725  rb_define_method(rb_cIO, "readbyte", rb_io_readbyte, 0);
15726  rb_define_method(rb_cIO, "ungetbyte",rb_io_ungetbyte, 1);
15727  rb_define_method(rb_cIO, "ungetc",rb_io_ungetc, 1);
15729  rb_define_method(rb_cIO, "flush", rb_io_flush, 0);
15730  rb_define_method(rb_cIO, "tell", rb_io_tell, 0);
15731  rb_define_method(rb_cIO, "seek", rb_io_seek_m, -1);
15732  /* Set I/O position from the beginning */
15733  rb_define_const(rb_cIO, "SEEK_SET", INT2FIX(SEEK_SET));
15734  /* Set I/O position from the current position */
15735  rb_define_const(rb_cIO, "SEEK_CUR", INT2FIX(SEEK_CUR));
15736  /* Set I/O position from the end */
15737  rb_define_const(rb_cIO, "SEEK_END", INT2FIX(SEEK_END));
15738 #ifdef SEEK_DATA
15739  /* Set I/O position to the next location containing data */
15740  rb_define_const(rb_cIO, "SEEK_DATA", INT2FIX(SEEK_DATA));
15741 #endif
15742 #ifdef SEEK_HOLE
15743  /* Set I/O position to the next hole */
15744  rb_define_const(rb_cIO, "SEEK_HOLE", INT2FIX(SEEK_HOLE));
15745 #endif
15746  rb_define_method(rb_cIO, "rewind", rb_io_rewind, 0);
15747  rb_define_method(rb_cIO, "pos", rb_io_tell, 0);
15748  rb_define_method(rb_cIO, "pos=", rb_io_set_pos, 1);
15749  rb_define_method(rb_cIO, "eof", rb_io_eof, 0);
15750  rb_define_method(rb_cIO, "eof?", rb_io_eof, 0);
15751 
15752  rb_define_method(rb_cIO, "close_on_exec?", rb_io_close_on_exec_p, 0);
15753  rb_define_method(rb_cIO, "close_on_exec=", rb_io_set_close_on_exec, 1);
15754 
15755  rb_define_method(rb_cIO, "close", rb_io_close_m, 0);
15756  rb_define_method(rb_cIO, "closed?", rb_io_closed_p, 0);
15757  rb_define_method(rb_cIO, "close_read", rb_io_close_read, 0);
15758  rb_define_method(rb_cIO, "close_write", rb_io_close_write, 0);
15759 
15760  rb_define_method(rb_cIO, "isatty", rb_io_isatty, 0);
15761  rb_define_method(rb_cIO, "tty?", rb_io_isatty, 0);
15762  rb_define_method(rb_cIO, "binmode", rb_io_binmode_m, 0);
15763  rb_define_method(rb_cIO, "binmode?", rb_io_binmode_p, 0);
15764  rb_define_method(rb_cIO, "sysseek", rb_io_sysseek, -1);
15765  rb_define_method(rb_cIO, "advise", rb_io_advise, -1);
15766 
15767  rb_define_method(rb_cIO, "ioctl", rb_io_ioctl, -1);
15768  rb_define_method(rb_cIO, "fcntl", rb_io_fcntl, -1);
15769  rb_define_method(rb_cIO, "pid", rb_io_pid, 0);
15770 
15771  rb_define_method(rb_cIO, "path", rb_io_path, 0);
15772  rb_define_method(rb_cIO, "to_path", rb_io_path, 0);
15773 
15774  rb_define_method(rb_cIO, "inspect", rb_io_inspect, 0);
15775 
15776  rb_define_method(rb_cIO, "external_encoding", rb_io_external_encoding, 0);
15777  rb_define_method(rb_cIO, "internal_encoding", rb_io_internal_encoding, 0);
15778  rb_define_method(rb_cIO, "set_encoding", rb_io_set_encoding, -1);
15779  rb_define_method(rb_cIO, "set_encoding_by_bom", rb_io_set_encoding_by_bom, 0);
15780 
15781  rb_define_method(rb_cIO, "autoclose?", rb_io_autoclose_p, 0);
15782  rb_define_method(rb_cIO, "autoclose=", rb_io_set_autoclose, 1);
15783 
15784  rb_define_method(rb_cIO, "wait", io_wait, -1);
15785 
15786  rb_define_method(rb_cIO, "wait_readable", io_wait_readable, -1);
15787  rb_define_method(rb_cIO, "wait_writable", io_wait_writable, -1);
15788  rb_define_method(rb_cIO, "wait_priority", io_wait_priority, -1);
15789 
15790  rb_define_virtual_variable("$stdin", stdin_getter, stdin_setter);
15791  rb_define_virtual_variable("$stdout", stdout_getter, stdout_setter);
15792  rb_define_virtual_variable("$>", stdout_getter, stdout_setter);
15793  rb_define_virtual_variable("$stderr", stderr_getter, stderr_setter);
15794 
15795  rb_gvar_ractor_local("$stdin");
15796  rb_gvar_ractor_local("$stdout");
15797  rb_gvar_ractor_local("$>");
15798  rb_gvar_ractor_local("$stderr");
15799 
15801  rb_stdin = rb_io_prep_stdin();
15803  rb_stdout = rb_io_prep_stdout();
15805  rb_stderr = rb_io_prep_stderr();
15806 
15807  orig_stdout = rb_stdout;
15808  orig_stderr = rb_stderr;
15809 
15810  /* Holds the original stdin */
15811  rb_define_global_const("STDIN", rb_stdin);
15812  /* Holds the original stdout */
15813  rb_define_global_const("STDOUT", rb_stdout);
15814  /* Holds the original stderr */
15815  rb_define_global_const("STDERR", rb_stderr);
15816 
15817 #if 0
15818  /* Hack to get rdoc to regard ARGF as a class: */
15819  rb_cARGF = rb_define_class("ARGF", rb_cObject);
15820 #endif
15821 
15822  rb_cARGF = rb_class_new(rb_cObject);
15823  rb_set_class_path(rb_cARGF, rb_cObject, "ARGF.class");
15824  rb_define_alloc_func(rb_cARGF, argf_alloc);
15825 
15826  rb_include_module(rb_cARGF, rb_mEnumerable);
15827 
15828  rb_define_method(rb_cARGF, "initialize", argf_initialize, -2);
15829  rb_define_method(rb_cARGF, "initialize_copy", argf_initialize_copy, 1);
15830  rb_define_method(rb_cARGF, "to_s", argf_to_s, 0);
15831  rb_define_alias(rb_cARGF, "inspect", "to_s");
15832  rb_define_method(rb_cARGF, "argv", argf_argv, 0);
15833 
15834  rb_define_method(rb_cARGF, "fileno", argf_fileno, 0);
15835  rb_define_method(rb_cARGF, "to_i", argf_fileno, 0);
15836  rb_define_method(rb_cARGF, "to_io", argf_to_io, 0);
15837  rb_define_method(rb_cARGF, "to_write_io", argf_write_io, 0);
15838  rb_define_method(rb_cARGF, "each", argf_each_line, -1);
15839  rb_define_method(rb_cARGF, "each_line", argf_each_line, -1);
15840  rb_define_method(rb_cARGF, "each_byte", argf_each_byte, 0);
15841  rb_define_method(rb_cARGF, "each_char", argf_each_char, 0);
15842  rb_define_method(rb_cARGF, "each_codepoint", argf_each_codepoint, 0);
15843 
15844  rb_define_method(rb_cARGF, "read", argf_read, -1);
15845  rb_define_method(rb_cARGF, "readpartial", argf_readpartial, -1);
15846  rb_define_method(rb_cARGF, "read_nonblock", argf_read_nonblock, -1);
15847  rb_define_method(rb_cARGF, "readlines", argf_readlines, -1);
15848  rb_define_method(rb_cARGF, "to_a", argf_readlines, -1);
15849  rb_define_method(rb_cARGF, "gets", argf_gets, -1);
15850  rb_define_method(rb_cARGF, "readline", argf_readline, -1);
15851  rb_define_method(rb_cARGF, "getc", argf_getc, 0);
15852  rb_define_method(rb_cARGF, "getbyte", argf_getbyte, 0);
15853  rb_define_method(rb_cARGF, "readchar", argf_readchar, 0);
15854  rb_define_method(rb_cARGF, "readbyte", argf_readbyte, 0);
15855  rb_define_method(rb_cARGF, "tell", argf_tell, 0);
15856  rb_define_method(rb_cARGF, "seek", argf_seek_m, -1);
15857  rb_define_method(rb_cARGF, "rewind", argf_rewind, 0);
15858  rb_define_method(rb_cARGF, "pos", argf_tell, 0);
15859  rb_define_method(rb_cARGF, "pos=", argf_set_pos, 1);
15860  rb_define_method(rb_cARGF, "eof", argf_eof, 0);
15861  rb_define_method(rb_cARGF, "eof?", argf_eof, 0);
15862  rb_define_method(rb_cARGF, "binmode", argf_binmode_m, 0);
15863  rb_define_method(rb_cARGF, "binmode?", argf_binmode_p, 0);
15864 
15865  rb_define_method(rb_cARGF, "write", argf_write, -1);
15866  rb_define_method(rb_cARGF, "print", rb_io_print, -1);
15867  rb_define_method(rb_cARGF, "putc", rb_io_putc, 1);
15868  rb_define_method(rb_cARGF, "puts", rb_io_puts, -1);
15869  rb_define_method(rb_cARGF, "printf", rb_io_printf, -1);
15870 
15871  rb_define_method(rb_cARGF, "filename", argf_filename, 0);
15872  rb_define_method(rb_cARGF, "path", argf_filename, 0);
15873  rb_define_method(rb_cARGF, "file", argf_file, 0);
15874  rb_define_method(rb_cARGF, "skip", argf_skip, 0);
15875  rb_define_method(rb_cARGF, "close", argf_close_m, 0);
15876  rb_define_method(rb_cARGF, "closed?", argf_closed, 0);
15877 
15878  rb_define_method(rb_cARGF, "lineno", argf_lineno, 0);
15879  rb_define_method(rb_cARGF, "lineno=", argf_set_lineno, 1);
15880 
15881  rb_define_method(rb_cARGF, "inplace_mode", argf_inplace_mode_get, 0);
15882  rb_define_method(rb_cARGF, "inplace_mode=", argf_inplace_mode_set, 1);
15883 
15884  rb_define_method(rb_cARGF, "external_encoding", argf_external_encoding, 0);
15885  rb_define_method(rb_cARGF, "internal_encoding", argf_internal_encoding, 0);
15886  rb_define_method(rb_cARGF, "set_encoding", argf_set_encoding, -1);
15887 
15888  argf = rb_class_new_instance(0, 0, rb_cARGF);
15889 
15891  /*
15892  * ARGF is a stream designed for use in scripts that process files given
15893  * as command-line arguments or passed in via STDIN.
15894  *
15895  * See ARGF (the class) for more details.
15896  */
15897  rb_define_global_const("ARGF", argf);
15898 
15899  rb_define_hooked_variable("$.", &argf, argf_lineno_getter, argf_lineno_setter);
15900  rb_define_hooked_variable("$FILENAME", &argf, argf_filename_getter, rb_gvar_readonly_setter);
15901  ARGF.filename = rb_str_new2("-");
15902 
15903  rb_define_hooked_variable("$-i", &argf, opt_i_get, opt_i_set);
15904  rb_gvar_ractor_local("$-i");
15905 
15906  rb_define_hooked_variable("$*", &argf, argf_argv_getter, rb_gvar_readonly_setter);
15907 
15908 #if defined (_WIN32) || defined(__CYGWIN__)
15909  atexit(pipe_atexit);
15910 #endif
15911 
15912  Init_File();
15913 
15914  rb_define_method(rb_cFile, "initialize", rb_file_initialize, -1);
15915 
15916  sym_mode = ID2SYM(rb_intern_const("mode"));
15917  sym_perm = ID2SYM(rb_intern_const("perm"));
15918  sym_flags = ID2SYM(rb_intern_const("flags"));
15919  sym_extenc = ID2SYM(rb_intern_const("external_encoding"));
15920  sym_intenc = ID2SYM(rb_intern_const("internal_encoding"));
15921  sym_encoding = ID2SYM(rb_id_encoding());
15922  sym_open_args = ID2SYM(rb_intern_const("open_args"));
15923  sym_textmode = ID2SYM(rb_intern_const("textmode"));
15924  sym_binmode = ID2SYM(rb_intern_const("binmode"));
15925  sym_autoclose = ID2SYM(rb_intern_const("autoclose"));
15926  sym_normal = ID2SYM(rb_intern_const("normal"));
15927  sym_sequential = ID2SYM(rb_intern_const("sequential"));
15928  sym_random = ID2SYM(rb_intern_const("random"));
15929  sym_willneed = ID2SYM(rb_intern_const("willneed"));
15930  sym_dontneed = ID2SYM(rb_intern_const("dontneed"));
15931  sym_noreuse = ID2SYM(rb_intern_const("noreuse"));
15932  sym_SET = ID2SYM(rb_intern_const("SET"));
15933  sym_CUR = ID2SYM(rb_intern_const("CUR"));
15934  sym_END = ID2SYM(rb_intern_const("END"));
15935 #ifdef SEEK_DATA
15936  sym_DATA = ID2SYM(rb_intern_const("DATA"));
15937 #endif
15938 #ifdef SEEK_HOLE
15939  sym_HOLE = ID2SYM(rb_intern_const("HOLE"));
15940 #endif
15941  sym_wait_readable = ID2SYM(rb_intern_const("wait_readable"));
15942  sym_wait_writable = ID2SYM(rb_intern_const("wait_writable"));
15943 }
15944 
15945 #include "io.rbinc"
#define RUBY_ASSERT(...)
Asserts that the given expression is truthy if and only if RUBY_DEBUG is truthy.
Definition: assert.h:219
std::atomic< unsigned > rb_atomic_t
Type that is eligible for atomic operations.
Definition: atomic.h:69
unsigned long ruby_strtoul(const char *str, char **endptr, int base)
Our own locale-insensitive version of strtoul(3).
Definition: util.c:138
#define rb_define_singleton_method(klass, mid, func, arity)
Defines klass.mid.
Definition: cxxanyargs.hpp:685
void rb_include_module(VALUE klass, VALUE module)
Includes a module to a class.
Definition: class.c:1187
VALUE rb_define_class(const char *name, VALUE super)
Defines a top-level class.
Definition: class.c:980
VALUE rb_class_new(VALUE super)
Creates a new, anonymous class.
Definition: class.c:359
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
Definition: class.c:1012
VALUE rb_define_module_under(VALUE outer, const char *name)
Defines a module under the namespace of outer.
Definition: class.c:1119
void rb_define_alias(VALUE klass, const char *name1, const char *name2)
Defines an alias of a method.
Definition: class.c:2345
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:2648
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:2635
void rb_define_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a method.
Definition: class.c:2142
int rb_block_given_p(void)
Determines if the current method is given a block.
Definition: eval.c:916
int rb_get_kwargs(VALUE keyword_hash, const ID *table, int required, int optional, VALUE *values)
Keyword argument deconstructor.
Definition: class.c:2424
void rb_define_global_function(const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a global function.
Definition: class.c:2339
#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:108
#define RB_INTEGER_TYPE_P
Old name of rb_integer_type_p.
Definition: value_type.h:87
#define ENC_CODERANGE_7BIT
Old name of RUBY_ENC_CODERANGE_7BIT.
Definition: coderange.h:180
#define T_FILE
Old name of RUBY_T_FILE.
Definition: value_type.h:62
#define ENC_CODERANGE_VALID
Old name of RUBY_ENC_CODERANGE_VALID.
Definition: coderange.h:181
#define ECONV_UNIVERSAL_NEWLINE_DECORATOR
Old name of RUBY_ECONV_UNIVERSAL_NEWLINE_DECORATOR.
Definition: transcode.h:532
#define 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:395
#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 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:135
#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:397
#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:659
#define ECONV_NEWLINE_DECORATOR_WRITE_MASK
Old name of RUBY_ECONV_NEWLINE_DECORATOR_WRITE_MASK.
Definition: transcode.h:531
#define ENCODING_MAXNAMELEN
Old name of RUBY_ENCODING_MAXNAMELEN.
Definition: encoding.h:111
#define MBCLEN_NEEDMORE_LEN(ret)
Old name of ONIGENC_MBCLEN_NEEDMORE_LEN.
Definition: encoding.h:520
#define ENCODING_GET(obj)
Old name of RB_ENCODING_GET.
Definition: encoding.h:109
#define LONG2FIX
Old name of RB_INT2FIX.
Definition: long.h:49
#define NUM2UINT
Old name of RB_NUM2UINT.
Definition: int.h:45
#define ALLOC_N
Old name of RB_ALLOC_N.
Definition: memory.h:394
#define MBCLEN_CHARFOUND_LEN(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_LEN.
Definition: encoding.h:517
#define LONG2NUM
Old name of RB_LONG2NUM.
Definition: long.h:50
#define rb_exc_new3
Old name of rb_exc_new_str.
Definition: error.h:38
#define STRNCASECMP
Old name of st_locale_insensitive_strncasecmp.
Definition: ctype.h:103
#define MBCLEN_INVALID_P(ret)
Old name of ONIGENC_MBCLEN_INVALID_P.
Definition: encoding.h:518
#define ISASCII
Old name of rb_isascii.
Definition: ctype.h:85
#define ECONV_STATEFUL_DECORATOR_MASK
Old name of RUBY_ECONV_STATEFUL_DECORATOR_MASK.
Definition: transcode.h:538
#define Qtrue
Old name of RUBY_Qtrue.
#define MBCLEN_NEEDMORE_P(ret)
Old name of ONIGENC_MBCLEN_NEEDMORE_P.
Definition: encoding.h:519
#define ECONV_PARTIAL_INPUT
Old name of RUBY_ECONV_PARTIAL_INPUT.
Definition: transcode.h:554
#define NUM2INT
Old name of RB_NUM2INT.
Definition: int.h:44
#define ECONV_ERROR_HANDLER_MASK
Old name of RUBY_ECONV_ERROR_HANDLER_MASK.
Definition: transcode.h:522
#define INT2NUM
Old name of RB_INT2NUM.
Definition: int.h:43
#define Qnil
Old name of RUBY_Qnil.
#define Qfalse
Old name of RUBY_Qfalse.
#define FIX2LONG
Old name of RB_FIX2LONG.
Definition: long.h:46
#define ENC_CODERANGE_BROKEN
Old name of RUBY_ENC_CODERANGE_BROKEN.
Definition: coderange.h:182
#define T_ARRAY
Old name of RUBY_T_ARRAY.
Definition: value_type.h:56
#define NIL_P
Old name of RB_NIL_P.
#define ALLOCV_N
Old name of RB_ALLOCV_N.
Definition: memory.h:400
#define MBCLEN_CHARFOUND_P(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_P.
Definition: encoding.h:516
#define ECONV_NEWLINE_DECORATOR_READ_MASK
Old name of RUBY_ECONV_NEWLINE_DECORATOR_READ_MASK.
Definition: transcode.h:530
#define NUM2CHR
Old name of RB_NUM2CHR.
Definition: char.h:33
#define NUM2LONG
Old name of RB_NUM2LONG.
Definition: long.h:51
#define UINT2NUM
Old name of RB_UINT2NUM.
Definition: int.h:46
#define FIXNUM_P
Old name of RB_FIXNUM_P.
#define ECONV_NEWLINE_DECORATOR_MASK
Old name of RUBY_ECONV_NEWLINE_DECORATOR_MASK.
Definition: transcode.h:529
#define CONST_ID
Old name of RUBY_CONST_ID.
Definition: symbol.h:47
#define rb_ary_new2
Old name of rb_ary_new_capa.
Definition: array.h:657
#define NUM2SIZET
Old name of RB_NUM2SIZE.
Definition: size_t.h:61
#define ENC_CODERANGE_SET(obj, cr)
Old name of RB_ENC_CODERANGE_SET.
Definition: coderange.h:186
#define rb_str_new4
Old name of rb_str_new_frozen.
Definition: string.h:1677
#define ALLOCV_END
Old name of RB_ALLOCV_END.
Definition: memory.h:401
#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:3679
void rb_category_warn(rb_warning_category_t category, const char *fmt,...)
Identical to rb_category_warning(), except it reports unless $VERBOSE is nil.
Definition: error.c:476
void rb_raise(VALUE exc_class, const char *fmt,...)
Exception entry point.
Definition: error.c:3635
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:508
VALUE rb_rescue2(VALUE(*b_proc)(VALUE), VALUE data1, VALUE(*r_proc)(VALUE, VALUE), VALUE data2,...)
An equivalent of rescue clause.
Definition: eval.c:945
VALUE rb_eNotImpError
NotImplementedError exception.
Definition: error.c:1418
void rb_exc_raise(VALUE mesg)
Raises an exception in the current thread.
Definition: eval.c:676
void rb_syserr_fail(int e, const char *mesg)
Raises appropriate exception that represents a C errno.
Definition: error.c:3748
void rb_bug(const char *fmt,...)
Interpreter panic switch.
Definition: error.c:1089
void rb_sys_fail(const char *mesg)
Converts a C errno into a Ruby exception, then raises it.
Definition: error.c:3761
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:14626
VALUE rb_eIOError
IOError exception.
Definition: io.c:189
VALUE rb_eStandardError
StandardError exception.
Definition: error.c:1405
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:3838
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:3754
#define ruby_verbose
This variable controls whether the interpreter is in debug mode.
Definition: error.h:475
VALUE rb_eTypeError
TypeError exception.
Definition: error.c:1408
VALUE rb_eEOFError
EOFError exception.
Definition: io.c:188
void rb_fatal(const char *fmt,...)
Raises the unsung "fatal" exception.
Definition: error.c:3687
void rb_readwrite_sys_fail(enum rb_io_wait_readwrite waiting, const char *mesg)
Raises appropriate exception using the parameters.
Definition: io.c:14620
void rb_iter_break_value(VALUE val)
Identical to rb_iter_break(), except it additionally takes the "value" of this breakage.
Definition: vm.c:2082
rb_io_wait_readwrite
for rb_readwrite_sys_fail first argument
Definition: error.h:73
VALUE rb_eRuntimeError
RuntimeError exception.
Definition: error.c:1406
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports unless $VERBOSE is nil.
Definition: error.c:466
VALUE rb_eArgError
ArgumentError exception.
Definition: error.c:1409
VALUE rb_ensure(VALUE(*b_proc)(VALUE), VALUE data1, VALUE(*e_proc)(VALUE), VALUE data2)
An equivalent to ensure clause.
Definition: eval.c:1045
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:3768
VALUE rb_eSystemCallError
SystemCallError exception.
Definition: error.c:1428
@ RB_WARN_CATEGORY_DEPRECATED
Warning is for deprecated features.
Definition: error.h:48
VALUE rb_mKernel
Kernel module.
Definition: object.c:65
VALUE rb_check_to_int(VALUE val)
Identical to rb_check_to_integer(), except it uses #to_int for conversion.
Definition: object.c:3194
VALUE rb_any_to_s(VALUE obj)
Generates a textual representation of the given object.
Definition: object.c:669
VALUE rb_obj_alloc(VALUE klass)
Allocates an instance of the given class.
Definition: object.c:2093
VALUE rb_class_new_instance(int argc, const VALUE *argv, VALUE klass)
Allocates, then initialises an instance of the given class.
Definition: object.c:2134
VALUE rb_cIO
IO class.
Definition: io.c:187
VALUE rb_class_new_instance_kw(int argc, const VALUE *argv, VALUE klass, int kw_splat)
Identical to rb_class_new_instance(), except you can specify how to handle the last element of the gi...
Definition: object.c:2122
VALUE rb_mEnumerable
Enumerable module.
Definition: enum.c:27
VALUE rb_stdin
STDIN constant.
Definition: io.c:201
VALUE rb_stderr
STDERR constant.
Definition: io.c:201
VALUE rb_obj_class(VALUE obj)
Queries the class of an object.
Definition: object.c:247
VALUE rb_obj_dup(VALUE obj)
Duplicates the given object.
Definition: object.c:576
VALUE rb_inspect(VALUE obj)
Generates a human-readable textual representation of the given object.
Definition: object.c:680
VALUE rb_mWaitReadable
IO::WaitReadable module.
Definition: io.c:191
VALUE rb_mWaitWritable
IO::WaitReadable module.
Definition: io.c:192
VALUE rb_obj_freeze(VALUE obj)
Just calls rb_obj_freeze_inline() inside.
Definition: object.c:1260
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:3175
VALUE rb_cFile
File class.
Definition: file.c:175
VALUE rb_stdout
STDOUT constant.
Definition: io.c:201
VALUE rb_to_int(VALUE val)
Identical to rb_check_to_int(), except it raises in case of conversion mismatch.
Definition: object.c:3188
rb_encoding * rb_locale_encoding(void)
Queries the encoding that represents the current locale.
Definition: encoding.c:1523
rb_encoding * rb_default_external_encoding(void)
Queries the "default external" encoding.
Definition: encoding.c:1589
int rb_enc_precise_mbclen(const char *p, const char *e, rb_encoding *enc)
Queries the number of bytes of the character at the passed pointer.
Definition: encoding.c:1191
int rb_to_encoding_index(VALUE obj)
Obtains a encoding index from a wider range of objects (than rb_enc_find_index()).
Definition: encoding.c:261
VALUE rb_enc_associate(VALUE obj, rb_encoding *enc)
Identical to rb_enc_associate_index(), except it takes an encoding itself instead of its index.
Definition: encoding.c:1022
rb_encoding * rb_usascii_encoding(void)
Queries the encoding that represents US-ASCII.
Definition: encoding.c:1487
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:683
int rb_utf8_encindex(void)
Identical to rb_utf8_encoding(), except it returns the encoding's index instead of the encoding itsel...
Definition: encoding.c:1481
rb_encoding * rb_default_internal_encoding(void)
Queries the "default internal" encoding.
Definition: encoding.c:1676
rb_encoding * rb_find_encoding(VALUE obj)
Identical to rb_to_encoding_index(), except the return type.
Definition: encoding.c:330
rb_encoding * rb_to_encoding(VALUE obj)
Identical to rb_find_encoding(), except it raises an exception instead of returning NULL.
Definition: encoding.c:323
rb_encoding * rb_ascii8bit_encoding(void)
Queries the encoding that represents ASCII-8BIT a.k.a.
Definition: encoding.c:1463
VALUE rb_enc_default_external(void)
Identical to rb_default_external_encoding(), except it returns the Ruby-level counterpart instance of...
Definition: encoding.c:1603
VALUE rb_enc_from_encoding(rb_encoding *enc)
Queries the Ruby-level counterpart instance of rb_cEncoding that corresponds to the passed encoding.
Definition: encoding.c:182
static bool rb_enc_asciicompat(rb_encoding *enc)
Queries if the passed encoding is in some sense compatible with ASCII.
Definition: encoding.h:768
static unsigned int rb_enc_codepoint(const char *p, const char *e, rb_encoding *enc)
Queries the code point of character pointed by the passed pointer.
Definition: encoding.h:571
rb_encoding * rb_enc_from_index(int idx)
Identical to rb_find_encoding(), except it takes an encoding index instead of a Ruby object.
Definition: encoding.c:402
int rb_enc_mbclen(const char *p, const char *e, rb_encoding *enc)
Queries the number of bytes of the character at the passed pointer.
Definition: encoding.c:1179
rb_encoding * rb_enc_get(VALUE obj)
Identical to rb_enc_get_index(), except the return type.
Definition: encoding.c:1028
static const char * rb_enc_name(rb_encoding *enc)
Queries the (canonical) name of the passed encoding.
Definition: encoding.h:417
int rb_enc_find_index(const char *name)
Queries the index of the encoding.
Definition: encoding.c:824
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:432
int rb_enc_ascget(const char *p, const char *e, int *len, rb_encoding *enc)
Queries the code point of character pointed by the passed pointer.
Definition: encoding.c:1203
VALUE rb_enc_uint_chr(unsigned int code, rb_encoding *enc)
Encodes the passed code point into a series of bytes.
Definition: numeric.c:3803
VALUE rb_enc_str_new(const char *ptr, long len, rb_encoding *enc)
Identical to rb_str_new(), except it additionally takes an encoding.
Definition: string.c:1068
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:784
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:2600
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:2097
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:1475
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:1770
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:1931
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:1996
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:2914
VALUE rb_econv_make_exception(rb_econv_t *ec)
This function makes sense right after rb_econv_convert() returns.
Definition: transcode.c:4272
void rb_econv_check_error(rb_econv_t *ec)
This is a rb_econv_make_exception() + rb_exc_raise() combo.
Definition: transcode.c:4278
const char * rb_econv_asciicompat_encoding(const char *encname)
Queries the passed encoding's corresponding ASCII compatible encoding.
Definition: transcode.c:1814
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:2651
void rb_econv_close(rb_econv_t *ec)
Destructs a converter.
Definition: transcode.c:1731
void rb_econv_putback(rb_econv_t *ec, unsigned char *p, int n)
Puts back the bytes.
Definition: transcode.c:1781
VALUE rb_funcall(VALUE recv, ID mid, int n,...)
Calls a method.
Definition: vm_eval.c:1099
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:1066
VALUE rb_funcallv(VALUE recv, ID mid, int argc, const VALUE *argv)
Identical to rb_funcall(), except it takes the method arguments as a C array.
Definition: vm_eval.c:1058
void rb_gc_mark(VALUE obj)
Marks an object.
Definition: gc.c:2211
void rb_gc(void)
Triggers a GC process.
Definition: gc.c:3638
void rb_global_variable(VALUE *)
An alias for rb_gc_register_address().
Definition: gc.c:2974
Defines RBIMPL_HAS_BUILTIN.
VALUE rb_ary_concat(VALUE lhs, VALUE rhs)
Destructively appends the contents of latter into the end of former.
Definition: array.c:5068
VALUE rb_ary_shift(VALUE ary)
Destructively deletes an element from the beginning of the passed array and returns what was deleted.
Definition: array.c:1490
VALUE rb_check_array_type(VALUE obj)
Try converting an object to its array representation using its to_ary method, if any.
Definition: array.c:1008
VALUE rb_ary_new(void)
Allocates a new, empty array.
Definition: array.c:741
VALUE rb_ary_push(VALUE ary, VALUE elem)
Special case of rb_ary_cat() that it adds only one element.
Definition: array.c:1378
VALUE rb_ary_entry(VALUE ary, long off)
Queries an element of an array.
Definition: array.c:1731
VALUE rb_assoc_new(VALUE car, VALUE cdr)
Identical to rb_ary_new_from_values(), except it expects exactly two parameters.
Definition: array.c:995
#define RETURN_ENUMERATOR(obj, argc, argv)
Identical to RETURN_SIZED_ENUMERATOR(), except its size is unknown.
Definition: enumerator.h:239
static int rb_check_arity(int argc, int min, int max)
Ensures that the passed integer is in the passed range.
Definition: error.h:284
ID rb_frame_this_func(void)
Queries the name of the Ruby level method that is calling this function.
Definition: eval.c:1094
void rb_jump_tag(int state)
This function is to re-throw global escapes.
Definition: eval.c:907
VALUE rb_str_encode_ospath(VALUE path)
Converts a string into an "OS Path" encoding, if any.
Definition: file.c:252
VALUE rb_check_hash_type(VALUE obj)
Try converting an object to its hash representation using its to_hash method, if any.
Definition: hash.c:1864
VALUE rb_hash_lookup2(VALUE hash, VALUE key, VALUE def)
Identical to rb_hash_lookup(), except you can specify what to return on misshits.
Definition: hash.c:2086
VALUE rb_hash_aref(VALUE hash, VALUE key)
Queries the given key in the given hash table.
Definition: hash.c:2073
VALUE rb_hash_aset(VALUE hash, VALUE key, VALUE val)
Inserts or replaces ("upsert"s) the objects into the given hash table.
Definition: hash.c:2893
VALUE rb_hash_lookup(VALUE hash, VALUE key)
Identical to rb_hash_aref(), except it always returns RUBY_Qnil for misshits.
Definition: hash.c:2099
VALUE rb_hash_dup(VALUE hash)
Duplicates a hash.
Definition: hash.c:1563
VALUE rb_hash_new(void)
Creates a new, empty hash object.
Definition: hash.c:1475
VALUE rb_io_printf(int argc, const VALUE *argv, VALUE io)
This is a rb_f_sprintf() + rb_io_write() combo.
Definition: io.c:8566
VALUE rb_io_gets(VALUE io)
Reads a "line" from the given IO.
Definition: io.c:4262
int rb_cloexec_pipe(int fildes[2])
Opens a pipe with closing on exec.
Definition: io.c:427
VALUE rb_rs
The record separator character for inputs, or the $/.
Definition: io.c:205
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:8692
VALUE rb_io_addstr(VALUE io, VALUE str)
Identical to rb_io_write(), except it always returns the passed IO.
Definition: io.c:2344
void rb_write_error(const char *str)
Writes the given error message to somewhere applicable.
Definition: io.c:9121
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:5131
VALUE rb_io_getbyte(VALUE io)
Reads a byte from the given IO.
Definition: io.c:5037
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:8924
int rb_cloexec_dup2(int oldfd, int newfd)
Identical to rb_cloexec_dup(), except you can specify the destination file descriptor.
Definition: io.c:374
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:9297
void rb_update_max_fd(int fd)
Informs the interpreter that the passed fd can be the max.
Definition: io.c:248
VALUE rb_io_write(VALUE io, VALUE str)
Writes the given string to the given IO.
Definition: io.c:2296
int rb_cloexec_open(const char *pathname, int flags, mode_t mode)
Opens a file that closes on exec.
Definition: io.c:328
VALUE rb_output_rs
The record separator character for outputs, or the $\.
Definition: io.c:206
VALUE rb_io_eof(VALUE io)
Queries if the passed IO is at the end of file.
Definition: io.c:2689
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:9101
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:298
VALUE rb_io_flush(VALUE io)
Flushes any buffered data within the passed IO to the underlying operating system.
Definition: io.c:2400
VALUE rb_io_ascii8bit_binmode(VALUE io)
Forces no conversions be applied to the passed IO.
Definition: io.c:6343
VALUE rb_io_binmode(VALUE io)
Sets the binmode.
Definition: io.c:6297
VALUE rb_io_ungetc(VALUE io, VALUE c)
"Unget"s a string.
Definition: io.c:5195
int rb_pipe(int *pipes)
This is an rb_cloexec_pipe() + rb_update_max_fd() combo.
Definition: io.c:7344
VALUE rb_gets(void)
Much like rb_io_gets(), but it reads from the mysterious ARGF object.
Definition: io.c:10366
int rb_cloexec_fcntl_dupfd(int fd, int minfd)
Duplicates a file descriptor with closing on exec.
Definition: io.c:461
VALUE rb_output_fs
The field separator character for outputs, or the $,.
Definition: io.c:204
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:7227
int rb_cloexec_dup(int oldfd)
Identical to rb_cloexec_fcntl_dupfd(), except it implies minfd is 3.
Definition: io.c:367
VALUE rb_file_open(const char *fname, const char *fmode)
Opens a file located at the given path.
Definition: io.c:7234
VALUE rb_io_close(VALUE io)
Closes the IO.
Definition: io.c:5717
VALUE rb_default_rs
This is the default value of rb_rs, i.e.
Definition: io.c:207
void rb_lastline_set(VALUE str)
Updates $_.
Definition: vm.c:1844
VALUE rb_lastline_get(void)
Queries the last line, or the $_.
Definition: vm.c:1838
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:2900
VALUE rb_protect(VALUE(*func)(VALUE args), VALUE args, int *state)
Protects a function call from potential global escapes from the function.
rb_pid_t rb_waitpid(rb_pid_t pid, int *status, int flags)
Waits for a process, with releasing GVL.
Definition: process.c:1269
void rb_last_status_set(int status, rb_pid_t pid)
Sets the "last status", or the $?.
Definition: process.c:682
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:3675
VALUE rb_str_buf_cat(VALUE, const char *, long)
Just another name of rb_str_cat.
size_t rb_str_capacity(VALUE str)
Queries the capacity of the given string.
Definition: string.c:954
VALUE rb_str_new_frozen(VALUE str)
Creates a frozen copy of the string, if necessary.
Definition: string.c:1461
VALUE rb_str_cat2(VALUE, const char *)
Just another name of rb_str_cat_cstr.
VALUE rb_str_dup(VALUE str)
Duplicates a string.
Definition: string.c:1916
void rb_str_modify(VALUE str)
Declares that the string is about to be modified.
Definition: string.c:2640
VALUE rb_str_cat(VALUE dst, const char *src, long srclen)
Destructively appends the passed contents to the string.
Definition: string.c:3443
VALUE rb_str_locktmp(VALUE str)
Obtains a "temporary lock" of the string.
VALUE rb_usascii_str_new(const char *ptr, long len)
Identical to rb_str_new(), except it generates a string of "US ASCII" encoding.
Definition: string.c:1056
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:3267
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:3617
VALUE rb_str_new(const char *ptr, long len)
Allocates an instance of rb_cString.
Definition: string.c:1050
VALUE rb_check_string_type(VALUE obj)
Try converting an object to its stringised representation using its to_str method,...
Definition: string.c:2850
VALUE rb_str_substr(VALUE str, long beg, long len)
This is the implementation of two-argumented String#slice.
Definition: string.c:3148
VALUE rb_str_unlocktmp(VALUE str)
Releases a lock formerly obtained by rb_str_locktmp().
Definition: string.c:3250
VALUE rb_str_new_cstr(const char *ptr)
Identical to rb_str_new(), except it assumes the passed pointer is a pointer to a C string.
Definition: string.c:1074
VALUE rb_str_resize(VALUE str, long len)
Overwrites the length of the string.
Definition: string.c:3315
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:2648
VALUE rb_str_buf_new(long capa)
Allocates a "string buffer".
Definition: string.c:1643
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:1775
int rb_thread_interrupted(VALUE thval)
Checks if the thread's execution was recently interrupted.
Definition: thread.c:1449
VALUE rb_mutex_new(void)
Creates a mutex.
Definition: thread_sync.c:191
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:1597
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:2705
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.
Definition: thread_sync.c:640
void rb_thread_check_ints(void)
Checks for interrupts.
Definition: thread.c:1432
VALUE rb_thread_current(void)
Obtains the "current" thread.
Definition: thread.c:2982
int rb_thread_wait_fd(int fd)
Blocks the current thread until the given file descriptor is ready to be read.
Definition: io.c:1591
void rb_thread_sleep(int sec)
Blocks for the given period of time.
Definition: thread.c:1455
struct timeval rb_time_interval(VALUE num)
Creates a "time interval".
Definition: time.c:2890
VALUE rb_attr_get(VALUE obj, ID name)
Identical to rb_ivar_get()
Definition: variable.c:1370
void rb_set_class_path(VALUE klass, VALUE space, const char *name)
Names a class.
Definition: variable.c:353
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:1871
VALUE rb_class_name(VALUE obj)
Queries the name of the given object's class.
Definition: variable.c:412
int rb_respond_to(VALUE obj, ID mid)
Queries if the object responds to the method.
Definition: vm_method.c:2960
int rb_method_basic_definition_p(VALUE klass, ID mid)
Well...
Definition: vm_method.c:2838
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:668
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:277
const char * rb_id2name(ID id)
Retrieves the name mapped to the given id.
Definition: symbol.c:992
ID rb_intern(const char *name)
Finds or creates a symbol of the given name.
Definition: symbol.c:823
#define RB_ID2SYM
Just another name of rb_id2sym.
Definition: symbol.h:42
VALUE rb_id2str(ID id)
Identical to rb_id2name(), except it returns a frozen Ruby String instead of a C String.
Definition: symbol.c:986
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:3740
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:744
rb_gvar_setter_t rb_gvar_readonly_setter
This function just raises rb_eNameError.
Definition: variable.h:135
void rb_define_virtual_variable(const char *name, rb_gvar_getter_t *getter, rb_gvar_setter_t *setter)
Defines a global variable that is purely function-backended.
Definition: variable.c:750
void rb_define_const(VALUE klass, const char *name, VALUE val)
Defines a Ruby level constant under a namespace.
Definition: variable.c:3726
void rb_define_hooked_variable(const char *name, VALUE *var, rb_gvar_getter_t *getter, rb_gvar_setter_t *setter)
Identical to rb_define_virtual_variable(), but can also specify a storage.
Definition: variable.c:719
#define FMODE_READABLE
The IO is opened for reading.
Definition: io.h:270
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:6429
VALUE rb_io_get_io(VALUE io)
Identical to rb_io_check_io(), except it raises exceptions on conversion failures.
Definition: io.c:811
VALUE rb_io_timeout(VALUE io)
Get the timeout associated with the specified io object.
Definition: io.c:857
VALUE rb_io_taint_check(VALUE obj)
Definition: io.c:781
void rb_io_read_check(rb_io_t *fptr)
Blocks until there is a pending read in the passed IO.
Definition: io.c:1069
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:6562
#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:368
int rb_io_mode(VALUE io)
Get the mode of the IO.
Definition: io.c:2912
rb_io_event
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
#define FMODE_READWRITE
The IO is opened for both read/write.
Definition: io.h:276
#define FMODE_EXTERNAL
This flag means that an IO object is wrapping an "external" file descriptor, which is owned by someth...
Definition: io.h:360
#define GetOpenFile
This is an old name of RB_IO_POINTER.
Definition: io.h:402
void rb_io_check_byte_readable(rb_io_t *fptr)
Asserts that an IO is opened for byte-based reading.
Definition: io.c:1015
#define FMODE_TTY
The IO is a TTY.
Definition: io.h:300
#define FMODE_CREATE
The IO is opened for creating.
Definition: io.h:323
void rb_io_check_readable(rb_io_t *fptr)
Just another name of rb_io_check_byte_readable.
Definition: io.c:1024
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:6711
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:9343
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:1585
int rb_io_descriptor(VALUE io)
Returns an integer representing the numeric file descriptor for io.
Definition: io.c:2892
#define FMODE_WRITABLE
The IO is opened for writing.
Definition: io.h:273
#define FMODE_APPEND
The IO is opened for appending.
Definition: io.h:315
#define MakeOpenFile
This is an old name of RB_IO_OPEN.
Definition: io.h:425
#define FMODE_DUPLEX
Ruby eventually detects that the IO is bidirectional.
Definition: io.h:308
#define FMODE_BINMODE
The IO is in "binary mode".
Definition: io.h:287
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:1644
int capa
Designed capacity of the buffer.
Definition: io.h:11
#define RB_IO_POINTER(obj, fp)
Queries the underlying IO pointer.
Definition: io.h:396
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:1603
VALUE rb_eIOTimeoutError
Indicates that a timeout has occurred while performing an IO operation.
Definition: io.c:190
char * ptr
Pointer to the underlying memory region, of at least capa bytes.
Definition: io.h:2
#define FMODE_SYNC
The IO is in "sync mode".
Definition: io.h:294
int off
Offset inside of ptr.
Definition: io.h:5
VALUE rb_io_path(VALUE io)
Returns the path for the given IO.
Definition: io.c:2966
void rb_io_check_initialized(rb_io_t *fptr)
Asserts that the passed IO is initialised.
Definition: io.c:788
#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:331
#define FMODE_TEXTMODE
The IO is in "text mode".
Definition: io.h:351
int rb_io_fptr_finalize(rb_io_t *fptr)
Destroys the given IO.
Definition: io.c:5646
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:817
VALUE rb_io_closed_p(VALUE io)
Returns whether or not the underlying IO is closed.
Definition: io.c:5825
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:7044
VALUE rb_io_set_timeout(VALUE io, VALUE timeout)
Set the timeout associated with the specified io object.
Definition: io.c:886
ssize_t rb_io_bufwrite(VALUE io, const void *buf, size_t size)
Buffered write to the passed IO.
Definition: io.c:2009
void rb_io_check_char_readable(rb_io_t *fptr)
Asserts that an IO is opened for character-based reading.
Definition: io.c:996
#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:337
VALUE rb_io_get_write_io(VALUE io)
Queries the tied IO for writing.
Definition: io.c:823
void rb_io_set_nonblock(rb_io_t *fptr)
Instructs the OS to put its internal file structure into "nonblocking mode".
Definition: io.c:3418
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:6836
int rb_io_wait_writable(int fd)
Blocks until the passed file descriptor gets writable.
Definition: io.c:1542
VALUE rb_io_open_descriptor(VALUE klass, int descriptor, int mode, VALUE path, VALUE timeout, struct rb_io_encoding *encoding)
Allocate a new IO object, with the given file descriptor.
Definition: io.c:9214
VALUE rb_io_set_write_io(VALUE io, VALUE w)
Assigns the tied IO for writing.
Definition: io.c:834
void rb_io_check_writable(rb_io_t *fptr)
Asserts that an IO is opened for writing.
Definition: io.c:1048
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:1659
void rb_io_check_closed(rb_io_t *fptr)
This badly named function asserts that the passed IO is open.
Definition: io.c:796
int rb_io_wait_readable(int fd)
Blocks until the passed file descriptor gets readable.
Definition: io.c:1508
void rb_io_synchronized(rb_io_t *fptr)
Sets FMODE_SYNC.
Definition: io.c:7331
VALUE rb_io_wait(VALUE io, VALUE events, VALUE timeout)
Blocks until the passed IO is ready for the passed events.
Definition: io.c:1447
int len
Length of the buffer.
Definition: io.h:8
VALUE rb_ractor_stderr(void)
Queries the standard error of the current Ractor that is calling this function.
Definition: ractor.c:2724
VALUE rb_ractor_stdin(void)
Queries the standard input of the current Ractor that is calling this function.
Definition: ractor.c:2700
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:2760
VALUE rb_ractor_stdout(void)
Queries the standard output of the current Ractor that is calling this function.
Definition: ractor.c:2712
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:2748
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:2736
void * rb_thread_call_with_gvl(void *(*func)(void *), void *data1)
(Re-)acquires the GVL.
Definition: thread.c:1902
#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:209
VALUE rb_sprintf(const char *fmt,...)
Ruby's extended sprintf(3).
Definition: sprintf.c:1217
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:1240
#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:1388
VALUE rb_yield(VALUE val)
Yields the block.
Definition: vm_eval.c:1354
int rb_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.
int rb_fd_isset(int fd, const rb_fdset_t *f)
Queries if the given FD is in the given set.
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:355
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
Definition: memory.h:162
#define MEMMOVE(p1, p2, type, n)
Handy macro to call memmove.
Definition: memory.h:379
#define NUM2MODET
Converts a C's mode_t into an instance of rb_cInteger.
Definition: mode_t.h:28
#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_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:51
static int RARRAY_LENINT(VALUE ary)
Identical to rb_array_len(), except it differs for the return type.
Definition: rarray.h:281
#define RARRAY_AREF(a, i)
Definition: rarray.h:403
#define RARRAY_CONST_PTR
Just another name of rb_array_const_ptr.
Definition: rarray.h:52
#define RFILE(obj)
Convenient casting macro.
Definition: rfile.h:50
#define StringValue(v)
Ensures that the parameter object is a String.
Definition: rstring.h:66
static char * RSTRING_END(VALUE str)
Queries the end of the contents pointer of the string.
Definition: rstring.h:442
static char * RSTRING_PTR(VALUE str)
Queries the contents pointer of the string.
Definition: rstring.h:416
#define RSTRING_GETMEM(str, ptrvar, lenvar)
Convenient macro to obtain the contents and length at once.
Definition: rstring.h:488
static long RSTRING_LEN(VALUE str)
Queries the length of the string.
Definition: rstring.h:367
#define StringValueCStr(v)
Identical to StringValuePtr, except it additionally checks for the contents for viability as a C stri...
Definition: rstring.h:89
#define RUBY_TYPED_DEFAULT_FREE
This is a value you can set to rb_data_type_struct::dfree.
Definition: rtypeddata.h: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:497
VALUE rb_get_argv(void)
Queries the arguments passed to the current process that you can access from Ruby as ARGV.
Definition: io.c:14586
void rb_p(VALUE obj)
Inspects an object.
Definition: io.c:9000
#define FilePathValue(v)
Ensures that the parameter object is a path.
Definition: ruby.h:90
#define errno
Ractor-aware version of errno.
Definition: ruby.h:388
#define RB_SCAN_ARGS_LAST_HASH_KEYWORDS
Treat a final argument as keywords if it is a hash, and not as keywords otherwise.
Definition: scan_args.h:59
#define RB_PASS_CALLED_KEYWORDS
Pass keywords if current method is called with keywords, useful for argument delegation.
Definition: scan_args.h:78
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:226
VALUE rb_fiber_scheduler_io_pread_memory(VALUE scheduler, VALUE io, rb_off_t from, void *base, size_t size, size_t length)
Non-blocking pread from the passed IO using a native buffer.
Definition: scheduler.c:630
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:269
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:442
VALUE rb_fiber_scheduler_io_read_memory(VALUE scheduler, VALUE io, void *base, size_t size, size_t length)
Non-blocking read from the passed IO using a native buffer.
Definition: scheduler.c:606
VALUE rb_fiber_scheduler_io_wait(VALUE scheduler, VALUE io, VALUE events, VALUE timeout)
Non-blocking version of rb_io_wait().
Definition: scheduler.c:436
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:472
VALUE rb_fiber_scheduler_io_pwrite_memory(VALUE scheduler, VALUE io, rb_off_t from, const void *base, size_t size, size_t length)
Non-blocking pwrite to the passed IO using a native buffer.
Definition: scheduler.c:642
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:231
VALUE rb_fiber_scheduler_io_write_memory(VALUE scheduler, VALUE io, const void *base, size_t size, size_t length)
Non-blocking write to the passed IO using a native buffer.
Definition: scheduler.c:618
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:448
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:4333
static bool RB_TEST(VALUE obj)
Emulates Ruby's "if" statement.
@ RUBY_Qfalse
#define RTEST
This is an old name of RB_TEST.
#define _(args)
This was a transition path from K&R to ANSI.
Definition: stdarg.h:35
C99 shim for <stdbool.h>
Ruby's File and IO.
Definition: rfile.h:35
Definition: io.c:236
Definition: win32.h:219
Definition: io.c:7240
This is the struct that holds necessary info for a struct.
Definition: rtypeddata.h:200
The data structure which wraps the fd_set bitmap used by select(2).
Definition: largesize.h:71
Decomposed encoding flags (e.g.
Definition: io.h:119
int ecflags
Flags.
Definition: io.h:129
VALUE ecopts
Flags as Ruby hash.
Definition: io.h:137
rb_encoding * enc2
External encoding.
Definition: io.h:123
rb_encoding * enc
Internal encoding.
Definition: io.h:121
IO buffers.
Definition: io.h:94
char * ptr
Pointer to the underlying memory region, of at least capa bytes.
Definition: io.h:97
int off
Offset inside of ptr.
Definition: io.h:100
int len
Length of the buffer.
Definition: io.h:103
int capa
Designed capacity of the buffer.
Definition: io.h:106
Ruby's IO, metadata and buffers.
Definition: io.h:143
int mode
mode flags: FMODE_XXXs
Definition: io.h:158
rb_io_buffer_t wbuf
Write buffer.
Definition: io.h:178
void(* finalize)(struct rb_io *, int)
finalize proc
Definition: io.h:174
rb_econv_t * readconv
Encoding converter used when reading from this IO.
Definition: io.h:200
rb_econv_t * writeconv
Encoding converter used when writing to this IO.
Definition: io.h:211
struct rb_io_encoding encs
Decomposed encoding flags.
Definition: io.h:196
VALUE self
The IO's Ruby level counterpart.
Definition: io.h:146
VALUE write_lock
This is a Ruby level mutex.
Definition: io.h:248
VALUE timeout
The timeout associated with this IO when performing blocking operations.
Definition: io.h:254
FILE * stdio_file
stdio ptr for read/write, if available.
Definition: io.h:150
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:238
VALUE tied_io_for_writing
Duplex IO object, if set.
Definition: io.h:193
int writeconv_initialized
Whether rb_io_t::writeconv is already set up.
Definition: io.h:224
int fd
file descriptor.
Definition: io.h:154
rb_io_buffer_t rbuf
(Byte) read buffer.
Definition: io.h:185
int lineno
number of lines read
Definition: io.h:166
VALUE writeconv_asciicompat
This is, when set, an instance of rb_cString which holds the "common" encoding.
Definition: io.h:220
rb_io_buffer_t cbuf
rb_io_ungetc() destination.
Definition: io.h:207
rb_pid_t pid
child's pid (for pipes)
Definition: io.h:162
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:231
VALUE pathv
pathname for file
Definition: io.h:170
Definition: io.c:12143
Definition: io.c:1735
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:307
static void Check_Type(VALUE v, enum ruby_value_type t)
Identical to RB_TYPE_P(), except it raises exceptions on predication failure.
Definition: value_type.h:433
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.
Definition: value_type.h:376