Ruby 3.3.0p0 (2023-12-25 revision 5124f9ac7513eb590c37717337c430cb93caa151)
io.c
1/**********************************************************************
2
3 io.c -
4
5 $Author$
6 created at: Fri Oct 15 18:08:59 JST 1993
7
8 Copyright (C) 1993-2007 Yukihiro Matsumoto
9 Copyright (C) 2000 Network Applied Communication Laboratory, Inc.
10 Copyright (C) 2000 Information-technology Promotion Agency, Japan
11
12**********************************************************************/
13
14#include "ruby/internal/config.h"
15
17#include "ruby/io/buffer.h"
18
19#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#endif
108
110#include "ccan/list/list.h"
111#include "dln.h"
112#include "encindex.h"
113#include "id.h"
114#include "internal.h"
115#include "internal/encoding.h"
116#include "internal/error.h"
117#include "internal/inits.h"
118#include "internal/io.h"
119#include "internal/numeric.h"
120#include "internal/object.h"
121#include "internal/process.h"
122#include "internal/thread.h"
123#include "internal/transcode.h"
124#include "internal/variable.h"
125#include "ruby/io.h"
126#include "ruby/io/buffer.h"
127#include "ruby/missing.h"
128#include "ruby/thread.h"
129#include "ruby/util.h"
130#include "ruby_atomic.h"
131#include "ruby/ractor.h"
132
133#if !USE_POLL
134# include "vm_core.h"
135#endif
136
137#include "builtin.h"
138
139#ifndef O_ACCMODE
140#define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR)
141#endif
142
143#ifndef PIPE_BUF
144# ifdef _POSIX_PIPE_BUF
145# define PIPE_BUF _POSIX_PIPE_BUF
146# else
147# define PIPE_BUF 512 /* is this ok? */
148# endif
149#endif
150
151#ifndef EWOULDBLOCK
152# define EWOULDBLOCK EAGAIN
153#endif
154
155#if defined(HAVE___SYSCALL) && (defined(__APPLE__) || defined(__OpenBSD__))
156/* Mac OS X and OpenBSD have __syscall but don't define it in headers */
157off_t __syscall(quad_t number, ...);
158#endif
159
160#define IO_RBUF_CAPA_MIN 8192
161#define IO_CBUF_CAPA_MIN (128*1024)
162#define IO_RBUF_CAPA_FOR(fptr) (NEED_READCONV(fptr) ? IO_CBUF_CAPA_MIN : IO_RBUF_CAPA_MIN)
163#define IO_WBUF_CAPA_MIN 8192
164
165#define IO_MAX_BUFFER_GROWTH 8 * 1024 * 1024 // 8MB
166
167/* define system APIs */
168#ifdef _WIN32
169#undef open
170#define open rb_w32_uopen
171#undef rename
172#define rename(f, t) rb_w32_urename((f), (t))
173#include "win32/file.h"
174#endif
175
182
183static VALUE rb_eEAGAINWaitReadable;
184static VALUE rb_eEAGAINWaitWritable;
185static VALUE rb_eEWOULDBLOCKWaitReadable;
186static VALUE rb_eEWOULDBLOCKWaitWritable;
187static VALUE rb_eEINPROGRESSWaitWritable;
188static VALUE rb_eEINPROGRESSWaitReadable;
189
191static VALUE orig_stdout, orig_stderr;
192
193VALUE rb_output_fs;
194VALUE rb_rs;
196VALUE rb_default_rs;
197
198static VALUE argf;
199
200static ID id_write, id_read, id_getc, id_flush, id_readpartial, id_set_encoding, id_fileno;
201static VALUE sym_mode, sym_perm, sym_flags, sym_extenc, sym_intenc, sym_encoding, sym_open_args;
202static VALUE sym_textmode, sym_binmode, sym_autoclose;
203static VALUE sym_SET, sym_CUR, sym_END;
204static VALUE sym_wait_readable, sym_wait_writable;
205#ifdef SEEK_DATA
206static VALUE sym_DATA;
207#endif
208#ifdef SEEK_HOLE
209static VALUE sym_HOLE;
210#endif
211
212static VALUE prep_io(int fd, int fmode, VALUE klass, const char *path);
213
214struct argf {
215 VALUE filename, current_file;
216 long last_lineno; /* $. */
217 long lineno;
218 VALUE argv;
219 VALUE inplace;
220 struct rb_io_encoding encs;
221 int8_t init_p, next_p, binmode;
222};
223
224static rb_atomic_t max_file_descriptor = NOFILE;
225void
227{
228 rb_atomic_t afd = (rb_atomic_t)fd;
229 rb_atomic_t max_fd = max_file_descriptor;
230 int err;
231
232 if (fd < 0 || afd <= max_fd)
233 return;
234
235#if defined(HAVE_FCNTL) && defined(F_GETFL)
236 err = fcntl(fd, F_GETFL) == -1;
237#else
238 {
239 struct stat buf;
240 err = fstat(fd, &buf) != 0;
241 }
242#endif
243 if (err && errno == EBADF) {
244 rb_bug("rb_update_max_fd: invalid fd (%d) given.", fd);
245 }
246
247 while (max_fd < afd) {
248 max_fd = ATOMIC_CAS(max_file_descriptor, max_fd, afd);
249 }
250}
251
252void
253rb_maygvl_fd_fix_cloexec(int fd)
254{
255 /* MinGW don't have F_GETFD and FD_CLOEXEC. [ruby-core:40281] */
256#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
257 int flags, flags2, ret;
258 flags = fcntl(fd, F_GETFD); /* should not fail except EBADF. */
259 if (flags == -1) {
260 rb_bug("rb_maygvl_fd_fix_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(errno));
261 }
262 if (fd <= 2)
263 flags2 = flags & ~FD_CLOEXEC; /* Clear CLOEXEC for standard file descriptors: 0, 1, 2. */
264 else
265 flags2 = flags | FD_CLOEXEC; /* Set CLOEXEC for non-standard file descriptors: 3, 4, 5, ... */
266 if (flags != flags2) {
267 ret = fcntl(fd, F_SETFD, flags2);
268 if (ret != 0) {
269 rb_bug("rb_maygvl_fd_fix_cloexec: fcntl(%d, F_SETFD, %d) failed: %s", fd, flags2, strerror(errno));
270 }
271 }
272#endif
273}
274
275void
277{
278 rb_maygvl_fd_fix_cloexec(fd);
280}
281
282/* this is only called once */
283static int
284rb_fix_detect_o_cloexec(int fd)
285{
286#if defined(O_CLOEXEC) && defined(F_GETFD)
287 int flags = fcntl(fd, F_GETFD);
288
289 if (flags == -1)
290 rb_bug("rb_fix_detect_o_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(errno));
291
292 if (flags & FD_CLOEXEC)
293 return 1;
294#endif /* fall through if O_CLOEXEC does not work: */
295 rb_maygvl_fd_fix_cloexec(fd);
296 return 0;
297}
298
299static inline bool
300io_again_p(int e)
301{
302 return (e == EWOULDBLOCK) || (e == EAGAIN);
303}
304
305int
306rb_cloexec_open(const char *pathname, int flags, mode_t mode)
307{
308 int ret;
309 static int o_cloexec_state = -1; /* <0: unknown, 0: ignored, >0: working */
310
311 static const int retry_interval = 0;
312 static const int retry_max_count = 10000;
313
314 int retry_count = 0;
315
316#ifdef O_CLOEXEC
317 /* O_CLOEXEC is available since Linux 2.6.23. Linux 2.6.18 silently ignore it. */
318 flags |= O_CLOEXEC;
319#elif defined O_NOINHERIT
320 flags |= O_NOINHERIT;
321#endif
322
323 while ((ret = open(pathname, flags, mode)) == -1) {
324 int e = errno;
325 if (!io_again_p(e)) break;
326 if (retry_count++ >= retry_max_count) break;
327
328 sleep(retry_interval);
329 }
330
331 if (ret < 0) return ret;
332 if (ret <= 2 || o_cloexec_state == 0) {
333 rb_maygvl_fd_fix_cloexec(ret);
334 }
335 else if (o_cloexec_state > 0) {
336 return ret;
337 }
338 else {
339 o_cloexec_state = rb_fix_detect_o_cloexec(ret);
340 }
341 return ret;
342}
343
344int
346{
347 /* Don't allocate standard file descriptors: 0, 1, 2 */
348 return rb_cloexec_fcntl_dupfd(oldfd, 3);
349}
350
351int
352rb_cloexec_dup2(int oldfd, int newfd)
353{
354 int ret;
355
356 /* When oldfd == newfd, dup2 succeeds but dup3 fails with EINVAL.
357 * rb_cloexec_dup2 succeeds as dup2. */
358 if (oldfd == newfd) {
359 ret = newfd;
360 }
361 else {
362#if defined(HAVE_DUP3) && defined(O_CLOEXEC)
363 static int try_dup3 = 1;
364 if (2 < newfd && try_dup3) {
365 ret = dup3(oldfd, newfd, O_CLOEXEC);
366 if (ret != -1)
367 return ret;
368 /* dup3 is available since Linux 2.6.27, glibc 2.9. */
369 if (errno == ENOSYS) {
370 try_dup3 = 0;
371 ret = dup2(oldfd, newfd);
372 }
373 }
374 else {
375 ret = dup2(oldfd, newfd);
376 }
377#else
378 ret = dup2(oldfd, newfd);
379#endif
380 if (ret < 0) return ret;
381 }
382 rb_maygvl_fd_fix_cloexec(ret);
383 return ret;
384}
385
386static int
387rb_fd_set_nonblock(int fd)
388{
389#ifdef _WIN32
390 return rb_w32_set_nonblock(fd);
391#elif defined(F_GETFL)
392 int oflags = fcntl(fd, F_GETFL);
393
394 if (oflags == -1)
395 return -1;
396 if (oflags & O_NONBLOCK)
397 return 0;
398 oflags |= O_NONBLOCK;
399 return fcntl(fd, F_SETFL, oflags);
400#endif
401 return 0;
402}
403
404int
405rb_cloexec_pipe(int descriptors[2])
406{
407#ifdef HAVE_PIPE2
408 int result = pipe2(descriptors, O_CLOEXEC | O_NONBLOCK);
409#else
410 int result = pipe(descriptors);
411#endif
412
413 if (result < 0)
414 return result;
415
416#ifdef __CYGWIN__
417 if (result == 0 && descriptors[1] == -1) {
418 close(descriptors[0]);
419 descriptors[0] = -1;
420 errno = ENFILE;
421 return -1;
422 }
423#endif
424
425#ifndef HAVE_PIPE2
426 rb_maygvl_fd_fix_cloexec(descriptors[0]);
427 rb_maygvl_fd_fix_cloexec(descriptors[1]);
428
429#ifndef _WIN32
430 rb_fd_set_nonblock(descriptors[0]);
431 rb_fd_set_nonblock(descriptors[1]);
432#endif
433#endif
434
435 return result;
436}
437
438int
439rb_cloexec_fcntl_dupfd(int fd, int minfd)
440{
441 int ret;
442
443#if defined(HAVE_FCNTL) && defined(F_DUPFD_CLOEXEC) && defined(F_DUPFD)
444 static int try_dupfd_cloexec = 1;
445 if (try_dupfd_cloexec) {
446 ret = fcntl(fd, F_DUPFD_CLOEXEC, minfd);
447 if (ret != -1) {
448 if (ret <= 2)
449 rb_maygvl_fd_fix_cloexec(ret);
450 return ret;
451 }
452 /* F_DUPFD_CLOEXEC is available since Linux 2.6.24. Linux 2.6.18 fails with EINVAL */
453 if (errno == EINVAL) {
454 ret = fcntl(fd, F_DUPFD, minfd);
455 if (ret != -1) {
456 try_dupfd_cloexec = 0;
457 }
458 }
459 }
460 else {
461 ret = fcntl(fd, F_DUPFD, minfd);
462 }
463#elif defined(HAVE_FCNTL) && defined(F_DUPFD)
464 ret = fcntl(fd, F_DUPFD, minfd);
465#else
466 ret = dup(fd);
467 if (ret >= 0 && ret < minfd) {
468 const int prev_fd = ret;
469 ret = rb_cloexec_fcntl_dupfd(fd, minfd);
470 close(prev_fd);
471 }
472 return ret;
473#endif
474 if (ret < 0) return ret;
475 rb_maygvl_fd_fix_cloexec(ret);
476 return ret;
477}
478
479#define argf_of(obj) (*(struct argf *)DATA_PTR(obj))
480#define ARGF argf_of(argf)
481
482#define GetWriteIO(io) rb_io_get_write_io(io)
483
484#define READ_DATA_PENDING(fptr) ((fptr)->rbuf.len)
485#define READ_DATA_PENDING_COUNT(fptr) ((fptr)->rbuf.len)
486#define READ_DATA_PENDING_PTR(fptr) ((fptr)->rbuf.ptr+(fptr)->rbuf.off)
487#define READ_DATA_BUFFERED(fptr) READ_DATA_PENDING(fptr)
488
489#define READ_CHAR_PENDING(fptr) ((fptr)->cbuf.len)
490#define READ_CHAR_PENDING_COUNT(fptr) ((fptr)->cbuf.len)
491#define READ_CHAR_PENDING_PTR(fptr) ((fptr)->cbuf.ptr+(fptr)->cbuf.off)
492
493#if defined(_WIN32)
494#define WAIT_FD_IN_WIN32(fptr) \
495 (rb_w32_io_cancelable_p((fptr)->fd) ? Qnil : rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), RUBY_IO_TIMEOUT_DEFAULT))
496#else
497#define WAIT_FD_IN_WIN32(fptr)
498#endif
499
500#define READ_CHECK(fptr) do {\
501 if (!READ_DATA_PENDING(fptr)) {\
502 WAIT_FD_IN_WIN32(fptr);\
503 rb_io_check_closed(fptr);\
504 }\
505} while(0)
506
507#ifndef S_ISSOCK
508# ifdef _S_ISSOCK
509# define S_ISSOCK(m) _S_ISSOCK(m)
510# else
511# ifdef _S_IFSOCK
512# define S_ISSOCK(m) (((m) & S_IFMT) == _S_IFSOCK)
513# else
514# ifdef S_IFSOCK
515# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
516# endif
517# endif
518# endif
519#endif
520
521static int io_fflush(rb_io_t *);
522static rb_io_t *flush_before_seek(rb_io_t *fptr);
523
524#define FMODE_SIGNAL_ON_EPIPE (1<<17)
525
526#define fptr_signal_on_epipe(fptr) \
527 (((fptr)->mode & FMODE_SIGNAL_ON_EPIPE) != 0)
528
529#define fptr_set_signal_on_epipe(fptr, flag) \
530 ((flag) ? \
531 (fptr)->mode |= FMODE_SIGNAL_ON_EPIPE : \
532 (fptr)->mode &= ~FMODE_SIGNAL_ON_EPIPE)
533
534extern ID ruby_static_id_signo;
535
536NORETURN(static void raise_on_write(rb_io_t *fptr, int e, VALUE errinfo));
537static void
538raise_on_write(rb_io_t *fptr, int e, VALUE errinfo)
539{
540#if defined EPIPE
541 if (fptr_signal_on_epipe(fptr) && (e == EPIPE)) {
542 const VALUE sig =
543# if defined SIGPIPE
544 INT2FIX(SIGPIPE) - INT2FIX(0) +
545# endif
546 INT2FIX(0);
547 rb_ivar_set(errinfo, ruby_static_id_signo, sig);
548 }
549#endif
550 rb_exc_raise(errinfo);
551}
552
553#define rb_sys_fail_on_write(fptr) \
554 do { \
555 int e = errno; \
556 raise_on_write(fptr, e, rb_syserr_new_path(e, (fptr)->pathv)); \
557 } while (0)
558
559#define NEED_NEWLINE_DECORATOR_ON_READ(fptr) ((fptr)->mode & FMODE_TEXTMODE)
560#define NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) ((fptr)->mode & FMODE_TEXTMODE)
561#if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)
562# define RUBY_CRLF_ENVIRONMENT 1
563#else
564# define RUBY_CRLF_ENVIRONMENT 0
565#endif
566
567#if RUBY_CRLF_ENVIRONMENT
568/* Windows */
569# define DEFAULT_TEXTMODE FMODE_TEXTMODE
570# define TEXTMODE_NEWLINE_DECORATOR_ON_WRITE ECONV_CRLF_NEWLINE_DECORATOR
571/*
572 * CRLF newline is set as default newline decorator.
573 * If only CRLF newline conversion is needed, we use binary IO process
574 * with OS's text mode for IO performance improvement.
575 * If encoding conversion is needed or a user sets text mode, we use encoding
576 * conversion IO process and universal newline decorator by default.
577 */
578#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || (fptr)->encs.ecflags & ~ECONV_CRLF_NEWLINE_DECORATOR)
579#define WRITECONV_MASK ( \
580 (ECONV_DECORATOR_MASK & ~ECONV_CRLF_NEWLINE_DECORATOR)|\
581 ECONV_STATEFUL_DECORATOR_MASK|\
582 0)
583#define NEED_WRITECONV(fptr) ( \
584 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
585 ((fptr)->encs.ecflags & WRITECONV_MASK) || \
586 0)
587#define SET_BINARY_MODE(fptr) setmode((fptr)->fd, O_BINARY)
588
589#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) do {\
590 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {\
591 if (((fptr)->mode & FMODE_READABLE) &&\
592 !((fptr)->encs.ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {\
593 setmode((fptr)->fd, O_BINARY);\
594 }\
595 else {\
596 setmode((fptr)->fd, O_TEXT);\
597 }\
598 }\
599} while(0)
600
601#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) do {\
602 if ((enc2) && ((ecflags) & ECONV_DEFAULT_NEWLINE_DECORATOR)) {\
603 (ecflags) |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;\
604 }\
605} while(0)
606
607/*
608 * IO unread with taking care of removed '\r' in text mode.
609 */
610static void
611io_unread(rb_io_t *fptr)
612{
613 rb_off_t r, pos;
614 ssize_t read_size;
615 long i;
616 long newlines = 0;
617 long extra_max;
618 char *p;
619 char *buf;
620
621 rb_io_check_closed(fptr);
622 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX) {
623 return;
624 }
625
626 errno = 0;
627 if (!rb_w32_fd_is_text(fptr->fd)) {
628 r = lseek(fptr->fd, -fptr->rbuf.len, SEEK_CUR);
629 if (r < 0 && errno) {
630 if (errno == ESPIPE)
631 fptr->mode |= FMODE_DUPLEX;
632 return;
633 }
634
635 fptr->rbuf.off = 0;
636 fptr->rbuf.len = 0;
637 return;
638 }
639
640 pos = lseek(fptr->fd, 0, SEEK_CUR);
641 if (pos < 0 && errno) {
642 if (errno == ESPIPE)
643 fptr->mode |= FMODE_DUPLEX;
644 return;
645 }
646
647 /* add extra offset for removed '\r' in rbuf */
648 extra_max = (long)(pos - fptr->rbuf.len);
649 p = fptr->rbuf.ptr + fptr->rbuf.off;
650
651 /* if the end of rbuf is '\r', rbuf doesn't have '\r' within rbuf.len */
652 if (*(fptr->rbuf.ptr + fptr->rbuf.capa - 1) == '\r') {
653 newlines++;
654 }
655
656 for (i = 0; i < fptr->rbuf.len; i++) {
657 if (*p == '\n') newlines++;
658 if (extra_max == newlines) break;
659 p++;
660 }
661
662 buf = ALLOC_N(char, fptr->rbuf.len + newlines);
663 while (newlines >= 0) {
664 r = lseek(fptr->fd, pos - fptr->rbuf.len - newlines, SEEK_SET);
665 if (newlines == 0) break;
666 if (r < 0) {
667 newlines--;
668 continue;
669 }
670 read_size = _read(fptr->fd, buf, fptr->rbuf.len + newlines);
671 if (read_size < 0) {
672 int e = errno;
673 free(buf);
674 rb_syserr_fail_path(e, fptr->pathv);
675 }
676 if (read_size == fptr->rbuf.len) {
677 lseek(fptr->fd, r, SEEK_SET);
678 break;
679 }
680 else {
681 newlines--;
682 }
683 }
684 free(buf);
685 fptr->rbuf.off = 0;
686 fptr->rbuf.len = 0;
687 return;
688}
689
690/*
691 * We use io_seek to back cursor position when changing mode from text to binary,
692 * but stdin and pipe cannot seek back. Stdin and pipe read should use encoding
693 * conversion for working properly with mode change.
694 *
695 * Return previous translation mode.
696 */
697static inline int
698set_binary_mode_with_seek_cur(rb_io_t *fptr)
699{
700 if (!rb_w32_fd_is_text(fptr->fd)) return O_BINARY;
701
702 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX) {
703 return setmode(fptr->fd, O_BINARY);
704 }
705 flush_before_seek(fptr);
706 return setmode(fptr->fd, O_BINARY);
707}
708#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) set_binary_mode_with_seek_cur(fptr)
709
710#else
711/* Unix */
712# define DEFAULT_TEXTMODE 0
713#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || NEED_NEWLINE_DECORATOR_ON_READ(fptr))
714#define NEED_WRITECONV(fptr) ( \
715 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
716 NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) || \
717 ((fptr)->encs.ecflags & (ECONV_DECORATOR_MASK|ECONV_STATEFUL_DECORATOR_MASK)) || \
718 0)
719#define SET_BINARY_MODE(fptr) (void)(fptr)
720#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) (void)(fptr)
721#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) ((void)(enc2), (void)(ecflags))
722#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) (void)(fptr)
723#endif
724
725#if !defined HAVE_SHUTDOWN && !defined shutdown
726#define shutdown(a,b) 0
727#endif
728
729#if defined(_WIN32)
730#define is_socket(fd, path) rb_w32_is_socket(fd)
731#elif !defined(S_ISSOCK)
732#define is_socket(fd, path) 0
733#else
734static int
735is_socket(int fd, VALUE path)
736{
737 struct stat sbuf;
738 if (fstat(fd, &sbuf) < 0)
739 rb_sys_fail_path(path);
740 return S_ISSOCK(sbuf.st_mode);
741}
742#endif
743
744static const char closed_stream[] = "closed stream";
745
746static void
747io_fd_check_closed(int fd)
748{
749 if (fd < 0) {
750 rb_thread_check_ints(); /* check for ruby_error_stream_closed */
751 rb_raise(rb_eIOError, closed_stream);
752 }
753}
754
755void
756rb_eof_error(void)
757{
758 rb_raise(rb_eEOFError, "end of file reached");
759}
760
761VALUE
763{
764 rb_check_frozen(io);
765 return io;
766}
767
768void
770{
771 if (!fptr) {
772 rb_raise(rb_eIOError, "uninitialized stream");
773 }
774}
775
776void
778{
780 io_fd_check_closed(fptr->fd);
781}
782
783static rb_io_t *
784rb_io_get_fptr(VALUE io)
785{
786 rb_io_t *fptr = RFILE(io)->fptr;
788 return fptr;
789}
790
791VALUE
793{
794 return rb_convert_type_with_id(io, T_FILE, "IO", idTo_io);
795}
796
797VALUE
799{
800 return rb_check_convert_type_with_id(io, T_FILE, "IO", idTo_io);
801}
802
803VALUE
805{
806 VALUE write_io;
807 write_io = rb_io_get_fptr(io)->tied_io_for_writing;
808 if (write_io) {
809 return write_io;
810 }
811 return io;
812}
813
814VALUE
816{
817 VALUE write_io;
818 rb_io_t *fptr = rb_io_get_fptr(io);
819 if (!RTEST(w)) {
820 w = 0;
821 }
822 else {
823 GetWriteIO(w);
824 }
825 write_io = fptr->tied_io_for_writing;
826 fptr->tied_io_for_writing = w;
827 return write_io ? write_io : Qnil;
828}
829
830/*
831 * call-seq:
832 * timeout -> duration or nil
833 *
834 * Get the internal timeout duration or nil if it was not set.
835 *
836 */
837VALUE
839{
840 rb_io_t *fptr = rb_io_get_fptr(self);
841
842 return fptr->timeout;
843}
844
845/*
846 * call-seq:
847 * timeout = duration -> duration
848 * timeout = nil -> nil
849 *
850 * Sets the internal timeout to the specified duration or nil. The timeout
851 * applies to all blocking operations where possible.
852 *
853 * When the operation performs longer than the timeout set, IO::TimeoutError
854 * is raised.
855 *
856 * This affects the following methods (but is not limited to): #gets, #puts,
857 * #read, #write, #wait_readable and #wait_writable. This also affects
858 * blocking socket operations like Socket#accept and Socket#connect.
859 *
860 * Some operations like File#open and IO#close are not affected by the
861 * timeout. A timeout during a write operation may leave the IO in an
862 * inconsistent state, e.g. data was partially written. Generally speaking, a
863 * timeout is a last ditch effort to prevent an application from hanging on
864 * slow I/O operations, such as those that occur during a slowloris attack.
865 */
866VALUE
868{
869 // Validate it:
870 if (RTEST(timeout)) {
871 rb_time_interval(timeout);
872 }
873
874 rb_io_t *fptr = rb_io_get_fptr(self);
875
876 fptr->timeout = timeout;
877
878 return self;
879}
880
881/*
882 * call-seq:
883 * IO.try_convert(object) -> new_io or nil
884 *
885 * Attempts to convert +object+ into an \IO object via method +to_io+;
886 * returns the new \IO object if successful, or +nil+ otherwise:
887 *
888 * IO.try_convert(STDOUT) # => #<IO:<STDOUT>>
889 * IO.try_convert(ARGF) # => #<IO:<STDIN>>
890 * IO.try_convert('STDOUT') # => nil
891 *
892 */
893static VALUE
894rb_io_s_try_convert(VALUE dummy, VALUE io)
895{
896 return rb_io_check_io(io);
897}
898
899#if !RUBY_CRLF_ENVIRONMENT
900static void
901io_unread(rb_io_t *fptr)
902{
903 rb_off_t r;
904 rb_io_check_closed(fptr);
905 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX)
906 return;
907 /* xxx: target position may be negative if buffer is filled by ungetc */
908 errno = 0;
909 r = lseek(fptr->fd, -fptr->rbuf.len, SEEK_CUR);
910 if (r < 0 && errno) {
911 if (errno == ESPIPE)
912 fptr->mode |= FMODE_DUPLEX;
913 return;
914 }
915 fptr->rbuf.off = 0;
916 fptr->rbuf.len = 0;
917 return;
918}
919#endif
920
921static rb_encoding *io_input_encoding(rb_io_t *fptr);
922
923static void
924io_ungetbyte(VALUE str, rb_io_t *fptr)
925{
926 long len = RSTRING_LEN(str);
927
928 if (fptr->rbuf.ptr == NULL) {
929 const int min_capa = IO_RBUF_CAPA_FOR(fptr);
930 fptr->rbuf.off = 0;
931 fptr->rbuf.len = 0;
932#if SIZEOF_LONG > SIZEOF_INT
933 if (len > INT_MAX)
934 rb_raise(rb_eIOError, "ungetbyte failed");
935#endif
936 if (len > min_capa)
937 fptr->rbuf.capa = (int)len;
938 else
939 fptr->rbuf.capa = min_capa;
940 fptr->rbuf.ptr = ALLOC_N(char, fptr->rbuf.capa);
941 }
942 if (fptr->rbuf.capa < len + fptr->rbuf.len) {
943 rb_raise(rb_eIOError, "ungetbyte failed");
944 }
945 if (fptr->rbuf.off < len) {
946 MEMMOVE(fptr->rbuf.ptr+fptr->rbuf.capa-fptr->rbuf.len,
947 fptr->rbuf.ptr+fptr->rbuf.off,
948 char, fptr->rbuf.len);
949 fptr->rbuf.off = fptr->rbuf.capa-fptr->rbuf.len;
950 }
951 fptr->rbuf.off-=(int)len;
952 fptr->rbuf.len+=(int)len;
953 MEMMOVE(fptr->rbuf.ptr+fptr->rbuf.off, RSTRING_PTR(str), char, len);
954}
955
956static rb_io_t *
957flush_before_seek(rb_io_t *fptr)
958{
959 if (io_fflush(fptr) < 0)
960 rb_sys_fail_on_write(fptr);
961 io_unread(fptr);
962 errno = 0;
963 return fptr;
964}
965
966#define io_seek(fptr, ofs, whence) (errno = 0, lseek(flush_before_seek(fptr)->fd, (ofs), (whence)))
967#define io_tell(fptr) lseek(flush_before_seek(fptr)->fd, 0, SEEK_CUR)
968
969#ifndef SEEK_CUR
970# define SEEK_SET 0
971# define SEEK_CUR 1
972# define SEEK_END 2
973#endif
974
975void
977{
978 rb_io_check_closed(fptr);
979 if (!(fptr->mode & FMODE_READABLE)) {
980 rb_raise(rb_eIOError, "not opened for reading");
981 }
982 if (fptr->wbuf.len) {
983 if (io_fflush(fptr) < 0)
984 rb_sys_fail_on_write(fptr);
985 }
986 if (fptr->tied_io_for_writing) {
987 rb_io_t *wfptr;
988 GetOpenFile(fptr->tied_io_for_writing, wfptr);
989 if (io_fflush(wfptr) < 0)
990 rb_sys_fail_on_write(wfptr);
991 }
992}
993
994void
996{
998 if (READ_CHAR_PENDING(fptr)) {
999 rb_raise(rb_eIOError, "byte oriented read for character buffered IO");
1000 }
1001}
1002
1003void
1008
1009static rb_encoding*
1010io_read_encoding(rb_io_t *fptr)
1011{
1012 if (fptr->encs.enc) {
1013 return fptr->encs.enc;
1014 }
1015 return rb_default_external_encoding();
1016}
1017
1018static rb_encoding*
1019io_input_encoding(rb_io_t *fptr)
1020{
1021 if (fptr->encs.enc2) {
1022 return fptr->encs.enc2;
1023 }
1024 return io_read_encoding(fptr);
1025}
1026
1027void
1029{
1030 rb_io_check_closed(fptr);
1031 if (!(fptr->mode & FMODE_WRITABLE)) {
1032 rb_raise(rb_eIOError, "not opened for writing");
1033 }
1034 if (fptr->rbuf.len) {
1035 io_unread(fptr);
1036 }
1037}
1038
1039int
1040rb_io_read_pending(rb_io_t *fptr)
1041{
1042 /* This function is used for bytes and chars. Confusing. */
1043 if (READ_CHAR_PENDING(fptr))
1044 return 1; /* should raise? */
1045 return READ_DATA_PENDING(fptr);
1046}
1047
1048void
1050{
1051 if (!READ_DATA_PENDING(fptr)) {
1052 rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), RUBY_IO_TIMEOUT_DEFAULT);
1053 }
1054 return;
1055}
1056
1057int
1058rb_gc_for_fd(int err)
1059{
1060 if (err == EMFILE || err == ENFILE || err == ENOMEM) {
1061 rb_gc();
1062 return 1;
1063 }
1064 return 0;
1065}
1066
1067/* try `expr` upto twice while it returns false and `errno`
1068 * is to GC. Each `errno`s are available as `first_errno` and
1069 * `retried_errno` respectively */
1070#define TRY_WITH_GC(expr) \
1071 for (int first_errno, retried_errno = 0, retried = 0; \
1072 (!retried && \
1073 !(expr) && \
1074 (!rb_gc_for_fd(first_errno = errno) || !(expr)) && \
1075 (retried_errno = errno, 1)); \
1076 (void)retried_errno, retried = 1)
1077
1078static int
1079ruby_dup(int orig)
1080{
1081 int fd = -1;
1082
1083 TRY_WITH_GC((fd = rb_cloexec_dup(orig)) >= 0) {
1084 rb_syserr_fail(first_errno, 0);
1085 }
1086 rb_update_max_fd(fd);
1087 return fd;
1088}
1089
1090static VALUE
1091io_alloc(VALUE klass)
1092{
1093 NEWOBJ_OF(io, struct RFile, klass, T_FILE, sizeof(struct RFile), 0);
1094
1095 io->fptr = 0;
1096
1097 return (VALUE)io;
1098}
1099
1100#ifndef S_ISREG
1101# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
1102#endif
1103
1105 VALUE th;
1106 rb_io_t *fptr;
1107 int nonblock;
1108 int fd;
1109
1110 void *buf;
1111 size_t capa;
1112 struct timeval *timeout;
1113};
1114
1116 VALUE th;
1117 rb_io_t *fptr;
1118 int nonblock;
1119 int fd;
1120
1121 const void *buf;
1122 size_t capa;
1123 struct timeval *timeout;
1124};
1125
1126#ifdef HAVE_WRITEV
1127struct io_internal_writev_struct {
1128 VALUE th;
1129 rb_io_t *fptr;
1130 int nonblock;
1131 int fd;
1132
1133 int iovcnt;
1134 const struct iovec *iov;
1135 struct timeval *timeout;
1136};
1137#endif
1138
1139static int nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout);
1140
1146static inline int
1147io_internal_wait(VALUE thread, rb_io_t *fptr, int error, int events, struct timeval *timeout)
1148{
1149 int ready = nogvl_wait_for(thread, fptr, events, timeout);
1150
1151 if (ready > 0) {
1152 return ready;
1153 }
1154 else if (ready == 0) {
1155 errno = ETIMEDOUT;
1156 return -1;
1157 }
1158
1159 errno = error;
1160 return -1;
1161}
1162
1163static VALUE
1164internal_read_func(void *ptr)
1165{
1166 struct io_internal_read_struct *iis = ptr;
1167 ssize_t result;
1168
1169 if (iis->timeout && !iis->nonblock) {
1170 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_IN, iis->timeout) == -1) {
1171 return -1;
1172 }
1173 }
1174
1175 retry:
1176 result = read(iis->fd, iis->buf, iis->capa);
1177
1178 if (result < 0 && !iis->nonblock) {
1179 if (io_again_p(errno)) {
1180 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_IN, iis->timeout) == -1) {
1181 return -1;
1182 }
1183 else {
1184 goto retry;
1185 }
1186 }
1187 }
1188
1189 return result;
1190}
1191
1192#if defined __APPLE__
1193# define do_write_retry(code) do {result = code;} while (result == -1 && errno == EPROTOTYPE)
1194#else
1195# define do_write_retry(code) result = code
1196#endif
1197
1198static VALUE
1199internal_write_func(void *ptr)
1200{
1201 struct io_internal_write_struct *iis = ptr;
1202 ssize_t result;
1203
1204 if (iis->timeout && !iis->nonblock) {
1205 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1206 return -1;
1207 }
1208 }
1209
1210 retry:
1211 do_write_retry(write(iis->fd, iis->buf, iis->capa));
1212
1213 if (result < 0 && !iis->nonblock) {
1214 int e = errno;
1215 if (io_again_p(e)) {
1216 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1217 return -1;
1218 }
1219 else {
1220 goto retry;
1221 }
1222 }
1223 }
1224
1225 return result;
1226}
1227
1228#ifdef HAVE_WRITEV
1229static VALUE
1230internal_writev_func(void *ptr)
1231{
1232 struct io_internal_writev_struct *iis = ptr;
1233 ssize_t result;
1234
1235 if (iis->timeout && !iis->nonblock) {
1236 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1237 return -1;
1238 }
1239 }
1240
1241 retry:
1242 do_write_retry(writev(iis->fd, iis->iov, iis->iovcnt));
1243
1244 if (result < 0 && !iis->nonblock) {
1245 if (io_again_p(errno)) {
1246 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1247 return -1;
1248 }
1249 else {
1250 goto retry;
1251 }
1252 }
1253 }
1254
1255 return result;
1256}
1257#endif
1258
1259static ssize_t
1260rb_io_read_memory(rb_io_t *fptr, void *buf, size_t count)
1261{
1262 VALUE scheduler = rb_fiber_scheduler_current();
1263 if (scheduler != Qnil) {
1264 VALUE result = rb_fiber_scheduler_io_read_memory(scheduler, fptr->self, buf, count, 0);
1265
1266 if (!UNDEF_P(result)) {
1268 }
1269 }
1270
1271 struct io_internal_read_struct iis = {
1272 .th = rb_thread_current(),
1273 .fptr = fptr,
1274 .nonblock = 0,
1275 .fd = fptr->fd,
1276
1277 .buf = buf,
1278 .capa = count,
1279 .timeout = NULL,
1280 };
1281
1282 struct timeval timeout_storage;
1283
1284 if (fptr->timeout != Qnil) {
1285 timeout_storage = rb_time_interval(fptr->timeout);
1286 iis.timeout = &timeout_storage;
1287 }
1288
1289 return (ssize_t)rb_thread_io_blocking_call(internal_read_func, &iis, fptr->fd, RB_WAITFD_IN);
1290}
1291
1292static ssize_t
1293rb_io_write_memory(rb_io_t *fptr, const void *buf, size_t count)
1294{
1295 VALUE scheduler = rb_fiber_scheduler_current();
1296 if (scheduler != Qnil) {
1297 VALUE result = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, buf, count, 0);
1298
1299 if (!UNDEF_P(result)) {
1301 }
1302 }
1303
1304 struct io_internal_write_struct iis = {
1305 .th = rb_thread_current(),
1306 .fptr = fptr,
1307 .nonblock = 0,
1308 .fd = fptr->fd,
1309
1310 .buf = buf,
1311 .capa = count,
1312 .timeout = NULL
1313 };
1314
1315 struct timeval timeout_storage;
1316
1317 if (fptr->timeout != Qnil) {
1318 timeout_storage = rb_time_interval(fptr->timeout);
1319 iis.timeout = &timeout_storage;
1320 }
1321
1322 return (ssize_t)rb_thread_io_blocking_call(internal_write_func, &iis, fptr->fd, RB_WAITFD_OUT);
1323}
1324
1325#ifdef HAVE_WRITEV
1326static ssize_t
1327rb_writev_internal(rb_io_t *fptr, const struct iovec *iov, int iovcnt)
1328{
1329 if (!iovcnt) return 0;
1330
1331 VALUE scheduler = rb_fiber_scheduler_current();
1332 if (scheduler != Qnil) {
1333 // This path assumes at least one `iov`:
1334 VALUE result = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, iov[0].iov_base, iov[0].iov_len, 0);
1335
1336 if (!UNDEF_P(result)) {
1338 }
1339 }
1340
1341 struct io_internal_writev_struct iis = {
1342 .th = rb_thread_current(),
1343 .fptr = fptr,
1344 .nonblock = 0,
1345 .fd = fptr->fd,
1346
1347 .iov = iov,
1348 .iovcnt = iovcnt,
1349 .timeout = NULL
1350 };
1351
1352 struct timeval timeout_storage;
1353
1354 if (fptr->timeout != Qnil) {
1355 timeout_storage = rb_time_interval(fptr->timeout);
1356 iis.timeout = &timeout_storage;
1357 }
1358
1359 return (ssize_t)rb_thread_io_blocking_call(internal_writev_func, &iis, fptr->fd, RB_WAITFD_OUT);
1360}
1361#endif
1362
1363static VALUE
1364io_flush_buffer_sync(void *arg)
1365{
1366 rb_io_t *fptr = arg;
1367 long l = fptr->wbuf.len;
1368 ssize_t r = write(fptr->fd, fptr->wbuf.ptr+fptr->wbuf.off, (size_t)l);
1369
1370 if (fptr->wbuf.len <= r) {
1371 fptr->wbuf.off = 0;
1372 fptr->wbuf.len = 0;
1373 return 0;
1374 }
1375
1376 if (0 <= r) {
1377 fptr->wbuf.off += (int)r;
1378 fptr->wbuf.len -= (int)r;
1379 errno = EAGAIN;
1380 }
1381
1382 return (VALUE)-1;
1383}
1384
1385static VALUE
1386io_flush_buffer_async(VALUE arg)
1387{
1388 rb_io_t *fptr = (rb_io_t *)arg;
1389 return rb_thread_io_blocking_call(io_flush_buffer_sync, fptr, fptr->fd, RB_WAITFD_OUT);
1390}
1391
1392static inline int
1393io_flush_buffer(rb_io_t *fptr)
1394{
1395 if (!NIL_P(fptr->write_lock) && rb_mutex_owned_p(fptr->write_lock)) {
1396 return (int)io_flush_buffer_async((VALUE)fptr);
1397 }
1398 else {
1399 return (int)rb_mutex_synchronize(fptr->write_lock, io_flush_buffer_async, (VALUE)fptr);
1400 }
1401}
1402
1403static int
1404io_fflush(rb_io_t *fptr)
1405{
1406 rb_io_check_closed(fptr);
1407
1408 if (fptr->wbuf.len == 0)
1409 return 0;
1410
1411 while (fptr->wbuf.len > 0 && io_flush_buffer(fptr) != 0) {
1412 if (!rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT))
1413 return -1;
1414
1415 rb_io_check_closed(fptr);
1416 }
1417
1418 return 0;
1419}
1420
1421VALUE
1422rb_io_wait(VALUE io, VALUE events, VALUE timeout)
1423{
1424 VALUE scheduler = rb_fiber_scheduler_current();
1425
1426 if (scheduler != Qnil) {
1427 return rb_fiber_scheduler_io_wait(scheduler, io, events, timeout);
1428 }
1429
1430 rb_io_t * fptr = NULL;
1431 RB_IO_POINTER(io, fptr);
1432
1433 struct timeval tv_storage;
1434 struct timeval *tv = NULL;
1435
1436 if (NIL_OR_UNDEF_P(timeout)) {
1437 timeout = fptr->timeout;
1438 }
1439
1440 if (timeout != Qnil) {
1441 tv_storage = rb_time_interval(timeout);
1442 tv = &tv_storage;
1443 }
1444
1445 int ready = rb_thread_wait_for_single_fd(fptr->fd, RB_NUM2INT(events), tv);
1446
1447 if (ready < 0) {
1448 rb_sys_fail(0);
1449 }
1450
1451 // Not sure if this is necessary:
1452 rb_io_check_closed(fptr);
1453
1454 if (ready) {
1455 return RB_INT2NUM(ready);
1456 }
1457 else {
1458 return Qfalse;
1459 }
1460}
1461
1462static VALUE
1463io_from_fd(int fd)
1464{
1465 return prep_io(fd, FMODE_EXTERNAL, rb_cIO, NULL);
1466}
1467
1468static int
1469io_wait_for_single_fd(int fd, int events, struct timeval *timeout)
1470{
1471 VALUE scheduler = rb_fiber_scheduler_current();
1472
1473 if (scheduler != Qnil) {
1474 return RTEST(
1475 rb_fiber_scheduler_io_wait(scheduler, io_from_fd(fd), RB_INT2NUM(events), rb_fiber_scheduler_make_timeout(timeout))
1476 );
1477 }
1478
1479 return rb_thread_wait_for_single_fd(fd, events, timeout);
1480}
1481
1482int
1484{
1485 io_fd_check_closed(f);
1486
1487 VALUE scheduler = rb_fiber_scheduler_current();
1488
1489 switch (errno) {
1490 case EINTR:
1491#if defined(ERESTART)
1492 case ERESTART:
1493#endif
1495 return TRUE;
1496
1497 case EAGAIN:
1498#if EWOULDBLOCK != EAGAIN
1499 case EWOULDBLOCK:
1500#endif
1501 if (scheduler != Qnil) {
1502 return RTEST(
1503 rb_fiber_scheduler_io_wait_readable(scheduler, io_from_fd(f))
1504 );
1505 }
1506 else {
1507 io_wait_for_single_fd(f, RUBY_IO_READABLE, NULL);
1508 }
1509 return TRUE;
1510
1511 default:
1512 return FALSE;
1513 }
1514}
1515
1516int
1518{
1519 io_fd_check_closed(f);
1520
1521 VALUE scheduler = rb_fiber_scheduler_current();
1522
1523 switch (errno) {
1524 case EINTR:
1525#if defined(ERESTART)
1526 case ERESTART:
1527#endif
1528 /*
1529 * In old Linux, several special files under /proc and /sys don't handle
1530 * select properly. Thus we need avoid to call if don't use O_NONBLOCK.
1531 * Otherwise, we face nasty hang up. Sigh.
1532 * e.g. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1533 * https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1534 * In EINTR case, we only need to call RUBY_VM_CHECK_INTS_BLOCKING().
1535 * Then rb_thread_check_ints() is enough.
1536 */
1538 return TRUE;
1539
1540 case EAGAIN:
1541#if EWOULDBLOCK != EAGAIN
1542 case EWOULDBLOCK:
1543#endif
1544 if (scheduler != Qnil) {
1545 return RTEST(
1546 rb_fiber_scheduler_io_wait_writable(scheduler, io_from_fd(f))
1547 );
1548 }
1549 else {
1550 io_wait_for_single_fd(f, RUBY_IO_WRITABLE, NULL);
1551 }
1552 return TRUE;
1553
1554 default:
1555 return FALSE;
1556 }
1557}
1558
1559int
1560rb_wait_for_single_fd(int fd, int events, struct timeval *timeout)
1561{
1562 return io_wait_for_single_fd(fd, events, timeout);
1563}
1564
1565int
1567{
1568 return rb_wait_for_single_fd(fd, RUBY_IO_READABLE, NULL);
1569}
1570
1571int
1573{
1574 return rb_wait_for_single_fd(fd, RUBY_IO_WRITABLE, NULL);
1575}
1576
1577VALUE
1578rb_io_maybe_wait(int error, VALUE io, VALUE events, VALUE timeout)
1579{
1580 // fptr->fd can be set to -1 at any time by another thread when the GVL is
1581 // released. Many code, e.g. `io_bufread` didn't check this correctly and
1582 // instead relies on `read(-1) -> -1` which causes this code path. We then
1583 // check here whether the IO was in fact closed. Probably it's better to
1584 // check that `fptr->fd != -1` before using it in syscall.
1585 rb_io_check_closed(RFILE(io)->fptr);
1586
1587 switch (error) {
1588 // In old Linux, several special files under /proc and /sys don't handle
1589 // select properly. Thus we need avoid to call if don't use O_NONBLOCK.
1590 // Otherwise, we face nasty hang up. Sigh.
1591 // e.g. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1592 // https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1593 // In EINTR case, we only need to call RUBY_VM_CHECK_INTS_BLOCKING().
1594 // Then rb_thread_check_ints() is enough.
1595 case EINTR:
1596#if defined(ERESTART)
1597 case ERESTART:
1598#endif
1599 // We might have pending interrupts since the previous syscall was interrupted:
1601
1602 // The operation was interrupted, so retry it immediately:
1603 return events;
1604
1605 case EAGAIN:
1606#if EWOULDBLOCK != EAGAIN
1607 case EWOULDBLOCK:
1608#endif
1609 // The operation would block, so wait for the specified events:
1610 return rb_io_wait(io, events, timeout);
1611
1612 default:
1613 // Non-specific error, no event is ready:
1614 return Qfalse;
1615 }
1616}
1617
1618int
1620{
1621 VALUE result = rb_io_maybe_wait(error, io, RB_INT2NUM(RUBY_IO_READABLE), timeout);
1622
1623 if (RTEST(result)) {
1624 return RB_NUM2INT(result);
1625 }
1626 else {
1627 return 0;
1628 }
1629}
1630
1631int
1633{
1634 VALUE result = rb_io_maybe_wait(error, io, RB_INT2NUM(RUBY_IO_WRITABLE), timeout);
1635
1636 if (RTEST(result)) {
1637 return RB_NUM2INT(result);
1638 }
1639 else {
1640 return 0;
1641 }
1642}
1643
1644static void
1645make_writeconv(rb_io_t *fptr)
1646{
1647 if (!fptr->writeconv_initialized) {
1648 const char *senc, *denc;
1649 rb_encoding *enc;
1650 int ecflags;
1651 VALUE ecopts;
1652
1653 fptr->writeconv_initialized = 1;
1654
1655 ecflags = fptr->encs.ecflags & ~ECONV_NEWLINE_DECORATOR_READ_MASK;
1656 ecopts = fptr->encs.ecopts;
1657
1658 if (!fptr->encs.enc || (rb_is_ascii8bit_enc(fptr->encs.enc) && !fptr->encs.enc2)) {
1659 /* no encoding conversion */
1660 fptr->writeconv_pre_ecflags = 0;
1661 fptr->writeconv_pre_ecopts = Qnil;
1662 fptr->writeconv = rb_econv_open_opts("", "", ecflags, ecopts);
1663 if (!fptr->writeconv)
1664 rb_exc_raise(rb_econv_open_exc("", "", ecflags));
1666 }
1667 else {
1668 enc = fptr->encs.enc2 ? fptr->encs.enc2 : fptr->encs.enc;
1669 senc = rb_econv_asciicompat_encoding(rb_enc_name(enc));
1670 if (!senc && !(fptr->encs.ecflags & ECONV_STATEFUL_DECORATOR_MASK)) {
1671 /* single conversion */
1672 fptr->writeconv_pre_ecflags = ecflags;
1673 fptr->writeconv_pre_ecopts = ecopts;
1674 fptr->writeconv = NULL;
1676 }
1677 else {
1678 /* double conversion */
1679 fptr->writeconv_pre_ecflags = ecflags & ~ECONV_STATEFUL_DECORATOR_MASK;
1680 fptr->writeconv_pre_ecopts = ecopts;
1681 if (senc) {
1682 denc = rb_enc_name(enc);
1683 fptr->writeconv_asciicompat = rb_str_new2(senc);
1684 }
1685 else {
1686 senc = denc = "";
1687 fptr->writeconv_asciicompat = rb_str_new2(rb_enc_name(enc));
1688 }
1690 ecopts = fptr->encs.ecopts;
1691 fptr->writeconv = rb_econv_open_opts(senc, denc, ecflags, ecopts);
1692 if (!fptr->writeconv)
1693 rb_exc_raise(rb_econv_open_exc(senc, denc, ecflags));
1694 }
1695 }
1696 }
1697}
1698
1699/* writing functions */
1701 rb_io_t *fptr;
1702 VALUE str;
1703 const char *ptr;
1704 long length;
1705};
1706
1708 VALUE io;
1709 VALUE str;
1710 int nosync;
1711};
1712
1713#ifdef HAVE_WRITEV
1714static ssize_t
1715io_binwrite_string_internal(rb_io_t *fptr, const char *ptr, long length)
1716{
1717 if (fptr->wbuf.len) {
1718 struct iovec iov[2];
1719
1720 iov[0].iov_base = fptr->wbuf.ptr+fptr->wbuf.off;
1721 iov[0].iov_len = fptr->wbuf.len;
1722 iov[1].iov_base = (void*)ptr;
1723 iov[1].iov_len = length;
1724
1725 ssize_t result = rb_writev_internal(fptr, iov, 2);
1726
1727 if (result < 0)
1728 return result;
1729
1730 if (result >= fptr->wbuf.len) {
1731 // We wrote more than the internal buffer:
1732 result -= fptr->wbuf.len;
1733 fptr->wbuf.off = 0;
1734 fptr->wbuf.len = 0;
1735 }
1736 else {
1737 // We only wrote less data than the internal buffer:
1738 fptr->wbuf.off += (int)result;
1739 fptr->wbuf.len -= (int)result;
1740
1741 result = 0;
1742 }
1743
1744 return result;
1745 }
1746 else {
1747 return rb_io_write_memory(fptr, ptr, length);
1748 }
1749}
1750#else
1751static ssize_t
1752io_binwrite_string_internal(rb_io_t *fptr, const char *ptr, long length)
1753{
1754 long remaining = length;
1755
1756 if (fptr->wbuf.len) {
1757 if (fptr->wbuf.len+length <= fptr->wbuf.capa) {
1758 if (fptr->wbuf.capa < fptr->wbuf.off+fptr->wbuf.len+length) {
1759 MEMMOVE(fptr->wbuf.ptr, fptr->wbuf.ptr+fptr->wbuf.off, char, fptr->wbuf.len);
1760 fptr->wbuf.off = 0;
1761 }
1762
1763 MEMMOVE(fptr->wbuf.ptr+fptr->wbuf.off+fptr->wbuf.len, ptr, char, length);
1764 fptr->wbuf.len += (int)length;
1765
1766 // We copied the entire incoming data to the internal buffer:
1767 remaining = 0;
1768 }
1769
1770 // Flush the internal buffer:
1771 if (io_fflush(fptr) < 0) {
1772 return -1;
1773 }
1774
1775 // If all the data was buffered, we are done:
1776 if (remaining == 0) {
1777 return length;
1778 }
1779 }
1780
1781 // Otherwise, we should write the data directly:
1782 return rb_io_write_memory(fptr, ptr, length);
1783}
1784#endif
1785
1786static VALUE
1787io_binwrite_string(VALUE arg)
1788{
1789 struct binwrite_arg *p = (struct binwrite_arg *)arg;
1790
1791 const char *ptr = p->ptr;
1792 size_t remaining = p->length;
1793
1794 while (remaining) {
1795 // Write as much as possible:
1796 ssize_t result = io_binwrite_string_internal(p->fptr, ptr, remaining);
1797
1798 // If only the internal buffer is written, result will be zero [bytes of given data written]. This means we
1799 // should try again.
1800 if (result == 0) {
1801 errno = EWOULDBLOCK;
1802 }
1803
1804 if (result > 0) {
1805 if ((size_t)result == remaining) break;
1806 ptr += result;
1807 remaining -= result;
1808 }
1809 // Wait for it to become writable:
1810 else if (rb_io_maybe_wait_writable(errno, p->fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
1811 rb_io_check_closed(p->fptr);
1812 }
1813 else {
1814 // The error was unrelated to waiting for it to become writable, so we fail:
1815 return -1;
1816 }
1817 }
1818
1819 return p->length;
1820}
1821
1822inline static void
1823io_allocate_write_buffer(rb_io_t *fptr, int sync)
1824{
1825 if (fptr->wbuf.ptr == NULL && !(sync && (fptr->mode & FMODE_SYNC))) {
1826 fptr->wbuf.off = 0;
1827 fptr->wbuf.len = 0;
1828 fptr->wbuf.capa = IO_WBUF_CAPA_MIN;
1829 fptr->wbuf.ptr = ALLOC_N(char, fptr->wbuf.capa);
1830 }
1831
1832 if (NIL_P(fptr->write_lock)) {
1833 fptr->write_lock = rb_mutex_new();
1834 rb_mutex_allow_trap(fptr->write_lock, 1);
1835 }
1836}
1837
1838static inline int
1839io_binwrite_requires_flush_write(rb_io_t *fptr, long len, int nosync)
1840{
1841 // If the requested operation was synchronous and the output mode is synchronous or a TTY:
1842 if (!nosync && (fptr->mode & (FMODE_SYNC|FMODE_TTY)))
1843 return 1;
1844
1845 // If the amount of data we want to write exceeds the internal buffer:
1846 if (fptr->wbuf.ptr && fptr->wbuf.capa <= fptr->wbuf.len + len)
1847 return 1;
1848
1849 // Otherwise, we can append to the internal buffer:
1850 return 0;
1851}
1852
1853static long
1854io_binwrite(VALUE str, const char *ptr, long len, rb_io_t *fptr, int nosync)
1855{
1856 if (len <= 0) return len;
1857
1858 // Don't write anything if current thread has a pending interrupt:
1860
1861 io_allocate_write_buffer(fptr, !nosync);
1862
1863 if (io_binwrite_requires_flush_write(fptr, len, nosync)) {
1864 struct binwrite_arg arg;
1865
1866 arg.fptr = fptr;
1867 arg.str = str;
1868 arg.ptr = ptr;
1869 arg.length = len;
1870
1871 if (!NIL_P(fptr->write_lock)) {
1872 return rb_mutex_synchronize(fptr->write_lock, io_binwrite_string, (VALUE)&arg);
1873 }
1874 else {
1875 return io_binwrite_string((VALUE)&arg);
1876 }
1877 }
1878 else {
1879 if (fptr->wbuf.off) {
1880 if (fptr->wbuf.len)
1881 MEMMOVE(fptr->wbuf.ptr, fptr->wbuf.ptr+fptr->wbuf.off, char, fptr->wbuf.len);
1882 fptr->wbuf.off = 0;
1883 }
1884
1885 MEMMOVE(fptr->wbuf.ptr+fptr->wbuf.off+fptr->wbuf.len, ptr, char, len);
1886 fptr->wbuf.len += (int)len;
1887
1888 return len;
1889 }
1890}
1891
1892# define MODE_BTMODE(a,b,c) ((fmode & FMODE_BINMODE) ? (b) : \
1893 (fmode & FMODE_TEXTMODE) ? (c) : (a))
1894
1895#define MODE_BTXMODE(a, b, c, d, e, f) ((fmode & FMODE_EXCL) ? \
1896 MODE_BTMODE(d, e, f) : \
1897 MODE_BTMODE(a, b, c))
1898
1899static VALUE
1900do_writeconv(VALUE str, rb_io_t *fptr, int *converted)
1901{
1902 if (NEED_WRITECONV(fptr)) {
1903 VALUE common_encoding = Qnil;
1904 SET_BINARY_MODE(fptr);
1905
1906 make_writeconv(fptr);
1907
1908 if (fptr->writeconv) {
1909#define fmode (fptr->mode)
1910 if (!NIL_P(fptr->writeconv_asciicompat))
1911 common_encoding = fptr->writeconv_asciicompat;
1912 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1) && !rb_enc_asciicompat(rb_enc_get(str))) {
1913 rb_raise(rb_eArgError, "ASCII incompatible string written for text mode IO without encoding conversion: %s",
1914 rb_enc_name(rb_enc_get(str)));
1915 }
1916#undef fmode
1917 }
1918 else {
1919 if (fptr->encs.enc2)
1920 common_encoding = rb_enc_from_encoding(fptr->encs.enc2);
1921 else if (fptr->encs.enc != rb_ascii8bit_encoding())
1922 common_encoding = rb_enc_from_encoding(fptr->encs.enc);
1923 }
1924
1925 if (!NIL_P(common_encoding)) {
1926 str = rb_str_encode(str, common_encoding,
1928 *converted = 1;
1929 }
1930
1931 if (fptr->writeconv) {
1933 *converted = 1;
1934 }
1935 }
1936#if RUBY_CRLF_ENVIRONMENT
1937#define fmode (fptr->mode)
1938 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1)) {
1939 if ((fptr->mode & FMODE_READABLE) &&
1941 setmode(fptr->fd, O_BINARY);
1942 }
1943 else {
1944 setmode(fptr->fd, O_TEXT);
1945 }
1946 if (!rb_enc_asciicompat(rb_enc_get(str))) {
1947 rb_raise(rb_eArgError, "ASCII incompatible string written for text mode IO without encoding conversion: %s",
1948 rb_enc_name(rb_enc_get(str)));
1949 }
1950 }
1951#undef fmode
1952#endif
1953 return str;
1954}
1955
1956static long
1957io_fwrite(VALUE str, rb_io_t *fptr, int nosync)
1958{
1959 int converted = 0;
1960 VALUE tmp;
1961 long n, len;
1962 const char *ptr;
1963
1964#ifdef _WIN32
1965 if (fptr->mode & FMODE_TTY) {
1966 long len = rb_w32_write_console(str, fptr->fd);
1967 if (len > 0) return len;
1968 }
1969#endif
1970
1971 str = do_writeconv(str, fptr, &converted);
1972 if (converted)
1973 OBJ_FREEZE(str);
1974
1975 tmp = rb_str_tmp_frozen_acquire(str);
1976 RSTRING_GETMEM(tmp, ptr, len);
1977 n = io_binwrite(tmp, ptr, len, fptr, nosync);
1978 rb_str_tmp_frozen_release(str, tmp);
1979
1980 return n;
1981}
1982
1983ssize_t
1984rb_io_bufwrite(VALUE io, const void *buf, size_t size)
1985{
1986 rb_io_t *fptr;
1987
1988 GetOpenFile(io, fptr);
1990 return (ssize_t)io_binwrite(0, buf, (long)size, fptr, 0);
1991}
1992
1993static VALUE
1994io_write(VALUE io, VALUE str, int nosync)
1995{
1996 rb_io_t *fptr;
1997 long n;
1998 VALUE tmp;
1999
2000 io = GetWriteIO(io);
2001 str = rb_obj_as_string(str);
2002 tmp = rb_io_check_io(io);
2003
2004 if (NIL_P(tmp)) {
2005 /* port is not IO, call write method for it. */
2006 return rb_funcall(io, id_write, 1, str);
2007 }
2008
2009 io = tmp;
2010 if (RSTRING_LEN(str) == 0) return INT2FIX(0);
2011
2012 GetOpenFile(io, fptr);
2014
2015 n = io_fwrite(str, fptr, nosync);
2016 if (n < 0L) rb_sys_fail_on_write(fptr);
2017
2018 return LONG2FIX(n);
2019}
2020
2021#ifdef HAVE_WRITEV
2022struct binwritev_arg {
2023 rb_io_t *fptr;
2024 struct iovec *iov;
2025 int iovcnt;
2026 size_t total;
2027};
2028
2029static VALUE
2030io_binwritev_internal(VALUE arg)
2031{
2032 struct binwritev_arg *p = (struct binwritev_arg *)arg;
2033
2034 size_t remaining = p->total;
2035 size_t offset = 0;
2036
2037 rb_io_t *fptr = p->fptr;
2038 struct iovec *iov = p->iov;
2039 int iovcnt = p->iovcnt;
2040
2041 while (remaining) {
2042 long result = rb_writev_internal(fptr, iov, iovcnt);
2043
2044 if (result >= 0) {
2045 offset += result;
2046 if (fptr->wbuf.ptr && fptr->wbuf.len) {
2047 if (offset < (size_t)fptr->wbuf.len) {
2048 fptr->wbuf.off += result;
2049 fptr->wbuf.len -= result;
2050 }
2051 else {
2052 offset -= (size_t)fptr->wbuf.len;
2053 fptr->wbuf.off = 0;
2054 fptr->wbuf.len = 0;
2055 }
2056 }
2057
2058 if (offset == p->total) {
2059 return p->total;
2060 }
2061
2062 while (result >= (ssize_t)iov->iov_len) {
2063 /* iovcnt > 0 */
2064 result -= iov->iov_len;
2065 iov->iov_len = 0;
2066 iov++;
2067
2068 if (!--iovcnt) {
2069 // I don't believe this code path can ever occur.
2070 return offset;
2071 }
2072 }
2073
2074 iov->iov_base = (char *)iov->iov_base + result;
2075 iov->iov_len -= result;
2076 }
2077 else if (rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
2078 rb_io_check_closed(fptr);
2079 }
2080 else {
2081 return -1;
2082 }
2083 }
2084
2085 return offset;
2086}
2087
2088static long
2089io_binwritev(struct iovec *iov, int iovcnt, rb_io_t *fptr)
2090{
2091 // Don't write anything if current thread has a pending interrupt:
2093
2094 if (iovcnt == 0) return 0;
2095
2096 size_t total = 0;
2097 for (int i = 1; i < iovcnt; i++) total += iov[i].iov_len;
2098
2099 io_allocate_write_buffer(fptr, 1);
2100
2101 if (fptr->wbuf.ptr && fptr->wbuf.len) {
2102 // The end of the buffered data:
2103 size_t offset = fptr->wbuf.off + fptr->wbuf.len;
2104
2105 if (offset + total <= (size_t)fptr->wbuf.capa) {
2106 for (int i = 1; i < iovcnt; i++) {
2107 memcpy(fptr->wbuf.ptr+offset, iov[i].iov_base, iov[i].iov_len);
2108 offset += iov[i].iov_len;
2109 }
2110
2111 fptr->wbuf.len += total;
2112
2113 return total;
2114 }
2115 else {
2116 iov[0].iov_base = fptr->wbuf.ptr + fptr->wbuf.off;
2117 iov[0].iov_len = fptr->wbuf.len;
2118 }
2119 }
2120 else {
2121 // The first iov is reserved for the internal buffer, and it's empty.
2122 iov++;
2123
2124 if (!--iovcnt) {
2125 // If there are no other io vectors we are done.
2126 return 0;
2127 }
2128 }
2129
2130 struct binwritev_arg arg;
2131 arg.fptr = fptr;
2132 arg.iov = iov;
2133 arg.iovcnt = iovcnt;
2134 arg.total = total;
2135
2136 if (!NIL_P(fptr->write_lock)) {
2137 return rb_mutex_synchronize(fptr->write_lock, io_binwritev_internal, (VALUE)&arg);
2138 }
2139 else {
2140 return io_binwritev_internal((VALUE)&arg);
2141 }
2142}
2143
2144static long
2145io_fwritev(int argc, const VALUE *argv, rb_io_t *fptr)
2146{
2147 int i, converted, iovcnt = argc + 1;
2148 long n;
2149 VALUE v1, v2, str, tmp, *tmp_array;
2150 struct iovec *iov;
2151
2152 iov = ALLOCV_N(struct iovec, v1, iovcnt);
2153 tmp_array = ALLOCV_N(VALUE, v2, argc);
2154
2155 for (i = 0; i < argc; i++) {
2156 str = rb_obj_as_string(argv[i]);
2157 converted = 0;
2158 str = do_writeconv(str, fptr, &converted);
2159
2160 if (converted)
2161 OBJ_FREEZE(str);
2162
2163 tmp = rb_str_tmp_frozen_acquire(str);
2164 tmp_array[i] = tmp;
2165
2166 /* iov[0] is reserved for buffer of fptr */
2167 iov[i+1].iov_base = RSTRING_PTR(tmp);
2168 iov[i+1].iov_len = RSTRING_LEN(tmp);
2169 }
2170
2171 n = io_binwritev(iov, iovcnt, fptr);
2172 if (v1) ALLOCV_END(v1);
2173
2174 for (i = 0; i < argc; i++) {
2175 rb_str_tmp_frozen_release(argv[i], tmp_array[i]);
2176 }
2177
2178 if (v2) ALLOCV_END(v2);
2179
2180 return n;
2181}
2182
2183static int
2184iovcnt_ok(int iovcnt)
2185{
2186#ifdef IOV_MAX
2187 return iovcnt < IOV_MAX;
2188#else /* GNU/Hurd has writev, but no IOV_MAX */
2189 return 1;
2190#endif
2191}
2192#endif /* HAVE_WRITEV */
2193
2194static VALUE
2195io_writev(int argc, const VALUE *argv, VALUE io)
2196{
2197 rb_io_t *fptr;
2198 long n;
2199 VALUE tmp, total = INT2FIX(0);
2200 int i, cnt = 1;
2201
2202 io = GetWriteIO(io);
2203 tmp = rb_io_check_io(io);
2204
2205 if (NIL_P(tmp)) {
2206 /* port is not IO, call write method for it. */
2207 return rb_funcallv(io, id_write, argc, argv);
2208 }
2209
2210 io = tmp;
2211
2212 GetOpenFile(io, fptr);
2214
2215 for (i = 0; i < argc; i += cnt) {
2216#ifdef HAVE_WRITEV
2217 if ((fptr->mode & (FMODE_SYNC|FMODE_TTY)) && iovcnt_ok(cnt = argc - i)) {
2218 n = io_fwritev(cnt, &argv[i], fptr);
2219 }
2220 else
2221#endif
2222 {
2223 cnt = 1;
2224 /* sync at last item */
2225 n = io_fwrite(rb_obj_as_string(argv[i]), fptr, (i < argc-1));
2226 }
2227
2228 if (n < 0L)
2229 rb_sys_fail_on_write(fptr);
2230
2231 total = rb_fix_plus(LONG2FIX(n), total);
2232 }
2233
2234 return total;
2235}
2236
2237/*
2238 * call-seq:
2239 * write(*objects) -> integer
2240 *
2241 * Writes each of the given +objects+ to +self+,
2242 * which must be opened for writing
2243 * (see {Access Modes}[rdoc-ref:File@Access+Modes]);
2244 * returns the total number bytes written;
2245 * each of +objects+ that is not a string is converted via method +to_s+:
2246 *
2247 * $stdout.write('Hello', ', ', 'World!', "\n") # => 14
2248 * $stdout.write('foo', :bar, 2, "\n") # => 8
2249 *
2250 * Output:
2251 *
2252 * Hello, World!
2253 * foobar2
2254 *
2255 * Related: IO#read.
2256 */
2257
2258static VALUE
2259io_write_m(int argc, VALUE *argv, VALUE io)
2260{
2261 if (argc != 1) {
2262 return io_writev(argc, argv, io);
2263 }
2264 else {
2265 VALUE str = argv[0];
2266 return io_write(io, str, 0);
2267 }
2268}
2269
2270VALUE
2271rb_io_write(VALUE io, VALUE str)
2272{
2273 return rb_funcallv(io, id_write, 1, &str);
2274}
2275
2276static VALUE
2277rb_io_writev(VALUE io, int argc, const VALUE *argv)
2278{
2279 if (argc > 1 && rb_obj_method_arity(io, id_write) == 1) {
2280 if (io != rb_ractor_stderr() && RTEST(ruby_verbose)) {
2281 VALUE klass = CLASS_OF(io);
2282 char sep = FL_TEST(klass, FL_SINGLETON) ? (klass = io, '.') : '#';
2284 RB_WARN_CATEGORY_DEPRECATED, "%+"PRIsVALUE"%c""write is outdated interface"
2285 " which accepts just one argument",
2286 klass, sep
2287 );
2288 }
2289
2290 do rb_io_write(io, *argv++); while (--argc);
2291
2292 return Qnil;
2293 }
2294
2295 return rb_funcallv(io, id_write, argc, argv);
2296}
2297
2298/*
2299 * call-seq:
2300 * self << object -> self
2301 *
2302 * Writes the given +object+ to +self+,
2303 * which must be opened for writing (see {Access Modes}[rdoc-ref:File@Access+Modes]);
2304 * returns +self+;
2305 * if +object+ is not a string, it is converted via method +to_s+:
2306 *
2307 * $stdout << 'Hello' << ', ' << 'World!' << "\n"
2308 * $stdout << 'foo' << :bar << 2 << "\n"
2309 *
2310 * Output:
2311 *
2312 * Hello, World!
2313 * foobar2
2314 *
2315 */
2316
2317
2318VALUE
2320{
2321 rb_io_write(io, str);
2322 return io;
2323}
2324
2325#ifdef HAVE_FSYNC
2326static VALUE
2327nogvl_fsync(void *ptr)
2328{
2329 rb_io_t *fptr = ptr;
2330
2331#ifdef _WIN32
2332 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->fd)) != FILE_TYPE_DISK)
2333 return 0;
2334#endif
2335 return (VALUE)fsync(fptr->fd);
2336}
2337#endif
2338
2339VALUE
2340rb_io_flush_raw(VALUE io, int sync)
2341{
2342 rb_io_t *fptr;
2343
2344 if (!RB_TYPE_P(io, T_FILE)) {
2345 return rb_funcall(io, id_flush, 0);
2346 }
2347
2348 io = GetWriteIO(io);
2349 GetOpenFile(io, fptr);
2350
2351 if (fptr->mode & FMODE_WRITABLE) {
2352 if (io_fflush(fptr) < 0)
2353 rb_sys_fail_on_write(fptr);
2354 }
2355 if (fptr->mode & FMODE_READABLE) {
2356 io_unread(fptr);
2357 }
2358
2359 return io;
2360}
2361
2362/*
2363 * call-seq:
2364 * flush -> self
2365 *
2366 * Flushes data buffered in +self+ to the operating system
2367 * (but does not necessarily flush data buffered in the operating system):
2368 *
2369 * $stdout.print 'no newline' # Not necessarily flushed.
2370 * $stdout.flush # Flushed.
2371 *
2372 */
2373
2374VALUE
2375rb_io_flush(VALUE io)
2376{
2377 return rb_io_flush_raw(io, 1);
2378}
2379
2380/*
2381 * call-seq:
2382 * tell -> integer
2383 *
2384 * Returns the current position (in bytes) in +self+
2385 * (see {Position}[rdoc-ref:IO@Position]):
2386 *
2387 * f = File.open('t.txt')
2388 * f.tell # => 0
2389 * f.gets # => "First line\n"
2390 * f.tell # => 12
2391 * f.close
2392 *
2393 * Related: IO#pos=, IO#seek.
2394 */
2395
2396static VALUE
2397rb_io_tell(VALUE io)
2398{
2399 rb_io_t *fptr;
2400 rb_off_t pos;
2401
2402 GetOpenFile(io, fptr);
2403 pos = io_tell(fptr);
2404 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2405 pos -= fptr->rbuf.len;
2406 return OFFT2NUM(pos);
2407}
2408
2409static VALUE
2410rb_io_seek(VALUE io, VALUE offset, int whence)
2411{
2412 rb_io_t *fptr;
2413 rb_off_t pos;
2414
2415 pos = NUM2OFFT(offset);
2416 GetOpenFile(io, fptr);
2417 pos = io_seek(fptr, pos, whence);
2418 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2419
2420 return INT2FIX(0);
2421}
2422
2423static int
2424interpret_seek_whence(VALUE vwhence)
2425{
2426 if (vwhence == sym_SET)
2427 return SEEK_SET;
2428 if (vwhence == sym_CUR)
2429 return SEEK_CUR;
2430 if (vwhence == sym_END)
2431 return SEEK_END;
2432#ifdef SEEK_DATA
2433 if (vwhence == sym_DATA)
2434 return SEEK_DATA;
2435#endif
2436#ifdef SEEK_HOLE
2437 if (vwhence == sym_HOLE)
2438 return SEEK_HOLE;
2439#endif
2440 return NUM2INT(vwhence);
2441}
2442
2443/*
2444 * call-seq:
2445 * seek(offset, whence = IO::SEEK_SET) -> 0
2446 *
2447 * Seeks to the position given by integer +offset+
2448 * (see {Position}[rdoc-ref:IO@Position])
2449 * and constant +whence+, which is one of:
2450 *
2451 * - +:CUR+ or <tt>IO::SEEK_CUR</tt>:
2452 * Repositions the stream to its current position plus the given +offset+:
2453 *
2454 * f = File.open('t.txt')
2455 * f.tell # => 0
2456 * f.seek(20, :CUR) # => 0
2457 * f.tell # => 20
2458 * f.seek(-10, :CUR) # => 0
2459 * f.tell # => 10
2460 * f.close
2461 *
2462 * - +:END+ or <tt>IO::SEEK_END</tt>:
2463 * Repositions the stream to its end plus the given +offset+:
2464 *
2465 * f = File.open('t.txt')
2466 * f.tell # => 0
2467 * f.seek(0, :END) # => 0 # Repositions to stream end.
2468 * f.tell # => 52
2469 * f.seek(-20, :END) # => 0
2470 * f.tell # => 32
2471 * f.seek(-40, :END) # => 0
2472 * f.tell # => 12
2473 * f.close
2474 *
2475 * - +:SET+ or <tt>IO:SEEK_SET</tt>:
2476 * Repositions the stream to the given +offset+:
2477 *
2478 * f = File.open('t.txt')
2479 * f.tell # => 0
2480 * f.seek(20, :SET) # => 0
2481 * f.tell # => 20
2482 * f.seek(40, :SET) # => 0
2483 * f.tell # => 40
2484 * f.close
2485 *
2486 * Related: IO#pos=, IO#tell.
2487 *
2488 */
2489
2490static VALUE
2491rb_io_seek_m(int argc, VALUE *argv, VALUE io)
2492{
2493 VALUE offset, ptrname;
2494 int whence = SEEK_SET;
2495
2496 if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
2497 whence = interpret_seek_whence(ptrname);
2498 }
2499
2500 return rb_io_seek(io, offset, whence);
2501}
2502
2503/*
2504 * call-seq:
2505 * pos = new_position -> new_position
2506 *
2507 * Seeks to the given +new_position+ (in bytes);
2508 * see {Position}[rdoc-ref:IO@Position]:
2509 *
2510 * f = File.open('t.txt')
2511 * f.tell # => 0
2512 * f.pos = 20 # => 20
2513 * f.tell # => 20
2514 * f.close
2515 *
2516 * Related: IO#seek, IO#tell.
2517 *
2518 */
2519
2520static VALUE
2521rb_io_set_pos(VALUE io, VALUE offset)
2522{
2523 rb_io_t *fptr;
2524 rb_off_t pos;
2525
2526 pos = NUM2OFFT(offset);
2527 GetOpenFile(io, fptr);
2528 pos = io_seek(fptr, pos, SEEK_SET);
2529 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2530
2531 return OFFT2NUM(pos);
2532}
2533
2534static void clear_readconv(rb_io_t *fptr);
2535
2536/*
2537 * call-seq:
2538 * rewind -> 0
2539 *
2540 * Repositions the stream to its beginning,
2541 * setting both the position and the line number to zero;
2542 * see {Position}[rdoc-ref:IO@Position]
2543 * and {Line Number}[rdoc-ref:IO@Line+Number]:
2544 *
2545 * f = File.open('t.txt')
2546 * f.tell # => 0
2547 * f.lineno # => 0
2548 * f.gets # => "First line\n"
2549 * f.tell # => 12
2550 * f.lineno # => 1
2551 * f.rewind # => 0
2552 * f.tell # => 0
2553 * f.lineno # => 0
2554 * f.close
2555 *
2556 * Note that this method cannot be used with streams such as pipes, ttys, and sockets.
2557 *
2558 */
2559
2560static VALUE
2561rb_io_rewind(VALUE io)
2562{
2563 rb_io_t *fptr;
2564
2565 GetOpenFile(io, fptr);
2566 if (io_seek(fptr, 0L, 0) < 0 && errno) rb_sys_fail_path(fptr->pathv);
2567 if (io == ARGF.current_file) {
2568 ARGF.lineno -= fptr->lineno;
2569 }
2570 fptr->lineno = 0;
2571 if (fptr->readconv) {
2572 clear_readconv(fptr);
2573 }
2574
2575 return INT2FIX(0);
2576}
2577
2578static int
2579fptr_wait_readable(rb_io_t *fptr)
2580{
2581 int result = rb_io_maybe_wait_readable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT);
2582
2583 if (result)
2584 rb_io_check_closed(fptr);
2585
2586 return result;
2587}
2588
2589static int
2590io_fillbuf(rb_io_t *fptr)
2591{
2592 ssize_t r;
2593
2594 if (fptr->rbuf.ptr == NULL) {
2595 fptr->rbuf.off = 0;
2596 fptr->rbuf.len = 0;
2597 fptr->rbuf.capa = IO_RBUF_CAPA_FOR(fptr);
2598 fptr->rbuf.ptr = ALLOC_N(char, fptr->rbuf.capa);
2599#ifdef _WIN32
2600 fptr->rbuf.capa--;
2601#endif
2602 }
2603 if (fptr->rbuf.len == 0) {
2604 retry:
2605 r = rb_io_read_memory(fptr, fptr->rbuf.ptr, fptr->rbuf.capa);
2606
2607 if (r < 0) {
2608 if (fptr_wait_readable(fptr))
2609 goto retry;
2610
2611 int e = errno;
2612 VALUE path = rb_sprintf("fd:%d ", fptr->fd);
2613 if (!NIL_P(fptr->pathv)) {
2614 rb_str_append(path, fptr->pathv);
2615 }
2616
2617 rb_syserr_fail_path(e, path);
2618 }
2619 if (r > 0) rb_io_check_closed(fptr);
2620 fptr->rbuf.off = 0;
2621 fptr->rbuf.len = (int)r; /* r should be <= rbuf_capa */
2622 if (r == 0)
2623 return -1; /* EOF */
2624 }
2625 return 0;
2626}
2627
2628/*
2629 * call-seq:
2630 * eof -> true or false
2631 *
2632 * Returns +true+ if the stream is positioned at its end, +false+ otherwise;
2633 * see {Position}[rdoc-ref:IO@Position]:
2634 *
2635 * f = File.open('t.txt')
2636 * f.eof # => false
2637 * f.seek(0, :END) # => 0
2638 * f.eof # => true
2639 * f.close
2640 *
2641 * Raises an exception unless the stream is opened for reading;
2642 * see {Mode}[rdoc-ref:File@Access+Modes].
2643 *
2644 * If +self+ is a stream such as pipe or socket, this method
2645 * blocks until the other end sends some data or closes it:
2646 *
2647 * r, w = IO.pipe
2648 * Thread.new { sleep 1; w.close }
2649 * r.eof? # => true # After 1-second wait.
2650 *
2651 * r, w = IO.pipe
2652 * Thread.new { sleep 1; w.puts "a" }
2653 * r.eof? # => false # After 1-second wait.
2654 *
2655 * r, w = IO.pipe
2656 * r.eof? # blocks forever
2657 *
2658 * Note that this method reads data to the input byte buffer. So
2659 * IO#sysread may not behave as you intend with IO#eof?, unless you
2660 * call IO#rewind first (which is not available for some streams).
2661 */
2662
2663VALUE
2665{
2666 rb_io_t *fptr;
2667
2668 GetOpenFile(io, fptr);
2670
2671 if (READ_CHAR_PENDING(fptr)) return Qfalse;
2672 if (READ_DATA_PENDING(fptr)) return Qfalse;
2673 READ_CHECK(fptr);
2674#if RUBY_CRLF_ENVIRONMENT
2675 if (!NEED_READCONV(fptr) && NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
2676 return RBOOL(eof(fptr->fd));;
2677 }
2678#endif
2679 return RBOOL(io_fillbuf(fptr) < 0);
2680}
2681
2682/*
2683 * call-seq:
2684 * sync -> true or false
2685 *
2686 * Returns the current sync mode of the stream.
2687 * When sync mode is true, all output is immediately flushed to the underlying
2688 * operating system and is not buffered by Ruby internally. See also #fsync.
2689 *
2690 * f = File.open('t.tmp', 'w')
2691 * f.sync # => false
2692 * f.sync = true
2693 * f.sync # => true
2694 * f.close
2695 *
2696 */
2697
2698static VALUE
2699rb_io_sync(VALUE io)
2700{
2701 rb_io_t *fptr;
2702
2703 io = GetWriteIO(io);
2704 GetOpenFile(io, fptr);
2705 return RBOOL(fptr->mode & FMODE_SYNC);
2706}
2707
2708#ifdef HAVE_FSYNC
2709
2710/*
2711 * call-seq:
2712 * sync = boolean -> boolean
2713 *
2714 * Sets the _sync_ _mode_ for the stream to the given value;
2715 * returns the given value.
2716 *
2717 * Values for the sync mode:
2718 *
2719 * - +true+: All output is immediately flushed to the
2720 * underlying operating system and is not buffered internally.
2721 * - +false+: Output may be buffered internally.
2722 *
2723 * Example;
2724 *
2725 * f = File.open('t.tmp', 'w')
2726 * f.sync # => false
2727 * f.sync = true
2728 * f.sync # => true
2729 * f.close
2730 *
2731 * Related: IO#fsync.
2732 *
2733 */
2734
2735static VALUE
2736rb_io_set_sync(VALUE io, VALUE sync)
2737{
2738 rb_io_t *fptr;
2739
2740 io = GetWriteIO(io);
2741 GetOpenFile(io, fptr);
2742 if (RTEST(sync)) {
2743 fptr->mode |= FMODE_SYNC;
2744 }
2745 else {
2746 fptr->mode &= ~FMODE_SYNC;
2747 }
2748 return sync;
2749}
2750
2751/*
2752 * call-seq:
2753 * fsync -> 0
2754 *
2755 * Immediately writes to disk all data buffered in the stream,
2756 * via the operating system's <tt>fsync(2)</tt>.
2757
2758 * Note this difference:
2759 *
2760 * - IO#sync=: Ensures that data is flushed from the stream's internal buffers,
2761 * but does not guarantee that the operating system actually writes the data to disk.
2762 * - IO#fsync: Ensures both that data is flushed from internal buffers,
2763 * and that data is written to disk.
2764 *
2765 * Raises an exception if the operating system does not support <tt>fsync(2)</tt>.
2766 *
2767 */
2768
2769static VALUE
2770rb_io_fsync(VALUE io)
2771{
2772 rb_io_t *fptr;
2773
2774 io = GetWriteIO(io);
2775 GetOpenFile(io, fptr);
2776
2777 if (io_fflush(fptr) < 0)
2778 rb_sys_fail_on_write(fptr);
2779 if ((int)rb_thread_io_blocking_region(nogvl_fsync, fptr, fptr->fd) < 0)
2780 rb_sys_fail_path(fptr->pathv);
2781 return INT2FIX(0);
2782}
2783#else
2784# define rb_io_fsync rb_f_notimplement
2785# define rb_io_sync rb_f_notimplement
2786static VALUE
2787rb_io_set_sync(VALUE io, VALUE sync)
2788{
2791}
2792#endif
2793
2794#ifdef HAVE_FDATASYNC
2795static VALUE
2796nogvl_fdatasync(void *ptr)
2797{
2798 rb_io_t *fptr = ptr;
2799
2800#ifdef _WIN32
2801 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->fd)) != FILE_TYPE_DISK)
2802 return 0;
2803#endif
2804 return (VALUE)fdatasync(fptr->fd);
2805}
2806
2807/*
2808 * call-seq:
2809 * fdatasync -> 0
2810 *
2811 * Immediately writes to disk all data buffered in the stream,
2812 * via the operating system's: <tt>fdatasync(2)</tt>, if supported,
2813 * otherwise via <tt>fsync(2)</tt>, if supported;
2814 * otherwise raises an exception.
2815 *
2816 */
2817
2818static VALUE
2819rb_io_fdatasync(VALUE io)
2820{
2821 rb_io_t *fptr;
2822
2823 io = GetWriteIO(io);
2824 GetOpenFile(io, fptr);
2825
2826 if (io_fflush(fptr) < 0)
2827 rb_sys_fail_on_write(fptr);
2828
2829 if ((int)rb_thread_io_blocking_region(nogvl_fdatasync, fptr, fptr->fd) == 0)
2830 return INT2FIX(0);
2831
2832 /* fall back */
2833 return rb_io_fsync(io);
2834}
2835#else
2836#define rb_io_fdatasync rb_io_fsync
2837#endif
2838
2839/*
2840 * call-seq:
2841 * fileno -> integer
2842 *
2843 * Returns the integer file descriptor for the stream:
2844 *
2845 * $stdin.fileno # => 0
2846 * $stdout.fileno # => 1
2847 * $stderr.fileno # => 2
2848 * File.open('t.txt').fileno # => 10
2849 * f.close
2850 *
2851 */
2852
2853static VALUE
2854rb_io_fileno(VALUE io)
2855{
2856 rb_io_t *fptr = RFILE(io)->fptr;
2857 int fd;
2858
2859 rb_io_check_closed(fptr);
2860 fd = fptr->fd;
2861 return INT2FIX(fd);
2862}
2863
2864int
2866{
2867 if (RB_TYPE_P(io, T_FILE)) {
2868 rb_io_t *fptr = RFILE(io)->fptr;
2869 rb_io_check_closed(fptr);
2870 return fptr->fd;
2871 }
2872 else {
2873 VALUE fileno = rb_check_funcall(io, id_fileno, 0, NULL);
2874 if (!UNDEF_P(fileno)) {
2875 return RB_NUM2INT(fileno);
2876 }
2877 }
2878
2879 rb_raise(rb_eTypeError, "expected IO or #fileno, %"PRIsVALUE" given", rb_obj_class(io));
2880
2882}
2883
2884int
2886{
2887 rb_io_t *fptr;
2888 GetOpenFile(io, fptr);
2889 return fptr->mode;
2890}
2891
2892/*
2893 * call-seq:
2894 * pid -> integer or nil
2895 *
2896 * Returns the process ID of a child process associated with the stream,
2897 * which will have been set by IO#popen, or +nil+ if the stream was not
2898 * created by IO#popen:
2899 *
2900 * pipe = IO.popen("-")
2901 * if pipe
2902 * $stderr.puts "In parent, child pid is #{pipe.pid}"
2903 * else
2904 * $stderr.puts "In child, pid is #{$$}"
2905 * end
2906 *
2907 * Output:
2908 *
2909 * In child, pid is 26209
2910 * In parent, child pid is 26209
2911 *
2912 */
2913
2914static VALUE
2915rb_io_pid(VALUE io)
2916{
2917 rb_io_t *fptr;
2918
2919 GetOpenFile(io, fptr);
2920 if (!fptr->pid)
2921 return Qnil;
2922 return PIDT2NUM(fptr->pid);
2923}
2924
2925/*
2926 * call-seq:
2927 * path -> string or nil
2928 *
2929 * Returns the path associated with the IO, or +nil+ if there is no path
2930 * associated with the IO. It is not guaranteed that the path exists on
2931 * the filesystem.
2932 *
2933 * $stdin.path # => "<STDIN>"
2934 *
2935 * File.open("testfile") {|f| f.path} # => "testfile"
2936 */
2937
2938VALUE
2940{
2941 rb_io_t *fptr = RFILE(io)->fptr;
2942
2943 if (!fptr)
2944 return Qnil;
2945
2946 return rb_obj_dup(fptr->pathv);
2947}
2948
2949/*
2950 * call-seq:
2951 * inspect -> string
2952 *
2953 * Returns a string representation of +self+:
2954 *
2955 * f = File.open('t.txt')
2956 * f.inspect # => "#<File:t.txt>"
2957 * f.close
2958 *
2959 */
2960
2961static VALUE
2962rb_io_inspect(VALUE obj)
2963{
2964 rb_io_t *fptr;
2965 VALUE result;
2966 static const char closed[] = " (closed)";
2967
2968 fptr = RFILE(obj)->fptr;
2969 if (!fptr) return rb_any_to_s(obj);
2970 result = rb_str_new_cstr("#<");
2971 rb_str_append(result, rb_class_name(CLASS_OF(obj)));
2972 rb_str_cat2(result, ":");
2973 if (NIL_P(fptr->pathv)) {
2974 if (fptr->fd < 0) {
2975 rb_str_cat(result, closed+1, strlen(closed)-1);
2976 }
2977 else {
2978 rb_str_catf(result, "fd %d", fptr->fd);
2979 }
2980 }
2981 else {
2982 rb_str_append(result, fptr->pathv);
2983 if (fptr->fd < 0) {
2984 rb_str_cat(result, closed, strlen(closed));
2985 }
2986 }
2987 return rb_str_cat2(result, ">");
2988}
2989
2990/*
2991 * call-seq:
2992 * to_io -> self
2993 *
2994 * Returns +self+.
2995 *
2996 */
2997
2998static VALUE
2999rb_io_to_io(VALUE io)
3000{
3001 return io;
3002}
3003
3004/* reading functions */
3005static long
3006read_buffered_data(char *ptr, long len, rb_io_t *fptr)
3007{
3008 int n;
3009
3010 n = READ_DATA_PENDING_COUNT(fptr);
3011 if (n <= 0) return 0;
3012 if (n > len) n = (int)len;
3013 MEMMOVE(ptr, fptr->rbuf.ptr+fptr->rbuf.off, char, n);
3014 fptr->rbuf.off += n;
3015 fptr->rbuf.len -= n;
3016 return n;
3017}
3018
3019static long
3020io_bufread(char *ptr, long len, rb_io_t *fptr)
3021{
3022 long offset = 0;
3023 long n = len;
3024 long c;
3025
3026 if (READ_DATA_PENDING(fptr) == 0) {
3027 while (n > 0) {
3028 again:
3029 rb_io_check_closed(fptr);
3030 c = rb_io_read_memory(fptr, ptr+offset, n);
3031 if (c == 0) break;
3032 if (c < 0) {
3033 if (fptr_wait_readable(fptr))
3034 goto again;
3035 return -1;
3036 }
3037 offset += c;
3038 if ((n -= c) <= 0) break;
3039 }
3040 return len - n;
3041 }
3042
3043 while (n > 0) {
3044 c = read_buffered_data(ptr+offset, n, fptr);
3045 if (c > 0) {
3046 offset += c;
3047 if ((n -= c) <= 0) break;
3048 }
3049 rb_io_check_closed(fptr);
3050 if (io_fillbuf(fptr) < 0) {
3051 break;
3052 }
3053 }
3054 return len - n;
3055}
3056
3057static int io_setstrbuf(VALUE *str, long len);
3058
3060 char *str_ptr;
3061 long len;
3062 rb_io_t *fptr;
3063};
3064
3065static VALUE
3066bufread_call(VALUE arg)
3067{
3068 struct bufread_arg *p = (struct bufread_arg *)arg;
3069 p->len = io_bufread(p->str_ptr, p->len, p->fptr);
3070 return Qundef;
3071}
3072
3073static long
3074io_fread(VALUE str, long offset, long size, rb_io_t *fptr)
3075{
3076 long len;
3077 struct bufread_arg arg;
3078
3079 io_setstrbuf(&str, offset + size);
3080 arg.str_ptr = RSTRING_PTR(str) + offset;
3081 arg.len = size;
3082 arg.fptr = fptr;
3083 rb_str_locktmp_ensure(str, bufread_call, (VALUE)&arg);
3084 len = arg.len;
3085 if (len < 0) rb_sys_fail_path(fptr->pathv);
3086 return len;
3087}
3088
3089static long
3090remain_size(rb_io_t *fptr)
3091{
3092 struct stat st;
3093 rb_off_t siz = READ_DATA_PENDING_COUNT(fptr);
3094 rb_off_t pos;
3095
3096 if (fstat(fptr->fd, &st) == 0 && S_ISREG(st.st_mode)
3097#if defined(__HAIKU__)
3098 && (st.st_dev > 3)
3099#endif
3100 )
3101 {
3102 if (io_fflush(fptr) < 0)
3103 rb_sys_fail_on_write(fptr);
3104 pos = lseek(fptr->fd, 0, SEEK_CUR);
3105 if (st.st_size >= pos && pos >= 0) {
3106 siz += st.st_size - pos;
3107 if (siz > LONG_MAX) {
3108 rb_raise(rb_eIOError, "file too big for single read");
3109 }
3110 }
3111 }
3112 else {
3113 siz += BUFSIZ;
3114 }
3115 return (long)siz;
3116}
3117
3118static VALUE
3119io_enc_str(VALUE str, rb_io_t *fptr)
3120{
3121 rb_enc_associate(str, io_read_encoding(fptr));
3122 return str;
3123}
3124
3125static rb_encoding *io_read_encoding(rb_io_t *fptr);
3126
3127static void
3128make_readconv(rb_io_t *fptr, int size)
3129{
3130 if (!fptr->readconv) {
3131 int ecflags;
3132 VALUE ecopts;
3133 const char *sname, *dname;
3134 ecflags = fptr->encs.ecflags & ~ECONV_NEWLINE_DECORATOR_WRITE_MASK;
3135 ecopts = fptr->encs.ecopts;
3136 if (fptr->encs.enc2) {
3137 sname = rb_enc_name(fptr->encs.enc2);
3138 dname = rb_enc_name(io_read_encoding(fptr));
3139 }
3140 else {
3141 sname = dname = "";
3142 }
3143 fptr->readconv = rb_econv_open_opts(sname, dname, ecflags, ecopts);
3144 if (!fptr->readconv)
3145 rb_exc_raise(rb_econv_open_exc(sname, dname, ecflags));
3146 fptr->cbuf.off = 0;
3147 fptr->cbuf.len = 0;
3148 if (size < IO_CBUF_CAPA_MIN) size = IO_CBUF_CAPA_MIN;
3149 fptr->cbuf.capa = size;
3150 fptr->cbuf.ptr = ALLOC_N(char, fptr->cbuf.capa);
3151 }
3152}
3153
3154#define MORE_CHAR_SUSPENDED Qtrue
3155#define MORE_CHAR_FINISHED Qnil
3156static VALUE
3157fill_cbuf(rb_io_t *fptr, int ec_flags)
3158{
3159 const unsigned char *ss, *sp, *se;
3160 unsigned char *ds, *dp, *de;
3162 int putbackable;
3163 int cbuf_len0;
3164 VALUE exc;
3165
3166 ec_flags |= ECONV_PARTIAL_INPUT;
3167
3168 if (fptr->cbuf.len == fptr->cbuf.capa)
3169 return MORE_CHAR_SUSPENDED; /* cbuf full */
3170 if (fptr->cbuf.len == 0)
3171 fptr->cbuf.off = 0;
3172 else if (fptr->cbuf.off + fptr->cbuf.len == fptr->cbuf.capa) {
3173 memmove(fptr->cbuf.ptr, fptr->cbuf.ptr+fptr->cbuf.off, fptr->cbuf.len);
3174 fptr->cbuf.off = 0;
3175 }
3176
3177 cbuf_len0 = fptr->cbuf.len;
3178
3179 while (1) {
3180 ss = sp = (const unsigned char *)fptr->rbuf.ptr + fptr->rbuf.off;
3181 se = sp + fptr->rbuf.len;
3182 ds = dp = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.off + fptr->cbuf.len;
3183 de = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.capa;
3184 res = rb_econv_convert(fptr->readconv, &sp, se, &dp, de, ec_flags);
3185 fptr->rbuf.off += (int)(sp - ss);
3186 fptr->rbuf.len -= (int)(sp - ss);
3187 fptr->cbuf.len += (int)(dp - ds);
3188
3189 putbackable = rb_econv_putbackable(fptr->readconv);
3190 if (putbackable) {
3191 rb_econv_putback(fptr->readconv, (unsigned char *)fptr->rbuf.ptr + fptr->rbuf.off - putbackable, putbackable);
3192 fptr->rbuf.off -= putbackable;
3193 fptr->rbuf.len += putbackable;
3194 }
3195
3196 exc = rb_econv_make_exception(fptr->readconv);
3197 if (!NIL_P(exc))
3198 return exc;
3199
3200 if (cbuf_len0 != fptr->cbuf.len)
3201 return MORE_CHAR_SUSPENDED;
3202
3203 if (res == econv_finished) {
3204 return MORE_CHAR_FINISHED;
3205 }
3206
3207 if (res == econv_source_buffer_empty) {
3208 if (fptr->rbuf.len == 0) {
3209 READ_CHECK(fptr);
3210 if (io_fillbuf(fptr) < 0) {
3211 if (!fptr->readconv) {
3212 return MORE_CHAR_FINISHED;
3213 }
3214 ds = dp = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.off + fptr->cbuf.len;
3215 de = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.capa;
3216 res = rb_econv_convert(fptr->readconv, NULL, NULL, &dp, de, 0);
3217 fptr->cbuf.len += (int)(dp - ds);
3219 break;
3220 }
3221 }
3222 }
3223 }
3224 if (cbuf_len0 != fptr->cbuf.len)
3225 return MORE_CHAR_SUSPENDED;
3226
3227 return MORE_CHAR_FINISHED;
3228}
3229
3230static VALUE
3231more_char(rb_io_t *fptr)
3232{
3233 VALUE v;
3234 v = fill_cbuf(fptr, ECONV_AFTER_OUTPUT);
3235 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED)
3236 rb_exc_raise(v);
3237 return v;
3238}
3239
3240static VALUE
3241io_shift_cbuf(rb_io_t *fptr, int len, VALUE *strp)
3242{
3243 VALUE str = Qnil;
3244 if (strp) {
3245 str = *strp;
3246 if (NIL_P(str)) {
3247 *strp = str = rb_str_new(fptr->cbuf.ptr+fptr->cbuf.off, len);
3248 }
3249 else {
3250 rb_str_cat(str, fptr->cbuf.ptr+fptr->cbuf.off, len);
3251 }
3252 rb_enc_associate(str, fptr->encs.enc);
3253 }
3254 fptr->cbuf.off += len;
3255 fptr->cbuf.len -= len;
3256 /* xxx: set coderange */
3257 if (fptr->cbuf.len == 0)
3258 fptr->cbuf.off = 0;
3259 else if (fptr->cbuf.capa/2 < fptr->cbuf.off) {
3260 memmove(fptr->cbuf.ptr, fptr->cbuf.ptr+fptr->cbuf.off, fptr->cbuf.len);
3261 fptr->cbuf.off = 0;
3262 }
3263 return str;
3264}
3265
3266static int
3267io_setstrbuf(VALUE *str, long len)
3268{
3269#ifdef _WIN32
3270 if (len > 0)
3271 len = (len + 1) & ~1L; /* round up for wide char */
3272#endif
3273 if (NIL_P(*str)) {
3274 *str = rb_str_new(0, len);
3275 return TRUE;
3276 }
3277 else {
3278 VALUE s = StringValue(*str);
3279 rb_str_modify(s);
3280
3281 long clen = RSTRING_LEN(s);
3282 if (clen >= len) {
3283 return FALSE;
3284 }
3285 len -= clen;
3286 }
3287 if ((rb_str_capacity(*str) - (size_t)RSTRING_LEN(*str)) < (size_t)len) {
3289 }
3290 return FALSE;
3291}
3292
3293#define MAX_REALLOC_GAP 4096
3294static void
3295io_shrink_read_string(VALUE str, long n)
3296{
3297 if (rb_str_capacity(str) - n > MAX_REALLOC_GAP) {
3298 rb_str_resize(str, n);
3299 }
3300}
3301
3302static void
3303io_set_read_length(VALUE str, long n, int shrinkable)
3304{
3305 if (RSTRING_LEN(str) != n) {
3306 rb_str_modify(str);
3307 rb_str_set_len(str, n);
3308 if (shrinkable) io_shrink_read_string(str, n);
3309 }
3310}
3311
3312static VALUE
3313read_all(rb_io_t *fptr, long siz, VALUE str)
3314{
3315 long bytes;
3316 long n;
3317 long pos;
3318 rb_encoding *enc;
3319 int cr;
3320 int shrinkable;
3321
3322 if (NEED_READCONV(fptr)) {
3323 int first = !NIL_P(str);
3324 SET_BINARY_MODE(fptr);
3325 shrinkable = io_setstrbuf(&str,0);
3326 make_readconv(fptr, 0);
3327 while (1) {
3328 VALUE v;
3329 if (fptr->cbuf.len) {
3330 if (first) rb_str_set_len(str, first = 0);
3331 io_shift_cbuf(fptr, fptr->cbuf.len, &str);
3332 }
3333 v = fill_cbuf(fptr, 0);
3334 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED) {
3335 if (fptr->cbuf.len) {
3336 if (first) rb_str_set_len(str, first = 0);
3337 io_shift_cbuf(fptr, fptr->cbuf.len, &str);
3338 }
3339 rb_exc_raise(v);
3340 }
3341 if (v == MORE_CHAR_FINISHED) {
3342 clear_readconv(fptr);
3343 if (first) rb_str_set_len(str, first = 0);
3344 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3345 return io_enc_str(str, fptr);
3346 }
3347 }
3348 }
3349
3350 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3351 bytes = 0;
3352 pos = 0;
3353
3354 enc = io_read_encoding(fptr);
3355 cr = 0;
3356
3357 if (siz == 0) siz = BUFSIZ;
3358 shrinkable = io_setstrbuf(&str, siz);
3359 for (;;) {
3360 READ_CHECK(fptr);
3361 n = io_fread(str, bytes, siz - bytes, fptr);
3362 if (n == 0 && bytes == 0) {
3363 rb_str_set_len(str, 0);
3364 break;
3365 }
3366 bytes += n;
3367 rb_str_set_len(str, bytes);
3368 if (cr != ENC_CODERANGE_BROKEN)
3369 pos += rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + bytes, enc, &cr);
3370 if (bytes < siz) break;
3371 siz += BUFSIZ;
3372
3373 size_t capa = rb_str_capacity(str);
3374 if (capa < (size_t)RSTRING_LEN(str) + BUFSIZ) {
3375 if (capa < BUFSIZ) {
3376 capa = BUFSIZ;
3377 }
3378 else if (capa > IO_MAX_BUFFER_GROWTH) {
3379 capa = IO_MAX_BUFFER_GROWTH;
3380 }
3382 }
3383 }
3384 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3385 str = io_enc_str(str, fptr);
3386 ENC_CODERANGE_SET(str, cr);
3387 return str;
3388}
3389
3390void
3392{
3393 if (rb_fd_set_nonblock(fptr->fd) != 0) {
3394 rb_sys_fail_path(fptr->pathv);
3395 }
3396}
3397
3398static VALUE
3399io_read_memory_call(VALUE arg)
3400{
3401 struct io_internal_read_struct *iis = (struct io_internal_read_struct *)arg;
3402
3403 VALUE scheduler = rb_fiber_scheduler_current();
3404 if (scheduler != Qnil) {
3405 VALUE result = rb_fiber_scheduler_io_read_memory(scheduler, iis->fptr->self, iis->buf, iis->capa, 0);
3406
3407 if (!UNDEF_P(result)) {
3408 // This is actually returned as a pseudo-VALUE and later cast to a long:
3410 }
3411 }
3412
3413 if (iis->nonblock) {
3414 return rb_thread_io_blocking_call(internal_read_func, iis, iis->fptr->fd, 0);
3415 }
3416 else {
3417 return rb_thread_io_blocking_call(internal_read_func, iis, iis->fptr->fd, RB_WAITFD_IN);
3418 }
3419}
3420
3421static long
3422io_read_memory_locktmp(VALUE str, struct io_internal_read_struct *iis)
3423{
3424 return (long)rb_str_locktmp_ensure(str, io_read_memory_call, (VALUE)iis);
3425}
3426
3427#define no_exception_p(opts) !rb_opts_exception_p((opts), TRUE)
3428
3429static VALUE
3430io_getpartial(int argc, VALUE *argv, VALUE io, int no_exception, int nonblock)
3431{
3432 rb_io_t *fptr;
3433 VALUE length, str;
3434 long n, len;
3435 struct io_internal_read_struct iis;
3436 int shrinkable;
3437
3438 rb_scan_args(argc, argv, "11", &length, &str);
3439
3440 if ((len = NUM2LONG(length)) < 0) {
3441 rb_raise(rb_eArgError, "negative length %ld given", len);
3442 }
3443
3444 shrinkable = io_setstrbuf(&str, len);
3445
3446 GetOpenFile(io, fptr);
3448
3449 if (len == 0) {
3450 io_set_read_length(str, 0, shrinkable);
3451 return str;
3452 }
3453
3454 if (!nonblock)
3455 READ_CHECK(fptr);
3456 n = read_buffered_data(RSTRING_PTR(str), len, fptr);
3457 if (n <= 0) {
3458 again:
3459 if (nonblock) {
3460 rb_io_set_nonblock(fptr);
3461 }
3462 io_setstrbuf(&str, len);
3463 iis.th = rb_thread_current();
3464 iis.fptr = fptr;
3465 iis.nonblock = nonblock;
3466 iis.fd = fptr->fd;
3467 iis.buf = RSTRING_PTR(str);
3468 iis.capa = len;
3469 iis.timeout = NULL;
3470 n = io_read_memory_locktmp(str, &iis);
3471 if (n < 0) {
3472 int e = errno;
3473 if (!nonblock && fptr_wait_readable(fptr))
3474 goto again;
3475 if (nonblock && (io_again_p(e))) {
3476 if (no_exception)
3477 return sym_wait_readable;
3478 else
3479 rb_readwrite_syserr_fail(RB_IO_WAIT_READABLE,
3480 e, "read would block");
3481 }
3482 rb_syserr_fail_path(e, fptr->pathv);
3483 }
3484 }
3485 io_set_read_length(str, n, shrinkable);
3486
3487 if (n == 0)
3488 return Qnil;
3489 else
3490 return str;
3491}
3492
3493/*
3494 * call-seq:
3495 * readpartial(maxlen) -> string
3496 * readpartial(maxlen, out_string) -> out_string
3497 *
3498 * Reads up to +maxlen+ bytes from the stream;
3499 * returns a string (either a new string or the given +out_string+).
3500 * Its encoding is:
3501 *
3502 * - The unchanged encoding of +out_string+, if +out_string+ is given.
3503 * - ASCII-8BIT, otherwise.
3504 *
3505 * - Contains +maxlen+ bytes from the stream, if available.
3506 * - Otherwise contains all available bytes, if any available.
3507 * - Otherwise is an empty string.
3508 *
3509 * With the single non-negative integer argument +maxlen+ given,
3510 * returns a new string:
3511 *
3512 * f = File.new('t.txt')
3513 * f.readpartial(20) # => "First line\nSecond l"
3514 * f.readpartial(20) # => "ine\n\nFourth line\n"
3515 * f.readpartial(20) # => "Fifth line\n"
3516 * f.readpartial(20) # Raises EOFError.
3517 * f.close
3518 *
3519 * With both argument +maxlen+ and string argument +out_string+ given,
3520 * returns modified +out_string+:
3521 *
3522 * f = File.new('t.txt')
3523 * s = 'foo'
3524 * f.readpartial(20, s) # => "First line\nSecond l"
3525 * s = 'bar'
3526 * f.readpartial(0, s) # => ""
3527 * f.close
3528 *
3529 * This method is useful for a stream such as a pipe, a socket, or a tty.
3530 * It blocks only when no data is immediately available.
3531 * This means that it blocks only when _all_ of the following are true:
3532 *
3533 * - The byte buffer in the stream is empty.
3534 * - The content of the stream is empty.
3535 * - The stream is not at EOF.
3536 *
3537 * When blocked, the method waits for either more data or EOF on the stream:
3538 *
3539 * - If more data is read, the method returns the data.
3540 * - If EOF is reached, the method raises EOFError.
3541 *
3542 * When not blocked, the method responds immediately:
3543 *
3544 * - Returns data from the buffer if there is any.
3545 * - Otherwise returns data from the stream if there is any.
3546 * - Otherwise raises EOFError if the stream has reached EOF.
3547 *
3548 * Note that this method is similar to sysread. The differences are:
3549 *
3550 * - If the byte buffer is not empty, read from the byte buffer
3551 * instead of "sysread for buffered IO (IOError)".
3552 * - It doesn't cause Errno::EWOULDBLOCK and Errno::EINTR. When
3553 * readpartial meets EWOULDBLOCK and EINTR by read system call,
3554 * readpartial retries the system call.
3555 *
3556 * The latter means that readpartial is non-blocking-flag insensitive.
3557 * It blocks on the situation IO#sysread causes Errno::EWOULDBLOCK as
3558 * if the fd is blocking mode.
3559 *
3560 * Examples:
3561 *
3562 * # # Returned Buffer Content Pipe Content
3563 * r, w = IO.pipe #
3564 * w << 'abc' # "" "abc".
3565 * r.readpartial(4096) # => "abc" "" ""
3566 * r.readpartial(4096) # (Blocks because buffer and pipe are empty.)
3567 *
3568 * # # Returned Buffer Content Pipe Content
3569 * r, w = IO.pipe #
3570 * w << 'abc' # "" "abc"
3571 * w.close # "" "abc" EOF
3572 * r.readpartial(4096) # => "abc" "" EOF
3573 * r.readpartial(4096) # raises EOFError
3574 *
3575 * # # Returned Buffer Content Pipe Content
3576 * r, w = IO.pipe #
3577 * w << "abc\ndef\n" # "" "abc\ndef\n"
3578 * r.gets # => "abc\n" "def\n" ""
3579 * w << "ghi\n" # "def\n" "ghi\n"
3580 * r.readpartial(4096) # => "def\n" "" "ghi\n"
3581 * r.readpartial(4096) # => "ghi\n" "" ""
3582 *
3583 */
3584
3585static VALUE
3586io_readpartial(int argc, VALUE *argv, VALUE io)
3587{
3588 VALUE ret;
3589
3590 ret = io_getpartial(argc, argv, io, Qnil, 0);
3591 if (NIL_P(ret))
3592 rb_eof_error();
3593 return ret;
3594}
3595
3596static VALUE
3597io_nonblock_eof(int no_exception)
3598{
3599 if (!no_exception) {
3600 rb_eof_error();
3601 }
3602 return Qnil;
3603}
3604
3605/* :nodoc: */
3606static VALUE
3607io_read_nonblock(rb_execution_context_t *ec, VALUE io, VALUE length, VALUE str, VALUE ex)
3608{
3609 rb_io_t *fptr;
3610 long n, len;
3611 struct io_internal_read_struct iis;
3612 int shrinkable;
3613
3614 if ((len = NUM2LONG(length)) < 0) {
3615 rb_raise(rb_eArgError, "negative length %ld given", len);
3616 }
3617
3618 shrinkable = io_setstrbuf(&str, len);
3619 rb_bool_expected(ex, "exception", TRUE);
3620
3621 GetOpenFile(io, fptr);
3623
3624 if (len == 0) {
3625 io_set_read_length(str, 0, shrinkable);
3626 return str;
3627 }
3628
3629 n = read_buffered_data(RSTRING_PTR(str), len, fptr);
3630 if (n <= 0) {
3631 rb_fd_set_nonblock(fptr->fd);
3632 shrinkable |= io_setstrbuf(&str, len);
3633 iis.fptr = fptr;
3634 iis.nonblock = 1;
3635 iis.fd = fptr->fd;
3636 iis.buf = RSTRING_PTR(str);
3637 iis.capa = len;
3638 iis.timeout = NULL;
3639 n = io_read_memory_locktmp(str, &iis);
3640 if (n < 0) {
3641 int e = errno;
3642 if (io_again_p(e)) {
3643 if (!ex) return sym_wait_readable;
3644 rb_readwrite_syserr_fail(RB_IO_WAIT_READABLE,
3645 e, "read would block");
3646 }
3647 rb_syserr_fail_path(e, fptr->pathv);
3648 }
3649 }
3650 io_set_read_length(str, n, shrinkable);
3651
3652 if (n == 0) {
3653 if (!ex) return Qnil;
3654 rb_eof_error();
3655 }
3656
3657 return str;
3658}
3659
3660/* :nodoc: */
3661static VALUE
3662io_write_nonblock(rb_execution_context_t *ec, VALUE io, VALUE str, VALUE ex)
3663{
3664 rb_io_t *fptr;
3665 long n;
3666
3667 if (!RB_TYPE_P(str, T_STRING))
3668 str = rb_obj_as_string(str);
3669 rb_bool_expected(ex, "exception", TRUE);
3670
3671 io = GetWriteIO(io);
3672 GetOpenFile(io, fptr);
3674
3675 if (io_fflush(fptr) < 0)
3676 rb_sys_fail_on_write(fptr);
3677
3678 rb_fd_set_nonblock(fptr->fd);
3679 n = write(fptr->fd, RSTRING_PTR(str), RSTRING_LEN(str));
3680 RB_GC_GUARD(str);
3681
3682 if (n < 0) {
3683 int e = errno;
3684 if (io_again_p(e)) {
3685 if (!ex) {
3686 return sym_wait_writable;
3687 }
3688 else {
3689 rb_readwrite_syserr_fail(RB_IO_WAIT_WRITABLE, e, "write would block");
3690 }
3691 }
3692 rb_syserr_fail_path(e, fptr->pathv);
3693 }
3694
3695 return LONG2FIX(n);
3696}
3697
3698/*
3699 * call-seq:
3700 * read(maxlen = nil, out_string = nil) -> new_string, out_string, or nil
3701 *
3702 * Reads bytes from the stream; the stream must be opened for reading
3703 * (see {Access Modes}[rdoc-ref:File@Access+Modes]):
3704 *
3705 * - If +maxlen+ is +nil+, reads all bytes using the stream's data mode.
3706 * - Otherwise reads up to +maxlen+ bytes in binary mode.
3707 *
3708 * Returns a string (either a new string or the given +out_string+)
3709 * containing the bytes read.
3710 * The encoding of the string depends on both +maxLen+ and +out_string+:
3711 *
3712 * - +maxlen+ is +nil+: uses internal encoding of +self+
3713 * (regardless of whether +out_string+ was given).
3714 * - +maxlen+ not +nil+:
3715 *
3716 * - +out_string+ given: encoding of +out_string+ not modified.
3717 * - +out_string+ not given: ASCII-8BIT is used.
3718 *
3719 * <b>Without Argument +out_string+</b>
3720 *
3721 * When argument +out_string+ is omitted,
3722 * the returned value is a new string:
3723 *
3724 * f = File.new('t.txt')
3725 * f.read
3726 * # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3727 * f.rewind
3728 * f.read(30) # => "First line\r\nSecond line\r\n\r\nFou"
3729 * f.read(30) # => "rth line\r\nFifth line\r\n"
3730 * f.read(30) # => nil
3731 * f.close
3732 *
3733 * If +maxlen+ is zero, returns an empty string.
3734 *
3735 * <b> With Argument +out_string+</b>
3736 *
3737 * When argument +out_string+ is given,
3738 * the returned value is +out_string+, whose content is replaced:
3739 *
3740 * f = File.new('t.txt')
3741 * s = 'foo' # => "foo"
3742 * f.read(nil, s) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3743 * s # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3744 * f.rewind
3745 * s = 'bar'
3746 * f.read(30, s) # => "First line\r\nSecond line\r\n\r\nFou"
3747 * s # => "First line\r\nSecond line\r\n\r\nFou"
3748 * s = 'baz'
3749 * f.read(30, s) # => "rth line\r\nFifth line\r\n"
3750 * s # => "rth line\r\nFifth line\r\n"
3751 * s = 'bat'
3752 * f.read(30, s) # => nil
3753 * s # => ""
3754 * f.close
3755 *
3756 * Note that this method behaves like the fread() function in C.
3757 * This means it retries to invoke read(2) system calls to read data
3758 * with the specified maxlen (or until EOF).
3759 *
3760 * This behavior is preserved even if the stream is in non-blocking mode.
3761 * (This method is non-blocking-flag insensitive as other methods.)
3762 *
3763 * If you need the behavior like a single read(2) system call,
3764 * consider #readpartial, #read_nonblock, and #sysread.
3765 *
3766 * Related: IO#write.
3767 */
3768
3769static VALUE
3770io_read(int argc, VALUE *argv, VALUE io)
3771{
3772 rb_io_t *fptr;
3773 long n, len;
3774 VALUE length, str;
3775 int shrinkable;
3776#if RUBY_CRLF_ENVIRONMENT
3777 int previous_mode;
3778#endif
3779
3780 rb_scan_args(argc, argv, "02", &length, &str);
3781
3782 if (NIL_P(length)) {
3783 GetOpenFile(io, fptr);
3785 return read_all(fptr, remain_size(fptr), str);
3786 }
3787 len = NUM2LONG(length);
3788 if (len < 0) {
3789 rb_raise(rb_eArgError, "negative length %ld given", len);
3790 }
3791
3792 shrinkable = io_setstrbuf(&str,len);
3793
3794 GetOpenFile(io, fptr);
3796 if (len == 0) {
3797 io_set_read_length(str, 0, shrinkable);
3798 return str;
3799 }
3800
3801 READ_CHECK(fptr);
3802#if RUBY_CRLF_ENVIRONMENT
3803 previous_mode = set_binary_mode_with_seek_cur(fptr);
3804#endif
3805 n = io_fread(str, 0, len, fptr);
3806 io_set_read_length(str, n, shrinkable);
3807#if RUBY_CRLF_ENVIRONMENT
3808 if (previous_mode == O_TEXT) {
3809 setmode(fptr->fd, O_TEXT);
3810 }
3811#endif
3812 if (n == 0) return Qnil;
3813
3814 return str;
3815}
3816
3817static void
3818rscheck(const char *rsptr, long rslen, VALUE rs)
3819{
3820 if (!rs) return;
3821 if (RSTRING_PTR(rs) != rsptr && RSTRING_LEN(rs) != rslen)
3822 rb_raise(rb_eRuntimeError, "rs modified");
3823}
3824
3825static int
3826appendline(rb_io_t *fptr, int delim, VALUE *strp, long *lp)
3827{
3828 VALUE str = *strp;
3829 long limit = *lp;
3830
3831 if (NEED_READCONV(fptr)) {
3832 SET_BINARY_MODE(fptr);
3833 make_readconv(fptr, 0);
3834 do {
3835 const char *p, *e;
3836 int searchlen = READ_CHAR_PENDING_COUNT(fptr);
3837 if (searchlen) {
3838 p = READ_CHAR_PENDING_PTR(fptr);
3839 if (0 < limit && limit < searchlen)
3840 searchlen = (int)limit;
3841 e = memchr(p, delim, searchlen);
3842 if (e) {
3843 int len = (int)(e-p+1);
3844 if (NIL_P(str))
3845 *strp = str = rb_str_new(p, len);
3846 else
3847 rb_str_buf_cat(str, p, len);
3848 fptr->cbuf.off += len;
3849 fptr->cbuf.len -= len;
3850 limit -= len;
3851 *lp = limit;
3852 return delim;
3853 }
3854
3855 if (NIL_P(str))
3856 *strp = str = rb_str_new(p, searchlen);
3857 else
3858 rb_str_buf_cat(str, p, searchlen);
3859 fptr->cbuf.off += searchlen;
3860 fptr->cbuf.len -= searchlen;
3861 limit -= searchlen;
3862
3863 if (limit == 0) {
3864 *lp = limit;
3865 return (unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
3866 }
3867 }
3868 } while (more_char(fptr) != MORE_CHAR_FINISHED);
3869 clear_readconv(fptr);
3870 *lp = limit;
3871 return EOF;
3872 }
3873
3874 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3875 do {
3876 long pending = READ_DATA_PENDING_COUNT(fptr);
3877 if (pending > 0) {
3878 const char *p = READ_DATA_PENDING_PTR(fptr);
3879 const char *e;
3880 long last;
3881
3882 if (limit > 0 && pending > limit) pending = limit;
3883 e = memchr(p, delim, pending);
3884 if (e) pending = e - p + 1;
3885 if (!NIL_P(str)) {
3886 last = RSTRING_LEN(str);
3887 rb_str_resize(str, last + pending);
3888 }
3889 else {
3890 last = 0;
3891 *strp = str = rb_str_buf_new(pending);
3892 rb_str_set_len(str, pending);
3893 }
3894 read_buffered_data(RSTRING_PTR(str) + last, pending, fptr); /* must not fail */
3895 limit -= pending;
3896 *lp = limit;
3897 if (e) return delim;
3898 if (limit == 0)
3899 return (unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
3900 }
3901 READ_CHECK(fptr);
3902 } while (io_fillbuf(fptr) >= 0);
3903 *lp = limit;
3904 return EOF;
3905}
3906
3907static inline int
3908swallow(rb_io_t *fptr, int term)
3909{
3910 if (NEED_READCONV(fptr)) {
3911 rb_encoding *enc = io_read_encoding(fptr);
3912 int needconv = rb_enc_mbminlen(enc) != 1;
3913 SET_BINARY_MODE(fptr);
3914 make_readconv(fptr, 0);
3915 do {
3916 size_t cnt;
3917 while ((cnt = READ_CHAR_PENDING_COUNT(fptr)) > 0) {
3918 const char *p = READ_CHAR_PENDING_PTR(fptr);
3919 int i;
3920 if (!needconv) {
3921 if (*p != term) return TRUE;
3922 i = (int)cnt;
3923 while (--i && *++p == term);
3924 }
3925 else {
3926 const char *e = p + cnt;
3927 if (rb_enc_ascget(p, e, &i, enc) != term) return TRUE;
3928 while ((p += i) < e && rb_enc_ascget(p, e, &i, enc) == term);
3929 i = (int)(e - p);
3930 }
3931 io_shift_cbuf(fptr, (int)cnt - i, NULL);
3932 }
3933 } while (more_char(fptr) != MORE_CHAR_FINISHED);
3934 return FALSE;
3935 }
3936
3937 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3938 do {
3939 size_t cnt;
3940 while ((cnt = READ_DATA_PENDING_COUNT(fptr)) > 0) {
3941 char buf[1024];
3942 const char *p = READ_DATA_PENDING_PTR(fptr);
3943 int i;
3944 if (cnt > sizeof buf) cnt = sizeof buf;
3945 if (*p != term) return TRUE;
3946 i = (int)cnt;
3947 while (--i && *++p == term);
3948 if (!read_buffered_data(buf, cnt - i, fptr)) /* must not fail */
3949 rb_sys_fail_path(fptr->pathv);
3950 }
3951 READ_CHECK(fptr);
3952 } while (io_fillbuf(fptr) == 0);
3953 return FALSE;
3954}
3955
3956static VALUE
3957rb_io_getline_fast(rb_io_t *fptr, rb_encoding *enc, int chomp)
3958{
3959 VALUE str = Qnil;
3960 int len = 0;
3961 long pos = 0;
3962 int cr = 0;
3963
3964 do {
3965 int pending = READ_DATA_PENDING_COUNT(fptr);
3966
3967 if (pending > 0) {
3968 const char *p = READ_DATA_PENDING_PTR(fptr);
3969 const char *e;
3970 int chomplen = 0;
3971
3972 e = memchr(p, '\n', pending);
3973 if (e) {
3974 pending = (int)(e - p + 1);
3975 if (chomp) {
3976 chomplen = (pending > 1 && *(e-1) == '\r') + 1;
3977 }
3978 }
3979 if (NIL_P(str)) {
3980 str = rb_str_new(p, pending - chomplen);
3981 fptr->rbuf.off += pending;
3982 fptr->rbuf.len -= pending;
3983 }
3984 else {
3985 rb_str_resize(str, len + pending - chomplen);
3986 read_buffered_data(RSTRING_PTR(str)+len, pending - chomplen, fptr);
3987 fptr->rbuf.off += chomplen;
3988 fptr->rbuf.len -= chomplen;
3989 if (pending == 1 && chomplen == 1 && len > 0) {
3990 if (RSTRING_PTR(str)[len-1] == '\r') {
3991 rb_str_resize(str, --len);
3992 break;
3993 }
3994 }
3995 }
3996 len += pending - chomplen;
3997 if (cr != ENC_CODERANGE_BROKEN)
3998 pos += rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + len, enc, &cr);
3999 if (e) break;
4000 }
4001 READ_CHECK(fptr);
4002 } while (io_fillbuf(fptr) >= 0);
4003 if (NIL_P(str)) return Qnil;
4004
4005 str = io_enc_str(str, fptr);
4006 ENC_CODERANGE_SET(str, cr);
4007 fptr->lineno++;
4008
4009 return str;
4010}
4011
4013 VALUE io;
4014 VALUE rs;
4015 long limit;
4016 unsigned int chomp: 1;
4017};
4018
4019static void
4020extract_getline_opts(VALUE opts, struct getline_arg *args)
4021{
4022 int chomp = FALSE;
4023 if (!NIL_P(opts)) {
4024 static ID kwds[1];
4025 VALUE vchomp;
4026 if (!kwds[0]) {
4027 kwds[0] = rb_intern_const("chomp");
4028 }
4029 rb_get_kwargs(opts, kwds, 0, -2, &vchomp);
4030 chomp = (!UNDEF_P(vchomp)) && RTEST(vchomp);
4031 }
4032 args->chomp = chomp;
4033}
4034
4035static void
4036extract_getline_args(int argc, VALUE *argv, struct getline_arg *args)
4037{
4038 VALUE rs = rb_rs, lim = Qnil;
4039
4040 if (argc == 1) {
4041 VALUE tmp = Qnil;
4042
4043 if (NIL_P(argv[0]) || !NIL_P(tmp = rb_check_string_type(argv[0]))) {
4044 rs = tmp;
4045 }
4046 else {
4047 lim = argv[0];
4048 }
4049 }
4050 else if (2 <= argc) {
4051 rs = argv[0], lim = argv[1];
4052 if (!NIL_P(rs))
4053 StringValue(rs);
4054 }
4055 args->rs = rs;
4056 args->limit = NIL_P(lim) ? -1L : NUM2LONG(lim);
4057}
4058
4059static void
4060check_getline_args(VALUE *rsp, long *limit, VALUE io)
4061{
4062 rb_io_t *fptr;
4063 VALUE rs = *rsp;
4064
4065 if (!NIL_P(rs)) {
4066 rb_encoding *enc_rs, *enc_io;
4067
4068 GetOpenFile(io, fptr);
4069 enc_rs = rb_enc_get(rs);
4070 enc_io = io_read_encoding(fptr);
4071 if (enc_io != enc_rs &&
4072 (!is_ascii_string(rs) ||
4073 (RSTRING_LEN(rs) > 0 && !rb_enc_asciicompat(enc_io)))) {
4074 if (rs == rb_default_rs) {
4075 rs = rb_enc_str_new(0, 0, enc_io);
4076 rb_str_buf_cat_ascii(rs, "\n");
4077 *rsp = rs;
4078 }
4079 else {
4080 rb_raise(rb_eArgError, "encoding mismatch: %s IO with %s RS",
4081 rb_enc_name(enc_io),
4082 rb_enc_name(enc_rs));
4083 }
4084 }
4085 }
4086}
4087
4088static void
4089prepare_getline_args(int argc, VALUE *argv, struct getline_arg *args, VALUE io)
4090{
4091 VALUE opts;
4092 argc = rb_scan_args(argc, argv, "02:", NULL, NULL, &opts);
4093 extract_getline_args(argc, argv, args);
4094 extract_getline_opts(opts, args);
4095 check_getline_args(&args->rs, &args->limit, io);
4096}
4097
4098static VALUE
4099rb_io_getline_0(VALUE rs, long limit, int chomp, rb_io_t *fptr)
4100{
4101 VALUE str = Qnil;
4102 int nolimit = 0;
4103 rb_encoding *enc;
4104
4106 if (NIL_P(rs) && limit < 0) {
4107 str = read_all(fptr, 0, Qnil);
4108 if (RSTRING_LEN(str) == 0) return Qnil;
4109 }
4110 else if (limit == 0) {
4111 return rb_enc_str_new(0, 0, io_read_encoding(fptr));
4112 }
4113 else if (rs == rb_default_rs && limit < 0 && !NEED_READCONV(fptr) &&
4114 rb_enc_asciicompat(enc = io_read_encoding(fptr))) {
4115 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4116 return rb_io_getline_fast(fptr, enc, chomp);
4117 }
4118 else {
4119 int c, newline = -1;
4120 const char *rsptr = 0;
4121 long rslen = 0;
4122 int rspara = 0;
4123 int extra_limit = 16;
4124 int chomp_cr = chomp;
4125
4126 SET_BINARY_MODE(fptr);
4127 enc = io_read_encoding(fptr);
4128
4129 if (!NIL_P(rs)) {
4130 rslen = RSTRING_LEN(rs);
4131 if (rslen == 0) {
4132 rsptr = "\n\n";
4133 rslen = 2;
4134 rspara = 1;
4135 swallow(fptr, '\n');
4136 rs = 0;
4137 if (!rb_enc_asciicompat(enc)) {
4138 rs = rb_usascii_str_new(rsptr, rslen);
4139 rs = rb_str_encode(rs, rb_enc_from_encoding(enc), 0, Qnil);
4140 OBJ_FREEZE(rs);
4141 rsptr = RSTRING_PTR(rs);
4142 rslen = RSTRING_LEN(rs);
4143 }
4144 }
4145 else {
4146 rsptr = RSTRING_PTR(rs);
4147 }
4148 newline = (unsigned char)rsptr[rslen - 1];
4149 chomp_cr = chomp && rslen == 1 && newline == '\n';
4150 }
4151
4152 /* MS - Optimization */
4153 while ((c = appendline(fptr, newline, &str, &limit)) != EOF) {
4154 const char *s, *p, *pp, *e;
4155
4156 if (c == newline) {
4157 if (RSTRING_LEN(str) < rslen) continue;
4158 s = RSTRING_PTR(str);
4159 e = RSTRING_END(str);
4160 p = e - rslen;
4161 if (!at_char_boundary(s, p, e, enc)) continue;
4162 if (!rspara) rscheck(rsptr, rslen, rs);
4163 if (memcmp(p, rsptr, rslen) == 0) {
4164 if (chomp) {
4165 if (chomp_cr && p > s && *(p-1) == '\r') --p;
4166 rb_str_set_len(str, p - s);
4167 }
4168 break;
4169 }
4170 }
4171 if (limit == 0) {
4172 s = RSTRING_PTR(str);
4173 p = RSTRING_END(str);
4174 pp = rb_enc_left_char_head(s, p-1, p, enc);
4175 if (extra_limit &&
4176 MBCLEN_NEEDMORE_P(rb_enc_precise_mbclen(pp, p, enc))) {
4177 /* relax the limit while incomplete character.
4178 * extra_limit limits the relax length */
4179 limit = 1;
4180 extra_limit--;
4181 }
4182 else {
4183 nolimit = 1;
4184 break;
4185 }
4186 }
4187 }
4188
4189 if (rspara && c != EOF)
4190 swallow(fptr, '\n');
4191 if (!NIL_P(str))
4192 str = io_enc_str(str, fptr);
4193 }
4194
4195 if (!NIL_P(str) && !nolimit) {
4196 fptr->lineno++;
4197 }
4198
4199 return str;
4200}
4201
4202static VALUE
4203rb_io_getline_1(VALUE rs, long limit, int chomp, VALUE io)
4204{
4205 rb_io_t *fptr;
4206 int old_lineno, new_lineno;
4207 VALUE str;
4208
4209 GetOpenFile(io, fptr);
4210 old_lineno = fptr->lineno;
4211 str = rb_io_getline_0(rs, limit, chomp, fptr);
4212 if (!NIL_P(str) && (new_lineno = fptr->lineno) != old_lineno) {
4213 if (io == ARGF.current_file) {
4214 ARGF.lineno += new_lineno - old_lineno;
4215 ARGF.last_lineno = ARGF.lineno;
4216 }
4217 else {
4218 ARGF.last_lineno = new_lineno;
4219 }
4220 }
4221
4222 return str;
4223}
4224
4225static VALUE
4226rb_io_getline(int argc, VALUE *argv, VALUE io)
4227{
4228 struct getline_arg args;
4229
4230 prepare_getline_args(argc, argv, &args, io);
4231 return rb_io_getline_1(args.rs, args.limit, args.chomp, io);
4232}
4233
4234VALUE
4236{
4237 return rb_io_getline_1(rb_default_rs, -1, FALSE, io);
4238}
4239
4240VALUE
4241rb_io_gets_internal(VALUE io)
4242{
4243 rb_io_t *fptr;
4244 GetOpenFile(io, fptr);
4245 return rb_io_getline_0(rb_default_rs, -1, FALSE, fptr);
4246}
4247
4248/*
4249 * call-seq:
4250 * gets(sep = $/, chomp: false) -> string or nil
4251 * gets(limit, chomp: false) -> string or nil
4252 * gets(sep, limit, chomp: false) -> string or nil
4253 *
4254 * Reads and returns a line from the stream;
4255 * assigns the return value to <tt>$_</tt>.
4256 * See {Line IO}[rdoc-ref:IO@Line+IO].
4257 *
4258 * With no arguments given, returns the next line
4259 * as determined by line separator <tt>$/</tt>, or +nil+ if none:
4260 *
4261 * f = File.open('t.txt')
4262 * f.gets # => "First line\n"
4263 * $_ # => "First line\n"
4264 * f.gets # => "\n"
4265 * f.gets # => "Fourth line\n"
4266 * f.gets # => "Fifth line\n"
4267 * f.gets # => nil
4268 * f.close
4269 *
4270 * With only string argument +sep+ given,
4271 * returns the next line as determined by line separator +sep+,
4272 * or +nil+ if none;
4273 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4274 *
4275 * f = File.new('t.txt')
4276 * f.gets('l') # => "First l"
4277 * f.gets('li') # => "ine\nSecond li"
4278 * f.gets('lin') # => "ne\n\nFourth lin"
4279 * f.gets # => "e\n"
4280 * f.close
4281 *
4282 * The two special values for +sep+ are honored:
4283 *
4284 * f = File.new('t.txt')
4285 * # Get all.
4286 * f.gets(nil) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
4287 * f.rewind
4288 * # Get paragraph (up to two line separators).
4289 * f.gets('') # => "First line\nSecond line\n\n"
4290 * f.close
4291 *
4292 * With only integer argument +limit+ given,
4293 * limits the number of bytes in the line;
4294 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4295 *
4296 * # No more than one line.
4297 * File.open('t.txt') {|f| f.gets(10) } # => "First line"
4298 * File.open('t.txt') {|f| f.gets(11) } # => "First line\n"
4299 * File.open('t.txt') {|f| f.gets(12) } # => "First line\n"
4300 *
4301 * With arguments +sep+ and +limit+ given,
4302 * combines the two behaviors:
4303 *
4304 * - Returns the next line as determined by line separator +sep+,
4305 * or +nil+ if none.
4306 * - But returns no more bytes than are allowed by the limit.
4307 *
4308 * Optional keyword argument +chomp+ specifies whether line separators
4309 * are to be omitted:
4310 *
4311 * f = File.open('t.txt')
4312 * # Chomp the lines.
4313 * f.gets(chomp: true) # => "First line"
4314 * f.gets(chomp: true) # => "Second line"
4315 * f.gets(chomp: true) # => ""
4316 * f.gets(chomp: true) # => "Fourth line"
4317 * f.gets(chomp: true) # => "Fifth line"
4318 * f.gets(chomp: true) # => nil
4319 * f.close
4320 *
4321 */
4322
4323static VALUE
4324rb_io_gets_m(int argc, VALUE *argv, VALUE io)
4325{
4326 VALUE str;
4327
4328 str = rb_io_getline(argc, argv, io);
4329 rb_lastline_set(str);
4330
4331 return str;
4332}
4333
4334/*
4335 * call-seq:
4336 * lineno -> integer
4337 *
4338 * Returns the current line number for the stream;
4339 * see {Line Number}[rdoc-ref:IO@Line+Number].
4340 *
4341 */
4342
4343static VALUE
4344rb_io_lineno(VALUE io)
4345{
4346 rb_io_t *fptr;
4347
4348 GetOpenFile(io, fptr);
4350 return INT2NUM(fptr->lineno);
4351}
4352
4353/*
4354 * call-seq:
4355 * lineno = integer -> integer
4356 *
4357 * Sets and returns the line number for the stream;
4358 * see {Line Number}[rdoc-ref:IO@Line+Number].
4359 *
4360 */
4361
4362static VALUE
4363rb_io_set_lineno(VALUE io, VALUE lineno)
4364{
4365 rb_io_t *fptr;
4366
4367 GetOpenFile(io, fptr);
4369 fptr->lineno = NUM2INT(lineno);
4370 return lineno;
4371}
4372
4373/* :nodoc: */
4374static VALUE
4375io_readline(rb_execution_context_t *ec, VALUE io, VALUE sep, VALUE lim, VALUE chomp)
4376{
4377 if (NIL_P(lim)) {
4378 // If sep is specified, but it's not a string and not nil, then assume
4379 // it's the limit (it should be an integer)
4380 if (!NIL_P(sep) && NIL_P(rb_check_string_type(sep))) {
4381 // If the user has specified a non-nil / non-string value
4382 // for the separator, we assume it's the limit and set the
4383 // separator to default: rb_rs.
4384 lim = sep;
4385 sep = rb_rs;
4386 }
4387 }
4388
4389 if (!NIL_P(sep)) {
4390 StringValue(sep);
4391 }
4392
4393 VALUE line = rb_io_getline_1(sep, NIL_P(lim) ? -1L : NUM2LONG(lim), RTEST(chomp), io);
4394 rb_lastline_set_up(line, 1);
4395
4396 if (NIL_P(line)) {
4397 rb_eof_error();
4398 }
4399 return line;
4400}
4401
4402static VALUE io_readlines(const struct getline_arg *arg, VALUE io);
4403
4404/*
4405 * call-seq:
4406 * readlines(sep = $/, chomp: false) -> array
4407 * readlines(limit, chomp: false) -> array
4408 * readlines(sep, limit, chomp: false) -> array
4409 *
4410 * Reads and returns all remaining line from the stream;
4411 * does not modify <tt>$_</tt>.
4412 * See {Line IO}[rdoc-ref:IO@Line+IO].
4413 *
4414 * With no arguments given, returns lines
4415 * as determined by line separator <tt>$/</tt>, or +nil+ if none:
4416 *
4417 * f = File.new('t.txt')
4418 * f.readlines
4419 * # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
4420 * f.readlines # => []
4421 * f.close
4422 *
4423 * With only string argument +sep+ given,
4424 * returns lines as determined by line separator +sep+,
4425 * or +nil+ if none;
4426 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4427 *
4428 * f = File.new('t.txt')
4429 * f.readlines('li')
4430 * # => ["First li", "ne\nSecond li", "ne\n\nFourth li", "ne\nFifth li", "ne\n"]
4431 * f.close
4432 *
4433 * The two special values for +sep+ are honored:
4434 *
4435 * f = File.new('t.txt')
4436 * # Get all into one string.
4437 * f.readlines(nil)
4438 * # => ["First line\nSecond line\n\nFourth line\nFifth line\n"]
4439 * # Get paragraphs (up to two line separators).
4440 * f.rewind
4441 * f.readlines('')
4442 * # => ["First line\nSecond line\n\n", "Fourth line\nFifth line\n"]
4443 * f.close
4444 *
4445 * With only integer argument +limit+ given,
4446 * limits the number of bytes in each line;
4447 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4448 *
4449 * f = File.new('t.txt')
4450 * f.readlines(8)
4451 * # => ["First li", "ne\n", "Second l", "ine\n", "\n", "Fourth l", "ine\n", "Fifth li", "ne\n"]
4452 * f.close
4453 *
4454 * With arguments +sep+ and +limit+ given,
4455 * combines the two behaviors:
4456 *
4457 * - Returns lines as determined by line separator +sep+.
4458 * - But returns no more bytes in a line than are allowed by the limit.
4459 *
4460 * Optional keyword argument +chomp+ specifies whether line separators
4461 * are to be omitted:
4462 *
4463 * f = File.new('t.txt')
4464 * f.readlines(chomp: true)
4465 * # => ["First line", "Second line", "", "Fourth line", "Fifth line"]
4466 * f.close
4467 *
4468 */
4469
4470static VALUE
4471rb_io_readlines(int argc, VALUE *argv, VALUE io)
4472{
4473 struct getline_arg args;
4474
4475 prepare_getline_args(argc, argv, &args, io);
4476 return io_readlines(&args, io);
4477}
4478
4479static VALUE
4480io_readlines(const struct getline_arg *arg, VALUE io)
4481{
4482 VALUE line, ary;
4483
4484 if (arg->limit == 0)
4485 rb_raise(rb_eArgError, "invalid limit: 0 for readlines");
4486 ary = rb_ary_new();
4487 while (!NIL_P(line = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, io))) {
4488 rb_ary_push(ary, line);
4489 }
4490 return ary;
4491}
4492
4493/*
4494 * call-seq:
4495 * each_line(sep = $/, chomp: false) {|line| ... } -> self
4496 * each_line(limit, chomp: false) {|line| ... } -> self
4497 * each_line(sep, limit, chomp: false) {|line| ... } -> self
4498 * each_line -> enumerator
4499 *
4500 * Calls the block with each remaining line read from the stream;
4501 * returns +self+.
4502 * Does nothing if already at end-of-stream;
4503 * See {Line IO}[rdoc-ref:IO@Line+IO].
4504 *
4505 * With no arguments given, reads lines
4506 * as determined by line separator <tt>$/</tt>:
4507 *
4508 * f = File.new('t.txt')
4509 * f.each_line {|line| p line }
4510 * f.each_line {|line| fail 'Cannot happen' }
4511 * f.close
4512 *
4513 * Output:
4514 *
4515 * "First line\n"
4516 * "Second line\n"
4517 * "\n"
4518 * "Fourth line\n"
4519 * "Fifth line\n"
4520 *
4521 * With only string argument +sep+ given,
4522 * reads lines as determined by line separator +sep+;
4523 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4524 *
4525 * f = File.new('t.txt')
4526 * f.each_line('li') {|line| p line }
4527 * f.close
4528 *
4529 * Output:
4530 *
4531 * "First li"
4532 * "ne\nSecond li"
4533 * "ne\n\nFourth li"
4534 * "ne\nFifth li"
4535 * "ne\n"
4536 *
4537 * The two special values for +sep+ are honored:
4538 *
4539 * f = File.new('t.txt')
4540 * # Get all into one string.
4541 * f.each_line(nil) {|line| p line }
4542 * f.close
4543 *
4544 * Output:
4545 *
4546 * "First line\nSecond line\n\nFourth line\nFifth line\n"
4547 *
4548 * f.rewind
4549 * # Get paragraphs (up to two line separators).
4550 * f.each_line('') {|line| p line }
4551 *
4552 * Output:
4553 *
4554 * "First line\nSecond line\n\n"
4555 * "Fourth line\nFifth line\n"
4556 *
4557 * With only integer argument +limit+ given,
4558 * limits the number of bytes in each line;
4559 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4560 *
4561 * f = File.new('t.txt')
4562 * f.each_line(8) {|line| p line }
4563 * f.close
4564 *
4565 * Output:
4566 *
4567 * "First li"
4568 * "ne\n"
4569 * "Second l"
4570 * "ine\n"
4571 * "\n"
4572 * "Fourth l"
4573 * "ine\n"
4574 * "Fifth li"
4575 * "ne\n"
4576 *
4577 * With arguments +sep+ and +limit+ given,
4578 * combines the two behaviors:
4579 *
4580 * - Calls with the next line as determined by line separator +sep+.
4581 * - But returns no more bytes than are allowed by the limit.
4582 *
4583 * Optional keyword argument +chomp+ specifies whether line separators
4584 * are to be omitted:
4585 *
4586 * f = File.new('t.txt')
4587 * f.each_line(chomp: true) {|line| p line }
4588 * f.close
4589 *
4590 * Output:
4591 *
4592 * "First line"
4593 * "Second line"
4594 * ""
4595 * "Fourth line"
4596 * "Fifth line"
4597 *
4598 * Returns an Enumerator if no block is given.
4599 */
4600
4601static VALUE
4602rb_io_each_line(int argc, VALUE *argv, VALUE io)
4603{
4604 VALUE str;
4605 struct getline_arg args;
4606
4607 RETURN_ENUMERATOR(io, argc, argv);
4608 prepare_getline_args(argc, argv, &args, io);
4609 if (args.limit == 0)
4610 rb_raise(rb_eArgError, "invalid limit: 0 for each_line");
4611 while (!NIL_P(str = rb_io_getline_1(args.rs, args.limit, args.chomp, io))) {
4612 rb_yield(str);
4613 }
4614 return io;
4615}
4616
4617/*
4618 * call-seq:
4619 * each_byte {|byte| ... } -> self
4620 * each_byte -> enumerator
4621 *
4622 * Calls the given block with each byte (0..255) in the stream; returns +self+.
4623 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
4624 *
4625 * f = File.new('t.rus')
4626 * a = []
4627 * f.each_byte {|b| a << b }
4628 * a # => [209, 130, 208, 181, 209, 129, 209, 130]
4629 * f.close
4630 *
4631 * Returns an Enumerator if no block is given.
4632 *
4633 * Related: IO#each_char, IO#each_codepoint.
4634 *
4635 */
4636
4637static VALUE
4638rb_io_each_byte(VALUE io)
4639{
4640 rb_io_t *fptr;
4641
4642 RETURN_ENUMERATOR(io, 0, 0);
4643 GetOpenFile(io, fptr);
4644
4645 do {
4646 while (fptr->rbuf.len > 0) {
4647 char *p = fptr->rbuf.ptr + fptr->rbuf.off++;
4648 fptr->rbuf.len--;
4649 rb_yield(INT2FIX(*p & 0xff));
4651 errno = 0;
4652 }
4653 READ_CHECK(fptr);
4654 } while (io_fillbuf(fptr) >= 0);
4655 return io;
4656}
4657
4658static VALUE
4659io_getc(rb_io_t *fptr, rb_encoding *enc)
4660{
4661 int r, n, cr = 0;
4662 VALUE str;
4663
4664 if (NEED_READCONV(fptr)) {
4665 rb_encoding *read_enc = io_read_encoding(fptr);
4666
4667 str = Qnil;
4668 SET_BINARY_MODE(fptr);
4669 make_readconv(fptr, 0);
4670
4671 while (1) {
4672 if (fptr->cbuf.len) {
4673 r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4674 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4675 read_enc);
4676 if (!MBCLEN_NEEDMORE_P(r))
4677 break;
4678 if (fptr->cbuf.len == fptr->cbuf.capa) {
4679 rb_raise(rb_eIOError, "too long character");
4680 }
4681 }
4682
4683 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4684 if (fptr->cbuf.len == 0) {
4685 clear_readconv(fptr);
4686 return Qnil;
4687 }
4688 /* return an unit of an incomplete character just before EOF */
4689 str = rb_enc_str_new(fptr->cbuf.ptr+fptr->cbuf.off, 1, read_enc);
4690 fptr->cbuf.off += 1;
4691 fptr->cbuf.len -= 1;
4692 if (fptr->cbuf.len == 0) clear_readconv(fptr);
4694 return str;
4695 }
4696 }
4697 if (MBCLEN_INVALID_P(r)) {
4698 r = rb_enc_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4699 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4700 read_enc);
4701 io_shift_cbuf(fptr, r, &str);
4703 }
4704 else {
4705 io_shift_cbuf(fptr, MBCLEN_CHARFOUND_LEN(r), &str);
4707 if (MBCLEN_CHARFOUND_LEN(r) == 1 && rb_enc_asciicompat(read_enc) &&
4708 ISASCII(RSTRING_PTR(str)[0])) {
4709 cr = ENC_CODERANGE_7BIT;
4710 }
4711 }
4712 str = io_enc_str(str, fptr);
4713 ENC_CODERANGE_SET(str, cr);
4714 return str;
4715 }
4716
4717 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4718 if (io_fillbuf(fptr) < 0) {
4719 return Qnil;
4720 }
4721 if (rb_enc_asciicompat(enc) && ISASCII(fptr->rbuf.ptr[fptr->rbuf.off])) {
4722 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, 1);
4723 fptr->rbuf.off += 1;
4724 fptr->rbuf.len -= 1;
4725 cr = ENC_CODERANGE_7BIT;
4726 }
4727 else {
4728 r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off, fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4729 if (MBCLEN_CHARFOUND_P(r) &&
4730 (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
4731 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, n);
4732 fptr->rbuf.off += n;
4733 fptr->rbuf.len -= n;
4735 }
4736 else if (MBCLEN_NEEDMORE_P(r)) {
4737 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, fptr->rbuf.len);
4738 fptr->rbuf.len = 0;
4739 getc_needmore:
4740 if (io_fillbuf(fptr) != -1) {
4741 rb_str_cat(str, fptr->rbuf.ptr+fptr->rbuf.off, 1);
4742 fptr->rbuf.off++;
4743 fptr->rbuf.len--;
4744 r = rb_enc_precise_mbclen(RSTRING_PTR(str), RSTRING_PTR(str)+RSTRING_LEN(str), enc);
4745 if (MBCLEN_NEEDMORE_P(r)) {
4746 goto getc_needmore;
4747 }
4748 else if (MBCLEN_CHARFOUND_P(r)) {
4750 }
4751 }
4752 }
4753 else {
4754 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, 1);
4755 fptr->rbuf.off++;
4756 fptr->rbuf.len--;
4757 }
4758 }
4759 if (!cr) cr = ENC_CODERANGE_BROKEN;
4760 str = io_enc_str(str, fptr);
4761 ENC_CODERANGE_SET(str, cr);
4762 return str;
4763}
4764
4765/*
4766 * call-seq:
4767 * each_char {|c| ... } -> self
4768 * each_char -> enumerator
4769 *
4770 * Calls the given block with each character in the stream; returns +self+.
4771 * See {Character IO}[rdoc-ref:IO@Character+IO].
4772 *
4773 * f = File.new('t.rus')
4774 * a = []
4775 * f.each_char {|c| a << c.ord }
4776 * a # => [1090, 1077, 1089, 1090]
4777 * f.close
4778 *
4779 * Returns an Enumerator if no block is given.
4780 *
4781 * Related: IO#each_byte, IO#each_codepoint.
4782 *
4783 */
4784
4785static VALUE
4786rb_io_each_char(VALUE io)
4787{
4788 rb_io_t *fptr;
4789 rb_encoding *enc;
4790 VALUE c;
4791
4792 RETURN_ENUMERATOR(io, 0, 0);
4793 GetOpenFile(io, fptr);
4795
4796 enc = io_input_encoding(fptr);
4797 READ_CHECK(fptr);
4798 while (!NIL_P(c = io_getc(fptr, enc))) {
4799 rb_yield(c);
4800 }
4801 return io;
4802}
4803
4804/*
4805 * call-seq:
4806 * each_codepoint {|c| ... } -> self
4807 * each_codepoint -> enumerator
4808 *
4809 * Calls the given block with each codepoint in the stream; returns +self+:
4810 *
4811 * f = File.new('t.rus')
4812 * a = []
4813 * f.each_codepoint {|c| a << c }
4814 * a # => [1090, 1077, 1089, 1090]
4815 * f.close
4816 *
4817 * Returns an Enumerator if no block is given.
4818 *
4819 * Related: IO#each_byte, IO#each_char.
4820 *
4821 */
4822
4823static VALUE
4824rb_io_each_codepoint(VALUE io)
4825{
4826 rb_io_t *fptr;
4827 rb_encoding *enc;
4828 unsigned int c;
4829 int r, n;
4830
4831 RETURN_ENUMERATOR(io, 0, 0);
4832 GetOpenFile(io, fptr);
4834
4835 READ_CHECK(fptr);
4836 if (NEED_READCONV(fptr)) {
4837 SET_BINARY_MODE(fptr);
4838 r = 1; /* no invalid char yet */
4839 for (;;) {
4840 make_readconv(fptr, 0);
4841 for (;;) {
4842 if (fptr->cbuf.len) {
4843 if (fptr->encs.enc)
4844 r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4845 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4846 fptr->encs.enc);
4847 else
4848 r = ONIGENC_CONSTRUCT_MBCLEN_CHARFOUND(1);
4849 if (!MBCLEN_NEEDMORE_P(r))
4850 break;
4851 if (fptr->cbuf.len == fptr->cbuf.capa) {
4852 rb_raise(rb_eIOError, "too long character");
4853 }
4854 }
4855 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4856 clear_readconv(fptr);
4857 if (!MBCLEN_CHARFOUND_P(r)) {
4858 enc = fptr->encs.enc;
4859 goto invalid;
4860 }
4861 return io;
4862 }
4863 }
4864 if (MBCLEN_INVALID_P(r)) {
4865 enc = fptr->encs.enc;
4866 goto invalid;
4867 }
4868 n = MBCLEN_CHARFOUND_LEN(r);
4869 if (fptr->encs.enc) {
4870 c = rb_enc_codepoint(fptr->cbuf.ptr+fptr->cbuf.off,
4871 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4872 fptr->encs.enc);
4873 }
4874 else {
4875 c = (unsigned char)fptr->cbuf.ptr[fptr->cbuf.off];
4876 }
4877 fptr->cbuf.off += n;
4878 fptr->cbuf.len -= n;
4879 rb_yield(UINT2NUM(c));
4881 }
4882 }
4883 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4884 enc = io_input_encoding(fptr);
4885 while (io_fillbuf(fptr) >= 0) {
4886 r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off,
4887 fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4888 if (MBCLEN_CHARFOUND_P(r) &&
4889 (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
4890 c = rb_enc_codepoint(fptr->rbuf.ptr+fptr->rbuf.off,
4891 fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4892 fptr->rbuf.off += n;
4893 fptr->rbuf.len -= n;
4894 rb_yield(UINT2NUM(c));
4895 }
4896 else if (MBCLEN_INVALID_P(r)) {
4897 goto invalid;
4898 }
4899 else if (MBCLEN_NEEDMORE_P(r)) {
4900 char cbuf[8], *p = cbuf;
4901 int more = MBCLEN_NEEDMORE_LEN(r);
4902 if (more > numberof(cbuf)) goto invalid;
4903 more += n = fptr->rbuf.len;
4904 if (more > numberof(cbuf)) goto invalid;
4905 while ((n = (int)read_buffered_data(p, more, fptr)) > 0 &&
4906 (p += n, (more -= n) > 0)) {
4907 if (io_fillbuf(fptr) < 0) goto invalid;
4908 if ((n = fptr->rbuf.len) > more) n = more;
4909 }
4910 r = rb_enc_precise_mbclen(cbuf, p, enc);
4911 if (!MBCLEN_CHARFOUND_P(r)) goto invalid;
4912 c = rb_enc_codepoint(cbuf, p, enc);
4913 rb_yield(UINT2NUM(c));
4914 }
4915 else {
4916 continue;
4917 }
4919 }
4920 return io;
4921
4922 invalid:
4923 rb_raise(rb_eArgError, "invalid byte sequence in %s", rb_enc_name(enc));
4925}
4926
4927/*
4928 * call-seq:
4929 * getc -> character or nil
4930 *
4931 * Reads and returns the next 1-character string from the stream;
4932 * returns +nil+ if already at end-of-stream.
4933 * See {Character IO}[rdoc-ref:IO@Character+IO].
4934 *
4935 * f = File.open('t.txt')
4936 * f.getc # => "F"
4937 * f.close
4938 * f = File.open('t.rus')
4939 * f.getc.ord # => 1090
4940 * f.close
4941 *
4942 * Related: IO#readchar (may raise EOFError).
4943 *
4944 */
4945
4946static VALUE
4947rb_io_getc(VALUE io)
4948{
4949 rb_io_t *fptr;
4950 rb_encoding *enc;
4951
4952 GetOpenFile(io, fptr);
4954
4955 enc = io_input_encoding(fptr);
4956 READ_CHECK(fptr);
4957 return io_getc(fptr, enc);
4958}
4959
4960/*
4961 * call-seq:
4962 * readchar -> string
4963 *
4964 * Reads and returns the next 1-character string from the stream;
4965 * raises EOFError if already at end-of-stream.
4966 * See {Character IO}[rdoc-ref:IO@Character+IO].
4967 *
4968 * f = File.open('t.txt')
4969 * f.readchar # => "F"
4970 * f.close
4971 * f = File.open('t.rus')
4972 * f.readchar.ord # => 1090
4973 * f.close
4974 *
4975 * Related: IO#getc (will not raise EOFError).
4976 *
4977 */
4978
4979static VALUE
4980rb_io_readchar(VALUE io)
4981{
4982 VALUE c = rb_io_getc(io);
4983
4984 if (NIL_P(c)) {
4985 rb_eof_error();
4986 }
4987 return c;
4988}
4989
4990/*
4991 * call-seq:
4992 * getbyte -> integer or nil
4993 *
4994 * Reads and returns the next byte (in range 0..255) from the stream;
4995 * returns +nil+ if already at end-of-stream.
4996 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
4997 *
4998 * f = File.open('t.txt')
4999 * f.getbyte # => 70
5000 * f.close
5001 * f = File.open('t.rus')
5002 * f.getbyte # => 209
5003 * f.close
5004 *
5005 * Related: IO#readbyte (may raise EOFError).
5006 */
5007
5008VALUE
5010{
5011 rb_io_t *fptr;
5012 int c;
5013
5014 GetOpenFile(io, fptr);
5016 READ_CHECK(fptr);
5017 VALUE r_stdout = rb_ractor_stdout();
5018 if (fptr->fd == 0 && (fptr->mode & FMODE_TTY) && RB_TYPE_P(r_stdout, T_FILE)) {
5019 rb_io_t *ofp;
5020 GetOpenFile(r_stdout, ofp);
5021 if (ofp->mode & FMODE_TTY) {
5022 rb_io_flush(r_stdout);
5023 }
5024 }
5025 if (io_fillbuf(fptr) < 0) {
5026 return Qnil;
5027 }
5028 fptr->rbuf.off++;
5029 fptr->rbuf.len--;
5030 c = (unsigned char)fptr->rbuf.ptr[fptr->rbuf.off-1];
5031 return INT2FIX(c & 0xff);
5032}
5033
5034/*
5035 * call-seq:
5036 * readbyte -> integer
5037 *
5038 * Reads and returns the next byte (in range 0..255) from the stream;
5039 * raises EOFError if already at end-of-stream.
5040 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5041 *
5042 * f = File.open('t.txt')
5043 * f.readbyte # => 70
5044 * f.close
5045 * f = File.open('t.rus')
5046 * f.readbyte # => 209
5047 * f.close
5048 *
5049 * Related: IO#getbyte (will not raise EOFError).
5050 *
5051 */
5052
5053static VALUE
5054rb_io_readbyte(VALUE io)
5055{
5056 VALUE c = rb_io_getbyte(io);
5057
5058 if (NIL_P(c)) {
5059 rb_eof_error();
5060 }
5061 return c;
5062}
5063
5064/*
5065 * call-seq:
5066 * ungetbyte(integer) -> nil
5067 * ungetbyte(string) -> nil
5068 *
5069 * Pushes back ("unshifts") the given data onto the stream's buffer,
5070 * placing the data so that it is next to be read; returns +nil+.
5071 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5072 *
5073 * Note that:
5074 *
5075 * - Calling the method has no effect with unbuffered reads (such as IO#sysread).
5076 * - Calling #rewind on the stream discards the pushed-back data.
5077 *
5078 * When argument +integer+ is given, uses only its low-order byte:
5079 *
5080 * File.write('t.tmp', '012')
5081 * f = File.open('t.tmp')
5082 * f.ungetbyte(0x41) # => nil
5083 * f.read # => "A012"
5084 * f.rewind
5085 * f.ungetbyte(0x4243) # => nil
5086 * f.read # => "C012"
5087 * f.close
5088 *
5089 * When argument +string+ is given, uses all bytes:
5090 *
5091 * File.write('t.tmp', '012')
5092 * f = File.open('t.tmp')
5093 * f.ungetbyte('A') # => nil
5094 * f.read # => "A012"
5095 * f.rewind
5096 * f.ungetbyte('BCDE') # => nil
5097 * f.read # => "BCDE012"
5098 * f.close
5099 *
5100 */
5101
5102VALUE
5104{
5105 rb_io_t *fptr;
5106
5107 GetOpenFile(io, fptr);
5109 switch (TYPE(b)) {
5110 case T_NIL:
5111 return Qnil;
5112 case T_FIXNUM:
5113 case T_BIGNUM: ;
5114 VALUE v = rb_int_modulo(b, INT2FIX(256));
5115 unsigned char c = NUM2INT(v) & 0xFF;
5116 b = rb_str_new((const char *)&c, 1);
5117 break;
5118 default:
5119 SafeStringValue(b);
5120 }
5121 io_ungetbyte(b, fptr);
5122 return Qnil;
5123}
5124
5125/*
5126 * call-seq:
5127 * ungetc(integer) -> nil
5128 * ungetc(string) -> nil
5129 *
5130 * Pushes back ("unshifts") the given data onto the stream's buffer,
5131 * placing the data so that it is next to be read; returns +nil+.
5132 * See {Character IO}[rdoc-ref:IO@Character+IO].
5133 *
5134 * Note that:
5135 *
5136 * - Calling the method has no effect with unbuffered reads (such as IO#sysread).
5137 * - Calling #rewind on the stream discards the pushed-back data.
5138 *
5139 * When argument +integer+ is given, interprets the integer as a character:
5140 *
5141 * File.write('t.tmp', '012')
5142 * f = File.open('t.tmp')
5143 * f.ungetc(0x41) # => nil
5144 * f.read # => "A012"
5145 * f.rewind
5146 * f.ungetc(0x0442) # => nil
5147 * f.getc.ord # => 1090
5148 * f.close
5149 *
5150 * When argument +string+ is given, uses all characters:
5151 *
5152 * File.write('t.tmp', '012')
5153 * f = File.open('t.tmp')
5154 * f.ungetc('A') # => nil
5155 * f.read # => "A012"
5156 * f.rewind
5157 * f.ungetc("\u0442\u0435\u0441\u0442") # => nil
5158 * f.getc.ord # => 1090
5159 * f.getc.ord # => 1077
5160 * f.getc.ord # => 1089
5161 * f.getc.ord # => 1090
5162 * f.close
5163 *
5164 */
5165
5166VALUE
5168{
5169 rb_io_t *fptr;
5170 long len;
5171
5172 GetOpenFile(io, fptr);
5174 if (FIXNUM_P(c)) {
5175 c = rb_enc_uint_chr(FIX2UINT(c), io_read_encoding(fptr));
5176 }
5177 else if (RB_BIGNUM_TYPE_P(c)) {
5178 c = rb_enc_uint_chr(NUM2UINT(c), io_read_encoding(fptr));
5179 }
5180 else {
5181 SafeStringValue(c);
5182 }
5183 if (NEED_READCONV(fptr)) {
5184 SET_BINARY_MODE(fptr);
5185 len = RSTRING_LEN(c);
5186#if SIZEOF_LONG > SIZEOF_INT
5187 if (len > INT_MAX)
5188 rb_raise(rb_eIOError, "ungetc failed");
5189#endif
5190 make_readconv(fptr, (int)len);
5191 if (fptr->cbuf.capa - fptr->cbuf.len < len)
5192 rb_raise(rb_eIOError, "ungetc failed");
5193 if (fptr->cbuf.off < len) {
5194 MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.capa-fptr->cbuf.len,
5195 fptr->cbuf.ptr+fptr->cbuf.off,
5196 char, fptr->cbuf.len);
5197 fptr->cbuf.off = fptr->cbuf.capa-fptr->cbuf.len;
5198 }
5199 fptr->cbuf.off -= (int)len;
5200 fptr->cbuf.len += (int)len;
5201 MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.off, RSTRING_PTR(c), char, len);
5202 }
5203 else {
5204 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
5205 io_ungetbyte(c, fptr);
5206 }
5207 return Qnil;
5208}
5209
5210/*
5211 * call-seq:
5212 * isatty -> true or false
5213 *
5214 * Returns +true+ if the stream is associated with a terminal device (tty),
5215 * +false+ otherwise:
5216 *
5217 * f = File.new('t.txt').isatty #=> false
5218 * f.close
5219 * f = File.new('/dev/tty').isatty #=> true
5220 * f.close
5221 *
5222 */
5223
5224static VALUE
5225rb_io_isatty(VALUE io)
5226{
5227 rb_io_t *fptr;
5228
5229 GetOpenFile(io, fptr);
5230 return RBOOL(isatty(fptr->fd) != 0);
5231}
5232
5233#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5234/*
5235 * call-seq:
5236 * close_on_exec? -> true or false
5237 *
5238 * Returns +true+ if the stream will be closed on exec, +false+ otherwise:
5239 *
5240 * f = File.open('t.txt')
5241 * f.close_on_exec? # => true
5242 * f.close_on_exec = false
5243 * f.close_on_exec? # => false
5244 * f.close
5245 *
5246 */
5247
5248static VALUE
5249rb_io_close_on_exec_p(VALUE io)
5250{
5251 rb_io_t *fptr;
5252 VALUE write_io;
5253 int fd, ret;
5254
5255 write_io = GetWriteIO(io);
5256 if (io != write_io) {
5257 GetOpenFile(write_io, fptr);
5258 if (fptr && 0 <= (fd = fptr->fd)) {
5259 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5260 if (!(ret & FD_CLOEXEC)) return Qfalse;
5261 }
5262 }
5263
5264 GetOpenFile(io, fptr);
5265 if (fptr && 0 <= (fd = fptr->fd)) {
5266 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5267 if (!(ret & FD_CLOEXEC)) return Qfalse;
5268 }
5269 return Qtrue;
5270}
5271#else
5272#define rb_io_close_on_exec_p rb_f_notimplement
5273#endif
5274
5275#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5276/*
5277 * call-seq:
5278 * self.close_on_exec = bool -> true or false
5279 *
5280 * Sets a close-on-exec flag.
5281 *
5282 * f = File.open(File::NULL)
5283 * f.close_on_exec = true
5284 * system("cat", "/proc/self/fd/#{f.fileno}") # cat: /proc/self/fd/3: No such file or directory
5285 * f.closed? #=> false
5286 *
5287 * Ruby sets close-on-exec flags of all file descriptors by default
5288 * since Ruby 2.0.0.
5289 * So you don't need to set by yourself.
5290 * Also, unsetting a close-on-exec flag can cause file descriptor leak
5291 * if another thread use fork() and exec() (via system() method for example).
5292 * If you really needs file descriptor inheritance to child process,
5293 * use spawn()'s argument such as fd=>fd.
5294 */
5295
5296static VALUE
5297rb_io_set_close_on_exec(VALUE io, VALUE arg)
5298{
5299 int flag = RTEST(arg) ? FD_CLOEXEC : 0;
5300 rb_io_t *fptr;
5301 VALUE write_io;
5302 int fd, ret;
5303
5304 write_io = GetWriteIO(io);
5305 if (io != write_io) {
5306 GetOpenFile(write_io, fptr);
5307 if (fptr && 0 <= (fd = fptr->fd)) {
5308 if ((ret = fcntl(fptr->fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5309 if ((ret & FD_CLOEXEC) != flag) {
5310 ret = (ret & ~FD_CLOEXEC) | flag;
5311 ret = fcntl(fd, F_SETFD, ret);
5312 if (ret != 0) rb_sys_fail_path(fptr->pathv);
5313 }
5314 }
5315
5316 }
5317
5318 GetOpenFile(io, fptr);
5319 if (fptr && 0 <= (fd = fptr->fd)) {
5320 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5321 if ((ret & FD_CLOEXEC) != flag) {
5322 ret = (ret & ~FD_CLOEXEC) | flag;
5323 ret = fcntl(fd, F_SETFD, ret);
5324 if (ret != 0) rb_sys_fail_path(fptr->pathv);
5325 }
5326 }
5327 return Qnil;
5328}
5329#else
5330#define rb_io_set_close_on_exec rb_f_notimplement
5331#endif
5332
5333#define RUBY_IO_EXTERNAL_P(f) ((f)->mode & FMODE_EXTERNAL)
5334#define PREP_STDIO_NAME(f) (RSTRING_PTR((f)->pathv))
5335
5336static VALUE
5337finish_writeconv(rb_io_t *fptr, int noalloc)
5338{
5339 unsigned char *ds, *dp, *de;
5341
5342 if (!fptr->wbuf.ptr) {
5343 unsigned char buf[1024];
5344
5346 while (res == econv_destination_buffer_full) {
5347 ds = dp = buf;
5348 de = buf + sizeof(buf);
5349 res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
5350 while (dp-ds) {
5351 size_t remaining = dp-ds;
5352 long result = rb_io_write_memory(fptr, ds, remaining);
5353
5354 if (result > 0) {
5355 ds += result;
5356 if ((size_t)result == remaining) break;
5357 }
5358 else if (rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
5359 if (fptr->fd < 0)
5360 return noalloc ? Qtrue : rb_exc_new3(rb_eIOError, rb_str_new_cstr(closed_stream));
5361 }
5362 else {
5363 return noalloc ? Qtrue : INT2NUM(errno);
5364 }
5365 }
5366 if (res == econv_invalid_byte_sequence ||
5367 res == econv_incomplete_input ||
5369 return noalloc ? Qtrue : rb_econv_make_exception(fptr->writeconv);
5370 }
5371 }
5372
5373 return Qnil;
5374 }
5375
5377 while (res == econv_destination_buffer_full) {
5378 if (fptr->wbuf.len == fptr->wbuf.capa) {
5379 if (io_fflush(fptr) < 0) {
5380 return noalloc ? Qtrue : INT2NUM(errno);
5381 }
5382 }
5383
5384 ds = dp = (unsigned char *)fptr->wbuf.ptr + fptr->wbuf.off + fptr->wbuf.len;
5385 de = (unsigned char *)fptr->wbuf.ptr + fptr->wbuf.capa;
5386 res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
5387 fptr->wbuf.len += (int)(dp - ds);
5388 if (res == econv_invalid_byte_sequence ||
5389 res == econv_incomplete_input ||
5391 return noalloc ? Qtrue : rb_econv_make_exception(fptr->writeconv);
5392 }
5393 }
5394 return Qnil;
5395}
5396
5398 rb_io_t *fptr;
5399 int noalloc;
5400};
5401
5402static VALUE
5403finish_writeconv_sync(VALUE arg)
5404{
5405 struct finish_writeconv_arg *p = (struct finish_writeconv_arg *)arg;
5406 return finish_writeconv(p->fptr, p->noalloc);
5407}
5408
5409static void*
5410nogvl_close(void *ptr)
5411{
5412 int *fd = ptr;
5413
5414 return (void*)(intptr_t)close(*fd);
5415}
5416
5417static int
5418maygvl_close(int fd, int keepgvl)
5419{
5420 if (keepgvl)
5421 return close(fd);
5422
5423 /*
5424 * close() may block for certain file types (NFS, SO_LINGER sockets,
5425 * inotify), so let other threads run.
5426 */
5427 return (int)(intptr_t)rb_thread_call_without_gvl(nogvl_close, &fd, RUBY_UBF_IO, 0);
5428}
5429
5430static void*
5431nogvl_fclose(void *ptr)
5432{
5433 FILE *file = ptr;
5434
5435 return (void*)(intptr_t)fclose(file);
5436}
5437
5438static int
5439maygvl_fclose(FILE *file, int keepgvl)
5440{
5441 if (keepgvl)
5442 return fclose(file);
5443
5444 return (int)(intptr_t)rb_thread_call_without_gvl(nogvl_fclose, file, RUBY_UBF_IO, 0);
5445}
5446
5447static void free_io_buffer(rb_io_buffer_t *buf);
5448static void clear_codeconv(rb_io_t *fptr);
5449
5450static void
5451fptr_finalize_flush(rb_io_t *fptr, int noraise, int keepgvl,
5452 struct rb_io_close_wait_list *busy)
5453{
5454 VALUE error = Qnil;
5455 int fd = fptr->fd;
5456 FILE *stdio_file = fptr->stdio_file;
5457 int mode = fptr->mode;
5458
5459 if (fptr->writeconv) {
5460 if (!NIL_P(fptr->write_lock) && !noraise) {
5461 struct finish_writeconv_arg arg;
5462 arg.fptr = fptr;
5463 arg.noalloc = noraise;
5464 error = rb_mutex_synchronize(fptr->write_lock, finish_writeconv_sync, (VALUE)&arg);
5465 }
5466 else {
5467 error = finish_writeconv(fptr, noraise);
5468 }
5469 }
5470 if (fptr->wbuf.len) {
5471 if (noraise) {
5472 io_flush_buffer_sync(fptr);
5473 }
5474 else {
5475 if (io_fflush(fptr) < 0 && NIL_P(error)) {
5476 error = INT2NUM(errno);
5477 }
5478 }
5479 }
5480
5481 int done = 0;
5482
5483 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2) {
5484 // Need to keep FILE objects of stdin, stdout and stderr, so we are done:
5485 done = 1;
5486 }
5487
5488 fptr->fd = -1;
5489 fptr->stdio_file = 0;
5491
5492 // Ensure waiting_fd users do not hit EBADF.
5493 if (busy) {
5494 // Wait for them to exit before we call close().
5495 rb_notify_fd_close_wait(busy);
5496 }
5497
5498 // Disable for now.
5499 // if (!done && fd >= 0) {
5500 // VALUE scheduler = rb_fiber_scheduler_current();
5501 // if (scheduler != Qnil) {
5502 // VALUE result = rb_fiber_scheduler_io_close(scheduler, fptr->self);
5503 // if (!UNDEF_P(result)) done = 1;
5504 // }
5505 // }
5506
5507 if (!done && stdio_file) {
5508 // stdio_file is deallocated anyway even if fclose failed.
5509 if ((maygvl_fclose(stdio_file, noraise) < 0) && NIL_P(error)) {
5510 if (!noraise) {
5511 error = INT2NUM(errno);
5512 }
5513 }
5514
5515 done = 1;
5516 }
5517
5518 if (!done && fd >= 0) {
5519 // fptr->fd may be closed even if close fails. POSIX doesn't specify it.
5520 // We assumes it is closed.
5521
5522 keepgvl |= !(mode & FMODE_WRITABLE);
5523 keepgvl |= noraise;
5524 if ((maygvl_close(fd, keepgvl) < 0) && NIL_P(error)) {
5525 if (!noraise) {
5526 error = INT2NUM(errno);
5527 }
5528 }
5529
5530 done = 1;
5531 }
5532
5533 if (!NIL_P(error) && !noraise) {
5534 if (RB_INTEGER_TYPE_P(error))
5535 rb_syserr_fail_path(NUM2INT(error), fptr->pathv);
5536 else
5537 rb_exc_raise(error);
5538 }
5539}
5540
5541static void
5542fptr_finalize(rb_io_t *fptr, int noraise)
5543{
5544 fptr_finalize_flush(fptr, noraise, FALSE, 0);
5545 free_io_buffer(&fptr->rbuf);
5546 free_io_buffer(&fptr->wbuf);
5547 clear_codeconv(fptr);
5548}
5549
5550static void
5551rb_io_fptr_cleanup(rb_io_t *fptr, int noraise)
5552{
5553 if (fptr->finalize) {
5554 (*fptr->finalize)(fptr, noraise);
5555 }
5556 else {
5557 fptr_finalize(fptr, noraise);
5558 }
5559}
5560
5561static void
5562free_io_buffer(rb_io_buffer_t *buf)
5563{
5564 if (buf->ptr) {
5565 ruby_sized_xfree(buf->ptr, (size_t)buf->capa);
5566 buf->ptr = NULL;
5567 }
5568}
5569
5570static void
5571clear_readconv(rb_io_t *fptr)
5572{
5573 if (fptr->readconv) {
5574 rb_econv_close(fptr->readconv);
5575 fptr->readconv = NULL;
5576 }
5577 free_io_buffer(&fptr->cbuf);
5578}
5579
5580static void
5581clear_writeconv(rb_io_t *fptr)
5582{
5583 if (fptr->writeconv) {
5585 fptr->writeconv = NULL;
5586 }
5587 fptr->writeconv_initialized = 0;
5588}
5589
5590static void
5591clear_codeconv(rb_io_t *fptr)
5592{
5593 clear_readconv(fptr);
5594 clear_writeconv(fptr);
5595}
5596
5597static void
5598rb_io_fptr_cleanup_all(rb_io_t *fptr)
5599{
5600 fptr->pathv = Qnil;
5601 if (0 <= fptr->fd)
5602 rb_io_fptr_cleanup(fptr, TRUE);
5603 fptr->write_lock = Qnil;
5604 free_io_buffer(&fptr->rbuf);
5605 free_io_buffer(&fptr->wbuf);
5606 clear_codeconv(fptr);
5607}
5608
5609void
5610rb_io_fptr_finalize_internal(void *ptr)
5611{
5612 if (!ptr) return;
5613 rb_io_fptr_cleanup_all(ptr);
5614 free(ptr);
5615}
5616
5617#undef rb_io_fptr_finalize
5618int
5619rb_io_fptr_finalize(rb_io_t *fptr)
5620{
5621 if (!fptr) {
5622 return 0;
5623 }
5624 else {
5625 rb_io_fptr_finalize_internal(fptr);
5626 return 1;
5627 }
5628}
5629#define rb_io_fptr_finalize(fptr) rb_io_fptr_finalize_internal(fptr)
5630
5631RUBY_FUNC_EXPORTED size_t
5632rb_io_memsize(const rb_io_t *fptr)
5633{
5634 size_t size = sizeof(rb_io_t);
5635 size += fptr->rbuf.capa;
5636 size += fptr->wbuf.capa;
5637 size += fptr->cbuf.capa;
5638 if (fptr->readconv) size += rb_econv_memsize(fptr->readconv);
5639 if (fptr->writeconv) size += rb_econv_memsize(fptr->writeconv);
5640 return size;
5641}
5642
5643#ifdef _WIN32
5644/* keep GVL while closing to prevent crash on Windows */
5645# define KEEPGVL TRUE
5646#else
5647# define KEEPGVL FALSE
5648#endif
5649
5650static rb_io_t *
5651io_close_fptr(VALUE io)
5652{
5653 rb_io_t *fptr;
5654 VALUE write_io;
5655 rb_io_t *write_fptr;
5656 struct rb_io_close_wait_list busy;
5657
5658 write_io = GetWriteIO(io);
5659 if (io != write_io) {
5660 write_fptr = RFILE(write_io)->fptr;
5661 if (write_fptr && 0 <= write_fptr->fd) {
5662 rb_io_fptr_cleanup(write_fptr, TRUE);
5663 }
5664 }
5665
5666 fptr = RFILE(io)->fptr;
5667 if (!fptr) return 0;
5668 if (fptr->fd < 0) return 0;
5669
5670 if (rb_notify_fd_close(fptr->fd, &busy)) {
5671 /* calls close(fptr->fd): */
5672 fptr_finalize_flush(fptr, FALSE, KEEPGVL, &busy);
5673 }
5674 rb_io_fptr_cleanup(fptr, FALSE);
5675 return fptr;
5676}
5677
5678static void
5679fptr_waitpid(rb_io_t *fptr, int nohang)
5680{
5681 int status;
5682 if (fptr->pid) {
5683 rb_last_status_clear();
5684 rb_waitpid(fptr->pid, &status, nohang ? WNOHANG : 0);
5685 fptr->pid = 0;
5686 }
5687}
5688
5689VALUE
5691{
5692 rb_io_t *fptr = io_close_fptr(io);
5693 if (fptr) fptr_waitpid(fptr, 0);
5694 return Qnil;
5695}
5696
5697/*
5698 * call-seq:
5699 * close -> nil
5700 *
5701 * Closes the stream for both reading and writing
5702 * if open for either or both; returns +nil+.
5703 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5704 *
5705 * If the stream is open for writing, flushes any buffered writes
5706 * to the operating system before closing.
5707 *
5708 * If the stream was opened by IO.popen, sets global variable <tt>$?</tt>
5709 * (child exit status).
5710 *
5711 * Example:
5712 *
5713 * IO.popen('ruby', 'r+') do |pipe|
5714 * puts pipe.closed?
5715 * pipe.close
5716 * puts $?
5717 * puts pipe.closed?
5718 * end
5719 *
5720 * Output:
5721 *
5722 * false
5723 * pid 13760 exit 0
5724 * true
5725 *
5726 * Related: IO#close_read, IO#close_write, IO#closed?.
5727 */
5728
5729static VALUE
5730rb_io_close_m(VALUE io)
5731{
5732 rb_io_t *fptr = rb_io_get_fptr(io);
5733 if (fptr->fd < 0) {
5734 return Qnil;
5735 }
5736 rb_io_close(io);
5737 return Qnil;
5738}
5739
5740static VALUE
5741io_call_close(VALUE io)
5742{
5743 rb_check_funcall(io, rb_intern("close"), 0, 0);
5744 return io;
5745}
5746
5747static VALUE
5748ignore_closed_stream(VALUE io, VALUE exc)
5749{
5750 enum {mesg_len = sizeof(closed_stream)-1};
5751 VALUE mesg = rb_attr_get(exc, idMesg);
5752 if (!RB_TYPE_P(mesg, T_STRING) ||
5753 RSTRING_LEN(mesg) != mesg_len ||
5754 memcmp(RSTRING_PTR(mesg), closed_stream, mesg_len)) {
5755 rb_exc_raise(exc);
5756 }
5757 return io;
5758}
5759
5760static VALUE
5761io_close(VALUE io)
5762{
5763 VALUE closed = rb_check_funcall(io, rb_intern("closed?"), 0, 0);
5764 if (!UNDEF_P(closed) && RTEST(closed)) return io;
5765 rb_rescue2(io_call_close, io, ignore_closed_stream, io,
5766 rb_eIOError, (VALUE)0);
5767 return io;
5768}
5769
5770/*
5771 * call-seq:
5772 * closed? -> true or false
5773 *
5774 * Returns +true+ if the stream is closed for both reading and writing,
5775 * +false+ otherwise.
5776 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5777 *
5778 * IO.popen('ruby', 'r+') do |pipe|
5779 * puts pipe.closed?
5780 * pipe.close_read
5781 * puts pipe.closed?
5782 * pipe.close_write
5783 * puts pipe.closed?
5784 * end
5785 *
5786 * Output:
5787 *
5788 * false
5789 * false
5790 * true
5791 *
5792 * Related: IO#close_read, IO#close_write, IO#close.
5793 */
5794VALUE
5796{
5797 rb_io_t *fptr;
5798 VALUE write_io;
5799 rb_io_t *write_fptr;
5800
5801 write_io = GetWriteIO(io);
5802 if (io != write_io) {
5803 write_fptr = RFILE(write_io)->fptr;
5804 if (write_fptr && 0 <= write_fptr->fd) {
5805 return Qfalse;
5806 }
5807 }
5808
5809 fptr = rb_io_get_fptr(io);
5810 return RBOOL(0 > fptr->fd);
5811}
5812
5813/*
5814 * call-seq:
5815 * close_read -> nil
5816 *
5817 * Closes the stream for reading if open for reading;
5818 * returns +nil+.
5819 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5820 *
5821 * If the stream was opened by IO.popen and is also closed for writing,
5822 * sets global variable <tt>$?</tt> (child exit status).
5823 *
5824 * Example:
5825 *
5826 * IO.popen('ruby', 'r+') do |pipe|
5827 * puts pipe.closed?
5828 * pipe.close_write
5829 * puts pipe.closed?
5830 * pipe.close_read
5831 * puts $?
5832 * puts pipe.closed?
5833 * end
5834 *
5835 * Output:
5836 *
5837 * false
5838 * false
5839 * pid 14748 exit 0
5840 * true
5841 *
5842 * Related: IO#close, IO#close_write, IO#closed?.
5843 */
5844
5845static VALUE
5846rb_io_close_read(VALUE io)
5847{
5848 rb_io_t *fptr;
5849 VALUE write_io;
5850
5851 fptr = rb_io_get_fptr(rb_io_taint_check(io));
5852 if (fptr->fd < 0) return Qnil;
5853 if (is_socket(fptr->fd, fptr->pathv)) {
5854#ifndef SHUT_RD
5855# define SHUT_RD 0
5856#endif
5857 if (shutdown(fptr->fd, SHUT_RD) < 0)
5858 rb_sys_fail_path(fptr->pathv);
5859 fptr->mode &= ~FMODE_READABLE;
5860 if (!(fptr->mode & FMODE_WRITABLE))
5861 return rb_io_close(io);
5862 return Qnil;
5863 }
5864
5865 write_io = GetWriteIO(io);
5866 if (io != write_io) {
5867 rb_io_t *wfptr;
5868 wfptr = rb_io_get_fptr(rb_io_taint_check(write_io));
5869 wfptr->pid = fptr->pid;
5870 fptr->pid = 0;
5871 RFILE(io)->fptr = wfptr;
5872 /* bind to write_io temporarily to get rid of memory/fd leak */
5873 fptr->tied_io_for_writing = 0;
5874 RFILE(write_io)->fptr = fptr;
5875 rb_io_fptr_cleanup(fptr, FALSE);
5876 /* should not finalize fptr because another thread may be reading it */
5877 return Qnil;
5878 }
5879
5880 if ((fptr->mode & (FMODE_DUPLEX|FMODE_WRITABLE)) == FMODE_WRITABLE) {
5881 rb_raise(rb_eIOError, "closing non-duplex IO for reading");
5882 }
5883 return rb_io_close(io);
5884}
5885
5886/*
5887 * call-seq:
5888 * close_write -> nil
5889 *
5890 * Closes the stream for writing if open for writing;
5891 * returns +nil+.
5892 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5893 *
5894 * Flushes any buffered writes to the operating system before closing.
5895 *
5896 * If the stream was opened by IO.popen and is also closed for reading,
5897 * sets global variable <tt>$?</tt> (child exit status).
5898 *
5899 * IO.popen('ruby', 'r+') do |pipe|
5900 * puts pipe.closed?
5901 * pipe.close_read
5902 * puts pipe.closed?
5903 * pipe.close_write
5904 * puts $?
5905 * puts pipe.closed?
5906 * end
5907 *
5908 * Output:
5909 *
5910 * false
5911 * false
5912 * pid 15044 exit 0
5913 * true
5914 *
5915 * Related: IO#close, IO#close_read, IO#closed?.
5916 */
5917
5918static VALUE
5919rb_io_close_write(VALUE io)
5920{
5921 rb_io_t *fptr;
5922 VALUE write_io;
5923
5924 write_io = GetWriteIO(io);
5925 fptr = rb_io_get_fptr(rb_io_taint_check(write_io));
5926 if (fptr->fd < 0) return Qnil;
5927 if (is_socket(fptr->fd, fptr->pathv)) {
5928#ifndef SHUT_WR
5929# define SHUT_WR 1
5930#endif
5931 if (shutdown(fptr->fd, SHUT_WR) < 0)
5932 rb_sys_fail_path(fptr->pathv);
5933 fptr->mode &= ~FMODE_WRITABLE;
5934 if (!(fptr->mode & FMODE_READABLE))
5935 return rb_io_close(write_io);
5936 return Qnil;
5937 }
5938
5939 if ((fptr->mode & (FMODE_DUPLEX|FMODE_READABLE)) == FMODE_READABLE) {
5940 rb_raise(rb_eIOError, "closing non-duplex IO for writing");
5941 }
5942
5943 if (io != write_io) {
5944 fptr = rb_io_get_fptr(rb_io_taint_check(io));
5945 fptr->tied_io_for_writing = 0;
5946 }
5947 rb_io_close(write_io);
5948 return Qnil;
5949}
5950
5951/*
5952 * call-seq:
5953 * sysseek(offset, whence = IO::SEEK_SET) -> integer
5954 *
5955 * Behaves like IO#seek, except that it:
5956 *
5957 * - Uses low-level system functions.
5958 * - Returns the new position.
5959 *
5960 */
5961
5962static VALUE
5963rb_io_sysseek(int argc, VALUE *argv, VALUE io)
5964{
5965 VALUE offset, ptrname;
5966 int whence = SEEK_SET;
5967 rb_io_t *fptr;
5968 rb_off_t pos;
5969
5970 if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
5971 whence = interpret_seek_whence(ptrname);
5972 }
5973 pos = NUM2OFFT(offset);
5974 GetOpenFile(io, fptr);
5975 if ((fptr->mode & FMODE_READABLE) &&
5976 (READ_DATA_BUFFERED(fptr) || READ_CHAR_PENDING(fptr))) {
5977 rb_raise(rb_eIOError, "sysseek for buffered IO");
5978 }
5979 if ((fptr->mode & FMODE_WRITABLE) && fptr->wbuf.len) {
5980 rb_warn("sysseek for buffered IO");
5981 }
5982 errno = 0;
5983 pos = lseek(fptr->fd, pos, whence);
5984 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
5985
5986 return OFFT2NUM(pos);
5987}
5988
5989/*
5990 * call-seq:
5991 * syswrite(object) -> integer
5992 *
5993 * Writes the given +object+ to self, which must be opened for writing (see Modes);
5994 * returns the number bytes written.
5995 * If +object+ is not a string is converted via method to_s:
5996 *
5997 * f = File.new('t.tmp', 'w')
5998 * f.syswrite('foo') # => 3
5999 * f.syswrite(30) # => 2
6000 * f.syswrite(:foo) # => 3
6001 * f.close
6002 *
6003 * This methods should not be used with other stream-writer methods.
6004 *
6005 */
6006
6007static VALUE
6008rb_io_syswrite(VALUE io, VALUE str)
6009{
6010 VALUE tmp;
6011 rb_io_t *fptr;
6012 long n, len;
6013 const char *ptr;
6014
6015 if (!RB_TYPE_P(str, T_STRING))
6016 str = rb_obj_as_string(str);
6017
6018 io = GetWriteIO(io);
6019 GetOpenFile(io, fptr);
6021
6022 if (fptr->wbuf.len) {
6023 rb_warn("syswrite for buffered IO");
6024 }
6025
6026 tmp = rb_str_tmp_frozen_acquire(str);
6027 RSTRING_GETMEM(tmp, ptr, len);
6028 n = rb_io_write_memory(fptr, ptr, len);
6029 if (n < 0) rb_sys_fail_path(fptr->pathv);
6030 rb_str_tmp_frozen_release(str, tmp);
6031
6032 return LONG2FIX(n);
6033}
6034
6035/*
6036 * call-seq:
6037 * sysread(maxlen) -> string
6038 * sysread(maxlen, out_string) -> string
6039 *
6040 * Behaves like IO#readpartial, except that it uses low-level system functions.
6041 *
6042 * This method should not be used with other stream-reader methods.
6043 *
6044 */
6045
6046static VALUE
6047rb_io_sysread(int argc, VALUE *argv, VALUE io)
6048{
6049 VALUE len, str;
6050 rb_io_t *fptr;
6051 long n, ilen;
6052 struct io_internal_read_struct iis;
6053 int shrinkable;
6054
6055 rb_scan_args(argc, argv, "11", &len, &str);
6056 ilen = NUM2LONG(len);
6057
6058 shrinkable = io_setstrbuf(&str, ilen);
6059 if (ilen == 0) return str;
6060
6061 GetOpenFile(io, fptr);
6063
6064 if (READ_DATA_BUFFERED(fptr)) {
6065 rb_raise(rb_eIOError, "sysread for buffered IO");
6066 }
6067
6068 rb_io_check_closed(fptr);
6069
6070 io_setstrbuf(&str, ilen);
6071 iis.th = rb_thread_current();
6072 iis.fptr = fptr;
6073 iis.nonblock = 0;
6074 iis.fd = fptr->fd;
6075 iis.buf = RSTRING_PTR(str);
6076 iis.capa = ilen;
6077 iis.timeout = NULL;
6078 n = io_read_memory_locktmp(str, &iis);
6079
6080 if (n < 0) {
6081 rb_sys_fail_path(fptr->pathv);
6082 }
6083
6084 io_set_read_length(str, n, shrinkable);
6085
6086 if (n == 0 && ilen > 0) {
6087 rb_eof_error();
6088 }
6089
6090 return str;
6091}
6092
6094 VALUE io;
6095 int fd;
6096 void *buf;
6097 size_t count;
6098 rb_off_t offset;
6099};
6100
6101static VALUE
6102internal_pread_func(void *_arg)
6103{
6104 struct prdwr_internal_arg *arg = _arg;
6105
6106 return (VALUE)pread(arg->fd, arg->buf, arg->count, arg->offset);
6107}
6108
6109static VALUE
6110pread_internal_call(VALUE _arg)
6111{
6112 struct prdwr_internal_arg *arg = (struct prdwr_internal_arg *)_arg;
6113
6114 VALUE scheduler = rb_fiber_scheduler_current();
6115 if (scheduler != Qnil) {
6116 VALUE result = rb_fiber_scheduler_io_pread_memory(scheduler, arg->io, arg->offset, arg->buf, arg->count, 0);
6117
6118 if (!UNDEF_P(result)) {
6120 }
6121 }
6122
6123 return rb_thread_io_blocking_call(internal_pread_func, arg, arg->fd, RB_WAITFD_IN);
6124}
6125
6126/*
6127 * call-seq:
6128 * pread(maxlen, offset) -> string
6129 * pread(maxlen, offset, out_string) -> string
6130 *
6131 * Behaves like IO#readpartial, except that it:
6132 *
6133 * - Reads at the given +offset+ (in bytes).
6134 * - Disregards, and does not modify, the stream's position
6135 * (see {Position}[rdoc-ref:IO@Position]).
6136 * - Bypasses any user space buffering in the stream.
6137 *
6138 * Because this method does not disturb the stream's state
6139 * (its position, in particular), +pread+ allows multiple threads and processes
6140 * to use the same \IO object for reading at various offsets.
6141 *
6142 * f = File.open('t.txt')
6143 * f.read # => "First line\nSecond line\n\nFourth line\nFifth line\n"
6144 * f.pos # => 52
6145 * # Read 12 bytes at offset 0.
6146 * f.pread(12, 0) # => "First line\n"
6147 * # Read 9 bytes at offset 8.
6148 * f.pread(9, 8) # => "ne\nSecon"
6149 * f.close
6150 *
6151 * Not available on some platforms.
6152 *
6153 */
6154static VALUE
6155rb_io_pread(int argc, VALUE *argv, VALUE io)
6156{
6157 VALUE len, offset, str;
6158 rb_io_t *fptr;
6159 ssize_t n;
6160 struct prdwr_internal_arg arg = {.io = io};
6161 int shrinkable;
6162
6163 rb_scan_args(argc, argv, "21", &len, &offset, &str);
6164 arg.count = NUM2SIZET(len);
6165 arg.offset = NUM2OFFT(offset);
6166
6167 shrinkable = io_setstrbuf(&str, (long)arg.count);
6168 if (arg.count == 0) return str;
6169 arg.buf = RSTRING_PTR(str);
6170
6171 GetOpenFile(io, fptr);
6173
6174 arg.fd = fptr->fd;
6175 rb_io_check_closed(fptr);
6176
6177 rb_str_locktmp(str);
6178 n = (ssize_t)rb_ensure(pread_internal_call, (VALUE)&arg, rb_str_unlocktmp, str);
6179
6180 if (n < 0) {
6181 rb_sys_fail_path(fptr->pathv);
6182 }
6183 io_set_read_length(str, n, shrinkable);
6184 if (n == 0 && arg.count > 0) {
6185 rb_eof_error();
6186 }
6187
6188 return str;
6189}
6190
6191static VALUE
6192internal_pwrite_func(void *_arg)
6193{
6194 struct prdwr_internal_arg *arg = _arg;
6195
6196 VALUE scheduler = rb_fiber_scheduler_current();
6197 if (scheduler != Qnil) {
6198 VALUE result = rb_fiber_scheduler_io_pwrite_memory(scheduler, arg->io, arg->offset, arg->buf, arg->count, 0);
6199
6200 if (!UNDEF_P(result)) {
6202 }
6203 }
6204
6205
6206 return (VALUE)pwrite(arg->fd, arg->buf, arg->count, arg->offset);
6207}
6208
6209/*
6210 * call-seq:
6211 * pwrite(object, offset) -> integer
6212 *
6213 * Behaves like IO#write, except that it:
6214 *
6215 * - Writes at the given +offset+ (in bytes).
6216 * - Disregards, and does not modify, the stream's position
6217 * (see {Position}[rdoc-ref:IO@Position]).
6218 * - Bypasses any user space buffering in the stream.
6219 *
6220 * Because this method does not disturb the stream's state
6221 * (its position, in particular), +pwrite+ allows multiple threads and processes
6222 * to use the same \IO object for writing at various offsets.
6223 *
6224 * f = File.open('t.tmp', 'w+')
6225 * # Write 6 bytes at offset 3.
6226 * f.pwrite('ABCDEF', 3) # => 6
6227 * f.rewind
6228 * f.read # => "\u0000\u0000\u0000ABCDEF"
6229 * f.close
6230 *
6231 * Not available on some platforms.
6232 *
6233 */
6234static VALUE
6235rb_io_pwrite(VALUE io, VALUE str, VALUE offset)
6236{
6237 rb_io_t *fptr;
6238 ssize_t n;
6239 struct prdwr_internal_arg arg = {.io = io};
6240 VALUE tmp;
6241
6242 if (!RB_TYPE_P(str, T_STRING))
6243 str = rb_obj_as_string(str);
6244
6245 arg.offset = NUM2OFFT(offset);
6246
6247 io = GetWriteIO(io);
6248 GetOpenFile(io, fptr);
6250 arg.fd = fptr->fd;
6251
6252 tmp = rb_str_tmp_frozen_acquire(str);
6253 arg.buf = RSTRING_PTR(tmp);
6254 arg.count = (size_t)RSTRING_LEN(tmp);
6255
6256 n = (ssize_t)rb_thread_io_blocking_call(internal_pwrite_func, &arg, fptr->fd, RB_WAITFD_OUT);
6257 if (n < 0) rb_sys_fail_path(fptr->pathv);
6258 rb_str_tmp_frozen_release(str, tmp);
6259
6260 return SSIZET2NUM(n);
6261}
6262
6263VALUE
6265{
6266 rb_io_t *fptr;
6267
6268 GetOpenFile(io, fptr);
6269 if (fptr->readconv)
6271 if (fptr->writeconv)
6273 fptr->mode |= FMODE_BINMODE;
6274 fptr->mode &= ~FMODE_TEXTMODE;
6275 fptr->writeconv_pre_ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
6276#ifdef O_BINARY
6277 if (!fptr->readconv) {
6278 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6279 }
6280 else {
6281 setmode(fptr->fd, O_BINARY);
6282 }
6283#endif
6284 return io;
6285}
6286
6287static void
6288io_ascii8bit_binmode(rb_io_t *fptr)
6289{
6290 if (fptr->readconv) {
6291 rb_econv_close(fptr->readconv);
6292 fptr->readconv = NULL;
6293 }
6294 if (fptr->writeconv) {
6296 fptr->writeconv = NULL;
6297 }
6298 fptr->mode |= FMODE_BINMODE;
6299 fptr->mode &= ~FMODE_TEXTMODE;
6300 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6301
6302 fptr->encs.enc = rb_ascii8bit_encoding();
6303 fptr->encs.enc2 = NULL;
6304 fptr->encs.ecflags = 0;
6305 fptr->encs.ecopts = Qnil;
6306 clear_codeconv(fptr);
6307}
6308
6309VALUE
6311{
6312 rb_io_t *fptr;
6313
6314 GetOpenFile(io, fptr);
6315 io_ascii8bit_binmode(fptr);
6316
6317 return io;
6318}
6319
6320/*
6321 * call-seq:
6322 * binmode -> self
6323 *
6324 * Sets the stream's data mode as binary
6325 * (see {Data Mode}[rdoc-ref:File@Data+Mode]).
6326 *
6327 * A stream's data mode may not be changed from binary to text.
6328 *
6329 */
6330
6331static VALUE
6332rb_io_binmode_m(VALUE io)
6333{
6334 VALUE write_io;
6335
6337
6338 write_io = GetWriteIO(io);
6339 if (write_io != io)
6340 rb_io_ascii8bit_binmode(write_io);
6341 return io;
6342}
6343
6344/*
6345 * call-seq:
6346 * binmode? -> true or false
6347 *
6348 * Returns +true+ if the stream is on binary mode, +false+ otherwise.
6349 * See {Data Mode}[rdoc-ref:File@Data+Mode].
6350 *
6351 */
6352static VALUE
6353rb_io_binmode_p(VALUE io)
6354{
6355 rb_io_t *fptr;
6356 GetOpenFile(io, fptr);
6357 return RBOOL(fptr->mode & FMODE_BINMODE);
6358}
6359
6360static const char*
6361rb_io_fmode_modestr(int fmode)
6362{
6363 if (fmode & FMODE_APPEND) {
6364 if ((fmode & FMODE_READWRITE) == FMODE_READWRITE) {
6365 return MODE_BTMODE("a+", "ab+", "at+");
6366 }
6367 return MODE_BTMODE("a", "ab", "at");
6368 }
6369 switch (fmode & FMODE_READWRITE) {
6370 default:
6371 rb_raise(rb_eArgError, "invalid access fmode 0x%x", fmode);
6372 case FMODE_READABLE:
6373 return MODE_BTMODE("r", "rb", "rt");
6374 case FMODE_WRITABLE:
6375 return MODE_BTXMODE("w", "wb", "wt", "wx", "wbx", "wtx");
6376 case FMODE_READWRITE:
6377 if (fmode & FMODE_CREATE) {
6378 return MODE_BTXMODE("w+", "wb+", "wt+", "w+x", "wb+x", "wt+x");
6379 }
6380 return MODE_BTMODE("r+", "rb+", "rt+");
6381 }
6382}
6383
6384static const char bom_prefix[] = "bom|";
6385static const char utf_prefix[] = "utf-";
6386enum {bom_prefix_len = (int)sizeof(bom_prefix) - 1};
6387enum {utf_prefix_len = (int)sizeof(utf_prefix) - 1};
6388
6389static int
6390io_encname_bom_p(const char *name, long len)
6391{
6392 return len > bom_prefix_len && STRNCASECMP(name, bom_prefix, bom_prefix_len) == 0;
6393}
6394
6395int
6396rb_io_modestr_fmode(const char *modestr)
6397{
6398 int fmode = 0;
6399 const char *m = modestr, *p = NULL;
6400
6401 switch (*m++) {
6402 case 'r':
6403 fmode |= FMODE_READABLE;
6404 break;
6405 case 'w':
6407 break;
6408 case 'a':
6410 break;
6411 default:
6412 goto error;
6413 }
6414
6415 while (*m) {
6416 switch (*m++) {
6417 case 'b':
6418 fmode |= FMODE_BINMODE;
6419 break;
6420 case 't':
6421 fmode |= FMODE_TEXTMODE;
6422 break;
6423 case '+':
6424 fmode |= FMODE_READWRITE;
6425 break;
6426 case 'x':
6427 if (modestr[0] != 'w')
6428 goto error;
6429 fmode |= FMODE_EXCL;
6430 break;
6431 default:
6432 goto error;
6433 case ':':
6434 p = strchr(m, ':');
6435 if (io_encname_bom_p(m, p ? (long)(p - m) : (long)strlen(m)))
6436 fmode |= FMODE_SETENC_BY_BOM;
6437 goto finished;
6438 }
6439 }
6440
6441 finished:
6442 if ((fmode & FMODE_BINMODE) && (fmode & FMODE_TEXTMODE))
6443 goto error;
6444
6445 return fmode;
6446
6447 error:
6448 rb_raise(rb_eArgError, "invalid access mode %s", modestr);
6450}
6451
6452int
6453rb_io_oflags_fmode(int oflags)
6454{
6455 int fmode = 0;
6456
6457 switch (oflags & O_ACCMODE) {
6458 case O_RDONLY:
6459 fmode = FMODE_READABLE;
6460 break;
6461 case O_WRONLY:
6462 fmode = FMODE_WRITABLE;
6463 break;
6464 case O_RDWR:
6465 fmode = FMODE_READWRITE;
6466 break;
6467 }
6468
6469 if (oflags & O_APPEND) {
6470 fmode |= FMODE_APPEND;
6471 }
6472 if (oflags & O_TRUNC) {
6473 fmode |= FMODE_TRUNC;
6474 }
6475 if (oflags & O_CREAT) {
6476 fmode |= FMODE_CREATE;
6477 }
6478 if (oflags & O_EXCL) {
6479 fmode |= FMODE_EXCL;
6480 }
6481#ifdef O_BINARY
6482 if (oflags & O_BINARY) {
6483 fmode |= FMODE_BINMODE;
6484 }
6485#endif
6486
6487 return fmode;
6488}
6489
6490static int
6491rb_io_fmode_oflags(int fmode)
6492{
6493 int oflags = 0;
6494
6495 switch (fmode & FMODE_READWRITE) {
6496 case FMODE_READABLE:
6497 oflags |= O_RDONLY;
6498 break;
6499 case FMODE_WRITABLE:
6500 oflags |= O_WRONLY;
6501 break;
6502 case FMODE_READWRITE:
6503 oflags |= O_RDWR;
6504 break;
6505 }
6506
6507 if (fmode & FMODE_APPEND) {
6508 oflags |= O_APPEND;
6509 }
6510 if (fmode & FMODE_TRUNC) {
6511 oflags |= O_TRUNC;
6512 }
6513 if (fmode & FMODE_CREATE) {
6514 oflags |= O_CREAT;
6515 }
6516 if (fmode & FMODE_EXCL) {
6517 oflags |= O_EXCL;
6518 }
6519#ifdef O_BINARY
6520 if (fmode & FMODE_BINMODE) {
6521 oflags |= O_BINARY;
6522 }
6523#endif
6524
6525 return oflags;
6526}
6527
6528int
6529rb_io_modestr_oflags(const char *modestr)
6530{
6531 return rb_io_fmode_oflags(rb_io_modestr_fmode(modestr));
6532}
6533
6534static const char*
6535rb_io_oflags_modestr(int oflags)
6536{
6537#ifdef O_BINARY
6538# define MODE_BINARY(a,b) ((oflags & O_BINARY) ? (b) : (a))
6539#else
6540# define MODE_BINARY(a,b) (a)
6541#endif
6542 int accmode;
6543 if (oflags & O_EXCL) {
6544 rb_raise(rb_eArgError, "exclusive access mode is not supported");
6545 }
6546 accmode = oflags & (O_RDONLY|O_WRONLY|O_RDWR);
6547 if (oflags & O_APPEND) {
6548 if (accmode == O_WRONLY) {
6549 return MODE_BINARY("a", "ab");
6550 }
6551 if (accmode == O_RDWR) {
6552 return MODE_BINARY("a+", "ab+");
6553 }
6554 }
6555 switch (accmode) {
6556 default:
6557 rb_raise(rb_eArgError, "invalid access oflags 0x%x", oflags);
6558 case O_RDONLY:
6559 return MODE_BINARY("r", "rb");
6560 case O_WRONLY:
6561 return MODE_BINARY("w", "wb");
6562 case O_RDWR:
6563 if (oflags & O_TRUNC) {
6564 return MODE_BINARY("w+", "wb+");
6565 }
6566 return MODE_BINARY("r+", "rb+");
6567 }
6568}
6569
6570/*
6571 * Convert external/internal encodings to enc/enc2
6572 * NULL => use default encoding
6573 * Qnil => no encoding specified (internal only)
6574 */
6575static void
6576rb_io_ext_int_to_encs(rb_encoding *ext, rb_encoding *intern, rb_encoding **enc, rb_encoding **enc2, int fmode)
6577{
6578 int default_ext = 0;
6579
6580 if (ext == NULL) {
6581 ext = rb_default_external_encoding();
6582 default_ext = 1;
6583 }
6584 if (rb_is_ascii8bit_enc(ext)) {
6585 /* If external is ASCII-8BIT, no transcoding */
6586 intern = NULL;
6587 }
6588 else if (intern == NULL) {
6589 intern = rb_default_internal_encoding();
6590 }
6591 if (intern == NULL || intern == (rb_encoding *)Qnil ||
6592 (!(fmode & FMODE_SETENC_BY_BOM) && (intern == ext))) {
6593 /* No internal encoding => use external + no transcoding */
6594 *enc = (default_ext && intern != ext) ? NULL : ext;
6595 *enc2 = NULL;
6596 }
6597 else {
6598 *enc = intern;
6599 *enc2 = ext;
6600 }
6601}
6602
6603static void
6604unsupported_encoding(const char *name, rb_encoding *enc)
6605{
6606 rb_enc_warn(enc, "Unsupported encoding %s ignored", name);
6607}
6608
6609static void
6610parse_mode_enc(const char *estr, rb_encoding *estr_enc,
6611 rb_encoding **enc_p, rb_encoding **enc2_p, int *fmode_p)
6612{
6613 const char *p;
6614 char encname[ENCODING_MAXNAMELEN+1];
6615 int idx, idx2;
6616 int fmode = fmode_p ? *fmode_p : 0;
6617 rb_encoding *ext_enc, *int_enc;
6618 long len;
6619
6620 /* parse estr as "enc" or "enc2:enc" or "enc:-" */
6621
6622 p = strrchr(estr, ':');
6623 len = p ? (p++ - estr) : (long)strlen(estr);
6624 if ((fmode & FMODE_SETENC_BY_BOM) || io_encname_bom_p(estr, len)) {
6625 estr += bom_prefix_len;
6626 len -= bom_prefix_len;
6627 if (!STRNCASECMP(estr, utf_prefix, utf_prefix_len)) {
6628 fmode |= FMODE_SETENC_BY_BOM;
6629 }
6630 else {
6631 rb_enc_warn(estr_enc, "BOM with non-UTF encoding %s is nonsense", estr);
6632 fmode &= ~FMODE_SETENC_BY_BOM;
6633 }
6634 }
6635 if (len == 0 || len > ENCODING_MAXNAMELEN) {
6636 idx = -1;
6637 }
6638 else {
6639 if (p) {
6640 memcpy(encname, estr, len);
6641 encname[len] = '\0';
6642 estr = encname;
6643 }
6644 idx = rb_enc_find_index(estr);
6645 }
6646 if (fmode_p) *fmode_p = fmode;
6647
6648 if (idx >= 0)
6649 ext_enc = rb_enc_from_index(idx);
6650 else {
6651 if (idx != -2)
6652 unsupported_encoding(estr, estr_enc);
6653 ext_enc = NULL;
6654 }
6655
6656 int_enc = NULL;
6657 if (p) {
6658 if (*p == '-' && *(p+1) == '\0') {
6659 /* Special case - "-" => no transcoding */
6660 int_enc = (rb_encoding *)Qnil;
6661 }
6662 else {
6663 idx2 = rb_enc_find_index(p);
6664 if (idx2 < 0)
6665 unsupported_encoding(p, estr_enc);
6666 else if (!(fmode & FMODE_SETENC_BY_BOM) && (idx2 == idx)) {
6667 int_enc = (rb_encoding *)Qnil;
6668 }
6669 else
6670 int_enc = rb_enc_from_index(idx2);
6671 }
6672 }
6673
6674 rb_io_ext_int_to_encs(ext_enc, int_enc, enc_p, enc2_p, fmode);
6675}
6676
6677int
6678rb_io_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding **enc2_p, int *fmode_p)
6679{
6680 VALUE encoding=Qnil, extenc=Qundef, intenc=Qundef, tmp;
6681 int extracted = 0;
6682 rb_encoding *extencoding = NULL;
6683 rb_encoding *intencoding = NULL;
6684
6685 if (!NIL_P(opt)) {
6686 VALUE v;
6687 v = rb_hash_lookup2(opt, sym_encoding, Qnil);
6688 if (v != Qnil) encoding = v;
6689 v = rb_hash_lookup2(opt, sym_extenc, Qundef);
6690 if (v != Qnil) extenc = v;
6691 v = rb_hash_lookup2(opt, sym_intenc, Qundef);
6692 if (!UNDEF_P(v)) intenc = v;
6693 }
6694 if ((!UNDEF_P(extenc) || !UNDEF_P(intenc)) && !NIL_P(encoding)) {
6695 if (!NIL_P(ruby_verbose)) {
6696 int idx = rb_to_encoding_index(encoding);
6697 if (idx >= 0) encoding = rb_enc_from_encoding(rb_enc_from_index(idx));
6698 rb_warn("Ignoring encoding parameter '%"PRIsVALUE"': %s_encoding is used",
6699 encoding, UNDEF_P(extenc) ? "internal" : "external");
6700 }
6701 encoding = Qnil;
6702 }
6703 if (!UNDEF_P(extenc) && !NIL_P(extenc)) {
6704 extencoding = rb_to_encoding(extenc);
6705 }
6706 if (!UNDEF_P(intenc)) {
6707 if (NIL_P(intenc)) {
6708 /* internal_encoding: nil => no transcoding */
6709 intencoding = (rb_encoding *)Qnil;
6710 }
6711 else if (!NIL_P(tmp = rb_check_string_type(intenc))) {
6712 char *p = StringValueCStr(tmp);
6713
6714 if (*p == '-' && *(p+1) == '\0') {
6715 /* Special case - "-" => no transcoding */
6716 intencoding = (rb_encoding *)Qnil;
6717 }
6718 else {
6719 intencoding = rb_to_encoding(intenc);
6720 }
6721 }
6722 else {
6723 intencoding = rb_to_encoding(intenc);
6724 }
6725 if (extencoding == intencoding) {
6726 intencoding = (rb_encoding *)Qnil;
6727 }
6728 }
6729 if (!NIL_P(encoding)) {
6730 extracted = 1;
6731 if (!NIL_P(tmp = rb_check_string_type(encoding))) {
6732 parse_mode_enc(StringValueCStr(tmp), rb_enc_get(tmp),
6733 enc_p, enc2_p, fmode_p);
6734 }
6735 else {
6736 rb_io_ext_int_to_encs(rb_to_encoding(encoding), NULL, enc_p, enc2_p, 0);
6737 }
6738 }
6739 else if (!UNDEF_P(extenc) || !UNDEF_P(intenc)) {
6740 extracted = 1;
6741 rb_io_ext_int_to_encs(extencoding, intencoding, enc_p, enc2_p, 0);
6742 }
6743 return extracted;
6744}
6745
6746static void
6747validate_enc_binmode(int *fmode_p, int ecflags, rb_encoding *enc, rb_encoding *enc2)
6748{
6749 int fmode = *fmode_p;
6750
6751 if ((fmode & FMODE_READABLE) &&
6752 !enc2 &&
6753 !(fmode & FMODE_BINMODE) &&
6754 !rb_enc_asciicompat(enc ? enc : rb_default_external_encoding()))
6755 rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
6756
6757 if ((fmode & FMODE_BINMODE) && (ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
6758 rb_raise(rb_eArgError, "newline decorator with binary mode");
6759 }
6760 if (!(fmode & FMODE_BINMODE) &&
6761 (DEFAULT_TEXTMODE || (ecflags & ECONV_NEWLINE_DECORATOR_MASK))) {
6762 fmode |= FMODE_TEXTMODE;
6763 *fmode_p = fmode;
6764 }
6765#if !DEFAULT_TEXTMODE
6766 else if (!(ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
6767 fmode &= ~FMODE_TEXTMODE;
6768 *fmode_p = fmode;
6769 }
6770#endif
6771}
6772
6773static void
6774extract_binmode(VALUE opthash, int *fmode)
6775{
6776 if (!NIL_P(opthash)) {
6777 VALUE v;
6778 v = rb_hash_aref(opthash, sym_textmode);
6779 if (!NIL_P(v)) {
6780 if (*fmode & FMODE_TEXTMODE)
6781 rb_raise(rb_eArgError, "textmode specified twice");
6782 if (*fmode & FMODE_BINMODE)
6783 rb_raise(rb_eArgError, "both textmode and binmode specified");
6784 if (RTEST(v))
6785 *fmode |= FMODE_TEXTMODE;
6786 }
6787 v = rb_hash_aref(opthash, sym_binmode);
6788 if (!NIL_P(v)) {
6789 if (*fmode & FMODE_BINMODE)
6790 rb_raise(rb_eArgError, "binmode specified twice");
6791 if (*fmode & FMODE_TEXTMODE)
6792 rb_raise(rb_eArgError, "both textmode and binmode specified");
6793 if (RTEST(v))
6794 *fmode |= FMODE_BINMODE;
6795 }
6796
6797 if ((*fmode & FMODE_BINMODE) && (*fmode & FMODE_TEXTMODE))
6798 rb_raise(rb_eArgError, "both textmode and binmode specified");
6799 }
6800}
6801
6802void
6803rb_io_extract_modeenc(VALUE *vmode_p, VALUE *vperm_p, VALUE opthash,
6804 int *oflags_p, int *fmode_p, struct rb_io_encoding *convconfig_p)
6805{
6806 VALUE vmode;
6807 int oflags, fmode;
6808 rb_encoding *enc, *enc2;
6809 int ecflags;
6810 VALUE ecopts;
6811 int has_enc = 0, has_vmode = 0;
6812 VALUE intmode;
6813
6814 vmode = *vmode_p;
6815
6816 /* Set to defaults */
6817 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
6818
6819 vmode_handle:
6820 if (NIL_P(vmode)) {
6821 fmode = FMODE_READABLE;
6822 oflags = O_RDONLY;
6823 }
6824 else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int"))) {
6825 vmode = intmode;
6826 oflags = NUM2INT(intmode);
6827 fmode = rb_io_oflags_fmode(oflags);
6828 }
6829 else {
6830 const char *p;
6831
6832 SafeStringValue(vmode);
6833 p = StringValueCStr(vmode);
6834 fmode = rb_io_modestr_fmode(p);
6835 oflags = rb_io_fmode_oflags(fmode);
6836 p = strchr(p, ':');
6837 if (p) {
6838 has_enc = 1;
6839 parse_mode_enc(p+1, rb_enc_get(vmode), &enc, &enc2, &fmode);
6840 }
6841 else {
6842 rb_encoding *e;
6843
6844 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
6845 rb_io_ext_int_to_encs(e, NULL, &enc, &enc2, fmode);
6846 }
6847 }
6848
6849 if (NIL_P(opthash)) {
6850 ecflags = (fmode & FMODE_READABLE) ?
6853#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
6854 ecflags |= (fmode & FMODE_WRITABLE) ?
6855 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
6856 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
6857#endif
6858 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
6859 ecopts = Qnil;
6860 if (fmode & FMODE_BINMODE) {
6861#ifdef O_BINARY
6862 oflags |= O_BINARY;
6863#endif
6864 if (!has_enc)
6865 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
6866 }
6867#if DEFAULT_TEXTMODE
6868 else if (NIL_P(vmode)) {
6869 fmode |= DEFAULT_TEXTMODE;
6870 }
6871#endif
6872 }
6873 else {
6874 VALUE v;
6875 if (!has_vmode) {
6876 v = rb_hash_aref(opthash, sym_mode);
6877 if (!NIL_P(v)) {
6878 if (!NIL_P(vmode)) {
6879 rb_raise(rb_eArgError, "mode specified twice");
6880 }
6881 has_vmode = 1;
6882 vmode = v;
6883 goto vmode_handle;
6884 }
6885 }
6886 v = rb_hash_aref(opthash, sym_flags);
6887 if (!NIL_P(v)) {
6888 v = rb_to_int(v);
6889 oflags |= NUM2INT(v);
6890 vmode = INT2NUM(oflags);
6891 fmode = rb_io_oflags_fmode(oflags);
6892 }
6893 extract_binmode(opthash, &fmode);
6894 if (fmode & FMODE_BINMODE) {
6895#ifdef O_BINARY
6896 oflags |= O_BINARY;
6897#endif
6898 if (!has_enc)
6899 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
6900 }
6901#if DEFAULT_TEXTMODE
6902 else if (NIL_P(vmode)) {
6903 fmode |= DEFAULT_TEXTMODE;
6904 }
6905#endif
6906 v = rb_hash_aref(opthash, sym_perm);
6907 if (!NIL_P(v)) {
6908 if (vperm_p) {
6909 if (!NIL_P(*vperm_p)) {
6910 rb_raise(rb_eArgError, "perm specified twice");
6911 }
6912 *vperm_p = v;
6913 }
6914 else {
6915 /* perm no use, just ignore */
6916 }
6917 }
6918 ecflags = (fmode & FMODE_READABLE) ?
6921#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
6922 ecflags |= (fmode & FMODE_WRITABLE) ?
6923 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
6924 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
6925#endif
6926
6927 if (rb_io_extract_encoding_option(opthash, &enc, &enc2, &fmode)) {
6928 if (has_enc) {
6929 rb_raise(rb_eArgError, "encoding specified twice");
6930 }
6931 }
6932 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
6933 ecflags = rb_econv_prepare_options(opthash, &ecopts, ecflags);
6934 }
6935
6936 validate_enc_binmode(&fmode, ecflags, enc, enc2);
6937
6938 *vmode_p = vmode;
6939
6940 *oflags_p = oflags;
6941 *fmode_p = fmode;
6942 convconfig_p->enc = enc;
6943 convconfig_p->enc2 = enc2;
6944 convconfig_p->ecflags = ecflags;
6945 convconfig_p->ecopts = ecopts;
6946}
6947
6949 VALUE fname;
6950 int oflags;
6951 mode_t perm;
6952};
6953
6954static void *
6955sysopen_func(void *ptr)
6956{
6957 const struct sysopen_struct *data = ptr;
6958 const char *fname = RSTRING_PTR(data->fname);
6959 return (void *)(VALUE)rb_cloexec_open(fname, data->oflags, data->perm);
6960}
6961
6962static inline int
6963rb_sysopen_internal(struct sysopen_struct *data)
6964{
6965 int fd;
6966 fd = (int)(VALUE)rb_thread_call_without_gvl(sysopen_func, data, RUBY_UBF_IO, 0);
6967 if (0 <= fd)
6968 rb_update_max_fd(fd);
6969 return fd;
6970}
6971
6972static int
6973rb_sysopen(VALUE fname, int oflags, mode_t perm)
6974{
6975 int fd = -1;
6976 struct sysopen_struct data;
6977
6978 data.fname = rb_str_encode_ospath(fname);
6979 StringValueCStr(data.fname);
6980 data.oflags = oflags;
6981 data.perm = perm;
6982
6983 TRY_WITH_GC((fd = rb_sysopen_internal(&data)) >= 0) {
6984 rb_syserr_fail_path(first_errno, fname);
6985 }
6986 return fd;
6987}
6988
6989static inline FILE *
6990fdopen_internal(int fd, const char *modestr)
6991{
6992 FILE *file;
6993
6994#if defined(__sun)
6995 errno = 0;
6996#endif
6997 file = fdopen(fd, modestr);
6998 if (!file) {
6999#ifdef _WIN32
7000 if (errno == 0) errno = EINVAL;
7001#elif defined(__sun)
7002 if (errno == 0) errno = EMFILE;
7003#endif
7004 }
7005 return file;
7006}
7007
7008FILE *
7009rb_fdopen(int fd, const char *modestr)
7010{
7011 FILE *file = 0;
7012
7013 TRY_WITH_GC((file = fdopen_internal(fd, modestr)) != 0) {
7014 rb_syserr_fail(first_errno, 0);
7015 }
7016
7017 /* xxx: should be _IONBF? A buffer in FILE may have trouble. */
7018#ifdef USE_SETVBUF
7019 if (setvbuf(file, NULL, _IOFBF, 0) != 0)
7020 rb_warn("setvbuf() can't be honoured (fd=%d)", fd);
7021#endif
7022 return file;
7023}
7024
7025static int
7026io_check_tty(rb_io_t *fptr)
7027{
7028 int t = isatty(fptr->fd);
7029 if (t)
7030 fptr->mode |= FMODE_TTY|FMODE_DUPLEX;
7031 return t;
7032}
7033
7034static VALUE rb_io_internal_encoding(VALUE);
7035static void io_encoding_set(rb_io_t *, VALUE, VALUE, VALUE);
7036
7037static int
7038io_strip_bom(VALUE io)
7039{
7040 VALUE b1, b2, b3, b4;
7041 rb_io_t *fptr;
7042
7043 GetOpenFile(io, fptr);
7044 if (!(fptr->mode & FMODE_READABLE)) return 0;
7045 if (NIL_P(b1 = rb_io_getbyte(io))) return 0;
7046 switch (b1) {
7047 case INT2FIX(0xEF):
7048 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7049 if (b2 == INT2FIX(0xBB) && !NIL_P(b3 = rb_io_getbyte(io))) {
7050 if (b3 == INT2FIX(0xBF)) {
7051 return rb_utf8_encindex();
7052 }
7053 rb_io_ungetbyte(io, b3);
7054 }
7055 rb_io_ungetbyte(io, b2);
7056 break;
7057
7058 case INT2FIX(0xFE):
7059 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7060 if (b2 == INT2FIX(0xFF)) {
7061 return ENCINDEX_UTF_16BE;
7062 }
7063 rb_io_ungetbyte(io, b2);
7064 break;
7065
7066 case INT2FIX(0xFF):
7067 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7068 if (b2 == INT2FIX(0xFE)) {
7069 b3 = rb_io_getbyte(io);
7070 if (b3 == INT2FIX(0) && !NIL_P(b4 = rb_io_getbyte(io))) {
7071 if (b4 == INT2FIX(0)) {
7072 return ENCINDEX_UTF_32LE;
7073 }
7074 rb_io_ungetbyte(io, b4);
7075 }
7076 rb_io_ungetbyte(io, b3);
7077 return ENCINDEX_UTF_16LE;
7078 }
7079 rb_io_ungetbyte(io, b2);
7080 break;
7081
7082 case INT2FIX(0):
7083 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7084 if (b2 == INT2FIX(0) && !NIL_P(b3 = rb_io_getbyte(io))) {
7085 if (b3 == INT2FIX(0xFE) && !NIL_P(b4 = rb_io_getbyte(io))) {
7086 if (b4 == INT2FIX(0xFF)) {
7087 return ENCINDEX_UTF_32BE;
7088 }
7089 rb_io_ungetbyte(io, b4);
7090 }
7091 rb_io_ungetbyte(io, b3);
7092 }
7093 rb_io_ungetbyte(io, b2);
7094 break;
7095 }
7096 rb_io_ungetbyte(io, b1);
7097 return 0;
7098}
7099
7100static rb_encoding *
7101io_set_encoding_by_bom(VALUE io)
7102{
7103 int idx = io_strip_bom(io);
7104 rb_io_t *fptr;
7105 rb_encoding *extenc = NULL;
7106
7107 GetOpenFile(io, fptr);
7108 if (idx) {
7109 extenc = rb_enc_from_index(idx);
7110 io_encoding_set(fptr, rb_enc_from_encoding(extenc),
7111 rb_io_internal_encoding(io), Qnil);
7112 }
7113 else {
7114 fptr->encs.enc2 = NULL;
7115 }
7116 return extenc;
7117}
7118
7119static VALUE
7120rb_file_open_generic(VALUE io, VALUE filename, int oflags, int fmode,
7121 const struct rb_io_encoding *convconfig, mode_t perm)
7122{
7123 VALUE pathv;
7124 rb_io_t *fptr;
7125 struct rb_io_encoding cc;
7126 if (!convconfig) {
7127 /* Set to default encodings */
7128 rb_io_ext_int_to_encs(NULL, NULL, &cc.enc, &cc.enc2, fmode);
7129 cc.ecflags = 0;
7130 cc.ecopts = Qnil;
7131 convconfig = &cc;
7132 }
7133 validate_enc_binmode(&fmode, convconfig->ecflags,
7134 convconfig->enc, convconfig->enc2);
7135
7136 MakeOpenFile(io, fptr);
7137 fptr->mode = fmode;
7138 fptr->encs = *convconfig;
7139 pathv = rb_str_new_frozen(filename);
7140#ifdef O_TMPFILE
7141 if (!(oflags & O_TMPFILE)) {
7142 fptr->pathv = pathv;
7143 }
7144#else
7145 fptr->pathv = pathv;
7146#endif
7147 fptr->fd = rb_sysopen(pathv, oflags, perm);
7148 io_check_tty(fptr);
7149 if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
7150
7151 return io;
7152}
7153
7154static VALUE
7155rb_file_open_internal(VALUE io, VALUE filename, const char *modestr)
7156{
7157 int fmode = rb_io_modestr_fmode(modestr);
7158 const char *p = strchr(modestr, ':');
7159 struct rb_io_encoding convconfig;
7160
7161 if (p) {
7162 parse_mode_enc(p+1, rb_usascii_encoding(),
7163 &convconfig.enc, &convconfig.enc2, &fmode);
7164 convconfig.ecflags = 0;
7165 convconfig.ecopts = Qnil;
7166 }
7167 else {
7168 rb_encoding *e;
7169 /* Set to default encodings */
7170
7171 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
7172 rb_io_ext_int_to_encs(e, NULL, &convconfig.enc, &convconfig.enc2, fmode);
7173 convconfig.ecflags = 0;
7174 convconfig.ecopts = Qnil;
7175 }
7176
7177 return rb_file_open_generic(io, filename,
7178 rb_io_fmode_oflags(fmode),
7179 fmode,
7180 &convconfig,
7181 0666);
7182}
7183
7184VALUE
7185rb_file_open_str(VALUE fname, const char *modestr)
7186{
7187 FilePathValue(fname);
7188 return rb_file_open_internal(io_alloc(rb_cFile), fname, modestr);
7189}
7190
7191VALUE
7192rb_file_open(const char *fname, const char *modestr)
7193{
7194 return rb_file_open_internal(io_alloc(rb_cFile), rb_str_new_cstr(fname), modestr);
7195}
7196
7197#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7198static struct pipe_list {
7199 rb_io_t *fptr;
7200 struct pipe_list *next;
7201} *pipe_list;
7202
7203static void
7204pipe_add_fptr(rb_io_t *fptr)
7205{
7206 struct pipe_list *list;
7207
7208 list = ALLOC(struct pipe_list);
7209 list->fptr = fptr;
7210 list->next = pipe_list;
7211 pipe_list = list;
7212}
7213
7214static void
7215pipe_del_fptr(rb_io_t *fptr)
7216{
7217 struct pipe_list **prev = &pipe_list;
7218 struct pipe_list *tmp;
7219
7220 while ((tmp = *prev) != 0) {
7221 if (tmp->fptr == fptr) {
7222 *prev = tmp->next;
7223 free(tmp);
7224 return;
7225 }
7226 prev = &tmp->next;
7227 }
7228}
7229
7230#if defined (_WIN32) || defined(__CYGWIN__)
7231static void
7232pipe_atexit(void)
7233{
7234 struct pipe_list *list = pipe_list;
7235 struct pipe_list *tmp;
7236
7237 while (list) {
7238 tmp = list->next;
7239 rb_io_fptr_finalize(list->fptr);
7240 list = tmp;
7241 }
7242}
7243#endif
7244
7245static void
7246pipe_finalize(rb_io_t *fptr, int noraise)
7247{
7248#if !defined(HAVE_WORKING_FORK) && !defined(_WIN32)
7249 int status = 0;
7250 if (fptr->stdio_file) {
7251 status = pclose(fptr->stdio_file);
7252 }
7253 fptr->fd = -1;
7254 fptr->stdio_file = 0;
7255 rb_last_status_set(status, fptr->pid);
7256#else
7257 fptr_finalize(fptr, noraise);
7258#endif
7259 pipe_del_fptr(fptr);
7260}
7261#endif
7262
7263static void
7264fptr_copy_finalizer(rb_io_t *fptr, const rb_io_t *orig)
7265{
7266#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7267 void (*const old_finalize)(struct rb_io*,int) = fptr->finalize;
7268
7269 if (old_finalize == orig->finalize) return;
7270#endif
7271
7272 fptr->finalize = orig->finalize;
7273
7274#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7275 if (old_finalize != pipe_finalize) {
7276 struct pipe_list *list;
7277 for (list = pipe_list; list; list = list->next) {
7278 if (list->fptr == fptr) break;
7279 }
7280 if (!list) pipe_add_fptr(fptr);
7281 }
7282 else {
7283 pipe_del_fptr(fptr);
7284 }
7285#endif
7286}
7287
7288void
7290{
7292 fptr->mode |= FMODE_SYNC;
7293}
7294
7295void
7296rb_io_unbuffered(rb_io_t *fptr)
7297{
7298 rb_io_synchronized(fptr);
7299}
7300
7301int
7302rb_pipe(int *pipes)
7303{
7304 int ret;
7305 TRY_WITH_GC((ret = rb_cloexec_pipe(pipes)) >= 0);
7306 if (ret == 0) {
7307 rb_update_max_fd(pipes[0]);
7308 rb_update_max_fd(pipes[1]);
7309 }
7310 return ret;
7311}
7312
7313#ifdef _WIN32
7314#define HAVE_SPAWNV 1
7315#define spawnv(mode, cmd, args) rb_w32_uaspawn((mode), (cmd), (args))
7316#define spawn(mode, cmd) rb_w32_uspawn((mode), (cmd), 0)
7317#endif
7318
7319#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7320struct popen_arg {
7321 VALUE execarg_obj;
7322 struct rb_execarg *eargp;
7323 int modef;
7324 int pair[2];
7325 int write_pair[2];
7326};
7327#endif
7328
7329#ifdef HAVE_WORKING_FORK
7330# ifndef __EMSCRIPTEN__
7331static void
7332popen_redirect(struct popen_arg *p)
7333{
7334 if ((p->modef & FMODE_READABLE) && (p->modef & FMODE_WRITABLE)) {
7335 close(p->write_pair[1]);
7336 if (p->write_pair[0] != 0) {
7337 dup2(p->write_pair[0], 0);
7338 close(p->write_pair[0]);
7339 }
7340 close(p->pair[0]);
7341 if (p->pair[1] != 1) {
7342 dup2(p->pair[1], 1);
7343 close(p->pair[1]);
7344 }
7345 }
7346 else if (p->modef & FMODE_READABLE) {
7347 close(p->pair[0]);
7348 if (p->pair[1] != 1) {
7349 dup2(p->pair[1], 1);
7350 close(p->pair[1]);
7351 }
7352 }
7353 else {
7354 close(p->pair[1]);
7355 if (p->pair[0] != 0) {
7356 dup2(p->pair[0], 0);
7357 close(p->pair[0]);
7358 }
7359 }
7360}
7361# endif
7362
7363#if defined(__linux__)
7364/* Linux /proc/self/status contains a line: "FDSize:\t<nnn>\n"
7365 * Since /proc may not be available, linux_get_maxfd is just a hint.
7366 * This function, linux_get_maxfd, must be async-signal-safe.
7367 * I.e. opendir() is not usable.
7368 *
7369 * Note that memchr() and memcmp is *not* async-signal-safe in POSIX.
7370 * However they are easy to re-implement in async-signal-safe manner.
7371 * (Also note that there is missing/memcmp.c.)
7372 */
7373static int
7374linux_get_maxfd(void)
7375{
7376 int fd;
7377 char buf[4096], *p, *np, *e;
7378 ssize_t ss;
7379 fd = rb_cloexec_open("/proc/self/status", O_RDONLY|O_NOCTTY, 0);
7380 if (fd < 0) return fd;
7381 ss = read(fd, buf, sizeof(buf));
7382 if (ss < 0) goto err;
7383 p = buf;
7384 e = buf + ss;
7385 while ((int)sizeof("FDSize:\t0\n")-1 <= e-p &&
7386 (np = memchr(p, '\n', e-p)) != NULL) {
7387 if (memcmp(p, "FDSize:", sizeof("FDSize:")-1) == 0) {
7388 int fdsize;
7389 p += sizeof("FDSize:")-1;
7390 *np = '\0';
7391 fdsize = (int)ruby_strtoul(p, (char **)NULL, 10);
7392 close(fd);
7393 return fdsize;
7394 }
7395 p = np+1;
7396 }
7397 /* fall through */
7398
7399 err:
7400 close(fd);
7401 return (int)ss;
7402}
7403#endif
7404
7405/* This function should be async-signal-safe. */
7406void
7407rb_close_before_exec(int lowfd, int maxhint, VALUE noclose_fds)
7408{
7409#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
7410 int fd, ret;
7411 int max = (int)max_file_descriptor;
7412# ifdef F_MAXFD
7413 /* F_MAXFD is available since NetBSD 2.0. */
7414 ret = fcntl(0, F_MAXFD); /* async-signal-safe */
7415 if (ret != -1)
7416 maxhint = max = ret;
7417# elif defined(__linux__)
7418 ret = linux_get_maxfd();
7419 if (maxhint < ret)
7420 maxhint = ret;
7421 /* maxhint = max = ret; if (ret == -1) abort(); // test */
7422# endif
7423 if (max < maxhint)
7424 max = maxhint;
7425 for (fd = lowfd; fd <= max; fd++) {
7426 if (!NIL_P(noclose_fds) &&
7427 RTEST(rb_hash_lookup(noclose_fds, INT2FIX(fd)))) /* async-signal-safe */
7428 continue;
7429 ret = fcntl(fd, F_GETFD); /* async-signal-safe */
7430 if (ret != -1 && !(ret & FD_CLOEXEC)) {
7431 fcntl(fd, F_SETFD, ret|FD_CLOEXEC); /* async-signal-safe */
7432 }
7433# define CONTIGUOUS_CLOSED_FDS 20
7434 if (ret != -1) {
7435 if (max < fd + CONTIGUOUS_CLOSED_FDS)
7436 max = fd + CONTIGUOUS_CLOSED_FDS;
7437 }
7438 }
7439#endif
7440}
7441
7442# ifndef __EMSCRIPTEN__
7443static int
7444popen_exec(void *pp, char *errmsg, size_t errmsg_len)
7445{
7446 struct popen_arg *p = (struct popen_arg*)pp;
7447
7448 return rb_exec_async_signal_safe(p->eargp, errmsg, errmsg_len);
7449}
7450# endif
7451#endif
7452
7453#if (defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)) && !defined __EMSCRIPTEN__
7454static VALUE
7455rb_execarg_fixup_v(VALUE execarg_obj)
7456{
7457 rb_execarg_parent_start(execarg_obj);
7458 return Qnil;
7459}
7460#else
7461char *rb_execarg_commandline(const struct rb_execarg *eargp, VALUE *prog);
7462#endif
7463
7464#ifndef __EMSCRIPTEN__
7465static VALUE
7466pipe_open(VALUE execarg_obj, const char *modestr, int fmode,
7467 const struct rb_io_encoding *convconfig)
7468{
7469 struct rb_execarg *eargp = NIL_P(execarg_obj) ? NULL : rb_execarg_get(execarg_obj);
7470 VALUE prog = eargp ? (eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name) : Qfalse ;
7471 rb_pid_t pid = 0;
7472 rb_io_t *fptr;
7473 VALUE port;
7474 rb_io_t *write_fptr;
7475 VALUE write_port;
7476#if defined(HAVE_WORKING_FORK)
7477 int status;
7478 char errmsg[80] = { '\0' };
7479#endif
7480#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7481 int state;
7482 struct popen_arg arg;
7483#endif
7484 int e = 0;
7485#if defined(HAVE_SPAWNV)
7486# if defined(HAVE_SPAWNVE)
7487# define DO_SPAWN(cmd, args, envp) ((args) ? \
7488 spawnve(P_NOWAIT, (cmd), (args), (envp)) : \
7489 spawne(P_NOWAIT, (cmd), (envp)))
7490# else
7491# define DO_SPAWN(cmd, args, envp) ((args) ? \
7492 spawnv(P_NOWAIT, (cmd), (args)) : \
7493 spawn(P_NOWAIT, (cmd)))
7494# endif
7495# if !defined(HAVE_WORKING_FORK)
7496 char **args = NULL;
7497# if defined(HAVE_SPAWNVE)
7498 char **envp = NULL;
7499# endif
7500# endif
7501#endif
7502#if !defined(HAVE_WORKING_FORK)
7503 struct rb_execarg sarg, *sargp = &sarg;
7504#endif
7505 FILE *fp = 0;
7506 int fd = -1;
7507 int write_fd = -1;
7508#if !defined(HAVE_WORKING_FORK)
7509 const char *cmd = 0;
7510
7511 if (prog)
7512 cmd = StringValueCStr(prog);
7513#endif
7514
7515#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7516 arg.execarg_obj = execarg_obj;
7517 arg.eargp = eargp;
7518 arg.modef = fmode;
7519 arg.pair[0] = arg.pair[1] = -1;
7520 arg.write_pair[0] = arg.write_pair[1] = -1;
7521# if !defined(HAVE_WORKING_FORK)
7522 if (eargp && !eargp->use_shell) {
7523 args = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
7524 }
7525# endif
7526 switch (fmode & (FMODE_READABLE|FMODE_WRITABLE)) {
7528 if (rb_pipe(arg.write_pair) < 0)
7529 rb_sys_fail_str(prog);
7530 if (rb_pipe(arg.pair) < 0) {
7531 e = errno;
7532 close(arg.write_pair[0]);
7533 close(arg.write_pair[1]);
7534 rb_syserr_fail_str(e, prog);
7535 }
7536 if (eargp) {
7537 rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.write_pair[0]));
7538 rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
7539 }
7540 break;
7541 case FMODE_READABLE:
7542 if (rb_pipe(arg.pair) < 0)
7543 rb_sys_fail_str(prog);
7544 if (eargp)
7545 rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
7546 break;
7547 case FMODE_WRITABLE:
7548 if (rb_pipe(arg.pair) < 0)
7549 rb_sys_fail_str(prog);
7550 if (eargp)
7551 rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.pair[0]));
7552 break;
7553 default:
7554 rb_sys_fail_str(prog);
7555 }
7556 if (!NIL_P(execarg_obj)) {
7557 rb_protect(rb_execarg_fixup_v, execarg_obj, &state);
7558 if (state) {
7559 if (0 <= arg.write_pair[0]) close(arg.write_pair[0]);
7560 if (0 <= arg.write_pair[1]) close(arg.write_pair[1]);
7561 if (0 <= arg.pair[0]) close(arg.pair[0]);
7562 if (0 <= arg.pair[1]) close(arg.pair[1]);
7563 rb_execarg_parent_end(execarg_obj);
7564 rb_jump_tag(state);
7565 }
7566
7567# if defined(HAVE_WORKING_FORK)
7568 pid = rb_fork_async_signal_safe(&status, popen_exec, &arg, arg.eargp->redirect_fds, errmsg, sizeof(errmsg));
7569# else
7570 rb_execarg_run_options(eargp, sargp, NULL, 0);
7571# if defined(HAVE_SPAWNVE)
7572 if (eargp->envp_str) envp = (char **)RSTRING_PTR(eargp->envp_str);
7573# endif
7574 while ((pid = DO_SPAWN(cmd, args, envp)) < 0) {
7575 /* exec failed */
7576 switch (e = errno) {
7577 case EAGAIN:
7578# if EWOULDBLOCK != EAGAIN
7579 case EWOULDBLOCK:
7580# endif
7581 rb_thread_sleep(1);
7582 continue;
7583 }
7584 break;
7585 }
7586 if (eargp)
7587 rb_execarg_run_options(sargp, NULL, NULL, 0);
7588# endif
7589 rb_execarg_parent_end(execarg_obj);
7590 }
7591 else {
7592# if defined(HAVE_WORKING_FORK)
7593 pid = rb_call_proc__fork();
7594 if (pid == 0) { /* child */
7595 popen_redirect(&arg);
7596 rb_io_synchronized(RFILE(orig_stdout)->fptr);
7597 rb_io_synchronized(RFILE(orig_stderr)->fptr);
7598 return Qnil;
7599 }
7600# else
7602# endif
7603 }
7604
7605 /* parent */
7606 if (pid < 0) {
7607# if defined(HAVE_WORKING_FORK)
7608 e = errno;
7609# endif
7610 close(arg.pair[0]);
7611 close(arg.pair[1]);
7613 close(arg.write_pair[0]);
7614 close(arg.write_pair[1]);
7615 }
7616# if defined(HAVE_WORKING_FORK)
7617 if (errmsg[0])
7618 rb_syserr_fail(e, errmsg);
7619# endif
7620 rb_syserr_fail_str(e, prog);
7621 }
7622 if ((fmode & FMODE_READABLE) && (fmode & FMODE_WRITABLE)) {
7623 close(arg.pair[1]);
7624 fd = arg.pair[0];
7625 close(arg.write_pair[0]);
7626 write_fd = arg.write_pair[1];
7627 }
7628 else if (fmode & FMODE_READABLE) {
7629 close(arg.pair[1]);
7630 fd = arg.pair[0];
7631 }
7632 else {
7633 close(arg.pair[0]);
7634 fd = arg.pair[1];
7635 }
7636#else
7637 cmd = rb_execarg_commandline(eargp, &prog);
7638 if (!NIL_P(execarg_obj)) {
7639 rb_execarg_parent_start(execarg_obj);
7640 rb_execarg_run_options(eargp, sargp, NULL, 0);
7641 }
7642 fp = popen(cmd, modestr);
7643 e = errno;
7644 if (eargp) {
7645 rb_execarg_parent_end(execarg_obj);
7646 rb_execarg_run_options(sargp, NULL, NULL, 0);
7647 }
7648 if (!fp) rb_syserr_fail_path(e, prog);
7649 fd = fileno(fp);
7650#endif
7651
7652 port = io_alloc(rb_cIO);
7653 MakeOpenFile(port, fptr);
7654 fptr->fd = fd;
7655 fptr->stdio_file = fp;
7656 fptr->mode = fmode | FMODE_SYNC|FMODE_DUPLEX;
7657 if (convconfig) {
7658 fptr->encs = *convconfig;
7659#if RUBY_CRLF_ENVIRONMENT
7662 }
7663#endif
7664 }
7665 else {
7666 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
7668 }
7669#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7670 if (NEED_NEWLINE_DECORATOR_ON_WRITE(fptr)) {
7671 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
7672 }
7673#endif
7674 }
7675 fptr->pid = pid;
7676
7677 if (0 <= write_fd) {
7678 write_port = io_alloc(rb_cIO);
7679 MakeOpenFile(write_port, write_fptr);
7680 write_fptr->fd = write_fd;
7681 write_fptr->mode = (fmode & ~FMODE_READABLE)| FMODE_SYNC|FMODE_DUPLEX;
7682 fptr->mode &= ~FMODE_WRITABLE;
7683 fptr->tied_io_for_writing = write_port;
7684 rb_ivar_set(port, rb_intern("@tied_io_for_writing"), write_port);
7685 }
7686
7687#if defined (__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7688 fptr->finalize = pipe_finalize;
7689 pipe_add_fptr(fptr);
7690#endif
7691 return port;
7692}
7693#else
7694static VALUE
7695pipe_open(VALUE execarg_obj, const char *modestr, int fmode,
7696 const struct rb_io_encoding *convconfig)
7697{
7698 rb_raise(rb_eNotImpError, "popen() is not available");
7699}
7700#endif
7701
7702static int
7703is_popen_fork(VALUE prog)
7704{
7705 if (RSTRING_LEN(prog) == 1 && RSTRING_PTR(prog)[0] == '-') {
7706#if !defined(HAVE_WORKING_FORK)
7707 rb_raise(rb_eNotImpError,
7708 "fork() function is unimplemented on this machine");
7709#else
7710 return TRUE;
7711#endif
7712 }
7713 return FALSE;
7714}
7715
7716static VALUE
7717pipe_open_s(VALUE prog, const char *modestr, int fmode,
7718 const struct rb_io_encoding *convconfig)
7719{
7720 int argc = 1;
7721 VALUE *argv = &prog;
7722 VALUE execarg_obj = Qnil;
7723
7724 if (!is_popen_fork(prog))
7725 execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
7726 return pipe_open(execarg_obj, modestr, fmode, convconfig);
7727}
7728
7729static VALUE
7730pipe_close(VALUE io)
7731{
7732 rb_io_t *fptr = io_close_fptr(io);
7733 if (fptr) {
7734 fptr_waitpid(fptr, rb_thread_to_be_killed(rb_thread_current()));
7735 }
7736 return Qnil;
7737}
7738
7739static VALUE popen_finish(VALUE port, VALUE klass);
7740
7741/*
7742 * call-seq:
7743 * IO.popen(env = {}, cmd, mode = 'r', **opts) -> io
7744 * IO.popen(env = {}, cmd, mode = 'r', **opts) {|io| ... } -> object
7745 *
7746 * Executes the given command +cmd+ as a subprocess
7747 * whose $stdin and $stdout are connected to a new stream +io+.
7748 *
7749 * This method has potential security vulnerabilities if called with untrusted input;
7750 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
7751 *
7752 * If no block is given, returns the new stream,
7753 * which depending on given +mode+ may be open for reading, writing, or both.
7754 * The stream should be explicitly closed (eventually) to avoid resource leaks.
7755 *
7756 * If a block is given, the stream is passed to the block
7757 * (again, open for reading, writing, or both);
7758 * when the block exits, the stream is closed,
7759 * and the block's value is assigned to global variable <tt>$?</tt> and returned.
7760 *
7761 * Optional argument +mode+ may be any valid \IO mode.
7762 * See {Access Modes}[rdoc-ref:File@Access+Modes].
7763 *
7764 * Required argument +cmd+ determines which of the following occurs:
7765 *
7766 * - The process forks.
7767 * - A specified program runs in a shell.
7768 * - A specified program runs with specified arguments.
7769 * - A specified program runs with specified arguments and a specified +argv0+.
7770 *
7771 * Each of these is detailed below.
7772 *
7773 * The optional hash argument +env+ specifies name/value pairs that are to be added
7774 * to the environment variables for the subprocess:
7775 *
7776 * IO.popen({'FOO' => 'bar'}, 'ruby', 'r+') do |pipe|
7777 * pipe.puts 'puts ENV["FOO"]'
7778 * pipe.close_write
7779 * pipe.gets
7780 * end => "bar\n"
7781 *
7782 * Optional keyword arguments +opts+ specify:
7783 *
7784 * - {Open options}[rdoc-ref:IO@Open+Options].
7785 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
7786 * - Options for Kernel#spawn.
7787 *
7788 * <b>Forked \Process</b>
7789 *
7790 * When argument +cmd+ is the 1-character string <tt>'-'</tt>, causes the process to fork:
7791 * IO.popen('-') do |pipe|
7792 * if pipe
7793 * $stderr.puts "In parent, child pid is #{pipe.pid}\n"
7794 * else
7795 * $stderr.puts "In child, pid is #{$$}\n"
7796 * end
7797 * end
7798 *
7799 * Output:
7800 *
7801 * In parent, child pid is 26253
7802 * In child, pid is 26253
7803 *
7804 * Note that this is not supported on all platforms.
7805 *
7806 * <b>Shell Subprocess</b>
7807 *
7808 * When argument +cmd+ is a single string (but not <tt>'-'</tt>),
7809 * the program named +cmd+ is run as a shell command:
7810 *
7811 * IO.popen('uname') do |pipe|
7812 * pipe.readlines
7813 * end
7814 *
7815 * Output:
7816 *
7817 * ["Linux\n"]
7818 *
7819 * Another example:
7820 *
7821 * IO.popen('/bin/sh', 'r+') do |pipe|
7822 * pipe.puts('ls')
7823 * pipe.close_write
7824 * $stderr.puts pipe.readlines.size
7825 * end
7826 *
7827 * Output:
7828 *
7829 * 213
7830 *
7831 * <b>Program Subprocess</b>
7832 *
7833 * When argument +cmd+ is an array of strings,
7834 * the program named <tt>cmd[0]</tt> is run with all elements of +cmd+ as its arguments:
7835 *
7836 * IO.popen(['du', '..', '.']) do |pipe|
7837 * $stderr.puts pipe.readlines.size
7838 * end
7839 *
7840 * Output:
7841 *
7842 * 1111
7843 *
7844 * <b>Program Subprocess with <tt>argv0</tt></b>
7845 *
7846 * When argument +cmd+ is an array whose first element is a 2-element string array
7847 * and whose remaining elements (if any) are strings:
7848 *
7849 * - <tt>cmd[0][0]</tt> (the first string in the nested array) is the name of a program that is run.
7850 * - <tt>cmd[0][1]</tt> (the second string in the nested array) is set as the program's <tt>argv[0]</tt>.
7851 * - <tt>cmd[1..-1]</tt> (the strings in the outer array) are the program's arguments.
7852 *
7853 * Example (sets <tt>$0</tt> to 'foo'):
7854 *
7855 * IO.popen([['/bin/sh', 'foo'], '-c', 'echo $0']).read # => "foo\n"
7856 *
7857 * <b>Some Special Examples</b>
7858 *
7859 * # Set IO encoding.
7860 * IO.popen("nkf -e filename", :external_encoding=>"EUC-JP") {|nkf_io|
7861 * euc_jp_string = nkf_io.read
7862 * }
7863 *
7864 * # Merge standard output and standard error using Kernel#spawn option. See Kernel#spawn.
7865 * IO.popen(["ls", "/", :err=>[:child, :out]]) do |io|
7866 * ls_result_with_error = io.read
7867 * end
7868 *
7869 * # Use mixture of spawn options and IO options.
7870 * IO.popen(["ls", "/"], :err=>[:child, :out]) do |io|
7871 * ls_result_with_error = io.read
7872 * end
7873 *
7874 * f = IO.popen("uname")
7875 * p f.readlines
7876 * f.close
7877 * puts "Parent is #{Process.pid}"
7878 * IO.popen("date") {|f| puts f.gets }
7879 * IO.popen("-") {|f| $stderr.puts "#{Process.pid} is here, f is #{f.inspect}"}
7880 * p $?
7881 * IO.popen(%w"sed -e s|^|<foo>| -e s&$&;zot;&", "r+") {|f|
7882 * f.puts "bar"; f.close_write; puts f.gets
7883 * }
7884 *
7885 * Output (from last section):
7886 *
7887 * ["Linux\n"]
7888 * Parent is 21346
7889 * Thu Jan 15 22:41:19 JST 2009
7890 * 21346 is here, f is #<IO:fd 3>
7891 * 21352 is here, f is nil
7892 * #<Process::Status: pid 21352 exit 0>
7893 * <foo>bar;zot;
7894 *
7895 * Raises exceptions that IO.pipe and Kernel.spawn raise.
7896 *
7897 */
7898
7899static VALUE
7900rb_io_s_popen(int argc, VALUE *argv, VALUE klass)
7901{
7902 VALUE pname, pmode = Qnil, opt = Qnil, env = Qnil;
7903
7904 if (argc > 1 && !NIL_P(opt = rb_check_hash_type(argv[argc-1]))) --argc;
7905 if (argc > 1 && !NIL_P(env = rb_check_hash_type(argv[0]))) --argc, ++argv;
7906 switch (argc) {
7907 case 2:
7908 pmode = argv[1];
7909 case 1:
7910 pname = argv[0];
7911 break;
7912 default:
7913 {
7914 int ex = !NIL_P(opt);
7915 rb_error_arity(argc + ex, 1 + ex, 2 + ex);
7916 }
7917 }
7918 return popen_finish(rb_io_popen(pname, pmode, env, opt), klass);
7919}
7920
7921VALUE
7922rb_io_popen(VALUE pname, VALUE pmode, VALUE env, VALUE opt)
7923{
7924 const char *modestr;
7925 VALUE tmp, execarg_obj = Qnil;
7926 int oflags, fmode;
7927 struct rb_io_encoding convconfig;
7928
7929 tmp = rb_check_array_type(pname);
7930 if (!NIL_P(tmp)) {
7931 long len = RARRAY_LEN(tmp);
7932#if SIZEOF_LONG > SIZEOF_INT
7933 if (len > INT_MAX) {
7934 rb_raise(rb_eArgError, "too many arguments");
7935 }
7936#endif
7937 execarg_obj = rb_execarg_new((int)len, RARRAY_CONST_PTR(tmp), FALSE, FALSE);
7938 RB_GC_GUARD(tmp);
7939 }
7940 else {
7941 SafeStringValue(pname);
7942 execarg_obj = Qnil;
7943 if (!is_popen_fork(pname))
7944 execarg_obj = rb_execarg_new(1, &pname, TRUE, FALSE);
7945 }
7946 if (!NIL_P(execarg_obj)) {
7947 if (!NIL_P(opt))
7948 opt = rb_execarg_extract_options(execarg_obj, opt);
7949 if (!NIL_P(env))
7950 rb_execarg_setenv(execarg_obj, env);
7951 }
7952 rb_io_extract_modeenc(&pmode, 0, opt, &oflags, &fmode, &convconfig);
7953 modestr = rb_io_oflags_modestr(oflags);
7954
7955 return pipe_open(execarg_obj, modestr, fmode, &convconfig);
7956}
7957
7958static VALUE
7959popen_finish(VALUE port, VALUE klass)
7960{
7961 if (NIL_P(port)) {
7962 /* child */
7963 if (rb_block_given_p()) {
7964 rb_yield(Qnil);
7965 rb_io_flush(rb_ractor_stdout());
7966 rb_io_flush(rb_ractor_stderr());
7967 _exit(0);
7968 }
7969 return Qnil;
7970 }
7971 RBASIC_SET_CLASS(port, klass);
7972 if (rb_block_given_p()) {
7973 return rb_ensure(rb_yield, port, pipe_close, port);
7974 }
7975 return port;
7976}
7977
7978#if defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)
7979struct popen_writer_arg {
7980 char *const *argv;
7981 struct popen_arg popen;
7982};
7983
7984static int
7985exec_popen_writer(void *arg, char *errmsg, size_t buflen)
7986{
7987 struct popen_writer_arg *pw = arg;
7988 pw->popen.modef = FMODE_WRITABLE;
7989 popen_redirect(&pw->popen);
7990 execv(pw->argv[0], pw->argv);
7991 strlcpy(errmsg, strerror(errno), buflen);
7992 return -1;
7993}
7994#endif
7995
7996FILE *
7997ruby_popen_writer(char *const *argv, rb_pid_t *pid)
7998{
7999#if (defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)) || defined(_WIN32)
8000# ifdef HAVE_WORKING_FORK
8001 struct popen_writer_arg pw;
8002 int *const write_pair = pw.popen.pair;
8003# else
8004 int write_pair[2];
8005# endif
8006
8007 int result = rb_cloexec_pipe(write_pair);
8008 *pid = -1;
8009 if (result == 0) {
8010# ifdef HAVE_WORKING_FORK
8011 pw.argv = argv;
8012 int status;
8013 char errmsg[80] = {'\0'};
8014 *pid = rb_fork_async_signal_safe(&status, exec_popen_writer, &pw, Qnil, errmsg, sizeof(errmsg));
8015# else
8016 *pid = rb_w32_uspawn_process(P_NOWAIT, argv[0], argv, write_pair[0], -1, -1, 0);
8017 const char *errmsg = (*pid < 0) ? strerror(errno) : NULL;
8018# endif
8019 close(write_pair[0]);
8020 if (*pid < 0) {
8021 close(write_pair[1]);
8022 fprintf(stderr, "ruby_popen_writer(%s): %s\n", argv[0], errmsg);
8023 }
8024 else {
8025 return fdopen(write_pair[1], "w");
8026 }
8027 }
8028#endif
8029 return NULL;
8030}
8031
8032static void
8033rb_scan_open_args(int argc, const VALUE *argv,
8034 VALUE *fname_p, int *oflags_p, int *fmode_p,
8035 struct rb_io_encoding *convconfig_p, mode_t *perm_p)
8036{
8037 VALUE opt, fname, vmode, vperm;
8038 int oflags, fmode;
8039 mode_t perm;
8040
8041 argc = rb_scan_args(argc, argv, "12:", &fname, &vmode, &vperm, &opt);
8042 FilePathValue(fname);
8043
8044 rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, convconfig_p);
8045
8046 perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
8047
8048 *fname_p = fname;
8049 *oflags_p = oflags;
8050 *fmode_p = fmode;
8051 *perm_p = perm;
8052}
8053
8054static VALUE
8055rb_open_file(int argc, const VALUE *argv, VALUE io)
8056{
8057 VALUE fname;
8058 int oflags, fmode;
8059 struct rb_io_encoding convconfig;
8060 mode_t perm;
8061
8062 rb_scan_open_args(argc, argv, &fname, &oflags, &fmode, &convconfig, &perm);
8063 rb_file_open_generic(io, fname, oflags, fmode, &convconfig, perm);
8064
8065 return io;
8066}
8067
8068/*
8069 * Document-method: File::open
8070 *
8071 * call-seq:
8072 * File.open(path, mode = 'r', perm = 0666, **opts) -> file
8073 * File.open(path, mode = 'r', perm = 0666, **opts) {|f| ... } -> object
8074 *
8075 * Creates a new File object, via File.new with the given arguments.
8076 *
8077 * With no block given, returns the File object.
8078 *
8079 * With a block given, calls the block with the File object
8080 * and returns the block's value.
8081 *
8082 */
8083
8084/*
8085 * Document-method: IO::open
8086 *
8087 * call-seq:
8088 * IO.open(fd, mode = 'r', **opts) -> io
8089 * IO.open(fd, mode = 'r', **opts) {|io| ... } -> object
8090 *
8091 * Creates a new \IO object, via IO.new with the given arguments.
8092 *
8093 * With no block given, returns the \IO object.
8094 *
8095 * With a block given, calls the block with the \IO object
8096 * and returns the block's value.
8097 *
8098 */
8099
8100static VALUE
8101rb_io_s_open(int argc, VALUE *argv, VALUE klass)
8102{
8104
8105 if (rb_block_given_p()) {
8106 return rb_ensure(rb_yield, io, io_close, io);
8107 }
8108
8109 return io;
8110}
8111
8112/*
8113 * call-seq:
8114 * IO.sysopen(path, mode = 'r', perm = 0666) -> integer
8115 *
8116 * Opens the file at the given path with the given mode and permissions;
8117 * returns the integer file descriptor.
8118 *
8119 * If the file is to be readable, it must exist;
8120 * if the file is to be writable and does not exist,
8121 * it is created with the given permissions:
8122 *
8123 * File.write('t.tmp', '') # => 0
8124 * IO.sysopen('t.tmp') # => 8
8125 * IO.sysopen('t.tmp', 'w') # => 9
8126 *
8127 *
8128 */
8129
8130static VALUE
8131rb_io_s_sysopen(int argc, VALUE *argv, VALUE _)
8132{
8133 VALUE fname, vmode, vperm;
8134 VALUE intmode;
8135 int oflags, fd;
8136 mode_t perm;
8137
8138 rb_scan_args(argc, argv, "12", &fname, &vmode, &vperm);
8139 FilePathValue(fname);
8140
8141 if (NIL_P(vmode))
8142 oflags = O_RDONLY;
8143 else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int")))
8144 oflags = NUM2INT(intmode);
8145 else {
8146 SafeStringValue(vmode);
8147 oflags = rb_io_modestr_oflags(StringValueCStr(vmode));
8148 }
8149 if (NIL_P(vperm)) perm = 0666;
8150 else perm = NUM2MODET(vperm);
8151
8152 RB_GC_GUARD(fname) = rb_str_new4(fname);
8153 fd = rb_sysopen(fname, oflags, perm);
8154 return INT2NUM(fd);
8155}
8156
8157static VALUE
8158check_pipe_command(VALUE filename_or_command)
8159{
8160 char *s = RSTRING_PTR(filename_or_command);
8161 long l = RSTRING_LEN(filename_or_command);
8162 char *e = s + l;
8163 int chlen;
8164
8165 if (rb_enc_ascget(s, e, &chlen, rb_enc_get(filename_or_command)) == '|') {
8166 VALUE cmd = rb_str_new(s+chlen, l-chlen);
8167 return cmd;
8168 }
8169 return Qnil;
8170}
8171
8172/*
8173 * call-seq:
8174 * open(path, mode = 'r', perm = 0666, **opts) -> io or nil
8175 * open(path, mode = 'r', perm = 0666, **opts) {|io| ... } -> obj
8176 *
8177 * Creates an IO object connected to the given file.
8178 *
8179 * This method has potential security vulnerabilities if called with untrusted input;
8180 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
8181 *
8182 * With no block given, file stream is returned:
8183 *
8184 * open('t.txt') # => #<File:t.txt>
8185 *
8186 * With a block given, calls the block with the open file stream,
8187 * then closes the stream:
8188 *
8189 * open('t.txt') {|f| p f } # => #<File:t.txt (closed)>
8190 *
8191 * Output:
8192 *
8193 * #<File:t.txt>
8194 *
8195 * See File.open for details.
8196 *
8197 */
8198
8199static VALUE
8200rb_f_open(int argc, VALUE *argv, VALUE _)
8201{
8202 ID to_open = 0;
8203 int redirect = FALSE;
8204
8205 if (argc >= 1) {
8206 CONST_ID(to_open, "to_open");
8207 if (rb_respond_to(argv[0], to_open)) {
8208 redirect = TRUE;
8209 }
8210 else {
8211 VALUE tmp = argv[0];
8212 FilePathValue(tmp);
8213 if (NIL_P(tmp)) {
8214 redirect = TRUE;
8215 }
8216 else {
8217 VALUE cmd = check_pipe_command(tmp);
8218 if (!NIL_P(cmd)) {
8219 // TODO: when removed in 4.0, update command_injection.rdoc
8220 rb_warn_deprecated_to_remove_at(4.0, "Calling Kernel#open with a leading '|'", "IO.popen");
8221 argv[0] = cmd;
8222 return rb_io_s_popen(argc, argv, rb_cIO);
8223 }
8224 }
8225 }
8226 }
8227 if (redirect) {
8228 VALUE io = rb_funcallv_kw(argv[0], to_open, argc-1, argv+1, RB_PASS_CALLED_KEYWORDS);
8229
8230 if (rb_block_given_p()) {
8231 return rb_ensure(rb_yield, io, io_close, io);
8232 }
8233 return io;
8234 }
8235 return rb_io_s_open(argc, argv, rb_cFile);
8236}
8237
8238static VALUE rb_io_open_generic(VALUE, VALUE, int, int, const struct rb_io_encoding *, mode_t);
8239
8240static VALUE
8241rb_io_open(VALUE io, VALUE filename, VALUE vmode, VALUE vperm, VALUE opt)
8242{
8243 int oflags, fmode;
8244 struct rb_io_encoding convconfig;
8245 mode_t perm;
8246
8247 rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, &convconfig);
8248 perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
8249 return rb_io_open_generic(io, filename, oflags, fmode, &convconfig, perm);
8250}
8251
8252static VALUE
8253rb_io_open_generic(VALUE klass, VALUE filename, int oflags, int fmode,
8254 const struct rb_io_encoding *convconfig, mode_t perm)
8255{
8256 VALUE cmd;
8257 if (klass == rb_cIO && !NIL_P(cmd = check_pipe_command(filename))) {
8258 // TODO: when removed in 4.0, update command_injection.rdoc
8259 rb_warn_deprecated_to_remove_at(4.0, "IO process creation with a leading '|'", "IO.popen");
8260 return pipe_open_s(cmd, rb_io_oflags_modestr(oflags), fmode, convconfig);
8261 }
8262 else {
8263 return rb_file_open_generic(io_alloc(klass), filename,
8264 oflags, fmode, convconfig, perm);
8265 }
8266}
8267
8268static VALUE
8269io_reopen(VALUE io, VALUE nfile)
8270{
8271 rb_io_t *fptr, *orig;
8272 int fd, fd2;
8273 rb_off_t pos = 0;
8274
8275 nfile = rb_io_get_io(nfile);
8276 GetOpenFile(io, fptr);
8277 GetOpenFile(nfile, orig);
8278
8279 if (fptr == orig) return io;
8280 if (RUBY_IO_EXTERNAL_P(fptr)) {
8281 if ((fptr->stdio_file == stdin && !(orig->mode & FMODE_READABLE)) ||
8282 (fptr->stdio_file == stdout && !(orig->mode & FMODE_WRITABLE)) ||
8283 (fptr->stdio_file == stderr && !(orig->mode & FMODE_WRITABLE))) {
8284 rb_raise(rb_eArgError,
8285 "%s can't change access mode from \"%s\" to \"%s\"",
8286 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
8287 rb_io_fmode_modestr(orig->mode));
8288 }
8289 }
8290 if (fptr->mode & FMODE_WRITABLE) {
8291 if (io_fflush(fptr) < 0)
8292 rb_sys_fail_on_write(fptr);
8293 }
8294 else {
8295 flush_before_seek(fptr);
8296 }
8297 if (orig->mode & FMODE_READABLE) {
8298 pos = io_tell(orig);
8299 }
8300 if (orig->mode & FMODE_WRITABLE) {
8301 if (io_fflush(orig) < 0)
8302 rb_sys_fail_on_write(fptr);
8303 }
8304
8305 /* copy rb_io_t structure */
8306 fptr->mode = orig->mode | (fptr->mode & FMODE_EXTERNAL);
8307 fptr->pid = orig->pid;
8308 fptr->lineno = orig->lineno;
8309 if (RTEST(orig->pathv)) fptr->pathv = orig->pathv;
8310 else if (!RUBY_IO_EXTERNAL_P(fptr)) fptr->pathv = Qnil;
8311 fptr_copy_finalizer(fptr, orig);
8312
8313 fd = fptr->fd;
8314 fd2 = orig->fd;
8315 if (fd != fd2) {
8316 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2 || !fptr->stdio_file) {
8317 /* need to keep FILE objects of stdin, stdout and stderr */
8318 if (rb_cloexec_dup2(fd2, fd) < 0)
8319 rb_sys_fail_path(orig->pathv);
8320 rb_update_max_fd(fd);
8321 }
8322 else {
8323 fclose(fptr->stdio_file);
8324 fptr->stdio_file = 0;
8325 fptr->fd = -1;
8326 if (rb_cloexec_dup2(fd2, fd) < 0)
8327 rb_sys_fail_path(orig->pathv);
8328 rb_update_max_fd(fd);
8329 fptr->fd = fd;
8330 }
8332 if ((orig->mode & FMODE_READABLE) && pos >= 0) {
8333 if (io_seek(fptr, pos, SEEK_SET) < 0 && errno) {
8334 rb_sys_fail_path(fptr->pathv);
8335 }
8336 if (io_seek(orig, pos, SEEK_SET) < 0 && errno) {
8337 rb_sys_fail_path(orig->pathv);
8338 }
8339 }
8340 }
8341
8342 if (fptr->mode & FMODE_BINMODE) {
8343 rb_io_binmode(io);
8344 }
8345
8346 RBASIC_SET_CLASS(io, rb_obj_class(nfile));
8347 return io;
8348}
8349
8350#ifdef _WIN32
8351int rb_freopen(VALUE fname, const char *mode, FILE *fp);
8352#else
8353static int
8354rb_freopen(VALUE fname, const char *mode, FILE *fp)
8355{
8356 if (!freopen(RSTRING_PTR(fname), mode, fp)) {
8357 RB_GC_GUARD(fname);
8358 return errno;
8359 }
8360 return 0;
8361}
8362#endif
8363
8364/*
8365 * call-seq:
8366 * reopen(other_io) -> self
8367 * reopen(path, mode = 'r', **opts) -> self
8368 *
8369 * Reassociates the stream with another stream,
8370 * which may be of a different class.
8371 * This method may be used to redirect an existing stream
8372 * to a new destination.
8373 *
8374 * With argument +other_io+ given, reassociates with that stream:
8375 *
8376 * # Redirect $stdin from a file.
8377 * f = File.open('t.txt')
8378 * $stdin.reopen(f)
8379 * f.close
8380 *
8381 * # Redirect $stdout to a file.
8382 * f = File.open('t.tmp', 'w')
8383 * $stdout.reopen(f)
8384 * f.close
8385 *
8386 * With argument +path+ given, reassociates with a new stream to that file path:
8387 *
8388 * $stdin.reopen('t.txt')
8389 * $stdout.reopen('t.tmp', 'w')
8390 *
8391 * Optional keyword arguments +opts+ specify:
8392 *
8393 * - {Open Options}[rdoc-ref:IO@Open+Options].
8394 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
8395 *
8396 */
8397
8398static VALUE
8399rb_io_reopen(int argc, VALUE *argv, VALUE file)
8400{
8401 VALUE fname, nmode, opt;
8402 int oflags;
8403 rb_io_t *fptr;
8404
8405 if (rb_scan_args(argc, argv, "11:", &fname, &nmode, &opt) == 1) {
8406 VALUE tmp = rb_io_check_io(fname);
8407 if (!NIL_P(tmp)) {
8408 return io_reopen(file, tmp);
8409 }
8410 }
8411
8412 FilePathValue(fname);
8413 rb_io_taint_check(file);
8414 fptr = RFILE(file)->fptr;
8415 if (!fptr) {
8416 fptr = RFILE(file)->fptr = ZALLOC(rb_io_t);
8417 }
8418
8419 if (!NIL_P(nmode) || !NIL_P(opt)) {
8420 int fmode;
8421 struct rb_io_encoding convconfig;
8422
8423 rb_io_extract_modeenc(&nmode, 0, opt, &oflags, &fmode, &convconfig);
8424 if (RUBY_IO_EXTERNAL_P(fptr) &&
8425 ((fptr->mode & FMODE_READWRITE) & (fmode & FMODE_READWRITE)) !=
8426 (fptr->mode & FMODE_READWRITE)) {
8427 rb_raise(rb_eArgError,
8428 "%s can't change access mode from \"%s\" to \"%s\"",
8429 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
8430 rb_io_fmode_modestr(fmode));
8431 }
8432 fptr->mode = fmode;
8433 fptr->encs = convconfig;
8434 }
8435 else {
8436 oflags = rb_io_fmode_oflags(fptr->mode);
8437 }
8438
8439 fptr->pathv = fname;
8440 if (fptr->fd < 0) {
8441 fptr->fd = rb_sysopen(fptr->pathv, oflags, 0666);
8442 fptr->stdio_file = 0;
8443 return file;
8444 }
8445
8446 if (fptr->mode & FMODE_WRITABLE) {
8447 if (io_fflush(fptr) < 0)
8448 rb_sys_fail_on_write(fptr);
8449 }
8450 fptr->rbuf.off = fptr->rbuf.len = 0;
8451
8452 if (fptr->stdio_file) {
8453 int e = rb_freopen(rb_str_encode_ospath(fptr->pathv),
8454 rb_io_oflags_modestr(oflags),
8455 fptr->stdio_file);
8456 if (e) rb_syserr_fail_path(e, fptr->pathv);
8457 fptr->fd = fileno(fptr->stdio_file);
8458 rb_fd_fix_cloexec(fptr->fd);
8459#ifdef USE_SETVBUF
8460 if (setvbuf(fptr->stdio_file, NULL, _IOFBF, 0) != 0)
8461 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8462#endif
8463 if (fptr->stdio_file == stderr) {
8464 if (setvbuf(fptr->stdio_file, NULL, _IONBF, BUFSIZ) != 0)
8465 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8466 }
8467 else if (fptr->stdio_file == stdout && isatty(fptr->fd)) {
8468 if (setvbuf(fptr->stdio_file, NULL, _IOLBF, BUFSIZ) != 0)
8469 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8470 }
8471 }
8472 else {
8473 int tmpfd = rb_sysopen(fptr->pathv, oflags, 0666);
8474 int err = 0;
8475 if (rb_cloexec_dup2(tmpfd, fptr->fd) < 0)
8476 err = errno;
8477 (void)close(tmpfd);
8478 if (err) {
8479 rb_syserr_fail_path(err, fptr->pathv);
8480 }
8481 }
8482
8483 return file;
8484}
8485
8486/* :nodoc: */
8487static VALUE
8488rb_io_init_copy(VALUE dest, VALUE io)
8489{
8490 rb_io_t *fptr, *orig;
8491 int fd;
8492 VALUE write_io;
8493 rb_off_t pos;
8494
8495 io = rb_io_get_io(io);
8496 if (!OBJ_INIT_COPY(dest, io)) return dest;
8497 GetOpenFile(io, orig);
8498 MakeOpenFile(dest, fptr);
8499
8500 rb_io_flush(io);
8501
8502 /* copy rb_io_t structure */
8503 fptr->mode = orig->mode & ~FMODE_EXTERNAL;
8504 fptr->encs = orig->encs;
8505 fptr->pid = orig->pid;
8506 fptr->lineno = orig->lineno;
8507 fptr->timeout = orig->timeout;
8508 if (!NIL_P(orig->pathv)) fptr->pathv = orig->pathv;
8509 fptr_copy_finalizer(fptr, orig);
8510
8511 fd = ruby_dup(orig->fd);
8512 fptr->fd = fd;
8513 pos = io_tell(orig);
8514 if (0 <= pos)
8515 io_seek(fptr, pos, SEEK_SET);
8516 if (fptr->mode & FMODE_BINMODE) {
8517 rb_io_binmode(dest);
8518 }
8519
8520 write_io = GetWriteIO(io);
8521 if (io != write_io) {
8522 write_io = rb_obj_dup(write_io);
8523 fptr->tied_io_for_writing = write_io;
8524 rb_ivar_set(dest, rb_intern("@tied_io_for_writing"), write_io);
8525 }
8526
8527 return dest;
8528}
8529
8530/*
8531 * call-seq:
8532 * printf(format_string, *objects) -> nil
8533 *
8534 * Formats and writes +objects+ to the stream.
8535 *
8536 * For details on +format_string+, see
8537 * {Format Specifications}[rdoc-ref:format_specifications.rdoc].
8538 *
8539 */
8540
8541VALUE
8542rb_io_printf(int argc, const VALUE *argv, VALUE out)
8543{
8544 rb_io_write(out, rb_f_sprintf(argc, argv));
8545 return Qnil;
8546}
8547
8548/*
8549 * call-seq:
8550 * printf(format_string, *objects) -> nil
8551 * printf(io, format_string, *objects) -> nil
8552 *
8553 * Equivalent to:
8554 *
8555 * io.write(sprintf(format_string, *objects))
8556 *
8557 * For details on +format_string+, see
8558 * {Format Specifications}[rdoc-ref:format_specifications.rdoc].
8559 *
8560 * With the single argument +format_string+, formats +objects+ into the string,
8561 * then writes the formatted string to $stdout:
8562 *
8563 * printf('%4.4d %10s %2.2f', 24, 24, 24.0)
8564 *
8565 * Output (on $stdout):
8566 *
8567 * 0024 24 24.00#
8568 *
8569 * With arguments +io+ and +format_string+, formats +objects+ into the string,
8570 * then writes the formatted string to +io+:
8571 *
8572 * printf($stderr, '%4.4d %10s %2.2f', 24, 24, 24.0)
8573 *
8574 * Output (on $stderr):
8575 *
8576 * 0024 24 24.00# => nil
8577 *
8578 * With no arguments, does nothing.
8579 *
8580 */
8581
8582static VALUE
8583rb_f_printf(int argc, VALUE *argv, VALUE _)
8584{
8585 VALUE out;
8586
8587 if (argc == 0) return Qnil;
8588 if (RB_TYPE_P(argv[0], T_STRING)) {
8589 out = rb_ractor_stdout();
8590 }
8591 else {
8592 out = argv[0];
8593 argv++;
8594 argc--;
8595 }
8596 rb_io_write(out, rb_f_sprintf(argc, argv));
8597
8598 return Qnil;
8599}
8600
8601static void
8602deprecated_str_setter(VALUE val, ID id, VALUE *var)
8603{
8604 rb_str_setter(val, id, &val);
8605 if (!NIL_P(val)) {
8606 rb_warn_deprecated("`%s'", NULL, rb_id2name(id));
8607 }
8608 *var = val;
8609}
8610
8611/*
8612 * call-seq:
8613 * print(*objects) -> nil
8614 *
8615 * Writes the given objects to the stream; returns +nil+.
8616 * Appends the output record separator <tt>$OUTPUT_RECORD_SEPARATOR</tt>
8617 * (<tt>$\</tt>), if it is not +nil+.
8618 * See {Line IO}[rdoc-ref:IO@Line+IO].
8619 *
8620 * With argument +objects+ given, for each object:
8621 *
8622 * - Converts via its method +to_s+ if not a string.
8623 * - Writes to the stream.
8624 * - If not the last object, writes the output field separator
8625 * <tt>$OUTPUT_FIELD_SEPARATOR</tt> (<tt>$,</tt>) if it is not +nil+.
8626 *
8627 * With default separators:
8628 *
8629 * f = File.open('t.tmp', 'w+')
8630 * objects = [0, 0.0, Rational(0, 1), Complex(0, 0), :zero, 'zero']
8631 * p $OUTPUT_RECORD_SEPARATOR
8632 * p $OUTPUT_FIELD_SEPARATOR
8633 * f.print(*objects)
8634 * f.rewind
8635 * p f.read
8636 * f.close
8637 *
8638 * Output:
8639 *
8640 * nil
8641 * nil
8642 * "00.00/10+0izerozero"
8643 *
8644 * With specified separators:
8645 *
8646 * $\ = "\n"
8647 * $, = ','
8648 * f.rewind
8649 * f.print(*objects)
8650 * f.rewind
8651 * p f.read
8652 *
8653 * Output:
8654 *
8655 * "0,0.0,0/1,0+0i,zero,zero\n"
8656 *
8657 * With no argument given, writes the content of <tt>$_</tt>
8658 * (which is usually the most recent user input):
8659 *
8660 * f = File.open('t.tmp', 'w+')
8661 * gets # Sets $_ to the most recent user input.
8662 * f.print
8663 * f.close
8664 *
8665 */
8666
8667VALUE
8668rb_io_print(int argc, const VALUE *argv, VALUE out)
8669{
8670 int i;
8671 VALUE line;
8672
8673 /* if no argument given, print `$_' */
8674 if (argc == 0) {
8675 argc = 1;
8676 line = rb_lastline_get();
8677 argv = &line;
8678 }
8679 if (argc > 1 && !NIL_P(rb_output_fs)) {
8680 rb_category_warn(RB_WARN_CATEGORY_DEPRECATED, "$, is set to non-nil value");
8681 }
8682 for (i=0; i<argc; i++) {
8683 if (!NIL_P(rb_output_fs) && i>0) {
8684 rb_io_write(out, rb_output_fs);
8685 }
8686 rb_io_write(out, argv[i]);
8687 }
8688 if (argc > 0 && !NIL_P(rb_output_rs)) {
8689 rb_io_write(out, rb_output_rs);
8690 }
8691
8692 return Qnil;
8693}
8694
8695/*
8696 * call-seq:
8697 * print(*objects) -> nil
8698 *
8699 * Equivalent to <tt>$stdout.print(*objects)</tt>,
8700 * this method is the straightforward way to write to <tt>$stdout</tt>.
8701 *
8702 * Writes the given objects to <tt>$stdout</tt>; returns +nil+.
8703 * Appends the output record separator <tt>$OUTPUT_RECORD_SEPARATOR</tt>
8704 * <tt>$\</tt>), if it is not +nil+.
8705 *
8706 * With argument +objects+ given, for each object:
8707 *
8708 * - Converts via its method +to_s+ if not a string.
8709 * - Writes to <tt>stdout</tt>.
8710 * - If not the last object, writes the output field separator
8711 * <tt>$OUTPUT_FIELD_SEPARATOR</tt> (<tt>$,</tt> if it is not +nil+.
8712 *
8713 * With default separators:
8714 *
8715 * objects = [0, 0.0, Rational(0, 1), Complex(0, 0), :zero, 'zero']
8716 * $OUTPUT_RECORD_SEPARATOR
8717 * $OUTPUT_FIELD_SEPARATOR
8718 * print(*objects)
8719 *
8720 * Output:
8721 *
8722 * nil
8723 * nil
8724 * 00.00/10+0izerozero
8725 *
8726 * With specified separators:
8727 *
8728 * $OUTPUT_RECORD_SEPARATOR = "\n"
8729 * $OUTPUT_FIELD_SEPARATOR = ','
8730 * print(*objects)
8731 *
8732 * Output:
8733 *
8734 * 0,0.0,0/1,0+0i,zero,zero
8735 *
8736 * With no argument given, writes the content of <tt>$_</tt>
8737 * (which is usually the most recent user input):
8738 *
8739 * gets # Sets $_ to the most recent user input.
8740 * print # Prints $_.
8741 *
8742 */
8743
8744static VALUE
8745rb_f_print(int argc, const VALUE *argv, VALUE _)
8746{
8747 rb_io_print(argc, argv, rb_ractor_stdout());
8748 return Qnil;
8749}
8750
8751/*
8752 * call-seq:
8753 * putc(object) -> object
8754 *
8755 * Writes a character to the stream.
8756 * See {Character IO}[rdoc-ref:IO@Character+IO].
8757 *
8758 * If +object+ is numeric, converts to integer if necessary,
8759 * then writes the character whose code is the
8760 * least significant byte;
8761 * if +object+ is a string, writes the first character:
8762 *
8763 * $stdout.putc "A"
8764 * $stdout.putc 65
8765 *
8766 * Output:
8767 *
8768 * AA
8769 *
8770 */
8771
8772static VALUE
8773rb_io_putc(VALUE io, VALUE ch)
8774{
8775 VALUE str;
8776 if (RB_TYPE_P(ch, T_STRING)) {
8777 str = rb_str_substr(ch, 0, 1);
8778 }
8779 else {
8780 char c = NUM2CHR(ch);
8781 str = rb_str_new(&c, 1);
8782 }
8783 rb_io_write(io, str);
8784 return ch;
8785}
8786
8787#define forward(obj, id, argc, argv) \
8788 rb_funcallv_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8789#define forward_public(obj, id, argc, argv) \
8790 rb_funcallv_public_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8791#define forward_current(id, argc, argv) \
8792 forward_public(ARGF.current_file, id, argc, argv)
8793
8794/*
8795 * call-seq:
8796 * putc(int) -> int
8797 *
8798 * Equivalent to:
8799 *
8800 * $stdout.putc(int)
8801 *
8802 * See IO#putc for important information regarding multi-byte characters.
8803 *
8804 */
8805
8806static VALUE
8807rb_f_putc(VALUE recv, VALUE ch)
8808{
8809 VALUE r_stdout = rb_ractor_stdout();
8810 if (recv == r_stdout) {
8811 return rb_io_putc(recv, ch);
8812 }
8813 return forward(r_stdout, rb_intern("putc"), 1, &ch);
8814}
8815
8816
8817int
8818rb_str_end_with_asciichar(VALUE str, int c)
8819{
8820 long len = RSTRING_LEN(str);
8821 const char *ptr = RSTRING_PTR(str);
8822 rb_encoding *enc = rb_enc_from_index(ENCODING_GET(str));
8823 int n;
8824
8825 if (len == 0) return 0;
8826 if ((n = rb_enc_mbminlen(enc)) == 1) {
8827 return ptr[len - 1] == c;
8828 }
8829 return rb_enc_ascget(ptr + ((len - 1) / n) * n, ptr + len, &n, enc) == c;
8830}
8831
8832static VALUE
8833io_puts_ary(VALUE ary, VALUE out, int recur)
8834{
8835 VALUE tmp;
8836 long i;
8837
8838 if (recur) {
8839 tmp = rb_str_new2("[...]");
8840 rb_io_puts(1, &tmp, out);
8841 return Qtrue;
8842 }
8843 ary = rb_check_array_type(ary);
8844 if (NIL_P(ary)) return Qfalse;
8845 for (i=0; i<RARRAY_LEN(ary); i++) {
8846 tmp = RARRAY_AREF(ary, i);
8847 rb_io_puts(1, &tmp, out);
8848 }
8849 return Qtrue;
8850}
8851
8852/*
8853 * call-seq:
8854 * puts(*objects) -> nil
8855 *
8856 * Writes the given +objects+ to the stream, which must be open for writing;
8857 * returns +nil+.\
8858 * Writes a newline after each that does not already end with a newline sequence.
8859 * If called without arguments, writes a newline.
8860 * See {Line IO}[rdoc-ref:IO@Line+IO].
8861 *
8862 * Note that each added newline is the character <tt>"\n"<//tt>,
8863 * not the output record separator (<tt>$\</tt>).
8864 *
8865 * Treatment for each object:
8866 *
8867 * - String: writes the string.
8868 * - Neither string nor array: writes <tt>object.to_s</tt>.
8869 * - Array: writes each element of the array; arrays may be nested.
8870 *
8871 * To keep these examples brief, we define this helper method:
8872 *
8873 * def show(*objects)
8874 * # Puts objects to file.
8875 * f = File.new('t.tmp', 'w+')
8876 * f.puts(objects)
8877 * # Return file content.
8878 * f.rewind
8879 * p f.read
8880 * f.close
8881 * end
8882 *
8883 * # Strings without newlines.
8884 * show('foo', 'bar', 'baz') # => "foo\nbar\nbaz\n"
8885 * # Strings, some with newlines.
8886 * show("foo\n", 'bar', "baz\n") # => "foo\nbar\nbaz\n"
8887 *
8888 * # Neither strings nor arrays:
8889 * show(0, 0.0, Rational(0, 1), Complex(9, 0), :zero)
8890 * # => "0\n0.0\n0/1\n9+0i\nzero\n"
8891 *
8892 * # Array of strings.
8893 * show(['foo', "bar\n", 'baz']) # => "foo\nbar\nbaz\n"
8894 * # Nested arrays.
8895 * show([[[0, 1], 2, 3], 4, 5]) # => "0\n1\n2\n3\n4\n5\n"
8896 *
8897 */
8898
8899VALUE
8900rb_io_puts(int argc, const VALUE *argv, VALUE out)
8901{
8902 VALUE line, args[2];
8903
8904 /* if no argument given, print newline. */
8905 if (argc == 0) {
8906 rb_io_write(out, rb_default_rs);
8907 return Qnil;
8908 }
8909 for (int i = 0; i < argc; i++) {
8910 // Convert the argument to a string:
8911 if (RB_TYPE_P(argv[i], T_STRING)) {
8912 line = argv[i];
8913 }
8914 else if (rb_exec_recursive(io_puts_ary, argv[i], out)) {
8915 continue;
8916 }
8917 else {
8918 line = rb_obj_as_string(argv[i]);
8919 }
8920
8921 // Write the line:
8922 int n = 0;
8923 if (RSTRING_LEN(line) == 0) {
8924 args[n++] = rb_default_rs;
8925 }
8926 else {
8927 args[n++] = line;
8928 if (!rb_str_end_with_asciichar(line, '\n')) {
8929 args[n++] = rb_default_rs;
8930 }
8931 }
8932
8933 rb_io_writev(out, n, args);
8934 }
8935
8936 return Qnil;
8937}
8938
8939/*
8940 * call-seq:
8941 * puts(*objects) -> nil
8942 *
8943 * Equivalent to
8944 *
8945 * $stdout.puts(objects)
8946 */
8947
8948static VALUE
8949rb_f_puts(int argc, VALUE *argv, VALUE recv)
8950{
8951 VALUE r_stdout = rb_ractor_stdout();
8952 if (recv == r_stdout) {
8953 return rb_io_puts(argc, argv, recv);
8954 }
8955 return forward(r_stdout, rb_intern("puts"), argc, argv);
8956}
8957
8958static VALUE
8959rb_p_write(VALUE str)
8960{
8961 VALUE args[2];
8962 args[0] = str;
8963 args[1] = rb_default_rs;
8964 VALUE r_stdout = rb_ractor_stdout();
8965 if (RB_TYPE_P(r_stdout, T_FILE) &&
8966 rb_method_basic_definition_p(CLASS_OF(r_stdout), id_write)) {
8967 io_writev(2, args, r_stdout);
8968 }
8969 else {
8970 rb_io_writev(r_stdout, 2, args);
8971 }
8972 return Qnil;
8973}
8974
8975void
8976rb_p(VALUE obj) /* for debug print within C code */
8977{
8978 rb_p_write(rb_obj_as_string(rb_inspect(obj)));
8979}
8980
8981static VALUE
8982rb_p_result(int argc, const VALUE *argv)
8983{
8984 VALUE ret = Qnil;
8985
8986 if (argc == 1) {
8987 ret = argv[0];
8988 }
8989 else if (argc > 1) {
8990 ret = rb_ary_new4(argc, argv);
8991 }
8992 VALUE r_stdout = rb_ractor_stdout();
8993 if (RB_TYPE_P(r_stdout, T_FILE)) {
8994 rb_uninterruptible(rb_io_flush, r_stdout);
8995 }
8996 return ret;
8997}
8998
8999/*
9000 * call-seq:
9001 * p(object) -> obj
9002 * p(*objects) -> array of objects
9003 * p -> nil
9004 *
9005 * For each object +obj+, executes:
9006 *
9007 * $stdout.write(obj.inspect, "\n")
9008 *
9009 * With one object given, returns the object;
9010 * with multiple objects given, returns an array containing the objects;
9011 * with no object given, returns +nil+.
9012 *
9013 * Examples:
9014 *
9015 * r = Range.new(0, 4)
9016 * p r # => 0..4
9017 * p [r, r, r] # => [0..4, 0..4, 0..4]
9018 * p # => nil
9019 *
9020 * Output:
9021 *
9022 * 0..4
9023 * [0..4, 0..4, 0..4]
9024 *
9025 * Kernel#p is designed for debugging purposes.
9026 * Ruby implementations may define Kernel#p to be uninterruptible
9027 * in whole or in part.
9028 * On CRuby, Kernel#p's writing of data is uninterruptible.
9029 */
9030
9031static VALUE
9032rb_f_p(int argc, VALUE *argv, VALUE self)
9033{
9034 int i;
9035 for (i=0; i<argc; i++) {
9036 VALUE inspected = rb_obj_as_string(rb_inspect(argv[i]));
9037 rb_uninterruptible(rb_p_write, inspected);
9038 }
9039 return rb_p_result(argc, argv);
9040}
9041
9042/*
9043 * call-seq:
9044 * display(port = $>) -> nil
9045 *
9046 * Writes +self+ on the given port:
9047 *
9048 * 1.display
9049 * "cat".display
9050 * [ 4, 5, 6 ].display
9051 * puts
9052 *
9053 * Output:
9054 *
9055 * 1cat[4, 5, 6]
9056 *
9057 */
9058
9059static VALUE
9060rb_obj_display(int argc, VALUE *argv, VALUE self)
9061{
9062 VALUE out;
9063
9064 out = (!rb_check_arity(argc, 0, 1) ? rb_ractor_stdout() : argv[0]);
9065 rb_io_write(out, self);
9066
9067 return Qnil;
9068}
9069
9070static int
9071rb_stderr_to_original_p(VALUE err)
9072{
9073 return (err == orig_stderr || RFILE(orig_stderr)->fptr->fd < 0);
9074}
9075
9076void
9077rb_write_error2(const char *mesg, long len)
9078{
9079 VALUE out = rb_ractor_stderr();
9080 if (rb_stderr_to_original_p(out)) {
9081#ifdef _WIN32
9082 if (isatty(fileno(stderr))) {
9083 if (rb_w32_write_console(rb_str_new(mesg, len), fileno(stderr)) > 0) return;
9084 }
9085#endif
9086 if (fwrite(mesg, sizeof(char), (size_t)len, stderr) < (size_t)len) {
9087 /* failed to write to stderr, what can we do? */
9088 return;
9089 }
9090 }
9091 else {
9092 rb_io_write(out, rb_str_new(mesg, len));
9093 }
9094}
9095
9096void
9097rb_write_error(const char *mesg)
9098{
9099 rb_write_error2(mesg, strlen(mesg));
9100}
9101
9102void
9103rb_write_error_str(VALUE mesg)
9104{
9105 VALUE out = rb_ractor_stderr();
9106 /* a stopgap measure for the time being */
9107 if (rb_stderr_to_original_p(out)) {
9108 size_t len = (size_t)RSTRING_LEN(mesg);
9109#ifdef _WIN32
9110 if (isatty(fileno(stderr))) {
9111 if (rb_w32_write_console(mesg, fileno(stderr)) > 0) return;
9112 }
9113#endif
9114 if (fwrite(RSTRING_PTR(mesg), sizeof(char), len, stderr) < len) {
9115 RB_GC_GUARD(mesg);
9116 return;
9117 }
9118 }
9119 else {
9120 /* may unlock GVL, and */
9121 rb_io_write(out, mesg);
9122 }
9123}
9124
9125int
9126rb_stderr_tty_p(void)
9127{
9128 if (rb_stderr_to_original_p(rb_ractor_stderr()))
9129 return isatty(fileno(stderr));
9130 return 0;
9131}
9132
9133static void
9134must_respond_to(ID mid, VALUE val, ID id)
9135{
9136 if (!rb_respond_to(val, mid)) {
9137 rb_raise(rb_eTypeError, "%"PRIsVALUE" must have %"PRIsVALUE" method, %"PRIsVALUE" given",
9138 rb_id2str(id), rb_id2str(mid),
9139 rb_obj_class(val));
9140 }
9141}
9142
9143static void
9144stdin_setter(VALUE val, ID id, VALUE *ptr)
9145{
9147}
9148
9149static VALUE
9150stdin_getter(ID id, VALUE *ptr)
9151{
9152 return rb_ractor_stdin();
9153}
9154
9155static void
9156stdout_setter(VALUE val, ID id, VALUE *ptr)
9157{
9158 must_respond_to(id_write, val, id);
9160}
9161
9162static VALUE
9163stdout_getter(ID id, VALUE *ptr)
9164{
9165 return rb_ractor_stdout();
9166}
9167
9168static void
9169stderr_setter(VALUE val, ID id, VALUE *ptr)
9170{
9171 must_respond_to(id_write, val, id);
9173}
9174
9175static VALUE
9176stderr_getter(ID id, VALUE *ptr)
9177{
9178 return rb_ractor_stderr();
9179}
9180
9181static VALUE
9182allocate_and_open_new_file(VALUE klass)
9183{
9184 VALUE self = io_alloc(klass);
9185 rb_io_make_open_file(self);
9186 return self;
9187}
9188
9189VALUE
9190rb_io_open_descriptor(VALUE klass, int descriptor, int mode, VALUE path, VALUE timeout, struct rb_io_encoding *encoding)
9191{
9192 int state;
9193 VALUE self = rb_protect(allocate_and_open_new_file, klass, &state);
9194 if (state) {
9195 /* if we raised an exception allocating an IO object, but the caller
9196 intended to transfer ownership of this FD to us, close the fd before
9197 raising the exception. Otherwise, we would leak a FD - the caller
9198 expects GC to close the file, but we never got around to assigning
9199 it to a rb_io. */
9200 if (!(mode & FMODE_EXTERNAL)) {
9201 maygvl_close(descriptor, 0);
9202 }
9203 rb_jump_tag(state);
9204 }
9205
9206
9207 rb_io_t *io = RFILE(self)->fptr;
9208 io->self = self;
9209 io->fd = descriptor;
9210 io->mode = mode;
9211
9212 /* At this point, Ruby fully owns the descriptor, and will close it when
9213 the IO gets GC'd (unless FMODE_EXTERNAL was set), no matter what happens
9214 in the rest of this method. */
9215
9216 if (NIL_P(path)) {
9217 io->pathv = Qnil;
9218 }
9219 else {
9220 StringValue(path);
9221 io->pathv = rb_str_new_frozen(path);
9222 }
9223
9224 io->timeout = timeout;
9225
9226 if (encoding) {
9227 io->encs = *encoding;
9228 }
9229
9230 rb_update_max_fd(descriptor);
9231
9232 return self;
9233}
9234
9235static VALUE
9236prep_io(int fd, int fmode, VALUE klass, const char *path)
9237{
9238 VALUE path_value = Qnil;
9239 if (path) {
9240 path_value = rb_obj_freeze(rb_str_new_cstr(path));
9241 }
9242
9243 VALUE self = rb_io_open_descriptor(klass, fd, fmode, path_value, Qnil, NULL);
9244 rb_io_t*io = RFILE(self)->fptr;
9245
9246 if (!io_check_tty(io)) {
9247#ifdef __CYGWIN__
9248 io->mode |= FMODE_BINMODE;
9249 setmode(fd, O_BINARY);
9250#endif
9251 }
9252
9253 return self;
9254}
9255
9256VALUE
9257rb_io_fdopen(int fd, int oflags, const char *path)
9258{
9259 VALUE klass = rb_cIO;
9260
9261 if (path && strcmp(path, "-")) klass = rb_cFile;
9262 return prep_io(fd, rb_io_oflags_fmode(oflags), klass, path);
9263}
9264
9265static VALUE
9266prep_stdio(FILE *f, int fmode, VALUE klass, const char *path)
9267{
9268 rb_io_t *fptr;
9269 VALUE io = prep_io(fileno(f), fmode|FMODE_EXTERNAL|DEFAULT_TEXTMODE, klass, path);
9270
9271 GetOpenFile(io, fptr);
9273#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9274 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
9275 if (fmode & FMODE_READABLE) {
9277 }
9278#endif
9279 fptr->stdio_file = f;
9280
9281 return io;
9282}
9283
9284VALUE
9285rb_io_prep_stdin(void)
9286{
9287 return prep_stdio(stdin, FMODE_READABLE, rb_cIO, "<STDIN>");
9288}
9289
9290VALUE
9291rb_io_prep_stdout(void)
9292{
9293 return prep_stdio(stdout, FMODE_WRITABLE|FMODE_SIGNAL_ON_EPIPE, rb_cIO, "<STDOUT>");
9294}
9295
9296VALUE
9297rb_io_prep_stderr(void)
9298{
9299 return prep_stdio(stderr, FMODE_WRITABLE|FMODE_SYNC, rb_cIO, "<STDERR>");
9300}
9301
9302FILE *
9304{
9305 if (!fptr->stdio_file) {
9306 int oflags = rb_io_fmode_oflags(fptr->mode) & ~O_EXCL;
9307 fptr->stdio_file = rb_fdopen(fptr->fd, rb_io_oflags_modestr(oflags));
9308 }
9309 return fptr->stdio_file;
9310}
9311
9312static inline void
9313rb_io_buffer_init(struct rb_io_internal_buffer *buf)
9314{
9315 buf->ptr = NULL;
9316 buf->off = 0;
9317 buf->len = 0;
9318 buf->capa = 0;
9319}
9320
9321static inline rb_io_t *
9322rb_io_fptr_new(void)
9323{
9324 rb_io_t *fp = ALLOC(rb_io_t);
9325 fp->self = Qnil;
9326 fp->fd = -1;
9327 fp->stdio_file = NULL;
9328 fp->mode = 0;
9329 fp->pid = 0;
9330 fp->lineno = 0;
9331 fp->pathv = Qnil;
9332 fp->finalize = 0;
9333 rb_io_buffer_init(&fp->wbuf);
9334 rb_io_buffer_init(&fp->rbuf);
9335 rb_io_buffer_init(&fp->cbuf);
9336 fp->readconv = NULL;
9337 fp->writeconv = NULL;
9339 fp->writeconv_pre_ecflags = 0;
9341 fp->writeconv_initialized = 0;
9342 fp->tied_io_for_writing = 0;
9343 fp->encs.enc = NULL;
9344 fp->encs.enc2 = NULL;
9345 fp->encs.ecflags = 0;
9346 fp->encs.ecopts = Qnil;
9347 fp->write_lock = Qnil;
9348 fp->timeout = Qnil;
9349 return fp;
9350}
9351
9352rb_io_t *
9353rb_io_make_open_file(VALUE obj)
9354{
9355 rb_io_t *fp = 0;
9356
9357 Check_Type(obj, T_FILE);
9358 if (RFILE(obj)->fptr) {
9359 rb_io_close(obj);
9360 rb_io_fptr_finalize(RFILE(obj)->fptr);
9361 RFILE(obj)->fptr = 0;
9362 }
9363 fp = rb_io_fptr_new();
9364 fp->self = obj;
9365 RFILE(obj)->fptr = fp;
9366 return fp;
9367}
9368
9369/*
9370 * call-seq:
9371 * IO.new(fd, mode = 'r', **opts) -> io
9372 *
9373 * Creates and returns a new \IO object (file stream) from a file descriptor.
9374 *
9375 * \IO.new may be useful for interaction with low-level libraries.
9376 * For higher-level interactions, it may be simpler to create
9377 * the file stream using File.open.
9378 *
9379 * Argument +fd+ must be a valid file descriptor (integer):
9380 *
9381 * path = 't.tmp'
9382 * fd = IO.sysopen(path) # => 3
9383 * IO.new(fd) # => #<IO:fd 3>
9384 *
9385 * The new \IO object does not inherit encoding
9386 * (because the integer file descriptor does not have an encoding):
9387 *
9388 * fd = IO.sysopen('t.rus', 'rb')
9389 * io = IO.new(fd)
9390 * io.external_encoding # => #<Encoding:UTF-8> # Not ASCII-8BIT.
9391 *
9392 * Optional argument +mode+ (defaults to 'r') must specify a valid mode;
9393 * see {Access Modes}[rdoc-ref:File@Access+Modes]:
9394 *
9395 * IO.new(fd, 'w') # => #<IO:fd 3>
9396 * IO.new(fd, File::WRONLY) # => #<IO:fd 3>
9397 *
9398 * Optional keyword arguments +opts+ specify:
9399 *
9400 * - {Open Options}[rdoc-ref:IO@Open+Options].
9401 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
9402 *
9403 * Examples:
9404 *
9405 * IO.new(fd, internal_encoding: nil) # => #<IO:fd 3>
9406 * IO.new(fd, autoclose: true) # => #<IO:fd 3>
9407 *
9408 */
9409
9410static VALUE
9411rb_io_initialize(int argc, VALUE *argv, VALUE io)
9412{
9413 VALUE fnum, vmode;
9414 rb_io_t *fp;
9415 int fd, fmode, oflags = O_RDONLY;
9416 struct rb_io_encoding convconfig;
9417 VALUE opt;
9418#if defined(HAVE_FCNTL) && defined(F_GETFL)
9419 int ofmode;
9420#else
9421 struct stat st;
9422#endif
9423
9424
9425 argc = rb_scan_args(argc, argv, "11:", &fnum, &vmode, &opt);
9426 rb_io_extract_modeenc(&vmode, 0, opt, &oflags, &fmode, &convconfig);
9427
9428 fd = NUM2INT(fnum);
9429 if (rb_reserved_fd_p(fd)) {
9430 rb_raise(rb_eArgError, "The given fd is not accessible because RubyVM reserves it");
9431 }
9432#if defined(HAVE_FCNTL) && defined(F_GETFL)
9433 oflags = fcntl(fd, F_GETFL);
9434 if (oflags == -1) rb_sys_fail(0);
9435#else
9436 if (fstat(fd, &st) < 0) rb_sys_fail(0);
9437#endif
9438 rb_update_max_fd(fd);
9439#if defined(HAVE_FCNTL) && defined(F_GETFL)
9440 ofmode = rb_io_oflags_fmode(oflags);
9441 if (NIL_P(vmode)) {
9442 fmode = ofmode;
9443 }
9444 else if ((~ofmode & fmode) & FMODE_READWRITE) {
9445 VALUE error = INT2FIX(EINVAL);
9446 rb_exc_raise(rb_class_new_instance(1, &error, rb_eSystemCallError));
9447 }
9448#endif
9449 VALUE path = Qnil;
9450
9451 if (!NIL_P(opt)) {
9452 if (rb_hash_aref(opt, sym_autoclose) == Qfalse) {
9453 fmode |= FMODE_EXTERNAL;
9454 }
9455
9456 path = rb_hash_aref(opt, RB_ID2SYM(idPath));
9457 if (!NIL_P(path)) {
9458 StringValue(path);
9459 path = rb_str_new_frozen(path);
9460 }
9461 }
9462
9463 MakeOpenFile(io, fp);
9464 fp->self = io;
9465 fp->fd = fd;
9466 fp->mode = fmode;
9467 fp->encs = convconfig;
9468 fp->pathv = path;
9469 fp->timeout = Qnil;
9470 clear_codeconv(fp);
9471 io_check_tty(fp);
9472 if (fileno(stdin) == fd)
9473 fp->stdio_file = stdin;
9474 else if (fileno(stdout) == fd)
9475 fp->stdio_file = stdout;
9476 else if (fileno(stderr) == fd)
9477 fp->stdio_file = stderr;
9478
9479 if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
9480 return io;
9481}
9482
9483/*
9484 * call-seq:
9485 * set_encoding_by_bom -> encoding or nil
9486 *
9487 * If the stream begins with a BOM
9488 * ({byte order marker}[https://en.wikipedia.org/wiki/Byte_order_mark]),
9489 * consumes the BOM and sets the external encoding accordingly;
9490 * returns the result encoding if found, or +nil+ otherwise:
9491 *
9492 * File.write('t.tmp', "\u{FEFF}abc")
9493 * io = File.open('t.tmp', 'rb')
9494 * io.set_encoding_by_bom # => #<Encoding:UTF-8>
9495 * io.close
9496 *
9497 * File.write('t.tmp', 'abc')
9498 * io = File.open('t.tmp', 'rb')
9499 * io.set_encoding_by_bom # => nil
9500 * io.close
9501 *
9502 * Raises an exception if the stream is not binmode
9503 * or its encoding has already been set.
9504 *
9505 */
9506
9507static VALUE
9508rb_io_set_encoding_by_bom(VALUE io)
9509{
9510 rb_io_t *fptr;
9511
9512 GetOpenFile(io, fptr);
9513 if (!(fptr->mode & FMODE_BINMODE)) {
9514 rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
9515 }
9516 if (fptr->encs.enc2) {
9517 rb_raise(rb_eArgError, "encoding conversion is set");
9518 }
9519 else if (fptr->encs.enc && fptr->encs.enc != rb_ascii8bit_encoding()) {
9520 rb_raise(rb_eArgError, "encoding is set to %s already",
9521 rb_enc_name(fptr->encs.enc));
9522 }
9523 if (!io_set_encoding_by_bom(io)) return Qnil;
9524 return rb_enc_from_encoding(fptr->encs.enc);
9525}
9526
9527/*
9528 * call-seq:
9529 * File.new(path, mode = 'r', perm = 0666, **opts) -> file
9530 *
9531 * Opens the file at the given +path+ according to the given +mode+;
9532 * creates and returns a new File object for that file.
9533 *
9534 * The new File object is buffered mode (or non-sync mode), unless
9535 * +filename+ is a tty.
9536 * See IO#flush, IO#fsync, IO#fdatasync, and IO#sync=.
9537 *
9538 * Argument +path+ must be a valid file path:
9539 *
9540 * f = File.new('/etc/fstab')
9541 * f.close
9542 * f = File.new('t.txt')
9543 * f.close
9544 *
9545 * Optional argument +mode+ (defaults to 'r') must specify a valid mode;
9546 * see {Access Modes}[rdoc-ref:File@Access+Modes]:
9547 *
9548 * f = File.new('t.tmp', 'w')
9549 * f.close
9550 * f = File.new('t.tmp', File::RDONLY)
9551 * f.close
9552 *
9553 * Optional argument +perm+ (defaults to 0666) must specify valid permissions
9554 * see {File Permissions}[rdoc-ref:File@File+Permissions]:
9555 *
9556 * f = File.new('t.tmp', File::CREAT, 0644)
9557 * f.close
9558 * f = File.new('t.tmp', File::CREAT, 0444)
9559 * f.close
9560 *
9561 * Optional keyword arguments +opts+ specify:
9562 *
9563 * - {Open Options}[rdoc-ref:IO@Open+Options].
9564 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
9565 *
9566 */
9567
9568static VALUE
9569rb_file_initialize(int argc, VALUE *argv, VALUE io)
9570{
9571 if (RFILE(io)->fptr) {
9572 rb_raise(rb_eRuntimeError, "reinitializing File");
9573 }
9574 if (0 < argc && argc < 3) {
9575 VALUE fd = rb_check_to_int(argv[0]);
9576
9577 if (!NIL_P(fd)) {
9578 argv[0] = fd;
9579 return rb_io_initialize(argc, argv, io);
9580 }
9581 }
9582 rb_open_file(argc, argv, io);
9583
9584 return io;
9585}
9586
9587/* :nodoc: */
9588static VALUE
9589rb_io_s_new(int argc, VALUE *argv, VALUE klass)
9590{
9591 if (rb_block_given_p()) {
9592 VALUE cname = rb_obj_as_string(klass);
9593
9594 rb_warn("%"PRIsVALUE"::new() does not take block; use %"PRIsVALUE"::open() instead",
9595 cname, cname);
9596 }
9597 return rb_class_new_instance_kw(argc, argv, klass, RB_PASS_CALLED_KEYWORDS);
9598}
9599
9600
9601/*
9602 * call-seq:
9603 * IO.for_fd(fd, mode = 'r', **opts) -> io
9604 *
9605 * Synonym for IO.new.
9606 *
9607 */
9608
9609static VALUE
9610rb_io_s_for_fd(int argc, VALUE *argv, VALUE klass)
9611{
9612 VALUE io = rb_obj_alloc(klass);
9613 rb_io_initialize(argc, argv, io);
9614 return io;
9615}
9616
9617/*
9618 * call-seq:
9619 * ios.autoclose? -> true or false
9620 *
9621 * Returns +true+ if the underlying file descriptor of _ios_ will be
9622 * closed at its finalization or at calling #close, otherwise +false+.
9623 */
9624
9625static VALUE
9626rb_io_autoclose_p(VALUE io)
9627{
9628 rb_io_t *fptr = RFILE(io)->fptr;
9629 rb_io_check_closed(fptr);
9630 return RBOOL(!(fptr->mode & FMODE_EXTERNAL));
9631}
9632
9633/*
9634 * call-seq:
9635 * io.autoclose = bool -> true or false
9636 *
9637 * Sets auto-close flag.
9638 *
9639 * f = File.open(File::NULL)
9640 * IO.for_fd(f.fileno).close
9641 * f.gets # raises Errno::EBADF
9642 *
9643 * f = File.open(File::NULL)
9644 * g = IO.for_fd(f.fileno)
9645 * g.autoclose = false
9646 * g.close
9647 * f.gets # won't cause Errno::EBADF
9648 */
9649
9650static VALUE
9651rb_io_set_autoclose(VALUE io, VALUE autoclose)
9652{
9653 rb_io_t *fptr;
9654 GetOpenFile(io, fptr);
9655 if (!RTEST(autoclose))
9656 fptr->mode |= FMODE_EXTERNAL;
9657 else
9658 fptr->mode &= ~FMODE_EXTERNAL;
9659 return autoclose;
9660}
9661
9662static VALUE
9663io_wait_event(VALUE io, int event, VALUE timeout, int return_io)
9664{
9665 VALUE result = rb_io_wait(io, RB_INT2NUM(event), timeout);
9666
9667 if (!RB_TEST(result)) {
9668 return Qnil;
9669 }
9670
9671 int mask = RB_NUM2INT(result);
9672
9673 if (mask & event) {
9674 if (return_io)
9675 return io;
9676 else
9677 return result;
9678 }
9679 else {
9680 return Qfalse;
9681 }
9682}
9683
9684/*
9685 * call-seq:
9686 * io.wait_readable -> truthy or falsy
9687 * io.wait_readable(timeout) -> truthy or falsy
9688 *
9689 * Waits until IO is readable and returns a truthy value, or a falsy
9690 * value when times out. Returns a truthy value immediately when
9691 * buffered data is available.
9692 */
9693
9694static VALUE
9695io_wait_readable(int argc, VALUE *argv, VALUE io)
9696{
9697 rb_io_t *fptr;
9698
9699 RB_IO_POINTER(io, fptr);
9701
9702 if (rb_io_read_pending(fptr)) return Qtrue;
9703
9704 rb_check_arity(argc, 0, 1);
9705 VALUE timeout = (argc == 1 ? argv[0] : Qnil);
9706
9707 return io_wait_event(io, RUBY_IO_READABLE, timeout, 1);
9708}
9709
9710/*
9711 * call-seq:
9712 * io.wait_writable -> truthy or falsy
9713 * io.wait_writable(timeout) -> truthy or falsy
9714 *
9715 * Waits until IO is writable and returns a truthy value or a falsy
9716 * value when times out.
9717 */
9718static VALUE
9719io_wait_writable(int argc, VALUE *argv, VALUE io)
9720{
9721 rb_io_t *fptr;
9722
9723 RB_IO_POINTER(io, fptr);
9725
9726 rb_check_arity(argc, 0, 1);
9727 VALUE timeout = (argc == 1 ? argv[0] : Qnil);
9728
9729 return io_wait_event(io, RUBY_IO_WRITABLE, timeout, 1);
9730}
9731
9732/*
9733 * call-seq:
9734 * io.wait_priority -> truthy or falsy
9735 * io.wait_priority(timeout) -> truthy or falsy
9736 *
9737 * Waits until IO is priority and returns a truthy value or a falsy
9738 * value when times out. Priority data is sent and received using
9739 * the Socket::MSG_OOB flag and is typically limited to streams.
9740 */
9741static VALUE
9742io_wait_priority(int argc, VALUE *argv, VALUE io)
9743{
9744 rb_io_t *fptr = NULL;
9745
9746 RB_IO_POINTER(io, 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_PRIORITY, timeout, 1);
9755}
9756
9757static int
9758wait_mode_sym(VALUE mode)
9759{
9760 if (mode == ID2SYM(rb_intern("r"))) {
9761 return RB_WAITFD_IN;
9762 }
9763 if (mode == ID2SYM(rb_intern("read"))) {
9764 return RB_WAITFD_IN;
9765 }
9766 if (mode == ID2SYM(rb_intern("readable"))) {
9767 return RB_WAITFD_IN;
9768 }
9769 if (mode == ID2SYM(rb_intern("w"))) {
9770 return RB_WAITFD_OUT;
9771 }
9772 if (mode == ID2SYM(rb_intern("write"))) {
9773 return RB_WAITFD_OUT;
9774 }
9775 if (mode == ID2SYM(rb_intern("writable"))) {
9776 return RB_WAITFD_OUT;
9777 }
9778 if (mode == ID2SYM(rb_intern("rw"))) {
9779 return RB_WAITFD_IN|RB_WAITFD_OUT;
9780 }
9781 if (mode == ID2SYM(rb_intern("read_write"))) {
9782 return RB_WAITFD_IN|RB_WAITFD_OUT;
9783 }
9784 if (mode == ID2SYM(rb_intern("readable_writable"))) {
9785 return RB_WAITFD_IN|RB_WAITFD_OUT;
9786 }
9787
9788 rb_raise(rb_eArgError, "unsupported mode: %"PRIsVALUE, mode);
9789}
9790
9791static inline enum rb_io_event
9792io_event_from_value(VALUE value)
9793{
9794 int events = RB_NUM2INT(value);
9795
9796 if (events <= 0) rb_raise(rb_eArgError, "Events must be positive integer!");
9797
9798 return events;
9799}
9800
9801/*
9802 * call-seq:
9803 * io.wait(events, timeout) -> event mask, false or nil
9804 * io.wait(timeout = nil, mode = :read) -> self, true, or false
9805 *
9806 * Waits until the IO becomes ready for the specified events and returns the
9807 * subset of events that become ready, or a falsy value when times out.
9808 *
9809 * The events can be a bit mask of +IO::READABLE+, +IO::WRITABLE+ or
9810 * +IO::PRIORITY+.
9811 *
9812 * Returns an event mask (truthy value) immediately when buffered data is available.
9813 *
9814 * Optional parameter +mode+ is one of +:read+, +:write+, or
9815 * +:read_write+.
9816 */
9817
9818static VALUE
9819io_wait(int argc, VALUE *argv, VALUE io)
9820{
9821 VALUE timeout = Qundef;
9822 enum rb_io_event events = 0;
9823 int return_io = 0;
9824
9825 // The documented signature for this method is actually incorrect.
9826 // A single timeout is allowed in any position, and multiple symbols can be given.
9827 // Whether this is intentional or not, I don't know, and as such I consider this to
9828 // be a legacy/slow path.
9829 if (argc != 2 || (RB_SYMBOL_P(argv[0]) || RB_SYMBOL_P(argv[1]))) {
9830 // We'd prefer to return the actual mask, but this form would return the io itself:
9831 return_io = 1;
9832
9833 // Slow/messy path:
9834 for (int i = 0; i < argc; i += 1) {
9835 if (RB_SYMBOL_P(argv[i])) {
9836 events |= wait_mode_sym(argv[i]);
9837 }
9838 else if (UNDEF_P(timeout)) {
9839 rb_time_interval(timeout = argv[i]);
9840 }
9841 else {
9842 rb_raise(rb_eArgError, "timeout given more than once");
9843 }
9844 }
9845
9846 if (UNDEF_P(timeout)) timeout = Qnil;
9847
9848 if (events == 0) {
9849 events = RUBY_IO_READABLE;
9850 }
9851 }
9852 else /* argc == 2 and neither are symbols */ {
9853 // This is the fast path:
9854 events = io_event_from_value(argv[0]);
9855 timeout = argv[1];
9856 }
9857
9858 if (events & RUBY_IO_READABLE) {
9859 rb_io_t *fptr = NULL;
9860 RB_IO_POINTER(io, fptr);
9861
9862 if (rb_io_read_pending(fptr)) {
9863 // This was the original behaviour:
9864 if (return_io) return Qtrue;
9865 // New behaviour always returns an event mask:
9866 else return RB_INT2NUM(RUBY_IO_READABLE);
9867 }
9868 }
9869
9870 return io_wait_event(io, events, timeout, return_io);
9871}
9872
9873static void
9874argf_mark(void *ptr)
9875{
9876 struct argf *p = ptr;
9877 rb_gc_mark(p->filename);
9878 rb_gc_mark(p->current_file);
9879 rb_gc_mark(p->argv);
9880 rb_gc_mark(p->inplace);
9881 rb_gc_mark(p->encs.ecopts);
9882}
9883
9884static size_t
9885argf_memsize(const void *ptr)
9886{
9887 const struct argf *p = ptr;
9888 size_t size = sizeof(*p);
9889 return size;
9890}
9891
9892static const rb_data_type_t argf_type = {
9893 "ARGF",
9894 {argf_mark, RUBY_TYPED_DEFAULT_FREE, argf_memsize},
9895 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
9896};
9897
9898static inline void
9899argf_init(struct argf *p, VALUE v)
9900{
9901 p->filename = Qnil;
9902 p->current_file = Qnil;
9903 p->lineno = 0;
9904 p->argv = v;
9905}
9906
9907static VALUE
9908argf_alloc(VALUE klass)
9909{
9910 struct argf *p;
9911 VALUE argf = TypedData_Make_Struct(klass, struct argf, &argf_type, p);
9912
9913 argf_init(p, Qnil);
9914 return argf;
9915}
9916
9917#undef rb_argv
9918
9919/* :nodoc: */
9920static VALUE
9921argf_initialize(VALUE argf, VALUE argv)
9922{
9923 memset(&ARGF, 0, sizeof(ARGF));
9924 argf_init(&ARGF, argv);
9925
9926 return argf;
9927}
9928
9929/* :nodoc: */
9930static VALUE
9931argf_initialize_copy(VALUE argf, VALUE orig)
9932{
9933 if (!OBJ_INIT_COPY(argf, orig)) return argf;
9934 ARGF = argf_of(orig);
9935 ARGF.argv = rb_obj_dup(ARGF.argv);
9936 return argf;
9937}
9938
9939/*
9940 * call-seq:
9941 * ARGF.lineno = integer -> integer
9942 *
9943 * Sets the line number of ARGF as a whole to the given Integer.
9944 *
9945 * ARGF sets the line number automatically as you read data, so normally
9946 * you will not need to set it explicitly. To access the current line number
9947 * use ARGF.lineno.
9948 *
9949 * For example:
9950 *
9951 * ARGF.lineno #=> 0
9952 * ARGF.readline #=> "This is line 1\n"
9953 * ARGF.lineno #=> 1
9954 * ARGF.lineno = 0 #=> 0
9955 * ARGF.lineno #=> 0
9956 */
9957static VALUE
9958argf_set_lineno(VALUE argf, VALUE val)
9959{
9960 ARGF.lineno = NUM2INT(val);
9961 ARGF.last_lineno = ARGF.lineno;
9962 return val;
9963}
9964
9965/*
9966 * call-seq:
9967 * ARGF.lineno -> integer
9968 *
9969 * Returns the current line number of ARGF as a whole. This value
9970 * can be set manually with ARGF.lineno=.
9971 *
9972 * For example:
9973 *
9974 * ARGF.lineno #=> 0
9975 * ARGF.readline #=> "This is line 1\n"
9976 * ARGF.lineno #=> 1
9977 */
9978static VALUE
9979argf_lineno(VALUE argf)
9980{
9981 return INT2FIX(ARGF.lineno);
9982}
9983
9984static VALUE
9985argf_forward(int argc, VALUE *argv, VALUE argf)
9986{
9987 return forward_current(rb_frame_this_func(), argc, argv);
9988}
9989
9990#define next_argv() argf_next_argv(argf)
9991#define ARGF_GENERIC_INPUT_P() \
9992 (ARGF.current_file == rb_stdin && !RB_TYPE_P(ARGF.current_file, T_FILE))
9993#define ARGF_FORWARD(argc, argv) do {\
9994 if (ARGF_GENERIC_INPUT_P())\
9995 return argf_forward((argc), (argv), argf);\
9996} while (0)
9997#define NEXT_ARGF_FORWARD(argc, argv) do {\
9998 if (!next_argv()) return Qnil;\
9999 ARGF_FORWARD((argc), (argv));\
10000} while (0)
10001
10002static void
10003argf_close(VALUE argf)
10004{
10005 VALUE file = ARGF.current_file;
10006 if (file == rb_stdin) return;
10007 if (RB_TYPE_P(file, T_FILE)) {
10008 rb_io_set_write_io(file, Qnil);
10009 }
10010 io_close(file);
10011 ARGF.init_p = -1;
10012}
10013
10014static int
10015argf_next_argv(VALUE argf)
10016{
10017 char *fn;
10018 rb_io_t *fptr;
10019 int stdout_binmode = 0;
10020 int fmode;
10021
10022 VALUE r_stdout = rb_ractor_stdout();
10023
10024 if (RB_TYPE_P(r_stdout, T_FILE)) {
10025 GetOpenFile(r_stdout, fptr);
10026 if (fptr->mode & FMODE_BINMODE)
10027 stdout_binmode = 1;
10028 }
10029
10030 if (ARGF.init_p == 0) {
10031 if (!NIL_P(ARGF.argv) && RARRAY_LEN(ARGF.argv) > 0) {
10032 ARGF.next_p = 1;
10033 }
10034 else {
10035 ARGF.next_p = -1;
10036 }
10037 ARGF.init_p = 1;
10038 }
10039 else {
10040 if (NIL_P(ARGF.argv)) {
10041 ARGF.next_p = -1;
10042 }
10043 else if (ARGF.next_p == -1 && RARRAY_LEN(ARGF.argv) > 0) {
10044 ARGF.next_p = 1;
10045 }
10046 }
10047
10048 if (ARGF.next_p == 1) {
10049 if (ARGF.init_p == 1) argf_close(argf);
10050 retry:
10051 if (RARRAY_LEN(ARGF.argv) > 0) {
10052 VALUE filename = rb_ary_shift(ARGF.argv);
10053 FilePathValue(filename);
10054 ARGF.filename = filename;
10055 filename = rb_str_encode_ospath(filename);
10056 fn = StringValueCStr(filename);
10057 if (RSTRING_LEN(filename) == 1 && fn[0] == '-') {
10058 ARGF.current_file = rb_stdin;
10059 if (ARGF.inplace) {
10060 rb_warn("Can't do inplace edit for stdio; skipping");
10061 goto retry;
10062 }
10063 }
10064 else {
10065 VALUE write_io = Qnil;
10066 int fr = rb_sysopen(filename, O_RDONLY, 0);
10067
10068 if (ARGF.inplace) {
10069 struct stat st;
10070#ifndef NO_SAFE_RENAME
10071 struct stat st2;
10072#endif
10073 VALUE str;
10074 int fw;
10075
10076 if (RB_TYPE_P(r_stdout, T_FILE) && r_stdout != orig_stdout) {
10077 rb_io_close(r_stdout);
10078 }
10079 fstat(fr, &st);
10080 str = filename;
10081 if (!NIL_P(ARGF.inplace)) {
10082 VALUE suffix = ARGF.inplace;
10083 str = rb_str_dup(str);
10084 if (NIL_P(rb_str_cat_conv_enc_opts(str, RSTRING_LEN(str),
10085 RSTRING_PTR(suffix), RSTRING_LEN(suffix),
10086 rb_enc_get(suffix), 0, Qnil))) {
10087 rb_str_append(str, suffix);
10088 }
10089#ifdef NO_SAFE_RENAME
10090 (void)close(fr);
10091 (void)unlink(RSTRING_PTR(str));
10092 if (rename(fn, RSTRING_PTR(str)) < 0) {
10093 rb_warn("Can't rename %"PRIsVALUE" to %"PRIsVALUE": %s, skipping file",
10094 filename, str, strerror(errno));
10095 goto retry;
10096 }
10097 fr = rb_sysopen(str, O_RDONLY, 0);
10098#else
10099 if (rename(fn, RSTRING_PTR(str)) < 0) {
10100 rb_warn("Can't rename %"PRIsVALUE" to %"PRIsVALUE": %s, skipping file",
10101 filename, str, strerror(errno));
10102 close(fr);
10103 goto retry;
10104 }
10105#endif
10106 }
10107 else {
10108#ifdef NO_SAFE_RENAME
10109 rb_fatal("Can't do inplace edit without backup");
10110#else
10111 if (unlink(fn) < 0) {
10112 rb_warn("Can't remove %"PRIsVALUE": %s, skipping file",
10113 filename, strerror(errno));
10114 close(fr);
10115 goto retry;
10116 }
10117#endif
10118 }
10119 fw = rb_sysopen(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666);
10120#ifndef NO_SAFE_RENAME
10121 fstat(fw, &st2);
10122#ifdef HAVE_FCHMOD
10123 fchmod(fw, st.st_mode);
10124#else
10125 chmod(fn, st.st_mode);
10126#endif
10127 if (st.st_uid!=st2.st_uid || st.st_gid!=st2.st_gid) {
10128 int err;
10129#ifdef HAVE_FCHOWN
10130 err = fchown(fw, st.st_uid, st.st_gid);
10131#else
10132 err = chown(fn, st.st_uid, st.st_gid);
10133#endif
10134 if (err && getuid() == 0 && st2.st_uid == 0) {
10135 const char *wkfn = RSTRING_PTR(filename);
10136 rb_warn("Can't set owner/group of %"PRIsVALUE" to same as %"PRIsVALUE": %s, skipping file",
10137 filename, str, strerror(errno));
10138 (void)close(fr);
10139 (void)close(fw);
10140 (void)unlink(wkfn);
10141 goto retry;
10142 }
10143 }
10144#endif
10145 write_io = prep_io(fw, FMODE_WRITABLE, rb_cFile, fn);
10146 rb_ractor_stdout_set(write_io);
10147 if (stdout_binmode) rb_io_binmode(rb_stdout);
10148 }
10149 fmode = FMODE_READABLE;
10150 if (!ARGF.binmode) {
10151 fmode |= DEFAULT_TEXTMODE;
10152 }
10153 ARGF.current_file = prep_io(fr, fmode, rb_cFile, fn);
10154 if (!NIL_P(write_io)) {
10155 rb_io_set_write_io(ARGF.current_file, write_io);
10156 }
10157 RB_GC_GUARD(filename);
10158 }
10159 if (ARGF.binmode) rb_io_ascii8bit_binmode(ARGF.current_file);
10160 GetOpenFile(ARGF.current_file, fptr);
10161 if (ARGF.encs.enc) {
10162 fptr->encs = ARGF.encs;
10163 clear_codeconv(fptr);
10164 }
10165 else {
10166 fptr->encs.ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
10167 if (!ARGF.binmode) {
10169#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
10170 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
10171#endif
10172 }
10173 }
10174 ARGF.next_p = 0;
10175 }
10176 else {
10177 ARGF.next_p = 1;
10178 return FALSE;
10179 }
10180 }
10181 else if (ARGF.next_p == -1) {
10182 ARGF.current_file = rb_stdin;
10183 ARGF.filename = rb_str_new2("-");
10184 if (ARGF.inplace) {
10185 rb_warn("Can't do inplace edit for stdio");
10186 rb_ractor_stdout_set(orig_stdout);
10187 }
10188 }
10189 if (ARGF.init_p == -1) ARGF.init_p = 1;
10190 return TRUE;
10191}
10192
10193static VALUE
10194argf_getline(int argc, VALUE *argv, VALUE argf)
10195{
10196 VALUE line;
10197 long lineno = ARGF.lineno;
10198
10199 retry:
10200 if (!next_argv()) return Qnil;
10201 if (ARGF_GENERIC_INPUT_P()) {
10202 line = forward_current(idGets, argc, argv);
10203 }
10204 else {
10205 if (argc == 0 && rb_rs == rb_default_rs) {
10206 line = rb_io_gets(ARGF.current_file);
10207 }
10208 else {
10209 line = rb_io_getline(argc, argv, ARGF.current_file);
10210 }
10211 if (NIL_P(line) && ARGF.next_p != -1) {
10212 argf_close(argf);
10213 ARGF.next_p = 1;
10214 goto retry;
10215 }
10216 }
10217 if (!NIL_P(line)) {
10218 ARGF.lineno = ++lineno;
10219 ARGF.last_lineno = ARGF.lineno;
10220 }
10221 return line;
10222}
10223
10224static VALUE
10225argf_lineno_getter(ID id, VALUE *var)
10226{
10227 VALUE argf = *var;
10228 return INT2FIX(ARGF.last_lineno);
10229}
10230
10231static void
10232argf_lineno_setter(VALUE val, ID id, VALUE *var)
10233{
10234 VALUE argf = *var;
10235 int n = NUM2INT(val);
10236 ARGF.last_lineno = ARGF.lineno = n;
10237}
10238
10239void
10240rb_reset_argf_lineno(long n)
10241{
10242 ARGF.last_lineno = ARGF.lineno = n;
10243}
10244
10245static VALUE argf_gets(int, VALUE *, VALUE);
10246
10247/*
10248 * call-seq:
10249 * gets(sep=$/ [, getline_args]) -> string or nil
10250 * gets(limit [, getline_args]) -> string or nil
10251 * gets(sep, limit [, getline_args]) -> string or nil
10252 *
10253 * Returns (and assigns to <code>$_</code>) the next line from the list
10254 * of files in +ARGV+ (or <code>$*</code>), or from standard input if
10255 * no files are present on the command line. Returns +nil+ at end of
10256 * file. The optional argument specifies the record separator. The
10257 * separator is included with the contents of each record. A separator
10258 * of +nil+ reads the entire contents, and a zero-length separator
10259 * reads the input one paragraph at a time, where paragraphs are
10260 * divided by two consecutive newlines. If the first argument is an
10261 * integer, or optional second argument is given, the returning string
10262 * would not be longer than the given value in bytes. If multiple
10263 * filenames are present in +ARGV+, <code>gets(nil)</code> will read
10264 * the contents one file at a time.
10265 *
10266 * ARGV << "testfile"
10267 * print while gets
10268 *
10269 * <em>produces:</em>
10270 *
10271 * This is line one
10272 * This is line two
10273 * This is line three
10274 * And so on...
10275 *
10276 * The style of programming using <code>$_</code> as an implicit
10277 * parameter is gradually losing favor in the Ruby community.
10278 */
10279
10280static VALUE
10281rb_f_gets(int argc, VALUE *argv, VALUE recv)
10282{
10283 if (recv == argf) {
10284 return argf_gets(argc, argv, argf);
10285 }
10286 return forward(argf, idGets, argc, argv);
10287}
10288
10289/*
10290 * call-seq:
10291 * ARGF.gets(sep=$/ [, getline_args]) -> string or nil
10292 * ARGF.gets(limit [, getline_args]) -> string or nil
10293 * ARGF.gets(sep, limit [, getline_args]) -> string or nil
10294 *
10295 * Returns the next line from the current file in ARGF.
10296 *
10297 * By default lines are assumed to be separated by <code>$/</code>;
10298 * to use a different character as a separator, supply it as a String
10299 * for the _sep_ argument.
10300 *
10301 * The optional _limit_ argument specifies how many characters of each line
10302 * to return. By default all characters are returned.
10303 *
10304 * See IO.readlines for details about getline_args.
10305 *
10306 */
10307static VALUE
10308argf_gets(int argc, VALUE *argv, VALUE argf)
10309{
10310 VALUE line;
10311
10312 line = argf_getline(argc, argv, argf);
10313 rb_lastline_set(line);
10314
10315 return line;
10316}
10317
10318VALUE
10320{
10321 VALUE line;
10322
10323 if (rb_rs != rb_default_rs) {
10324 return rb_f_gets(0, 0, argf);
10325 }
10326
10327 retry:
10328 if (!next_argv()) return Qnil;
10329 line = rb_io_gets(ARGF.current_file);
10330 if (NIL_P(line) && ARGF.next_p != -1) {
10331 rb_io_close(ARGF.current_file);
10332 ARGF.next_p = 1;
10333 goto retry;
10334 }
10335 rb_lastline_set(line);
10336 if (!NIL_P(line)) {
10337 ARGF.lineno++;
10338 ARGF.last_lineno = ARGF.lineno;
10339 }
10340
10341 return line;
10342}
10343
10344static VALUE argf_readline(int, VALUE *, VALUE);
10345
10346/*
10347 * call-seq:
10348 * readline(sep = $/, chomp: false) -> string
10349 * readline(limit, chomp: false) -> string
10350 * readline(sep, limit, chomp: false) -> string
10351 *
10352 * Equivalent to method Kernel#gets, except that it raises an exception
10353 * if called at end-of-stream:
10354 *
10355 * $ cat t.txt | ruby -e "p readlines; readline"
10356 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10357 * in `readline': end of file reached (EOFError)
10358 *
10359 * Optional keyword argument +chomp+ specifies whether line separators
10360 * are to be omitted.
10361 */
10362
10363static VALUE
10364rb_f_readline(int argc, VALUE *argv, VALUE recv)
10365{
10366 if (recv == argf) {
10367 return argf_readline(argc, argv, argf);
10368 }
10369 return forward(argf, rb_intern("readline"), argc, argv);
10370}
10371
10372
10373/*
10374 * call-seq:
10375 * ARGF.readline(sep=$/) -> string
10376 * ARGF.readline(limit) -> string
10377 * ARGF.readline(sep, limit) -> string
10378 *
10379 * Returns the next line from the current file in ARGF.
10380 *
10381 * By default lines are assumed to be separated by <code>$/</code>;
10382 * to use a different character as a separator, supply it as a String
10383 * for the _sep_ argument.
10384 *
10385 * The optional _limit_ argument specifies how many characters of each line
10386 * to return. By default all characters are returned.
10387 *
10388 * An EOFError is raised at the end of the file.
10389 */
10390static VALUE
10391argf_readline(int argc, VALUE *argv, VALUE argf)
10392{
10393 VALUE line;
10394
10395 if (!next_argv()) rb_eof_error();
10396 ARGF_FORWARD(argc, argv);
10397 line = argf_gets(argc, argv, argf);
10398 if (NIL_P(line)) {
10399 rb_eof_error();
10400 }
10401
10402 return line;
10403}
10404
10405static VALUE argf_readlines(int, VALUE *, VALUE);
10406
10407/*
10408 * call-seq:
10409 * readlines(sep = $/, chomp: false, **enc_opts) -> array
10410 * readlines(limit, chomp: false, **enc_opts) -> array
10411 * readlines(sep, limit, chomp: false, **enc_opts) -> array
10412 *
10413 * Returns an array containing the lines returned by calling
10414 * Kernel#gets until the end-of-stream is reached;
10415 * (see {Line IO}[rdoc-ref:IO@Line+IO]).
10416 *
10417 * With only string argument +sep+ given,
10418 * returns the remaining lines as determined by line separator +sep+,
10419 * or +nil+ if none;
10420 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
10421 *
10422 * # Default separator.
10423 * $ cat t.txt | ruby -e "p readlines"
10424 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10425 *
10426 * # Specified separator.
10427 * $ cat t.txt | ruby -e "p readlines 'li'"
10428 * ["First li", "ne\nSecond li", "ne\n\nFourth li", "ne\nFifth li", "ne\n"]
10429 *
10430 * # Get-all separator.
10431 * $ cat t.txt | ruby -e "p readlines nil"
10432 * ["First line\nSecond line\n\nFourth line\nFifth line\n"]
10433 *
10434 * # Get-paragraph separator.
10435 * $ cat t.txt | ruby -e "p readlines ''"
10436 * ["First line\nSecond line\n\n", "Fourth line\nFifth line\n"]
10437 *
10438 * With only integer argument +limit+ given,
10439 * limits the number of bytes in the line;
10440 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
10441 *
10442 * $cat t.txt | ruby -e "p readlines 10"
10443 * ["First line", "\n", "Second lin", "e\n", "\n", "Fourth lin", "e\n", "Fifth line", "\n"]
10444 *
10445 * $cat t.txt | ruby -e "p readlines 11"
10446 * ["First line\n", "Second line", "\n", "\n", "Fourth line", "\n", "Fifth line\n"]
10447 *
10448 * $cat t.txt | ruby -e "p readlines 12"
10449 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10450 *
10451 * With arguments +sep+ and +limit+ given, combines the two behaviors;
10452 * see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit].
10453 *
10454 * Optional keyword argument +chomp+ specifies whether line separators
10455 * are to be omitted:
10456 *
10457 * $ cat t.txt | ruby -e "p readlines(chomp: true)"
10458 * ["First line", "Second line", "", "Fourth line", "Fifth line"]
10459 *
10460 * Optional keyword arguments +enc_opts+ specify encoding options;
10461 * see {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
10462 *
10463 */
10464
10465static VALUE
10466rb_f_readlines(int argc, VALUE *argv, VALUE recv)
10467{
10468 if (recv == argf) {
10469 return argf_readlines(argc, argv, argf);
10470 }
10471 return forward(argf, rb_intern("readlines"), argc, argv);
10472}
10473
10474/*
10475 * call-seq:
10476 * ARGF.readlines(sep = $/, chomp: false) -> array
10477 * ARGF.readlines(limit, chomp: false) -> array
10478 * ARGF.readlines(sep, limit, chomp: false) -> array
10479 *
10480 * ARGF.to_a(sep = $/, chomp: false) -> array
10481 * ARGF.to_a(limit, chomp: false) -> array
10482 * ARGF.to_a(sep, limit, chomp: false) -> array
10483 *
10484 * Reads each file in ARGF in its entirety, returning an Array containing
10485 * lines from the files. Lines are assumed to be separated by _sep_.
10486 *
10487 * lines = ARGF.readlines
10488 * lines[0] #=> "This is line one\n"
10489 *
10490 * See +IO.readlines+ for a full description of all options.
10491 */
10492static VALUE
10493argf_readlines(int argc, VALUE *argv, VALUE argf)
10494{
10495 long lineno = ARGF.lineno;
10496 VALUE lines, ary;
10497
10498 ary = rb_ary_new();
10499 while (next_argv()) {
10500 if (ARGF_GENERIC_INPUT_P()) {
10501 lines = forward_current(rb_intern("readlines"), argc, argv);
10502 }
10503 else {
10504 lines = rb_io_readlines(argc, argv, ARGF.current_file);
10505 argf_close(argf);
10506 }
10507 ARGF.next_p = 1;
10508 rb_ary_concat(ary, lines);
10509 ARGF.lineno = lineno + RARRAY_LEN(ary);
10510 ARGF.last_lineno = ARGF.lineno;
10511 }
10512 ARGF.init_p = 0;
10513 return ary;
10514}
10515
10516/*
10517 * call-seq:
10518 * `command` -> string
10519 *
10520 * Returns the <tt>$stdout</tt> output from running +command+ in a subshell;
10521 * sets global variable <tt>$?</tt> to the process status.
10522 *
10523 * This method has potential security vulnerabilities if called with untrusted input;
10524 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
10525 *
10526 * Examples:
10527 *
10528 * $ `date` # => "Wed Apr 9 08:56:30 CDT 2003\n"
10529 * $ `echo oops && exit 99` # => "oops\n"
10530 * $ $? # => #<Process::Status: pid 17088 exit 99>
10531 * $ $?.status # => 99>
10532 *
10533 * The built-in syntax <tt>%x{...}</tt> uses this method.
10534 *
10535 */
10536
10537static VALUE
10538rb_f_backquote(VALUE obj, VALUE str)
10539{
10540 VALUE port;
10541 VALUE result;
10542 rb_io_t *fptr;
10543
10544 SafeStringValue(str);
10545 rb_last_status_clear();
10546 port = pipe_open_s(str, "r", FMODE_READABLE|DEFAULT_TEXTMODE, NULL);
10547 if (NIL_P(port)) return rb_str_new(0,0);
10548
10549 GetOpenFile(port, fptr);
10550 result = read_all(fptr, remain_size(fptr), Qnil);
10551 rb_io_close(port);
10552 rb_io_fptr_cleanup_all(fptr);
10553 RB_GC_GUARD(port);
10554
10555 return result;
10556}
10557
10558#ifdef HAVE_SYS_SELECT_H
10559#include <sys/select.h>
10560#endif
10561
10562static VALUE
10563select_internal(VALUE read, VALUE write, VALUE except, struct timeval *tp, rb_fdset_t *fds)
10564{
10565 VALUE res, list;
10566 rb_fdset_t *rp, *wp, *ep;
10567 rb_io_t *fptr;
10568 long i;
10569 int max = 0, n;
10570 int pending = 0;
10571 struct timeval timerec;
10572
10573 if (!NIL_P(read)) {
10574 Check_Type(read, T_ARRAY);
10575 for (i=0; i<RARRAY_LEN(read); i++) {
10576 GetOpenFile(rb_io_get_io(RARRAY_AREF(read, i)), fptr);
10577 rb_fd_set(fptr->fd, &fds[0]);
10578 if (READ_DATA_PENDING(fptr) || READ_CHAR_PENDING(fptr)) { /* check for buffered data */
10579 pending++;
10580 rb_fd_set(fptr->fd, &fds[3]);
10581 }
10582 if (max < fptr->fd) max = fptr->fd;
10583 }
10584 if (pending) { /* no blocking if there's buffered data */
10585 timerec.tv_sec = timerec.tv_usec = 0;
10586 tp = &timerec;
10587 }
10588 rp = &fds[0];
10589 }
10590 else
10591 rp = 0;
10592
10593 if (!NIL_P(write)) {
10594 Check_Type(write, T_ARRAY);
10595 for (i=0; i<RARRAY_LEN(write); i++) {
10596 VALUE write_io = GetWriteIO(rb_io_get_io(RARRAY_AREF(write, i)));
10597 GetOpenFile(write_io, fptr);
10598 rb_fd_set(fptr->fd, &fds[1]);
10599 if (max < fptr->fd) max = fptr->fd;
10600 }
10601 wp = &fds[1];
10602 }
10603 else
10604 wp = 0;
10605
10606 if (!NIL_P(except)) {
10607 Check_Type(except, T_ARRAY);
10608 for (i=0; i<RARRAY_LEN(except); i++) {
10609 VALUE io = rb_io_get_io(RARRAY_AREF(except, i));
10610 VALUE write_io = GetWriteIO(io);
10611 GetOpenFile(io, fptr);
10612 rb_fd_set(fptr->fd, &fds[2]);
10613 if (max < fptr->fd) max = fptr->fd;
10614 if (io != write_io) {
10615 GetOpenFile(write_io, fptr);
10616 rb_fd_set(fptr->fd, &fds[2]);
10617 if (max < fptr->fd) max = fptr->fd;
10618 }
10619 }
10620 ep = &fds[2];
10621 }
10622 else {
10623 ep = 0;
10624 }
10625
10626 max++;
10627
10628 n = rb_thread_fd_select(max, rp, wp, ep, tp);
10629 if (n < 0) {
10630 rb_sys_fail(0);
10631 }
10632 if (!pending && n == 0) return Qnil; /* returns nil on timeout */
10633
10634 res = rb_ary_new2(3);
10635 rb_ary_push(res, rp?rb_ary_new():rb_ary_new2(0));
10636 rb_ary_push(res, wp?rb_ary_new():rb_ary_new2(0));
10637 rb_ary_push(res, ep?rb_ary_new():rb_ary_new2(0));
10638
10639 if (rp) {
10640 list = RARRAY_AREF(res, 0);
10641 for (i=0; i< RARRAY_LEN(read); i++) {
10642 VALUE obj = rb_ary_entry(read, i);
10643 VALUE io = rb_io_get_io(obj);
10644 GetOpenFile(io, fptr);
10645 if (rb_fd_isset(fptr->fd, &fds[0]) ||
10646 rb_fd_isset(fptr->fd, &fds[3])) {
10647 rb_ary_push(list, obj);
10648 }
10649 }
10650 }
10651
10652 if (wp) {
10653 list = RARRAY_AREF(res, 1);
10654 for (i=0; i< RARRAY_LEN(write); i++) {
10655 VALUE obj = rb_ary_entry(write, i);
10656 VALUE io = rb_io_get_io(obj);
10657 VALUE write_io = GetWriteIO(io);
10658 GetOpenFile(write_io, fptr);
10659 if (rb_fd_isset(fptr->fd, &fds[1])) {
10660 rb_ary_push(list, obj);
10661 }
10662 }
10663 }
10664
10665 if (ep) {
10666 list = RARRAY_AREF(res, 2);
10667 for (i=0; i< RARRAY_LEN(except); i++) {
10668 VALUE obj = rb_ary_entry(except, i);
10669 VALUE io = rb_io_get_io(obj);
10670 VALUE write_io = GetWriteIO(io);
10671 GetOpenFile(io, fptr);
10672 if (rb_fd_isset(fptr->fd, &fds[2])) {
10673 rb_ary_push(list, obj);
10674 }
10675 else if (io != write_io) {
10676 GetOpenFile(write_io, fptr);
10677 if (rb_fd_isset(fptr->fd, &fds[2])) {
10678 rb_ary_push(list, obj);
10679 }
10680 }
10681 }
10682 }
10683
10684 return res; /* returns an empty array on interrupt */
10685}
10686
10688 VALUE read, write, except;
10689 struct timeval *timeout;
10690 rb_fdset_t fdsets[4];
10691};
10692
10693static VALUE
10694select_call(VALUE arg)
10695{
10696 struct select_args *p = (struct select_args *)arg;
10697
10698 return select_internal(p->read, p->write, p->except, p->timeout, p->fdsets);
10699}
10700
10701static VALUE
10702select_end(VALUE arg)
10703{
10704 struct select_args *p = (struct select_args *)arg;
10705 int i;
10706
10707 for (i = 0; i < numberof(p->fdsets); ++i)
10708 rb_fd_term(&p->fdsets[i]);
10709 return Qnil;
10710}
10711
10712static VALUE sym_normal, sym_sequential, sym_random,
10713 sym_willneed, sym_dontneed, sym_noreuse;
10714
10715#ifdef HAVE_POSIX_FADVISE
10716struct io_advise_struct {
10717 int fd;
10718 int advice;
10719 rb_off_t offset;
10720 rb_off_t len;
10721};
10722
10723static VALUE
10724io_advise_internal(void *arg)
10725{
10726 struct io_advise_struct *ptr = arg;
10727 return posix_fadvise(ptr->fd, ptr->offset, ptr->len, ptr->advice);
10728}
10729
10730static VALUE
10731io_advise_sym_to_const(VALUE sym)
10732{
10733#ifdef POSIX_FADV_NORMAL
10734 if (sym == sym_normal)
10735 return INT2NUM(POSIX_FADV_NORMAL);
10736#endif
10737
10738#ifdef POSIX_FADV_RANDOM
10739 if (sym == sym_random)
10740 return INT2NUM(POSIX_FADV_RANDOM);
10741#endif
10742
10743#ifdef POSIX_FADV_SEQUENTIAL
10744 if (sym == sym_sequential)
10745 return INT2NUM(POSIX_FADV_SEQUENTIAL);
10746#endif
10747
10748#ifdef POSIX_FADV_WILLNEED
10749 if (sym == sym_willneed)
10750 return INT2NUM(POSIX_FADV_WILLNEED);
10751#endif
10752
10753#ifdef POSIX_FADV_DONTNEED
10754 if (sym == sym_dontneed)
10755 return INT2NUM(POSIX_FADV_DONTNEED);
10756#endif
10757
10758#ifdef POSIX_FADV_NOREUSE
10759 if (sym == sym_noreuse)
10760 return INT2NUM(POSIX_FADV_NOREUSE);
10761#endif
10762
10763 return Qnil;
10764}
10765
10766static VALUE
10767do_io_advise(rb_io_t *fptr, VALUE advice, rb_off_t offset, rb_off_t len)
10768{
10769 int rv;
10770 struct io_advise_struct ias;
10771 VALUE num_adv;
10772
10773 num_adv = io_advise_sym_to_const(advice);
10774
10775 /*
10776 * The platform doesn't support this hint. We don't raise exception, instead
10777 * silently ignore it. Because IO::advise is only hint.
10778 */
10779 if (NIL_P(num_adv))
10780 return Qnil;
10781
10782 ias.fd = fptr->fd;
10783 ias.advice = NUM2INT(num_adv);
10784 ias.offset = offset;
10785 ias.len = len;
10786
10787 rv = (int)rb_thread_io_blocking_region(io_advise_internal, &ias, fptr->fd);
10788 if (rv && rv != ENOSYS) {
10789 /* posix_fadvise(2) doesn't set errno. On success it returns 0; otherwise
10790 it returns the error code. */
10791 VALUE message = rb_sprintf("%"PRIsVALUE" "
10792 "(%"PRI_OFFT_PREFIX"d, "
10793 "%"PRI_OFFT_PREFIX"d, "
10794 "%"PRIsVALUE")",
10795 fptr->pathv, offset, len, advice);
10796 rb_syserr_fail_str(rv, message);
10797 }
10798
10799 return Qnil;
10800}
10801
10802#endif /* HAVE_POSIX_FADVISE */
10803
10804static void
10805advice_arg_check(VALUE advice)
10806{
10807 if (!SYMBOL_P(advice))
10808 rb_raise(rb_eTypeError, "advice must be a Symbol");
10809
10810 if (advice != sym_normal &&
10811 advice != sym_sequential &&
10812 advice != sym_random &&
10813 advice != sym_willneed &&
10814 advice != sym_dontneed &&
10815 advice != sym_noreuse) {
10816 rb_raise(rb_eNotImpError, "Unsupported advice: %+"PRIsVALUE, advice);
10817 }
10818}
10819
10820/*
10821 * call-seq:
10822 * advise(advice, offset = 0, len = 0) -> nil
10823 *
10824 * Invokes Posix system call
10825 * {posix_fadvise(2)}[https://linux.die.net/man/2/posix_fadvise],
10826 * which announces an intention to access data from the current file
10827 * in a particular manner.
10828 *
10829 * The arguments and results are platform-dependent.
10830 *
10831 * The relevant data is specified by:
10832 *
10833 * - +offset+: The offset of the first byte of data.
10834 * - +len+: The number of bytes to be accessed;
10835 * if +len+ is zero, or is larger than the number of bytes remaining,
10836 * all remaining bytes will be accessed.
10837 *
10838 * Argument +advice+ is one of the following symbols:
10839 *
10840 * - +:normal+: The application has no advice to give
10841 * about its access pattern for the specified data.
10842 * If no advice is given for an open file, this is the default assumption.
10843 * - +:sequential+: The application expects to access the specified data sequentially
10844 * (with lower offsets read before higher ones).
10845 * - +:random+: The specified data will be accessed in random order.
10846 * - +:noreuse+: The specified data will be accessed only once.
10847 * - +:willneed+: The specified data will be accessed in the near future.
10848 * - +:dontneed+: The specified data will not be accessed in the near future.
10849 *
10850 * Not implemented on all platforms.
10851 *
10852 */
10853static VALUE
10854rb_io_advise(int argc, VALUE *argv, VALUE io)
10855{
10856 VALUE advice, offset, len;
10857 rb_off_t off, l;
10858 rb_io_t *fptr;
10859
10860 rb_scan_args(argc, argv, "12", &advice, &offset, &len);
10861 advice_arg_check(advice);
10862
10863 io = GetWriteIO(io);
10864 GetOpenFile(io, fptr);
10865
10866 off = NIL_P(offset) ? 0 : NUM2OFFT(offset);
10867 l = NIL_P(len) ? 0 : NUM2OFFT(len);
10868
10869#ifdef HAVE_POSIX_FADVISE
10870 return do_io_advise(fptr, advice, off, l);
10871#else
10872 ((void)off, (void)l); /* Ignore all hint */
10873 return Qnil;
10874#endif
10875}
10876
10877/*
10878 * call-seq:
10879 * IO.select(read_ios, write_ios = [], error_ios = [], timeout = nil) -> array or nil
10880 *
10881 * Invokes system call {select(2)}[https://linux.die.net/man/2/select],
10882 * which monitors multiple file descriptors,
10883 * waiting until one or more of the file descriptors
10884 * becomes ready for some class of I/O operation.
10885 *
10886 * Not implemented on all platforms.
10887 *
10888 * Each of the arguments +read_ios+, +write_ios+, and +error_ios+
10889 * is an array of IO objects.
10890 *
10891 * Argument +timeout+ is an integer timeout interval in seconds.
10892 *
10893 * The method monitors the \IO objects given in all three arrays,
10894 * waiting for some to be ready;
10895 * returns a 3-element array whose elements are:
10896 *
10897 * - An array of the objects in +read_ios+ that are ready for reading.
10898 * - An array of the objects in +write_ios+ that are ready for writing.
10899 * - An array of the objects in +error_ios+ have pending exceptions.
10900 *
10901 * If no object becomes ready within the given +timeout+, +nil+ is returned.
10902 *
10903 * \IO.select peeks the buffer of \IO objects for testing readability.
10904 * If the \IO buffer is not empty, \IO.select immediately notifies
10905 * readability. This "peek" only happens for \IO objects. It does not
10906 * happen for IO-like objects such as OpenSSL::SSL::SSLSocket.
10907 *
10908 * The best way to use \IO.select is invoking it after non-blocking
10909 * methods such as #read_nonblock, #write_nonblock, etc. The methods
10910 * raise an exception which is extended by IO::WaitReadable or
10911 * IO::WaitWritable. The modules notify how the caller should wait
10912 * with \IO.select. If IO::WaitReadable is raised, the caller should
10913 * wait for reading. If IO::WaitWritable is raised, the caller should
10914 * wait for writing.
10915 *
10916 * So, blocking read (#readpartial) can be emulated using
10917 * #read_nonblock and \IO.select as follows:
10918 *
10919 * begin
10920 * result = io_like.read_nonblock(maxlen)
10921 * rescue IO::WaitReadable
10922 * IO.select([io_like])
10923 * retry
10924 * rescue IO::WaitWritable
10925 * IO.select(nil, [io_like])
10926 * retry
10927 * end
10928 *
10929 * Especially, the combination of non-blocking methods and \IO.select is
10930 * preferred for IO like objects such as OpenSSL::SSL::SSLSocket. It
10931 * has #to_io method to return underlying IO object. IO.select calls
10932 * #to_io to obtain the file descriptor to wait.
10933 *
10934 * This means that readability notified by \IO.select doesn't mean
10935 * readability from OpenSSL::SSL::SSLSocket object.
10936 *
10937 * The most likely situation is that OpenSSL::SSL::SSLSocket buffers
10938 * some data. \IO.select doesn't see the buffer. So \IO.select can
10939 * block when OpenSSL::SSL::SSLSocket#readpartial doesn't block.
10940 *
10941 * However, several more complicated situations exist.
10942 *
10943 * SSL is a protocol which is sequence of records.
10944 * The record consists of multiple bytes.
10945 * So, the remote side of SSL sends a partial record, IO.select
10946 * notifies readability but OpenSSL::SSL::SSLSocket cannot decrypt a
10947 * byte and OpenSSL::SSL::SSLSocket#readpartial will block.
10948 *
10949 * Also, the remote side can request SSL renegotiation which forces
10950 * the local SSL engine to write some data.
10951 * This means OpenSSL::SSL::SSLSocket#readpartial may invoke #write
10952 * system call and it can block.
10953 * In such a situation, OpenSSL::SSL::SSLSocket#read_nonblock raises
10954 * IO::WaitWritable instead of blocking.
10955 * So, the caller should wait for ready for writability as above
10956 * example.
10957 *
10958 * The combination of non-blocking methods and \IO.select is also useful
10959 * for streams such as tty, pipe socket socket when multiple processes
10960 * read from a stream.
10961 *
10962 * Finally, Linux kernel developers don't guarantee that
10963 * readability of select(2) means readability of following read(2) even
10964 * for a single process;
10965 * see {select(2)}[https://linux.die.net/man/2/select]
10966 *
10967 * Invoking \IO.select before IO#readpartial works well as usual.
10968 * However it is not the best way to use \IO.select.
10969 *
10970 * The writability notified by select(2) doesn't show
10971 * how many bytes are writable.
10972 * IO#write method blocks until given whole string is written.
10973 * So, <tt>IO#write(two or more bytes)</tt> can block after
10974 * writability is notified by \IO.select. IO#write_nonblock is required
10975 * to avoid the blocking.
10976 *
10977 * Blocking write (#write) can be emulated using #write_nonblock and
10978 * IO.select as follows: IO::WaitReadable should also be rescued for
10979 * SSL renegotiation in OpenSSL::SSL::SSLSocket.
10980 *
10981 * while 0 < string.bytesize
10982 * begin
10983 * written = io_like.write_nonblock(string)
10984 * rescue IO::WaitReadable
10985 * IO.select([io_like])
10986 * retry
10987 * rescue IO::WaitWritable
10988 * IO.select(nil, [io_like])
10989 * retry
10990 * end
10991 * string = string.byteslice(written..-1)
10992 * end
10993 *
10994 * Example:
10995 *
10996 * rp, wp = IO.pipe
10997 * mesg = "ping "
10998 * 100.times {
10999 * # IO.select follows IO#read. Not the best way to use IO.select.
11000 * rs, ws, = IO.select([rp], [wp])
11001 * if r = rs[0]
11002 * ret = r.read(5)
11003 * print ret
11004 * case ret
11005 * when /ping/
11006 * mesg = "pong\n"
11007 * when /pong/
11008 * mesg = "ping "
11009 * end
11010 * end
11011 * if w = ws[0]
11012 * w.write(mesg)
11013 * end
11014 * }
11015 *
11016 * Output:
11017 *
11018 * ping pong
11019 * ping pong
11020 * ping pong
11021 * (snipped)
11022 * ping
11023 *
11024 */
11025
11026static VALUE
11027rb_f_select(int argc, VALUE *argv, VALUE obj)
11028{
11029 VALUE scheduler = rb_fiber_scheduler_current();
11030 if (scheduler != Qnil) {
11031 // It's optionally supported.
11032 VALUE result = rb_fiber_scheduler_io_selectv(scheduler, argc, argv);
11033 if (!UNDEF_P(result)) return result;
11034 }
11035
11036 VALUE timeout;
11037 struct select_args args;
11038 struct timeval timerec;
11039 int i;
11040
11041 rb_scan_args(argc, argv, "13", &args.read, &args.write, &args.except, &timeout);
11042 if (NIL_P(timeout)) {
11043 args.timeout = 0;
11044 }
11045 else {
11046 timerec = rb_time_interval(timeout);
11047 args.timeout = &timerec;
11048 }
11049
11050 for (i = 0; i < numberof(args.fdsets); ++i)
11051 rb_fd_init(&args.fdsets[i]);
11052
11053 return rb_ensure(select_call, (VALUE)&args, select_end, (VALUE)&args);
11054}
11055
11056#ifdef IOCTL_REQ_TYPE
11057 typedef IOCTL_REQ_TYPE ioctl_req_t;
11058#else
11059 typedef int ioctl_req_t;
11060# define NUM2IOCTLREQ(num) ((int)NUM2LONG(num))
11061#endif
11062
11063#ifdef HAVE_IOCTL
11064struct ioctl_arg {
11065 int fd;
11066 ioctl_req_t cmd;
11067 long narg;
11068};
11069
11070static VALUE
11071nogvl_ioctl(void *ptr)
11072{
11073 struct ioctl_arg *arg = ptr;
11074
11075 return (VALUE)ioctl(arg->fd, arg->cmd, arg->narg);
11076}
11077
11078static int
11079do_ioctl(int fd, ioctl_req_t cmd, long narg)
11080{
11081 int retval;
11082 struct ioctl_arg arg;
11083
11084 arg.fd = fd;
11085 arg.cmd = cmd;
11086 arg.narg = narg;
11087
11088 retval = (int)rb_thread_io_blocking_region(nogvl_ioctl, &arg, fd);
11089
11090 return retval;
11091}
11092#endif
11093
11094#define DEFAULT_IOCTL_NARG_LEN (256)
11095
11096#if defined(__linux__) && defined(_IOC_SIZE)
11097static long
11098linux_iocparm_len(ioctl_req_t cmd)
11099{
11100 long len;
11101
11102 if ((cmd & 0xFFFF0000) == 0) {
11103 /* legacy and unstructured ioctl number. */
11104 return DEFAULT_IOCTL_NARG_LEN;
11105 }
11106
11107 len = _IOC_SIZE(cmd);
11108
11109 /* paranoia check for silly drivers which don't keep ioctl convention */
11110 if (len < DEFAULT_IOCTL_NARG_LEN)
11111 len = DEFAULT_IOCTL_NARG_LEN;
11112
11113 return len;
11114}
11115#endif
11116
11117#ifdef HAVE_IOCTL
11118static long
11119ioctl_narg_len(ioctl_req_t cmd)
11120{
11121 long len;
11122
11123#ifdef IOCPARM_MASK
11124#ifndef IOCPARM_LEN
11125#define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK)
11126#endif
11127#endif
11128#ifdef IOCPARM_LEN
11129 len = IOCPARM_LEN(cmd); /* on BSDish systems we're safe */
11130#elif defined(__linux__) && defined(_IOC_SIZE)
11131 len = linux_iocparm_len(cmd);
11132#else
11133 /* otherwise guess at what's safe */
11134 len = DEFAULT_IOCTL_NARG_LEN;
11135#endif
11136
11137 return len;
11138}
11139#endif
11140
11141#ifdef HAVE_FCNTL
11142#ifdef __linux__
11143typedef long fcntl_arg_t;
11144#else
11145/* posix */
11146typedef int fcntl_arg_t;
11147#endif
11148
11149static long
11150fcntl_narg_len(ioctl_req_t cmd)
11151{
11152 long len;
11153
11154 switch (cmd) {
11155#ifdef F_DUPFD
11156 case F_DUPFD:
11157 len = sizeof(fcntl_arg_t);
11158 break;
11159#endif
11160#ifdef F_DUP2FD /* bsd specific */
11161 case F_DUP2FD:
11162 len = sizeof(int);
11163 break;
11164#endif
11165#ifdef F_DUPFD_CLOEXEC /* linux specific */
11166 case F_DUPFD_CLOEXEC:
11167 len = sizeof(fcntl_arg_t);
11168 break;
11169#endif
11170#ifdef F_GETFD
11171 case F_GETFD:
11172 len = 1;
11173 break;
11174#endif
11175#ifdef F_SETFD
11176 case F_SETFD:
11177 len = sizeof(fcntl_arg_t);
11178 break;
11179#endif
11180#ifdef F_GETFL
11181 case F_GETFL:
11182 len = 1;
11183 break;
11184#endif
11185#ifdef F_SETFL
11186 case F_SETFL:
11187 len = sizeof(fcntl_arg_t);
11188 break;
11189#endif
11190#ifdef F_GETOWN
11191 case F_GETOWN:
11192 len = 1;
11193 break;
11194#endif
11195#ifdef F_SETOWN
11196 case F_SETOWN:
11197 len = sizeof(fcntl_arg_t);
11198 break;
11199#endif
11200#ifdef F_GETOWN_EX /* linux specific */
11201 case F_GETOWN_EX:
11202 len = sizeof(struct f_owner_ex);
11203 break;
11204#endif
11205#ifdef F_SETOWN_EX /* linux specific */
11206 case F_SETOWN_EX:
11207 len = sizeof(struct f_owner_ex);
11208 break;
11209#endif
11210#ifdef F_GETLK
11211 case F_GETLK:
11212 len = sizeof(struct flock);
11213 break;
11214#endif
11215#ifdef F_SETLK
11216 case F_SETLK:
11217 len = sizeof(struct flock);
11218 break;
11219#endif
11220#ifdef F_SETLKW
11221 case F_SETLKW:
11222 len = sizeof(struct flock);
11223 break;
11224#endif
11225#ifdef F_READAHEAD /* bsd specific */
11226 case F_READAHEAD:
11227 len = sizeof(int);
11228 break;
11229#endif
11230#ifdef F_RDAHEAD /* Darwin specific */
11231 case F_RDAHEAD:
11232 len = sizeof(int);
11233 break;
11234#endif
11235#ifdef F_GETSIG /* linux specific */
11236 case F_GETSIG:
11237 len = 1;
11238 break;
11239#endif
11240#ifdef F_SETSIG /* linux specific */
11241 case F_SETSIG:
11242 len = sizeof(fcntl_arg_t);
11243 break;
11244#endif
11245#ifdef F_GETLEASE /* linux specific */
11246 case F_GETLEASE:
11247 len = 1;
11248 break;
11249#endif
11250#ifdef F_SETLEASE /* linux specific */
11251 case F_SETLEASE:
11252 len = sizeof(fcntl_arg_t);
11253 break;
11254#endif
11255#ifdef F_NOTIFY /* linux specific */
11256 case F_NOTIFY:
11257 len = sizeof(fcntl_arg_t);
11258 break;
11259#endif
11260
11261 default:
11262 len = 256;
11263 break;
11264 }
11265
11266 return len;
11267}
11268#else /* HAVE_FCNTL */
11269static long
11270fcntl_narg_len(ioctl_req_t cmd)
11271{
11272 return 0;
11273}
11274#endif /* HAVE_FCNTL */
11275
11276#define NARG_SENTINEL 17
11277
11278static long
11279setup_narg(ioctl_req_t cmd, VALUE *argp, long (*narg_len)(ioctl_req_t))
11280{
11281 long narg = 0;
11282 VALUE arg = *argp;
11283
11284 if (!RTEST(arg)) {
11285 narg = 0;
11286 }
11287 else if (FIXNUM_P(arg)) {
11288 narg = FIX2LONG(arg);
11289 }
11290 else if (arg == Qtrue) {
11291 narg = 1;
11292 }
11293 else {
11294 VALUE tmp = rb_check_string_type(arg);
11295
11296 if (NIL_P(tmp)) {
11297 narg = NUM2LONG(arg);
11298 }
11299 else {
11300 char *ptr;
11301 long len, slen;
11302
11303 *argp = arg = tmp;
11304 len = narg_len(cmd);
11305 rb_str_modify(arg);
11306
11307 slen = RSTRING_LEN(arg);
11308 /* expand for data + sentinel. */
11309 if (slen < len+1) {
11310 rb_str_resize(arg, len+1);
11311 MEMZERO(RSTRING_PTR(arg)+slen, char, len-slen);
11312 slen = len+1;
11313 }
11314 /* a little sanity check here */
11315 ptr = RSTRING_PTR(arg);
11316 ptr[slen - 1] = NARG_SENTINEL;
11317 narg = (long)(SIGNED_VALUE)ptr;
11318 }
11319 }
11320
11321 return narg;
11322}
11323
11324static VALUE
11325finish_narg(int retval, VALUE arg, const rb_io_t *fptr)
11326{
11327 if (retval < 0) rb_sys_fail_path(fptr->pathv);
11328 if (RB_TYPE_P(arg, T_STRING)) {
11329 char *ptr;
11330 long slen;
11331 RSTRING_GETMEM(arg, ptr, slen);
11332 if (ptr[slen-1] != NARG_SENTINEL)
11333 rb_raise(rb_eArgError, "return value overflowed string");
11334 ptr[slen-1] = '\0';
11335 }
11336
11337 return INT2NUM(retval);
11338}
11339
11340#ifdef HAVE_IOCTL
11341static VALUE
11342rb_ioctl(VALUE io, VALUE req, VALUE arg)
11343{
11344 ioctl_req_t cmd = NUM2IOCTLREQ(req);
11345 rb_io_t *fptr;
11346 long narg;
11347 int retval;
11348
11349 narg = setup_narg(cmd, &arg, ioctl_narg_len);
11350 GetOpenFile(io, fptr);
11351 retval = do_ioctl(fptr->fd, cmd, narg);
11352 return finish_narg(retval, arg, fptr);
11353}
11354
11355/*
11356 * call-seq:
11357 * ioctl(integer_cmd, argument) -> integer
11358 *
11359 * Invokes Posix system call {ioctl(2)}[https://linux.die.net/man/2/ioctl],
11360 * which issues a low-level command to an I/O device.
11361 *
11362 * Issues a low-level command to an I/O device.
11363 * The arguments and returned value are platform-dependent.
11364 * The effect of the call is platform-dependent.
11365 *
11366 * If argument +argument+ is an integer, it is passed directly;
11367 * if it is a string, it is interpreted as a binary sequence of bytes.
11368 *
11369 * Not implemented on all platforms.
11370 *
11371 */
11372
11373static VALUE
11374rb_io_ioctl(int argc, VALUE *argv, VALUE io)
11375{
11376 VALUE req, arg;
11377
11378 rb_scan_args(argc, argv, "11", &req, &arg);
11379 return rb_ioctl(io, req, arg);
11380}
11381#else
11382#define rb_io_ioctl rb_f_notimplement
11383#endif
11384
11385#ifdef HAVE_FCNTL
11386struct fcntl_arg {
11387 int fd;
11388 int cmd;
11389 long narg;
11390};
11391
11392static VALUE
11393nogvl_fcntl(void *ptr)
11394{
11395 struct fcntl_arg *arg = ptr;
11396
11397#if defined(F_DUPFD)
11398 if (arg->cmd == F_DUPFD)
11399 return (VALUE)rb_cloexec_fcntl_dupfd(arg->fd, (int)arg->narg);
11400#endif
11401 return (VALUE)fcntl(arg->fd, arg->cmd, arg->narg);
11402}
11403
11404static int
11405do_fcntl(int fd, int cmd, long narg)
11406{
11407 int retval;
11408 struct fcntl_arg arg;
11409
11410 arg.fd = fd;
11411 arg.cmd = cmd;
11412 arg.narg = narg;
11413
11414 retval = (int)rb_thread_io_blocking_region(nogvl_fcntl, &arg, fd);
11415 if (retval != -1) {
11416 switch (cmd) {
11417#if defined(F_DUPFD)
11418 case F_DUPFD:
11419#endif
11420#if defined(F_DUPFD_CLOEXEC)
11421 case F_DUPFD_CLOEXEC:
11422#endif
11423 rb_update_max_fd(retval);
11424 }
11425 }
11426
11427 return retval;
11428}
11429
11430static VALUE
11431rb_fcntl(VALUE io, VALUE req, VALUE arg)
11432{
11433 int cmd = NUM2INT(req);
11434 rb_io_t *fptr;
11435 long narg;
11436 int retval;
11437
11438 narg = setup_narg(cmd, &arg, fcntl_narg_len);
11439 GetOpenFile(io, fptr);
11440 retval = do_fcntl(fptr->fd, cmd, narg);
11441 return finish_narg(retval, arg, fptr);
11442}
11443
11444/*
11445 * call-seq:
11446 * fcntl(integer_cmd, argument) -> integer
11447 *
11448 * Invokes Posix system call {fcntl(2)}[https://linux.die.net/man/2/fcntl],
11449 * which provides a mechanism for issuing low-level commands to control or query
11450 * a file-oriented I/O stream. Arguments and results are platform
11451 * dependent.
11452 *
11453 * If +argument+ is a number, its value is passed directly;
11454 * if it is a string, it is interpreted as a binary sequence of bytes.
11455 * (Array#pack might be a useful way to build this string.)
11456 *
11457 * Not implemented on all platforms.
11458 *
11459 */
11460
11461static VALUE
11462rb_io_fcntl(int argc, VALUE *argv, VALUE io)
11463{
11464 VALUE req, arg;
11465
11466 rb_scan_args(argc, argv, "11", &req, &arg);
11467 return rb_fcntl(io, req, arg);
11468}
11469#else
11470#define rb_io_fcntl rb_f_notimplement
11471#endif
11472
11473#if defined(HAVE_SYSCALL) || defined(HAVE___SYSCALL)
11474/*
11475 * call-seq:
11476 * syscall(integer_callno, *arguments) -> integer
11477 *
11478 * Invokes Posix system call {syscall(2)}[https://linux.die.net/man/2/syscall],
11479 * which calls a specified function.
11480 *
11481 * Calls the operating system function identified by +integer_callno+;
11482 * returns the result of the function or raises SystemCallError if it failed.
11483 * The effect of the call is platform-dependent.
11484 * The arguments and returned value are platform-dependent.
11485 *
11486 * For each of +arguments+: if it is an integer, it is passed directly;
11487 * if it is a string, it is interpreted as a binary sequence of bytes.
11488 * There may be as many as nine such arguments.
11489 *
11490 * Arguments +integer_callno+ and +argument+, as well as the returned value,
11491 * are platform-dependent.
11492 *
11493 * Note: Method +syscall+ is essentially unsafe and unportable.
11494 * The DL (Fiddle) library is preferred for safer and a bit
11495 * more portable programming.
11496 *
11497 * Not implemented on all platforms.
11498 *
11499 */
11500
11501static VALUE
11502rb_f_syscall(int argc, VALUE *argv, VALUE _)
11503{
11504 VALUE arg[8];
11505#if SIZEOF_VOIDP == 8 && defined(HAVE___SYSCALL) && SIZEOF_INT != 8 /* mainly *BSD */
11506# define SYSCALL __syscall
11507# define NUM2SYSCALLID(x) NUM2LONG(x)
11508# define RETVAL2NUM(x) LONG2NUM(x)
11509# if SIZEOF_LONG == 8
11510 long num, retval = -1;
11511# elif SIZEOF_LONG_LONG == 8
11512 long long num, retval = -1;
11513# else
11514# error ---->> it is asserted that __syscall takes the first argument and returns retval in 64bit signed integer. <<----
11515# endif
11516#elif defined(__linux__)
11517# define SYSCALL syscall
11518# define NUM2SYSCALLID(x) NUM2LONG(x)
11519# define RETVAL2NUM(x) LONG2NUM(x)
11520 /*
11521 * Linux man page says, syscall(2) function prototype is below.
11522 *
11523 * int syscall(int number, ...);
11524 *
11525 * But, it's incorrect. Actual one takes and returned long. (see unistd.h)
11526 */
11527 long num, retval = -1;
11528#else
11529# define SYSCALL syscall
11530# define NUM2SYSCALLID(x) NUM2INT(x)
11531# define RETVAL2NUM(x) INT2NUM(x)
11532 int num, retval = -1;
11533#endif
11534 int i;
11535
11536 if (RTEST(ruby_verbose)) {
11538 "We plan to remove a syscall function at future release. DL(Fiddle) provides safer alternative.");
11539 }
11540
11541 if (argc == 0)
11542 rb_raise(rb_eArgError, "too few arguments for syscall");
11543 if (argc > numberof(arg))
11544 rb_raise(rb_eArgError, "too many arguments for syscall");
11545 num = NUM2SYSCALLID(argv[0]); ++argv;
11546 for (i = argc - 1; i--; ) {
11547 VALUE v = rb_check_string_type(argv[i]);
11548
11549 if (!NIL_P(v)) {
11550 SafeStringValue(v);
11551 rb_str_modify(v);
11552 arg[i] = (VALUE)StringValueCStr(v);
11553 }
11554 else {
11555 arg[i] = (VALUE)NUM2LONG(argv[i]);
11556 }
11557 }
11558
11559 switch (argc) {
11560 case 1:
11561 retval = SYSCALL(num);
11562 break;
11563 case 2:
11564 retval = SYSCALL(num, arg[0]);
11565 break;
11566 case 3:
11567 retval = SYSCALL(num, arg[0],arg[1]);
11568 break;
11569 case 4:
11570 retval = SYSCALL(num, arg[0],arg[1],arg[2]);
11571 break;
11572 case 5:
11573 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3]);
11574 break;
11575 case 6:
11576 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4]);
11577 break;
11578 case 7:
11579 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5]);
11580 break;
11581 case 8:
11582 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6]);
11583 break;
11584 }
11585
11586 if (retval == -1)
11587 rb_sys_fail(0);
11588 return RETVAL2NUM(retval);
11589#undef SYSCALL
11590#undef NUM2SYSCALLID
11591#undef RETVAL2NUM
11592}
11593#else
11594#define rb_f_syscall rb_f_notimplement
11595#endif
11596
11597static VALUE
11598io_new_instance(VALUE args)
11599{
11600 return rb_class_new_instance(2, (VALUE*)args+1, *(VALUE*)args);
11601}
11602
11603static rb_encoding *
11604find_encoding(VALUE v)
11605{
11606 rb_encoding *enc = rb_find_encoding(v);
11607 if (!enc) rb_warn("Unsupported encoding %"PRIsVALUE" ignored", v);
11608 return enc;
11609}
11610
11611static void
11612io_encoding_set(rb_io_t *fptr, VALUE v1, VALUE v2, VALUE opt)
11613{
11614 rb_encoding *enc, *enc2;
11615 int ecflags = fptr->encs.ecflags;
11616 VALUE ecopts, tmp;
11617
11618 if (!NIL_P(v2)) {
11619 enc2 = find_encoding(v1);
11620 tmp = rb_check_string_type(v2);
11621 if (!NIL_P(tmp)) {
11622 if (RSTRING_LEN(tmp) == 1 && RSTRING_PTR(tmp)[0] == '-') {
11623 /* Special case - "-" => no transcoding */
11624 enc = enc2;
11625 enc2 = NULL;
11626 }
11627 else
11628 enc = find_encoding(v2);
11629 if (enc == enc2) {
11630 /* Special case - "-" => no transcoding */
11631 enc2 = NULL;
11632 }
11633 }
11634 else {
11635 enc = find_encoding(v2);
11636 if (enc == enc2) {
11637 /* Special case - "-" => no transcoding */
11638 enc2 = NULL;
11639 }
11640 }
11641 if (enc2 == rb_ascii8bit_encoding()) {
11642 /* If external is ASCII-8BIT, no transcoding */
11643 enc = enc2;
11644 enc2 = NULL;
11645 }
11646 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11647 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
11648 }
11649 else {
11650 if (NIL_P(v1)) {
11651 /* Set to default encodings */
11652 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
11653 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11654 ecopts = Qnil;
11655 }
11656 else {
11657 tmp = rb_check_string_type(v1);
11658 if (!NIL_P(tmp) && rb_enc_asciicompat(enc = rb_enc_get(tmp))) {
11659 parse_mode_enc(RSTRING_PTR(tmp), enc, &enc, &enc2, NULL);
11660 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11661 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
11662 }
11663 else {
11664 rb_io_ext_int_to_encs(find_encoding(v1), NULL, &enc, &enc2, 0);
11665 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11666 ecopts = Qnil;
11667 }
11668 }
11669 }
11670 validate_enc_binmode(&fptr->mode, ecflags, enc, enc2);
11671 fptr->encs.enc = enc;
11672 fptr->encs.enc2 = enc2;
11673 fptr->encs.ecflags = ecflags;
11674 fptr->encs.ecopts = ecopts;
11675 clear_codeconv(fptr);
11676
11677}
11678
11680 rb_io_t *fptr;
11681 VALUE v1;
11682 VALUE v2;
11683 VALUE opt;
11684};
11685
11686static VALUE
11687io_encoding_set_v(VALUE v)
11688{
11689 struct io_encoding_set_args *arg = (struct io_encoding_set_args *)v;
11690 io_encoding_set(arg->fptr, arg->v1, arg->v2, arg->opt);
11691 return Qnil;
11692}
11693
11694static VALUE
11695pipe_pair_close(VALUE rw)
11696{
11697 VALUE *rwp = (VALUE *)rw;
11698 return rb_ensure(io_close, rwp[0], io_close, rwp[1]);
11699}
11700
11701/*
11702 * call-seq:
11703 * IO.pipe(**opts) -> [read_io, write_io]
11704 * IO.pipe(enc, **opts) -> [read_io, write_io]
11705 * IO.pipe(ext_enc, int_enc, **opts) -> [read_io, write_io]
11706 * IO.pipe(**opts) {|read_io, write_io| ...} -> object
11707 * IO.pipe(enc, **opts) {|read_io, write_io| ...} -> object
11708 * IO.pipe(ext_enc, int_enc, **opts) {|read_io, write_io| ...} -> object
11709 *
11710 * Creates a pair of pipe endpoints, +read_io+ and +write_io+,
11711 * connected to each other.
11712 *
11713 * If argument +enc_string+ is given, it must be a string containing one of:
11714 *
11715 * - The name of the encoding to be used as the external encoding.
11716 * - The colon-separated names of two encodings to be used as the external
11717 * and internal encodings.
11718 *
11719 * If argument +int_enc+ is given, it must be an Encoding object
11720 * or encoding name string that specifies the internal encoding to be used;
11721 * if argument +ext_enc+ is also given, it must be an Encoding object
11722 * or encoding name string that specifies the external encoding to be used.
11723 *
11724 * The string read from +read_io+ is tagged with the external encoding;
11725 * if an internal encoding is also specified, the string is converted
11726 * to, and tagged with, that encoding.
11727 *
11728 * If any encoding is specified,
11729 * optional hash arguments specify the conversion option.
11730 *
11731 * Optional keyword arguments +opts+ specify:
11732 *
11733 * - {Open Options}[rdoc-ref:IO@Open+Options].
11734 * - {Encoding Options}[rdoc-ref:encodings.rdoc@Encoding+Options].
11735 *
11736 * With no block given, returns the two endpoints in an array:
11737 *
11738 * IO.pipe # => [#<IO:fd 4>, #<IO:fd 5>]
11739 *
11740 * With a block given, calls the block with the two endpoints;
11741 * closes both endpoints and returns the value of the block:
11742 *
11743 * IO.pipe {|read_io, write_io| p read_io; p write_io }
11744 *
11745 * Output:
11746 *
11747 * #<IO:fd 6>
11748 * #<IO:fd 7>
11749 *
11750 * Not available on all platforms.
11751 *
11752 * In the example below, the two processes close the ends of the pipe
11753 * that they are not using. This is not just a cosmetic nicety. The
11754 * read end of a pipe will not generate an end of file condition if
11755 * there are any writers with the pipe still open. In the case of the
11756 * parent process, the <tt>rd.read</tt> will never return if it
11757 * does not first issue a <tt>wr.close</tt>:
11758 *
11759 * rd, wr = IO.pipe
11760 *
11761 * if fork
11762 * wr.close
11763 * puts "Parent got: <#{rd.read}>"
11764 * rd.close
11765 * Process.wait
11766 * else
11767 * rd.close
11768 * puts 'Sending message to parent'
11769 * wr.write "Hi Dad"
11770 * wr.close
11771 * end
11772 *
11773 * <em>produces:</em>
11774 *
11775 * Sending message to parent
11776 * Parent got: <Hi Dad>
11777 *
11778 */
11779
11780static VALUE
11781rb_io_s_pipe(int argc, VALUE *argv, VALUE klass)
11782{
11783 int pipes[2], state;
11784 VALUE r, w, args[3], v1, v2;
11785 VALUE opt;
11786 rb_io_t *fptr, *fptr2;
11787 struct io_encoding_set_args ies_args;
11788 int fmode = 0;
11789 VALUE ret;
11790
11791 argc = rb_scan_args(argc, argv, "02:", &v1, &v2, &opt);
11792 if (rb_pipe(pipes) < 0)
11793 rb_sys_fail(0);
11794
11795 args[0] = klass;
11796 args[1] = INT2NUM(pipes[0]);
11797 args[2] = INT2FIX(O_RDONLY);
11798 r = rb_protect(io_new_instance, (VALUE)args, &state);
11799 if (state) {
11800 close(pipes[0]);
11801 close(pipes[1]);
11802 rb_jump_tag(state);
11803 }
11804 GetOpenFile(r, fptr);
11805
11806 ies_args.fptr = fptr;
11807 ies_args.v1 = v1;
11808 ies_args.v2 = v2;
11809 ies_args.opt = opt;
11810 rb_protect(io_encoding_set_v, (VALUE)&ies_args, &state);
11811 if (state) {
11812 close(pipes[1]);
11813 io_close(r);
11814 rb_jump_tag(state);
11815 }
11816
11817 args[1] = INT2NUM(pipes[1]);
11818 args[2] = INT2FIX(O_WRONLY);
11819 w = rb_protect(io_new_instance, (VALUE)args, &state);
11820 if (state) {
11821 close(pipes[1]);
11822 if (!NIL_P(r)) rb_io_close(r);
11823 rb_jump_tag(state);
11824 }
11825 GetOpenFile(w, fptr2);
11826 rb_io_synchronized(fptr2);
11827
11828 extract_binmode(opt, &fmode);
11829
11830 if ((fmode & FMODE_BINMODE) && NIL_P(v1)) {
11833 }
11834
11835#if DEFAULT_TEXTMODE
11836 if ((fptr->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
11837 fptr->mode &= ~FMODE_TEXTMODE;
11838 setmode(fptr->fd, O_BINARY);
11839 }
11840#if RUBY_CRLF_ENVIRONMENT
11843 }
11844#endif
11845#endif
11846 fptr->mode |= fmode;
11847#if DEFAULT_TEXTMODE
11848 if ((fptr2->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
11849 fptr2->mode &= ~FMODE_TEXTMODE;
11850 setmode(fptr2->fd, O_BINARY);
11851 }
11852#endif
11853 fptr2->mode |= fmode;
11854
11855 ret = rb_assoc_new(r, w);
11856 if (rb_block_given_p()) {
11857 VALUE rw[2];
11858 rw[0] = r;
11859 rw[1] = w;
11860 return rb_ensure(rb_yield, ret, pipe_pair_close, (VALUE)rw);
11861 }
11862 return ret;
11863}
11864
11866 int argc;
11867 VALUE *argv;
11868 VALUE io;
11869};
11870
11871static void
11872open_key_args(VALUE klass, int argc, VALUE *argv, VALUE opt, struct foreach_arg *arg)
11873{
11874 VALUE path, v;
11875 VALUE vmode = Qnil, vperm = Qnil;
11876
11877 path = *argv++;
11878 argc--;
11879 FilePathValue(path);
11880 arg->io = 0;
11881 arg->argc = argc;
11882 arg->argv = argv;
11883 if (NIL_P(opt)) {
11884 vmode = INT2NUM(O_RDONLY);
11885 vperm = INT2FIX(0666);
11886 }
11887 else if (!NIL_P(v = rb_hash_aref(opt, sym_open_args))) {
11888 int n;
11889
11890 v = rb_to_array_type(v);
11891 n = RARRAY_LENINT(v);
11892 rb_check_arity(n, 0, 3); /* rb_io_open */
11893 rb_scan_args_kw(RB_SCAN_ARGS_LAST_HASH_KEYWORDS, n, RARRAY_CONST_PTR(v), "02:", &vmode, &vperm, &opt);
11894 }
11895 arg->io = rb_io_open(klass, path, vmode, vperm, opt);
11896}
11897
11898static VALUE
11899io_s_foreach(VALUE v)
11900{
11901 struct getline_arg *arg = (void *)v;
11902 VALUE str;
11903
11904 if (arg->limit == 0)
11905 rb_raise(rb_eArgError, "invalid limit: 0 for foreach");
11906 while (!NIL_P(str = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, arg->io))) {
11907 rb_lastline_set(str);
11908 rb_yield(str);
11909 }
11911 return Qnil;
11912}
11913
11914/*
11915 * call-seq:
11916 * IO.foreach(path, sep = $/, **opts) {|line| block } -> nil
11917 * IO.foreach(path, limit, **opts) {|line| block } -> nil
11918 * IO.foreach(path, sep, limit, **opts) {|line| block } -> nil
11919 * IO.foreach(...) -> an_enumerator
11920 *
11921 * Calls the block with each successive line read from the stream.
11922 *
11923 * When called from class \IO (but not subclasses of \IO),
11924 * this method has potential security vulnerabilities if called with untrusted input;
11925 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
11926 *
11927 * The first argument must be a string that is the path to a file.
11928 *
11929 * With only argument +path+ given, parses lines from the file at the given +path+,
11930 * as determined by the default line separator,
11931 * and calls the block with each successive line:
11932 *
11933 * File.foreach('t.txt') {|line| p line }
11934 *
11935 * Output: the same as above.
11936 *
11937 * For both forms, command and path, the remaining arguments are the same.
11938 *
11939 * With argument +sep+ given, parses lines as determined by that line separator
11940 * (see {Line Separator}[rdoc-ref:IO@Line+Separator]):
11941 *
11942 * File.foreach('t.txt', 'li') {|line| p line }
11943 *
11944 * Output:
11945 *
11946 * "First li"
11947 * "ne\nSecond li"
11948 * "ne\n\nThird li"
11949 * "ne\nFourth li"
11950 * "ne\n"
11951 *
11952 * Each paragraph:
11953 *
11954 * File.foreach('t.txt', '') {|paragraph| p paragraph }
11955 *
11956 * Output:
11957 *
11958 * "First line\nSecond line\n\n"
11959 * "Third line\nFourth line\n"
11960 *
11961 * With argument +limit+ given, parses lines as determined by the default
11962 * line separator and the given line-length limit
11963 * (see {Line Limit}[rdoc-ref:IO@Line+Limit]):
11964 *
11965 * File.foreach('t.txt', 7) {|line| p line }
11966 *
11967 * Output:
11968 *
11969 * "First l"
11970 * "ine\n"
11971 * "Second "
11972 * "line\n"
11973 * "\n"
11974 * "Third l"
11975 * "ine\n"
11976 * "Fourth l"
11977 * "line\n"
11978 *
11979 * With arguments +sep+ and +limit+ given,
11980 * parses lines as determined by the given
11981 * line separator and the given line-length limit
11982 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]):
11983 *
11984 * Optional keyword arguments +opts+ specify:
11985 *
11986 * - {Open Options}[rdoc-ref:IO@Open+Options].
11987 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
11988 * - {Line Options}[rdoc-ref:IO@Line+IO].
11989 *
11990 * Returns an Enumerator if no block is given.
11991 *
11992 */
11993
11994static VALUE
11995rb_io_s_foreach(int argc, VALUE *argv, VALUE self)
11996{
11997 VALUE opt;
11998 int orig_argc = argc;
11999 struct foreach_arg arg;
12000 struct getline_arg garg;
12001
12002 argc = rb_scan_args(argc, argv, "12:", NULL, NULL, NULL, &opt);
12003 RETURN_ENUMERATOR(self, orig_argc, argv);
12004 extract_getline_args(argc-1, argv+1, &garg);
12005 open_key_args(self, argc, argv, opt, &arg);
12006 if (NIL_P(arg.io)) return Qnil;
12007 extract_getline_opts(opt, &garg);
12008 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12009 return rb_ensure(io_s_foreach, (VALUE)&garg, rb_io_close, arg.io);
12010}
12011
12012static VALUE
12013io_s_readlines(VALUE v)
12014{
12015 struct getline_arg *arg = (void *)v;
12016 return io_readlines(arg, arg->io);
12017}
12018
12019/*
12020 * call-seq:
12021 * IO.readlines(path, sep = $/, **opts) -> array
12022 * IO.readlines(path, limit, **opts) -> array
12023 * IO.readlines(path, sep, limit, **opts) -> array
12024 *
12025 * Returns an array of all lines read from the stream.
12026 *
12027 * When called from class \IO (but not subclasses of \IO),
12028 * this method has potential security vulnerabilities if called with untrusted input;
12029 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12030 *
12031 * The first argument must be a string that is the path to a file.
12032 *
12033 * With only argument +path+ given, parses lines from the file at the given +path+,
12034 * as determined by the default line separator,
12035 * and returns those lines in an array:
12036 *
12037 * IO.readlines('t.txt')
12038 * # => ["First line\n", "Second line\n", "\n", "Third line\n", "Fourth line\n"]
12039 *
12040 * With argument +sep+ given, parses lines as determined by that line separator
12041 * (see {Line Separator}[rdoc-ref:IO@Line+Separator]):
12042 *
12043 * # Ordinary separator.
12044 * IO.readlines('t.txt', 'li')
12045 * # =>["First li", "ne\nSecond li", "ne\n\nThird li", "ne\nFourth li", "ne\n"]
12046 * # Get-paragraphs separator.
12047 * IO.readlines('t.txt', '')
12048 * # => ["First line\nSecond line\n\n", "Third line\nFourth line\n"]
12049 * # Get-all separator.
12050 * IO.readlines('t.txt', nil)
12051 * # => ["First line\nSecond line\n\nThird line\nFourth line\n"]
12052 *
12053 * With argument +limit+ given, parses lines as determined by the default
12054 * line separator and the given line-length limit
12055 * (see {Line Limit}[rdoc-ref:IO@Line+Limit]):
12056 *
12057 * IO.readlines('t.txt', 7)
12058 * # => ["First l", "ine\n", "Second ", "line\n", "\n", "Third l", "ine\n", "Fourth ", "line\n"]
12059 *
12060 * With arguments +sep+ and +limit+ given,
12061 * parses lines as determined by the given
12062 * line separator and the given line-length limit
12063 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]):
12064 *
12065 * Optional keyword arguments +opts+ specify:
12066 *
12067 * - {Open Options}[rdoc-ref:IO@Open+Options].
12068 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12069 * - {Line Options}[rdoc-ref:IO@Line+IO].
12070 *
12071 */
12072
12073static VALUE
12074rb_io_s_readlines(int argc, VALUE *argv, VALUE io)
12075{
12076 VALUE opt;
12077 struct foreach_arg arg;
12078 struct getline_arg garg;
12079
12080 argc = rb_scan_args(argc, argv, "12:", NULL, NULL, NULL, &opt);
12081 extract_getline_args(argc-1, argv+1, &garg);
12082 open_key_args(io, argc, argv, opt, &arg);
12083 if (NIL_P(arg.io)) return Qnil;
12084 extract_getline_opts(opt, &garg);
12085 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12086 return rb_ensure(io_s_readlines, (VALUE)&garg, rb_io_close, arg.io);
12087}
12088
12089static VALUE
12090io_s_read(VALUE v)
12091{
12092 struct foreach_arg *arg = (void *)v;
12093 return io_read(arg->argc, arg->argv, arg->io);
12094}
12095
12096struct seek_arg {
12097 VALUE io;
12098 VALUE offset;
12099 int mode;
12100};
12101
12102static VALUE
12103seek_before_access(VALUE argp)
12104{
12105 struct seek_arg *arg = (struct seek_arg *)argp;
12106 rb_io_binmode(arg->io);
12107 return rb_io_seek(arg->io, arg->offset, arg->mode);
12108}
12109
12110/*
12111 * call-seq:
12112 * IO.read(path, length = nil, offset = 0, **opts) -> string or nil
12113 *
12114 * Opens the stream, reads and returns some or all of its content,
12115 * and closes the stream; returns +nil+ if no bytes were read.
12116 *
12117 * When called from class \IO (but not subclasses of \IO),
12118 * this method has potential security vulnerabilities if called with untrusted input;
12119 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12120 *
12121 * The first argument must be a string that is the path to a file.
12122 *
12123 * With only argument +path+ given, reads in text mode and returns the entire content
12124 * of the file at the given path:
12125 *
12126 * IO.read('t.txt')
12127 * # => "First line\nSecond line\n\nThird line\nFourth line\n"
12128 *
12129 * On Windows, text mode can terminate reading and leave bytes in the file
12130 * unread when encountering certain special bytes. Consider using
12131 * IO.binread if all bytes in the file should be read.
12132 *
12133 * With argument +length+, returns +length+ bytes if available:
12134 *
12135 * IO.read('t.txt', 7) # => "First l"
12136 * IO.read('t.txt', 700)
12137 * # => "First line\r\nSecond line\r\n\r\nFourth line\r\nFifth line\r\n"
12138 *
12139 * With arguments +length+ and +offset+, returns +length+ bytes
12140 * if available, beginning at the given +offset+:
12141 *
12142 * IO.read('t.txt', 10, 2) # => "rst line\nS"
12143 * IO.read('t.txt', 10, 200) # => nil
12144 *
12145 * Optional keyword arguments +opts+ specify:
12146 *
12147 * - {Open Options}[rdoc-ref:IO@Open+Options].
12148 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12149 *
12150 */
12151
12152static VALUE
12153rb_io_s_read(int argc, VALUE *argv, VALUE io)
12154{
12155 VALUE opt, offset;
12156 long off;
12157 struct foreach_arg arg;
12158
12159 argc = rb_scan_args(argc, argv, "13:", NULL, NULL, &offset, NULL, &opt);
12160 if (!NIL_P(offset) && (off = NUM2LONG(offset)) < 0) {
12161 rb_raise(rb_eArgError, "negative offset %ld given", off);
12162 }
12163 open_key_args(io, argc, argv, opt, &arg);
12164 if (NIL_P(arg.io)) return Qnil;
12165 if (!NIL_P(offset)) {
12166 struct seek_arg sarg;
12167 int state = 0;
12168 sarg.io = arg.io;
12169 sarg.offset = offset;
12170 sarg.mode = SEEK_SET;
12171 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12172 if (state) {
12173 rb_io_close(arg.io);
12174 rb_jump_tag(state);
12175 }
12176 if (arg.argc == 2) arg.argc = 1;
12177 }
12178 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
12179}
12180
12181/*
12182 * call-seq:
12183 * IO.binread(path, length = nil, offset = 0) -> string or nil
12184 *
12185 * Behaves like IO.read, except that the stream is opened in binary mode
12186 * with ASCII-8BIT encoding.
12187 *
12188 * When called from class \IO (but not subclasses of \IO),
12189 * this method has potential security vulnerabilities if called with untrusted input;
12190 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12191 *
12192 */
12193
12194static VALUE
12195rb_io_s_binread(int argc, VALUE *argv, VALUE io)
12196{
12197 VALUE offset;
12198 struct foreach_arg arg;
12199 enum {
12201 oflags = O_RDONLY
12202#ifdef O_BINARY
12203 |O_BINARY
12204#endif
12205 };
12206 struct rb_io_encoding convconfig = {NULL, NULL, 0, Qnil};
12207
12208 rb_scan_args(argc, argv, "12", NULL, NULL, &offset);
12209 FilePathValue(argv[0]);
12210 convconfig.enc = rb_ascii8bit_encoding();
12211 arg.io = rb_io_open_generic(io, argv[0], oflags, fmode, &convconfig, 0);
12212 if (NIL_P(arg.io)) return Qnil;
12213 arg.argv = argv+1;
12214 arg.argc = (argc > 1) ? 1 : 0;
12215 if (!NIL_P(offset)) {
12216 struct seek_arg sarg;
12217 int state = 0;
12218 sarg.io = arg.io;
12219 sarg.offset = offset;
12220 sarg.mode = SEEK_SET;
12221 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12222 if (state) {
12223 rb_io_close(arg.io);
12224 rb_jump_tag(state);
12225 }
12226 }
12227 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
12228}
12229
12230static VALUE
12231io_s_write0(VALUE v)
12232{
12233 struct write_arg *arg = (void *)v;
12234 return io_write(arg->io,arg->str,arg->nosync);
12235}
12236
12237static VALUE
12238io_s_write(int argc, VALUE *argv, VALUE klass, int binary)
12239{
12240 VALUE string, offset, opt;
12241 struct foreach_arg arg;
12242 struct write_arg warg;
12243
12244 rb_scan_args(argc, argv, "21:", NULL, &string, &offset, &opt);
12245
12246 if (NIL_P(opt)) opt = rb_hash_new();
12247 else opt = rb_hash_dup(opt);
12248
12249
12250 if (NIL_P(rb_hash_aref(opt,sym_mode))) {
12251 int mode = O_WRONLY|O_CREAT;
12252#ifdef O_BINARY
12253 if (binary) mode |= O_BINARY;
12254#endif
12255 if (NIL_P(offset)) mode |= O_TRUNC;
12256 rb_hash_aset(opt,sym_mode,INT2NUM(mode));
12257 }
12258 open_key_args(klass, argc, argv, opt, &arg);
12259
12260#ifndef O_BINARY
12261 if (binary) rb_io_binmode_m(arg.io);
12262#endif
12263
12264 if (NIL_P(arg.io)) return Qnil;
12265 if (!NIL_P(offset)) {
12266 struct seek_arg sarg;
12267 int state = 0;
12268 sarg.io = arg.io;
12269 sarg.offset = offset;
12270 sarg.mode = SEEK_SET;
12271 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12272 if (state) {
12273 rb_io_close(arg.io);
12274 rb_jump_tag(state);
12275 }
12276 }
12277
12278 warg.io = arg.io;
12279 warg.str = string;
12280 warg.nosync = 0;
12281
12282 return rb_ensure(io_s_write0, (VALUE)&warg, rb_io_close, arg.io);
12283}
12284
12285/*
12286 * call-seq:
12287 * IO.write(path, data, offset = 0, **opts) -> integer
12288 *
12289 * Opens the stream, writes the given +data+ to it,
12290 * and closes the stream; returns the number of bytes written.
12291 *
12292 * When called from class \IO (but not subclasses of \IO),
12293 * this method has potential security vulnerabilities if called with untrusted input;
12294 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12295 *
12296 * The first argument must be a string that is the path to a file.
12297 *
12298 * With only argument +path+ given, writes the given +data+ to the file at that path:
12299 *
12300 * IO.write('t.tmp', 'abc') # => 3
12301 * File.read('t.tmp') # => "abc"
12302 *
12303 * If +offset+ is zero (the default), the file is overwritten:
12304 *
12305 * IO.write('t.tmp', 'A') # => 1
12306 * File.read('t.tmp') # => "A"
12307 *
12308 * If +offset+ in within the file content, the file is partly overwritten:
12309 *
12310 * IO.write('t.tmp', 'abcdef') # => 3
12311 * File.read('t.tmp') # => "abcdef"
12312 * # Offset within content.
12313 * IO.write('t.tmp', '012', 2) # => 3
12314 * File.read('t.tmp') # => "ab012f"
12315 *
12316 * If +offset+ is outside the file content,
12317 * the file is padded with null characters <tt>"\u0000"</tt>:
12318 *
12319 * IO.write('t.tmp', 'xyz', 10) # => 3
12320 * File.read('t.tmp') # => "ab012f\u0000\u0000\u0000\u0000xyz"
12321 *
12322 * Optional keyword arguments +opts+ specify:
12323 *
12324 * - {Open Options}[rdoc-ref:IO@Open+Options].
12325 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12326 *
12327 */
12328
12329static VALUE
12330rb_io_s_write(int argc, VALUE *argv, VALUE io)
12331{
12332 return io_s_write(argc, argv, io, 0);
12333}
12334
12335/*
12336 * call-seq:
12337 * IO.binwrite(path, string, offset = 0) -> integer
12338 *
12339 * Behaves like IO.write, except that the stream is opened in binary mode
12340 * with ASCII-8BIT encoding.
12341 *
12342 * When called from class \IO (but not subclasses of \IO),
12343 * this method has potential security vulnerabilities if called with untrusted input;
12344 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12345 *
12346 */
12347
12348static VALUE
12349rb_io_s_binwrite(int argc, VALUE *argv, VALUE io)
12350{
12351 return io_s_write(argc, argv, io, 1);
12352}
12353
12355 VALUE src;
12356 VALUE dst;
12357 rb_off_t copy_length; /* (rb_off_t)-1 if not specified */
12358 rb_off_t src_offset; /* (rb_off_t)-1 if not specified */
12359
12360 rb_io_t *src_fptr;
12361 rb_io_t *dst_fptr;
12362 unsigned close_src : 1;
12363 unsigned close_dst : 1;
12364 int error_no;
12365 rb_off_t total;
12366 const char *syserr;
12367 const char *notimp;
12368 VALUE th;
12369 struct stat src_stat;
12370 struct stat dst_stat;
12371#ifdef HAVE_FCOPYFILE
12372 copyfile_state_t copyfile_state;
12373#endif
12374};
12375
12376static void *
12377exec_interrupts(void *arg)
12378{
12379 VALUE th = (VALUE)arg;
12380 rb_thread_execute_interrupts(th);
12381 return NULL;
12382}
12383
12384/*
12385 * returns TRUE if the preceding system call was interrupted
12386 * so we can continue. If the thread was interrupted, we
12387 * reacquire the GVL to execute interrupts before continuing.
12388 */
12389static int
12390maygvl_copy_stream_continue_p(int has_gvl, struct copy_stream_struct *stp)
12391{
12392 switch (errno) {
12393 case EINTR:
12394#if defined(ERESTART)
12395 case ERESTART:
12396#endif
12397 if (rb_thread_interrupted(stp->th)) {
12398 if (has_gvl)
12399 rb_thread_execute_interrupts(stp->th);
12400 else
12401 rb_thread_call_with_gvl(exec_interrupts, (void *)stp->th);
12402 }
12403 return TRUE;
12404 }
12405 return FALSE;
12406}
12407
12409 VALUE scheduler;
12410
12411 rb_io_t *fptr;
12412 short events;
12413
12414 VALUE result;
12415};
12416
12417static void *
12418fiber_scheduler_wait_for(void * _arguments)
12419{
12420 struct fiber_scheduler_wait_for_arguments *arguments = (struct fiber_scheduler_wait_for_arguments *)_arguments;
12421
12422 arguments->result = rb_fiber_scheduler_io_wait(arguments->scheduler, arguments->fptr->self, INT2NUM(arguments->events), RUBY_IO_TIMEOUT_DEFAULT);
12423
12424 return NULL;
12425}
12426
12427#if USE_POLL
12428# define IOWAIT_SYSCALL "poll"
12429STATIC_ASSERT(pollin_expected, POLLIN == RB_WAITFD_IN);
12430STATIC_ASSERT(pollout_expected, POLLOUT == RB_WAITFD_OUT);
12431static int
12432nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout)
12433{
12435 if (scheduler != Qnil) {
12436 struct fiber_scheduler_wait_for_arguments args = {.scheduler = scheduler, .fptr = fptr, .events = events};
12437 rb_thread_call_with_gvl(fiber_scheduler_wait_for, &args);
12438 return RTEST(args.result);
12439 }
12440
12441 int fd = fptr->fd;
12442 if (fd == -1) return 0;
12443
12444 struct pollfd fds;
12445
12446 fds.fd = fd;
12447 fds.events = events;
12448
12449 int timeout_milliseconds = -1;
12450
12451 if (timeout) {
12452 timeout_milliseconds = (int)(timeout->tv_sec * 1000) + (int)(timeout->tv_usec / 1000);
12453 }
12454
12455 return poll(&fds, 1, timeout_milliseconds);
12456}
12457#else /* !USE_POLL */
12458# define IOWAIT_SYSCALL "select"
12459static int
12460nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout)
12461{
12463 if (scheduler != Qnil) {
12464 struct fiber_scheduler_wait_for_arguments args = {.scheduler = scheduler, .fptr = fptr, .events = events};
12465 rb_thread_call_with_gvl(fiber_scheduler_wait_for, &args);
12466 return RTEST(args.result);
12467 }
12468
12469 int fd = fptr->fd;
12470
12471 if (fd == -1) {
12472 errno = EBADF;
12473 return -1;
12474 }
12475
12476 rb_fdset_t fds;
12477 int ret;
12478
12479 rb_fd_init(&fds);
12480 rb_fd_set(fd, &fds);
12481
12482 switch (events) {
12483 case RB_WAITFD_IN:
12484 ret = rb_fd_select(fd + 1, &fds, 0, 0, timeout);
12485 break;
12486 case RB_WAITFD_OUT:
12487 ret = rb_fd_select(fd + 1, 0, &fds, 0, timeout);
12488 break;
12489 default:
12490 VM_UNREACHABLE(nogvl_wait_for);
12491 }
12492
12493 rb_fd_term(&fds);
12494
12495 // On timeout, this returns 0.
12496 return ret;
12497}
12498#endif /* !USE_POLL */
12499
12500static int
12501maygvl_copy_stream_wait_read(int has_gvl, struct copy_stream_struct *stp)
12502{
12503 int ret;
12504
12505 do {
12506 if (has_gvl) {
12508 }
12509 else {
12510 ret = nogvl_wait_for(stp->th, stp->src_fptr, RB_WAITFD_IN, NULL);
12511 }
12512 } while (ret < 0 && maygvl_copy_stream_continue_p(has_gvl, stp));
12513
12514 if (ret < 0) {
12515 stp->syserr = IOWAIT_SYSCALL;
12516 stp->error_no = errno;
12517 return ret;
12518 }
12519 return 0;
12520}
12521
12522static int
12523nogvl_copy_stream_wait_write(struct copy_stream_struct *stp)
12524{
12525 int ret;
12526
12527 do {
12528 ret = nogvl_wait_for(stp->th, stp->dst_fptr, RB_WAITFD_OUT, NULL);
12529 } while (ret < 0 && maygvl_copy_stream_continue_p(0, stp));
12530
12531 if (ret < 0) {
12532 stp->syserr = IOWAIT_SYSCALL;
12533 stp->error_no = errno;
12534 return ret;
12535 }
12536 return 0;
12537}
12538
12539#ifdef USE_COPY_FILE_RANGE
12540
12541static ssize_t
12542simple_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)
12543{
12544#ifdef HAVE_COPY_FILE_RANGE
12545 return copy_file_range(in_fd, in_offset, out_fd, out_offset, count, flags);
12546#else
12547 return syscall(__NR_copy_file_range, in_fd, in_offset, out_fd, out_offset, count, flags);
12548#endif
12549}
12550
12551static int
12552nogvl_copy_file_range(struct copy_stream_struct *stp)
12553{
12554 ssize_t ss;
12555 rb_off_t src_size;
12556 rb_off_t copy_length, src_offset, *src_offset_ptr;
12557
12558 if (!S_ISREG(stp->src_stat.st_mode))
12559 return 0;
12560
12561 src_size = stp->src_stat.st_size;
12562 src_offset = stp->src_offset;
12563 if (src_offset >= (rb_off_t)0) {
12564 src_offset_ptr = &src_offset;
12565 }
12566 else {
12567 src_offset_ptr = NULL; /* if src_offset_ptr is NULL, then bytes are read from in_fd starting from the file offset */
12568 }
12569
12570 copy_length = stp->copy_length;
12571 if (copy_length < (rb_off_t)0) {
12572 if (src_offset < (rb_off_t)0) {
12573 rb_off_t current_offset;
12574 errno = 0;
12575 current_offset = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12576 if (current_offset < (rb_off_t)0 && errno) {
12577 stp->syserr = "lseek";
12578 stp->error_no = errno;
12579 return (int)current_offset;
12580 }
12581 copy_length = src_size - current_offset;
12582 }
12583 else {
12584 copy_length = src_size - src_offset;
12585 }
12586 }
12587
12588 retry_copy_file_range:
12589# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12590 /* we are limited by the 32-bit ssize_t return value on 32-bit */
12591 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12592# else
12593 ss = (ssize_t)copy_length;
12594# endif
12595 ss = simple_copy_file_range(stp->src_fptr->fd, src_offset_ptr, stp->dst_fptr->fd, NULL, ss, 0);
12596 if (0 < ss) {
12597 stp->total += ss;
12598 copy_length -= ss;
12599 if (0 < copy_length) {
12600 goto retry_copy_file_range;
12601 }
12602 }
12603 if (ss < 0) {
12604 if (maygvl_copy_stream_continue_p(0, stp)) {
12605 goto retry_copy_file_range;
12606 }
12607 switch (errno) {
12608 case EINVAL:
12609 case EPERM: /* copy_file_range(2) doesn't exist (may happen in
12610 docker container) */
12611#ifdef ENOSYS
12612 case ENOSYS:
12613#endif
12614#ifdef EXDEV
12615 case EXDEV: /* in_fd and out_fd are not on the same filesystem */
12616#endif
12617 return 0;
12618 case EAGAIN:
12619#if EWOULDBLOCK != EAGAIN
12620 case EWOULDBLOCK:
12621#endif
12622 {
12623 int ret = nogvl_copy_stream_wait_write(stp);
12624 if (ret < 0) return ret;
12625 }
12626 goto retry_copy_file_range;
12627 case EBADF:
12628 {
12629 int e = errno;
12630 int flags = fcntl(stp->dst_fptr->fd, F_GETFL);
12631
12632 if (flags != -1 && flags & O_APPEND) {
12633 return 0;
12634 }
12635 errno = e;
12636 }
12637 }
12638 stp->syserr = "copy_file_range";
12639 stp->error_no = errno;
12640 return (int)ss;
12641 }
12642 return 1;
12643}
12644#endif
12645
12646#ifdef HAVE_FCOPYFILE
12647static int
12648nogvl_fcopyfile(struct copy_stream_struct *stp)
12649{
12650 rb_off_t cur, ss = 0;
12651 const rb_off_t src_offset = stp->src_offset;
12652 int ret;
12653
12654 if (stp->copy_length >= (rb_off_t)0) {
12655 /* copy_length can't be specified in fcopyfile(3) */
12656 return 0;
12657 }
12658
12659 if (!S_ISREG(stp->src_stat.st_mode))
12660 return 0;
12661
12662 if (!S_ISREG(stp->dst_stat.st_mode))
12663 return 0;
12664 if (lseek(stp->dst_fptr->fd, 0, SEEK_CUR) > (rb_off_t)0) /* if dst IO was already written */
12665 return 0;
12666 if (fcntl(stp->dst_fptr->fd, F_GETFL) & O_APPEND) {
12667 /* fcopyfile(3) appends src IO to dst IO and then truncates
12668 * dst IO to src IO's original size. */
12669 rb_off_t end = lseek(stp->dst_fptr->fd, 0, SEEK_END);
12670 lseek(stp->dst_fptr->fd, 0, SEEK_SET);
12671 if (end > (rb_off_t)0) return 0;
12672 }
12673
12674 if (src_offset > (rb_off_t)0) {
12675 rb_off_t r;
12676
12677 /* get current offset */
12678 errno = 0;
12679 cur = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12680 if (cur < (rb_off_t)0 && errno) {
12681 stp->error_no = errno;
12682 return 1;
12683 }
12684
12685 errno = 0;
12686 r = lseek(stp->src_fptr->fd, src_offset, SEEK_SET);
12687 if (r < (rb_off_t)0 && errno) {
12688 stp->error_no = errno;
12689 return 1;
12690 }
12691 }
12692
12693 stp->copyfile_state = copyfile_state_alloc(); /* this will be freed by copy_stream_finalize() */
12694 ret = fcopyfile(stp->src_fptr->fd, stp->dst_fptr->fd, stp->copyfile_state, COPYFILE_DATA);
12695 copyfile_state_get(stp->copyfile_state, COPYFILE_STATE_COPIED, &ss); /* get copied bytes */
12696
12697 if (ret == 0) { /* success */
12698 stp->total = ss;
12699 if (src_offset > (rb_off_t)0) {
12700 rb_off_t r;
12701 errno = 0;
12702 /* reset offset */
12703 r = lseek(stp->src_fptr->fd, cur, SEEK_SET);
12704 if (r < (rb_off_t)0 && errno) {
12705 stp->error_no = errno;
12706 return 1;
12707 }
12708 }
12709 }
12710 else {
12711 switch (errno) {
12712 case ENOTSUP:
12713 case EPERM:
12714 case EINVAL:
12715 return 0;
12716 }
12717 stp->syserr = "fcopyfile";
12718 stp->error_no = errno;
12719 return (int)ret;
12720 }
12721 return 1;
12722}
12723#endif
12724
12725#ifdef HAVE_SENDFILE
12726
12727# ifdef __linux__
12728# define USE_SENDFILE
12729
12730# ifdef HAVE_SYS_SENDFILE_H
12731# include <sys/sendfile.h>
12732# endif
12733
12734static ssize_t
12735simple_sendfile(int out_fd, int in_fd, rb_off_t *offset, rb_off_t count)
12736{
12737 return sendfile(out_fd, in_fd, offset, (size_t)count);
12738}
12739
12740# elif 0 /* defined(__FreeBSD__) || defined(__DragonFly__) */ || defined(__APPLE__)
12741/* This runs on FreeBSD8.1 r30210, but sendfiles blocks its execution
12742 * without cpuset -l 0.
12743 */
12744# define USE_SENDFILE
12745
12746static ssize_t
12747simple_sendfile(int out_fd, int in_fd, rb_off_t *offset, rb_off_t count)
12748{
12749 int r;
12750 rb_off_t pos = offset ? *offset : lseek(in_fd, 0, SEEK_CUR);
12751 rb_off_t sbytes;
12752# ifdef __APPLE__
12753 r = sendfile(in_fd, out_fd, pos, &count, NULL, 0);
12754 sbytes = count;
12755# else
12756 r = sendfile(in_fd, out_fd, pos, (size_t)count, NULL, &sbytes, 0);
12757# endif
12758 if (r != 0 && sbytes == 0) return r;
12759 if (offset) {
12760 *offset += sbytes;
12761 }
12762 else {
12763 lseek(in_fd, sbytes, SEEK_CUR);
12764 }
12765 return (ssize_t)sbytes;
12766}
12767
12768# endif
12769
12770#endif
12771
12772#ifdef USE_SENDFILE
12773static int
12774nogvl_copy_stream_sendfile(struct copy_stream_struct *stp)
12775{
12776 ssize_t ss;
12777 rb_off_t src_size;
12778 rb_off_t copy_length;
12779 rb_off_t src_offset;
12780 int use_pread;
12781
12782 if (!S_ISREG(stp->src_stat.st_mode))
12783 return 0;
12784
12785 src_size = stp->src_stat.st_size;
12786#ifndef __linux__
12787 if ((stp->dst_stat.st_mode & S_IFMT) != S_IFSOCK)
12788 return 0;
12789#endif
12790
12791 src_offset = stp->src_offset;
12792 use_pread = src_offset >= (rb_off_t)0;
12793
12794 copy_length = stp->copy_length;
12795 if (copy_length < (rb_off_t)0) {
12796 if (use_pread)
12797 copy_length = src_size - src_offset;
12798 else {
12799 rb_off_t cur;
12800 errno = 0;
12801 cur = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12802 if (cur < (rb_off_t)0 && errno) {
12803 stp->syserr = "lseek";
12804 stp->error_no = errno;
12805 return (int)cur;
12806 }
12807 copy_length = src_size - cur;
12808 }
12809 }
12810
12811 retry_sendfile:
12812# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12813 /* we are limited by the 32-bit ssize_t return value on 32-bit */
12814 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12815# else
12816 ss = (ssize_t)copy_length;
12817# endif
12818 if (use_pread) {
12819 ss = simple_sendfile(stp->dst_fptr->fd, stp->src_fptr->fd, &src_offset, ss);
12820 }
12821 else {
12822 ss = simple_sendfile(stp->dst_fptr->fd, stp->src_fptr->fd, NULL, ss);
12823 }
12824 if (0 < ss) {
12825 stp->total += ss;
12826 copy_length -= ss;
12827 if (0 < copy_length) {
12828 goto retry_sendfile;
12829 }
12830 }
12831 if (ss < 0) {
12832 if (maygvl_copy_stream_continue_p(0, stp))
12833 goto retry_sendfile;
12834 switch (errno) {
12835 case EINVAL:
12836#ifdef ENOSYS
12837 case ENOSYS:
12838#endif
12839#ifdef EOPNOTSUP
12840 /* some RedHat kernels may return EOPNOTSUP on an NFS mount.
12841 see also: [Feature #16965] */
12842 case EOPNOTSUP:
12843#endif
12844 return 0;
12845 case EAGAIN:
12846#if EWOULDBLOCK != EAGAIN
12847 case EWOULDBLOCK:
12848#endif
12849 {
12850 int ret;
12851#ifndef __linux__
12852 /*
12853 * Linux requires stp->src_fptr->fd to be a mmap-able (regular) file,
12854 * select() reports regular files to always be "ready", so
12855 * there is no need to select() on it.
12856 * Other OSes may have the same limitation for sendfile() which
12857 * allow us to bypass maygvl_copy_stream_wait_read()...
12858 */
12859 ret = maygvl_copy_stream_wait_read(0, stp);
12860 if (ret < 0) return ret;
12861#endif
12862 ret = nogvl_copy_stream_wait_write(stp);
12863 if (ret < 0) return ret;
12864 }
12865 goto retry_sendfile;
12866 }
12867 stp->syserr = "sendfile";
12868 stp->error_no = errno;
12869 return (int)ss;
12870 }
12871 return 1;
12872}
12873#endif
12874
12875static ssize_t
12876maygvl_read(int has_gvl, rb_io_t *fptr, void *buf, size_t count)
12877{
12878 if (has_gvl)
12879 return rb_io_read_memory(fptr, buf, count);
12880 else
12881 return read(fptr->fd, buf, count);
12882}
12883
12884static ssize_t
12885maygvl_copy_stream_read(int has_gvl, struct copy_stream_struct *stp, char *buf, size_t len, rb_off_t offset)
12886{
12887 ssize_t ss;
12888 retry_read:
12889 if (offset < (rb_off_t)0) {
12890 ss = maygvl_read(has_gvl, stp->src_fptr, buf, len);
12891 }
12892 else {
12893 ss = pread(stp->src_fptr->fd, buf, len, offset);
12894 }
12895 if (ss == 0) {
12896 return 0;
12897 }
12898 if (ss < 0) {
12899 if (maygvl_copy_stream_continue_p(has_gvl, stp))
12900 goto retry_read;
12901 switch (errno) {
12902 case EAGAIN:
12903#if EWOULDBLOCK != EAGAIN
12904 case EWOULDBLOCK:
12905#endif
12906 {
12907 int ret = maygvl_copy_stream_wait_read(has_gvl, stp);
12908 if (ret < 0) return ret;
12909 }
12910 goto retry_read;
12911#ifdef ENOSYS
12912 case ENOSYS:
12913 stp->notimp = "pread";
12914 return ss;
12915#endif
12916 }
12917 stp->syserr = offset < (rb_off_t)0 ? "read" : "pread";
12918 stp->error_no = errno;
12919 }
12920 return ss;
12921}
12922
12923static int
12924nogvl_copy_stream_write(struct copy_stream_struct *stp, char *buf, size_t len)
12925{
12926 ssize_t ss;
12927 int off = 0;
12928 while (len) {
12929 ss = write(stp->dst_fptr->fd, buf+off, len);
12930 if (ss < 0) {
12931 if (maygvl_copy_stream_continue_p(0, stp))
12932 continue;
12933 if (io_again_p(errno)) {
12934 int ret = nogvl_copy_stream_wait_write(stp);
12935 if (ret < 0) return ret;
12936 continue;
12937 }
12938 stp->syserr = "write";
12939 stp->error_no = errno;
12940 return (int)ss;
12941 }
12942 off += (int)ss;
12943 len -= (int)ss;
12944 stp->total += ss;
12945 }
12946 return 0;
12947}
12948
12949static void
12950nogvl_copy_stream_read_write(struct copy_stream_struct *stp)
12951{
12952 char buf[1024*16];
12953 size_t len;
12954 ssize_t ss;
12955 int ret;
12956 rb_off_t copy_length;
12957 rb_off_t src_offset;
12958 int use_eof;
12959 int use_pread;
12960
12961 copy_length = stp->copy_length;
12962 use_eof = copy_length < (rb_off_t)0;
12963 src_offset = stp->src_offset;
12964 use_pread = src_offset >= (rb_off_t)0;
12965
12966 if (use_pread && stp->close_src) {
12967 rb_off_t r;
12968 errno = 0;
12969 r = lseek(stp->src_fptr->fd, src_offset, SEEK_SET);
12970 if (r < (rb_off_t)0 && errno) {
12971 stp->syserr = "lseek";
12972 stp->error_no = errno;
12973 return;
12974 }
12975 src_offset = (rb_off_t)-1;
12976 use_pread = 0;
12977 }
12978
12979 while (use_eof || 0 < copy_length) {
12980 if (!use_eof && copy_length < (rb_off_t)sizeof(buf)) {
12981 len = (size_t)copy_length;
12982 }
12983 else {
12984 len = sizeof(buf);
12985 }
12986 if (use_pread) {
12987 ss = maygvl_copy_stream_read(0, stp, buf, len, src_offset);
12988 if (0 < ss)
12989 src_offset += ss;
12990 }
12991 else {
12992 ss = maygvl_copy_stream_read(0, stp, buf, len, (rb_off_t)-1);
12993 }
12994 if (ss <= 0) /* EOF or error */
12995 return;
12996
12997 ret = nogvl_copy_stream_write(stp, buf, ss);
12998 if (ret < 0)
12999 return;
13000
13001 if (!use_eof)
13002 copy_length -= ss;
13003 }
13004}
13005
13006static void *
13007nogvl_copy_stream_func(void *arg)
13008{
13009 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13010#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13011 int ret;
13012#endif
13013
13014#ifdef USE_COPY_FILE_RANGE
13015 ret = nogvl_copy_file_range(stp);
13016 if (ret != 0)
13017 goto finish; /* error or success */
13018#endif
13019
13020#ifdef HAVE_FCOPYFILE
13021 ret = nogvl_fcopyfile(stp);
13022 if (ret != 0)
13023 goto finish; /* error or success */
13024#endif
13025
13026#ifdef USE_SENDFILE
13027 ret = nogvl_copy_stream_sendfile(stp);
13028 if (ret != 0)
13029 goto finish; /* error or success */
13030#endif
13031
13032 nogvl_copy_stream_read_write(stp);
13033
13034#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13035 finish:
13036#endif
13037 return 0;
13038}
13039
13040static VALUE
13041copy_stream_fallback_body(VALUE arg)
13042{
13043 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13044 const int buflen = 16*1024;
13045 VALUE n;
13046 VALUE buf = rb_str_buf_new(buflen);
13047 rb_off_t rest = stp->copy_length;
13048 rb_off_t off = stp->src_offset;
13049 ID read_method = id_readpartial;
13050
13051 if (!stp->src_fptr) {
13052 if (!rb_respond_to(stp->src, read_method)) {
13053 read_method = id_read;
13054 }
13055 }
13056
13057 while (1) {
13058 long numwrote;
13059 long l;
13060 if (stp->copy_length < (rb_off_t)0) {
13061 l = buflen;
13062 }
13063 else {
13064 if (rest == 0) {
13065 rb_str_resize(buf, 0);
13066 break;
13067 }
13068 l = buflen < rest ? buflen : (long)rest;
13069 }
13070 if (!stp->src_fptr) {
13071 VALUE rc = rb_funcall(stp->src, read_method, 2, INT2FIX(l), buf);
13072
13073 if (read_method == id_read && NIL_P(rc))
13074 break;
13075 }
13076 else {
13077 ssize_t ss;
13078 rb_str_resize(buf, buflen);
13079 ss = maygvl_copy_stream_read(1, stp, RSTRING_PTR(buf), l, off);
13080 rb_str_resize(buf, ss > 0 ? ss : 0);
13081 if (ss < 0)
13082 return Qnil;
13083 if (ss == 0)
13084 rb_eof_error();
13085 if (off >= (rb_off_t)0)
13086 off += ss;
13087 }
13088 n = rb_io_write(stp->dst, buf);
13089 numwrote = NUM2LONG(n);
13090 stp->total += numwrote;
13091 rest -= numwrote;
13092 if (read_method == id_read && RSTRING_LEN(buf) == 0) {
13093 break;
13094 }
13095 }
13096
13097 return Qnil;
13098}
13099
13100static VALUE
13101copy_stream_fallback(struct copy_stream_struct *stp)
13102{
13103 if (!stp->src_fptr && stp->src_offset >= (rb_off_t)0) {
13104 rb_raise(rb_eArgError, "cannot specify src_offset for non-IO");
13105 }
13106 rb_rescue2(copy_stream_fallback_body, (VALUE)stp,
13107 (VALUE (*) (VALUE, VALUE))0, (VALUE)0,
13108 rb_eEOFError, (VALUE)0);
13109 return Qnil;
13110}
13111
13112static VALUE
13113copy_stream_body(VALUE arg)
13114{
13115 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13116 VALUE src_io = stp->src, dst_io = stp->dst;
13117 const int common_oflags = 0
13118#ifdef O_NOCTTY
13119 | O_NOCTTY
13120#endif
13121 ;
13122
13123 stp->th = rb_thread_current();
13124
13125 stp->total = 0;
13126
13127 if (src_io == argf ||
13128 !(RB_TYPE_P(src_io, T_FILE) ||
13129 RB_TYPE_P(src_io, T_STRING) ||
13130 rb_respond_to(src_io, rb_intern("to_path")))) {
13131 stp->src_fptr = NULL;
13132 }
13133 else {
13134 int stat_ret;
13135 VALUE tmp_io = rb_io_check_io(src_io);
13136 if (!NIL_P(tmp_io)) {
13137 src_io = tmp_io;
13138 }
13139 else if (!RB_TYPE_P(src_io, T_FILE)) {
13140 VALUE args[2];
13141 FilePathValue(src_io);
13142 args[0] = src_io;
13143 args[1] = INT2NUM(O_RDONLY|common_oflags);
13144 src_io = rb_class_new_instance(2, args, rb_cFile);
13145 stp->src = src_io;
13146 stp->close_src = 1;
13147 }
13148 RB_IO_POINTER(src_io, stp->src_fptr);
13149 rb_io_check_byte_readable(stp->src_fptr);
13150
13151 stat_ret = fstat(stp->src_fptr->fd, &stp->src_stat);
13152 if (stat_ret < 0) {
13153 stp->syserr = "fstat";
13154 stp->error_no = errno;
13155 return Qnil;
13156 }
13157 }
13158
13159 if (dst_io == argf ||
13160 !(RB_TYPE_P(dst_io, T_FILE) ||
13161 RB_TYPE_P(dst_io, T_STRING) ||
13162 rb_respond_to(dst_io, rb_intern("to_path")))) {
13163 stp->dst_fptr = NULL;
13164 }
13165 else {
13166 int stat_ret;
13167 VALUE tmp_io = rb_io_check_io(dst_io);
13168 if (!NIL_P(tmp_io)) {
13169 dst_io = GetWriteIO(tmp_io);
13170 }
13171 else if (!RB_TYPE_P(dst_io, T_FILE)) {
13172 VALUE args[3];
13173 FilePathValue(dst_io);
13174 args[0] = dst_io;
13175 args[1] = INT2NUM(O_WRONLY|O_CREAT|O_TRUNC|common_oflags);
13176 args[2] = INT2FIX(0666);
13177 dst_io = rb_class_new_instance(3, args, rb_cFile);
13178 stp->dst = dst_io;
13179 stp->close_dst = 1;
13180 }
13181 else {
13182 dst_io = GetWriteIO(dst_io);
13183 stp->dst = dst_io;
13184 }
13185 RB_IO_POINTER(dst_io, stp->dst_fptr);
13186 rb_io_check_writable(stp->dst_fptr);
13187
13188 stat_ret = fstat(stp->dst_fptr->fd, &stp->dst_stat);
13189 if (stat_ret < 0) {
13190 stp->syserr = "fstat";
13191 stp->error_no = errno;
13192 return Qnil;
13193 }
13194 }
13195
13196#ifdef O_BINARY
13197 if (stp->src_fptr)
13198 SET_BINARY_MODE_WITH_SEEK_CUR(stp->src_fptr);
13199#endif
13200 if (stp->dst_fptr)
13201 io_ascii8bit_binmode(stp->dst_fptr);
13202
13203 if (stp->src_offset < (rb_off_t)0 && stp->src_fptr && stp->src_fptr->rbuf.len) {
13204 size_t len = stp->src_fptr->rbuf.len;
13205 VALUE str;
13206 if (stp->copy_length >= (rb_off_t)0 && stp->copy_length < (rb_off_t)len) {
13207 len = (size_t)stp->copy_length;
13208 }
13209 str = rb_str_buf_new(len);
13210 rb_str_resize(str,len);
13211 read_buffered_data(RSTRING_PTR(str), len, stp->src_fptr);
13212 if (stp->dst_fptr) { /* IO or filename */
13213 if (io_binwrite(str, RSTRING_PTR(str), RSTRING_LEN(str), stp->dst_fptr, 0) < 0)
13214 rb_sys_fail_on_write(stp->dst_fptr);
13215 }
13216 else /* others such as StringIO */
13217 rb_io_write(dst_io, str);
13218 rb_str_resize(str, 0);
13219 stp->total += len;
13220 if (stp->copy_length >= (rb_off_t)0)
13221 stp->copy_length -= len;
13222 }
13223
13224 if (stp->dst_fptr && io_fflush(stp->dst_fptr) < 0) {
13225 rb_raise(rb_eIOError, "flush failed");
13226 }
13227
13228 if (stp->copy_length == 0)
13229 return Qnil;
13230
13231 if (stp->src_fptr == NULL || stp->dst_fptr == NULL) {
13232 return copy_stream_fallback(stp);
13233 }
13234
13235 rb_thread_call_without_gvl(nogvl_copy_stream_func, (void*)stp, RUBY_UBF_IO, 0);
13236 return Qnil;
13237}
13238
13239static VALUE
13240copy_stream_finalize(VALUE arg)
13241{
13242 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13243
13244#ifdef HAVE_FCOPYFILE
13245 if (stp->copyfile_state) {
13246 copyfile_state_free(stp->copyfile_state);
13247 }
13248#endif
13249
13250 if (stp->close_src) {
13251 rb_io_close_m(stp->src);
13252 }
13253 if (stp->close_dst) {
13254 rb_io_close_m(stp->dst);
13255 }
13256 if (stp->syserr) {
13257 rb_syserr_fail(stp->error_no, stp->syserr);
13258 }
13259 if (stp->notimp) {
13260 rb_raise(rb_eNotImpError, "%s() not implemented", stp->notimp);
13261 }
13262 return Qnil;
13263}
13264
13265/*
13266 * call-seq:
13267 * IO.copy_stream(src, dst, src_length = nil, src_offset = 0) -> integer
13268 *
13269 * Copies from the given +src+ to the given +dst+,
13270 * returning the number of bytes copied.
13271 *
13272 * - The given +src+ must be one of the following:
13273 *
13274 * - The path to a readable file, from which source data is to be read.
13275 * - An \IO-like object, opened for reading and capable of responding
13276 * to method +:readpartial+ or method +:read+.
13277 *
13278 * - The given +dst+ must be one of the following:
13279 *
13280 * - The path to a writable file, to which data is to be written.
13281 * - An \IO-like object, opened for writing and capable of responding
13282 * to method +:write+.
13283 *
13284 * The examples here use file <tt>t.txt</tt> as source:
13285 *
13286 * File.read('t.txt')
13287 * # => "First line\nSecond line\n\nThird line\nFourth line\n"
13288 * File.read('t.txt').size # => 47
13289 *
13290 * If only arguments +src+ and +dst+ are given,
13291 * the entire source stream is copied:
13292 *
13293 * # Paths.
13294 * IO.copy_stream('t.txt', 't.tmp') # => 47
13295 *
13296 * # IOs (recall that a File is also an IO).
13297 * src_io = File.open('t.txt', 'r') # => #<File:t.txt>
13298 * dst_io = File.open('t.tmp', 'w') # => #<File:t.tmp>
13299 * IO.copy_stream(src_io, dst_io) # => 47
13300 * src_io.close
13301 * dst_io.close
13302 *
13303 * With argument +src_length+ a non-negative integer,
13304 * no more than that many bytes are copied:
13305 *
13306 * IO.copy_stream('t.txt', 't.tmp', 10) # => 10
13307 * File.read('t.tmp') # => "First line"
13308 *
13309 * With argument +src_offset+ also given,
13310 * the source stream is read beginning at that offset:
13311 *
13312 * IO.copy_stream('t.txt', 't.tmp', 11, 11) # => 11
13313 * IO.read('t.tmp') # => "Second line"
13314 *
13315 */
13316static VALUE
13317rb_io_s_copy_stream(int argc, VALUE *argv, VALUE io)
13318{
13319 VALUE src, dst, length, src_offset;
13320 struct copy_stream_struct st;
13321
13322 MEMZERO(&st, struct copy_stream_struct, 1);
13323
13324 rb_scan_args(argc, argv, "22", &src, &dst, &length, &src_offset);
13325
13326 st.src = src;
13327 st.dst = dst;
13328
13329 st.src_fptr = NULL;
13330 st.dst_fptr = NULL;
13331
13332 if (NIL_P(length))
13333 st.copy_length = (rb_off_t)-1;
13334 else
13335 st.copy_length = NUM2OFFT(length);
13336
13337 if (NIL_P(src_offset))
13338 st.src_offset = (rb_off_t)-1;
13339 else
13340 st.src_offset = NUM2OFFT(src_offset);
13341
13342 rb_ensure(copy_stream_body, (VALUE)&st, copy_stream_finalize, (VALUE)&st);
13343
13344 return OFFT2NUM(st.total);
13345}
13346
13347/*
13348 * call-seq:
13349 * external_encoding -> encoding or nil
13350 *
13351 * Returns the Encoding object that represents the encoding of the stream,
13352 * or +nil+ if the stream is in write mode and no encoding is specified.
13353 *
13354 * See {Encodings}[rdoc-ref:File@Encodings].
13355 *
13356 */
13357
13358static VALUE
13359rb_io_external_encoding(VALUE io)
13360{
13361 rb_io_t *fptr = RFILE(rb_io_taint_check(io))->fptr;
13362
13363 if (fptr->encs.enc2) {
13364 return rb_enc_from_encoding(fptr->encs.enc2);
13365 }
13366 if (fptr->mode & FMODE_WRITABLE) {
13367 if (fptr->encs.enc)
13368 return rb_enc_from_encoding(fptr->encs.enc);
13369 return Qnil;
13370 }
13371 return rb_enc_from_encoding(io_read_encoding(fptr));
13372}
13373
13374/*
13375 * call-seq:
13376 * internal_encoding -> encoding or nil
13377 *
13378 * Returns the Encoding object that represents the encoding of the internal string,
13379 * if conversion is specified,
13380 * or +nil+ otherwise.
13381 *
13382 * See {Encodings}[rdoc-ref:File@Encodings].
13383 *
13384 */
13385
13386static VALUE
13387rb_io_internal_encoding(VALUE io)
13388{
13389 rb_io_t *fptr = RFILE(rb_io_taint_check(io))->fptr;
13390
13391 if (!fptr->encs.enc2) return Qnil;
13392 return rb_enc_from_encoding(io_read_encoding(fptr));
13393}
13394
13395/*
13396 * call-seq:
13397 * set_encoding(ext_enc) -> self
13398 * set_encoding(ext_enc, int_enc, **enc_opts) -> self
13399 * set_encoding('ext_enc:int_enc', **enc_opts) -> self
13400 *
13401 * See {Encodings}[rdoc-ref:File@Encodings].
13402 *
13403 * Argument +ext_enc+, if given, must be an Encoding object
13404 * or a String with the encoding name;
13405 * it is assigned as the encoding for the stream.
13406 *
13407 * Argument +int_enc+, if given, must be an Encoding object
13408 * or a String with the encoding name;
13409 * it is assigned as the encoding for the internal string.
13410 *
13411 * Argument <tt>'ext_enc:int_enc'</tt>, if given, is a string
13412 * containing two colon-separated encoding names;
13413 * corresponding Encoding objects are assigned as the external
13414 * and internal encodings for the stream.
13415 *
13416 * If the external encoding of a string is binary/ASCII-8BIT,
13417 * the internal encoding of the string is set to nil, since no
13418 * transcoding is needed.
13419 *
13420 * Optional keyword arguments +enc_opts+ specify
13421 * {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
13422 *
13423 */
13424
13425static VALUE
13426rb_io_set_encoding(int argc, VALUE *argv, VALUE io)
13427{
13428 rb_io_t *fptr;
13429 VALUE v1, v2, opt;
13430
13431 if (!RB_TYPE_P(io, T_FILE)) {
13432 return forward(io, id_set_encoding, argc, argv);
13433 }
13434
13435 argc = rb_scan_args(argc, argv, "11:", &v1, &v2, &opt);
13436 GetOpenFile(io, fptr);
13437 io_encoding_set(fptr, v1, v2, opt);
13438 return io;
13439}
13440
13441void
13442rb_stdio_set_default_encoding(void)
13443{
13444 VALUE val = Qnil;
13445
13446#ifdef _WIN32
13447 if (isatty(fileno(stdin))) {
13448 rb_encoding *external = rb_locale_encoding();
13449 rb_encoding *internal = rb_default_internal_encoding();
13450 if (!internal) internal = rb_default_external_encoding();
13451 io_encoding_set(RFILE(rb_stdin)->fptr,
13452 rb_enc_from_encoding(external),
13453 rb_enc_from_encoding(internal),
13454 Qnil);
13455 }
13456 else
13457#endif
13458 rb_io_set_encoding(1, &val, rb_stdin);
13459 rb_io_set_encoding(1, &val, rb_stdout);
13460 rb_io_set_encoding(1, &val, rb_stderr);
13461}
13462
13463static inline int
13464global_argf_p(VALUE arg)
13465{
13466 return arg == argf;
13467}
13468
13469typedef VALUE (*argf_encoding_func)(VALUE io);
13470
13471static VALUE
13472argf_encoding(VALUE argf, argf_encoding_func func)
13473{
13474 if (!RTEST(ARGF.current_file)) {
13475 return rb_enc_default_external();
13476 }
13477 return func(rb_io_check_io(ARGF.current_file));
13478}
13479
13480/*
13481 * call-seq:
13482 * ARGF.external_encoding -> encoding
13483 *
13484 * Returns the external encoding for files read from ARGF as an Encoding
13485 * object. The external encoding is the encoding of the text as stored in a
13486 * file. Contrast with ARGF.internal_encoding, which is the encoding used to
13487 * represent this text within Ruby.
13488 *
13489 * To set the external encoding use ARGF.set_encoding.
13490 *
13491 * For example:
13492 *
13493 * ARGF.external_encoding #=> #<Encoding:UTF-8>
13494 *
13495 */
13496static VALUE
13497argf_external_encoding(VALUE argf)
13498{
13499 return argf_encoding(argf, rb_io_external_encoding);
13500}
13501
13502/*
13503 * call-seq:
13504 * ARGF.internal_encoding -> encoding
13505 *
13506 * Returns the internal encoding for strings read from ARGF as an
13507 * Encoding object.
13508 *
13509 * If ARGF.set_encoding has been called with two encoding names, the second
13510 * is returned. Otherwise, if +Encoding.default_external+ has been set, that
13511 * value is returned. Failing that, if a default external encoding was
13512 * specified on the command-line, that value is used. If the encoding is
13513 * unknown, +nil+ is returned.
13514 */
13515static VALUE
13516argf_internal_encoding(VALUE argf)
13517{
13518 return argf_encoding(argf, rb_io_internal_encoding);
13519}
13520
13521/*
13522 * call-seq:
13523 * ARGF.set_encoding(ext_enc) -> ARGF
13524 * ARGF.set_encoding("ext_enc:int_enc") -> ARGF
13525 * ARGF.set_encoding(ext_enc, int_enc) -> ARGF
13526 * ARGF.set_encoding("ext_enc:int_enc", opt) -> ARGF
13527 * ARGF.set_encoding(ext_enc, int_enc, opt) -> ARGF
13528 *
13529 * If single argument is specified, strings read from ARGF are tagged with
13530 * the encoding specified.
13531 *
13532 * If two encoding names separated by a colon are given, e.g. "ascii:utf-8",
13533 * the read string is converted from the first encoding (external encoding)
13534 * to the second encoding (internal encoding), then tagged with the second
13535 * encoding.
13536 *
13537 * If two arguments are specified, they must be encoding objects or encoding
13538 * names. Again, the first specifies the external encoding; the second
13539 * specifies the internal encoding.
13540 *
13541 * If the external encoding and the internal encoding are specified, the
13542 * optional Hash argument can be used to adjust the conversion process. The
13543 * structure of this hash is explained in the String#encode documentation.
13544 *
13545 * For example:
13546 *
13547 * ARGF.set_encoding('ascii') # Tag the input as US-ASCII text
13548 * ARGF.set_encoding(Encoding::UTF_8) # Tag the input as UTF-8 text
13549 * ARGF.set_encoding('utf-8','ascii') # Transcode the input from US-ASCII
13550 * # to UTF-8.
13551 */
13552static VALUE
13553argf_set_encoding(int argc, VALUE *argv, VALUE argf)
13554{
13555 rb_io_t *fptr;
13556
13557 if (!next_argv()) {
13558 rb_raise(rb_eArgError, "no stream to set encoding");
13559 }
13560 rb_io_set_encoding(argc, argv, ARGF.current_file);
13561 GetOpenFile(ARGF.current_file, fptr);
13562 ARGF.encs = fptr->encs;
13563 return argf;
13564}
13565
13566/*
13567 * call-seq:
13568 * ARGF.tell -> Integer
13569 * ARGF.pos -> Integer
13570 *
13571 * Returns the current offset (in bytes) of the current file in ARGF.
13572 *
13573 * ARGF.pos #=> 0
13574 * ARGF.gets #=> "This is line one\n"
13575 * ARGF.pos #=> 17
13576 *
13577 */
13578static VALUE
13579argf_tell(VALUE argf)
13580{
13581 if (!next_argv()) {
13582 rb_raise(rb_eArgError, "no stream to tell");
13583 }
13584 ARGF_FORWARD(0, 0);
13585 return rb_io_tell(ARGF.current_file);
13586}
13587
13588/*
13589 * call-seq:
13590 * ARGF.seek(amount, whence=IO::SEEK_SET) -> 0
13591 *
13592 * Seeks to offset _amount_ (an Integer) in the ARGF stream according to
13593 * the value of _whence_. See IO#seek for further details.
13594 */
13595static VALUE
13596argf_seek_m(int argc, VALUE *argv, VALUE argf)
13597{
13598 if (!next_argv()) {
13599 rb_raise(rb_eArgError, "no stream to seek");
13600 }
13601 ARGF_FORWARD(argc, argv);
13602 return rb_io_seek_m(argc, argv, ARGF.current_file);
13603}
13604
13605/*
13606 * call-seq:
13607 * ARGF.pos = position -> Integer
13608 *
13609 * Seeks to the position given by _position_ (in bytes) in ARGF.
13610 *
13611 * For example:
13612 *
13613 * ARGF.pos = 17
13614 * ARGF.gets #=> "This is line two\n"
13615 */
13616static VALUE
13617argf_set_pos(VALUE argf, VALUE offset)
13618{
13619 if (!next_argv()) {
13620 rb_raise(rb_eArgError, "no stream to set position");
13621 }
13622 ARGF_FORWARD(1, &offset);
13623 return rb_io_set_pos(ARGF.current_file, offset);
13624}
13625
13626/*
13627 * call-seq:
13628 * ARGF.rewind -> 0
13629 *
13630 * Positions the current file to the beginning of input, resetting
13631 * ARGF.lineno to zero.
13632 *
13633 * ARGF.readline #=> "This is line one\n"
13634 * ARGF.rewind #=> 0
13635 * ARGF.lineno #=> 0
13636 * ARGF.readline #=> "This is line one\n"
13637 */
13638static VALUE
13639argf_rewind(VALUE argf)
13640{
13641 VALUE ret;
13642 int old_lineno;
13643
13644 if (!next_argv()) {
13645 rb_raise(rb_eArgError, "no stream to rewind");
13646 }
13647 ARGF_FORWARD(0, 0);
13648 old_lineno = RFILE(ARGF.current_file)->fptr->lineno;
13649 ret = rb_io_rewind(ARGF.current_file);
13650 if (!global_argf_p(argf)) {
13651 ARGF.last_lineno = ARGF.lineno -= old_lineno;
13652 }
13653 return ret;
13654}
13655
13656/*
13657 * call-seq:
13658 * ARGF.fileno -> integer
13659 * ARGF.to_i -> integer
13660 *
13661 * Returns an integer representing the numeric file descriptor for
13662 * the current file. Raises an ArgumentError if there isn't a current file.
13663 *
13664 * ARGF.fileno #=> 3
13665 */
13666static VALUE
13667argf_fileno(VALUE argf)
13668{
13669 if (!next_argv()) {
13670 rb_raise(rb_eArgError, "no stream");
13671 }
13672 ARGF_FORWARD(0, 0);
13673 return rb_io_fileno(ARGF.current_file);
13674}
13675
13676/*
13677 * call-seq:
13678 * ARGF.to_io -> IO
13679 *
13680 * Returns an IO object representing the current file. This will be a
13681 * File object unless the current file is a stream such as STDIN.
13682 *
13683 * For example:
13684 *
13685 * ARGF.to_io #=> #<File:glark.txt>
13686 * ARGF.to_io #=> #<IO:<STDIN>>
13687 */
13688static VALUE
13689argf_to_io(VALUE argf)
13690{
13691 next_argv();
13692 ARGF_FORWARD(0, 0);
13693 return ARGF.current_file;
13694}
13695
13696/*
13697 * call-seq:
13698 * ARGF.eof? -> true or false
13699 * ARGF.eof -> true or false
13700 *
13701 * Returns true if the current file in ARGF is at end of file, i.e. it has
13702 * no data to read. The stream must be opened for reading or an IOError
13703 * will be raised.
13704 *
13705 * $ echo "eof" | ruby argf.rb
13706 *
13707 * ARGF.eof? #=> false
13708 * 3.times { ARGF.readchar }
13709 * ARGF.eof? #=> false
13710 * ARGF.readchar #=> "\n"
13711 * ARGF.eof? #=> true
13712 */
13713
13714static VALUE
13715argf_eof(VALUE argf)
13716{
13717 next_argv();
13718 if (RTEST(ARGF.current_file)) {
13719 if (ARGF.init_p == 0) return Qtrue;
13720 next_argv();
13721 ARGF_FORWARD(0, 0);
13722 if (rb_io_eof(ARGF.current_file)) {
13723 return Qtrue;
13724 }
13725 }
13726 return Qfalse;
13727}
13728
13729/*
13730 * call-seq:
13731 * ARGF.read([length [, outbuf]]) -> string, outbuf, or nil
13732 *
13733 * Reads _length_ bytes from ARGF. The files named on the command line
13734 * are concatenated and treated as a single file by this method, so when
13735 * called without arguments the contents of this pseudo file are returned in
13736 * their entirety.
13737 *
13738 * _length_ must be a non-negative integer or +nil+.
13739 *
13740 * If _length_ is a positive integer, +read+ tries to read
13741 * _length_ bytes without any conversion (binary mode).
13742 * It returns +nil+ if an EOF is encountered before anything can be read.
13743 * Fewer than _length_ bytes are returned if an EOF is encountered during
13744 * the read.
13745 * In the case of an integer _length_, the resulting string is always
13746 * in ASCII-8BIT encoding.
13747 *
13748 * If _length_ is omitted or is +nil+, it reads until EOF
13749 * and the encoding conversion is applied, if applicable.
13750 * A string is returned even if EOF is encountered before any data is read.
13751 *
13752 * If _length_ is zero, it returns an empty string (<code>""</code>).
13753 *
13754 * If the optional _outbuf_ argument is present,
13755 * it must reference a String, which will receive the data.
13756 * The _outbuf_ will contain only the received data after the method call
13757 * even if it is not empty at the beginning.
13758 *
13759 * For example:
13760 *
13761 * $ echo "small" > small.txt
13762 * $ echo "large" > large.txt
13763 * $ ./glark.rb small.txt large.txt
13764 *
13765 * ARGF.read #=> "small\nlarge"
13766 * ARGF.read(200) #=> "small\nlarge"
13767 * ARGF.read(2) #=> "sm"
13768 * ARGF.read(0) #=> ""
13769 *
13770 * Note that this method behaves like the fread() function in C.
13771 * This means it retries to invoke read(2) system calls to read data
13772 * with the specified length.
13773 * If you need the behavior like a single read(2) system call,
13774 * consider ARGF#readpartial or ARGF#read_nonblock.
13775 */
13776
13777static VALUE
13778argf_read(int argc, VALUE *argv, VALUE argf)
13779{
13780 VALUE tmp, str, length;
13781 long len = 0;
13782
13783 rb_scan_args(argc, argv, "02", &length, &str);
13784 if (!NIL_P(length)) {
13785 len = NUM2LONG(argv[0]);
13786 }
13787 if (!NIL_P(str)) {
13788 StringValue(str);
13789 rb_str_resize(str,0);
13790 argv[1] = Qnil;
13791 }
13792
13793 retry:
13794 if (!next_argv()) {
13795 return str;
13796 }
13797 if (ARGF_GENERIC_INPUT_P()) {
13798 tmp = argf_forward(argc, argv, argf);
13799 }
13800 else {
13801 tmp = io_read(argc, argv, ARGF.current_file);
13802 }
13803 if (NIL_P(str)) str = tmp;
13804 else if (!NIL_P(tmp)) rb_str_append(str, tmp);
13805 if (NIL_P(tmp) || NIL_P(length)) {
13806 if (ARGF.next_p != -1) {
13807 argf_close(argf);
13808 ARGF.next_p = 1;
13809 goto retry;
13810 }
13811 }
13812 else if (argc >= 1) {
13813 long slen = RSTRING_LEN(str);
13814 if (slen < len) {
13815 argv[0] = LONG2NUM(len - slen);
13816 goto retry;
13817 }
13818 }
13819 return str;
13820}
13821
13823 int argc;
13824 VALUE *argv;
13825 VALUE argf;
13826};
13827
13828static VALUE
13829argf_forward_call(VALUE arg)
13830{
13831 struct argf_call_arg *p = (struct argf_call_arg *)arg;
13832 argf_forward(p->argc, p->argv, p->argf);
13833 return Qnil;
13834}
13835
13836static VALUE argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts,
13837 int nonblock);
13838
13839/*
13840 * call-seq:
13841 * ARGF.readpartial(maxlen) -> string
13842 * ARGF.readpartial(maxlen, outbuf) -> outbuf
13843 *
13844 * Reads at most _maxlen_ bytes from the ARGF stream.
13845 *
13846 * If the optional _outbuf_ argument is present,
13847 * it must reference a String, which will receive the data.
13848 * The _outbuf_ will contain only the received data after the method call
13849 * even if it is not empty at the beginning.
13850 *
13851 * It raises EOFError on end of ARGF stream.
13852 * Since ARGF stream is a concatenation of multiple files,
13853 * internally EOF is occur for each file.
13854 * ARGF.readpartial returns empty strings for EOFs except the last one and
13855 * raises EOFError for the last one.
13856 *
13857 */
13858
13859static VALUE
13860argf_readpartial(int argc, VALUE *argv, VALUE argf)
13861{
13862 return argf_getpartial(argc, argv, argf, Qnil, 0);
13863}
13864
13865/*
13866 * call-seq:
13867 * ARGF.read_nonblock(maxlen[, options]) -> string
13868 * ARGF.read_nonblock(maxlen, outbuf[, options]) -> outbuf
13869 *
13870 * Reads at most _maxlen_ bytes from the ARGF stream in non-blocking mode.
13871 */
13872
13873static VALUE
13874argf_read_nonblock(int argc, VALUE *argv, VALUE argf)
13875{
13876 VALUE opts;
13877
13878 rb_scan_args(argc, argv, "11:", NULL, NULL, &opts);
13879
13880 if (!NIL_P(opts))
13881 argc--;
13882
13883 return argf_getpartial(argc, argv, argf, opts, 1);
13884}
13885
13886static VALUE
13887argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts, int nonblock)
13888{
13889 VALUE tmp, str, length;
13890 int no_exception;
13891
13892 rb_scan_args(argc, argv, "11", &length, &str);
13893 if (!NIL_P(str)) {
13894 StringValue(str);
13895 argv[1] = str;
13896 }
13897 no_exception = no_exception_p(opts);
13898
13899 if (!next_argv()) {
13900 if (!NIL_P(str)) {
13901 rb_str_resize(str, 0);
13902 }
13903 rb_eof_error();
13904 }
13905 if (ARGF_GENERIC_INPUT_P()) {
13906 VALUE (*const rescue_does_nothing)(VALUE, VALUE) = 0;
13907 struct argf_call_arg arg;
13908 arg.argc = argc;
13909 arg.argv = argv;
13910 arg.argf = argf;
13911 tmp = rb_rescue2(argf_forward_call, (VALUE)&arg,
13912 rescue_does_nothing, Qnil, rb_eEOFError, (VALUE)0);
13913 }
13914 else {
13915 tmp = io_getpartial(argc, argv, ARGF.current_file, no_exception, nonblock);
13916 }
13917 if (NIL_P(tmp)) {
13918 if (ARGF.next_p == -1) {
13919 return io_nonblock_eof(no_exception);
13920 }
13921 argf_close(argf);
13922 ARGF.next_p = 1;
13923 if (RARRAY_LEN(ARGF.argv) == 0) {
13924 return io_nonblock_eof(no_exception);
13925 }
13926 if (NIL_P(str))
13927 str = rb_str_new(NULL, 0);
13928 return str;
13929 }
13930 return tmp;
13931}
13932
13933/*
13934 * call-seq:
13935 * ARGF.getc -> String or nil
13936 *
13937 * Reads the next character from ARGF and returns it as a String. Returns
13938 * +nil+ at the end of the stream.
13939 *
13940 * ARGF treats the files named on the command line as a single file created
13941 * by concatenating their contents. After returning the last character of the
13942 * first file, it returns the first character of the second file, and so on.
13943 *
13944 * For example:
13945 *
13946 * $ echo "foo" > file
13947 * $ ruby argf.rb file
13948 *
13949 * ARGF.getc #=> "f"
13950 * ARGF.getc #=> "o"
13951 * ARGF.getc #=> "o"
13952 * ARGF.getc #=> "\n"
13953 * ARGF.getc #=> nil
13954 * ARGF.getc #=> nil
13955 */
13956static VALUE
13957argf_getc(VALUE argf)
13958{
13959 VALUE ch;
13960
13961 retry:
13962 if (!next_argv()) return Qnil;
13963 if (ARGF_GENERIC_INPUT_P()) {
13964 ch = forward_current(rb_intern("getc"), 0, 0);
13965 }
13966 else {
13967 ch = rb_io_getc(ARGF.current_file);
13968 }
13969 if (NIL_P(ch) && ARGF.next_p != -1) {
13970 argf_close(argf);
13971 ARGF.next_p = 1;
13972 goto retry;
13973 }
13974
13975 return ch;
13976}
13977
13978/*
13979 * call-seq:
13980 * ARGF.getbyte -> Integer or nil
13981 *
13982 * Gets the next 8-bit byte (0..255) from ARGF. Returns +nil+ if called at
13983 * the end of the stream.
13984 *
13985 * For example:
13986 *
13987 * $ echo "foo" > file
13988 * $ ruby argf.rb file
13989 *
13990 * ARGF.getbyte #=> 102
13991 * ARGF.getbyte #=> 111
13992 * ARGF.getbyte #=> 111
13993 * ARGF.getbyte #=> 10
13994 * ARGF.getbyte #=> nil
13995 */
13996static VALUE
13997argf_getbyte(VALUE argf)
13998{
13999 VALUE ch;
14000
14001 retry:
14002 if (!next_argv()) return Qnil;
14003 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
14004 ch = forward_current(rb_intern("getbyte"), 0, 0);
14005 }
14006 else {
14007 ch = rb_io_getbyte(ARGF.current_file);
14008 }
14009 if (NIL_P(ch) && ARGF.next_p != -1) {
14010 argf_close(argf);
14011 ARGF.next_p = 1;
14012 goto retry;
14013 }
14014
14015 return ch;
14016}
14017
14018/*
14019 * call-seq:
14020 * ARGF.readchar -> String or nil
14021 *
14022 * Reads the next character from ARGF and returns it as a String. Raises
14023 * an EOFError after the last character of the last file has been read.
14024 *
14025 * For example:
14026 *
14027 * $ echo "foo" > file
14028 * $ ruby argf.rb file
14029 *
14030 * ARGF.readchar #=> "f"
14031 * ARGF.readchar #=> "o"
14032 * ARGF.readchar #=> "o"
14033 * ARGF.readchar #=> "\n"
14034 * ARGF.readchar #=> end of file reached (EOFError)
14035 */
14036static VALUE
14037argf_readchar(VALUE argf)
14038{
14039 VALUE ch;
14040
14041 retry:
14042 if (!next_argv()) rb_eof_error();
14043 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
14044 ch = forward_current(rb_intern("getc"), 0, 0);
14045 }
14046 else {
14047 ch = rb_io_getc(ARGF.current_file);
14048 }
14049 if (NIL_P(ch) && ARGF.next_p != -1) {
14050 argf_close(argf);
14051 ARGF.next_p = 1;
14052 goto retry;
14053 }
14054
14055 return ch;
14056}
14057
14058/*
14059 * call-seq:
14060 * ARGF.readbyte -> Integer
14061 *
14062 * Reads the next 8-bit byte from ARGF and returns it as an Integer. Raises
14063 * an EOFError after the last byte of the last file has been read.
14064 *
14065 * For example:
14066 *
14067 * $ echo "foo" > file
14068 * $ ruby argf.rb file
14069 *
14070 * ARGF.readbyte #=> 102
14071 * ARGF.readbyte #=> 111
14072 * ARGF.readbyte #=> 111
14073 * ARGF.readbyte #=> 10
14074 * ARGF.readbyte #=> end of file reached (EOFError)
14075 */
14076static VALUE
14077argf_readbyte(VALUE argf)
14078{
14079 VALUE c;
14080
14081 NEXT_ARGF_FORWARD(0, 0);
14082 c = argf_getbyte(argf);
14083 if (NIL_P(c)) {
14084 rb_eof_error();
14085 }
14086 return c;
14087}
14088
14089#define FOREACH_ARGF() while (next_argv())
14090
14091static VALUE
14092argf_block_call_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
14093{
14094 const VALUE current = ARGF.current_file;
14095 rb_yield_values2(argc, argv);
14096 if (ARGF.init_p == -1 || current != ARGF.current_file) {
14098 }
14099 return Qnil;
14100}
14101
14102#define ARGF_block_call(mid, argc, argv, func, argf) \
14103 rb_block_call_kw(ARGF.current_file, mid, argc, argv, \
14104 func, argf, rb_keyword_given_p())
14105
14106static void
14107argf_block_call(ID mid, int argc, VALUE *argv, VALUE argf)
14108{
14109 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_i, argf);
14110 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14111}
14112
14113static VALUE
14114argf_block_call_line_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
14115{
14116 if (!global_argf_p(argf)) {
14117 ARGF.last_lineno = ++ARGF.lineno;
14118 }
14119 return argf_block_call_i(i, argf, argc, argv, blockarg);
14120}
14121
14122static void
14123argf_block_call_line(ID mid, int argc, VALUE *argv, VALUE argf)
14124{
14125 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_line_i, argf);
14126 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14127}
14128
14129/*
14130 * call-seq:
14131 * ARGF.each(sep=$/) {|line| block } -> ARGF
14132 * ARGF.each(sep=$/, limit) {|line| block } -> ARGF
14133 * ARGF.each(...) -> an_enumerator
14134 *
14135 * ARGF.each_line(sep=$/) {|line| block } -> ARGF
14136 * ARGF.each_line(sep=$/, limit) {|line| block } -> ARGF
14137 * ARGF.each_line(...) -> an_enumerator
14138 *
14139 * Returns an enumerator which iterates over each line (separated by _sep_,
14140 * which defaults to your platform's newline character) of each file in
14141 * +ARGV+. If a block is supplied, each line in turn will be yielded to the
14142 * block, otherwise an enumerator is returned.
14143 * The optional _limit_ argument is an Integer specifying the maximum
14144 * length of each line; longer lines will be split according to this limit.
14145 *
14146 * This method allows you to treat the files supplied on the command line as
14147 * a single file consisting of the concatenation of each named file. After
14148 * the last line of the first file has been returned, the first line of the
14149 * second file is returned. The ARGF.filename and ARGF.lineno methods can be
14150 * used to determine the filename of the current line and line number of the
14151 * whole input, respectively.
14152 *
14153 * For example, the following code prints out each line of each named file
14154 * prefixed with its line number, displaying the filename once per file:
14155 *
14156 * ARGF.each_line do |line|
14157 * puts ARGF.filename if ARGF.file.lineno == 1
14158 * puts "#{ARGF.file.lineno}: #{line}"
14159 * end
14160 *
14161 * While the following code prints only the first file's name at first, and
14162 * the contents with line number counted through all named files.
14163 *
14164 * ARGF.each_line do |line|
14165 * puts ARGF.filename if ARGF.lineno == 1
14166 * puts "#{ARGF.lineno}: #{line}"
14167 * end
14168 */
14169static VALUE
14170argf_each_line(int argc, VALUE *argv, VALUE argf)
14171{
14172 RETURN_ENUMERATOR(argf, argc, argv);
14173 FOREACH_ARGF() {
14174 argf_block_call_line(rb_intern("each_line"), argc, argv, argf);
14175 }
14176 return argf;
14177}
14178
14179/*
14180 * call-seq:
14181 * ARGF.each_byte {|byte| block } -> ARGF
14182 * ARGF.each_byte -> an_enumerator
14183 *
14184 * Iterates over each byte of each file in +ARGV+.
14185 * A byte is returned as an Integer in the range 0..255.
14186 *
14187 * This method allows you to treat the files supplied on the command line as
14188 * a single file consisting of the concatenation of each named file. After
14189 * the last byte of the first file has been returned, the first byte of the
14190 * second file is returned. The ARGF.filename method can be used to
14191 * determine the filename of the current byte.
14192 *
14193 * If no block is given, an enumerator is returned instead.
14194 *
14195 * For example:
14196 *
14197 * ARGF.bytes.to_a #=> [35, 32, ... 95, 10]
14198 *
14199 */
14200static VALUE
14201argf_each_byte(VALUE argf)
14202{
14203 RETURN_ENUMERATOR(argf, 0, 0);
14204 FOREACH_ARGF() {
14205 argf_block_call(rb_intern("each_byte"), 0, 0, argf);
14206 }
14207 return argf;
14208}
14209
14210/*
14211 * call-seq:
14212 * ARGF.each_char {|char| block } -> ARGF
14213 * ARGF.each_char -> an_enumerator
14214 *
14215 * Iterates over each character of each file in ARGF.
14216 *
14217 * This method allows you to treat the files supplied on the command line as
14218 * a single file consisting of the concatenation of each named file. After
14219 * the last character of the first file has been returned, the first
14220 * character of the second file is returned. The ARGF.filename method can
14221 * be used to determine the name of the file in which the current character
14222 * appears.
14223 *
14224 * If no block is given, an enumerator is returned instead.
14225 */
14226static VALUE
14227argf_each_char(VALUE argf)
14228{
14229 RETURN_ENUMERATOR(argf, 0, 0);
14230 FOREACH_ARGF() {
14231 argf_block_call(rb_intern("each_char"), 0, 0, argf);
14232 }
14233 return argf;
14234}
14235
14236/*
14237 * call-seq:
14238 * ARGF.each_codepoint {|codepoint| block } -> ARGF
14239 * ARGF.each_codepoint -> an_enumerator
14240 *
14241 * Iterates over each codepoint of each file in ARGF.
14242 *
14243 * This method allows you to treat the files supplied on the command line as
14244 * a single file consisting of the concatenation of each named file. After
14245 * the last codepoint of the first file has been returned, the first
14246 * codepoint of the second file is returned. The ARGF.filename method can
14247 * be used to determine the name of the file in which the current codepoint
14248 * appears.
14249 *
14250 * If no block is given, an enumerator is returned instead.
14251 */
14252static VALUE
14253argf_each_codepoint(VALUE argf)
14254{
14255 RETURN_ENUMERATOR(argf, 0, 0);
14256 FOREACH_ARGF() {
14257 argf_block_call(rb_intern("each_codepoint"), 0, 0, argf);
14258 }
14259 return argf;
14260}
14261
14262/*
14263 * call-seq:
14264 * ARGF.filename -> String
14265 * ARGF.path -> String
14266 *
14267 * Returns the current filename. "-" is returned when the current file is
14268 * STDIN.
14269 *
14270 * For example:
14271 *
14272 * $ echo "foo" > foo
14273 * $ echo "bar" > bar
14274 * $ echo "glark" > glark
14275 *
14276 * $ ruby argf.rb foo bar glark
14277 *
14278 * ARGF.filename #=> "foo"
14279 * ARGF.read(5) #=> "foo\nb"
14280 * ARGF.filename #=> "bar"
14281 * ARGF.skip
14282 * ARGF.filename #=> "glark"
14283 */
14284static VALUE
14285argf_filename(VALUE argf)
14286{
14287 next_argv();
14288 return ARGF.filename;
14289}
14290
14291static VALUE
14292argf_filename_getter(ID id, VALUE *var)
14293{
14294 return argf_filename(*var);
14295}
14296
14297/*
14298 * call-seq:
14299 * ARGF.file -> IO or File object
14300 *
14301 * Returns the current file as an IO or File object.
14302 * <code>$stdin</code> is returned when the current file is STDIN.
14303 *
14304 * For example:
14305 *
14306 * $ echo "foo" > foo
14307 * $ echo "bar" > bar
14308 *
14309 * $ ruby argf.rb foo bar
14310 *
14311 * ARGF.file #=> #<File:foo>
14312 * ARGF.read(5) #=> "foo\nb"
14313 * ARGF.file #=> #<File:bar>
14314 */
14315static VALUE
14316argf_file(VALUE argf)
14317{
14318 next_argv();
14319 return ARGF.current_file;
14320}
14321
14322/*
14323 * call-seq:
14324 * ARGF.binmode -> ARGF
14325 *
14326 * Puts ARGF into binary mode. Once a stream is in binary mode, it cannot
14327 * be reset to non-binary mode. This option has the following effects:
14328 *
14329 * * Newline conversion is disabled.
14330 * * Encoding conversion is disabled.
14331 * * Content is treated as ASCII-8BIT.
14332 */
14333static VALUE
14334argf_binmode_m(VALUE argf)
14335{
14336 ARGF.binmode = 1;
14337 next_argv();
14338 ARGF_FORWARD(0, 0);
14339 rb_io_ascii8bit_binmode(ARGF.current_file);
14340 return argf;
14341}
14342
14343/*
14344 * call-seq:
14345 * ARGF.binmode? -> true or false
14346 *
14347 * Returns true if ARGF is being read in binary mode; false otherwise.
14348 * To enable binary mode use ARGF.binmode.
14349 *
14350 * For example:
14351 *
14352 * ARGF.binmode? #=> false
14353 * ARGF.binmode
14354 * ARGF.binmode? #=> true
14355 */
14356static VALUE
14357argf_binmode_p(VALUE argf)
14358{
14359 return RBOOL(ARGF.binmode);
14360}
14361
14362/*
14363 * call-seq:
14364 * ARGF.skip -> ARGF
14365 *
14366 * Sets the current file to the next file in ARGV. If there aren't any more
14367 * files it has no effect.
14368 *
14369 * For example:
14370 *
14371 * $ ruby argf.rb foo bar
14372 * ARGF.filename #=> "foo"
14373 * ARGF.skip
14374 * ARGF.filename #=> "bar"
14375 */
14376static VALUE
14377argf_skip(VALUE argf)
14378{
14379 if (ARGF.init_p && ARGF.next_p == 0) {
14380 argf_close(argf);
14381 ARGF.next_p = 1;
14382 }
14383 return argf;
14384}
14385
14386/*
14387 * call-seq:
14388 * ARGF.close -> ARGF
14389 *
14390 * Closes the current file and skips to the next file in ARGV. If there are
14391 * no more files to open, just closes the current file. STDIN will not be
14392 * closed.
14393 *
14394 * For example:
14395 *
14396 * $ ruby argf.rb foo bar
14397 *
14398 * ARGF.filename #=> "foo"
14399 * ARGF.close
14400 * ARGF.filename #=> "bar"
14401 * ARGF.close
14402 */
14403static VALUE
14404argf_close_m(VALUE argf)
14405{
14406 next_argv();
14407 argf_close(argf);
14408 if (ARGF.next_p != -1) {
14409 ARGF.next_p = 1;
14410 }
14411 ARGF.lineno = 0;
14412 return argf;
14413}
14414
14415/*
14416 * call-seq:
14417 * ARGF.closed? -> true or false
14418 *
14419 * Returns _true_ if the current file has been closed; _false_ otherwise. Use
14420 * ARGF.close to actually close the current file.
14421 */
14422static VALUE
14423argf_closed(VALUE argf)
14424{
14425 next_argv();
14426 ARGF_FORWARD(0, 0);
14427 return rb_io_closed_p(ARGF.current_file);
14428}
14429
14430/*
14431 * call-seq:
14432 * ARGF.to_s -> String
14433 *
14434 * Returns "ARGF".
14435 */
14436static VALUE
14437argf_to_s(VALUE argf)
14438{
14439 return rb_str_new2("ARGF");
14440}
14441
14442/*
14443 * call-seq:
14444 * ARGF.inplace_mode -> String
14445 *
14446 * Returns the file extension appended to the names of backup copies of
14447 * modified files under in-place edit mode. This value can be set using
14448 * ARGF.inplace_mode= or passing the +-i+ switch to the Ruby binary.
14449 */
14450static VALUE
14451argf_inplace_mode_get(VALUE argf)
14452{
14453 if (!ARGF.inplace) return Qnil;
14454 if (NIL_P(ARGF.inplace)) return rb_str_new(0, 0);
14455 return rb_str_dup(ARGF.inplace);
14456}
14457
14458static VALUE
14459opt_i_get(ID id, VALUE *var)
14460{
14461 return argf_inplace_mode_get(*var);
14462}
14463
14464/*
14465 * call-seq:
14466 * ARGF.inplace_mode = ext -> ARGF
14467 *
14468 * Sets the filename extension for in-place editing mode to the given String.
14469 * The backup copy of each file being edited has this value appended to its
14470 * filename.
14471 *
14472 * For example:
14473 *
14474 * $ ruby argf.rb file.txt
14475 *
14476 * ARGF.inplace_mode = '.bak'
14477 * ARGF.each_line do |line|
14478 * print line.sub("foo","bar")
14479 * end
14480 *
14481 * First, _file.txt.bak_ is created as a backup copy of _file.txt_.
14482 * Then, each line of _file.txt_ has the first occurrence of "foo" replaced with
14483 * "bar".
14484 */
14485static VALUE
14486argf_inplace_mode_set(VALUE argf, VALUE val)
14487{
14488 if (!RTEST(val)) {
14489 ARGF.inplace = Qfalse;
14490 }
14491 else if (StringValueCStr(val), !RSTRING_LEN(val)) {
14492 ARGF.inplace = Qnil;
14493 }
14494 else {
14495 ARGF.inplace = rb_str_new_frozen(val);
14496 }
14497 return argf;
14498}
14499
14500static void
14501opt_i_set(VALUE val, ID id, VALUE *var)
14502{
14503 argf_inplace_mode_set(*var, val);
14504}
14505
14506void
14507ruby_set_inplace_mode(const char *suffix)
14508{
14509 ARGF.inplace = !suffix ? Qfalse : !*suffix ? Qnil : rb_str_new(suffix, strlen(suffix));
14510}
14511
14512/*
14513 * call-seq:
14514 * ARGF.argv -> ARGV
14515 *
14516 * Returns the +ARGV+ array, which contains the arguments passed to your
14517 * script, one per element.
14518 *
14519 * For example:
14520 *
14521 * $ ruby argf.rb -v glark.txt
14522 *
14523 * ARGF.argv #=> ["-v", "glark.txt"]
14524 *
14525 */
14526static VALUE
14527argf_argv(VALUE argf)
14528{
14529 return ARGF.argv;
14530}
14531
14532static VALUE
14533argf_argv_getter(ID id, VALUE *var)
14534{
14535 return argf_argv(*var);
14536}
14537
14538VALUE
14540{
14541 return ARGF.argv;
14542}
14543
14544/*
14545 * call-seq:
14546 * ARGF.to_write_io -> io
14547 *
14548 * Returns IO instance tied to _ARGF_ for writing if inplace mode is
14549 * enabled.
14550 */
14551static VALUE
14552argf_write_io(VALUE argf)
14553{
14554 if (!RTEST(ARGF.current_file)) {
14555 rb_raise(rb_eIOError, "not opened for writing");
14556 }
14557 return GetWriteIO(ARGF.current_file);
14558}
14559
14560/*
14561 * call-seq:
14562 * ARGF.write(string) -> integer
14563 *
14564 * Writes _string_ if inplace mode.
14565 */
14566static VALUE
14567argf_write(VALUE argf, VALUE str)
14568{
14569 return rb_io_write(argf_write_io(argf), str);
14570}
14571
14572void
14573rb_readwrite_sys_fail(enum rb_io_wait_readwrite waiting, const char *mesg)
14574{
14575 rb_readwrite_syserr_fail(waiting, errno, mesg);
14576}
14577
14578void
14579rb_readwrite_syserr_fail(enum rb_io_wait_readwrite waiting, int n, const char *mesg)
14580{
14581 VALUE arg, c = Qnil;
14582 arg = mesg ? rb_str_new2(mesg) : Qnil;
14583 switch (waiting) {
14584 case RB_IO_WAIT_WRITABLE:
14585 switch (n) {
14586 case EAGAIN:
14587 c = rb_eEAGAINWaitWritable;
14588 break;
14589#if EAGAIN != EWOULDBLOCK
14590 case EWOULDBLOCK:
14591 c = rb_eEWOULDBLOCKWaitWritable;
14592 break;
14593#endif
14594 case EINPROGRESS:
14595 c = rb_eEINPROGRESSWaitWritable;
14596 break;
14597 default:
14599 }
14600 break;
14601 case RB_IO_WAIT_READABLE:
14602 switch (n) {
14603 case EAGAIN:
14604 c = rb_eEAGAINWaitReadable;
14605 break;
14606#if EAGAIN != EWOULDBLOCK
14607 case EWOULDBLOCK:
14608 c = rb_eEWOULDBLOCKWaitReadable;
14609 break;
14610#endif
14611 case EINPROGRESS:
14612 c = rb_eEINPROGRESSWaitReadable;
14613 break;
14614 default:
14616 }
14617 break;
14618 default:
14619 rb_bug("invalid read/write type passed to rb_readwrite_sys_fail: %d", waiting);
14620 }
14621 rb_exc_raise(rb_class_new_instance(1, &arg, c));
14622}
14623
14624static VALUE
14625get_LAST_READ_LINE(ID _x, VALUE *_y)
14626{
14627 return rb_lastline_get();
14628}
14629
14630static void
14631set_LAST_READ_LINE(VALUE val, ID _x, VALUE *_y)
14632{
14633 rb_lastline_set(val);
14634}
14635
14636/*
14637 * Document-class: IOError
14638 *
14639 * Raised when an IO operation fails.
14640 *
14641 * File.open("/etc/hosts") {|f| f << "example"}
14642 * #=> IOError: not opened for writing
14643 *
14644 * File.open("/etc/hosts") {|f| f.close; f.read }
14645 * #=> IOError: closed stream
14646 *
14647 * Note that some IO failures raise <code>SystemCallError</code>s
14648 * and these are not subclasses of IOError:
14649 *
14650 * File.open("does/not/exist")
14651 * #=> Errno::ENOENT: No such file or directory - does/not/exist
14652 */
14653
14654/*
14655 * Document-class: EOFError
14656 *
14657 * Raised by some IO operations when reaching the end of file. Many IO
14658 * methods exist in two forms,
14659 *
14660 * one that returns +nil+ when the end of file is reached, the other
14661 * raises EOFError.
14662 *
14663 * EOFError is a subclass of IOError.
14664 *
14665 * file = File.open("/etc/hosts")
14666 * file.read
14667 * file.gets #=> nil
14668 * file.readline #=> EOFError: end of file reached
14669 * file.close
14670 */
14671
14672/*
14673 * Document-class: ARGF
14674 *
14675 * ARGF is a stream designed for use in scripts that process files given as
14676 * command-line arguments or passed in via STDIN.
14677 *
14678 * The arguments passed to your script are stored in the +ARGV+ Array, one
14679 * argument per element. ARGF assumes that any arguments that aren't
14680 * filenames have been removed from +ARGV+. For example:
14681 *
14682 * $ ruby argf.rb --verbose file1 file2
14683 *
14684 * ARGV #=> ["--verbose", "file1", "file2"]
14685 * option = ARGV.shift #=> "--verbose"
14686 * ARGV #=> ["file1", "file2"]
14687 *
14688 * You can now use ARGF to work with a concatenation of each of these named
14689 * files. For instance, ARGF.read will return the contents of _file1_
14690 * followed by the contents of _file2_.
14691 *
14692 * After a file in +ARGV+ has been read ARGF removes it from the Array.
14693 * Thus, after all files have been read +ARGV+ will be empty.
14694 *
14695 * You can manipulate +ARGV+ yourself to control what ARGF operates on. If
14696 * you remove a file from +ARGV+, it is ignored by ARGF; if you add files to
14697 * +ARGV+, they are treated as if they were named on the command line. For
14698 * example:
14699 *
14700 * ARGV.replace ["file1"]
14701 * ARGF.readlines # Returns the contents of file1 as an Array
14702 * ARGV #=> []
14703 * ARGV.replace ["file2", "file3"]
14704 * ARGF.read # Returns the contents of file2 and file3
14705 *
14706 * If +ARGV+ is empty, ARGF acts as if it contained <tt>"-"</tt> that
14707 * makes ARGF read from STDIN, i.e. the data piped or typed to your
14708 * script. For example:
14709 *
14710 * $ echo "glark" | ruby -e 'p ARGF.read'
14711 * "glark\n"
14712 *
14713 * $ echo Glark > file1
14714 * $ echo "glark" | ruby -e 'p ARGF.read' -- - file1
14715 * "glark\nGlark\n"
14716 */
14717
14718/*
14719 * An instance of class \IO (commonly called a _stream_)
14720 * represents an input/output stream in the underlying operating system.
14721 * \Class \IO is the basis for input and output in Ruby.
14722 *
14723 * \Class File is the only class in the Ruby core that is a subclass of \IO.
14724 * Some classes in the Ruby standard library are also subclasses of \IO;
14725 * these include TCPSocket and UDPSocket.
14726 *
14727 * The global constant ARGF (also accessible as <tt>$<</tt>)
14728 * provides an IO-like stream that allows access to all file paths
14729 * found in ARGV (or found in STDIN if ARGV is empty).
14730 * ARGF is not itself a subclass of \IO.
14731 *
14732 * \Class StringIO provides an IO-like stream that handles a String.
14733 * StringIO is not itself a subclass of \IO.
14734 *
14735 * Important objects based on \IO include:
14736 *
14737 * - $stdin.
14738 * - $stdout.
14739 * - $stderr.
14740 * - Instances of class File.
14741 *
14742 * An instance of \IO may be created using:
14743 *
14744 * - IO.new: returns a new \IO object for the given integer file descriptor.
14745 * - IO.open: passes a new \IO object to the given block.
14746 * - IO.popen: returns a new \IO object that is connected to the $stdin and $stdout
14747 * of a newly-launched subprocess.
14748 * - Kernel#open: Returns a new \IO object connected to a given source:
14749 * stream, file, or subprocess.
14750 *
14751 * Like a File stream, an \IO stream has:
14752 *
14753 * - A read/write mode, which may be read-only, write-only, or read/write;
14754 * see {Read/Write Mode}[rdoc-ref:File@Read-2FWrite+Mode].
14755 * - A data mode, which may be text-only or binary;
14756 * see {Data Mode}[rdoc-ref:File@Data+Mode].
14757 * - Internal and external encodings;
14758 * see {Encodings}[rdoc-ref:File@Encodings].
14759 *
14760 * And like other \IO streams, it has:
14761 *
14762 * - A position, which determines where in the stream the next
14763 * read or write is to occur;
14764 * see {Position}[rdoc-ref:IO@Position].
14765 * - A line number, which is a special, line-oriented, "position"
14766 * (different from the position mentioned above);
14767 * see {Line Number}[rdoc-ref:IO@Line+Number].
14768 *
14769 * == Extension <tt>io/console</tt>
14770 *
14771 * Extension <tt>io/console</tt> provides numerous methods
14772 * for interacting with the console;
14773 * requiring it adds numerous methods to class \IO.
14774 *
14775 * == Example Files
14776 *
14777 * Many examples here use these variables:
14778 *
14779 * :include: doc/examples/files.rdoc
14780 *
14781 * == Open Options
14782 *
14783 * A number of \IO methods accept optional keyword arguments
14784 * that determine how a new stream is to be opened:
14785 *
14786 * - +:mode+: Stream mode.
14787 * - +:flags+: Integer file open flags;
14788 * If +mode+ is also given, the two are bitwise-ORed.
14789 * - +:external_encoding+: External encoding for the stream.
14790 * - +:internal_encoding+: Internal encoding for the stream.
14791 * <tt>'-'</tt> is a synonym for the default internal encoding.
14792 * If the value is +nil+ no conversion occurs.
14793 * - +:encoding+: Specifies external and internal encodings as <tt>'extern:intern'</tt>.
14794 * - +:textmode+: If a truthy value, specifies the mode as text-only, binary otherwise.
14795 * - +:binmode+: If a truthy value, specifies the mode as binary, text-only otherwise.
14796 * - +:autoclose+: If a truthy value, specifies that the +fd+ will close
14797 * when the stream closes; otherwise it remains open.
14798 * - +:path:+ If a string value is provided, it is used in #inspect and is available as
14799 * #path method.
14800 *
14801 * Also available are the options offered in String#encode,
14802 * which may control conversion between external and internal encoding.
14803 *
14804 * == Basic \IO
14805 *
14806 * You can perform basic stream \IO with these methods,
14807 * which typically operate on multi-byte strings:
14808 *
14809 * - IO#read: Reads and returns some or all of the remaining bytes from the stream.
14810 * - IO#write: Writes zero or more strings to the stream;
14811 * each given object that is not already a string is converted via +to_s+.
14812 *
14813 * === Position
14814 *
14815 * An \IO stream has a nonnegative integer _position_,
14816 * which is the byte offset at which the next read or write is to occur.
14817 * A new stream has position zero (and line number zero);
14818 * method +rewind+ resets the position (and line number) to zero.
14819 *
14820 * The relevant methods:
14821 *
14822 * - IO#tell (aliased as +#pos+): Returns the current position (in bytes) in the stream.
14823 * - IO#pos=: Sets the position of the stream to a given integer +new_position+ (in bytes).
14824 * - IO#seek: Sets the position of the stream to a given integer +offset+ (in bytes),
14825 * relative to a given position +whence+
14826 * (indicating the beginning, end, or current position).
14827 * - IO#rewind: Positions the stream at the beginning (also resetting the line number).
14828 *
14829 * === Open and Closed Streams
14830 *
14831 * A new \IO stream may be open for reading, open for writing, or both.
14832 *
14833 * A stream is automatically closed when claimed by the garbage collector.
14834 *
14835 * Attempted reading or writing on a closed stream raises an exception.
14836 *
14837 * The relevant methods:
14838 *
14839 * - IO#close: Closes the stream for both reading and writing.
14840 * - IO#close_read: Closes the stream for reading.
14841 * - IO#close_write: Closes the stream for writing.
14842 * - IO#closed?: Returns whether the stream is closed.
14843 *
14844 * === End-of-Stream
14845 *
14846 * You can query whether a stream is positioned at its end:
14847 *
14848 * - IO#eof? (also aliased as +#eof+): Returns whether the stream is at end-of-stream.
14849 *
14850 * You can reposition to end-of-stream by using method IO#seek:
14851 *
14852 * f = File.new('t.txt')
14853 * f.eof? # => false
14854 * f.seek(0, :END)
14855 * f.eof? # => true
14856 * f.close
14857 *
14858 * Or by reading all stream content (which is slower than using IO#seek):
14859 *
14860 * f.rewind
14861 * f.eof? # => false
14862 * f.read # => "First line\nSecond line\n\nFourth line\nFifth line\n"
14863 * f.eof? # => true
14864 *
14865 * == Line \IO
14866 *
14867 * You can read an \IO stream line-by-line using these methods:
14868 *
14869 * - IO#each_line: Reads each remaining line, passing it to the given block.
14870 * - IO#gets: Returns the next line.
14871 * - IO#readline: Like #gets, but raises an exception at end-of-stream.
14872 * - IO#readlines: Returns all remaining lines in an array.
14873 *
14874 * Each of these reader methods accepts:
14875 *
14876 * - An optional line separator, +sep+;
14877 * see {Line Separator}[rdoc-ref:IO@Line+Separator].
14878 * - An optional line-size limit, +limit+;
14879 * see {Line Limit}[rdoc-ref:IO@Line+Limit].
14880 *
14881 * For each of these reader methods, reading may begin mid-line,
14882 * depending on the stream's position;
14883 * see {Position}[rdoc-ref:IO@Position]:
14884 *
14885 * f = File.new('t.txt')
14886 * f.pos = 27
14887 * f.each_line {|line| p line }
14888 * f.close
14889 *
14890 * Output:
14891 *
14892 * "rth line\n"
14893 * "Fifth line\n"
14894 *
14895 * You can write to an \IO stream line-by-line using this method:
14896 *
14897 * - IO#puts: Writes objects to the stream.
14898 *
14899 * === Line Separator
14900 *
14901 * Each of these methods uses a <i>line separator</i>,
14902 * which is the string that delimits lines:
14903 *
14904 * - IO.foreach.
14905 * - IO.readlines.
14906 * - IO#each_line.
14907 * - IO#gets.
14908 * - IO#readline.
14909 * - IO#readlines.
14910 *
14911 * The default line separator is the given by the global variable <tt>$/</tt>,
14912 * whose value is by default <tt>"\n"</tt>.
14913 * The line to be read next is all data from the current position
14914 * to the next line separator:
14915 *
14916 * f = File.new('t.txt')
14917 * f.gets # => "First line\n"
14918 * f.gets # => "Second line\n"
14919 * f.gets # => "\n"
14920 * f.gets # => "Fourth line\n"
14921 * f.gets # => "Fifth line\n"
14922 * f.close
14923 *
14924 * You can specify a different line separator:
14925 *
14926 * f = File.new('t.txt')
14927 * f.gets('l') # => "First l"
14928 * f.gets('li') # => "ine\nSecond li"
14929 * f.gets('lin') # => "ne\n\nFourth lin"
14930 * f.gets # => "e\n"
14931 * f.close
14932 *
14933 * There are two special line separators:
14934 *
14935 * - +nil+: The entire stream is read into a single string:
14936 *
14937 * f = File.new('t.txt')
14938 * f.gets(nil) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
14939 * f.close
14940 *
14941 * - <tt>''</tt> (the empty string): The next "paragraph" is read
14942 * (paragraphs being separated by two consecutive line separators):
14943 *
14944 * f = File.new('t.txt')
14945 * f.gets('') # => "First line\nSecond line\n\n"
14946 * f.gets('') # => "Fourth line\nFifth line\n"
14947 * f.close
14948 *
14949 * === Line Limit
14950 *
14951 * Each of these methods uses a <i>line limit</i>,
14952 * which specifies that the number of bytes returned may not be (much) longer
14953 * than the given +limit+;
14954 *
14955 * - IO.foreach.
14956 * - IO.readlines.
14957 * - IO#each_line.
14958 * - IO#gets.
14959 * - IO#readline.
14960 * - IO#readlines.
14961 *
14962 * A multi-byte character will not be split, and so a line may be slightly longer
14963 * than the given limit.
14964 *
14965 * If +limit+ is not given, the line is determined only by +sep+.
14966 *
14967 * # Text with 1-byte characters.
14968 * File.open('t.txt') {|f| f.gets(1) } # => "F"
14969 * File.open('t.txt') {|f| f.gets(2) } # => "Fi"
14970 * File.open('t.txt') {|f| f.gets(3) } # => "Fir"
14971 * File.open('t.txt') {|f| f.gets(4) } # => "Firs"
14972 * # No more than one line.
14973 * File.open('t.txt') {|f| f.gets(10) } # => "First line"
14974 * File.open('t.txt') {|f| f.gets(11) } # => "First line\n"
14975 * File.open('t.txt') {|f| f.gets(12) } # => "First line\n"
14976 *
14977 * # Text with 2-byte characters, which will not be split.
14978 * File.open('t.rus') {|f| f.gets(1).size } # => 1
14979 * File.open('t.rus') {|f| f.gets(2).size } # => 1
14980 * File.open('t.rus') {|f| f.gets(3).size } # => 2
14981 * File.open('t.rus') {|f| f.gets(4).size } # => 2
14982 *
14983 * === Line Separator and Line Limit
14984 *
14985 * With arguments +sep+ and +limit+ given,
14986 * combines the two behaviors:
14987 *
14988 * - Returns the next line as determined by line separator +sep+.
14989 * - But returns no more bytes than are allowed by the limit.
14990 *
14991 * Example:
14992 *
14993 * File.open('t.txt') {|f| f.gets('li', 20) } # => "First li"
14994 * File.open('t.txt') {|f| f.gets('li', 2) } # => "Fi"
14995 *
14996 * === Line Number
14997 *
14998 * A readable \IO stream has a non-negative integer <i>line number</i>.
14999 *
15000 * The relevant methods:
15001 *
15002 * - IO#lineno: Returns the line number.
15003 * - IO#lineno=: Resets and returns the line number.
15004 *
15005 * Unless modified by a call to method IO#lineno=,
15006 * the line number is the number of lines read
15007 * by certain line-oriented methods,
15008 * according to the given line separator +sep+:
15009 *
15010 * - IO.foreach: Increments the line number on each call to the block.
15011 * - IO#each_line: Increments the line number on each call to the block.
15012 * - IO#gets: Increments the line number.
15013 * - IO#readline: Increments the line number.
15014 * - IO#readlines: Increments the line number for each line read.
15015 *
15016 * A new stream is initially has line number zero (and position zero);
15017 * method +rewind+ resets the line number (and position) to zero:
15018 *
15019 * f = File.new('t.txt')
15020 * f.lineno # => 0
15021 * f.gets # => "First line\n"
15022 * f.lineno # => 1
15023 * f.rewind
15024 * f.lineno # => 0
15025 * f.close
15026 *
15027 * Reading lines from a stream usually changes its line number:
15028 *
15029 * f = File.new('t.txt', 'r')
15030 * f.lineno # => 0
15031 * f.readline # => "This is line one.\n"
15032 * f.lineno # => 1
15033 * f.readline # => "This is the second line.\n"
15034 * f.lineno # => 2
15035 * f.readline # => "Here's the third line.\n"
15036 * f.lineno # => 3
15037 * f.eof? # => true
15038 * f.close
15039 *
15040 * Iterating over lines in a stream usually changes its line number:
15041 *
15042 * File.open('t.txt') do |f|
15043 * f.each_line do |line|
15044 * p "position=#{f.pos} eof?=#{f.eof?} lineno=#{f.lineno}"
15045 * end
15046 * end
15047 *
15048 * Output:
15049 *
15050 * "position=11 eof?=false lineno=1"
15051 * "position=23 eof?=false lineno=2"
15052 * "position=24 eof?=false lineno=3"
15053 * "position=36 eof?=false lineno=4"
15054 * "position=47 eof?=true lineno=5"
15055 *
15056 * Unlike the stream's {position}[rdoc-ref:IO@Position],
15057 * the line number does not affect where the next read or write will occur:
15058 *
15059 * f = File.new('t.txt')
15060 * f.lineno = 1000
15061 * f.lineno # => 1000
15062 * f.gets # => "First line\n"
15063 * f.lineno # => 1001
15064 * f.close
15065 *
15066 * Associated with the line number is the global variable <tt>$.</tt>:
15067 *
15068 * - When a stream is opened, <tt>$.</tt> is not set;
15069 * its value is left over from previous activity in the process:
15070 *
15071 * $. = 41
15072 * f = File.new('t.txt')
15073 * $. = 41
15074 * # => 41
15075 * f.close
15076 *
15077 * - When a stream is read, <tt>$.</tt> is set to the line number for that stream:
15078 *
15079 * f0 = File.new('t.txt')
15080 * f1 = File.new('t.dat')
15081 * f0.readlines # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
15082 * $. # => 5
15083 * f1.readlines # => ["\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"]
15084 * $. # => 1
15085 * f0.close
15086 * f1.close
15087 *
15088 * - Methods IO#rewind and IO#seek do not affect <tt>$.</tt>:
15089 *
15090 * f = File.new('t.txt')
15091 * f.readlines # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
15092 * $. # => 5
15093 * f.rewind
15094 * f.seek(0, :SET)
15095 * $. # => 5
15096 * f.close
15097 *
15098 * == Character \IO
15099 *
15100 * You can process an \IO stream character-by-character using these methods:
15101 *
15102 * - IO#getc: Reads and returns the next character from the stream.
15103 * - IO#readchar: Like #getc, but raises an exception at end-of-stream.
15104 * - IO#ungetc: Pushes back ("unshifts") a character or integer onto the stream.
15105 * - IO#putc: Writes a character to the stream.
15106 * - IO#each_char: Reads each remaining character in the stream,
15107 * passing the character to the given block.
15108 * == Byte \IO
15109 *
15110 * You can process an \IO stream byte-by-byte using these methods:
15111 *
15112 * - IO#getbyte: Returns the next 8-bit byte as an integer in range 0..255.
15113 * - IO#readbyte: Like #getbyte, but raises an exception if at end-of-stream.
15114 * - IO#ungetbyte: Pushes back ("unshifts") a byte back onto the stream.
15115 * - IO#each_byte: Reads each remaining byte in the stream,
15116 * passing the byte to the given block.
15117 *
15118 * == Codepoint \IO
15119 *
15120 * You can process an \IO stream codepoint-by-codepoint:
15121 *
15122 * - IO#each_codepoint: Reads each remaining codepoint, passing it to the given block.
15123 *
15124 * == What's Here
15125 *
15126 * First, what's elsewhere. \Class \IO:
15127 *
15128 * - Inherits from {class Object}[rdoc-ref:Object@What-27s+Here].
15129 * - Includes {module Enumerable}[rdoc-ref:Enumerable@What-27s+Here],
15130 * which provides dozens of additional methods.
15131 *
15132 * Here, class \IO provides methods that are useful for:
15133 *
15134 * - {Creating}[rdoc-ref:IO@Creating]
15135 * - {Reading}[rdoc-ref:IO@Reading]
15136 * - {Writing}[rdoc-ref:IO@Writing]
15137 * - {Positioning}[rdoc-ref:IO@Positioning]
15138 * - {Iterating}[rdoc-ref:IO@Iterating]
15139 * - {Settings}[rdoc-ref:IO@Settings]
15140 * - {Querying}[rdoc-ref:IO@Querying]
15141 * - {Buffering}[rdoc-ref:IO@Buffering]
15142 * - {Low-Level Access}[rdoc-ref:IO@Low-Level+Access]
15143 * - {Other}[rdoc-ref:IO@Other]
15144 *
15145 * === Creating
15146 *
15147 * - ::new (aliased as ::for_fd): Creates and returns a new \IO object for the given
15148 * integer file descriptor.
15149 * - ::open: Creates a new \IO object.
15150 * - ::pipe: Creates a connected pair of reader and writer \IO objects.
15151 * - ::popen: Creates an \IO object to interact with a subprocess.
15152 * - ::select: Selects which given \IO instances are ready for reading,
15153 * writing, or have pending exceptions.
15154 *
15155 * === Reading
15156 *
15157 * - ::binread: Returns a binary string with all or a subset of bytes
15158 * from the given file.
15159 * - ::read: Returns a string with all or a subset of bytes from the given file.
15160 * - ::readlines: Returns an array of strings, which are the lines from the given file.
15161 * - #getbyte: Returns the next 8-bit byte read from +self+ as an integer.
15162 * - #getc: Returns the next character read from +self+ as a string.
15163 * - #gets: Returns the line read from +self+.
15164 * - #pread: Returns all or the next _n_ bytes read from +self+,
15165 * not updating the receiver's offset.
15166 * - #read: Returns all remaining or the next _n_ bytes read from +self+
15167 * for a given _n_.
15168 * - #read_nonblock: the next _n_ bytes read from +self+ for a given _n_,
15169 * in non-block mode.
15170 * - #readbyte: Returns the next byte read from +self+;
15171 * same as #getbyte, but raises an exception on end-of-stream.
15172 * - #readchar: Returns the next character read from +self+;
15173 * same as #getc, but raises an exception on end-of-stream.
15174 * - #readline: Returns the next line read from +self+;
15175 * same as #getline, but raises an exception of end-of-stream.
15176 * - #readlines: Returns an array of all lines read read from +self+.
15177 * - #readpartial: Returns up to the given number of bytes from +self+.
15178 *
15179 * === Writing
15180 *
15181 * - ::binwrite: Writes the given string to the file at the given filepath,
15182 * in binary mode.
15183 * - ::write: Writes the given string to +self+.
15184 * - #<<: Appends the given string to +self+.
15185 * - #print: Prints last read line or given objects to +self+.
15186 * - #printf: Writes to +self+ based on the given format string and objects.
15187 * - #putc: Writes a character to +self+.
15188 * - #puts: Writes lines to +self+, making sure line ends with a newline.
15189 * - #pwrite: Writes the given string at the given offset,
15190 * not updating the receiver's offset.
15191 * - #write: Writes one or more given strings to +self+.
15192 * - #write_nonblock: Writes one or more given strings to +self+ in non-blocking mode.
15193 *
15194 * === Positioning
15195 *
15196 * - #lineno: Returns the current line number in +self+.
15197 * - #lineno=: Sets the line number is +self+.
15198 * - #pos (aliased as #tell): Returns the current byte offset in +self+.
15199 * - #pos=: Sets the byte offset in +self+.
15200 * - #reopen: Reassociates +self+ with a new or existing \IO stream.
15201 * - #rewind: Positions +self+ to the beginning of input.
15202 * - #seek: Sets the offset for +self+ relative to given position.
15203 *
15204 * === Iterating
15205 *
15206 * - ::foreach: Yields each line of given file to the block.
15207 * - #each (aliased as #each_line): Calls the given block
15208 * with each successive line in +self+.
15209 * - #each_byte: Calls the given block with each successive byte in +self+
15210 * as an integer.
15211 * - #each_char: Calls the given block with each successive character in +self+
15212 * as a string.
15213 * - #each_codepoint: Calls the given block with each successive codepoint in +self+
15214 * as an integer.
15215 *
15216 * === Settings
15217 *
15218 * - #autoclose=: Sets whether +self+ auto-closes.
15219 * - #binmode: Sets +self+ to binary mode.
15220 * - #close: Closes +self+.
15221 * - #close_on_exec=: Sets the close-on-exec flag.
15222 * - #close_read: Closes +self+ for reading.
15223 * - #close_write: Closes +self+ for writing.
15224 * - #set_encoding: Sets the encoding for +self+.
15225 * - #set_encoding_by_bom: Sets the encoding for +self+, based on its
15226 * Unicode byte-order-mark.
15227 * - #sync=: Sets the sync-mode to the given value.
15228 *
15229 * === Querying
15230 *
15231 * - #autoclose?: Returns whether +self+ auto-closes.
15232 * - #binmode?: Returns whether +self+ is in binary mode.
15233 * - #close_on_exec?: Returns the close-on-exec flag for +self+.
15234 * - #closed?: Returns whether +self+ is closed.
15235 * - #eof? (aliased as #eof): Returns whether +self+ is at end-of-stream.
15236 * - #external_encoding: Returns the external encoding object for +self+.
15237 * - #fileno (aliased as #to_i): Returns the integer file descriptor for +self+
15238 * - #internal_encoding: Returns the internal encoding object for +self+.
15239 * - #pid: Returns the process ID of a child process associated with +self+,
15240 * if +self+ was created by ::popen.
15241 * - #stat: Returns the File::Stat object containing status information for +self+.
15242 * - #sync: Returns whether +self+ is in sync-mode.
15243 * - #tty? (aliased as #isatty): Returns whether +self+ is a terminal.
15244 *
15245 * === Buffering
15246 *
15247 * - #fdatasync: Immediately writes all buffered data in +self+ to disk.
15248 * - #flush: Flushes any buffered data within +self+ to the underlying
15249 * operating system.
15250 * - #fsync: Immediately writes all buffered data and attributes in +self+ to disk.
15251 * - #ungetbyte: Prepends buffer for +self+ with given integer byte or string.
15252 * - #ungetc: Prepends buffer for +self+ with given string.
15253 *
15254 * === Low-Level Access
15255 *
15256 * - ::sysopen: Opens the file given by its path,
15257 * returning the integer file descriptor.
15258 * - #advise: Announces the intention to access data from +self+ in a specific way.
15259 * - #fcntl: Passes a low-level command to the file specified
15260 * by the given file descriptor.
15261 * - #ioctl: Passes a low-level command to the device specified
15262 * by the given file descriptor.
15263 * - #sysread: Returns up to the next _n_ bytes read from self using a low-level read.
15264 * - #sysseek: Sets the offset for +self+.
15265 * - #syswrite: Writes the given string to +self+ using a low-level write.
15266 *
15267 * === Other
15268 *
15269 * - ::copy_stream: Copies data from a source to a destination,
15270 * each of which is a filepath or an \IO-like object.
15271 * - ::try_convert: Returns a new \IO object resulting from converting
15272 * the given object.
15273 * - #inspect: Returns the string representation of +self+.
15274 *
15275 */
15276
15277void
15278Init_IO(void)
15279{
15280 VALUE rb_cARGF;
15281#ifdef __CYGWIN__
15282#include <sys/cygwin.h>
15283 static struct __cygwin_perfile pf[] =
15284 {
15285 {"", O_RDONLY | O_BINARY},
15286 {"", O_WRONLY | O_BINARY},
15287 {"", O_RDWR | O_BINARY},
15288 {"", O_APPEND | O_BINARY},
15289 {NULL, 0}
15290 };
15291 cygwin_internal(CW_PERFILE, pf);
15292#endif
15293
15296
15297 id_write = rb_intern_const("write");
15298 id_read = rb_intern_const("read");
15299 id_getc = rb_intern_const("getc");
15300 id_flush = rb_intern_const("flush");
15301 id_readpartial = rb_intern_const("readpartial");
15302 id_set_encoding = rb_intern_const("set_encoding");
15303 id_fileno = rb_intern_const("fileno");
15304
15305 rb_define_global_function("syscall", rb_f_syscall, -1);
15306
15307 rb_define_global_function("open", rb_f_open, -1);
15308 rb_define_global_function("printf", rb_f_printf, -1);
15309 rb_define_global_function("print", rb_f_print, -1);
15310 rb_define_global_function("putc", rb_f_putc, 1);
15311 rb_define_global_function("puts", rb_f_puts, -1);
15312 rb_define_global_function("gets", rb_f_gets, -1);
15313 rb_define_global_function("readline", rb_f_readline, -1);
15314 rb_define_global_function("select", rb_f_select, -1);
15315
15316 rb_define_global_function("readlines", rb_f_readlines, -1);
15317
15318 rb_define_global_function("`", rb_f_backquote, 1);
15319
15320 rb_define_global_function("p", rb_f_p, -1);
15321 rb_define_method(rb_mKernel, "display", rb_obj_display, -1);
15322
15323 rb_cIO = rb_define_class("IO", rb_cObject);
15325
15326 /* Can be raised by IO operations when IO#timeout= is set. */
15328
15329 /* Readable event mask for IO#wait. */
15331 /* Writable event mask for IO#wait. */
15333 /* Priority event mask for IO#wait. */
15335
15336 /* exception to wait for reading. see IO.select. */
15338 /* exception to wait for writing. see IO.select. */
15340 /* exception to wait for reading by EAGAIN. see IO.select. */
15341 rb_eEAGAINWaitReadable = rb_define_class_under(rb_cIO, "EAGAINWaitReadable", rb_eEAGAIN);
15342 rb_include_module(rb_eEAGAINWaitReadable, rb_mWaitReadable);
15343 /* exception to wait for writing by EAGAIN. see IO.select. */
15344 rb_eEAGAINWaitWritable = rb_define_class_under(rb_cIO, "EAGAINWaitWritable", rb_eEAGAIN);
15345 rb_include_module(rb_eEAGAINWaitWritable, rb_mWaitWritable);
15346#if EAGAIN == EWOULDBLOCK
15347 rb_eEWOULDBLOCKWaitReadable = rb_eEAGAINWaitReadable;
15348 /* same as IO::EAGAINWaitReadable */
15349 rb_define_const(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEAGAINWaitReadable);
15350 rb_eEWOULDBLOCKWaitWritable = rb_eEAGAINWaitWritable;
15351 /* same as IO::EAGAINWaitWritable */
15352 rb_define_const(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEAGAINWaitWritable);
15353#else
15354 /* exception to wait for reading by EWOULDBLOCK. see IO.select. */
15355 rb_eEWOULDBLOCKWaitReadable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEWOULDBLOCK);
15356 rb_include_module(rb_eEWOULDBLOCKWaitReadable, rb_mWaitReadable);
15357 /* exception to wait for writing by EWOULDBLOCK. see IO.select. */
15358 rb_eEWOULDBLOCKWaitWritable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEWOULDBLOCK);
15359 rb_include_module(rb_eEWOULDBLOCKWaitWritable, rb_mWaitWritable);
15360#endif
15361 /* exception to wait for reading by EINPROGRESS. see IO.select. */
15362 rb_eEINPROGRESSWaitReadable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitReadable", rb_eEINPROGRESS);
15363 rb_include_module(rb_eEINPROGRESSWaitReadable, rb_mWaitReadable);
15364 /* exception to wait for writing by EINPROGRESS. see IO.select. */
15365 rb_eEINPROGRESSWaitWritable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitWritable", rb_eEINPROGRESS);
15366 rb_include_module(rb_eEINPROGRESSWaitWritable, rb_mWaitWritable);
15367
15368#if 0
15369 /* This is necessary only for forcing rdoc handle File::open */
15370 rb_define_singleton_method(rb_cFile, "open", rb_io_s_open, -1);
15371#endif
15372
15373 rb_define_alloc_func(rb_cIO, io_alloc);
15374 rb_define_singleton_method(rb_cIO, "new", rb_io_s_new, -1);
15375 rb_define_singleton_method(rb_cIO, "open", rb_io_s_open, -1);
15376 rb_define_singleton_method(rb_cIO, "sysopen", rb_io_s_sysopen, -1);
15377 rb_define_singleton_method(rb_cIO, "for_fd", rb_io_s_for_fd, -1);
15378 rb_define_singleton_method(rb_cIO, "popen", rb_io_s_popen, -1);
15379 rb_define_singleton_method(rb_cIO, "foreach", rb_io_s_foreach, -1);
15380 rb_define_singleton_method(rb_cIO, "readlines", rb_io_s_readlines, -1);
15381 rb_define_singleton_method(rb_cIO, "read", rb_io_s_read, -1);
15382 rb_define_singleton_method(rb_cIO, "binread", rb_io_s_binread, -1);
15383 rb_define_singleton_method(rb_cIO, "write", rb_io_s_write, -1);
15384 rb_define_singleton_method(rb_cIO, "binwrite", rb_io_s_binwrite, -1);
15385 rb_define_singleton_method(rb_cIO, "select", rb_f_select, -1);
15386 rb_define_singleton_method(rb_cIO, "pipe", rb_io_s_pipe, -1);
15387 rb_define_singleton_method(rb_cIO, "try_convert", rb_io_s_try_convert, 1);
15388 rb_define_singleton_method(rb_cIO, "copy_stream", rb_io_s_copy_stream, -1);
15389
15390 rb_define_method(rb_cIO, "initialize", rb_io_initialize, -1);
15391
15392 rb_output_fs = Qnil;
15393 rb_define_hooked_variable("$,", &rb_output_fs, 0, deprecated_str_setter);
15394
15395 rb_default_rs = rb_fstring_lit("\n"); /* avoid modifying RS_default */
15396 rb_gc_register_mark_object(rb_default_rs);
15397 rb_rs = rb_default_rs;
15399 rb_define_hooked_variable("$/", &rb_rs, 0, deprecated_str_setter);
15400 rb_define_hooked_variable("$-0", &rb_rs, 0, deprecated_str_setter);
15401 rb_define_hooked_variable("$\\", &rb_output_rs, 0, deprecated_str_setter);
15402
15403 rb_define_virtual_variable("$_", get_LAST_READ_LINE, set_LAST_READ_LINE);
15404 rb_gvar_ractor_local("$_");
15405
15406 rb_define_method(rb_cIO, "initialize_copy", rb_io_init_copy, 1);
15407 rb_define_method(rb_cIO, "reopen", rb_io_reopen, -1);
15408
15409 rb_define_method(rb_cIO, "print", rb_io_print, -1);
15410 rb_define_method(rb_cIO, "putc", rb_io_putc, 1);
15411 rb_define_method(rb_cIO, "puts", rb_io_puts, -1);
15412 rb_define_method(rb_cIO, "printf", rb_io_printf, -1);
15413
15414 rb_define_method(rb_cIO, "each", rb_io_each_line, -1);
15415 rb_define_method(rb_cIO, "each_line", rb_io_each_line, -1);
15416 rb_define_method(rb_cIO, "each_byte", rb_io_each_byte, 0);
15417 rb_define_method(rb_cIO, "each_char", rb_io_each_char, 0);
15418 rb_define_method(rb_cIO, "each_codepoint", rb_io_each_codepoint, 0);
15419
15420 rb_define_method(rb_cIO, "syswrite", rb_io_syswrite, 1);
15421 rb_define_method(rb_cIO, "sysread", rb_io_sysread, -1);
15422
15423 rb_define_method(rb_cIO, "pread", rb_io_pread, -1);
15424 rb_define_method(rb_cIO, "pwrite", rb_io_pwrite, 2);
15425
15426 rb_define_method(rb_cIO, "fileno", rb_io_fileno, 0);
15427 rb_define_alias(rb_cIO, "to_i", "fileno");
15428 rb_define_method(rb_cIO, "to_io", rb_io_to_io, 0);
15429
15430 rb_define_method(rb_cIO, "timeout", rb_io_timeout, 0);
15431 rb_define_method(rb_cIO, "timeout=", rb_io_set_timeout, 1);
15432
15433 rb_define_method(rb_cIO, "fsync", rb_io_fsync, 0);
15434 rb_define_method(rb_cIO, "fdatasync", rb_io_fdatasync, 0);
15435 rb_define_method(rb_cIO, "sync", rb_io_sync, 0);
15436 rb_define_method(rb_cIO, "sync=", rb_io_set_sync, 1);
15437
15438 rb_define_method(rb_cIO, "lineno", rb_io_lineno, 0);
15439 rb_define_method(rb_cIO, "lineno=", rb_io_set_lineno, 1);
15440
15441 rb_define_method(rb_cIO, "readlines", rb_io_readlines, -1);
15442
15443 rb_define_method(rb_cIO, "readpartial", io_readpartial, -1);
15444 rb_define_method(rb_cIO, "read", io_read, -1);
15445 rb_define_method(rb_cIO, "write", io_write_m, -1);
15446 rb_define_method(rb_cIO, "gets", rb_io_gets_m, -1);
15447 rb_define_method(rb_cIO, "getc", rb_io_getc, 0);
15448 rb_define_method(rb_cIO, "getbyte", rb_io_getbyte, 0);
15449 rb_define_method(rb_cIO, "readchar", rb_io_readchar, 0);
15450 rb_define_method(rb_cIO, "readbyte", rb_io_readbyte, 0);
15451 rb_define_method(rb_cIO, "ungetbyte",rb_io_ungetbyte, 1);
15452 rb_define_method(rb_cIO, "ungetc",rb_io_ungetc, 1);
15454 rb_define_method(rb_cIO, "flush", rb_io_flush, 0);
15455 rb_define_method(rb_cIO, "tell", rb_io_tell, 0);
15456 rb_define_method(rb_cIO, "seek", rb_io_seek_m, -1);
15457 /* Set I/O position from the beginning */
15458 rb_define_const(rb_cIO, "SEEK_SET", INT2FIX(SEEK_SET));
15459 /* Set I/O position from the current position */
15460 rb_define_const(rb_cIO, "SEEK_CUR", INT2FIX(SEEK_CUR));
15461 /* Set I/O position from the end */
15462 rb_define_const(rb_cIO, "SEEK_END", INT2FIX(SEEK_END));
15463#ifdef SEEK_DATA
15464 /* Set I/O position to the next location containing data */
15465 rb_define_const(rb_cIO, "SEEK_DATA", INT2FIX(SEEK_DATA));
15466#endif
15467#ifdef SEEK_HOLE
15468 /* Set I/O position to the next hole */
15469 rb_define_const(rb_cIO, "SEEK_HOLE", INT2FIX(SEEK_HOLE));
15470#endif
15471 rb_define_method(rb_cIO, "rewind", rb_io_rewind, 0);
15472 rb_define_method(rb_cIO, "pos", rb_io_tell, 0);
15473 rb_define_method(rb_cIO, "pos=", rb_io_set_pos, 1);
15474 rb_define_method(rb_cIO, "eof", rb_io_eof, 0);
15475 rb_define_method(rb_cIO, "eof?", rb_io_eof, 0);
15476
15477 rb_define_method(rb_cIO, "close_on_exec?", rb_io_close_on_exec_p, 0);
15478 rb_define_method(rb_cIO, "close_on_exec=", rb_io_set_close_on_exec, 1);
15479
15480 rb_define_method(rb_cIO, "close", rb_io_close_m, 0);
15481 rb_define_method(rb_cIO, "closed?", rb_io_closed_p, 0);
15482 rb_define_method(rb_cIO, "close_read", rb_io_close_read, 0);
15483 rb_define_method(rb_cIO, "close_write", rb_io_close_write, 0);
15484
15485 rb_define_method(rb_cIO, "isatty", rb_io_isatty, 0);
15486 rb_define_method(rb_cIO, "tty?", rb_io_isatty, 0);
15487 rb_define_method(rb_cIO, "binmode", rb_io_binmode_m, 0);
15488 rb_define_method(rb_cIO, "binmode?", rb_io_binmode_p, 0);
15489 rb_define_method(rb_cIO, "sysseek", rb_io_sysseek, -1);
15490 rb_define_method(rb_cIO, "advise", rb_io_advise, -1);
15491
15492 rb_define_method(rb_cIO, "ioctl", rb_io_ioctl, -1);
15493 rb_define_method(rb_cIO, "fcntl", rb_io_fcntl, -1);
15494 rb_define_method(rb_cIO, "pid", rb_io_pid, 0);
15495
15496 rb_define_method(rb_cIO, "path", rb_io_path, 0);
15497 rb_define_method(rb_cIO, "to_path", rb_io_path, 0);
15498
15499 rb_define_method(rb_cIO, "inspect", rb_io_inspect, 0);
15500
15501 rb_define_method(rb_cIO, "external_encoding", rb_io_external_encoding, 0);
15502 rb_define_method(rb_cIO, "internal_encoding", rb_io_internal_encoding, 0);
15503 rb_define_method(rb_cIO, "set_encoding", rb_io_set_encoding, -1);
15504 rb_define_method(rb_cIO, "set_encoding_by_bom", rb_io_set_encoding_by_bom, 0);
15505
15506 rb_define_method(rb_cIO, "autoclose?", rb_io_autoclose_p, 0);
15507 rb_define_method(rb_cIO, "autoclose=", rb_io_set_autoclose, 1);
15508
15509 rb_define_method(rb_cIO, "wait", io_wait, -1);
15510
15511 rb_define_method(rb_cIO, "wait_readable", io_wait_readable, -1);
15512 rb_define_method(rb_cIO, "wait_writable", io_wait_writable, -1);
15513 rb_define_method(rb_cIO, "wait_priority", io_wait_priority, -1);
15514
15515 rb_define_virtual_variable("$stdin", stdin_getter, stdin_setter);
15516 rb_define_virtual_variable("$stdout", stdout_getter, stdout_setter);
15517 rb_define_virtual_variable("$>", stdout_getter, stdout_setter);
15518 rb_define_virtual_variable("$stderr", stderr_getter, stderr_setter);
15519
15520 rb_gvar_ractor_local("$stdin");
15521 rb_gvar_ractor_local("$stdout");
15522 rb_gvar_ractor_local("$>");
15523 rb_gvar_ractor_local("$stderr");
15524
15526 rb_stdin = rb_io_prep_stdin();
15528 rb_stdout = rb_io_prep_stdout();
15530 rb_stderr = rb_io_prep_stderr();
15531
15532 orig_stdout = rb_stdout;
15533 orig_stderr = rb_stderr;
15534
15535 /* Holds the original stdin */
15537 /* Holds the original stdout */
15539 /* Holds the original stderr */
15541
15542#if 0
15543 /* Hack to get rdoc to regard ARGF as a class: */
15544 rb_cARGF = rb_define_class("ARGF", rb_cObject);
15545#endif
15546
15547 rb_cARGF = rb_class_new(rb_cObject);
15548 rb_set_class_path(rb_cARGF, rb_cObject, "ARGF.class");
15549 rb_define_alloc_func(rb_cARGF, argf_alloc);
15550
15552
15553 rb_define_method(rb_cARGF, "initialize", argf_initialize, -2);
15554 rb_define_method(rb_cARGF, "initialize_copy", argf_initialize_copy, 1);
15555 rb_define_method(rb_cARGF, "to_s", argf_to_s, 0);
15556 rb_define_alias(rb_cARGF, "inspect", "to_s");
15557 rb_define_method(rb_cARGF, "argv", argf_argv, 0);
15558
15559 rb_define_method(rb_cARGF, "fileno", argf_fileno, 0);
15560 rb_define_method(rb_cARGF, "to_i", argf_fileno, 0);
15561 rb_define_method(rb_cARGF, "to_io", argf_to_io, 0);
15562 rb_define_method(rb_cARGF, "to_write_io", argf_write_io, 0);
15563 rb_define_method(rb_cARGF, "each", argf_each_line, -1);
15564 rb_define_method(rb_cARGF, "each_line", argf_each_line, -1);
15565 rb_define_method(rb_cARGF, "each_byte", argf_each_byte, 0);
15566 rb_define_method(rb_cARGF, "each_char", argf_each_char, 0);
15567 rb_define_method(rb_cARGF, "each_codepoint", argf_each_codepoint, 0);
15568
15569 rb_define_method(rb_cARGF, "read", argf_read, -1);
15570 rb_define_method(rb_cARGF, "readpartial", argf_readpartial, -1);
15571 rb_define_method(rb_cARGF, "read_nonblock", argf_read_nonblock, -1);
15572 rb_define_method(rb_cARGF, "readlines", argf_readlines, -1);
15573 rb_define_method(rb_cARGF, "to_a", argf_readlines, -1);
15574 rb_define_method(rb_cARGF, "gets", argf_gets, -1);
15575 rb_define_method(rb_cARGF, "readline", argf_readline, -1);
15576 rb_define_method(rb_cARGF, "getc", argf_getc, 0);
15577 rb_define_method(rb_cARGF, "getbyte", argf_getbyte, 0);
15578 rb_define_method(rb_cARGF, "readchar", argf_readchar, 0);
15579 rb_define_method(rb_cARGF, "readbyte", argf_readbyte, 0);
15580 rb_define_method(rb_cARGF, "tell", argf_tell, 0);
15581 rb_define_method(rb_cARGF, "seek", argf_seek_m, -1);
15582 rb_define_method(rb_cARGF, "rewind", argf_rewind, 0);
15583 rb_define_method(rb_cARGF, "pos", argf_tell, 0);
15584 rb_define_method(rb_cARGF, "pos=", argf_set_pos, 1);
15585 rb_define_method(rb_cARGF, "eof", argf_eof, 0);
15586 rb_define_method(rb_cARGF, "eof?", argf_eof, 0);
15587 rb_define_method(rb_cARGF, "binmode", argf_binmode_m, 0);
15588 rb_define_method(rb_cARGF, "binmode?", argf_binmode_p, 0);
15589
15590 rb_define_method(rb_cARGF, "write", argf_write, 1);
15591 rb_define_method(rb_cARGF, "print", rb_io_print, -1);
15592 rb_define_method(rb_cARGF, "putc", rb_io_putc, 1);
15593 rb_define_method(rb_cARGF, "puts", rb_io_puts, -1);
15594 rb_define_method(rb_cARGF, "printf", rb_io_printf, -1);
15595
15596 rb_define_method(rb_cARGF, "filename", argf_filename, 0);
15597 rb_define_method(rb_cARGF, "path", argf_filename, 0);
15598 rb_define_method(rb_cARGF, "file", argf_file, 0);
15599 rb_define_method(rb_cARGF, "skip", argf_skip, 0);
15600 rb_define_method(rb_cARGF, "close", argf_close_m, 0);
15601 rb_define_method(rb_cARGF, "closed?", argf_closed, 0);
15602
15603 rb_define_method(rb_cARGF, "lineno", argf_lineno, 0);
15604 rb_define_method(rb_cARGF, "lineno=", argf_set_lineno, 1);
15605
15606 rb_define_method(rb_cARGF, "inplace_mode", argf_inplace_mode_get, 0);
15607 rb_define_method(rb_cARGF, "inplace_mode=", argf_inplace_mode_set, 1);
15608
15609 rb_define_method(rb_cARGF, "external_encoding", argf_external_encoding, 0);
15610 rb_define_method(rb_cARGF, "internal_encoding", argf_internal_encoding, 0);
15611 rb_define_method(rb_cARGF, "set_encoding", argf_set_encoding, -1);
15612
15613 argf = rb_class_new_instance(0, 0, rb_cARGF);
15614
15616 /*
15617 * ARGF is a stream designed for use in scripts that process files given
15618 * as command-line arguments or passed in via STDIN.
15619 *
15620 * See ARGF (the class) for more details.
15621 */
15623
15624 rb_define_hooked_variable("$.", &argf, argf_lineno_getter, argf_lineno_setter);
15625 rb_define_hooked_variable("$FILENAME", &argf, argf_filename_getter, rb_gvar_readonly_setter);
15626 ARGF.filename = rb_str_new2("-");
15627
15628 rb_define_hooked_variable("$-i", &argf, opt_i_get, opt_i_set);
15629 rb_gvar_ractor_local("$-i");
15630
15631 rb_define_hooked_variable("$*", &argf, argf_argv_getter, rb_gvar_readonly_setter);
15632
15633#if defined (_WIN32) || defined(__CYGWIN__)
15634 atexit(pipe_atexit);
15635#endif
15636
15637 Init_File();
15638
15639 rb_define_method(rb_cFile, "initialize", rb_file_initialize, -1);
15640
15641 sym_mode = ID2SYM(rb_intern_const("mode"));
15642 sym_perm = ID2SYM(rb_intern_const("perm"));
15643 sym_flags = ID2SYM(rb_intern_const("flags"));
15644 sym_extenc = ID2SYM(rb_intern_const("external_encoding"));
15645 sym_intenc = ID2SYM(rb_intern_const("internal_encoding"));
15646 sym_encoding = ID2SYM(rb_id_encoding());
15647 sym_open_args = ID2SYM(rb_intern_const("open_args"));
15648 sym_textmode = ID2SYM(rb_intern_const("textmode"));
15649 sym_binmode = ID2SYM(rb_intern_const("binmode"));
15650 sym_autoclose = ID2SYM(rb_intern_const("autoclose"));
15651 sym_normal = ID2SYM(rb_intern_const("normal"));
15652 sym_sequential = ID2SYM(rb_intern_const("sequential"));
15653 sym_random = ID2SYM(rb_intern_const("random"));
15654 sym_willneed = ID2SYM(rb_intern_const("willneed"));
15655 sym_dontneed = ID2SYM(rb_intern_const("dontneed"));
15656 sym_noreuse = ID2SYM(rb_intern_const("noreuse"));
15657 sym_SET = ID2SYM(rb_intern_const("SET"));
15658 sym_CUR = ID2SYM(rb_intern_const("CUR"));
15659 sym_END = ID2SYM(rb_intern_const("END"));
15660#ifdef SEEK_DATA
15661 sym_DATA = ID2SYM(rb_intern_const("DATA"));
15662#endif
15663#ifdef SEEK_HOLE
15664 sym_HOLE = ID2SYM(rb_intern_const("HOLE"));
15665#endif
15666 sym_wait_readable = ID2SYM(rb_intern_const("wait_readable"));
15667 sym_wait_writable = ID2SYM(rb_intern_const("wait_writable"));
15668}
15669
15670#include "io.rbinc"
std::atomic< unsigned > rb_atomic_t
Type that is eligible for atomic operations.
Definition atomic.h:69
unsigned long ruby_strtoul(const char *str, char **endptr, int base)
Our own locale-insensitive version of strtoul(3).
Definition util.c:137
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
#define rb_define_singleton_method(klass, mid, func, arity)
Defines klass.mid.
#define rb_define_global_function(mid, func, arity)
Defines rb_mKernel #mid.
void rb_include_module(VALUE klass, VALUE module)
Includes a module to a class.
Definition class.c:1172
VALUE rb_define_class(const char *name, VALUE super)
Defines a top-level class.
Definition class.c:970
VALUE rb_class_new(VALUE super)
Creates a new, anonymous class.
Definition class.c:350
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
Definition class.c:1002
VALUE rb_define_module_under(VALUE outer, const char *name)
Defines a module under the namespace of outer.
Definition class.c:1104
void rb_define_alias(VALUE klass, const char *name1, const char *name2)
Defines an alias of a method.
Definition class.c:2331
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:2634
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:2621
int rb_block_given_p(void)
Determines if the current method is given a block.
Definition eval.c:866
int rb_get_kwargs(VALUE keyword_hash, const ID *table, int required, int optional, VALUE *values)
Keyword argument deconstructor.
Definition class.c:2410
#define ECONV_AFTER_OUTPUT
Old name of RUBY_ECONV_AFTER_OUTPUT.
Definition transcode.h:555
#define rb_str_new2
Old name of rb_str_new_cstr.
Definition string.h:1675
#define TYPE(_)
Old name of rb_type.
Definition value_type.h:107
#define NEWOBJ_OF
Old name of RB_NEWOBJ_OF.
Definition newobj.h:61
#define FL_SINGLETON
Old name of RUBY_FL_SINGLETON.
Definition fl_type.h:58
#define RB_INTEGER_TYPE_P
Old name of rb_integer_type_p.
Definition value_type.h:87
#define ENC_CODERANGE_7BIT
Old name of RUBY_ENC_CODERANGE_7BIT.
Definition coderange.h:180
#define T_FILE
Old name of RUBY_T_FILE.
Definition value_type.h:62
#define ENC_CODERANGE_VALID
Old name of RUBY_ENC_CODERANGE_VALID.
Definition coderange.h:181
#define ECONV_UNIVERSAL_NEWLINE_DECORATOR
Old name of RUBY_ECONV_UNIVERSAL_NEWLINE_DECORATOR.
Definition transcode.h:532
#define OBJ_INIT_COPY(obj, orig)
Old name of RB_OBJ_INIT_COPY.
Definition object.h:41
#define ALLOC
Old name of RB_ALLOC.
Definition memory.h:394
#define T_STRING
Old name of RUBY_T_STRING.
Definition value_type.h:78
#define Qundef
Old name of RUBY_Qundef.
#define INT2FIX
Old name of RB_INT2FIX.
Definition long.h:48
#define rb_str_cat2
Old name of rb_str_cat_cstr.
Definition string.h:1683
#define T_NIL
Old name of RUBY_T_NIL.
Definition value_type.h:72
#define UNREACHABLE
Old name of RBIMPL_UNREACHABLE.
Definition assume.h:28
#define ID2SYM
Old name of RB_ID2SYM.
Definition symbol.h:44
#define T_BIGNUM
Old name of RUBY_T_BIGNUM.
Definition value_type.h:57
#define OBJ_FREEZE
Old name of RB_OBJ_FREEZE.
Definition fl_type.h: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:396
#define CLASS_OF
Old name of rb_class_of.
Definition globals.h:203
#define rb_ary_new4
Old name of rb_ary_new_from_values.
Definition array.h:653
#define ENCODING_MAXNAMELEN
Old name of RUBY_ENCODING_MAXNAMELEN.
Definition encoding.h:110
#define MBCLEN_NEEDMORE_LEN(ret)
Old name of ONIGENC_MBCLEN_NEEDMORE_LEN.
Definition encoding.h:519
#define ENCODING_GET(obj)
Old name of RB_ENCODING_GET.
Definition encoding.h:108
#define LONG2FIX
Old name of RB_INT2FIX.
Definition long.h:49
#define NUM2UINT
Old name of RB_NUM2UINT.
Definition int.h:45
#define ALLOC_N
Old name of RB_ALLOC_N.
Definition memory.h:393
#define MBCLEN_CHARFOUND_LEN(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_LEN.
Definition encoding.h:516
#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:517
#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:518
#define ECONV_PARTIAL_INPUT
Old name of RUBY_ECONV_PARTIAL_INPUT.
Definition transcode.h:554
#define NUM2INT
Old name of RB_NUM2INT.
Definition int.h:44
#define ECONV_ERROR_HANDLER_MASK
Old name of RUBY_ECONV_ERROR_HANDLER_MASK.
Definition transcode.h:522
#define INT2NUM
Old name of RB_INT2NUM.
Definition int.h:43
#define Qnil
Old name of RUBY_Qnil.
#define Qfalse
Old name of RUBY_Qfalse.
#define FIX2LONG
Old name of RB_FIX2LONG.
Definition long.h:46
#define ENC_CODERANGE_BROKEN
Old name of RUBY_ENC_CODERANGE_BROKEN.
Definition coderange.h:182
#define T_ARRAY
Old name of RUBY_T_ARRAY.
Definition value_type.h:56
#define NIL_P
Old name of RB_NIL_P.
#define ALLOCV_N
Old name of RB_ALLOCV_N.
Definition memory.h:399
#define MBCLEN_CHARFOUND_P(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_P.
Definition encoding.h:515
#define NUM2CHR
Old name of RB_NUM2CHR.
Definition char.h:33
#define FL_TEST
Old name of RB_FL_TEST.
Definition fl_type.h:131
#define NUM2LONG
Old name of RB_NUM2LONG.
Definition long.h:51
#define UINT2NUM
Old name of RB_UINT2NUM.
Definition int.h:46
#define FIXNUM_P
Old name of RB_FIXNUM_P.
#define ECONV_NEWLINE_DECORATOR_MASK
Old name of RUBY_ECONV_NEWLINE_DECORATOR_MASK.
Definition transcode.h:529
#define CONST_ID
Old name of RUBY_CONST_ID.
Definition symbol.h:47
#define rb_ary_new2
Old name of rb_ary_new_capa.
Definition array.h:651
#define NUM2SIZET
Old name of RB_NUM2SIZE.
Definition size_t.h:61
#define ENC_CODERANGE_SET(obj, cr)
Old name of RB_ENC_CODERANGE_SET.
Definition coderange.h:186
#define rb_str_new4
Old name of rb_str_new_frozen.
Definition string.h:1677
#define ALLOCV_END
Old name of RB_ALLOCV_END.
Definition memory.h:400
#define SYMBOL_P
Old name of RB_SYMBOL_P.
Definition value_type.h:88
#define ECONV_DEFAULT_NEWLINE_DECORATOR
Old name of RUBY_ECONV_DEFAULT_NEWLINE_DECORATOR.
Definition transcode.h:540
void rb_notimplement(void)
Definition error.c:3498
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:433
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:465
VALUE rb_eNotImpError
NotImplementedError exception.
Definition error.c:1354
void rb_syserr_fail(int e, const char *mesg)
Raises appropriate exception that represents a C errno.
Definition error.c:3567
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:14579
VALUE rb_eIOError
IOError exception.
Definition io.c:178
VALUE rb_eStandardError
StandardError exception.
Definition error.c:1341
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:3657
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:3573
#define ruby_verbose
This variable controls whether the interpreter is in debug mode.
Definition error.h:471
VALUE rb_eTypeError
TypeError exception.
Definition error.c:1344
VALUE rb_eEOFError
EOFError exception.
Definition io.c:177
void rb_readwrite_sys_fail(enum rb_io_wait_readwrite waiting, const char *mesg)
Raises appropriate exception using the parameters.
Definition io.c:14573
void rb_iter_break_value(VALUE val)
Identical to rb_iter_break(), except it additionally takes the "value" of this breakage.
Definition vm.c:2049
rb_io_wait_readwrite
for rb_readwrite_sys_fail first argument
Definition error.h:69
VALUE rb_eRuntimeError
RuntimeError exception.
Definition error.c:1342
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports unless $VERBOSE is nil.
Definition error.c:423
VALUE rb_eSystemCallError
SystemCallError exception.
Definition error.c:1364
@ RB_WARN_CATEGORY_DEPRECATED
Warning is for deprecated features.
Definition error.h:48
VALUE rb_mKernel
Kernel module.
Definition object.c:63
VALUE rb_check_to_int(VALUE val)
Identical to rb_check_to_integer(), except it uses #to_int for conversion.
Definition object.c:3142
VALUE rb_any_to_s(VALUE obj)
Generates a textual representation of the given object.
Definition object.c:625
VALUE rb_obj_alloc(VALUE klass)
Allocates an instance of the given class.
Definition object.c:2049
VALUE rb_class_new_instance(int argc, const VALUE *argv, VALUE klass)
Allocates, then initialises an instance of the given class.
Definition object.c:2090
VALUE rb_cIO
IO class.
Definition io.c:176
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:2078
VALUE rb_mEnumerable
Enumerable module.
Definition enum.c:27
VALUE rb_stdin
STDIN constant.
Definition io.c:190
VALUE rb_stderr
STDERR constant.
Definition io.c:190
VALUE rb_obj_class(VALUE obj)
Queries the class of an object.
Definition object.c:215
VALUE rb_obj_dup(VALUE obj)
Duplicates the given object.
Definition object.c:529
VALUE rb_inspect(VALUE obj)
Generates a human-readable textual representation of the given object.
Definition object.c:636
VALUE rb_mWaitReadable
IO::WaitReadable module.
Definition io.c:180
VALUE rb_mWaitWritable
IO::WaitReadable module.
Definition io.c:181
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:3123
VALUE rb_cFile
File class.
Definition file.c:175
VALUE rb_stdout
STDOUT constant.
Definition io.c:190
VALUE rb_to_int(VALUE val)
Identical to rb_check_to_int(), except it raises in case of conversion mismatch.
Definition object.c:3136
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:682
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:570
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:431
VALUE rb_enc_uint_chr(unsigned int code, rb_encoding *enc)
Encodes the passed code point into a series of bytes.
Definition numeric.c:3740
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:653
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
const char * rb_econv_asciicompat_encoding(const char *encname)
Queries the passed encoding's corresponding ASCII compatible encoding.
Definition transcode.c:1814
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
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_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
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:1121
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:1088
#define RETURN_ENUMERATOR(obj, argc, argv)
Identical to RETURN_SIZED_ENUMERATOR(), except its size is unknown.
Definition enumerator.h:239
#define rb_check_frozen
Just another name of rb_check_frozen.
Definition error.h:264
static int rb_check_arity(int argc, int min, int max)
Ensures that the passed integer is in the passed range.
Definition error.h:280
VALUE rb_io_printf(int argc, const VALUE *argv, VALUE io)
This is a rb_f_sprintf() + rb_io_write() combo.
Definition io.c:8542
VALUE rb_io_gets(VALUE io)
Reads a "line" from the given IO.
Definition io.c:4235
int rb_cloexec_pipe(int fildes[2])
Opens a pipe with closing on exec.
Definition io.c:405
VALUE rb_io_print(int argc, const VALUE *argv, VALUE io)
Iterates over the passed array to apply rb_io_write() individually.
Definition io.c:8668
VALUE rb_io_addstr(VALUE io, VALUE str)
Identical to rb_io_write(), except it always returns the passed IO.
Definition io.c:2319
void rb_write_error(const char *str)
Writes the given error message to somewhere applicable.
Definition io.c:9097
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:5103
VALUE rb_io_getbyte(VALUE io)
Reads a byte from the given IO.
Definition io.c:5009
int rb_cloexec_dup2(int oldfd, int newfd)
Identical to rb_cloexec_dup(), except you can specify the destination file descriptor.
Definition io.c:352
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:9257
void rb_update_max_fd(int fd)
Informs the interpreter that the passed fd can be the max.
Definition io.c:226
int rb_cloexec_open(const char *pathname, int flags, mode_t mode)
Opens a file that closes on exec.
Definition io.c:306
VALUE rb_output_rs
The record separator character for outputs, or the $\.
Definition io.c:195
VALUE rb_io_eof(VALUE io)
Queries if the passed IO is at the end of file.
Definition io.c:2664
void rb_write_error2(const char *str, long len)
Identical to rb_write_error(), except it additionally takes the message's length.
Definition io.c:9077
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:276
VALUE rb_io_ascii8bit_binmode(VALUE io)
Forces no conversions be applied to the passed IO.
Definition io.c:6310
VALUE rb_io_binmode(VALUE io)
Sets the binmode.
Definition io.c:6264
VALUE rb_io_ungetc(VALUE io, VALUE c)
"Unget"s a string.
Definition io.c:5167
int rb_pipe(int *pipes)
This is an rb_cloexec_pipe() + rb_update_max_fd() combo.
Definition io.c:7302
VALUE rb_gets(void)
Much like rb_io_gets(), but it reads from the mysterious ARGF object.
Definition io.c:10319
int rb_cloexec_fcntl_dupfd(int fd, int minfd)
Duplicates a file descriptor with closing on exec.
Definition io.c:439
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:7185
int rb_cloexec_dup(int oldfd)
Identical to rb_cloexec_fcntl_dupfd(), except it implies minfd is 3.
Definition io.c:345
VALUE rb_file_open(const char *fname, const char *fmode)
Opens a file located at the given path.
Definition io.c:7192
VALUE rb_io_close(VALUE io)
Closes the IO.
Definition io.c:5690
void rb_lastline_set(VALUE str)
Updates $_.
Definition vm.c:1811
VALUE rb_lastline_get(void)
Queries the last line, or the $_.
Definition vm.c:1805
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:2866
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:3382
#define rb_str_new(str, len)
Allocates an instance of rb_cString.
Definition string.h:1498
#define rb_str_buf_cat
Just another name of rb_str_cat.
Definition string.h:1681
#define rb_usascii_str_new(str, len)
Identical to rb_str_new, except it generates a string of "US ASCII" encoding.
Definition string.h:1532
size_t rb_str_capacity(VALUE str)
Queries the capacity of the given string.
Definition string.c:815
VALUE rb_str_locktmp(VALUE str)
Obtains a "temporary lock" of the string.
rb_gvar_setter_t rb_str_setter
This is a rb_gvar_setter_t that refutes non-string assignments.
Definition string.h:1146
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:3324
VALUE rb_check_string_type(VALUE obj)
Try converting an object to its stringised representation using its to_str method,...
Definition string.c:2654
VALUE rb_str_substr(VALUE str, long beg, long len)
This is the implementation of two-argumented String#slice.
Definition string.c:2950
VALUE rb_str_unlocktmp(VALUE str)
Releases a lock formerly obtained by rb_str_locktmp().
Definition string.c:3043
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:2459
#define rb_str_new_cstr(str)
Identical to rb_str_new, except it assumes the passed pointer is a pointer to a C string.
Definition string.h:1514
int rb_thread_interrupted(VALUE thval)
Checks if the thread's execution was recently interrupted.
Definition thread.c:1417
VALUE rb_mutex_new(void)
Creates a mutex.
int rb_thread_fd_writable(int fd)
Identical to rb_thread_wait_fd(), except it blocks the current thread until the given file descriptor...
Definition io.c:1572
#define RUBY_UBF_IO
A special UBF for blocking IO operations.
Definition thread.h:382
VALUE rb_exec_recursive(VALUE(*f)(VALUE g, VALUE h, int r), VALUE g, VALUE h)
"Recursion" API entry point.
void rb_thread_fd_close(int fd)
Notifies a closing of a file descriptor to other threads.
Definition thread.c:2627
VALUE rb_mutex_synchronize(VALUE mutex, VALUE(*func)(VALUE arg), VALUE arg)
Obtains the lock, runs the passed function, and releases the lock when it completes.
void rb_thread_check_ints(void)
Checks for interrupts.
Definition thread.c:1400
VALUE rb_thread_current(void)
Obtains the "current" thread.
Definition thread.c:2904
int rb_thread_wait_fd(int fd)
Blocks the current thread until the given file descriptor is ready to be read.
Definition io.c:1566
void rb_thread_sleep(int sec)
Blocks for the given period of time.
Definition thread.c:1423
struct timeval rb_time_interval(VALUE num)
Creates a "time interval".
Definition time.c:2875
void rb_set_class_path(VALUE klass, VALUE space, const char *name)
Names a class.
Definition variable.c:343
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:1854
VALUE rb_class_name(VALUE obj)
Queries the name of the given object's class.
Definition variable.c:402
int rb_respond_to(VALUE obj, ID mid)
Queries if the object responds to the method.
Definition vm_method.c:2822
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:687
void rb_define_alloc_func(VALUE klass, rb_alloc_func_t func)
Sets the allocator function of a class.
static ID rb_intern_const(const char *str)
This is a "tiny optimisation" over rb_intern().
Definition symbol.h:276
#define RB_ID2SYM
Just another name of rb_id2sym.
Definition symbol.h:42
void rb_define_global_const(const char *name, VALUE val)
Identical to rb_define_const(), except it defines that of "global", i.e.
Definition variable.c:3702
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:722
rb_gvar_setter_t rb_gvar_readonly_setter
This function just raises rb_eNameError.
Definition variable.h:135
void rb_define_const(VALUE klass, const char *name, VALUE val)
Defines a Ruby level constant under a namespace.
Definition variable.c:3690
#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:6396
VALUE rb_io_get_io(VALUE io)
Identical to rb_io_check_io(), except it raises exceptions on conversion failures.
Definition io.c:792
VALUE rb_io_timeout(VALUE io)
Get the timeout associated with the specified io object.
Definition io.c:838
VALUE rb_io_taint_check(VALUE obj)
Definition io.c:762
void rb_io_read_check(rb_io_t *fptr)
Blocks until there is a pending read in the passed IO.
Definition io.c:1049
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:6529
#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:2885
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:995
#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:1004
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:6678
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:1560
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:7009
int rb_io_descriptor(VALUE io)
Returns an integer representing the numeric file descriptor for io.
Definition io.c:2865
#define FMODE_WRITABLE
The IO is opened for writing.
Definition io.h:273
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:9303
#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:1619
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:1578
VALUE rb_eIOTimeoutError
Indicates that a timeout has occurred while performing an IO operation.
Definition io.c:179
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:2939
void rb_io_check_initialized(rb_io_t *fptr)
Asserts that the passed IO is initialised.
Definition io.c:769
#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
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:798
VALUE rb_io_closed_p(VALUE io)
Returns whether or not the underlying IO is closed.
Definition io.c:5795
VALUE rb_io_set_timeout(VALUE io, VALUE timeout)
Set the timeout associated with the specified io object.
Definition io.c:867
ssize_t rb_io_bufwrite(VALUE io, const void *buf, size_t size)
Buffered write to the passed IO.
Definition io.c:1984
void rb_io_check_char_readable(rb_io_t *fptr)
Asserts that an IO is opened for character-based reading.
Definition io.c:976
#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:804
void rb_io_set_nonblock(rb_io_t *fptr)
Instructs the OS to put its internal file structure into "nonblocking mode".
Definition io.c:3391
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:6803
int rb_io_wait_writable(int fd)
Blocks until the passed file descriptor gets writable.
Definition io.c:1517
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:9190
VALUE rb_io_set_write_io(VALUE io, VALUE w)
Assigns the tied IO for writing.
Definition io.c:815
void rb_io_check_writable(rb_io_t *fptr)
Asserts that an IO is opened for writing.
Definition io.c:1028
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:1632
void rb_io_check_closed(rb_io_t *fptr)
This badly named function asserts that the passed IO is open.
Definition io.c:777
int rb_io_wait_readable(int fd)
Blocks until the passed file descriptor gets readable.
Definition io.c:1483
void rb_io_synchronized(rb_io_t *fptr)
Sets FMODE_SYNC.
Definition io.c:7289
VALUE rb_io_wait(VALUE io, VALUE events, VALUE timeout)
Blocks until the passed IO is ready for the passed events.
Definition io.c:1422
int len
Length of the buffer.
Definition io.h:8
VALUE rb_ractor_stdin(void)
Queries the standard input of the current Ractor that is calling this function.
Definition ractor.c:2655
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:2715
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:2703
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:2691
void * rb_thread_call_with_gvl(void *(*func)(void *), void *data1)
(Re-)acquires the GVL.
Definition thread.c:1817
void * rb_thread_call_without_gvl(void *(*func)(void *), void *data1, rb_unblock_function_t *ubf, void *data2)
Allows the passed function to run in parallel with other Ruby threads.
#define RB_NUM2INT
Just another name of rb_num2int_inline.
Definition int.h:38
#define RB_INT2NUM
Just another name of rb_int2num_inline.
Definition int.h:37
VALUE rb_f_sprintf(int argc, const VALUE *argv)
Identical to rb_str_format(), except how the arguments are arranged.
Definition sprintf.c:208
#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:1410
VALUE rb_yield(VALUE val)
Yields the block.
Definition vm_eval.c:1376
void rb_fd_term(rb_fdset_t *f)
Destroys the rb_fdset_t, releasing any memory and resources it used.
#define MEMZERO(p, type, n)
Handy macro to erase a region of memory.
Definition memory.h:354
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
Definition memory.h:161
#define MEMMOVE(p1, p2, type, n)
Handy macro to call memmove.
Definition memory.h:378
#define NUM2MODET
Converts a C's mode_t into an instance of rb_cInteger.
Definition mode_t.h:28
void rb_define_hooked_variable(const char *q, VALUE *w, type *e, void_type *r)
Define a function-backended global variable.
void rb_define_virtual_variable(const char *q, type *w, void_type *e)
Define a function-backended global variable.
VALUE rb_rescue2(type *q, VALUE w, type *e, VALUE r,...)
An equivalent of rescue clause.
VALUE rb_ensure(type *q, VALUE w, type *e, VALUE r)
An equivalent of ensure clause.
#define PRI_OFFT_PREFIX
A rb_sprintf() format prefix to be used for an off_t parameter.
Definition off_t.h:55
#define OFFT2NUM
Converts a C's off_t into an instance of rb_cInteger.
Definition off_t.h:33
#define NUM2OFFT
Converts an instance of rb_cNumeric into C's off_t.
Definition off_t.h:44
#define PIDT2NUM
Converts a C's pid_t into an instance of rb_cInteger.
Definition pid_t.h:28
#define rb_fd_isset
Queries if the given fd is in the rb_fdset_t.
Definition posix.h:60
#define rb_fd_select
Waits for multiple file descriptors at once.
Definition posix.h:66
#define rb_fd_init
Initialises the :given :rb_fdset_t.
Definition posix.h:63
#define rb_fd_set
Sets the given fd to the rb_fdset_t.
Definition posix.h:54
#define RARRAY_LEN
Just another name of rb_array_len.
Definition rarray.h: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 SafeStringValue(v)
Definition rstring.h:98
#define StringValue(v)
Ensures that the parameter object is a String.
Definition rstring.h:66
#define RSTRING_GETMEM(str, ptrvar, lenvar)
Convenient macro to obtain the contents and length at once.
Definition rstring.h:488
#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:14539
void rb_p(VALUE obj)
Inspects an object.
Definition io.c:8976
#define FilePathValue(v)
Ensures that the parameter object is a path.
Definition ruby.h: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:203
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:607
VALUE rb_fiber_scheduler_make_timeout(struct timeval *timeout)
Converts the passed timeout to an expression that rb_fiber_scheduler_block() etc.
Definition scheduler.c:246
VALUE rb_fiber_scheduler_io_wait_readable(VALUE scheduler, VALUE io)
Non-blocking wait until the passed IO is ready for reading.
Definition scheduler.c:419
VALUE rb_fiber_scheduler_io_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:583
VALUE rb_fiber_scheduler_io_wait(VALUE scheduler, VALUE io, VALUE events, VALUE timeout)
Non-blocking version of rb_io_wait().
Definition scheduler.c:413
static ssize_t rb_fiber_scheduler_io_result_apply(VALUE result)
Apply an io result to the local thread, returning the value of the original system call that created ...
Definition scheduler.h:70
VALUE rb_fiber_scheduler_io_selectv(VALUE scheduler, int argc, VALUE *argv)
Non-blocking version of IO.select, argv variant.
Definition scheduler.c:449
VALUE rb_fiber_scheduler_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:619
VALUE rb_fiber_scheduler_current_for_thread(VALUE thread)
Identical to rb_fiber_scheduler_current(), except it queries for that of the passed thread instead of...
Definition scheduler.c:208
VALUE rb_fiber_scheduler_io_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:595
VALUE rb_fiber_scheduler_io_wait_writable(VALUE scheduler, VALUE io)
Non-blocking wait until the passed IO is ready for writing.
Definition scheduler.c:425
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:4251
static bool RB_TEST(VALUE obj)
Emulates Ruby's "if" statement.
#define RTEST
This is an old name of RB_TEST.
#define _(args)
This was a transition path from K&R to ANSI.
Definition stdarg.h:35
C99 shim for <stdbool.h>
Ruby's File and IO.
Definition rfile.h:35
Definition io.c:214
Definition win32.h:218
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
intptr_t SIGNED_VALUE
A signed integer type that has the same width with VALUE.
Definition value.h:63
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
Definition value.h:52
uintptr_t VALUE
Type that represents a Ruby object.
Definition value.h:40
static bool RB_SYMBOL_P(VALUE obj)
Queries if the object is an instance of rb_cSymbol.
Definition value_type.h:306
static void Check_Type(VALUE v, enum ruby_value_type t)
Identical to RB_TYPE_P(), except it raises exceptions on predication failure.
Definition value_type.h:432