Ruby 3.1.3p185 (2022-11-24 revision 1a6b16756e0ba6b95ab71a441357ed5484e33498)
io.c
1/**********************************************************************
2
3 io.c -
4
5 $Author$
6 created at: Fri Oct 15 18:08:59 JST 1993
7
8 Copyright (C) 1993-2007 Yukihiro Matsumoto
9 Copyright (C) 2000 Network Applied Communication Laboratory, Inc.
10 Copyright (C) 2000 Information-technology Promotion Agency, Japan
11
12**********************************************************************/
13
14#include "ruby/internal/config.h"
15
17#include "ruby/io/buffer.h"
18
19#ifdef _WIN32
20# include "ruby/ruby.h"
21# include "ruby/io.h"
22#endif
23
24#include <ctype.h>
25#include <errno.h>
26#include <stddef.h>
27
28/* non-Linux poll may not work on all FDs */
29#if defined(HAVE_POLL)
30# if defined(__linux__)
31# define USE_POLL 1
32# endif
33# if defined(__FreeBSD_version) && __FreeBSD_version >= 1100000
34# define USE_POLL 1
35# endif
36#endif
37
38#ifndef USE_POLL
39# define USE_POLL 0
40#endif
41
42#undef free
43#define free(x) xfree(x)
44
45#if defined(DOSISH) || defined(__CYGWIN__)
46#include <io.h>
47#endif
48
49#include <sys/types.h>
50#if defined HAVE_NET_SOCKET_H
51# include <net/socket.h>
52#elif defined HAVE_SYS_SOCKET_H
53# include <sys/socket.h>
54#endif
55
56#if defined(__BOW__) || defined(__CYGWIN__) || defined(_WIN32)
57# define NO_SAFE_RENAME
58#endif
59
60#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__sun) || defined(_nec_ews)
61# define USE_SETVBUF
62#endif
63
64#ifdef __QNXNTO__
65#include <unix.h>
66#endif
67
68#include <sys/types.h>
69#if defined(HAVE_SYS_IOCTL_H) && !defined(_WIN32)
70#include <sys/ioctl.h>
71#endif
72#if defined(HAVE_FCNTL_H) || defined(_WIN32)
73#include <fcntl.h>
74#elif defined(HAVE_SYS_FCNTL_H)
75#include <sys/fcntl.h>
76#endif
77
78#if !HAVE_OFF_T && !defined(off_t)
79# define off_t long
80#endif
81
82#ifdef HAVE_SYS_TIME_H
83# include <sys/time.h>
84#endif
85
86#include <sys/stat.h>
87
88#if defined(HAVE_SYS_PARAM_H) || defined(__HIUX_MPP__)
89# include <sys/param.h>
90#endif
91
92#if !defined NOFILE
93# define NOFILE 64
94#endif
95
96#ifdef HAVE_UNISTD_H
97#include <unistd.h>
98#endif
99
100#ifdef HAVE_SYSCALL_H
101#include <syscall.h>
102#elif defined HAVE_SYS_SYSCALL_H
103#include <sys/syscall.h>
104#endif
105
106#ifdef HAVE_SYS_UIO_H
107#include <sys/uio.h>
108#endif
109
110#ifdef HAVE_SYS_WAIT_H
111# include <sys/wait.h> /* for WNOHANG on BSD */
112#endif
113
114#ifdef HAVE_COPYFILE_H
115# include <copyfile.h>
116#endif
117
119#include "ccan/list/list.h"
120#include "dln.h"
121#include "encindex.h"
122#include "id.h"
123#include "internal.h"
124#include "internal/encoding.h"
125#include "internal/error.h"
126#include "internal/inits.h"
127#include "internal/io.h"
128#include "internal/numeric.h"
129#include "internal/object.h"
130#include "internal/process.h"
131#include "internal/thread.h"
132#include "internal/transcode.h"
133#include "internal/variable.h"
134#include "ruby/io.h"
135#include "ruby/io/buffer.h"
136#include "ruby/thread.h"
137#include "ruby/util.h"
138#include "ruby_atomic.h"
139#include "ruby/ractor.h"
140
141#if !USE_POLL
142# include "vm_core.h"
143#endif
144
145#include "builtin.h"
146
147#ifndef O_ACCMODE
148#define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR)
149#endif
150
151#if SIZEOF_OFF_T > SIZEOF_LONG && !defined(HAVE_LONG_LONG)
152# error off_t is bigger than long, but you have no long long...
153#endif
154
155#ifndef PIPE_BUF
156# ifdef _POSIX_PIPE_BUF
157# define PIPE_BUF _POSIX_PIPE_BUF
158# else
159# define PIPE_BUF 512 /* is this ok? */
160# endif
161#endif
162
163#ifndef EWOULDBLOCK
164# define EWOULDBLOCK EAGAIN
165#endif
166
167#if defined(HAVE___SYSCALL) && (defined(__APPLE__) || defined(__OpenBSD__))
168/* Mac OS X and OpenBSD have __syscall but don't define it in headers */
169off_t __syscall(quad_t number, ...);
170#endif
171
172#define IO_RBUF_CAPA_MIN 8192
173#define IO_CBUF_CAPA_MIN (128*1024)
174#define IO_RBUF_CAPA_FOR(fptr) (NEED_READCONV(fptr) ? IO_CBUF_CAPA_MIN : IO_RBUF_CAPA_MIN)
175#define IO_WBUF_CAPA_MIN 8192
176
177/* define system APIs */
178#ifdef _WIN32
179#undef open
180#define open rb_w32_uopen
181#undef rename
182#define rename(f, t) rb_w32_urename((f), (t))
183#endif
184
185VALUE rb_cIO;
190
191static VALUE rb_eEAGAINWaitReadable;
192static VALUE rb_eEAGAINWaitWritable;
193static VALUE rb_eEWOULDBLOCKWaitReadable;
194static VALUE rb_eEWOULDBLOCKWaitWritable;
195static VALUE rb_eEINPROGRESSWaitWritable;
196static VALUE rb_eEINPROGRESSWaitReadable;
197
199static VALUE orig_stdout, orig_stderr;
200
202VALUE rb_rs;
205
206static VALUE argf;
207
208static ID id_write, id_read, id_getc, id_flush, id_readpartial, id_set_encoding, id_fileno;
209static VALUE sym_mode, sym_perm, sym_flags, sym_extenc, sym_intenc, sym_encoding, sym_open_args;
210static VALUE sym_textmode, sym_binmode, sym_autoclose;
211static VALUE sym_SET, sym_CUR, sym_END;
212static VALUE sym_wait_readable, sym_wait_writable;
213#ifdef SEEK_DATA
214static VALUE sym_DATA;
215#endif
216#ifdef SEEK_HOLE
217static VALUE sym_HOLE;
218#endif
219
220static VALUE prep_io(int fd, int fmode, VALUE klass, const char *path);
221
222struct argf {
223 VALUE filename, current_file;
224 long last_lineno; /* $. */
225 long lineno;
226 VALUE argv;
227 VALUE inplace;
228 struct rb_io_enc_t encs;
229 int8_t init_p, next_p, binmode;
230};
231
232static rb_atomic_t max_file_descriptor = NOFILE;
233void
235{
236 rb_atomic_t afd = (rb_atomic_t)fd;
237 rb_atomic_t max_fd = max_file_descriptor;
238 int err;
239
240 if (fd < 0 || afd <= max_fd)
241 return;
242
243#if defined(HAVE_FCNTL) && defined(F_GETFL)
244 err = fcntl(fd, F_GETFL) == -1;
245#else
246 {
247 struct stat buf;
248 err = fstat(fd, &buf) != 0;
249 }
250#endif
251 if (err && errno == EBADF) {
252 rb_bug("rb_update_max_fd: invalid fd (%d) given.", fd);
253 }
254
255 while (max_fd < afd) {
256 max_fd = ATOMIC_CAS(max_file_descriptor, max_fd, afd);
257 }
258}
259
260void
261rb_maygvl_fd_fix_cloexec(int fd)
262{
263 /* MinGW don't have F_GETFD and FD_CLOEXEC. [ruby-core:40281] */
264#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
265 int flags, flags2, ret;
266 flags = fcntl(fd, F_GETFD); /* should not fail except EBADF. */
267 if (flags == -1) {
268 rb_bug("rb_maygvl_fd_fix_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(errno));
269 }
270 if (fd <= 2)
271 flags2 = flags & ~FD_CLOEXEC; /* Clear CLOEXEC for standard file descriptors: 0, 1, 2. */
272 else
273 flags2 = flags | FD_CLOEXEC; /* Set CLOEXEC for non-standard file descriptors: 3, 4, 5, ... */
274 if (flags != flags2) {
275 ret = fcntl(fd, F_SETFD, flags2);
276 if (ret != 0) {
277 rb_bug("rb_maygvl_fd_fix_cloexec: fcntl(%d, F_SETFD, %d) failed: %s", fd, flags2, strerror(errno));
278 }
279 }
280#endif
281}
282
283void
285{
286 rb_maygvl_fd_fix_cloexec(fd);
288}
289
290/* this is only called once */
291static int
292rb_fix_detect_o_cloexec(int fd)
293{
294#if defined(O_CLOEXEC) && defined(F_GETFD)
295 int flags = fcntl(fd, F_GETFD);
296
297 if (flags == -1)
298 rb_bug("rb_fix_detect_o_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(errno));
299
300 if (flags & FD_CLOEXEC)
301 return 1;
302#endif /* fall through if O_CLOEXEC does not work: */
303 rb_maygvl_fd_fix_cloexec(fd);
304 return 0;
305}
306
307static inline bool
308io_again_p(int e)
309{
310 return (e == EWOULDBLOCK) || (e == EAGAIN);
311}
312
313int
314rb_cloexec_open(const char *pathname, int flags, mode_t mode)
315{
316 int ret;
317 static int o_cloexec_state = -1; /* <0: unknown, 0: ignored, >0: working */
318
319 static const int retry_interval = 0;
320 static const int retry_max_count = 10000;
321
322 int retry_count = 0;
323
324#ifdef O_CLOEXEC
325 /* O_CLOEXEC is available since Linux 2.6.23. Linux 2.6.18 silently ignore it. */
326 flags |= O_CLOEXEC;
327#elif defined O_NOINHERIT
328 flags |= O_NOINHERIT;
329#endif
330
331 while ((ret = open(pathname, flags, mode)) == -1) {
332 int e = errno;
333 if (!io_again_p(e)) break;
334 if (retry_count++ >= retry_max_count) break;
335
336 sleep(retry_interval);
337 }
338
339 if (ret < 0) return ret;
340 if (ret <= 2 || o_cloexec_state == 0) {
341 rb_maygvl_fd_fix_cloexec(ret);
342 }
343 else if (o_cloexec_state > 0) {
344 return ret;
345 }
346 else {
347 o_cloexec_state = rb_fix_detect_o_cloexec(ret);
348 }
349 return ret;
350}
351
352int
354{
355 /* Don't allocate standard file descriptors: 0, 1, 2 */
356 return rb_cloexec_fcntl_dupfd(oldfd, 3);
357}
358
359int
360rb_cloexec_dup2(int oldfd, int newfd)
361{
362 int ret;
363
364 /* When oldfd == newfd, dup2 succeeds but dup3 fails with EINVAL.
365 * rb_cloexec_dup2 succeeds as dup2. */
366 if (oldfd == newfd) {
367 ret = newfd;
368 }
369 else {
370#if defined(HAVE_DUP3) && defined(O_CLOEXEC)
371 static int try_dup3 = 1;
372 if (2 < newfd && try_dup3) {
373 ret = dup3(oldfd, newfd, O_CLOEXEC);
374 if (ret != -1)
375 return ret;
376 /* dup3 is available since Linux 2.6.27, glibc 2.9. */
377 if (errno == ENOSYS) {
378 try_dup3 = 0;
379 ret = dup2(oldfd, newfd);
380 }
381 }
382 else {
383 ret = dup2(oldfd, newfd);
384 }
385#else
386 ret = dup2(oldfd, newfd);
387#endif
388 if (ret < 0) return ret;
389 }
390 rb_maygvl_fd_fix_cloexec(ret);
391 return ret;
392}
393
394static int
395rb_fd_set_nonblock(int fd)
396{
397#ifdef _WIN32
398 return rb_w32_set_nonblock(fd);
399#elif defined(F_GETFL)
400 int oflags = fcntl(fd, F_GETFL);
401
402 if (oflags == -1)
403 return -1;
404 if (oflags & O_NONBLOCK)
405 return 0;
406 oflags |= O_NONBLOCK;
407 return fcntl(fd, F_SETFL, oflags);
408#endif
409 return 0;
410}
411
412int
413rb_cloexec_pipe(int descriptors[2])
414{
415#ifdef HAVE_PIPE2
416 int result = pipe2(descriptors, O_CLOEXEC | O_NONBLOCK);
417#else
418 int result = pipe(descriptors);
419#endif
420
421 if (result < 0)
422 return result;
423
424#ifdef __CYGWIN__
425 if (result == 0 && descriptors[1] == -1) {
426 close(descriptors[0]);
427 descriptors[0] = -1;
428 errno = ENFILE;
429 return -1;
430 }
431#endif
432
433#ifndef HAVE_PIPE2
434 rb_maygvl_fd_fix_cloexec(descriptors[0]);
435 rb_maygvl_fd_fix_cloexec(descriptors[1]);
436
437#ifndef _WIN32
438 rb_fd_set_nonblock(descriptors[0]);
439 rb_fd_set_nonblock(descriptors[1]);
440#endif
441#endif
442
443 return result;
444}
445
446int
447rb_cloexec_fcntl_dupfd(int fd, int minfd)
448{
449 int ret;
450
451#if defined(HAVE_FCNTL) && defined(F_DUPFD_CLOEXEC) && defined(F_DUPFD)
452 static int try_dupfd_cloexec = 1;
453 if (try_dupfd_cloexec) {
454 ret = fcntl(fd, F_DUPFD_CLOEXEC, minfd);
455 if (ret != -1) {
456 if (ret <= 2)
457 rb_maygvl_fd_fix_cloexec(ret);
458 return ret;
459 }
460 /* F_DUPFD_CLOEXEC is available since Linux 2.6.24. Linux 2.6.18 fails with EINVAL */
461 if (errno == EINVAL) {
462 ret = fcntl(fd, F_DUPFD, minfd);
463 if (ret != -1) {
464 try_dupfd_cloexec = 0;
465 }
466 }
467 }
468 else {
469 ret = fcntl(fd, F_DUPFD, minfd);
470 }
471#elif defined(HAVE_FCNTL) && defined(F_DUPFD)
472 ret = fcntl(fd, F_DUPFD, minfd);
473#else
474 ret = dup(fd);
475 if (ret >= 0 && ret < minfd) {
476 const int prev_fd = ret;
477 ret = rb_cloexec_fcntl_dupfd(fd, minfd);
478 close(prev_fd);
479 }
480 return ret;
481#endif
482 if (ret < 0) return ret;
483 rb_maygvl_fd_fix_cloexec(ret);
484 return ret;
485}
486
487#define argf_of(obj) (*(struct argf *)DATA_PTR(obj))
488#define ARGF argf_of(argf)
489
490#define GetWriteIO(io) rb_io_get_write_io(io)
491
492#define READ_DATA_PENDING(fptr) ((fptr)->rbuf.len)
493#define READ_DATA_PENDING_COUNT(fptr) ((fptr)->rbuf.len)
494#define READ_DATA_PENDING_PTR(fptr) ((fptr)->rbuf.ptr+(fptr)->rbuf.off)
495#define READ_DATA_BUFFERED(fptr) READ_DATA_PENDING(fptr)
496
497#define READ_CHAR_PENDING(fptr) ((fptr)->cbuf.len)
498#define READ_CHAR_PENDING_COUNT(fptr) ((fptr)->cbuf.len)
499#define READ_CHAR_PENDING_PTR(fptr) ((fptr)->cbuf.ptr+(fptr)->cbuf.off)
500
501#if defined(_WIN32)
502#define WAIT_FD_IN_WIN32(fptr) \
503 (rb_w32_io_cancelable_p((fptr)->fd) ? Qnil : rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), Qnil))
504#else
505#define WAIT_FD_IN_WIN32(fptr)
506#endif
507
508#define READ_CHECK(fptr) do {\
509 if (!READ_DATA_PENDING(fptr)) {\
510 WAIT_FD_IN_WIN32(fptr);\
511 rb_io_check_closed(fptr);\
512 }\
513} while(0)
514
515#ifndef S_ISSOCK
516# ifdef _S_ISSOCK
517# define S_ISSOCK(m) _S_ISSOCK(m)
518# else
519# ifdef _S_IFSOCK
520# define S_ISSOCK(m) (((m) & S_IFMT) == _S_IFSOCK)
521# else
522# ifdef S_IFSOCK
523# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
524# endif
525# endif
526# endif
527#endif
528
529static int io_fflush(rb_io_t *);
530static rb_io_t *flush_before_seek(rb_io_t *fptr);
531
532#define FMODE_PREP (1<<16)
533#define FMODE_SIGNAL_ON_EPIPE (1<<17)
534
535#define fptr_signal_on_epipe(fptr) \
536 (((fptr)->mode & FMODE_SIGNAL_ON_EPIPE) != 0)
537
538#define fptr_set_signal_on_epipe(fptr, flag) \
539 ((flag) ? \
540 (fptr)->mode |= FMODE_SIGNAL_ON_EPIPE : \
541 (fptr)->mode &= ~FMODE_SIGNAL_ON_EPIPE)
542
543extern ID ruby_static_id_signo;
544
545NORETURN(static void raise_on_write(rb_io_t *fptr, int e, VALUE errinfo));
546static void
547raise_on_write(rb_io_t *fptr, int e, VALUE errinfo)
548{
549#if defined EPIPE
550 if (fptr_signal_on_epipe(fptr) && (e == EPIPE)) {
551 const VALUE sig =
552# if defined SIGPIPE
553 INT2FIX(SIGPIPE) - INT2FIX(0) +
554# endif
555 INT2FIX(0);
556 rb_ivar_set(errinfo, ruby_static_id_signo, sig);
557 }
558#endif
559 rb_exc_raise(errinfo);
560}
561
562#define rb_sys_fail_on_write(fptr) \
563 do { \
564 int e = errno; \
565 raise_on_write(fptr, e, rb_syserr_new_path(e, (fptr)->pathv)); \
566 } while (0)
567
568#define NEED_NEWLINE_DECORATOR_ON_READ(fptr) ((fptr)->mode & FMODE_TEXTMODE)
569#define NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) ((fptr)->mode & FMODE_TEXTMODE)
570#if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)
571# define RUBY_CRLF_ENVIRONMENT 1
572#else
573# define RUBY_CRLF_ENVIRONMENT 0
574#endif
575
576#if RUBY_CRLF_ENVIRONMENT
577/* Windows */
578# define DEFAULT_TEXTMODE FMODE_TEXTMODE
579# define TEXTMODE_NEWLINE_DECORATOR_ON_WRITE ECONV_CRLF_NEWLINE_DECORATOR
580/*
581 * CRLF newline is set as default newline decorator.
582 * If only CRLF newline conversion is needed, we use binary IO process
583 * with OS's text mode for IO performance improvement.
584 * If encoding conversion is needed or a user sets text mode, we use encoding
585 * conversion IO process and universal newline decorator by default.
586 */
587#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || (fptr)->encs.ecflags & ~ECONV_CRLF_NEWLINE_DECORATOR)
588#define WRITECONV_MASK ( \
589 (ECONV_DECORATOR_MASK & ~ECONV_CRLF_NEWLINE_DECORATOR)|\
590 ECONV_STATEFUL_DECORATOR_MASK|\
591 0)
592#define NEED_WRITECONV(fptr) ( \
593 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
594 ((fptr)->encs.ecflags & WRITECONV_MASK) || \
595 0)
596#define SET_BINARY_MODE(fptr) setmode((fptr)->fd, O_BINARY)
597
598#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) do {\
599 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {\
600 if (((fptr)->mode & FMODE_READABLE) &&\
601 !((fptr)->encs.ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {\
602 setmode((fptr)->fd, O_BINARY);\
603 }\
604 else {\
605 setmode((fptr)->fd, O_TEXT);\
606 }\
607 }\
608} while(0)
609
610#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) do {\
611 if ((enc2) && ((ecflags) & ECONV_DEFAULT_NEWLINE_DECORATOR)) {\
612 (ecflags) |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;\
613 }\
614} while(0)
615
616/*
617 * IO unread with taking care of removed '\r' in text mode.
618 */
619static void
620io_unread(rb_io_t *fptr)
621{
622 off_t r, pos;
623 ssize_t read_size;
624 long i;
625 long newlines = 0;
626 long extra_max;
627 char *p;
628 char *buf;
629
630 rb_io_check_closed(fptr);
631 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX) {
632 return;
633 }
634
635 errno = 0;
636 if (!rb_w32_fd_is_text(fptr->fd)) {
637 r = lseek(fptr->fd, -fptr->rbuf.len, SEEK_CUR);
638 if (r < 0 && errno) {
639 if (errno == ESPIPE)
640 fptr->mode |= FMODE_DUPLEX;
641 return;
642 }
643
644 fptr->rbuf.off = 0;
645 fptr->rbuf.len = 0;
646 return;
647 }
648
649 pos = lseek(fptr->fd, 0, SEEK_CUR);
650 if (pos < 0 && errno) {
651 if (errno == ESPIPE)
652 fptr->mode |= FMODE_DUPLEX;
653 return;
654 }
655
656 /* add extra offset for removed '\r' in rbuf */
657 extra_max = (long)(pos - fptr->rbuf.len);
658 p = fptr->rbuf.ptr + fptr->rbuf.off;
659
660 /* if the end of rbuf is '\r', rbuf doesn't have '\r' within rbuf.len */
661 if (*(fptr->rbuf.ptr + fptr->rbuf.capa - 1) == '\r') {
662 newlines++;
663 }
664
665 for (i = 0; i < fptr->rbuf.len; i++) {
666 if (*p == '\n') newlines++;
667 if (extra_max == newlines) break;
668 p++;
669 }
670
671 buf = ALLOC_N(char, fptr->rbuf.len + newlines);
672 while (newlines >= 0) {
673 r = lseek(fptr->fd, pos - fptr->rbuf.len - newlines, SEEK_SET);
674 if (newlines == 0) break;
675 if (r < 0) {
676 newlines--;
677 continue;
678 }
679 read_size = _read(fptr->fd, buf, fptr->rbuf.len + newlines);
680 if (read_size < 0) {
681 int e = errno;
682 free(buf);
683 rb_syserr_fail_path(e, fptr->pathv);
684 }
685 if (read_size == fptr->rbuf.len) {
686 lseek(fptr->fd, r, SEEK_SET);
687 break;
688 }
689 else {
690 newlines--;
691 }
692 }
693 free(buf);
694 fptr->rbuf.off = 0;
695 fptr->rbuf.len = 0;
696 return;
697}
698
699/*
700 * We use io_seek to back cursor position when changing mode from text to binary,
701 * but stdin and pipe cannot seek back. Stdin and pipe read should use encoding
702 * conversion for working properly with mode change.
703 *
704 * Return previous translation mode.
705 */
706static inline int
707set_binary_mode_with_seek_cur(rb_io_t *fptr)
708{
709 if (!rb_w32_fd_is_text(fptr->fd)) return O_BINARY;
710
711 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX) {
712 return setmode(fptr->fd, O_BINARY);
713 }
714 flush_before_seek(fptr);
715 return setmode(fptr->fd, O_BINARY);
716}
717#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) set_binary_mode_with_seek_cur(fptr)
718
719#else
720/* Unix */
721# define DEFAULT_TEXTMODE 0
722#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || NEED_NEWLINE_DECORATOR_ON_READ(fptr))
723#define NEED_WRITECONV(fptr) ( \
724 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
725 NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) || \
726 ((fptr)->encs.ecflags & (ECONV_DECORATOR_MASK|ECONV_STATEFUL_DECORATOR_MASK)) || \
727 0)
728#define SET_BINARY_MODE(fptr) (void)(fptr)
729#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) (void)(fptr)
730#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) ((void)(enc2), (void)(ecflags))
731#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) (void)(fptr)
732#endif
733
734#if !defined HAVE_SHUTDOWN && !defined shutdown
735#define shutdown(a,b) 0
736#endif
737
738#if defined(_WIN32)
739#define is_socket(fd, path) rb_w32_is_socket(fd)
740#elif !defined(S_ISSOCK)
741#define is_socket(fd, path) 0
742#else
743static int
744is_socket(int fd, VALUE path)
745{
746 struct stat sbuf;
747 if (fstat(fd, &sbuf) < 0)
748 rb_sys_fail_path(path);
749 return S_ISSOCK(sbuf.st_mode);
750}
751#endif
752
753static const char closed_stream[] = "closed stream";
754
755static void
756io_fd_check_closed(int fd)
757{
758 if (fd < 0) {
759 rb_thread_check_ints(); /* check for ruby_error_stream_closed */
760 rb_raise(rb_eIOError, closed_stream);
761 }
762}
763
764void
765rb_eof_error(void)
766{
767 rb_raise(rb_eEOFError, "end of file reached");
768}
769
770VALUE
772{
773 rb_check_frozen(io);
774 return io;
775}
776
777void
779{
780 if (!fptr) {
781 rb_raise(rb_eIOError, "uninitialized stream");
782 }
783}
784
785void
787{
789 io_fd_check_closed(fptr->fd);
790}
791
792static rb_io_t *
793rb_io_get_fptr(VALUE io)
794{
795 rb_io_t *fptr = RFILE(io)->fptr;
797 return fptr;
798}
799
800VALUE
802{
803 return rb_convert_type_with_id(io, T_FILE, "IO", idTo_io);
804}
805
806VALUE
808{
809 return rb_check_convert_type_with_id(io, T_FILE, "IO", idTo_io);
810}
811
812VALUE
814{
815 VALUE write_io;
816 write_io = rb_io_get_fptr(io)->tied_io_for_writing;
817 if (write_io) {
818 return write_io;
819 }
820 return io;
821}
822
823VALUE
824rb_io_set_write_io(VALUE io, VALUE w)
825{
826 VALUE write_io;
827 rb_io_t *fptr = rb_io_get_fptr(io);
828 if (!RTEST(w)) {
829 w = 0;
830 }
831 else {
832 GetWriteIO(w);
833 }
834 write_io = fptr->tied_io_for_writing;
835 fptr->tied_io_for_writing = w;
836 return write_io ? write_io : Qnil;
837}
838
839/*
840 * call-seq:
841 * IO.try_convert(object) -> new_io or nil
842 *
843 * Attempts to convert +object+ into an \IO object via method +to_io+;
844 * returns the new \IO object if successful, or +nil+ otherwise:
845 *
846 * IO.try_convert(STDOUT) # => #<IO:<STDOUT>>
847 * IO.try_convert(ARGF) # => #<IO:<STDIN>>
848 * IO.try_convert('STDOUT') # => nil
849 *
850 */
851static VALUE
852rb_io_s_try_convert(VALUE dummy, VALUE io)
853{
854 return rb_io_check_io(io);
855}
856
857#if !RUBY_CRLF_ENVIRONMENT
858static void
859io_unread(rb_io_t *fptr)
860{
861 off_t r;
862 rb_io_check_closed(fptr);
863 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX)
864 return;
865 /* xxx: target position may be negative if buffer is filled by ungetc */
866 errno = 0;
867 r = lseek(fptr->fd, -fptr->rbuf.len, SEEK_CUR);
868 if (r < 0 && errno) {
869 if (errno == ESPIPE)
870 fptr->mode |= FMODE_DUPLEX;
871 return;
872 }
873 fptr->rbuf.off = 0;
874 fptr->rbuf.len = 0;
875 return;
876}
877#endif
878
879static rb_encoding *io_input_encoding(rb_io_t *fptr);
880
881static void
882io_ungetbyte(VALUE str, rb_io_t *fptr)
883{
884 long len = RSTRING_LEN(str);
885
886 if (fptr->rbuf.ptr == NULL) {
887 const int min_capa = IO_RBUF_CAPA_FOR(fptr);
888 fptr->rbuf.off = 0;
889 fptr->rbuf.len = 0;
890#if SIZEOF_LONG > SIZEOF_INT
891 if (len > INT_MAX)
892 rb_raise(rb_eIOError, "ungetbyte failed");
893#endif
894 if (len > min_capa)
895 fptr->rbuf.capa = (int)len;
896 else
897 fptr->rbuf.capa = min_capa;
898 fptr->rbuf.ptr = ALLOC_N(char, fptr->rbuf.capa);
899 }
900 if (fptr->rbuf.capa < len + fptr->rbuf.len) {
901 rb_raise(rb_eIOError, "ungetbyte failed");
902 }
903 if (fptr->rbuf.off < len) {
904 MEMMOVE(fptr->rbuf.ptr+fptr->rbuf.capa-fptr->rbuf.len,
905 fptr->rbuf.ptr+fptr->rbuf.off,
906 char, fptr->rbuf.len);
907 fptr->rbuf.off = fptr->rbuf.capa-fptr->rbuf.len;
908 }
909 fptr->rbuf.off-=(int)len;
910 fptr->rbuf.len+=(int)len;
911 MEMMOVE(fptr->rbuf.ptr+fptr->rbuf.off, RSTRING_PTR(str), char, len);
912}
913
914static rb_io_t *
915flush_before_seek(rb_io_t *fptr)
916{
917 if (io_fflush(fptr) < 0)
918 rb_sys_fail_on_write(fptr);
919 io_unread(fptr);
920 errno = 0;
921 return fptr;
922}
923
924#define io_seek(fptr, ofs, whence) (errno = 0, lseek(flush_before_seek(fptr)->fd, (ofs), (whence)))
925#define io_tell(fptr) lseek(flush_before_seek(fptr)->fd, 0, SEEK_CUR)
926
927#ifndef SEEK_CUR
928# define SEEK_SET 0
929# define SEEK_CUR 1
930# define SEEK_END 2
931#endif
932
933void
935{
936 rb_io_check_closed(fptr);
937 if (!(fptr->mode & FMODE_READABLE)) {
938 rb_raise(rb_eIOError, "not opened for reading");
939 }
940 if (fptr->wbuf.len) {
941 if (io_fflush(fptr) < 0)
942 rb_sys_fail_on_write(fptr);
943 }
944 if (fptr->tied_io_for_writing) {
945 rb_io_t *wfptr;
946 GetOpenFile(fptr->tied_io_for_writing, wfptr);
947 if (io_fflush(wfptr) < 0)
948 rb_sys_fail_on_write(wfptr);
949 }
950}
951
952void
954{
956 if (READ_CHAR_PENDING(fptr)) {
957 rb_raise(rb_eIOError, "byte oriented read for character buffered IO");
958 }
959}
960
961void
963{
965}
966
967static rb_encoding*
968io_read_encoding(rb_io_t *fptr)
969{
970 if (fptr->encs.enc) {
971 return fptr->encs.enc;
972 }
974}
975
976static rb_encoding*
977io_input_encoding(rb_io_t *fptr)
978{
979 if (fptr->encs.enc2) {
980 return fptr->encs.enc2;
981 }
982 return io_read_encoding(fptr);
983}
984
985void
987{
988 rb_io_check_closed(fptr);
989 if (!(fptr->mode & FMODE_WRITABLE)) {
990 rb_raise(rb_eIOError, "not opened for writing");
991 }
992 if (fptr->rbuf.len) {
993 io_unread(fptr);
994 }
995}
996
997int
998rb_io_read_pending(rb_io_t *fptr)
999{
1000 /* This function is used for bytes and chars. Confusing. */
1001 if (READ_CHAR_PENDING(fptr))
1002 return 1; /* should raise? */
1003 return READ_DATA_PENDING(fptr);
1004}
1005
1006void
1008{
1009 if (!READ_DATA_PENDING(fptr)) {
1011 }
1012 return;
1013}
1014
1015int
1016rb_gc_for_fd(int err)
1017{
1018 if (err == EMFILE || err == ENFILE || err == ENOMEM) {
1019 rb_gc();
1020 return 1;
1021 }
1022 return 0;
1023}
1024
1025static int
1026ruby_dup(int orig)
1027{
1028 int fd;
1029
1030 fd = rb_cloexec_dup(orig);
1031 if (fd < 0) {
1032 int e = errno;
1033 if (rb_gc_for_fd(e)) {
1034 fd = rb_cloexec_dup(orig);
1035 }
1036 if (fd < 0) {
1037 rb_syserr_fail(e, 0);
1038 }
1039 }
1040 rb_update_max_fd(fd);
1041 return fd;
1042}
1043
1044static VALUE
1045io_alloc(VALUE klass)
1046{
1047 NEWOBJ_OF(io, struct RFile, klass, T_FILE);
1048
1049 io->fptr = 0;
1050
1051 return (VALUE)io;
1052}
1053
1054#ifndef S_ISREG
1055# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
1056#endif
1057
1059 VALUE th;
1060 rb_io_t *fptr;
1061 int nonblock;
1062 void *buf;
1063 size_t capa;
1064};
1065
1067 int fd;
1068 const void *buf;
1069 size_t capa;
1070};
1071
1072#ifdef HAVE_WRITEV
1073struct io_internal_writev_struct {
1074 int fd;
1075 int iovcnt;
1076 const struct iovec *iov;
1077};
1078#endif
1079
1080static int nogvl_wait_for(VALUE th, rb_io_t *fptr, short events);
1081static VALUE
1082internal_read_func(void *ptr)
1083{
1084 struct io_internal_read_struct *iis = ptr;
1085 ssize_t r;
1086retry:
1087 r = read(iis->fptr->fd, iis->buf, iis->capa);
1088 if (r < 0 && !iis->nonblock) {
1089 int e = errno;
1090 if (io_again_p(e)) {
1091 if (nogvl_wait_for(iis->th, iis->fptr, RB_WAITFD_IN) != -1) {
1092 goto retry;
1093 }
1094 errno = e;
1095 }
1096 }
1097 return r;
1098}
1099
1100#if defined __APPLE__
1101# define do_write_retry(code) do {ret = code;} while (ret == -1 && errno == EPROTOTYPE)
1102#else
1103# define do_write_retry(code) ret = code
1104#endif
1105static VALUE
1106internal_write_func(void *ptr)
1107{
1108 struct io_internal_write_struct *iis = ptr;
1109 ssize_t ret;
1110 do_write_retry(write(iis->fd, iis->buf, iis->capa));
1111 return (VALUE)ret;
1112}
1113
1114static void*
1115internal_write_func2(void *ptr)
1116{
1117 return (void*)internal_write_func(ptr);
1118}
1119
1120#ifdef HAVE_WRITEV
1121static VALUE
1122internal_writev_func(void *ptr)
1123{
1124 struct io_internal_writev_struct *iis = ptr;
1125 ssize_t ret;
1126 do_write_retry(writev(iis->fd, iis->iov, iis->iovcnt));
1127 return (VALUE)ret;
1128}
1129#endif
1130
1131static ssize_t
1132rb_read_internal(rb_io_t *fptr, void *buf, size_t count)
1133{
1134 VALUE scheduler = rb_fiber_scheduler_current();
1135 if (scheduler != Qnil) {
1136 VALUE result = rb_fiber_scheduler_io_read_memory(scheduler, fptr->self, buf, count, 0);
1137
1138 if (result != Qundef) {
1140 }
1141 }
1142
1143 struct io_internal_read_struct iis = {
1144 .th = rb_thread_current(),
1145 .fptr = fptr,
1146 .nonblock = 0,
1147 .buf = buf,
1148 .capa = count
1149 };
1150
1151 return (ssize_t)rb_thread_io_blocking_region(internal_read_func, &iis, fptr->fd);
1152}
1153
1154static ssize_t
1155rb_write_internal(rb_io_t *fptr, const void *buf, size_t count)
1156{
1157 VALUE scheduler = rb_fiber_scheduler_current();
1158 if (scheduler != Qnil) {
1159 VALUE result = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, buf, count, 0);
1160
1161 if (result != Qundef) {
1163 }
1164 }
1165
1166 struct io_internal_write_struct iis = {
1167 .fd = fptr->fd,
1168 .buf = buf,
1169 .capa = count
1170 };
1171
1172 if (fptr->write_lock && rb_mutex_owned_p(fptr->write_lock))
1173 return (ssize_t)rb_thread_call_without_gvl2(internal_write_func2, &iis, RUBY_UBF_IO, NULL);
1174 else
1175 return (ssize_t)rb_thread_io_blocking_region(internal_write_func, &iis, fptr->fd);
1176}
1177
1178#ifdef HAVE_WRITEV
1179static ssize_t
1180rb_writev_internal(rb_io_t *fptr, const struct iovec *iov, int iovcnt)
1181{
1182 VALUE scheduler = rb_fiber_scheduler_current();
1183 if (scheduler != Qnil) {
1184 for (int i = 0; i < iovcnt; i += 1) {
1185 VALUE result = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, iov[i].iov_base, iov[i].iov_len, 0);
1186
1187 if (result != Qundef) {
1189 }
1190 }
1191 }
1192
1193 struct io_internal_writev_struct iis = {
1194 .fd = fptr->fd,
1195 .iov = iov,
1196 .iovcnt = iovcnt,
1197 };
1198
1199 return (ssize_t)rb_thread_io_blocking_region(internal_writev_func, &iis, fptr->fd);
1200}
1201#endif
1202
1203static VALUE
1204io_flush_buffer_sync(void *arg)
1205{
1206 rb_io_t *fptr = arg;
1207 long l = fptr->wbuf.len;
1208 ssize_t r = write(fptr->fd, fptr->wbuf.ptr+fptr->wbuf.off, (size_t)l);
1209
1210 if (fptr->wbuf.len <= r) {
1211 fptr->wbuf.off = 0;
1212 fptr->wbuf.len = 0;
1213 return 0;
1214 }
1215 if (0 <= r) {
1216 fptr->wbuf.off += (int)r;
1217 fptr->wbuf.len -= (int)r;
1218 errno = EAGAIN;
1219 }
1220 return (VALUE)-1;
1221}
1222
1223static void*
1224io_flush_buffer_sync2(void *arg)
1225{
1226 VALUE result = io_flush_buffer_sync(arg);
1227
1228 /*
1229 * rb_thread_call_without_gvl2 uses 0 as interrupted.
1230 * So, we need to avoid to use 0.
1231 */
1232 return !result ? (void*)1 : (void*)result;
1233}
1234
1235static VALUE
1236io_flush_buffer_async(VALUE arg)
1237{
1238 rb_io_t *fptr = (rb_io_t *)arg;
1239 return rb_thread_io_blocking_region(io_flush_buffer_sync, fptr, fptr->fd);
1240}
1241
1242static VALUE
1243io_flush_buffer_async2(VALUE arg)
1244{
1245 rb_io_t *fptr = (rb_io_t *)arg;
1246 VALUE ret;
1247
1248 ret = (VALUE)rb_thread_call_without_gvl2(io_flush_buffer_sync2, fptr, RUBY_UBF_IO, NULL);
1249
1250 if (!ret) {
1251 /* pending async interrupt is there. */
1252 errno = EAGAIN;
1253 return -1;
1254 }
1255 else if (ret == 1) {
1256 return 0;
1257 }
1258 return ret;
1259}
1260
1261static inline int
1262io_flush_buffer(rb_io_t *fptr)
1263{
1264 if (fptr->write_lock) {
1265 if (rb_mutex_owned_p(fptr->write_lock))
1266 return (int)io_flush_buffer_async2((VALUE)fptr);
1267 else
1268 return (int)rb_mutex_synchronize(fptr->write_lock, io_flush_buffer_async2, (VALUE)fptr);
1269 }
1270 else {
1271 return (int)io_flush_buffer_async((VALUE)fptr);
1272 }
1273}
1274
1275static int
1276io_fflush(rb_io_t *fptr)
1277{
1278 rb_io_check_closed(fptr);
1279
1280 if (fptr->wbuf.len == 0)
1281 return 0;
1282
1283 while (fptr->wbuf.len > 0 && io_flush_buffer(fptr) != 0) {
1284 if (!rb_io_maybe_wait_writable(errno, fptr->self, Qnil))
1285 return -1;
1286
1287 rb_io_check_closed(fptr);
1288 }
1289
1290 return 0;
1291}
1292
1293VALUE
1294rb_io_wait(VALUE io, VALUE events, VALUE timeout)
1295{
1296 VALUE scheduler = rb_fiber_scheduler_current();
1297
1298 if (scheduler != Qnil) {
1299 return rb_fiber_scheduler_io_wait(scheduler, io, events, timeout);
1300 }
1301
1302 rb_io_t * fptr = NULL;
1303 RB_IO_POINTER(io, fptr);
1304
1305 struct timeval tv_storage;
1306 struct timeval *tv = NULL;
1307
1308 if (timeout != Qnil) {
1309 tv_storage = rb_time_interval(timeout);
1310 tv = &tv_storage;
1311 }
1312
1313 int ready = rb_thread_wait_for_single_fd(fptr->fd, RB_NUM2INT(events), tv);
1314
1315 if (ready < 0) {
1316 rb_sys_fail(0);
1317 }
1318
1319 // Not sure if this is necessary:
1320 rb_io_check_closed(fptr);
1321
1322 if (ready) {
1323 return RB_INT2NUM(ready);
1324 }
1325 else {
1326 return Qfalse;
1327 }
1328}
1329
1330static VALUE
1331io_from_fd(int fd)
1332{
1333 return prep_io(fd, FMODE_PREP, rb_cIO, NULL);
1334}
1335
1336static int
1337io_wait_for_single_fd(int fd, int events, struct timeval *timeout)
1338{
1339 VALUE scheduler = rb_fiber_scheduler_current();
1340
1341 if (scheduler != Qnil) {
1342 return RTEST(
1343 rb_fiber_scheduler_io_wait(scheduler, io_from_fd(fd), RB_INT2NUM(events), rb_fiber_scheduler_make_timeout(timeout))
1344 );
1345 }
1346
1347 return rb_thread_wait_for_single_fd(fd, events, timeout);
1348}
1349
1350int
1352{
1353 io_fd_check_closed(f);
1354
1355 VALUE scheduler = rb_fiber_scheduler_current();
1356
1357 switch (errno) {
1358 case EINTR:
1359#if defined(ERESTART)
1360 case ERESTART:
1361#endif
1363 return TRUE;
1364
1365 case EAGAIN:
1366#if EWOULDBLOCK != EAGAIN
1367 case EWOULDBLOCK:
1368#endif
1369 if (scheduler != Qnil) {
1370 return RTEST(
1371 rb_fiber_scheduler_io_wait_readable(scheduler, io_from_fd(f))
1372 );
1373 }
1374 else {
1375 io_wait_for_single_fd(f, RUBY_IO_READABLE, NULL);
1376 }
1377 return TRUE;
1378
1379 default:
1380 return FALSE;
1381 }
1382}
1383
1384int
1386{
1387 io_fd_check_closed(f);
1388
1389 VALUE scheduler = rb_fiber_scheduler_current();
1390
1391 switch (errno) {
1392 case EINTR:
1393#if defined(ERESTART)
1394 case ERESTART:
1395#endif
1396 /*
1397 * In old Linux, several special files under /proc and /sys don't handle
1398 * select properly. Thus we need avoid to call if don't use O_NONBLOCK.
1399 * Otherwise, we face nasty hang up. Sigh.
1400 * e.g. http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=31b07093c44a7a442394d44423e21d783f5523b8
1401 * http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=31b07093c44a7a442394d44423e21d783f5523b8
1402 * In EINTR case, we only need to call RUBY_VM_CHECK_INTS_BLOCKING().
1403 * Then rb_thread_check_ints() is enough.
1404 */
1406 return TRUE;
1407
1408 case EAGAIN:
1409#if EWOULDBLOCK != EAGAIN
1410 case EWOULDBLOCK:
1411#endif
1412 if (scheduler != Qnil) {
1413 return RTEST(
1414 rb_fiber_scheduler_io_wait_writable(scheduler, io_from_fd(f))
1415 );
1416 }
1417 else {
1418 io_wait_for_single_fd(f, RUBY_IO_WRITABLE, NULL);
1419 }
1420 return TRUE;
1421
1422 default:
1423 return FALSE;
1424 }
1425}
1426
1427int
1428rb_wait_for_single_fd(int fd, int events, struct timeval *timeout)
1429{
1430 return io_wait_for_single_fd(fd, events, timeout);
1431}
1432
1433int
1435{
1436 return rb_wait_for_single_fd(fd, RUBY_IO_READABLE, NULL);
1437}
1438
1439int
1441{
1442 return rb_wait_for_single_fd(fd, RUBY_IO_WRITABLE, NULL);
1443}
1444
1445VALUE
1446rb_io_maybe_wait(int error, VALUE io, VALUE events, VALUE timeout)
1447{
1448 // fptr->fd can be set to -1 at any time by another thread when the GVL is
1449 // released. Many code, e.g. `io_bufread` didn't check this correctly and
1450 // instead relies on `read(-1) -> -1` which causes this code path. We then
1451 // check here whether the IO was in fact closed. Probably it's better to
1452 // check that `fptr->fd != -1` before using it in syscall.
1453 rb_io_check_closed(RFILE(io)->fptr);
1454
1455 switch (error) {
1456 // In old Linux, several special files under /proc and /sys don't handle
1457 // select properly. Thus we need avoid to call if don't use O_NONBLOCK.
1458 // Otherwise, we face nasty hang up. Sigh.
1459 // e.g. http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=31b07093c44a7a442394d44423e21d783f5523b8
1460 // http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=31b07093c44a7a442394d44423e21d783f5523b8
1461 // In EINTR case, we only need to call RUBY_VM_CHECK_INTS_BLOCKING().
1462 // Then rb_thread_check_ints() is enough.
1463 case EINTR:
1464#if defined(ERESTART)
1465 case ERESTART:
1466#endif
1467 // We might have pending interrupts since the previous syscall was interrupted:
1469
1470 // The operation was interrupted, so retry it immediately:
1471 return events;
1472
1473 case EAGAIN:
1474#if EWOULDBLOCK != EAGAIN
1475 case EWOULDBLOCK:
1476#endif
1477 // The operation would block, so wait for the specified events:
1478 return rb_io_wait(io, events, timeout);
1479
1480 default:
1481 // Non-specific error, no event is ready:
1482 return Qfalse;
1483 }
1484}
1485
1486int
1487rb_io_maybe_wait_readable(int error, VALUE io, VALUE timeout)
1488{
1489 VALUE result = rb_io_maybe_wait(error, io, RB_INT2NUM(RUBY_IO_READABLE), timeout);
1490
1491 if (RTEST(result)) {
1492 return RB_NUM2INT(result);
1493 }
1494 else {
1495 return 0;
1496 }
1497}
1498
1499int
1500rb_io_maybe_wait_writable(int error, VALUE io, VALUE timeout)
1501{
1502 VALUE result = rb_io_maybe_wait(error, io, RB_INT2NUM(RUBY_IO_WRITABLE), timeout);
1503
1504 if (RTEST(result)) {
1505 return RB_NUM2INT(result);
1506 }
1507 else {
1508 return 0;
1509 }
1510}
1511
1512static void
1513make_writeconv(rb_io_t *fptr)
1514{
1515 if (!fptr->writeconv_initialized) {
1516 const char *senc, *denc;
1517 rb_encoding *enc;
1518 int ecflags;
1519 VALUE ecopts;
1520
1521 fptr->writeconv_initialized = 1;
1522
1523 ecflags = fptr->encs.ecflags & ~ECONV_NEWLINE_DECORATOR_READ_MASK;
1524 ecopts = fptr->encs.ecopts;
1525
1526 if (!fptr->encs.enc || (fptr->encs.enc == rb_ascii8bit_encoding() && !fptr->encs.enc2)) {
1527 /* no encoding conversion */
1528 fptr->writeconv_pre_ecflags = 0;
1529 fptr->writeconv_pre_ecopts = Qnil;
1530 fptr->writeconv = rb_econv_open_opts("", "", ecflags, ecopts);
1531 if (!fptr->writeconv)
1532 rb_exc_raise(rb_econv_open_exc("", "", ecflags));
1534 }
1535 else {
1536 enc = fptr->encs.enc2 ? fptr->encs.enc2 : fptr->encs.enc;
1538 if (!senc && !(fptr->encs.ecflags & ECONV_STATEFUL_DECORATOR_MASK)) {
1539 /* single conversion */
1540 fptr->writeconv_pre_ecflags = ecflags;
1541 fptr->writeconv_pre_ecopts = ecopts;
1542 fptr->writeconv = NULL;
1544 }
1545 else {
1546 /* double conversion */
1547 fptr->writeconv_pre_ecflags = ecflags & ~ECONV_STATEFUL_DECORATOR_MASK;
1548 fptr->writeconv_pre_ecopts = ecopts;
1549 if (senc) {
1550 denc = rb_enc_name(enc);
1551 fptr->writeconv_asciicompat = rb_str_new2(senc);
1552 }
1553 else {
1554 senc = denc = "";
1556 }
1558 ecopts = fptr->encs.ecopts;
1559 fptr->writeconv = rb_econv_open_opts(senc, denc, ecflags, ecopts);
1560 if (!fptr->writeconv)
1561 rb_exc_raise(rb_econv_open_exc(senc, denc, ecflags));
1562 }
1563 }
1564 }
1565}
1566
1567/* writing functions */
1569 rb_io_t *fptr;
1570 VALUE str;
1571 const char *ptr;
1572 long length;
1573};
1574
1576 VALUE io;
1577 VALUE str;
1578 int nosync;
1579};
1580
1581#ifdef HAVE_WRITEV
1582static VALUE
1583io_binwrite_string(VALUE arg)
1584{
1585 struct binwrite_arg *p = (struct binwrite_arg *)arg;
1586 rb_io_t *fptr = p->fptr;
1587 long r;
1588
1589 if (fptr->wbuf.len) {
1590 struct iovec iov[2];
1591
1592 iov[0].iov_base = fptr->wbuf.ptr+fptr->wbuf.off;
1593 iov[0].iov_len = fptr->wbuf.len;
1594 iov[1].iov_base = (char *)p->ptr;
1595 iov[1].iov_len = p->length;
1596
1597 r = rb_writev_internal(fptr, iov, 2);
1598
1599 if (r < 0)
1600 return r;
1601
1602 if (fptr->wbuf.len <= r) {
1603 r -= fptr->wbuf.len;
1604 fptr->wbuf.off = 0;
1605 fptr->wbuf.len = 0;
1606 }
1607 else {
1608 fptr->wbuf.off += (int)r;
1609 fptr->wbuf.len -= (int)r;
1610 r = 0L;
1611 }
1612 }
1613 else {
1614 r = rb_write_internal(fptr, p->ptr, p->length);
1615 }
1616
1617 return r;
1618}
1619#else
1620static VALUE
1621io_binwrite_string(VALUE arg)
1622{
1623 struct binwrite_arg *p = (struct binwrite_arg *)arg;
1624 rb_io_t *fptr = p->fptr;
1625 long l, len;
1626
1627 l = len = p->length;
1628
1629 if (fptr->wbuf.len) {
1630 if (fptr->wbuf.len+len <= fptr->wbuf.capa) {
1631 if (fptr->wbuf.capa < fptr->wbuf.off+fptr->wbuf.len+len) {
1632 MEMMOVE(fptr->wbuf.ptr, fptr->wbuf.ptr+fptr->wbuf.off, char, fptr->wbuf.len);
1633 fptr->wbuf.off = 0;
1634 }
1635 MEMMOVE(fptr->wbuf.ptr+fptr->wbuf.off+fptr->wbuf.len, p->ptr, char, len);
1636 fptr->wbuf.len += (int)len;
1637 l = 0;
1638 }
1639 if (io_fflush(fptr) < 0)
1640 return -2L; /* fail in fflush */
1641 if (l == 0)
1642 return len;
1643 }
1644
1645 return rb_write_internal(p->fptr, p->ptr, p->length);
1646}
1647#endif
1648
1649static long
1650io_binwrite(VALUE str, const char *ptr, long len, rb_io_t *fptr, int nosync)
1651{
1652 long n, r, offset = 0;
1653
1654 /* don't write anything if current thread has a pending interrupt. */
1656
1657 if ((n = len) <= 0) return n;
1658
1659 if (fptr->wbuf.ptr == NULL && !(!nosync && (fptr->mode & FMODE_SYNC))) {
1660 fptr->wbuf.off = 0;
1661 fptr->wbuf.len = 0;
1662 fptr->wbuf.capa = IO_WBUF_CAPA_MIN;
1663 fptr->wbuf.ptr = ALLOC_N(char, fptr->wbuf.capa);
1664 fptr->write_lock = rb_mutex_new();
1665 rb_mutex_allow_trap(fptr->write_lock, 1);
1666 }
1667
1668 if ((!nosync && (fptr->mode & (FMODE_SYNC|FMODE_TTY))) ||
1669 (fptr->wbuf.ptr && fptr->wbuf.capa <= fptr->wbuf.len + len)) {
1670 struct binwrite_arg arg;
1671
1672 arg.fptr = fptr;
1673 arg.str = str;
1674 retry:
1675 arg.ptr = ptr + offset;
1676 arg.length = n;
1677
1678 if (fptr->write_lock) {
1679 r = rb_mutex_synchronize(fptr->write_lock, io_binwrite_string, (VALUE)&arg);
1680 }
1681 else {
1682 r = io_binwrite_string((VALUE)&arg);
1683 }
1684
1685 /* xxx: other threads may modify given string. */
1686 if (r == n) return len;
1687 if (0 <= r) {
1688 offset += r;
1689 n -= r;
1690 errno = EAGAIN;
1691 }
1692
1693 if (r == -2L)
1694 return -1L;
1695 if (rb_io_maybe_wait_writable(errno, fptr->self, Qnil)) {
1696 rb_io_check_closed(fptr);
1697
1698 if (offset < len)
1699 goto retry;
1700 }
1701
1702 return -1L;
1703 }
1704
1705 if (fptr->wbuf.off) {
1706 if (fptr->wbuf.len)
1707 MEMMOVE(fptr->wbuf.ptr, fptr->wbuf.ptr+fptr->wbuf.off, char, fptr->wbuf.len);
1708 fptr->wbuf.off = 0;
1709 }
1710
1711 MEMMOVE(fptr->wbuf.ptr+fptr->wbuf.off+fptr->wbuf.len, ptr+offset, char, len);
1712 fptr->wbuf.len += (int)len;
1713
1714 return len;
1715}
1716
1717# define MODE_BTMODE(a,b,c) ((fmode & FMODE_BINMODE) ? (b) : \
1718 (fmode & FMODE_TEXTMODE) ? (c) : (a))
1719
1720#define MODE_BTXMODE(a, b, c, d, e, f) ((fmode & FMODE_EXCL) ? \
1721 MODE_BTMODE(d, e, f) : \
1722 MODE_BTMODE(a, b, c))
1723
1724static VALUE
1725do_writeconv(VALUE str, rb_io_t *fptr, int *converted)
1726{
1727 if (NEED_WRITECONV(fptr)) {
1728 VALUE common_encoding = Qnil;
1729 SET_BINARY_MODE(fptr);
1730
1731 make_writeconv(fptr);
1732
1733 if (fptr->writeconv) {
1734#define fmode (fptr->mode)
1735 if (!NIL_P(fptr->writeconv_asciicompat))
1736 common_encoding = fptr->writeconv_asciicompat;
1737 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1) && !rb_enc_asciicompat(rb_enc_get(str))) {
1738 rb_raise(rb_eArgError, "ASCII incompatible string written for text mode IO without encoding conversion: %s",
1739 rb_enc_name(rb_enc_get(str)));
1740 }
1741#undef fmode
1742 }
1743 else {
1744 if (fptr->encs.enc2)
1745 common_encoding = rb_enc_from_encoding(fptr->encs.enc2);
1746 else if (fptr->encs.enc != rb_ascii8bit_encoding())
1747 common_encoding = rb_enc_from_encoding(fptr->encs.enc);
1748 }
1749
1750 if (!NIL_P(common_encoding)) {
1751 str = rb_str_encode(str, common_encoding,
1753 *converted = 1;
1754 }
1755
1756 if (fptr->writeconv) {
1758 *converted = 1;
1759 }
1760 }
1761#if RUBY_CRLF_ENVIRONMENT
1762#define fmode (fptr->mode)
1763 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1)) {
1764 if ((fptr->mode & FMODE_READABLE) &&
1766 setmode(fptr->fd, O_BINARY);
1767 }
1768 else {
1769 setmode(fptr->fd, O_TEXT);
1770 }
1771 if (!rb_enc_asciicompat(rb_enc_get(str))) {
1772 rb_raise(rb_eArgError, "ASCII incompatible string written for text mode IO without encoding conversion: %s",
1773 rb_enc_name(rb_enc_get(str)));
1774 }
1775 }
1776#undef fmode
1777#endif
1778 return str;
1779}
1780
1781static long
1782io_fwrite(VALUE str, rb_io_t *fptr, int nosync)
1783{
1784 int converted = 0;
1785 VALUE tmp;
1786 long n, len;
1787 const char *ptr;
1788#ifdef _WIN32
1789 if (fptr->mode & FMODE_TTY) {
1790 long len = rb_w32_write_console(str, fptr->fd);
1791 if (len > 0) return len;
1792 }
1793#endif
1794 str = do_writeconv(str, fptr, &converted);
1795 if (converted)
1796 OBJ_FREEZE(str);
1797
1798 tmp = rb_str_tmp_frozen_acquire(str);
1799 RSTRING_GETMEM(tmp, ptr, len);
1800 n = io_binwrite(tmp, ptr, len, fptr, nosync);
1801 rb_str_tmp_frozen_release(str, tmp);
1802
1803 return n;
1804}
1805
1806ssize_t
1807rb_io_bufwrite(VALUE io, const void *buf, size_t size)
1808{
1809 rb_io_t *fptr;
1810
1811 GetOpenFile(io, fptr);
1813 return (ssize_t)io_binwrite(0, buf, (long)size, fptr, 0);
1814}
1815
1816static VALUE
1817io_write(VALUE io, VALUE str, int nosync)
1818{
1819 rb_io_t *fptr;
1820 long n;
1821 VALUE tmp;
1822
1823 io = GetWriteIO(io);
1824 str = rb_obj_as_string(str);
1825 tmp = rb_io_check_io(io);
1826 if (NIL_P(tmp)) {
1827 /* port is not IO, call write method for it. */
1828 return rb_funcall(io, id_write, 1, str);
1829 }
1830 io = tmp;
1831 if (RSTRING_LEN(str) == 0) return INT2FIX(0);
1832
1833 GetOpenFile(io, fptr);
1835
1836 n = io_fwrite(str, fptr, nosync);
1837 if (n < 0L) rb_sys_fail_on_write(fptr);
1838
1839 return LONG2FIX(n);
1840}
1841
1842#ifdef HAVE_WRITEV
1843struct binwritev_arg {
1844 rb_io_t *fptr;
1845 const struct iovec *iov;
1846 int iovcnt;
1847};
1848
1849static VALUE
1850call_writev_internal(VALUE arg)
1851{
1852 struct binwritev_arg *p = (struct binwritev_arg *)arg;
1853 return rb_writev_internal(p->fptr, p->iov, p->iovcnt);
1854}
1855
1856static long
1857io_binwritev(struct iovec *iov, int iovcnt, rb_io_t *fptr)
1858{
1859 int i;
1860 long r, total = 0, written_len = 0;
1861
1862 /* don't write anything if current thread has a pending interrupt. */
1864
1865 if (iovcnt == 0) return 0;
1866 for (i = 1; i < iovcnt; i++) total += iov[i].iov_len;
1867
1868 if (fptr->wbuf.ptr == NULL && !(fptr->mode & FMODE_SYNC)) {
1869 fptr->wbuf.off = 0;
1870 fptr->wbuf.len = 0;
1871 fptr->wbuf.capa = IO_WBUF_CAPA_MIN;
1872 fptr->wbuf.ptr = ALLOC_N(char, fptr->wbuf.capa);
1873 fptr->write_lock = rb_mutex_new();
1874 rb_mutex_allow_trap(fptr->write_lock, 1);
1875 }
1876
1877 if (fptr->wbuf.ptr && fptr->wbuf.len) {
1878 long offset = fptr->wbuf.off + fptr->wbuf.len;
1879 if (offset + total <= fptr->wbuf.capa) {
1880 for (i = 1; i < iovcnt; i++) {
1881 memcpy(fptr->wbuf.ptr+offset, iov[i].iov_base, iov[i].iov_len);
1882 offset += iov[i].iov_len;
1883 }
1884 fptr->wbuf.len += total;
1885 return total;
1886 }
1887 else {
1888 iov[0].iov_base = fptr->wbuf.ptr + fptr->wbuf.off;
1889 iov[0].iov_len = fptr->wbuf.len;
1890 }
1891 }
1892 else {
1893 iov++;
1894 if (!--iovcnt) return 0;
1895 }
1896
1897 retry:
1898 if (fptr->write_lock) {
1899 struct binwritev_arg arg;
1900 arg.fptr = fptr;
1901 arg.iov = iov;
1902 arg.iovcnt = iovcnt;
1903 r = rb_mutex_synchronize(fptr->write_lock, call_writev_internal, (VALUE)&arg);
1904 }
1905 else {
1906 r = rb_writev_internal(fptr, iov, iovcnt);
1907 }
1908
1909 if (r >= 0) {
1910 written_len += r;
1911 if (fptr->wbuf.ptr && fptr->wbuf.len) {
1912 if (written_len < fptr->wbuf.len) {
1913 fptr->wbuf.off += r;
1914 fptr->wbuf.len -= r;
1915 }
1916 else {
1917 written_len -= fptr->wbuf.len;
1918 fptr->wbuf.off = 0;
1919 fptr->wbuf.len = 0;
1920 }
1921 }
1922 if (written_len == total) return total;
1923
1924 while (r >= (ssize_t)iov->iov_len) {
1925 /* iovcnt > 0 */
1926 r -= iov->iov_len;
1927 iov->iov_len = 0;
1928 iov++;
1929 if (!--iovcnt) return total;
1930 /* defensive check: written_len should == total */
1931 }
1932 iov->iov_base = (char *)iov->iov_base + r;
1933 iov->iov_len -= r;
1934
1935 errno = EAGAIN;
1936 }
1937 if (rb_io_maybe_wait_writable(errno, fptr->self, Qnil)) {
1938 rb_io_check_closed(fptr);
1939 goto retry;
1940 }
1941
1942 return -1L;
1943}
1944
1945static long
1946io_fwritev(int argc, const VALUE *argv, rb_io_t *fptr)
1947{
1948 int i, converted, iovcnt = argc + 1;
1949 long n;
1950 VALUE v1, v2, str, tmp, *tmp_array;
1951 struct iovec *iov;
1952
1953 iov = ALLOCV_N(struct iovec, v1, iovcnt);
1954 tmp_array = ALLOCV_N(VALUE, v2, argc);
1955
1956 for (i = 0; i < argc; i++) {
1957 str = rb_obj_as_string(argv[i]);
1958 converted = 0;
1959 str = do_writeconv(str, fptr, &converted);
1960 if (converted)
1961 OBJ_FREEZE(str);
1962
1963 tmp = rb_str_tmp_frozen_acquire(str);
1964 tmp_array[i] = tmp;
1965 /* iov[0] is reserved for buffer of fptr */
1966 iov[i+1].iov_base = RSTRING_PTR(tmp);
1967 iov[i+1].iov_len = RSTRING_LEN(tmp);
1968 }
1969
1970 n = io_binwritev(iov, iovcnt, fptr);
1971 if (v1) ALLOCV_END(v1);
1972
1973 for (i = 0; i < argc; i++) {
1974 rb_str_tmp_frozen_release(argv[i], tmp_array[i]);
1975 }
1976
1977 if (v2) ALLOCV_END(v2);
1978
1979 return n;
1980}
1981
1982static int
1983iovcnt_ok(int iovcnt)
1984{
1985#ifdef IOV_MAX
1986 return iovcnt < IOV_MAX;
1987#else /* GNU/Hurd has writev, but no IOV_MAX */
1988 return 1;
1989#endif
1990}
1991#endif /* HAVE_WRITEV */
1992
1993static VALUE
1994io_writev(int argc, const VALUE *argv, VALUE io)
1995{
1996 rb_io_t *fptr;
1997 long n;
1998 VALUE tmp, total = INT2FIX(0);
1999 int i, cnt = 1;
2000
2001 io = GetWriteIO(io);
2002 tmp = rb_io_check_io(io);
2003 if (NIL_P(tmp)) {
2004 /* port is not IO, call write method for it. */
2005 return rb_funcallv(io, id_write, argc, argv);
2006 }
2007 io = tmp;
2008
2009 GetOpenFile(io, fptr);
2011
2012 for (i = 0; i < argc; i += cnt) {
2013#ifdef HAVE_WRITEV
2014 if ((fptr->mode & (FMODE_SYNC|FMODE_TTY)) && iovcnt_ok(cnt = argc - i)) {
2015 n = io_fwritev(cnt, &argv[i], fptr);
2016 }
2017 else
2018#endif
2019 {
2020 cnt = 1;
2021 /* sync at last item */
2022 n = io_fwrite(rb_obj_as_string(argv[i]), fptr, (i < argc-1));
2023 }
2024 if (n < 0L) rb_sys_fail_on_write(fptr);
2025 total = rb_fix_plus(LONG2FIX(n), total);
2026 }
2027
2028 return total;
2029}
2030
2031/*
2032 * call-seq:
2033 * write(*objects) -> integer
2034 *
2035 * Writes each of the given +objects+ to +self+,
2036 * which must be opened for writing (see {Modes}[#class-IO-label-Modes]);
2037 * returns the total number bytes written;
2038 * each of +objects+ that is not a string is converted via method +to_s+:
2039 *
2040 * $stdout.write('Hello', ', ', 'World!', "\n") # => 14
2041 * $stdout.write('foo', :bar, 2, "\n") # => 8
2042 *
2043 * Output:
2044 *
2045 * Hello, World!
2046 * foobar2
2047 *
2048 */
2049
2050static VALUE
2051io_write_m(int argc, VALUE *argv, VALUE io)
2052{
2053 if (argc != 1) {
2054 return io_writev(argc, argv, io);
2055 }
2056 else {
2057 VALUE str = argv[0];
2058 return io_write(io, str, 0);
2059 }
2060}
2061
2062VALUE
2063rb_io_write(VALUE io, VALUE str)
2064{
2065 return rb_funcallv(io, id_write, 1, &str);
2066}
2067
2068static VALUE
2069rb_io_writev(VALUE io, int argc, const VALUE *argv)
2070{
2071 if (argc > 1 && rb_obj_method_arity(io, id_write) == 1) {
2072 if (io != rb_ractor_stderr() && RTEST(ruby_verbose)) {
2073 VALUE klass = CLASS_OF(io);
2074 char sep = FL_TEST(klass, FL_SINGLETON) ? (klass = io, '.') : '#';
2075 rb_category_warning(RB_WARN_CATEGORY_DEPRECATED, "%+"PRIsVALUE"%c""write is outdated interface"
2076 " which accepts just one argument",
2077 klass, sep);
2078 }
2079 do rb_io_write(io, *argv++); while (--argc);
2080 return argv[0]; /* unused right now */
2081 }
2082 return rb_funcallv(io, id_write, argc, argv);
2083}
2084
2085/*
2086 * call-seq:
2087 * self << object -> self
2088 *
2089 * Writes the given +object+ to +self+,
2090 * which must be opened for writing (see {Modes}[#class-IO-label-Modes]);
2091 * returns +self+;
2092 * if +object+ is not a string, it is converted via method +to_s+:
2093 *
2094 * $stdout << 'Hello' << ', ' << 'World!' << "\n"
2095 * $stdout << 'foo' << :bar << 2 << "\n"
2096 *
2097 * Output:
2098 *
2099 * Hello, World!
2100 * foobar2
2101 *
2102 */
2103
2104
2105VALUE
2106rb_io_addstr(VALUE io, VALUE str)
2107{
2108 rb_io_write(io, str);
2109 return io;
2110}
2111
2112#ifdef HAVE_FSYNC
2113static VALUE
2114nogvl_fsync(void *ptr)
2115{
2116 rb_io_t *fptr = ptr;
2117
2118#ifdef _WIN32
2119 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->fd)) != FILE_TYPE_DISK)
2120 return 0;
2121#endif
2122 return (VALUE)fsync(fptr->fd);
2123}
2124#endif
2125
2126VALUE
2127rb_io_flush_raw(VALUE io, int sync)
2128{
2129 rb_io_t *fptr;
2130
2131 if (!RB_TYPE_P(io, T_FILE)) {
2132 return rb_funcall(io, id_flush, 0);
2133 }
2134
2135 io = GetWriteIO(io);
2136 GetOpenFile(io, fptr);
2137
2138 if (fptr->mode & FMODE_WRITABLE) {
2139 if (io_fflush(fptr) < 0)
2140 rb_sys_fail_on_write(fptr);
2141 }
2142 if (fptr->mode & FMODE_READABLE) {
2143 io_unread(fptr);
2144 }
2145
2146 return io;
2147}
2148
2149/*
2150 * call-seq:
2151 * flush -> self
2152 *
2153 * Flushes data buffered in +self+ to the operating system
2154 * (but does not necessarily flush data buffered in the operating system):
2155 *
2156 * $stdout.print 'no newline' # Not necessarily flushed.
2157 * $stdout.flush # Flushed.
2158 *
2159 */
2160
2161VALUE
2163{
2164 return rb_io_flush_raw(io, 1);
2165}
2166
2167/*
2168 * call-seq:
2169 * tell -> integer
2170 *
2171 * Returns the current position (in bytes) in +self+
2172 * (see {Position}[#class-IO-label-Position]):
2173 *
2174 * f = File.new('t.txt')
2175 * f.tell # => 0
2176 * f.readline # => "This is line one.\n"
2177 * f.tell # => 19
2178 *
2179 * Related: IO#pos=, IO#seek.
2180 *
2181 * IO#pos is an alias for IO#tell.
2182 *
2183 */
2184
2185static VALUE
2186rb_io_tell(VALUE io)
2187{
2188 rb_io_t *fptr;
2189 off_t pos;
2190
2191 GetOpenFile(io, fptr);
2192 pos = io_tell(fptr);
2193 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2194 pos -= fptr->rbuf.len;
2195 return OFFT2NUM(pos);
2196}
2197
2198static VALUE
2199rb_io_seek(VALUE io, VALUE offset, int whence)
2200{
2201 rb_io_t *fptr;
2202 off_t pos;
2203
2204 pos = NUM2OFFT(offset);
2205 GetOpenFile(io, fptr);
2206 pos = io_seek(fptr, pos, whence);
2207 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2208
2209 return INT2FIX(0);
2210}
2211
2212static int
2213interpret_seek_whence(VALUE vwhence)
2214{
2215 if (vwhence == sym_SET)
2216 return SEEK_SET;
2217 if (vwhence == sym_CUR)
2218 return SEEK_CUR;
2219 if (vwhence == sym_END)
2220 return SEEK_END;
2221#ifdef SEEK_DATA
2222 if (vwhence == sym_DATA)
2223 return SEEK_DATA;
2224#endif
2225#ifdef SEEK_HOLE
2226 if (vwhence == sym_HOLE)
2227 return SEEK_HOLE;
2228#endif
2229 return NUM2INT(vwhence);
2230}
2231
2232/*
2233 * call-seq:
2234 * seek(offset, whence = IO::SEEK_SET) -> 0
2235 *
2236 * Seeks to the position given by integer +offset+
2237 * (see {Position}[#class-IO-label-Position])
2238 * and constant +whence+, which is one of:
2239 *
2240 * - +:CUR+ or <tt>IO::SEEK_CUR</tt>:
2241 * Repositions the stream to its current position plus the given +offset+:
2242 *
2243 * f = File.open('t.txt')
2244 * f.tell # => 0
2245 * f.seek(20, :CUR) # => 0
2246 * f.tell # => 20
2247 * f.seek(-10, :CUR) # => 0
2248 * f.tell # => 10
2249 *
2250 * - +:END+ or <tt>IO::SEEK_END</tt>:
2251 * Repositions the stream to its end plus the given +offset+:
2252 *
2253 * f = File.open('t.txt')
2254 * f.tell # => 0
2255 * f.seek(0, :END) # => 0 # Repositions to stream end.
2256 * f.tell # => 70
2257 * f.seek(-20, :END) # => 0
2258 * f.tell # => 50
2259 * f.seek(-40, :END) # => 0
2260 * f.tell # => 30
2261 *
2262 * - +:SET+ or <tt>IO:SEEK_SET</tt>:
2263 * Repositions the stream to the given +offset+:
2264 *
2265 * f = File.open('t.txt')
2266 * f.tell # => 0
2267 * f.seek(20, :SET) # => 0
2268 * f.tell # => 20
2269 * f.seek(40, :SET) # => 0
2270 * f.tell # => 40
2271 *
2272 * Related: IO#pos=, IO#tell.
2273 *
2274 */
2275
2276static VALUE
2277rb_io_seek_m(int argc, VALUE *argv, VALUE io)
2278{
2279 VALUE offset, ptrname;
2280 int whence = SEEK_SET;
2281
2282 if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
2283 whence = interpret_seek_whence(ptrname);
2284 }
2285
2286 return rb_io_seek(io, offset, whence);
2287}
2288
2289/*
2290 * call-seq:
2291 * pos = new_position -> new_position
2292 *
2293 * Seeks to the given +new_position+ (in bytes);
2294 * see {Position}[#class-IO-label-Position]:
2295 *
2296 * f = File.open('t.txt')
2297 * f.tell # => 0
2298 * f.pos = 20 # => 20
2299 * f.tell # => 20
2300 *
2301 * Related: IO#seek, IO#tell.
2302 *
2303 */
2304
2305static VALUE
2306rb_io_set_pos(VALUE io, VALUE offset)
2307{
2308 rb_io_t *fptr;
2309 off_t pos;
2310
2311 pos = NUM2OFFT(offset);
2312 GetOpenFile(io, fptr);
2313 pos = io_seek(fptr, pos, SEEK_SET);
2314 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2315
2316 return OFFT2NUM(pos);
2317}
2318
2319static void clear_readconv(rb_io_t *fptr);
2320
2321/*
2322 * call-seq:
2323 * rewind -> 0
2324 *
2325 * Repositions the stream to its beginning,
2326 * setting both the position and the line number to zero;
2327 * see {Position}[#class-IO-label-Position]
2328 * and {Line Number}[#class-IO-label-Line+Number]:
2329 *
2330 * f = File.open('t.txt')
2331 * f.tell # => 0
2332 * f.lineno # => 0
2333 * f.readline # => "This is line one.\n"
2334 * f.tell # => 19
2335 * f.lineno # => 1
2336 * f.rewind # => 0
2337 * f.tell # => 0
2338 * f.lineno # => 0
2339 *
2340 * Note that this method cannot be used with streams such as pipes, ttys, and sockets.
2341 *
2342 */
2343
2344static VALUE
2345rb_io_rewind(VALUE io)
2346{
2347 rb_io_t *fptr;
2348
2349 GetOpenFile(io, fptr);
2350 if (io_seek(fptr, 0L, 0) < 0 && errno) rb_sys_fail_path(fptr->pathv);
2351 if (io == ARGF.current_file) {
2352 ARGF.lineno -= fptr->lineno;
2353 }
2354 fptr->lineno = 0;
2355 if (fptr->readconv) {
2356 clear_readconv(fptr);
2357 }
2358
2359 return INT2FIX(0);
2360}
2361
2362static int
2363fptr_wait_readable(rb_io_t *fptr)
2364{
2365 int ret = rb_io_maybe_wait_readable(errno, fptr->self, Qnil);
2366
2367 if (ret)
2368 rb_io_check_closed(fptr);
2369
2370 return ret;
2371}
2372
2373static int
2374io_fillbuf(rb_io_t *fptr)
2375{
2376 ssize_t r;
2377
2378 if (fptr->rbuf.ptr == NULL) {
2379 fptr->rbuf.off = 0;
2380 fptr->rbuf.len = 0;
2381 fptr->rbuf.capa = IO_RBUF_CAPA_FOR(fptr);
2382 fptr->rbuf.ptr = ALLOC_N(char, fptr->rbuf.capa);
2383#ifdef _WIN32
2384 fptr->rbuf.capa--;
2385#endif
2386 }
2387 if (fptr->rbuf.len == 0) {
2388 retry:
2389 r = rb_read_internal(fptr, fptr->rbuf.ptr, fptr->rbuf.capa);
2390
2391 if (r < 0) {
2392 if (fptr_wait_readable(fptr))
2393 goto retry;
2394
2395 int e = errno;
2396 VALUE path = rb_sprintf("fd:%d ", fptr->fd);
2397 if (!NIL_P(fptr->pathv)) {
2398 rb_str_append(path, fptr->pathv);
2399 }
2400
2401 rb_syserr_fail_path(e, path);
2402 }
2403 if (r > 0) rb_io_check_closed(fptr);
2404 fptr->rbuf.off = 0;
2405 fptr->rbuf.len = (int)r; /* r should be <= rbuf_capa */
2406 if (r == 0)
2407 return -1; /* EOF */
2408 }
2409 return 0;
2410}
2411
2412/*
2413 * call-seq:
2414 * eof -> true or false
2415 *
2416 * Returns +true+ if the stream is positioned at its end, +false+ otherwise;
2417 * see {Position}[#class-IO-label-Position]:
2418 *
2419 * f = File.open('t.txt')
2420 * f.eof # => false
2421 * f.seek(0, :END) # => 0
2422 * f.eof # => true
2423 *
2424 * Raises an exception unless the stream is opened for reading;
2425 * see {Mode}[#class-IO-label-Mode].
2426 *
2427 * If +self+ is a stream such as pipe or socket, this method
2428 * blocks until the other end sends some data or closes it:
2429 *
2430 * r, w = IO.pipe
2431 * Thread.new { sleep 1; w.close }
2432 * r.eof? # => true # After 1-second wait.
2433 *
2434 * r, w = IO.pipe
2435 * Thread.new { sleep 1; w.puts "a" }
2436 * r.eof? # => false # After 1-second wait.
2437 *
2438 * r, w = IO.pipe
2439 * r.eof? # blocks forever
2440 *
2441 * Note that this method reads data to the input byte buffer. So
2442 * IO#sysread may not behave as you intend with IO#eof?, unless you
2443 * call IO#rewind first (which is not available for some streams).
2444 *
2445 * I#eof? is an alias for IO#eof.
2446 *
2447 */
2448
2449VALUE
2450rb_io_eof(VALUE io)
2451{
2452 rb_io_t *fptr;
2453
2454 GetOpenFile(io, fptr);
2456
2457 if (READ_CHAR_PENDING(fptr)) return Qfalse;
2458 if (READ_DATA_PENDING(fptr)) return Qfalse;
2459 READ_CHECK(fptr);
2460#if RUBY_CRLF_ENVIRONMENT
2461 if (!NEED_READCONV(fptr) && NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
2462 return RBOOL(eof(fptr->fd));;
2463 }
2464#endif
2465 return RBOOL(io_fillbuf(fptr) < 0);
2466}
2467
2468/*
2469 * call-seq:
2470 * sync -> true or false
2471 *
2472 * Returns the current sync mode of the stream.
2473 * When sync mode is true, all output is immediately flushed to the underlying
2474 * operating system and is not buffered by Ruby internally. See also #fsync.
2475 *
2476 * f = File.open('t.tmp', 'w')
2477 * f.sync # => false
2478 * f.sync = true
2479 * f.sync # => true
2480 *
2481 */
2482
2483static VALUE
2484rb_io_sync(VALUE io)
2485{
2486 rb_io_t *fptr;
2487
2488 io = GetWriteIO(io);
2489 GetOpenFile(io, fptr);
2490 return RBOOL(fptr->mode & FMODE_SYNC);
2491}
2492
2493#ifdef HAVE_FSYNC
2494
2495/*
2496 * call-seq:
2497 * sync = boolean -> boolean
2498 *
2499 * Sets the _sync_ _mode_ for the stream to the given value;
2500 * returns the given value.
2501 *
2502 * Values for the sync mode:
2503 *
2504 * - +true+: All output is immediately flushed to the
2505 * underlying operating system and is not buffered internally.
2506 * - +false+: Output may be buffered internally.
2507 *
2508 * Example;
2509 *
2510 * f = File.open('t.tmp', 'w')
2511 * f.sync # => false
2512 * f.sync = true
2513 * f.sync # => true
2514 *
2515 * Related: IO#fsync.
2516 *
2517 */
2518
2519static VALUE
2520rb_io_set_sync(VALUE io, VALUE sync)
2521{
2522 rb_io_t *fptr;
2523
2524 io = GetWriteIO(io);
2525 GetOpenFile(io, fptr);
2526 if (RTEST(sync)) {
2527 fptr->mode |= FMODE_SYNC;
2528 }
2529 else {
2530 fptr->mode &= ~FMODE_SYNC;
2531 }
2532 return sync;
2533}
2534
2535/*
2536 * call-seq:
2537 * fsync -> 0
2538 *
2539 * Immediately writes to disk all data buffered in the stream,
2540 * via the operating system's <tt>fsync(2)</tt>.
2541
2542 * Note this difference:
2543 *
2544 * - IO#sync=: Ensures that data is flushed from the stream's internal buffers,
2545 * but does not guarantee that the operating system actually writes the data to disk.
2546 * - IO#fsync: Ensures both that data is flushed from internal buffers,
2547 * and that data is written to disk.
2548 *
2549 * Raises an exception if the operating system does not support <tt>fsync(2)</tt>.
2550 *
2551 */
2552
2553static VALUE
2554rb_io_fsync(VALUE io)
2555{
2556 rb_io_t *fptr;
2557
2558 io = GetWriteIO(io);
2559 GetOpenFile(io, fptr);
2560
2561 if (io_fflush(fptr) < 0)
2562 rb_sys_fail_on_write(fptr);
2563 if ((int)rb_thread_io_blocking_region(nogvl_fsync, fptr, fptr->fd) < 0)
2564 rb_sys_fail_path(fptr->pathv);
2565 return INT2FIX(0);
2566}
2567#else
2568# define rb_io_fsync rb_f_notimplement
2569# define rb_io_sync rb_f_notimplement
2570static VALUE
2571rb_io_set_sync(VALUE io, VALUE sync)
2572{
2575}
2576#endif
2577
2578#ifdef HAVE_FDATASYNC
2579static VALUE
2580nogvl_fdatasync(void *ptr)
2581{
2582 rb_io_t *fptr = ptr;
2583
2584#ifdef _WIN32
2585 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->fd)) != FILE_TYPE_DISK)
2586 return 0;
2587#endif
2588 return (VALUE)fdatasync(fptr->fd);
2589}
2590
2591/*
2592 * call-seq:
2593 * fdatasync -> 0
2594 *
2595 * Immediately writes to disk all data buffered in the stream,
2596 * via the operating system's: <tt>fdatasync(2)</tt>, if supported,
2597 * otherwise via <tt>fsync(2)</tt>, if supported;
2598 * otherwise raises an exception.
2599 *
2600 */
2601
2602static VALUE
2603rb_io_fdatasync(VALUE io)
2604{
2605 rb_io_t *fptr;
2606
2607 io = GetWriteIO(io);
2608 GetOpenFile(io, fptr);
2609
2610 if (io_fflush(fptr) < 0)
2611 rb_sys_fail_on_write(fptr);
2612
2613 if ((int)rb_thread_io_blocking_region(nogvl_fdatasync, fptr, fptr->fd) == 0)
2614 return INT2FIX(0);
2615
2616 /* fall back */
2617 return rb_io_fsync(io);
2618}
2619#else
2620#define rb_io_fdatasync rb_io_fsync
2621#endif
2622
2623/*
2624 * call-seq:
2625 * fileno -> integer
2626 *
2627 * Returns the integer file descriptor for the stream:
2628 *
2629 * $stdin.fileno # => 0
2630 * $stdout.fileno # => 1
2631 * $stderr.fileno # => 2
2632 * File.open('t.txt').fileno # => 10
2633 *
2634 * IO#to_i is an alias for IO#fileno.
2635 *
2636 */
2637
2638static VALUE
2639rb_io_fileno(VALUE io)
2640{
2641 rb_io_t *fptr = RFILE(io)->fptr;
2642 int fd;
2643
2644 rb_io_check_closed(fptr);
2645 fd = fptr->fd;
2646 return INT2FIX(fd);
2647}
2648
2649int
2651{
2652 if (RB_TYPE_P(io, T_FILE)) {
2653 rb_io_t *fptr = RFILE(io)->fptr;
2654 rb_io_check_closed(fptr);
2655 return fptr->fd;
2656 }
2657 else {
2658 return RB_NUM2INT(rb_funcall(io, id_fileno, 0));
2659 }
2660}
2661
2662/*
2663 * call-seq:
2664 * pid -> integer or nil
2665 *
2666 * Returns the process ID of a child process associated with the stream,
2667 * which will have been set by IO#popen, or +nil+ if the stream was not
2668 * created by IO#popen:
2669 *
2670 * pipe = IO.popen("-")
2671 * if pipe
2672 * $stderr.puts "In parent, child pid is #{pipe.pid}"
2673 * else
2674 * $stderr.puts "In child, pid is #{$$}"
2675 * end
2676 *
2677 * Output:
2678 *
2679 * In child, pid is 26209
2680 * In parent, child pid is 26209
2681 *
2682 */
2683
2684static VALUE
2685rb_io_pid(VALUE io)
2686{
2687 rb_io_t *fptr;
2688
2689 GetOpenFile(io, fptr);
2690 if (!fptr->pid)
2691 return Qnil;
2692 return PIDT2NUM(fptr->pid);
2693}
2694
2695
2696/*
2697 * call-seq:
2698 * inspect -> string
2699 *
2700 * Returns a string representation of +self+:
2701 *
2702 * f = File.open('t.txt')
2703 * f.inspect # => "#<File:t.txt>"
2704 *
2705 */
2706
2707static VALUE
2708rb_io_inspect(VALUE obj)
2709{
2710 rb_io_t *fptr;
2711 VALUE result;
2712 static const char closed[] = " (closed)";
2713
2714 fptr = RFILE(obj)->fptr;
2715 if (!fptr) return rb_any_to_s(obj);
2716 result = rb_str_new_cstr("#<");
2717 rb_str_append(result, rb_class_name(CLASS_OF(obj)));
2718 rb_str_cat2(result, ":");
2719 if (NIL_P(fptr->pathv)) {
2720 if (fptr->fd < 0) {
2721 rb_str_cat(result, closed+1, strlen(closed)-1);
2722 }
2723 else {
2724 rb_str_catf(result, "fd %d", fptr->fd);
2725 }
2726 }
2727 else {
2728 rb_str_append(result, fptr->pathv);
2729 if (fptr->fd < 0) {
2730 rb_str_cat(result, closed, strlen(closed));
2731 }
2732 }
2733 return rb_str_cat2(result, ">");
2734}
2735
2736/*
2737 * call-seq:
2738 * to_io -> self
2739 *
2740 * Returns +self+.
2741 *
2742 */
2743
2744static VALUE
2745rb_io_to_io(VALUE io)
2746{
2747 return io;
2748}
2749
2750/* reading functions */
2751static long
2752read_buffered_data(char *ptr, long len, rb_io_t *fptr)
2753{
2754 int n;
2755
2756 n = READ_DATA_PENDING_COUNT(fptr);
2757 if (n <= 0) return 0;
2758 if (n > len) n = (int)len;
2759 MEMMOVE(ptr, fptr->rbuf.ptr+fptr->rbuf.off, char, n);
2760 fptr->rbuf.off += n;
2761 fptr->rbuf.len -= n;
2762 return n;
2763}
2764
2765static long
2766io_bufread(char *ptr, long len, rb_io_t *fptr)
2767{
2768 long offset = 0;
2769 long n = len;
2770 long c;
2771
2772 if (READ_DATA_PENDING(fptr) == 0) {
2773 while (n > 0) {
2774 again:
2775 rb_io_check_closed(fptr);
2776 c = rb_read_internal(fptr, ptr+offset, n);
2777 if (c == 0) break;
2778 if (c < 0) {
2779 if (fptr_wait_readable(fptr))
2780 goto again;
2781 return -1;
2782 }
2783 offset += c;
2784 if ((n -= c) <= 0) break;
2785 }
2786 return len - n;
2787 }
2788
2789 while (n > 0) {
2790 c = read_buffered_data(ptr+offset, n, fptr);
2791 if (c > 0) {
2792 offset += c;
2793 if ((n -= c) <= 0) break;
2794 }
2795 rb_io_check_closed(fptr);
2796 if (io_fillbuf(fptr) < 0) {
2797 break;
2798 }
2799 }
2800 return len - n;
2801}
2802
2803static int io_setstrbuf(VALUE *str, long len);
2804
2806 char *str_ptr;
2807 long len;
2808 rb_io_t *fptr;
2809};
2810
2811static VALUE
2812bufread_call(VALUE arg)
2813{
2814 struct bufread_arg *p = (struct bufread_arg *)arg;
2815 p->len = io_bufread(p->str_ptr, p->len, p->fptr);
2816 return Qundef;
2817}
2818
2819static long
2820io_fread(VALUE str, long offset, long size, rb_io_t *fptr)
2821{
2822 long len;
2823 struct bufread_arg arg;
2824
2825 io_setstrbuf(&str, offset + size);
2826 arg.str_ptr = RSTRING_PTR(str) + offset;
2827 arg.len = size;
2828 arg.fptr = fptr;
2829 rb_str_locktmp_ensure(str, bufread_call, (VALUE)&arg);
2830 len = arg.len;
2831 if (len < 0) rb_sys_fail_path(fptr->pathv);
2832 return len;
2833}
2834
2835static long
2836remain_size(rb_io_t *fptr)
2837{
2838 struct stat st;
2839 off_t siz = READ_DATA_PENDING_COUNT(fptr);
2840 off_t pos;
2841
2842 if (fstat(fptr->fd, &st) == 0 && S_ISREG(st.st_mode)
2843#if defined(__HAIKU__)
2844 && (st.st_dev > 3)
2845#endif
2846 )
2847 {
2848 if (io_fflush(fptr) < 0)
2849 rb_sys_fail_on_write(fptr);
2850 pos = lseek(fptr->fd, 0, SEEK_CUR);
2851 if (st.st_size >= pos && pos >= 0) {
2852 siz += st.st_size - pos;
2853 if (siz > LONG_MAX) {
2854 rb_raise(rb_eIOError, "file too big for single read");
2855 }
2856 }
2857 }
2858 else {
2859 siz += BUFSIZ;
2860 }
2861 return (long)siz;
2862}
2863
2864static VALUE
2865io_enc_str(VALUE str, rb_io_t *fptr)
2866{
2867 rb_enc_associate(str, io_read_encoding(fptr));
2868 return str;
2869}
2870
2871static void
2872make_readconv(rb_io_t *fptr, int size)
2873{
2874 if (!fptr->readconv) {
2875 int ecflags;
2876 VALUE ecopts;
2877 const char *sname, *dname;
2878 ecflags = fptr->encs.ecflags & ~ECONV_NEWLINE_DECORATOR_WRITE_MASK;
2879 ecopts = fptr->encs.ecopts;
2880 if (fptr->encs.enc2) {
2881 sname = rb_enc_name(fptr->encs.enc2);
2882 dname = rb_enc_name(fptr->encs.enc);
2883 }
2884 else {
2885 sname = dname = "";
2886 }
2887 fptr->readconv = rb_econv_open_opts(sname, dname, ecflags, ecopts);
2888 if (!fptr->readconv)
2889 rb_exc_raise(rb_econv_open_exc(sname, dname, ecflags));
2890 fptr->cbuf.off = 0;
2891 fptr->cbuf.len = 0;
2892 if (size < IO_CBUF_CAPA_MIN) size = IO_CBUF_CAPA_MIN;
2893 fptr->cbuf.capa = size;
2894 fptr->cbuf.ptr = ALLOC_N(char, fptr->cbuf.capa);
2895 }
2896}
2897
2898#define MORE_CHAR_SUSPENDED Qtrue
2899#define MORE_CHAR_FINISHED Qnil
2900static VALUE
2901fill_cbuf(rb_io_t *fptr, int ec_flags)
2902{
2903 const unsigned char *ss, *sp, *se;
2904 unsigned char *ds, *dp, *de;
2905 rb_econv_result_t res;
2906 int putbackable;
2907 int cbuf_len0;
2908 VALUE exc;
2909
2910 ec_flags |= ECONV_PARTIAL_INPUT;
2911
2912 if (fptr->cbuf.len == fptr->cbuf.capa)
2913 return MORE_CHAR_SUSPENDED; /* cbuf full */
2914 if (fptr->cbuf.len == 0)
2915 fptr->cbuf.off = 0;
2916 else if (fptr->cbuf.off + fptr->cbuf.len == fptr->cbuf.capa) {
2917 memmove(fptr->cbuf.ptr, fptr->cbuf.ptr+fptr->cbuf.off, fptr->cbuf.len);
2918 fptr->cbuf.off = 0;
2919 }
2920
2921 cbuf_len0 = fptr->cbuf.len;
2922
2923 while (1) {
2924 ss = sp = (const unsigned char *)fptr->rbuf.ptr + fptr->rbuf.off;
2925 se = sp + fptr->rbuf.len;
2926 ds = dp = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.off + fptr->cbuf.len;
2927 de = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.capa;
2928 res = rb_econv_convert(fptr->readconv, &sp, se, &dp, de, ec_flags);
2929 fptr->rbuf.off += (int)(sp - ss);
2930 fptr->rbuf.len -= (int)(sp - ss);
2931 fptr->cbuf.len += (int)(dp - ds);
2932
2933 putbackable = rb_econv_putbackable(fptr->readconv);
2934 if (putbackable) {
2935 rb_econv_putback(fptr->readconv, (unsigned char *)fptr->rbuf.ptr + fptr->rbuf.off - putbackable, putbackable);
2936 fptr->rbuf.off -= putbackable;
2937 fptr->rbuf.len += putbackable;
2938 }
2939
2940 exc = rb_econv_make_exception(fptr->readconv);
2941 if (!NIL_P(exc))
2942 return exc;
2943
2944 if (cbuf_len0 != fptr->cbuf.len)
2945 return MORE_CHAR_SUSPENDED;
2946
2947 if (res == econv_finished) {
2948 return MORE_CHAR_FINISHED;
2949 }
2950
2951 if (res == econv_source_buffer_empty) {
2952 if (fptr->rbuf.len == 0) {
2953 READ_CHECK(fptr);
2954 if (io_fillbuf(fptr) < 0) {
2955 if (!fptr->readconv) {
2956 return MORE_CHAR_FINISHED;
2957 }
2958 ds = dp = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.off + fptr->cbuf.len;
2959 de = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.capa;
2960 res = rb_econv_convert(fptr->readconv, NULL, NULL, &dp, de, 0);
2961 fptr->cbuf.len += (int)(dp - ds);
2963 break;
2964 }
2965 }
2966 }
2967 }
2968 if (cbuf_len0 != fptr->cbuf.len)
2969 return MORE_CHAR_SUSPENDED;
2970
2971 return MORE_CHAR_FINISHED;
2972}
2973
2974static VALUE
2975more_char(rb_io_t *fptr)
2976{
2977 VALUE v;
2978 v = fill_cbuf(fptr, ECONV_AFTER_OUTPUT);
2979 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED)
2980 rb_exc_raise(v);
2981 return v;
2982}
2983
2984static VALUE
2985io_shift_cbuf(rb_io_t *fptr, int len, VALUE *strp)
2986{
2987 VALUE str = Qnil;
2988 if (strp) {
2989 str = *strp;
2990 if (NIL_P(str)) {
2991 *strp = str = rb_str_new(fptr->cbuf.ptr+fptr->cbuf.off, len);
2992 }
2993 else {
2994 rb_str_cat(str, fptr->cbuf.ptr+fptr->cbuf.off, len);
2995 }
2996 rb_enc_associate(str, fptr->encs.enc);
2997 }
2998 fptr->cbuf.off += len;
2999 fptr->cbuf.len -= len;
3000 /* xxx: set coderange */
3001 if (fptr->cbuf.len == 0)
3002 fptr->cbuf.off = 0;
3003 else if (fptr->cbuf.capa/2 < fptr->cbuf.off) {
3004 memmove(fptr->cbuf.ptr, fptr->cbuf.ptr+fptr->cbuf.off, fptr->cbuf.len);
3005 fptr->cbuf.off = 0;
3006 }
3007 return str;
3008}
3009
3010static int
3011io_setstrbuf(VALUE *str, long len)
3012{
3013#ifdef _WIN32
3014 len = (len + 1) & ~1L; /* round up for wide char */
3015#endif
3016 if (NIL_P(*str)) {
3017 *str = rb_str_new(0, len);
3018 return TRUE;
3019 }
3020 else {
3021 VALUE s = StringValue(*str);
3022 long clen = RSTRING_LEN(s);
3023 if (clen >= len) {
3024 rb_str_modify(s);
3025 return FALSE;
3026 }
3027 len -= clen;
3028 }
3029 rb_str_modify_expand(*str, len);
3030 return FALSE;
3031}
3032
3033#define MAX_REALLOC_GAP 4096
3034static void
3035io_shrink_read_string(VALUE str, long n)
3036{
3037 if (rb_str_capacity(str) - n > MAX_REALLOC_GAP) {
3038 rb_str_resize(str, n);
3039 }
3040}
3041
3042static void
3043io_set_read_length(VALUE str, long n, int shrinkable)
3044{
3045 if (RSTRING_LEN(str) != n) {
3046 rb_str_modify(str);
3047 rb_str_set_len(str, n);
3048 if (shrinkable) io_shrink_read_string(str, n);
3049 }
3050}
3051
3052static VALUE
3053read_all(rb_io_t *fptr, long siz, VALUE str)
3054{
3055 long bytes;
3056 long n;
3057 long pos;
3058 rb_encoding *enc;
3059 int cr;
3060 int shrinkable;
3061
3062 if (NEED_READCONV(fptr)) {
3063 int first = !NIL_P(str);
3064 SET_BINARY_MODE(fptr);
3065 shrinkable = io_setstrbuf(&str,0);
3066 make_readconv(fptr, 0);
3067 while (1) {
3068 VALUE v;
3069 if (fptr->cbuf.len) {
3070 if (first) rb_str_set_len(str, first = 0);
3071 io_shift_cbuf(fptr, fptr->cbuf.len, &str);
3072 }
3073 v = fill_cbuf(fptr, 0);
3074 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED) {
3075 if (fptr->cbuf.len) {
3076 if (first) rb_str_set_len(str, first = 0);
3077 io_shift_cbuf(fptr, fptr->cbuf.len, &str);
3078 }
3079 rb_exc_raise(v);
3080 }
3081 if (v == MORE_CHAR_FINISHED) {
3082 clear_readconv(fptr);
3083 if (first) rb_str_set_len(str, first = 0);
3084 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3085 return io_enc_str(str, fptr);
3086 }
3087 }
3088 }
3089
3090 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3091 bytes = 0;
3092 pos = 0;
3093
3094 enc = io_read_encoding(fptr);
3095 cr = 0;
3096
3097 if (siz == 0) siz = BUFSIZ;
3098 shrinkable = io_setstrbuf(&str, siz);
3099 for (;;) {
3100 READ_CHECK(fptr);
3101 n = io_fread(str, bytes, siz - bytes, fptr);
3102 if (n == 0 && bytes == 0) {
3103 rb_str_set_len(str, 0);
3104 break;
3105 }
3106 bytes += n;
3107 rb_str_set_len(str, bytes);
3108 if (cr != ENC_CODERANGE_BROKEN)
3109 pos += rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + bytes, enc, &cr);
3110 if (bytes < siz) break;
3111 siz += BUFSIZ;
3112 rb_str_modify_expand(str, BUFSIZ);
3113 }
3114 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3115 str = io_enc_str(str, fptr);
3116 ENC_CODERANGE_SET(str, cr);
3117 return str;
3118}
3119
3120void
3122{
3123 if (rb_fd_set_nonblock(fptr->fd) != 0) {
3124 rb_sys_fail_path(fptr->pathv);
3125 }
3126}
3127
3128static VALUE
3129read_internal_call(VALUE arg)
3130{
3131 struct io_internal_read_struct *iis = (struct io_internal_read_struct *)arg;
3132
3133 VALUE scheduler = rb_fiber_scheduler_current();
3134 if (scheduler != Qnil) {
3135 VALUE result = rb_fiber_scheduler_io_read_memory(scheduler, iis->fptr->self, iis->buf, iis->capa, 0);
3136
3137 if (result != Qundef) {
3138 // This is actually returned as a pseudo-VALUE and later cast to a long:
3139 return (VALUE)rb_fiber_scheduler_io_result_apply(result);
3140 }
3141 }
3142
3143 return rb_thread_io_blocking_region(internal_read_func, iis, iis->fptr->fd);
3144}
3145
3146static long
3147read_internal_locktmp(VALUE str, struct io_internal_read_struct *iis)
3148{
3149 return (long)rb_str_locktmp_ensure(str, read_internal_call, (VALUE)iis);
3150}
3151
3152#define no_exception_p(opts) !rb_opts_exception_p((opts), TRUE)
3153
3154static VALUE
3155io_getpartial(int argc, VALUE *argv, VALUE io, int no_exception, int nonblock)
3156{
3157 rb_io_t *fptr;
3158 VALUE length, str;
3159 long n, len;
3160 struct io_internal_read_struct iis;
3161 int shrinkable;
3162
3163 rb_scan_args(argc, argv, "11", &length, &str);
3164
3165 if ((len = NUM2LONG(length)) < 0) {
3166 rb_raise(rb_eArgError, "negative length %ld given", len);
3167 }
3168
3169 shrinkable = io_setstrbuf(&str, len);
3170
3171 GetOpenFile(io, fptr);
3173
3174 if (len == 0) {
3175 io_set_read_length(str, 0, shrinkable);
3176 return str;
3177 }
3178
3179 if (!nonblock)
3180 READ_CHECK(fptr);
3181 n = read_buffered_data(RSTRING_PTR(str), len, fptr);
3182 if (n <= 0) {
3183 again:
3184 if (nonblock) {
3185 rb_io_set_nonblock(fptr);
3186 }
3187 io_setstrbuf(&str, len);
3188 iis.th = rb_thread_current();
3189 iis.fptr = fptr;
3190 iis.nonblock = nonblock;
3191 iis.buf = RSTRING_PTR(str);
3192 iis.capa = len;
3193 n = read_internal_locktmp(str, &iis);
3194 if (n < 0) {
3195 int e = errno;
3196 if (!nonblock && fptr_wait_readable(fptr))
3197 goto again;
3198 if (nonblock && (io_again_p(e))) {
3199 if (no_exception)
3200 return sym_wait_readable;
3201 else
3202 rb_readwrite_syserr_fail(RB_IO_WAIT_READABLE,
3203 e, "read would block");
3204 }
3205 rb_syserr_fail_path(e, fptr->pathv);
3206 }
3207 }
3208 io_set_read_length(str, n, shrinkable);
3209
3210 if (n == 0)
3211 return Qnil;
3212 else
3213 return str;
3214}
3215
3216/*
3217 * call-seq:
3218 * readpartial(maxlen) -> string
3219 * readpartial(maxlen, out_string) -> out_string
3220 *
3221 * Reads up to +maxlen+ bytes from the stream;
3222 * returns a string (either a new string or the given +out_string+).
3223 * Its encoding is:
3224 *
3225 * - The unchanged encoding of +out_string+, if +out_string+ is given.
3226 * - ASCII-8BIT, otherwise.
3227 *
3228 * - Contains +maxlen+ bytes from the stream, if available.
3229 * - Otherwise contains all available bytes, if any available.
3230 * - Otherwise is an empty string.
3231 *
3232 * With the single non-negative integer argument +maxlen+ given,
3233 * returns a new string:
3234 *
3235 * f = File.new('t.txt')
3236 * f.readpartial(30) # => "This is line one.\nThis is the"
3237 * f.readpartial(30) # => " second line.\nThis is the thi"
3238 * f.readpartial(30) # => "rd line.\n"
3239 * f.eof # => true
3240 * f.readpartial(30) # Raises EOFError.
3241 *
3242 * With both argument +maxlen+ and string argument +out_string+ given,
3243 * returns modified +out_string+:
3244 *
3245 * f = File.new('t.txt')
3246 * s = 'foo'
3247 * f.readpartial(30, s) # => "This is line one.\nThis is the"
3248 * s = 'bar'
3249 * f.readpartial(0, s) # => ""
3250 *
3251 * This method is useful for a stream such as a pipe, a socket, or a tty.
3252 * It blocks only when no data is immediately available.
3253 * This means that it blocks only when _all_ of the following are true:
3254 *
3255 * - The byte buffer in the stream is empty.
3256 * - The content of the stream is empty.
3257 * - The stream is not at EOF.
3258 *
3259 * When blocked, the method waits for either more data or EOF on the stream:
3260 *
3261 * - If more data is read, the method returns the data.
3262 * - If EOF is reached, the method raises EOFError.
3263 *
3264 * When not blocked, the method responds immediately:
3265 *
3266 * - Returns data from the buffer if there is any.
3267 * - Otherwise returns data from the stream if there is any.
3268 * - Otherwise raises EOFError if the stream has reached EOF.
3269 *
3270 * Note that this method is similar to sysread. The differences are:
3271 *
3272 * - If the byte buffer is not empty, read from the byte buffer
3273 * instead of "sysread for buffered IO (IOError)".
3274 * - It doesn't cause Errno::EWOULDBLOCK and Errno::EINTR. When
3275 * readpartial meets EWOULDBLOCK and EINTR by read system call,
3276 * readpartial retries the system call.
3277 *
3278 * The latter means that readpartial is non-blocking-flag insensitive.
3279 * It blocks on the situation IO#sysread causes Errno::EWOULDBLOCK as
3280 * if the fd is blocking mode.
3281 *
3282 * Examples:
3283 *
3284 * # # Returned Buffer Content Pipe Content
3285 * r, w = IO.pipe #
3286 * w << 'abc' # "" "abc".
3287 * r.readpartial(4096) # => "abc" "" ""
3288 * r.readpartial(4096) # (Blocks because buffer and pipe are empty.)
3289 *
3290 * # # Returned Buffer Content Pipe Content
3291 * r, w = IO.pipe #
3292 * w << 'abc' # "" "abc"
3293 * w.close # "" "abc" EOF
3294 * r.readpartial(4096) # => "abc" "" EOF
3295 * r.readpartial(4096) # raises EOFError
3296 *
3297 * # # Returned Buffer Content Pipe Content
3298 * r, w = IO.pipe #
3299 * w << "abc\ndef\n" # "" "abc\ndef\n"
3300 * r.gets # => "abc\n" "def\n" ""
3301 * w << "ghi\n" # "def\n" "ghi\n"
3302 * r.readpartial(4096) # => "def\n" "" "ghi\n"
3303 * r.readpartial(4096) # => "ghi\n" "" ""
3304 *
3305 */
3306
3307static VALUE
3308io_readpartial(int argc, VALUE *argv, VALUE io)
3309{
3310 VALUE ret;
3311
3312 ret = io_getpartial(argc, argv, io, Qnil, 0);
3313 if (NIL_P(ret))
3314 rb_eof_error();
3315 return ret;
3316}
3317
3318static VALUE
3319io_nonblock_eof(int no_exception)
3320{
3321 if (!no_exception) {
3322 rb_eof_error();
3323 }
3324 return Qnil;
3325}
3326
3327/* :nodoc: */
3328static VALUE
3329io_read_nonblock(rb_execution_context_t *ec, VALUE io, VALUE length, VALUE str, VALUE ex)
3330{
3331 rb_io_t *fptr;
3332 long n, len;
3333 struct io_internal_read_struct iis;
3334 int shrinkable;
3335
3336 if ((len = NUM2LONG(length)) < 0) {
3337 rb_raise(rb_eArgError, "negative length %ld given", len);
3338 }
3339
3340 shrinkable = io_setstrbuf(&str, len);
3341 rb_bool_expected(ex, "exception");
3342
3343 GetOpenFile(io, fptr);
3345
3346 if (len == 0) {
3347 io_set_read_length(str, 0, shrinkable);
3348 return str;
3349 }
3350
3351 n = read_buffered_data(RSTRING_PTR(str), len, fptr);
3352 if (n <= 0) {
3353 rb_io_set_nonblock(fptr);
3354 shrinkable |= io_setstrbuf(&str, len);
3355 iis.fptr = fptr;
3356 iis.nonblock = 1;
3357 iis.buf = RSTRING_PTR(str);
3358 iis.capa = len;
3359 n = read_internal_locktmp(str, &iis);
3360 if (n < 0) {
3361 int e = errno;
3362 if (io_again_p(e)) {
3363 if (!ex) return sym_wait_readable;
3364 rb_readwrite_syserr_fail(RB_IO_WAIT_READABLE,
3365 e, "read would block");
3366 }
3367 rb_syserr_fail_path(e, fptr->pathv);
3368 }
3369 }
3370 io_set_read_length(str, n, shrinkable);
3371
3372 if (n == 0) {
3373 if (!ex) return Qnil;
3374 rb_eof_error();
3375 }
3376
3377 return str;
3378}
3379
3380/* :nodoc: */
3381static VALUE
3382io_write_nonblock(rb_execution_context_t *ec, VALUE io, VALUE str, VALUE ex)
3383{
3384 rb_io_t *fptr;
3385 long n;
3386
3387 if (!RB_TYPE_P(str, T_STRING))
3388 str = rb_obj_as_string(str);
3389 rb_bool_expected(ex, "exception");
3390
3391 io = GetWriteIO(io);
3392 GetOpenFile(io, fptr);
3394
3395 if (io_fflush(fptr) < 0)
3396 rb_sys_fail_on_write(fptr);
3397
3398 rb_io_set_nonblock(fptr);
3399 n = write(fptr->fd, RSTRING_PTR(str), RSTRING_LEN(str));
3400 RB_GC_GUARD(str);
3401
3402 if (n < 0) {
3403 int e = errno;
3404 if (io_again_p(e)) {
3405 if (!ex) {
3406 return sym_wait_writable;
3407 }
3408 else {
3409 rb_readwrite_syserr_fail(RB_IO_WAIT_WRITABLE, e, "write would block");
3410 }
3411 }
3412 rb_syserr_fail_path(e, fptr->pathv);
3413 }
3414
3415 return LONG2FIX(n);
3416}
3417
3418/*
3419 * call-seq:
3420 * read(maxlen = nil) -> string or nil
3421 * read(maxlen = nil, out_string) -> out_string or nil
3422 *
3423 * Reads bytes from the stream (in binary mode):
3424 *
3425 * - If +maxlen+ is +nil+, reads all bytes.
3426 * - Otherwise reads +maxlen+ bytes, if available.
3427 * - Otherwise reads all bytes.
3428 *
3429 * Returns a string (either a new string or the given +out_string+)
3430 * containing the bytes read.
3431 * The encoding of the string depends on both +maxLen+ and +out_string+:
3432 *
3433 * - +maxlen+ is +nil+: uses internal encoding of +self+
3434 * (regardless of whether +out_string+ was given).
3435 * - +maxlen+ not +nil+:
3436 *
3437 * - +out_string+ given: encoding of +out_string+ not modified.
3438 * - +out_string+ not given: ASCII-8BIT is used.
3439 *
3440 * <b>Without Argument +out_string+</b>
3441 *
3442 * When argument +out_string+ is omitted,
3443 * the returned value is a new string:
3444 *
3445 * f = File.new('t.txt')
3446 * f.read
3447 * # => "This is line one.\nThis is the second line.\nThis is the third line.\n"
3448 * f.rewind
3449 * f.read(40) # => "This is line one.\r\nThis is the second li"
3450 * f.read(40) # => "ne.\r\nThis is the third line.\r\n"
3451 * f.read(40) # => nil
3452 *
3453 * If +maxlen+ is zero, returns an empty string.
3454 *
3455 * <b> With Argument +out_string+</b>
3456 *
3457 * When argument +out_string+ is given,
3458 * the returned value is +out_string+, whose content is replaced:
3459 *
3460 * f = File.new('t.txt')
3461 * s = 'foo' # => "foo"
3462 * f.read(nil, s) # => "This is line one.\nThis is the second line.\nThis is the third line.\n"
3463 * s # => "This is line one.\nThis is the second line.\nThis is the third line.\n"
3464 * f.rewind
3465 * s = 'bar'
3466 * f.read(40, s) # => "This is line one.\r\nThis is the second li"
3467 * s # => "This is line one.\r\nThis is the second li"
3468 * s = 'baz'
3469 * f.read(40, s) # => "ne.\r\nThis is the third line.\r\n"
3470 * s # => "ne.\r\nThis is the third line.\r\n"
3471 * s = 'bat'
3472 * f.read(40, s) # => nil
3473 * s # => ""
3474 *
3475 * Note that this method behaves like the fread() function in C.
3476 * This means it retries to invoke read(2) system calls to read data
3477 * with the specified maxlen (or until EOF).
3478 *
3479 * This behavior is preserved even if the stream is in non-blocking mode.
3480 * (This method is non-blocking-flag insensitive as other methods.)
3481 *
3482 * If you need the behavior like a single read(2) system call,
3483 * consider #readpartial, #read_nonblock, and #sysread.
3484 *
3485 */
3486
3487static VALUE
3488io_read(int argc, VALUE *argv, VALUE io)
3489{
3490 rb_io_t *fptr;
3491 long n, len;
3492 VALUE length, str;
3493 int shrinkable;
3494#if RUBY_CRLF_ENVIRONMENT
3495 int previous_mode;
3496#endif
3497
3498 rb_scan_args(argc, argv, "02", &length, &str);
3499
3500 if (NIL_P(length)) {
3501 GetOpenFile(io, fptr);
3503 return read_all(fptr, remain_size(fptr), str);
3504 }
3505 len = NUM2LONG(length);
3506 if (len < 0) {
3507 rb_raise(rb_eArgError, "negative length %ld given", len);
3508 }
3509
3510 shrinkable = io_setstrbuf(&str,len);
3511
3512 GetOpenFile(io, fptr);
3514 if (len == 0) {
3515 io_set_read_length(str, 0, shrinkable);
3516 return str;
3517 }
3518
3519 READ_CHECK(fptr);
3520#if RUBY_CRLF_ENVIRONMENT
3521 previous_mode = set_binary_mode_with_seek_cur(fptr);
3522#endif
3523 n = io_fread(str, 0, len, fptr);
3524 io_set_read_length(str, n, shrinkable);
3525#if RUBY_CRLF_ENVIRONMENT
3526 if (previous_mode == O_TEXT) {
3527 setmode(fptr->fd, O_TEXT);
3528 }
3529#endif
3530 if (n == 0) return Qnil;
3531
3532 return str;
3533}
3534
3535static void
3536rscheck(const char *rsptr, long rslen, VALUE rs)
3537{
3538 if (!rs) return;
3539 if (RSTRING_PTR(rs) != rsptr && RSTRING_LEN(rs) != rslen)
3540 rb_raise(rb_eRuntimeError, "rs modified");
3541}
3542
3543static int
3544appendline(rb_io_t *fptr, int delim, VALUE *strp, long *lp)
3545{
3546 VALUE str = *strp;
3547 long limit = *lp;
3548
3549 if (NEED_READCONV(fptr)) {
3550 SET_BINARY_MODE(fptr);
3551 make_readconv(fptr, 0);
3552 do {
3553 const char *p, *e;
3554 int searchlen = READ_CHAR_PENDING_COUNT(fptr);
3555 if (searchlen) {
3556 p = READ_CHAR_PENDING_PTR(fptr);
3557 if (0 < limit && limit < searchlen)
3558 searchlen = (int)limit;
3559 e = memchr(p, delim, searchlen);
3560 if (e) {
3561 int len = (int)(e-p+1);
3562 if (NIL_P(str))
3563 *strp = str = rb_str_new(p, len);
3564 else
3565 rb_str_buf_cat(str, p, len);
3566 fptr->cbuf.off += len;
3567 fptr->cbuf.len -= len;
3568 limit -= len;
3569 *lp = limit;
3570 return delim;
3571 }
3572
3573 if (NIL_P(str))
3574 *strp = str = rb_str_new(p, searchlen);
3575 else
3576 rb_str_buf_cat(str, p, searchlen);
3577 fptr->cbuf.off += searchlen;
3578 fptr->cbuf.len -= searchlen;
3579 limit -= searchlen;
3580
3581 if (limit == 0) {
3582 *lp = limit;
3583 return (unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
3584 }
3585 }
3586 } while (more_char(fptr) != MORE_CHAR_FINISHED);
3587 clear_readconv(fptr);
3588 *lp = limit;
3589 return EOF;
3590 }
3591
3592 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3593 do {
3594 long pending = READ_DATA_PENDING_COUNT(fptr);
3595 if (pending > 0) {
3596 const char *p = READ_DATA_PENDING_PTR(fptr);
3597 const char *e;
3598 long last;
3599
3600 if (limit > 0 && pending > limit) pending = limit;
3601 e = memchr(p, delim, pending);
3602 if (e) pending = e - p + 1;
3603 if (!NIL_P(str)) {
3604 last = RSTRING_LEN(str);
3605 rb_str_resize(str, last + pending);
3606 }
3607 else {
3608 last = 0;
3609 *strp = str = rb_str_buf_new(pending);
3610 rb_str_set_len(str, pending);
3611 }
3612 read_buffered_data(RSTRING_PTR(str) + last, pending, fptr); /* must not fail */
3613 limit -= pending;
3614 *lp = limit;
3615 if (e) return delim;
3616 if (limit == 0)
3617 return (unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
3618 }
3619 READ_CHECK(fptr);
3620 } while (io_fillbuf(fptr) >= 0);
3621 *lp = limit;
3622 return EOF;
3623}
3624
3625static inline int
3626swallow(rb_io_t *fptr, int term)
3627{
3628 if (NEED_READCONV(fptr)) {
3629 rb_encoding *enc = io_read_encoding(fptr);
3630 int needconv = rb_enc_mbminlen(enc) != 1;
3631 SET_BINARY_MODE(fptr);
3632 make_readconv(fptr, 0);
3633 do {
3634 size_t cnt;
3635 while ((cnt = READ_CHAR_PENDING_COUNT(fptr)) > 0) {
3636 const char *p = READ_CHAR_PENDING_PTR(fptr);
3637 int i;
3638 if (!needconv) {
3639 if (*p != term) return TRUE;
3640 i = (int)cnt;
3641 while (--i && *++p == term);
3642 }
3643 else {
3644 const char *e = p + cnt;
3645 if (rb_enc_ascget(p, e, &i, enc) != term) return TRUE;
3646 while ((p += i) < e && rb_enc_ascget(p, e, &i, enc) == term);
3647 i = (int)(e - p);
3648 }
3649 io_shift_cbuf(fptr, (int)cnt - i, NULL);
3650 }
3651 } while (more_char(fptr) != MORE_CHAR_FINISHED);
3652 return FALSE;
3653 }
3654
3655 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3656 do {
3657 size_t cnt;
3658 while ((cnt = READ_DATA_PENDING_COUNT(fptr)) > 0) {
3659 char buf[1024];
3660 const char *p = READ_DATA_PENDING_PTR(fptr);
3661 int i;
3662 if (cnt > sizeof buf) cnt = sizeof buf;
3663 if (*p != term) return TRUE;
3664 i = (int)cnt;
3665 while (--i && *++p == term);
3666 if (!read_buffered_data(buf, cnt - i, fptr)) /* must not fail */
3667 rb_sys_fail_path(fptr->pathv);
3668 }
3669 READ_CHECK(fptr);
3670 } while (io_fillbuf(fptr) == 0);
3671 return FALSE;
3672}
3673
3674static VALUE
3675rb_io_getline_fast(rb_io_t *fptr, rb_encoding *enc, int chomp)
3676{
3677 VALUE str = Qnil;
3678 int len = 0;
3679 long pos = 0;
3680 int cr = 0;
3681
3682 do {
3683 int pending = READ_DATA_PENDING_COUNT(fptr);
3684
3685 if (pending > 0) {
3686 const char *p = READ_DATA_PENDING_PTR(fptr);
3687 const char *e;
3688 int chomplen = 0;
3689
3690 e = memchr(p, '\n', pending);
3691 if (e) {
3692 pending = (int)(e - p + 1);
3693 if (chomp) {
3694 chomplen = (pending > 1 && *(e-1) == '\r') + 1;
3695 }
3696 }
3697 if (NIL_P(str)) {
3698 str = rb_str_new(p, pending - chomplen);
3699 fptr->rbuf.off += pending;
3700 fptr->rbuf.len -= pending;
3701 }
3702 else {
3703 rb_str_resize(str, len + pending - chomplen);
3704 read_buffered_data(RSTRING_PTR(str)+len, pending - chomplen, fptr);
3705 fptr->rbuf.off += chomplen;
3706 fptr->rbuf.len -= chomplen;
3707 if (pending == 1 && chomplen == 1 && len > 0) {
3708 if (RSTRING_PTR(str)[len-1] == '\r') {
3709 rb_str_resize(str, --len);
3710 break;
3711 }
3712 }
3713 }
3714 len += pending - chomplen;
3715 if (cr != ENC_CODERANGE_BROKEN)
3716 pos += rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + len, enc, &cr);
3717 if (e) break;
3718 }
3719 READ_CHECK(fptr);
3720 } while (io_fillbuf(fptr) >= 0);
3721 if (NIL_P(str)) return Qnil;
3722
3723 str = io_enc_str(str, fptr);
3724 ENC_CODERANGE_SET(str, cr);
3725 fptr->lineno++;
3726
3727 return str;
3728}
3729
3731 VALUE io;
3732 VALUE rs;
3733 long limit;
3734 unsigned int chomp: 1;
3735};
3736
3737static void
3738extract_getline_opts(VALUE opts, struct getline_arg *args)
3739{
3740 int chomp = FALSE;
3741 if (!NIL_P(opts)) {
3742 static ID kwds[1];
3743 VALUE vchomp;
3744 if (!kwds[0]) {
3745 kwds[0] = rb_intern_const("chomp");
3746 }
3747 rb_get_kwargs(opts, kwds, 0, -2, &vchomp);
3748 chomp = (vchomp != Qundef) && RTEST(vchomp);
3749 }
3750 args->chomp = chomp;
3751}
3752
3753static void
3754extract_getline_args(int argc, VALUE *argv, struct getline_arg *args)
3755{
3756 VALUE rs = rb_rs, lim = Qnil;
3757
3758 if (argc == 1) {
3759 VALUE tmp = Qnil;
3760
3761 if (NIL_P(argv[0]) || !NIL_P(tmp = rb_check_string_type(argv[0]))) {
3762 rs = tmp;
3763 }
3764 else {
3765 lim = argv[0];
3766 }
3767 }
3768 else if (2 <= argc) {
3769 rs = argv[0], lim = argv[1];
3770 if (!NIL_P(rs))
3771 StringValue(rs);
3772 }
3773 args->rs = rs;
3774 args->limit = NIL_P(lim) ? -1L : NUM2LONG(lim);
3775}
3776
3777static void
3778check_getline_args(VALUE *rsp, long *limit, VALUE io)
3779{
3780 rb_io_t *fptr;
3781 VALUE rs = *rsp;
3782
3783 if (!NIL_P(rs)) {
3784 rb_encoding *enc_rs, *enc_io;
3785
3786 GetOpenFile(io, fptr);
3787 enc_rs = rb_enc_get(rs);
3788 enc_io = io_read_encoding(fptr);
3789 if (enc_io != enc_rs &&
3791 (RSTRING_LEN(rs) > 0 && !rb_enc_asciicompat(enc_io)))) {
3792 if (rs == rb_default_rs) {
3793 rs = rb_enc_str_new(0, 0, enc_io);
3794 rb_str_buf_cat_ascii(rs, "\n");
3795 *rsp = rs;
3796 }
3797 else {
3798 rb_raise(rb_eArgError, "encoding mismatch: %s IO with %s RS",
3799 rb_enc_name(enc_io),
3800 rb_enc_name(enc_rs));
3801 }
3802 }
3803 }
3804}
3805
3806static void
3807prepare_getline_args(int argc, VALUE *argv, struct getline_arg *args, VALUE io)
3808{
3809 VALUE opts;
3810 argc = rb_scan_args(argc, argv, "02:", NULL, NULL, &opts);
3811 extract_getline_args(argc, argv, args);
3812 extract_getline_opts(opts, args);
3813 check_getline_args(&args->rs, &args->limit, io);
3814}
3815
3816static VALUE
3817rb_io_getline_0(VALUE rs, long limit, int chomp, rb_io_t *fptr)
3818{
3819 VALUE str = Qnil;
3820 int nolimit = 0;
3821 rb_encoding *enc;
3822
3824 if (NIL_P(rs) && limit < 0) {
3825 str = read_all(fptr, 0, Qnil);
3826 if (RSTRING_LEN(str) == 0) return Qnil;
3827 if (chomp) rb_str_chomp_string(str, rb_default_rs);
3828 }
3829 else if (limit == 0) {
3830 return rb_enc_str_new(0, 0, io_read_encoding(fptr));
3831 }
3832 else if (rs == rb_default_rs && limit < 0 && !NEED_READCONV(fptr) &&
3833 rb_enc_asciicompat(enc = io_read_encoding(fptr))) {
3834 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3835 return rb_io_getline_fast(fptr, enc, chomp);
3836 }
3837 else {
3838 int c, newline = -1;
3839 const char *rsptr = 0;
3840 long rslen = 0;
3841 int rspara = 0;
3842 int extra_limit = 16;
3843 int chomp_cr = chomp;
3844
3845 SET_BINARY_MODE(fptr);
3846 enc = io_read_encoding(fptr);
3847
3848 if (!NIL_P(rs)) {
3849 rslen = RSTRING_LEN(rs);
3850 if (rslen == 0) {
3851 rsptr = "\n\n";
3852 rslen = 2;
3853 rspara = 1;
3854 swallow(fptr, '\n');
3855 rs = 0;
3856 if (!rb_enc_asciicompat(enc)) {
3857 rs = rb_usascii_str_new(rsptr, rslen);
3858 rs = rb_str_encode(rs, rb_enc_from_encoding(enc), 0, Qnil);
3859 OBJ_FREEZE(rs);
3860 rsptr = RSTRING_PTR(rs);
3861 rslen = RSTRING_LEN(rs);
3862 }
3863 }
3864 else {
3865 rsptr = RSTRING_PTR(rs);
3866 }
3867 newline = (unsigned char)rsptr[rslen - 1];
3868 chomp_cr = chomp && rslen == 1 && newline == '\n';
3869 }
3870
3871 /* MS - Optimization */
3872 while ((c = appendline(fptr, newline, &str, &limit)) != EOF) {
3873 const char *s, *p, *pp, *e;
3874
3875 if (c == newline) {
3876 if (RSTRING_LEN(str) < rslen) continue;
3877 s = RSTRING_PTR(str);
3878 e = RSTRING_END(str);
3879 p = e - rslen;
3880 pp = rb_enc_left_char_head(s, p, e, enc);
3881 if (pp != p) continue;
3882 if (!rspara) rscheck(rsptr, rslen, rs);
3883 if (memcmp(p, rsptr, rslen) == 0) {
3884 if (chomp) {
3885 if (chomp_cr && p > s && *(p-1) == '\r') --p;
3886 rb_str_set_len(str, p - s);
3887 }
3888 break;
3889 }
3890 }
3891 if (limit == 0) {
3892 s = RSTRING_PTR(str);
3893 p = RSTRING_END(str);
3894 pp = rb_enc_left_char_head(s, p-1, p, enc);
3895 if (extra_limit &&
3897 /* relax the limit while incomplete character.
3898 * extra_limit limits the relax length */
3899 limit = 1;
3900 extra_limit--;
3901 }
3902 else {
3903 nolimit = 1;
3904 break;
3905 }
3906 }
3907 }
3908
3909 if (rspara && c != EOF)
3910 swallow(fptr, '\n');
3911 if (!NIL_P(str))
3912 str = io_enc_str(str, fptr);
3913 }
3914
3915 if (!NIL_P(str) && !nolimit) {
3916 fptr->lineno++;
3917 }
3918
3919 return str;
3920}
3921
3922static VALUE
3923rb_io_getline_1(VALUE rs, long limit, int chomp, VALUE io)
3924{
3925 rb_io_t *fptr;
3926 int old_lineno, new_lineno;
3927 VALUE str;
3928
3929 GetOpenFile(io, fptr);
3930 old_lineno = fptr->lineno;
3931 str = rb_io_getline_0(rs, limit, chomp, fptr);
3932 if (!NIL_P(str) && (new_lineno = fptr->lineno) != old_lineno) {
3933 if (io == ARGF.current_file) {
3934 ARGF.lineno += new_lineno - old_lineno;
3935 ARGF.last_lineno = ARGF.lineno;
3936 }
3937 else {
3938 ARGF.last_lineno = new_lineno;
3939 }
3940 }
3941
3942 return str;
3943}
3944
3945static VALUE
3946rb_io_getline(int argc, VALUE *argv, VALUE io)
3947{
3948 struct getline_arg args;
3949
3950 prepare_getline_args(argc, argv, &args, io);
3951 return rb_io_getline_1(args.rs, args.limit, args.chomp, io);
3952}
3953
3954VALUE
3955rb_io_gets(VALUE io)
3956{
3957 return rb_io_getline_1(rb_default_rs, -1, FALSE, io);
3958}
3959
3960VALUE
3961rb_io_gets_internal(VALUE io)
3962{
3963 rb_io_t *fptr;
3964 GetOpenFile(io, fptr);
3965 return rb_io_getline_0(rb_default_rs, -1, FALSE, fptr);
3966}
3967
3968/*
3969 * call-seq:
3970 * gets(sep = $/, **getline_opts) -> string or nil
3971 * gets(limit, **getline_opts) -> string or nil
3972 * gets(sep, limit, **getline_opts) -> string or nil
3973 *
3974 * Reads and returns data from the stream;
3975 * assigns the return value to <tt>$_</tt>.
3976 *
3977 * With no arguments given, returns the next line
3978 * as determined by line separator <tt>$/</tt>, or +nil+ if none:
3979 *
3980 * f = File.open('t.txt')
3981 * f.gets # => "This is line one.\n"
3982 * $_ # => "This is line one.\n"
3983 * f.gets # => "This is the second line.\n"
3984 * f.gets # => "This is the third line.\n"
3985 * f.gets # => nil
3986 *
3987 * With string argument +sep+ given, but not argument +limit+,
3988 * returns the next line as determined by line separator +sep+,
3989 * or +nil+ if none:
3990 *
3991 * f = File.open('t.txt')
3992 * f.gets(' is') # => "This is"
3993 * f.gets(' is') # => " line one.\nThis is"
3994 * f.gets(' is') # => " the second line.\nThis is"
3995 * f.gets(' is') # => " the third line.\n"
3996 * f.gets(' is') # => nil
3997 *
3998 * Note two special values for +sep+:
3999 *
4000 * - +nil+: The entire stream is read and returned.
4001 * - <tt>''</tt> (empty string): The next "paragraph" is read and returned,
4002 * the paragraph separator being two successive line separators.
4003 *
4004 * With integer argument +limit+ given,
4005 * returns up to <tt>limit+1</tt> bytes:
4006 *
4007 * # Text with 1-byte characters.
4008 * File.open('t.txt') {|f| f.gets(1) } # => "T"
4009 * File.open('t.txt') {|f| f.gets(2) } # => "Th"
4010 * File.open('t.txt') {|f| f.gets(3) } # => "Thi"
4011 * File.open('t.txt') {|f| f.gets(4) } # => "This"
4012 * # No more than one line.
4013 * File.open('t.txt') {|f| f.gets(17) } # => "This is line one."
4014 * File.open('t.txt') {|f| f.gets(18) } # => "This is line one.\n"
4015 * File.open('t.txt') {|f| f.gets(19) } # => "This is line one.\n"
4016 *
4017 * # Text with 2-byte characters, which will not be split.
4018 * File.open('t.rus') {|f| f.gets(1).size } # => 1
4019 * File.open('t.rus') {|f| f.gets(2).size } # => 1
4020 * File.open('t.rus') {|f| f.gets(3).size } # => 2
4021 * File.open('t.rus') {|f| f.gets(4).size } # => 2
4022 *
4023 * With arguments +sep+ and +limit+,
4024 * combines the two behaviors above:
4025 *
4026 * - Returns the next line as determined by line separator +sep+,
4027 * or +nil+ if none.
4028 * - But returns no more than <tt>limit+1</tt> bytes.
4029 *
4030 * For all forms above, trailing optional keyword arguments may be given;
4031 * see {Getline Options}[#class-IO-label-Getline+Options]:
4032 *
4033 * f = File.open('t.txt')
4034 * # Chomp the lines.
4035 * f.gets(chomp: true) # => "This is line one."
4036 * f.gets(chomp: true) # => "This is the second line."
4037 * f.gets(chomp: true) # => "This is the third line."
4038 * f.gets(chomp: true) # => nil
4039 *
4040 */
4041
4042static VALUE
4043rb_io_gets_m(int argc, VALUE *argv, VALUE io)
4044{
4045 VALUE str;
4046
4047 str = rb_io_getline(argc, argv, io);
4048 rb_lastline_set(str);
4049
4050 return str;
4051}
4052
4053/*
4054 * call-seq:
4055 * ios.lineno -> integer
4056 *
4057 * Returns the current line number in <em>ios</em>. The stream must be
4058 * opened for reading. #lineno counts the number of times #gets is called
4059 * rather than the number of newlines encountered. The two values will
4060 * differ if #gets is called with a separator other than newline.
4061 *
4062 * Methods that use <code>$/</code> like #each, #lines and #readline will
4063 * also increment #lineno.
4064 *
4065 * See also the <code>$.</code> variable.
4066 *
4067 * f = File.new("testfile")
4068 * f.lineno #=> 0
4069 * f.gets #=> "This is line one\n"
4070 * f.lineno #=> 1
4071 * f.gets #=> "This is line two\n"
4072 * f.lineno #=> 2
4073 */
4074
4075static VALUE
4076rb_io_lineno(VALUE io)
4077{
4078 rb_io_t *fptr;
4079
4080 GetOpenFile(io, fptr);
4082 return INT2NUM(fptr->lineno);
4083}
4084
4085/*
4086 * call-seq:
4087 * ios.lineno = integer -> integer
4088 *
4089 * Manually sets the current line number to the given value.
4090 * <code>$.</code> is updated only on the next read.
4091 *
4092 * f = File.new("testfile")
4093 * f.gets #=> "This is line one\n"
4094 * $. #=> 1
4095 * f.lineno = 1000
4096 * f.lineno #=> 1000
4097 * $. #=> 1 # lineno of last read
4098 * f.gets #=> "This is line two\n"
4099 * $. #=> 1001 # lineno of last read
4100 */
4101
4102static VALUE
4103rb_io_set_lineno(VALUE io, VALUE lineno)
4104{
4105 rb_io_t *fptr;
4106
4107 GetOpenFile(io, fptr);
4109 fptr->lineno = NUM2INT(lineno);
4110 return lineno;
4111}
4112
4113/*
4114 * call-seq:
4115 * ios.readline(sep=$/ [, getline_args]) -> string
4116 * ios.readline(limit [, getline_args]) -> string
4117 * ios.readline(sep, limit [, getline_args]) -> string
4118 *
4119 * Reads a line as with IO#gets, but raises an EOFError on end of file.
4120 */
4121
4122static VALUE
4123rb_io_readline(int argc, VALUE *argv, VALUE io)
4124{
4125 VALUE line = rb_io_gets_m(argc, argv, io);
4126
4127 if (NIL_P(line)) {
4128 rb_eof_error();
4129 }
4130 return line;
4131}
4132
4133static VALUE io_readlines(const struct getline_arg *arg, VALUE io);
4134
4135/*
4136 * call-seq:
4137 * ios.readlines(sep=$/ [, getline_args]) -> array
4138 * ios.readlines(limit [, getline_args]) -> array
4139 * ios.readlines(sep, limit [, getline_args]) -> array
4140 *
4141 * Reads all of the lines in <em>ios</em>, and returns them in
4142 * an array. Lines are separated by the optional <i>sep</i>. If
4143 * <i>sep</i> is +nil+, the rest of the stream is returned
4144 * as a single record.
4145 * If the first argument is an integer, or an
4146 * optional second argument is given, the returning string would not be
4147 * longer than the given value in bytes. The stream must be opened for
4148 * reading or an IOError will be raised.
4149 *
4150 * f = File.new("testfile")
4151 * f.readlines[0] #=> "This is line one\n"
4152 *
4153 * f = File.new("testfile", chomp: true)
4154 * f.readlines[0] #=> "This is line one"
4155 *
4156 * See IO.readlines for details about getline_args.
4157 */
4158
4159static VALUE
4160rb_io_readlines(int argc, VALUE *argv, VALUE io)
4161{
4162 struct getline_arg args;
4163
4164 prepare_getline_args(argc, argv, &args, io);
4165 return io_readlines(&args, io);
4166}
4167
4168static VALUE
4169io_readlines(const struct getline_arg *arg, VALUE io)
4170{
4171 VALUE line, ary;
4172
4173 if (arg->limit == 0)
4174 rb_raise(rb_eArgError, "invalid limit: 0 for readlines");
4175 ary = rb_ary_new();
4176 while (!NIL_P(line = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, io))) {
4177 rb_ary_push(ary, line);
4178 }
4179 return ary;
4180}
4181
4182/*
4183 * call-seq:
4184 * ios.each(sep=$/ [, getline_args]) {|line| block } -> ios
4185 * ios.each(limit [, getline_args]) {|line| block } -> ios
4186 * ios.each(sep, limit [, getline_args]) {|line| block } -> ios
4187 * ios.each(...) -> an_enumerator
4188 *
4189 * ios.each_line(sep=$/ [, getline_args]) {|line| block } -> ios
4190 * ios.each_line(limit [, getline_args]) {|line| block } -> ios
4191 * ios.each_line(sep, limit [, getline_args]) {|line| block } -> ios
4192 * ios.each_line(...) -> an_enumerator
4193 *
4194 * Executes the block for every line in <em>ios</em>, where lines are
4195 * separated by <i>sep</i>. <em>ios</em> must be opened for
4196 * reading or an IOError will be raised.
4197 *
4198 * If no block is given, an enumerator is returned instead.
4199 *
4200 * f = File.new("testfile")
4201 * f.each {|line| puts "#{f.lineno}: #{line}" }
4202 *
4203 * <em>produces:</em>
4204 *
4205 * 1: This is line one
4206 * 2: This is line two
4207 * 3: This is line three
4208 * 4: And so on...
4209 *
4210 * See IO.readlines for details about getline_args.
4211 */
4212
4213static VALUE
4214rb_io_each_line(int argc, VALUE *argv, VALUE io)
4215{
4216 VALUE str;
4217 struct getline_arg args;
4218
4219 RETURN_ENUMERATOR(io, argc, argv);
4220 prepare_getline_args(argc, argv, &args, io);
4221 if (args.limit == 0)
4222 rb_raise(rb_eArgError, "invalid limit: 0 for each_line");
4223 while (!NIL_P(str = rb_io_getline_1(args.rs, args.limit, args.chomp, io))) {
4224 rb_yield(str);
4225 }
4226 return io;
4227}
4228
4229/*
4230 * call-seq:
4231 * ios.each_byte {|byte| block } -> ios
4232 * ios.each_byte -> an_enumerator
4233 *
4234 * Calls the given block once for each byte (0..255) in <em>ios</em>,
4235 * passing the byte as an argument. The stream must be opened for
4236 * reading or an IOError will be raised.
4237 *
4238 * If no block is given, an enumerator is returned instead.
4239 *
4240 * f = File.new("testfile")
4241 * checksum = 0
4242 * f.each_byte {|x| checksum ^= x } #=> #<File:testfile>
4243 * checksum #=> 12
4244 */
4245
4246static VALUE
4247rb_io_each_byte(VALUE io)
4248{
4249 rb_io_t *fptr;
4250
4251 RETURN_ENUMERATOR(io, 0, 0);
4252 GetOpenFile(io, fptr);
4253
4254 do {
4255 while (fptr->rbuf.len > 0) {
4256 char *p = fptr->rbuf.ptr + fptr->rbuf.off++;
4257 fptr->rbuf.len--;
4258 rb_yield(INT2FIX(*p & 0xff));
4260 errno = 0;
4261 }
4262 READ_CHECK(fptr);
4263 } while (io_fillbuf(fptr) >= 0);
4264 return io;
4265}
4266
4267static VALUE
4268io_getc(rb_io_t *fptr, rb_encoding *enc)
4269{
4270 int r, n, cr = 0;
4271 VALUE str;
4272
4273 if (NEED_READCONV(fptr)) {
4274 rb_encoding *read_enc = io_read_encoding(fptr);
4275
4276 str = Qnil;
4277 SET_BINARY_MODE(fptr);
4278 make_readconv(fptr, 0);
4279
4280 while (1) {
4281 if (fptr->cbuf.len) {
4282 r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4283 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4284 read_enc);
4285 if (!MBCLEN_NEEDMORE_P(r))
4286 break;
4287 if (fptr->cbuf.len == fptr->cbuf.capa) {
4288 rb_raise(rb_eIOError, "too long character");
4289 }
4290 }
4291
4292 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4293 if (fptr->cbuf.len == 0) {
4294 clear_readconv(fptr);
4295 return Qnil;
4296 }
4297 /* return an unit of an incomplete character just before EOF */
4298 str = rb_enc_str_new(fptr->cbuf.ptr+fptr->cbuf.off, 1, read_enc);
4299 fptr->cbuf.off += 1;
4300 fptr->cbuf.len -= 1;
4301 if (fptr->cbuf.len == 0) clear_readconv(fptr);
4303 return str;
4304 }
4305 }
4306 if (MBCLEN_INVALID_P(r)) {
4307 r = rb_enc_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4308 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4309 read_enc);
4310 io_shift_cbuf(fptr, r, &str);
4312 }
4313 else {
4314 io_shift_cbuf(fptr, MBCLEN_CHARFOUND_LEN(r), &str);
4316 if (MBCLEN_CHARFOUND_LEN(r) == 1 && rb_enc_asciicompat(read_enc) &&
4317 ISASCII(RSTRING_PTR(str)[0])) {
4318 cr = ENC_CODERANGE_7BIT;
4319 }
4320 }
4321 str = io_enc_str(str, fptr);
4322 ENC_CODERANGE_SET(str, cr);
4323 return str;
4324 }
4325
4326 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4327 if (io_fillbuf(fptr) < 0) {
4328 return Qnil;
4329 }
4330 if (rb_enc_asciicompat(enc) && ISASCII(fptr->rbuf.ptr[fptr->rbuf.off])) {
4331 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, 1);
4332 fptr->rbuf.off += 1;
4333 fptr->rbuf.len -= 1;
4334 cr = ENC_CODERANGE_7BIT;
4335 }
4336 else {
4337 r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off, fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4338 if (MBCLEN_CHARFOUND_P(r) &&
4339 (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
4340 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, n);
4341 fptr->rbuf.off += n;
4342 fptr->rbuf.len -= n;
4344 }
4345 else if (MBCLEN_NEEDMORE_P(r)) {
4346 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, fptr->rbuf.len);
4347 fptr->rbuf.len = 0;
4348 getc_needmore:
4349 if (io_fillbuf(fptr) != -1) {
4350 rb_str_cat(str, fptr->rbuf.ptr+fptr->rbuf.off, 1);
4351 fptr->rbuf.off++;
4352 fptr->rbuf.len--;
4353 r = rb_enc_precise_mbclen(RSTRING_PTR(str), RSTRING_PTR(str)+RSTRING_LEN(str), enc);
4354 if (MBCLEN_NEEDMORE_P(r)) {
4355 goto getc_needmore;
4356 }
4357 else if (MBCLEN_CHARFOUND_P(r)) {
4359 }
4360 }
4361 }
4362 else {
4363 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, 1);
4364 fptr->rbuf.off++;
4365 fptr->rbuf.len--;
4366 }
4367 }
4368 if (!cr) cr = ENC_CODERANGE_BROKEN;
4369 str = io_enc_str(str, fptr);
4370 ENC_CODERANGE_SET(str, cr);
4371 return str;
4372}
4373
4374/*
4375 * call-seq:
4376 * ios.each_char {|c| block } -> ios
4377 * ios.each_char -> an_enumerator
4378 *
4379 * Calls the given block once for each character in <em>ios</em>,
4380 * passing the character as an argument. The stream must be opened for
4381 * reading or an IOError will be raised.
4382 *
4383 * If no block is given, an enumerator is returned instead.
4384 *
4385 * f = File.new("testfile")
4386 * f.each_char {|c| print c, ' ' } #=> #<File:testfile>
4387 */
4388
4389static VALUE
4390rb_io_each_char(VALUE io)
4391{
4392 rb_io_t *fptr;
4393 rb_encoding *enc;
4394 VALUE c;
4395
4396 RETURN_ENUMERATOR(io, 0, 0);
4397 GetOpenFile(io, fptr);
4399
4400 enc = io_input_encoding(fptr);
4401 READ_CHECK(fptr);
4402 while (!NIL_P(c = io_getc(fptr, enc))) {
4403 rb_yield(c);
4404 }
4405 return io;
4406}
4407
4408/*
4409 * call-seq:
4410 * ios.each_codepoint {|c| block } -> ios
4411 * ios.each_codepoint -> an_enumerator
4412 *
4413 * Passes the Integer ordinal of each character in <i>ios</i>,
4414 * passing the codepoint as an argument. The stream must be opened for
4415 * reading or an IOError will be raised.
4416 *
4417 * If no block is given, an enumerator is returned instead.
4418 *
4419 */
4420
4421static VALUE
4422rb_io_each_codepoint(VALUE io)
4423{
4424 rb_io_t *fptr;
4425 rb_encoding *enc;
4426 unsigned int c;
4427 int r, n;
4428
4429 RETURN_ENUMERATOR(io, 0, 0);
4430 GetOpenFile(io, fptr);
4432
4433 READ_CHECK(fptr);
4434 if (NEED_READCONV(fptr)) {
4435 SET_BINARY_MODE(fptr);
4436 r = 1; /* no invalid char yet */
4437 for (;;) {
4438 make_readconv(fptr, 0);
4439 for (;;) {
4440 if (fptr->cbuf.len) {
4441 if (fptr->encs.enc)
4442 r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4443 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4444 fptr->encs.enc);
4445 else
4446 r = ONIGENC_CONSTRUCT_MBCLEN_CHARFOUND(1);
4447 if (!MBCLEN_NEEDMORE_P(r))
4448 break;
4449 if (fptr->cbuf.len == fptr->cbuf.capa) {
4450 rb_raise(rb_eIOError, "too long character");
4451 }
4452 }
4453 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4454 clear_readconv(fptr);
4455 if (!MBCLEN_CHARFOUND_P(r)) {
4456 enc = fptr->encs.enc;
4457 goto invalid;
4458 }
4459 return io;
4460 }
4461 }
4462 if (MBCLEN_INVALID_P(r)) {
4463 enc = fptr->encs.enc;
4464 goto invalid;
4465 }
4466 n = MBCLEN_CHARFOUND_LEN(r);
4467 if (fptr->encs.enc) {
4468 c = rb_enc_codepoint(fptr->cbuf.ptr+fptr->cbuf.off,
4469 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4470 fptr->encs.enc);
4471 }
4472 else {
4473 c = (unsigned char)fptr->cbuf.ptr[fptr->cbuf.off];
4474 }
4475 fptr->cbuf.off += n;
4476 fptr->cbuf.len -= n;
4477 rb_yield(UINT2NUM(c));
4479 }
4480 }
4481 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4482 enc = io_input_encoding(fptr);
4483 while (io_fillbuf(fptr) >= 0) {
4484 r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off,
4485 fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4486 if (MBCLEN_CHARFOUND_P(r) &&
4487 (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
4488 c = rb_enc_codepoint(fptr->rbuf.ptr+fptr->rbuf.off,
4489 fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4490 fptr->rbuf.off += n;
4491 fptr->rbuf.len -= n;
4492 rb_yield(UINT2NUM(c));
4493 }
4494 else if (MBCLEN_INVALID_P(r)) {
4495 goto invalid;
4496 }
4497 else if (MBCLEN_NEEDMORE_P(r)) {
4498 char cbuf[8], *p = cbuf;
4499 int more = MBCLEN_NEEDMORE_LEN(r);
4500 if (more > numberof(cbuf)) goto invalid;
4501 more += n = fptr->rbuf.len;
4502 if (more > numberof(cbuf)) goto invalid;
4503 while ((n = (int)read_buffered_data(p, more, fptr)) > 0 &&
4504 (p += n, (more -= n) > 0)) {
4505 if (io_fillbuf(fptr) < 0) goto invalid;
4506 if ((n = fptr->rbuf.len) > more) n = more;
4507 }
4508 r = rb_enc_precise_mbclen(cbuf, p, enc);
4509 if (!MBCLEN_CHARFOUND_P(r)) goto invalid;
4510 c = rb_enc_codepoint(cbuf, p, enc);
4511 rb_yield(UINT2NUM(c));
4512 }
4513 else {
4514 continue;
4515 }
4517 }
4518 return io;
4519
4520 invalid:
4521 rb_raise(rb_eArgError, "invalid byte sequence in %s", rb_enc_name(enc));
4523}
4524
4525/*
4526 * call-seq:
4527 * ios.getc -> string or nil
4528 *
4529 * Reads a one-character string from <em>ios</em>. Returns
4530 * +nil+ if called at end of file.
4531 *
4532 * f = File.new("testfile")
4533 * f.getc #=> "h"
4534 * f.getc #=> "e"
4535 */
4536
4537static VALUE
4538rb_io_getc(VALUE io)
4539{
4540 rb_io_t *fptr;
4541 rb_encoding *enc;
4542
4543 GetOpenFile(io, fptr);
4545
4546 enc = io_input_encoding(fptr);
4547 READ_CHECK(fptr);
4548 return io_getc(fptr, enc);
4549}
4550
4551/*
4552 * call-seq:
4553 * ios.readchar -> string
4554 *
4555 * Reads a one-character string from <em>ios</em>. Raises an
4556 * EOFError on end of file.
4557 *
4558 * f = File.new("testfile")
4559 * f.readchar #=> "h"
4560 * f.readchar #=> "e"
4561 */
4562
4563static VALUE
4564rb_io_readchar(VALUE io)
4565{
4566 VALUE c = rb_io_getc(io);
4567
4568 if (NIL_P(c)) {
4569 rb_eof_error();
4570 }
4571 return c;
4572}
4573
4574/*
4575 * call-seq:
4576 * ios.getbyte -> integer or nil
4577 *
4578 * Gets the next 8-bit byte (0..255) from <em>ios</em>. Returns
4579 * +nil+ if called at end of file.
4580 *
4581 * f = File.new("testfile")
4582 * f.getbyte #=> 84
4583 * f.getbyte #=> 104
4584 */
4585
4586VALUE
4588{
4589 rb_io_t *fptr;
4590 int c;
4591
4592 GetOpenFile(io, fptr);
4594 READ_CHECK(fptr);
4595 VALUE r_stdout = rb_ractor_stdout();
4596 if (fptr->fd == 0 && (fptr->mode & FMODE_TTY) && RB_TYPE_P(r_stdout, T_FILE)) {
4597 rb_io_t *ofp;
4598 GetOpenFile(r_stdout, ofp);
4599 if (ofp->mode & FMODE_TTY) {
4600 rb_io_flush(r_stdout);
4601 }
4602 }
4603 if (io_fillbuf(fptr) < 0) {
4604 return Qnil;
4605 }
4606 fptr->rbuf.off++;
4607 fptr->rbuf.len--;
4608 c = (unsigned char)fptr->rbuf.ptr[fptr->rbuf.off-1];
4609 return INT2FIX(c & 0xff);
4610}
4611
4612/*
4613 * call-seq:
4614 * ios.readbyte -> integer
4615 *
4616 * Reads a byte as with IO#getbyte, but raises an EOFError on end of
4617 * file.
4618 */
4619
4620static VALUE
4621rb_io_readbyte(VALUE io)
4622{
4623 VALUE c = rb_io_getbyte(io);
4624
4625 if (NIL_P(c)) {
4626 rb_eof_error();
4627 }
4628 return c;
4629}
4630
4631/*
4632 * call-seq:
4633 * ios.ungetbyte(string) -> nil
4634 * ios.ungetbyte(integer) -> nil
4635 *
4636 * Pushes back bytes (passed as a parameter) onto <em>ios</em>,
4637 * such that a subsequent buffered read will return it.
4638 * It is only guaranteed to support a single byte, and only if ungetbyte
4639 * or ungetc has not already been called on <em>ios</em> since the previous
4640 * read of at least a single byte from <em>ios</em>.
4641 * However, it can support additional bytes if there is space in the
4642 * internal buffer to allow for it.
4643 *
4644 * f = File.new("testfile") #=> #<File:testfile>
4645 * b = f.getbyte #=> 0x38
4646 * f.ungetbyte(b) #=> nil
4647 * f.getbyte #=> 0x38
4648 *
4649 * If given an integer, only uses the lower 8 bits of the integer as the byte
4650 * to push.
4651 *
4652 * f = File.new("testfile") #=> #<File:testfile>
4653 * f.ungetbyte(0x102) #=> nil
4654 * f.getbyte #=> 0x2
4655 *
4656 * Calling this method prepends to the existing buffer, even if the method
4657 * has already been called previously:
4658 *
4659 * f = File.new("testfile") #=> #<File:testfile>
4660 * f.ungetbyte("ab") #=> nil
4661 * f.ungetbyte("cd") #=> nil
4662 * f.read(5) #=> "cdab8"
4663 *
4664 * Has no effect with unbuffered reads (such as IO#sysread).
4665 */
4666
4667VALUE
4668rb_io_ungetbyte(VALUE io, VALUE b)
4669{
4670 rb_io_t *fptr;
4671
4672 GetOpenFile(io, fptr);
4674 switch (TYPE(b)) {
4675 case T_NIL:
4676 return Qnil;
4677 case T_FIXNUM:
4678 case T_BIGNUM: ;
4679 VALUE v = rb_int_modulo(b, INT2FIX(256));
4680 unsigned char c = NUM2INT(v) & 0xFF;
4681 b = rb_str_new((const char *)&c, 1);
4682 break;
4683 default:
4684 SafeStringValue(b);
4685 }
4686 io_ungetbyte(b, fptr);
4687 return Qnil;
4688}
4689
4690/*
4691 * call-seq:
4692 * ios.ungetc(integer) -> nil
4693 * ios.ungetc(string) -> nil
4694 *
4695 * Pushes back characters (passed as a parameter) onto <em>ios</em>,
4696 * such that a subsequent buffered read will return it.
4697 * It is only guaranteed to support a single byte, and only if ungetbyte
4698 * or ungetc has not already been called on <em>ios</em> since the previous
4699 * read of at least a single byte from <em>ios</em>.
4700 * However, it can support additional bytes if there is space in the
4701 * internal buffer to allow for it.
4702 *
4703 * f = File.new("testfile") #=> #<File:testfile>
4704 * c = f.getc #=> "8"
4705 * f.ungetc(c) #=> nil
4706 * f.getc #=> "8"
4707 *
4708 * If given an integer, the integer must represent a valid codepoint in the
4709 * external encoding of <em>ios</em>.
4710 *
4711 * Calling this method prepends to the existing buffer, even if the method
4712 * has already been called previously:
4713 *
4714 * f = File.new("testfile") #=> #<File:testfile>
4715 * f.ungetc("ab") #=> nil
4716 * f.ungetc("cd") #=> nil
4717 * f.read(5) #=> "cdab8"
4718 *
4719 * Has no effect with unbuffered reads (such as IO#sysread).
4720 */
4721
4722VALUE
4723rb_io_ungetc(VALUE io, VALUE c)
4724{
4725 rb_io_t *fptr;
4726 long len;
4727
4728 GetOpenFile(io, fptr);
4730 if (FIXNUM_P(c)) {
4731 c = rb_enc_uint_chr(FIX2UINT(c), io_read_encoding(fptr));
4732 }
4733 else if (RB_BIGNUM_TYPE_P(c)) {
4734 c = rb_enc_uint_chr(NUM2UINT(c), io_read_encoding(fptr));
4735 }
4736 else {
4737 SafeStringValue(c);
4738 }
4739 if (NEED_READCONV(fptr)) {
4740 SET_BINARY_MODE(fptr);
4741 len = RSTRING_LEN(c);
4742#if SIZEOF_LONG > SIZEOF_INT
4743 if (len > INT_MAX)
4744 rb_raise(rb_eIOError, "ungetc failed");
4745#endif
4746 make_readconv(fptr, (int)len);
4747 if (fptr->cbuf.capa - fptr->cbuf.len < len)
4748 rb_raise(rb_eIOError, "ungetc failed");
4749 if (fptr->cbuf.off < len) {
4750 MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.capa-fptr->cbuf.len,
4751 fptr->cbuf.ptr+fptr->cbuf.off,
4752 char, fptr->cbuf.len);
4753 fptr->cbuf.off = fptr->cbuf.capa-fptr->cbuf.len;
4754 }
4755 fptr->cbuf.off -= (int)len;
4756 fptr->cbuf.len += (int)len;
4757 MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.off, RSTRING_PTR(c), char, len);
4758 }
4759 else {
4760 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4761 io_ungetbyte(c, fptr);
4762 }
4763 return Qnil;
4764}
4765
4766/*
4767 * call-seq:
4768 * ios.isatty -> true or false
4769 * ios.tty? -> true or false
4770 *
4771 * Returns <code>true</code> if <em>ios</em> is associated with a
4772 * terminal device (tty), <code>false</code> otherwise.
4773 *
4774 * File.new("testfile").isatty #=> false
4775 * File.new("/dev/tty").isatty #=> true
4776 */
4777
4778static VALUE
4779rb_io_isatty(VALUE io)
4780{
4781 rb_io_t *fptr;
4782
4783 GetOpenFile(io, fptr);
4784 return RBOOL(isatty(fptr->fd) != 0);
4785}
4786
4787#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
4788/*
4789 * call-seq:
4790 * ios.close_on_exec? -> true or false
4791 *
4792 * Returns <code>true</code> if <em>ios</em> will be closed on exec.
4793 *
4794 * f = open("/dev/null")
4795 * f.close_on_exec? #=> false
4796 * f.close_on_exec = true
4797 * f.close_on_exec? #=> true
4798 * f.close_on_exec = false
4799 * f.close_on_exec? #=> false
4800 */
4801
4802static VALUE
4803rb_io_close_on_exec_p(VALUE io)
4804{
4805 rb_io_t *fptr;
4806 VALUE write_io;
4807 int fd, ret;
4808
4809 write_io = GetWriteIO(io);
4810 if (io != write_io) {
4811 GetOpenFile(write_io, fptr);
4812 if (fptr && 0 <= (fd = fptr->fd)) {
4813 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
4814 if (!(ret & FD_CLOEXEC)) return Qfalse;
4815 }
4816 }
4817
4818 GetOpenFile(io, fptr);
4819 if (fptr && 0 <= (fd = fptr->fd)) {
4820 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
4821 if (!(ret & FD_CLOEXEC)) return Qfalse;
4822 }
4823 return Qtrue;
4824}
4825#else
4826#define rb_io_close_on_exec_p rb_f_notimplement
4827#endif
4828
4829#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
4830/*
4831 * call-seq:
4832 * ios.close_on_exec = bool -> true or false
4833 *
4834 * Sets a close-on-exec flag.
4835 *
4836 * f = open("/dev/null")
4837 * f.close_on_exec = true
4838 * system("cat", "/proc/self/fd/#{f.fileno}") # cat: /proc/self/fd/3: No such file or directory
4839 * f.closed? #=> false
4840 *
4841 * Ruby sets close-on-exec flags of all file descriptors by default
4842 * since Ruby 2.0.0.
4843 * So you don't need to set by yourself.
4844 * Also, unsetting a close-on-exec flag can cause file descriptor leak
4845 * if another thread use fork() and exec() (via system() method for example).
4846 * If you really needs file descriptor inheritance to child process,
4847 * use spawn()'s argument such as fd=>fd.
4848 */
4849
4850static VALUE
4851rb_io_set_close_on_exec(VALUE io, VALUE arg)
4852{
4853 int flag = RTEST(arg) ? FD_CLOEXEC : 0;
4854 rb_io_t *fptr;
4855 VALUE write_io;
4856 int fd, ret;
4857
4858 write_io = GetWriteIO(io);
4859 if (io != write_io) {
4860 GetOpenFile(write_io, fptr);
4861 if (fptr && 0 <= (fd = fptr->fd)) {
4862 if ((ret = fcntl(fptr->fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
4863 if ((ret & FD_CLOEXEC) != flag) {
4864 ret = (ret & ~FD_CLOEXEC) | flag;
4865 ret = fcntl(fd, F_SETFD, ret);
4866 if (ret != 0) rb_sys_fail_path(fptr->pathv);
4867 }
4868 }
4869
4870 }
4871
4872 GetOpenFile(io, fptr);
4873 if (fptr && 0 <= (fd = fptr->fd)) {
4874 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
4875 if ((ret & FD_CLOEXEC) != flag) {
4876 ret = (ret & ~FD_CLOEXEC) | flag;
4877 ret = fcntl(fd, F_SETFD, ret);
4878 if (ret != 0) rb_sys_fail_path(fptr->pathv);
4879 }
4880 }
4881 return Qnil;
4882}
4883#else
4884#define rb_io_set_close_on_exec rb_f_notimplement
4885#endif
4886
4887#define IS_PREP_STDIO(f) ((f)->mode & FMODE_PREP)
4888#define PREP_STDIO_NAME(f) (RSTRING_PTR((f)->pathv))
4889
4890static VALUE
4891finish_writeconv(rb_io_t *fptr, int noalloc)
4892{
4893 unsigned char *ds, *dp, *de;
4894 rb_econv_result_t res;
4895
4896 if (!fptr->wbuf.ptr) {
4897 unsigned char buf[1024];
4898 long r;
4899
4901 while (res == econv_destination_buffer_full) {
4902 ds = dp = buf;
4903 de = buf + sizeof(buf);
4904 res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
4905 while (dp-ds) {
4906 retry:
4907 r = rb_write_internal(fptr, ds, dp-ds);
4908 if (r == dp-ds)
4909 break;
4910 if (0 <= r) {
4911 ds += r;
4912 }
4913 if (rb_io_maybe_wait_writable(errno, fptr->self, Qnil)) {
4914 if (fptr->fd < 0)
4915 return noalloc ? Qtrue : rb_exc_new3(rb_eIOError, rb_str_new_cstr(closed_stream));
4916 goto retry;
4917 }
4918 return noalloc ? Qtrue : INT2NUM(errno);
4919 }
4920 if (res == econv_invalid_byte_sequence ||
4921 res == econv_incomplete_input ||
4923 return noalloc ? Qtrue : rb_econv_make_exception(fptr->writeconv);
4924 }
4925 }
4926
4927 return Qnil;
4928 }
4929
4931 while (res == econv_destination_buffer_full) {
4932 if (fptr->wbuf.len == fptr->wbuf.capa) {
4933 if (io_fflush(fptr) < 0)
4934 return noalloc ? Qtrue : INT2NUM(errno);
4935 }
4936
4937 ds = dp = (unsigned char *)fptr->wbuf.ptr + fptr->wbuf.off + fptr->wbuf.len;
4938 de = (unsigned char *)fptr->wbuf.ptr + fptr->wbuf.capa;
4939 res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
4940 fptr->wbuf.len += (int)(dp - ds);
4941 if (res == econv_invalid_byte_sequence ||
4942 res == econv_incomplete_input ||
4944 return noalloc ? Qtrue : rb_econv_make_exception(fptr->writeconv);
4945 }
4946 }
4947 return Qnil;
4948}
4949
4951 rb_io_t *fptr;
4952 int noalloc;
4953};
4954
4955static VALUE
4956finish_writeconv_sync(VALUE arg)
4957{
4958 struct finish_writeconv_arg *p = (struct finish_writeconv_arg *)arg;
4959 return finish_writeconv(p->fptr, p->noalloc);
4960}
4961
4962static void*
4963nogvl_close(void *ptr)
4964{
4965 int *fd = ptr;
4966
4967 return (void*)(intptr_t)close(*fd);
4968}
4969
4970static int
4971maygvl_close(int fd, int keepgvl)
4972{
4973 if (keepgvl)
4974 return close(fd);
4975
4976 /*
4977 * close() may block for certain file types (NFS, SO_LINGER sockets,
4978 * inotify), so let other threads run.
4979 */
4980 return (int)(intptr_t)rb_thread_call_without_gvl(nogvl_close, &fd, RUBY_UBF_IO, 0);
4981}
4982
4983static void*
4984nogvl_fclose(void *ptr)
4985{
4986 FILE *file = ptr;
4987
4988 return (void*)(intptr_t)fclose(file);
4989}
4990
4991static int
4992maygvl_fclose(FILE *file, int keepgvl)
4993{
4994 if (keepgvl)
4995 return fclose(file);
4996
4997 return (int)(intptr_t)rb_thread_call_without_gvl(nogvl_fclose, file, RUBY_UBF_IO, 0);
4998}
4999
5000static void free_io_buffer(rb_io_buffer_t *buf);
5001static void clear_codeconv(rb_io_t *fptr);
5002
5003static void
5004fptr_finalize_flush(rb_io_t *fptr, int noraise, int keepgvl,
5005 struct list_head *busy)
5006{
5007 VALUE err = Qnil;
5008 int fd = fptr->fd;
5009 FILE *stdio_file = fptr->stdio_file;
5010 int mode = fptr->mode;
5011
5012 if (fptr->writeconv) {
5013 if (fptr->write_lock && !noraise) {
5014 struct finish_writeconv_arg arg;
5015 arg.fptr = fptr;
5016 arg.noalloc = noraise;
5017 err = rb_mutex_synchronize(fptr->write_lock, finish_writeconv_sync, (VALUE)&arg);
5018 }
5019 else {
5020 err = finish_writeconv(fptr, noraise);
5021 }
5022 }
5023 if (fptr->wbuf.len) {
5024 if (noraise) {
5025 io_flush_buffer_sync(fptr);
5026 }
5027 else {
5028 if (io_fflush(fptr) < 0 && NIL_P(err))
5029 err = INT2NUM(errno);
5030 }
5031 }
5032
5033 int done = 0;
5034
5035 if (IS_PREP_STDIO(fptr) || fd <= 2) {
5036 // Need to keep FILE objects of stdin, stdout and stderr, so we are done:
5037 done = 1;
5038 }
5039
5040 fptr->fd = -1;
5041 fptr->stdio_file = 0;
5043
5044 // Ensure waiting_fd users do not hit EBADF.
5045 if (busy) {
5046 // Wait for them to exit before we call close().
5047 do rb_thread_schedule(); while (!list_empty(busy));
5048 }
5049
5050 // Disable for now.
5051 // if (!done && fd >= 0) {
5052 // VALUE scheduler = rb_fiber_scheduler_current();
5053 // if (scheduler != Qnil) {
5054 // VALUE result = rb_fiber_scheduler_io_close(scheduler, fptr->self);
5055 // if (result != Qundef) done = 1;
5056 // }
5057 // }
5058
5059 if (!done && stdio_file) {
5060 // stdio_file is deallocated anyway even if fclose failed.
5061 if ((maygvl_fclose(stdio_file, noraise) < 0) && NIL_P(err))
5062 if (!noraise) err = INT2NUM(errno);
5063
5064 done = 1;
5065 }
5066
5067 if (!done && fd >= 0) {
5068 // fptr->fd may be closed even if close fails. POSIX doesn't specify it.
5069 // We assumes it is closed.
5070
5071 keepgvl |= !(mode & FMODE_WRITABLE);
5072 keepgvl |= noraise;
5073 if ((maygvl_close(fd, keepgvl) < 0) && NIL_P(err))
5074 if (!noraise) err = INT2NUM(errno);
5075
5076 done = 1;
5077 }
5078
5079 if (!NIL_P(err) && !noraise) {
5080 if (RB_INTEGER_TYPE_P(err))
5081 rb_syserr_fail_path(NUM2INT(err), fptr->pathv);
5082 else
5083 rb_exc_raise(err);
5084 }
5085}
5086
5087static void
5088fptr_finalize(rb_io_t *fptr, int noraise)
5089{
5090 fptr_finalize_flush(fptr, noraise, FALSE, 0);
5091 free_io_buffer(&fptr->rbuf);
5092 free_io_buffer(&fptr->wbuf);
5093 clear_codeconv(fptr);
5094}
5095
5096static void
5097rb_io_fptr_cleanup(rb_io_t *fptr, int noraise)
5098{
5099 if (fptr->finalize) {
5100 (*fptr->finalize)(fptr, noraise);
5101 }
5102 else {
5103 fptr_finalize(fptr, noraise);
5104 }
5105}
5106
5107static void
5108free_io_buffer(rb_io_buffer_t *buf)
5109{
5110 if (buf->ptr) {
5111 ruby_sized_xfree(buf->ptr, (size_t)buf->capa);
5112 buf->ptr = NULL;
5113 }
5114}
5115
5116static void
5117clear_readconv(rb_io_t *fptr)
5118{
5119 if (fptr->readconv) {
5120 rb_econv_close(fptr->readconv);
5121 fptr->readconv = NULL;
5122 }
5123 free_io_buffer(&fptr->cbuf);
5124}
5125
5126static void
5127clear_writeconv(rb_io_t *fptr)
5128{
5129 if (fptr->writeconv) {
5131 fptr->writeconv = NULL;
5132 }
5133 fptr->writeconv_initialized = 0;
5134}
5135
5136static void
5137clear_codeconv(rb_io_t *fptr)
5138{
5139 clear_readconv(fptr);
5140 clear_writeconv(fptr);
5141}
5142
5143void
5144rb_io_fptr_finalize_internal(void *ptr)
5145{
5146 rb_io_t *fptr = ptr;
5147
5148 if (!ptr) return;
5149 fptr->pathv = Qnil;
5150 if (0 <= fptr->fd)
5151 rb_io_fptr_cleanup(fptr, TRUE);
5152 fptr->write_lock = 0;
5153 free_io_buffer(&fptr->rbuf);
5154 free_io_buffer(&fptr->wbuf);
5155 clear_codeconv(fptr);
5156 free(fptr);
5157}
5158
5159#undef rb_io_fptr_finalize
5160int
5162{
5163 if (!fptr) {
5164 return 0;
5165 }
5166 else {
5167 rb_io_fptr_finalize_internal(fptr);
5168 return 1;
5169 }
5170}
5171#define rb_io_fptr_finalize(fptr) rb_io_fptr_finalize_internal(fptr)
5172
5173RUBY_FUNC_EXPORTED size_t
5174rb_io_memsize(const rb_io_t *fptr)
5175{
5176 size_t size = sizeof(rb_io_t);
5177 size += fptr->rbuf.capa;
5178 size += fptr->wbuf.capa;
5179 size += fptr->cbuf.capa;
5180 if (fptr->readconv) size += rb_econv_memsize(fptr->readconv);
5181 if (fptr->writeconv) size += rb_econv_memsize(fptr->writeconv);
5182 return size;
5183}
5184
5185#ifdef _WIN32
5186/* keep GVL while closing to prevent crash on Windows */
5187# define KEEPGVL TRUE
5188#else
5189# define KEEPGVL FALSE
5190#endif
5191
5192int rb_notify_fd_close(int fd, struct list_head *);
5193static rb_io_t *
5194io_close_fptr(VALUE io)
5195{
5196 rb_io_t *fptr;
5197 VALUE write_io;
5198 rb_io_t *write_fptr;
5199 struct list_head busy;
5200
5201 list_head_init(&busy);
5202 write_io = GetWriteIO(io);
5203 if (io != write_io) {
5204 write_fptr = RFILE(write_io)->fptr;
5205 if (write_fptr && 0 <= write_fptr->fd) {
5206 rb_io_fptr_cleanup(write_fptr, TRUE);
5207 }
5208 }
5209
5210 fptr = RFILE(io)->fptr;
5211 if (!fptr) return 0;
5212 if (fptr->fd < 0) return 0;
5213
5214 if (rb_notify_fd_close(fptr->fd, &busy)) {
5215 /* calls close(fptr->fd): */
5216 fptr_finalize_flush(fptr, FALSE, KEEPGVL, &busy);
5217 }
5218 rb_io_fptr_cleanup(fptr, FALSE);
5219 return fptr;
5220}
5221
5222static void
5223fptr_waitpid(rb_io_t *fptr, int nohang)
5224{
5225 int status;
5226 if (fptr->pid) {
5227 rb_last_status_clear();
5228 rb_waitpid(fptr->pid, &status, nohang ? WNOHANG : 0);
5229 fptr->pid = 0;
5230 }
5231}
5232
5233VALUE
5235{
5236 rb_io_t *fptr = io_close_fptr(io);
5237 if (fptr) fptr_waitpid(fptr, 0);
5238 return Qnil;
5239}
5240
5241/*
5242 * call-seq:
5243 * ios.close -> nil
5244 *
5245 * Closes <em>ios</em> and flushes any pending writes to the operating
5246 * system. The stream is unavailable for any further data operations;
5247 * an IOError is raised if such an attempt is made. I/O streams are
5248 * automatically closed when they are claimed by the garbage collector.
5249 *
5250 * If <em>ios</em> is opened by IO.popen, #close sets
5251 * <code>$?</code>.
5252 *
5253 * Calling this method on closed IO object is just ignored since Ruby 2.3.
5254 */
5255
5256static VALUE
5257rb_io_close_m(VALUE io)
5258{
5259 rb_io_t *fptr = rb_io_get_fptr(io);
5260 if (fptr->fd < 0) {
5261 return Qnil;
5262 }
5263 rb_io_close(io);
5264 return Qnil;
5265}
5266
5267static VALUE
5268io_call_close(VALUE io)
5269{
5270 rb_check_funcall(io, rb_intern("close"), 0, 0);
5271 return io;
5272}
5273
5274static VALUE
5275ignore_closed_stream(VALUE io, VALUE exc)
5276{
5277 enum {mesg_len = sizeof(closed_stream)-1};
5278 VALUE mesg = rb_attr_get(exc, idMesg);
5279 if (!RB_TYPE_P(mesg, T_STRING) ||
5280 RSTRING_LEN(mesg) != mesg_len ||
5281 memcmp(RSTRING_PTR(mesg), closed_stream, mesg_len)) {
5282 rb_exc_raise(exc);
5283 }
5284 return io;
5285}
5286
5287static VALUE
5288io_close(VALUE io)
5289{
5290 VALUE closed = rb_check_funcall(io, rb_intern("closed?"), 0, 0);
5291 if (closed != Qundef && RTEST(closed)) return io;
5292 rb_rescue2(io_call_close, io, ignore_closed_stream, io,
5293 rb_eIOError, (VALUE)0);
5294 return io;
5295}
5296
5297/*
5298 * call-seq:
5299 * ios.closed? -> true or false
5300 *
5301 * Returns <code>true</code> if <em>ios</em> is completely closed (for
5302 * duplex streams, both reader and writer), <code>false</code>
5303 * otherwise.
5304 *
5305 * f = File.new("testfile")
5306 * f.close #=> nil
5307 * f.closed? #=> true
5308 * f = IO.popen("/bin/sh","r+")
5309 * f.close_write #=> nil
5310 * f.closed? #=> false
5311 * f.close_read #=> nil
5312 * f.closed? #=> true
5313 */
5314
5315
5316static VALUE
5317rb_io_closed(VALUE io)
5318{
5319 rb_io_t *fptr;
5320 VALUE write_io;
5321 rb_io_t *write_fptr;
5322
5323 write_io = GetWriteIO(io);
5324 if (io != write_io) {
5325 write_fptr = RFILE(write_io)->fptr;
5326 if (write_fptr && 0 <= write_fptr->fd) {
5327 return Qfalse;
5328 }
5329 }
5330
5331 fptr = rb_io_get_fptr(io);
5332 return RBOOL(0 > fptr->fd);
5333}
5334
5335/*
5336 * call-seq:
5337 * ios.close_read -> nil
5338 *
5339 * Closes the read end of a duplex I/O stream (i.e., one that contains
5340 * both a read and a write stream, such as a pipe). Will raise an
5341 * IOError if the stream is not duplexed.
5342 *
5343 * f = IO.popen("/bin/sh","r+")
5344 * f.close_read
5345 * f.readlines
5346 *
5347 * <em>produces:</em>
5348 *
5349 * prog.rb:3:in `readlines': not opened for reading (IOError)
5350 * from prog.rb:3
5351 *
5352 * Calling this method on closed IO object is just ignored since Ruby 2.3.
5353 */
5354
5355static VALUE
5356rb_io_close_read(VALUE io)
5357{
5358 rb_io_t *fptr;
5359 VALUE write_io;
5360
5361 fptr = rb_io_get_fptr(rb_io_taint_check(io));
5362 if (fptr->fd < 0) return Qnil;
5363 if (is_socket(fptr->fd, fptr->pathv)) {
5364#ifndef SHUT_RD
5365# define SHUT_RD 0
5366#endif
5367 if (shutdown(fptr->fd, SHUT_RD) < 0)
5368 rb_sys_fail_path(fptr->pathv);
5369 fptr->mode &= ~FMODE_READABLE;
5370 if (!(fptr->mode & FMODE_WRITABLE))
5371 return rb_io_close(io);
5372 return Qnil;
5373 }
5374
5375 write_io = GetWriteIO(io);
5376 if (io != write_io) {
5377 rb_io_t *wfptr;
5378 wfptr = rb_io_get_fptr(rb_io_taint_check(write_io));
5379 wfptr->pid = fptr->pid;
5380 fptr->pid = 0;
5381 RFILE(io)->fptr = wfptr;
5382 /* bind to write_io temporarily to get rid of memory/fd leak */
5383 fptr->tied_io_for_writing = 0;
5384 RFILE(write_io)->fptr = fptr;
5385 rb_io_fptr_cleanup(fptr, FALSE);
5386 /* should not finalize fptr because another thread may be reading it */
5387 return Qnil;
5388 }
5389
5390 if ((fptr->mode & (FMODE_DUPLEX|FMODE_WRITABLE)) == FMODE_WRITABLE) {
5391 rb_raise(rb_eIOError, "closing non-duplex IO for reading");
5392 }
5393 return rb_io_close(io);
5394}
5395
5396/*
5397 * call-seq:
5398 * ios.close_write -> nil
5399 *
5400 * Closes the write end of a duplex I/O stream (i.e., one that contains
5401 * both a read and a write stream, such as a pipe). Will raise an
5402 * IOError if the stream is not duplexed.
5403 *
5404 * f = IO.popen("/bin/sh","r+")
5405 * f.close_write
5406 * f.print "nowhere"
5407 *
5408 * <em>produces:</em>
5409 *
5410 * prog.rb:3:in `write': not opened for writing (IOError)
5411 * from prog.rb:3:in `print'
5412 * from prog.rb:3
5413 *
5414 * Calling this method on closed IO object is just ignored since Ruby 2.3.
5415 */
5416
5417static VALUE
5418rb_io_close_write(VALUE io)
5419{
5420 rb_io_t *fptr;
5421 VALUE write_io;
5422
5423 write_io = GetWriteIO(io);
5424 fptr = rb_io_get_fptr(rb_io_taint_check(write_io));
5425 if (fptr->fd < 0) return Qnil;
5426 if (is_socket(fptr->fd, fptr->pathv)) {
5427#ifndef SHUT_WR
5428# define SHUT_WR 1
5429#endif
5430 if (shutdown(fptr->fd, SHUT_WR) < 0)
5431 rb_sys_fail_path(fptr->pathv);
5432 fptr->mode &= ~FMODE_WRITABLE;
5433 if (!(fptr->mode & FMODE_READABLE))
5434 return rb_io_close(write_io);
5435 return Qnil;
5436 }
5437
5438 if ((fptr->mode & (FMODE_DUPLEX|FMODE_READABLE)) == FMODE_READABLE) {
5439 rb_raise(rb_eIOError, "closing non-duplex IO for writing");
5440 }
5441
5442 if (io != write_io) {
5443 fptr = rb_io_get_fptr(rb_io_taint_check(io));
5444 fptr->tied_io_for_writing = 0;
5445 }
5446 rb_io_close(write_io);
5447 return Qnil;
5448}
5449
5450/*
5451 * call-seq:
5452 * ios.sysseek(offset, whence=IO::SEEK_SET) -> integer
5453 *
5454 * Seeks to a given <i>offset</i> in the stream according to the value
5455 * of <i>whence</i> (see IO#seek for values of <i>whence</i>). Returns
5456 * the new offset into the file.
5457 *
5458 * f = File.new("testfile")
5459 * f.sysseek(-13, IO::SEEK_END) #=> 53
5460 * f.sysread(10) #=> "And so on."
5461 */
5462
5463static VALUE
5464rb_io_sysseek(int argc, VALUE *argv, VALUE io)
5465{
5466 VALUE offset, ptrname;
5467 int whence = SEEK_SET;
5468 rb_io_t *fptr;
5469 off_t pos;
5470
5471 if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
5472 whence = interpret_seek_whence(ptrname);
5473 }
5474 pos = NUM2OFFT(offset);
5475 GetOpenFile(io, fptr);
5476 if ((fptr->mode & FMODE_READABLE) &&
5477 (READ_DATA_BUFFERED(fptr) || READ_CHAR_PENDING(fptr))) {
5478 rb_raise(rb_eIOError, "sysseek for buffered IO");
5479 }
5480 if ((fptr->mode & FMODE_WRITABLE) && fptr->wbuf.len) {
5481 rb_warn("sysseek for buffered IO");
5482 }
5483 errno = 0;
5484 pos = lseek(fptr->fd, pos, whence);
5485 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
5486
5487 return OFFT2NUM(pos);
5488}
5489
5490/*
5491 * call-seq:
5492 * ios.syswrite(string) -> integer
5493 *
5494 * Writes the given string to <em>ios</em> using a low-level write.
5495 * Returns the number of bytes written. Do not mix with other methods
5496 * that write to <em>ios</em> or you may get unpredictable results.
5497 * Raises SystemCallError on error.
5498 *
5499 * f = File.new("out", "w")
5500 * f.syswrite("ABCDEF") #=> 6
5501 */
5502
5503static VALUE
5504rb_io_syswrite(VALUE io, VALUE str)
5505{
5506 VALUE tmp;
5507 rb_io_t *fptr;
5508 long n, len;
5509 const char *ptr;
5510
5511 if (!RB_TYPE_P(str, T_STRING))
5512 str = rb_obj_as_string(str);
5513
5514 io = GetWriteIO(io);
5515 GetOpenFile(io, fptr);
5517
5518 if (fptr->wbuf.len) {
5519 rb_warn("syswrite for buffered IO");
5520 }
5521
5522 tmp = rb_str_tmp_frozen_acquire(str);
5523 RSTRING_GETMEM(tmp, ptr, len);
5524 n = rb_write_internal(fptr, ptr, len);
5525 if (n < 0) rb_sys_fail_path(fptr->pathv);
5526 rb_str_tmp_frozen_release(str, tmp);
5527
5528 return LONG2FIX(n);
5529}
5530
5531/*
5532 * call-seq:
5533 * ios.sysread(maxlen[, outbuf]) -> string
5534 *
5535 * Reads <i>maxlen</i> bytes from <em>ios</em> using a low-level
5536 * read and returns them as a string. Do not mix with other methods
5537 * that read from <em>ios</em> or you may get unpredictable results.
5538 *
5539 * If the optional _outbuf_ argument is present,
5540 * it must reference a String, which will receive the data.
5541 * The _outbuf_ will contain only the received data after the method call
5542 * even if it is not empty at the beginning.
5543 *
5544 * Raises SystemCallError on error and EOFError at end of file.
5545 *
5546 * f = File.new("testfile")
5547 * f.sysread(16) #=> "This is line one"
5548 */
5549
5550static VALUE
5551rb_io_sysread(int argc, VALUE *argv, VALUE io)
5552{
5553 VALUE len, str;
5554 rb_io_t *fptr;
5555 long n, ilen;
5556 struct io_internal_read_struct iis;
5557 int shrinkable;
5558
5559 rb_scan_args(argc, argv, "11", &len, &str);
5560 ilen = NUM2LONG(len);
5561
5562 shrinkable = io_setstrbuf(&str, ilen);
5563 if (ilen == 0) return str;
5564
5565 GetOpenFile(io, fptr);
5567
5568 if (READ_DATA_BUFFERED(fptr)) {
5569 rb_raise(rb_eIOError, "sysread for buffered IO");
5570 }
5571
5572 rb_io_check_closed(fptr);
5573
5574 io_setstrbuf(&str, ilen);
5575 iis.th = rb_thread_current();
5576 iis.fptr = fptr;
5577 iis.nonblock = 0;
5578 iis.buf = RSTRING_PTR(str);
5579 iis.capa = ilen;
5580 n = read_internal_locktmp(str, &iis);
5581
5582 if (n < 0) {
5583 rb_sys_fail_path(fptr->pathv);
5584 }
5585
5586 io_set_read_length(str, n, shrinkable);
5587
5588 if (n == 0 && ilen > 0) {
5589 rb_eof_error();
5590 }
5591
5592 return str;
5593}
5594
5595#if defined(HAVE_PREAD) || defined(HAVE_PWRITE)
5596struct prdwr_internal_arg {
5597 int fd;
5598 void *buf;
5599 size_t count;
5600 off_t offset;
5601};
5602#endif /* HAVE_PREAD || HAVE_PWRITE */
5603
5604#if defined(HAVE_PREAD)
5605static VALUE
5606internal_pread_func(void *arg)
5607{
5608 struct prdwr_internal_arg *p = arg;
5609 return (VALUE)pread(p->fd, p->buf, p->count, p->offset);
5610}
5611
5612static VALUE
5613pread_internal_call(VALUE arg)
5614{
5615 struct prdwr_internal_arg *p = (struct prdwr_internal_arg *)arg;
5616 return rb_thread_io_blocking_region(internal_pread_func, p, p->fd);
5617}
5618
5619/*
5620 * call-seq:
5621 * ios.pread(maxlen, offset[, outbuf]) -> string
5622 *
5623 * Reads <i>maxlen</i> bytes from <em>ios</em> using the pread system call
5624 * and returns them as a string without modifying the underlying
5625 * descriptor offset. This is advantageous compared to combining IO#seek
5626 * and IO#read in that it is atomic, allowing multiple threads/process to
5627 * share the same IO object for reading the file at various locations.
5628 * This bypasses any userspace buffering of the IO layer.
5629 * If the optional <i>outbuf</i> argument is present, it must
5630 * reference a String, which will receive the data.
5631 * Raises SystemCallError on error, EOFError at end of file and
5632 * NotImplementedError if platform does not implement the system call.
5633 *
5634 * File.write("testfile", "This is line one\nThis is line two\n")
5635 * File.open("testfile") do |f|
5636 * p f.read # => "This is line one\nThis is line two\n"
5637 * p f.pread(12, 0) # => "This is line"
5638 * p f.pread(9, 8) # => "line one\n"
5639 * end
5640 */
5641static VALUE
5642rb_io_pread(int argc, VALUE *argv, VALUE io)
5643{
5644 VALUE len, offset, str;
5645 rb_io_t *fptr;
5646 ssize_t n;
5647 struct prdwr_internal_arg arg;
5648 int shrinkable;
5649
5650 rb_scan_args(argc, argv, "21", &len, &offset, &str);
5651 arg.count = NUM2SIZET(len);
5652 arg.offset = NUM2OFFT(offset);
5653
5654 shrinkable = io_setstrbuf(&str, (long)arg.count);
5655 if (arg.count == 0) return str;
5656 arg.buf = RSTRING_PTR(str);
5657
5658 GetOpenFile(io, fptr);
5660
5661 arg.fd = fptr->fd;
5662 rb_io_check_closed(fptr);
5663
5664 rb_str_locktmp(str);
5665 n = (ssize_t)rb_ensure(pread_internal_call, (VALUE)&arg, rb_str_unlocktmp, str);
5666
5667 if (n < 0) {
5668 rb_sys_fail_path(fptr->pathv);
5669 }
5670 io_set_read_length(str, n, shrinkable);
5671 if (n == 0 && arg.count > 0) {
5672 rb_eof_error();
5673 }
5674
5675 return str;
5676}
5677#else
5678# define rb_io_pread rb_f_notimplement
5679#endif /* HAVE_PREAD */
5680
5681#if defined(HAVE_PWRITE)
5682static VALUE
5683internal_pwrite_func(void *ptr)
5684{
5685 struct prdwr_internal_arg *arg = ptr;
5686
5687 return (VALUE)pwrite(arg->fd, arg->buf, arg->count, arg->offset);
5688}
5689
5690/*
5691 * call-seq:
5692 * ios.pwrite(string, offset) -> integer
5693 *
5694 * Writes the given string to <em>ios</em> at <i>offset</i> using pwrite()
5695 * system call. This is advantageous to combining IO#seek and IO#write
5696 * in that it is atomic, allowing multiple threads/process to share the
5697 * same IO object for reading the file at various locations.
5698 * This bypasses any userspace buffering of the IO layer.
5699 * Returns the number of bytes written.
5700 * Raises SystemCallError on error and NotImplementedError
5701 * if platform does not implement the system call.
5702 *
5703 * File.open("out", "w") do |f|
5704 * f.pwrite("ABCDEF", 3) #=> 6
5705 * end
5706 *
5707 * File.read("out") #=> "\u0000\u0000\u0000ABCDEF"
5708 */
5709static VALUE
5710rb_io_pwrite(VALUE io, VALUE str, VALUE offset)
5711{
5712 rb_io_t *fptr;
5713 ssize_t n;
5714 struct prdwr_internal_arg arg;
5715 VALUE tmp;
5716
5717 if (!RB_TYPE_P(str, T_STRING))
5718 str = rb_obj_as_string(str);
5719
5720 arg.offset = NUM2OFFT(offset);
5721
5722 io = GetWriteIO(io);
5723 GetOpenFile(io, fptr);
5725 arg.fd = fptr->fd;
5726
5727 tmp = rb_str_tmp_frozen_acquire(str);
5728 arg.buf = RSTRING_PTR(tmp);
5729 arg.count = (size_t)RSTRING_LEN(tmp);
5730
5731 n = (ssize_t)rb_thread_io_blocking_region(internal_pwrite_func, &arg, fptr->fd);
5732 if (n < 0) rb_sys_fail_path(fptr->pathv);
5733 rb_str_tmp_frozen_release(str, tmp);
5734
5735 return SSIZET2NUM(n);
5736}
5737#else
5738# define rb_io_pwrite rb_f_notimplement
5739#endif /* HAVE_PWRITE */
5740
5741VALUE
5743{
5744 rb_io_t *fptr;
5745
5746 GetOpenFile(io, fptr);
5747 if (fptr->readconv)
5749 if (fptr->writeconv)
5751 fptr->mode |= FMODE_BINMODE;
5752 fptr->mode &= ~FMODE_TEXTMODE;
5753 fptr->writeconv_pre_ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
5754#ifdef O_BINARY
5755 if (!fptr->readconv) {
5756 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
5757 }
5758 else {
5759 setmode(fptr->fd, O_BINARY);
5760 }
5761#endif
5762 return io;
5763}
5764
5765static void
5766io_ascii8bit_binmode(rb_io_t *fptr)
5767{
5768 if (fptr->readconv) {
5769 rb_econv_close(fptr->readconv);
5770 fptr->readconv = NULL;
5771 }
5772 if (fptr->writeconv) {
5774 fptr->writeconv = NULL;
5775 }
5776 fptr->mode |= FMODE_BINMODE;
5777 fptr->mode &= ~FMODE_TEXTMODE;
5778 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
5779
5780 fptr->encs.enc = rb_ascii8bit_encoding();
5781 fptr->encs.enc2 = NULL;
5782 fptr->encs.ecflags = 0;
5783 fptr->encs.ecopts = Qnil;
5784 clear_codeconv(fptr);
5785}
5786
5787VALUE
5789{
5790 rb_io_t *fptr;
5791
5792 GetOpenFile(io, fptr);
5793 io_ascii8bit_binmode(fptr);
5794
5795 return io;
5796}
5797
5798/*
5799 * call-seq:
5800 * ios.binmode -> ios
5801 *
5802 * Puts <em>ios</em> into binary mode.
5803 * Once a stream is in binary mode, it cannot be reset to nonbinary mode.
5804 *
5805 * - newline conversion disabled
5806 * - encoding conversion disabled
5807 * - content is treated as ASCII-8BIT
5808 */
5809
5810static VALUE
5811rb_io_binmode_m(VALUE io)
5812{
5813 VALUE write_io;
5814
5816
5817 write_io = GetWriteIO(io);
5818 if (write_io != io)
5819 rb_io_ascii8bit_binmode(write_io);
5820 return io;
5821}
5822
5823/*
5824 * call-seq:
5825 * ios.binmode? -> true or false
5826 *
5827 * Returns <code>true</code> if <em>ios</em> is binmode.
5828 */
5829static VALUE
5830rb_io_binmode_p(VALUE io)
5831{
5832 rb_io_t *fptr;
5833 GetOpenFile(io, fptr);
5834 return RBOOL(fptr->mode & FMODE_BINMODE);
5835}
5836
5837static const char*
5838rb_io_fmode_modestr(int fmode)
5839{
5840 if (fmode & FMODE_APPEND) {
5841 if ((fmode & FMODE_READWRITE) == FMODE_READWRITE) {
5842 return MODE_BTMODE("a+", "ab+", "at+");
5843 }
5844 return MODE_BTMODE("a", "ab", "at");
5845 }
5846 switch (fmode & FMODE_READWRITE) {
5847 default:
5848 rb_raise(rb_eArgError, "invalid access fmode 0x%x", fmode);
5849 case FMODE_READABLE:
5850 return MODE_BTMODE("r", "rb", "rt");
5851 case FMODE_WRITABLE:
5852 return MODE_BTXMODE("w", "wb", "wt", "wx", "wbx", "wtx");
5853 case FMODE_READWRITE:
5854 if (fmode & FMODE_CREATE) {
5855 return MODE_BTXMODE("w+", "wb+", "wt+", "w+x", "wb+x", "wt+x");
5856 }
5857 return MODE_BTMODE("r+", "rb+", "rt+");
5858 }
5859}
5860
5861static const char bom_prefix[] = "bom|";
5862static const char utf_prefix[] = "utf-";
5863enum {bom_prefix_len = (int)sizeof(bom_prefix) - 1};
5864enum {utf_prefix_len = (int)sizeof(utf_prefix) - 1};
5865
5866static int
5867io_encname_bom_p(const char *name, long len)
5868{
5869 return len > bom_prefix_len && STRNCASECMP(name, bom_prefix, bom_prefix_len) == 0;
5870}
5871
5872int
5873rb_io_modestr_fmode(const char *modestr)
5874{
5875 int fmode = 0;
5876 const char *m = modestr, *p = NULL;
5877
5878 switch (*m++) {
5879 case 'r':
5880 fmode |= FMODE_READABLE;
5881 break;
5882 case 'w':
5884 break;
5885 case 'a':
5887 break;
5888 default:
5889 goto error;
5890 }
5891
5892 while (*m) {
5893 switch (*m++) {
5894 case 'b':
5895 fmode |= FMODE_BINMODE;
5896 break;
5897 case 't':
5898 fmode |= FMODE_TEXTMODE;
5899 break;
5900 case '+':
5901 fmode |= FMODE_READWRITE;
5902 break;
5903 case 'x':
5904 if (modestr[0] != 'w')
5905 goto error;
5906 fmode |= FMODE_EXCL;
5907 break;
5908 default:
5909 goto error;
5910 case ':':
5911 p = strchr(m, ':');
5912 if (io_encname_bom_p(m, p ? (long)(p - m) : (long)strlen(m)))
5913 fmode |= FMODE_SETENC_BY_BOM;
5914 goto finished;
5915 }
5916 }
5917
5918 finished:
5919 if ((fmode & FMODE_BINMODE) && (fmode & FMODE_TEXTMODE))
5920 goto error;
5921
5922 return fmode;
5923
5924 error:
5925 rb_raise(rb_eArgError, "invalid access mode %s", modestr);
5927}
5928
5929int
5930rb_io_oflags_fmode(int oflags)
5931{
5932 int fmode = 0;
5933
5934 switch (oflags & O_ACCMODE) {
5935 case O_RDONLY:
5936 fmode = FMODE_READABLE;
5937 break;
5938 case O_WRONLY:
5939 fmode = FMODE_WRITABLE;
5940 break;
5941 case O_RDWR:
5942 fmode = FMODE_READWRITE;
5943 break;
5944 }
5945
5946 if (oflags & O_APPEND) {
5947 fmode |= FMODE_APPEND;
5948 }
5949 if (oflags & O_TRUNC) {
5950 fmode |= FMODE_TRUNC;
5951 }
5952 if (oflags & O_CREAT) {
5953 fmode |= FMODE_CREATE;
5954 }
5955 if (oflags & O_EXCL) {
5956 fmode |= FMODE_EXCL;
5957 }
5958#ifdef O_BINARY
5959 if (oflags & O_BINARY) {
5960 fmode |= FMODE_BINMODE;
5961 }
5962#endif
5963
5964 return fmode;
5965}
5966
5967static int
5968rb_io_fmode_oflags(int fmode)
5969{
5970 int oflags = 0;
5971
5972 switch (fmode & FMODE_READWRITE) {
5973 case FMODE_READABLE:
5974 oflags |= O_RDONLY;
5975 break;
5976 case FMODE_WRITABLE:
5977 oflags |= O_WRONLY;
5978 break;
5979 case FMODE_READWRITE:
5980 oflags |= O_RDWR;
5981 break;
5982 }
5983
5984 if (fmode & FMODE_APPEND) {
5985 oflags |= O_APPEND;
5986 }
5987 if (fmode & FMODE_TRUNC) {
5988 oflags |= O_TRUNC;
5989 }
5990 if (fmode & FMODE_CREATE) {
5991 oflags |= O_CREAT;
5992 }
5993 if (fmode & FMODE_EXCL) {
5994 oflags |= O_EXCL;
5995 }
5996#ifdef O_BINARY
5997 if (fmode & FMODE_BINMODE) {
5998 oflags |= O_BINARY;
5999 }
6000#endif
6001
6002 return oflags;
6003}
6004
6005int
6006rb_io_modestr_oflags(const char *modestr)
6007{
6008 return rb_io_fmode_oflags(rb_io_modestr_fmode(modestr));
6009}
6010
6011static const char*
6012rb_io_oflags_modestr(int oflags)
6013{
6014#ifdef O_BINARY
6015# define MODE_BINARY(a,b) ((oflags & O_BINARY) ? (b) : (a))
6016#else
6017# define MODE_BINARY(a,b) (a)
6018#endif
6019 int accmode;
6020 if (oflags & O_EXCL) {
6021 rb_raise(rb_eArgError, "exclusive access mode is not supported");
6022 }
6023 accmode = oflags & (O_RDONLY|O_WRONLY|O_RDWR);
6024 if (oflags & O_APPEND) {
6025 if (accmode == O_WRONLY) {
6026 return MODE_BINARY("a", "ab");
6027 }
6028 if (accmode == O_RDWR) {
6029 return MODE_BINARY("a+", "ab+");
6030 }
6031 }
6032 switch (accmode) {
6033 default:
6034 rb_raise(rb_eArgError, "invalid access oflags 0x%x", oflags);
6035 case O_RDONLY:
6036 return MODE_BINARY("r", "rb");
6037 case O_WRONLY:
6038 return MODE_BINARY("w", "wb");
6039 case O_RDWR:
6040 if (oflags & O_TRUNC) {
6041 return MODE_BINARY("w+", "wb+");
6042 }
6043 return MODE_BINARY("r+", "rb+");
6044 }
6045}
6046
6047/*
6048 * Convert external/internal encodings to enc/enc2
6049 * NULL => use default encoding
6050 * Qnil => no encoding specified (internal only)
6051 */
6052static void
6053rb_io_ext_int_to_encs(rb_encoding *ext, rb_encoding *intern, rb_encoding **enc, rb_encoding **enc2, int fmode)
6054{
6055 int default_ext = 0;
6056
6057 if (ext == NULL) {
6059 default_ext = 1;
6060 }
6061 if (ext == rb_ascii8bit_encoding()) {
6062 /* If external is ASCII-8BIT, no transcoding */
6063 intern = NULL;
6064 }
6065 else if (intern == NULL) {
6067 }
6068 if (intern == NULL || intern == (rb_encoding *)Qnil ||
6069 (!(fmode & FMODE_SETENC_BY_BOM) && (intern == ext))) {
6070 /* No internal encoding => use external + no transcoding */
6071 *enc = (default_ext && intern != ext) ? NULL : ext;
6072 *enc2 = NULL;
6073 }
6074 else {
6075 *enc = intern;
6076 *enc2 = ext;
6077 }
6078}
6079
6080static void
6081unsupported_encoding(const char *name, rb_encoding *enc)
6082{
6083 rb_enc_warn(enc, "Unsupported encoding %s ignored", name);
6084}
6085
6086static void
6087parse_mode_enc(const char *estr, rb_encoding *estr_enc,
6088 rb_encoding **enc_p, rb_encoding **enc2_p, int *fmode_p)
6089{
6090 const char *p;
6091 char encname[ENCODING_MAXNAMELEN+1];
6092 int idx, idx2;
6093 int fmode = fmode_p ? *fmode_p : 0;
6094 rb_encoding *ext_enc, *int_enc;
6095 long len;
6096
6097 /* parse estr as "enc" or "enc2:enc" or "enc:-" */
6098
6099 p = strrchr(estr, ':');
6100 len = p ? (p++ - estr) : (long)strlen(estr);
6101 if ((fmode & FMODE_SETENC_BY_BOM) || io_encname_bom_p(estr, len)) {
6102 estr += bom_prefix_len;
6103 len -= bom_prefix_len;
6104 if (!STRNCASECMP(estr, utf_prefix, utf_prefix_len)) {
6105 fmode |= FMODE_SETENC_BY_BOM;
6106 }
6107 else {
6108 rb_enc_warn(estr_enc, "BOM with non-UTF encoding %s is nonsense", estr);
6109 fmode &= ~FMODE_SETENC_BY_BOM;
6110 }
6111 }
6112 if (len == 0 || len > ENCODING_MAXNAMELEN) {
6113 idx = -1;
6114 }
6115 else {
6116 if (p) {
6117 memcpy(encname, estr, len);
6118 encname[len] = '\0';
6119 estr = encname;
6120 }
6121 idx = rb_enc_find_index(estr);
6122 }
6123 if (fmode_p) *fmode_p = fmode;
6124
6125 if (idx >= 0)
6126 ext_enc = rb_enc_from_index(idx);
6127 else {
6128 if (idx != -2)
6129 unsupported_encoding(estr, estr_enc);
6130 ext_enc = NULL;
6131 }
6132
6133 int_enc = NULL;
6134 if (p) {
6135 if (*p == '-' && *(p+1) == '\0') {
6136 /* Special case - "-" => no transcoding */
6137 int_enc = (rb_encoding *)Qnil;
6138 }
6139 else {
6140 idx2 = rb_enc_find_index(p);
6141 if (idx2 < 0)
6142 unsupported_encoding(p, estr_enc);
6143 else if (!(fmode & FMODE_SETENC_BY_BOM) && (idx2 == idx)) {
6144 int_enc = (rb_encoding *)Qnil;
6145 }
6146 else
6147 int_enc = rb_enc_from_index(idx2);
6148 }
6149 }
6150
6151 rb_io_ext_int_to_encs(ext_enc, int_enc, enc_p, enc2_p, fmode);
6152}
6153
6154int
6155rb_io_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding **enc2_p, int *fmode_p)
6156{
6157 VALUE encoding=Qnil, extenc=Qundef, intenc=Qundef, tmp;
6158 int extracted = 0;
6159 rb_encoding *extencoding = NULL;
6160 rb_encoding *intencoding = NULL;
6161
6162 if (!NIL_P(opt)) {
6163 VALUE v;
6164 v = rb_hash_lookup2(opt, sym_encoding, Qnil);
6165 if (v != Qnil) encoding = v;
6166 v = rb_hash_lookup2(opt, sym_extenc, Qundef);
6167 if (v != Qnil) extenc = v;
6168 v = rb_hash_lookup2(opt, sym_intenc, Qundef);
6169 if (v != Qundef) intenc = v;
6170 }
6171 if ((extenc != Qundef || intenc != Qundef) && !NIL_P(encoding)) {
6172 if (!NIL_P(ruby_verbose)) {
6173 int idx = rb_to_encoding_index(encoding);
6174 if (idx >= 0) encoding = rb_enc_from_encoding(rb_enc_from_index(idx));
6175 rb_warn("Ignoring encoding parameter '%"PRIsVALUE"': %s_encoding is used",
6176 encoding, extenc == Qundef ? "internal" : "external");
6177 }
6178 encoding = Qnil;
6179 }
6180 if (extenc != Qundef && !NIL_P(extenc)) {
6181 extencoding = rb_to_encoding(extenc);
6182 }
6183 if (intenc != Qundef) {
6184 if (NIL_P(intenc)) {
6185 /* internal_encoding: nil => no transcoding */
6186 intencoding = (rb_encoding *)Qnil;
6187 }
6188 else if (!NIL_P(tmp = rb_check_string_type(intenc))) {
6189 char *p = StringValueCStr(tmp);
6190
6191 if (*p == '-' && *(p+1) == '\0') {
6192 /* Special case - "-" => no transcoding */
6193 intencoding = (rb_encoding *)Qnil;
6194 }
6195 else {
6196 intencoding = rb_to_encoding(intenc);
6197 }
6198 }
6199 else {
6200 intencoding = rb_to_encoding(intenc);
6201 }
6202 if (extencoding == intencoding) {
6203 intencoding = (rb_encoding *)Qnil;
6204 }
6205 }
6206 if (!NIL_P(encoding)) {
6207 extracted = 1;
6208 if (!NIL_P(tmp = rb_check_string_type(encoding))) {
6209 parse_mode_enc(StringValueCStr(tmp), rb_enc_get(tmp),
6210 enc_p, enc2_p, fmode_p);
6211 }
6212 else {
6213 rb_io_ext_int_to_encs(rb_to_encoding(encoding), NULL, enc_p, enc2_p, 0);
6214 }
6215 }
6216 else if (extenc != Qundef || intenc != Qundef) {
6217 extracted = 1;
6218 rb_io_ext_int_to_encs(extencoding, intencoding, enc_p, enc2_p, 0);
6219 }
6220 return extracted;
6221}
6222
6223typedef struct rb_io_enc_t convconfig_t;
6224
6225static void
6226validate_enc_binmode(int *fmode_p, int ecflags, rb_encoding *enc, rb_encoding *enc2)
6227{
6228 int fmode = *fmode_p;
6229
6230 if ((fmode & FMODE_READABLE) &&
6231 !enc2 &&
6232 !(fmode & FMODE_BINMODE) &&
6234 rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
6235
6236 if ((fmode & FMODE_BINMODE) && (ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
6237 rb_raise(rb_eArgError, "newline decorator with binary mode");
6238 }
6239 if (!(fmode & FMODE_BINMODE) &&
6240 (DEFAULT_TEXTMODE || (ecflags & ECONV_NEWLINE_DECORATOR_MASK))) {
6241 fmode |= FMODE_TEXTMODE;
6242 *fmode_p = fmode;
6243 }
6244#if !DEFAULT_TEXTMODE
6245 else if (!(ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
6246 fmode &= ~FMODE_TEXTMODE;
6247 *fmode_p = fmode;
6248 }
6249#endif
6250}
6251
6252static void
6253extract_binmode(VALUE opthash, int *fmode)
6254{
6255 if (!NIL_P(opthash)) {
6256 VALUE v;
6257 v = rb_hash_aref(opthash, sym_textmode);
6258 if (!NIL_P(v)) {
6259 if (*fmode & FMODE_TEXTMODE)
6260 rb_raise(rb_eArgError, "textmode specified twice");
6261 if (*fmode & FMODE_BINMODE)
6262 rb_raise(rb_eArgError, "both textmode and binmode specified");
6263 if (RTEST(v))
6264 *fmode |= FMODE_TEXTMODE;
6265 }
6266 v = rb_hash_aref(opthash, sym_binmode);
6267 if (!NIL_P(v)) {
6268 if (*fmode & FMODE_BINMODE)
6269 rb_raise(rb_eArgError, "binmode specified twice");
6270 if (*fmode & FMODE_TEXTMODE)
6271 rb_raise(rb_eArgError, "both textmode and binmode specified");
6272 if (RTEST(v))
6273 *fmode |= FMODE_BINMODE;
6274 }
6275
6276 if ((*fmode & FMODE_BINMODE) && (*fmode & FMODE_TEXTMODE))
6277 rb_raise(rb_eArgError, "both textmode and binmode specified");
6278 }
6279}
6280
6281void
6282rb_io_extract_modeenc(VALUE *vmode_p, VALUE *vperm_p, VALUE opthash,
6283 int *oflags_p, int *fmode_p, convconfig_t *convconfig_p)
6284{
6285 VALUE vmode;
6286 int oflags, fmode;
6287 rb_encoding *enc, *enc2;
6288 int ecflags;
6289 VALUE ecopts;
6290 int has_enc = 0, has_vmode = 0;
6291 VALUE intmode;
6292
6293 vmode = *vmode_p;
6294
6295 /* Set to defaults */
6296 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
6297
6298 vmode_handle:
6299 if (NIL_P(vmode)) {
6300 fmode = FMODE_READABLE;
6301 oflags = O_RDONLY;
6302 }
6303 else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int"))) {
6304 vmode = intmode;
6305 oflags = NUM2INT(intmode);
6306 fmode = rb_io_oflags_fmode(oflags);
6307 }
6308 else {
6309 const char *p;
6310
6311 SafeStringValue(vmode);
6312 p = StringValueCStr(vmode);
6313 fmode = rb_io_modestr_fmode(p);
6314 oflags = rb_io_fmode_oflags(fmode);
6315 p = strchr(p, ':');
6316 if (p) {
6317 has_enc = 1;
6318 parse_mode_enc(p+1, rb_enc_get(vmode), &enc, &enc2, &fmode);
6319 }
6320 else {
6321 rb_encoding *e;
6322
6323 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
6324 rb_io_ext_int_to_encs(e, NULL, &enc, &enc2, fmode);
6325 }
6326 }
6327
6328 if (NIL_P(opthash)) {
6329 ecflags = (fmode & FMODE_READABLE) ?
6332#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
6333 ecflags |= (fmode & FMODE_WRITABLE) ?
6334 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
6335 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
6336#endif
6337 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
6338 ecopts = Qnil;
6339 if (fmode & FMODE_BINMODE) {
6340#ifdef O_BINARY
6341 oflags |= O_BINARY;
6342#endif
6343 if (!has_enc)
6344 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
6345 }
6346#if DEFAULT_TEXTMODE
6347 else if (NIL_P(vmode)) {
6348 fmode |= DEFAULT_TEXTMODE;
6349 }
6350#endif
6351 }
6352 else {
6353 VALUE v;
6354 if (!has_vmode) {
6355 v = rb_hash_aref(opthash, sym_mode);
6356 if (!NIL_P(v)) {
6357 if (!NIL_P(vmode)) {
6358 rb_raise(rb_eArgError, "mode specified twice");
6359 }
6360 has_vmode = 1;
6361 vmode = v;
6362 goto vmode_handle;
6363 }
6364 }
6365 v = rb_hash_aref(opthash, sym_flags);
6366 if (!NIL_P(v)) {
6367 v = rb_to_int(v);
6368 oflags |= NUM2INT(v);
6369 vmode = INT2NUM(oflags);
6370 fmode = rb_io_oflags_fmode(oflags);
6371 }
6372 extract_binmode(opthash, &fmode);
6373 if (fmode & FMODE_BINMODE) {
6374#ifdef O_BINARY
6375 oflags |= O_BINARY;
6376#endif
6377 if (!has_enc)
6378 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
6379 }
6380#if DEFAULT_TEXTMODE
6381 else if (NIL_P(vmode)) {
6382 fmode |= DEFAULT_TEXTMODE;
6383 }
6384#endif
6385 v = rb_hash_aref(opthash, sym_perm);
6386 if (!NIL_P(v)) {
6387 if (vperm_p) {
6388 if (!NIL_P(*vperm_p)) {
6389 rb_raise(rb_eArgError, "perm specified twice");
6390 }
6391 *vperm_p = v;
6392 }
6393 else {
6394 /* perm no use, just ignore */
6395 }
6396 }
6397 ecflags = (fmode & FMODE_READABLE) ?
6400#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
6401 ecflags |= (fmode & FMODE_WRITABLE) ?
6402 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
6403 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
6404#endif
6405
6406 if (rb_io_extract_encoding_option(opthash, &enc, &enc2, &fmode)) {
6407 if (has_enc) {
6408 rb_raise(rb_eArgError, "encoding specified twice");
6409 }
6410 }
6411 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
6412 ecflags = rb_econv_prepare_options(opthash, &ecopts, ecflags);
6413 }
6414
6415 validate_enc_binmode(&fmode, ecflags, enc, enc2);
6416
6417 *vmode_p = vmode;
6418
6419 *oflags_p = oflags;
6420 *fmode_p = fmode;
6421 convconfig_p->enc = enc;
6422 convconfig_p->enc2 = enc2;
6423 convconfig_p->ecflags = ecflags;
6424 convconfig_p->ecopts = ecopts;
6425}
6426
6428 VALUE fname;
6429 int oflags;
6430 mode_t perm;
6431};
6432
6433static void *
6434sysopen_func(void *ptr)
6435{
6436 const struct sysopen_struct *data = ptr;
6437 const char *fname = RSTRING_PTR(data->fname);
6438 return (void *)(VALUE)rb_cloexec_open(fname, data->oflags, data->perm);
6439}
6440
6441static inline int
6442rb_sysopen_internal(struct sysopen_struct *data)
6443{
6444 int fd;
6445 fd = (int)(VALUE)rb_thread_call_without_gvl(sysopen_func, data, RUBY_UBF_IO, 0);
6446 if (0 <= fd)
6447 rb_update_max_fd(fd);
6448 return fd;
6449}
6450
6451static int
6452rb_sysopen(VALUE fname, int oflags, mode_t perm)
6453{
6454 int fd;
6455 struct sysopen_struct data;
6456
6457 data.fname = rb_str_encode_ospath(fname);
6458 StringValueCStr(data.fname);
6459 data.oflags = oflags;
6460 data.perm = perm;
6461
6462 fd = rb_sysopen_internal(&data);
6463 if (fd < 0) {
6464 int e = errno;
6465 if (rb_gc_for_fd(e)) {
6466 fd = rb_sysopen_internal(&data);
6467 }
6468 if (fd < 0) {
6469 rb_syserr_fail_path(e, fname);
6470 }
6471 }
6472 return fd;
6473}
6474
6475FILE *
6476rb_fdopen(int fd, const char *modestr)
6477{
6478 FILE *file;
6479
6480#if defined(__sun)
6481 errno = 0;
6482#endif
6483 file = fdopen(fd, modestr);
6484 if (!file) {
6485 int e = errno;
6486#if defined(__sun)
6487 if (e == 0) {
6488 rb_gc();
6489 errno = 0;
6490 file = fdopen(fd, modestr);
6491 }
6492 else
6493#endif
6494 if (rb_gc_for_fd(e)) {
6495 file = fdopen(fd, modestr);
6496 }
6497 if (!file) {
6498#ifdef _WIN32
6499 if (e == 0) e = EINVAL;
6500#elif defined(__sun)
6501 if (e == 0) e = EMFILE;
6502#endif
6503 rb_syserr_fail(e, 0);
6504 }
6505 }
6506
6507 /* xxx: should be _IONBF? A buffer in FILE may have trouble. */
6508#ifdef USE_SETVBUF
6509 if (setvbuf(file, NULL, _IOFBF, 0) != 0)
6510 rb_warn("setvbuf() can't be honoured (fd=%d)", fd);
6511#endif
6512 return file;
6513}
6514
6515static int
6516io_check_tty(rb_io_t *fptr)
6517{
6518 int t = isatty(fptr->fd);
6519 if (t)
6520 fptr->mode |= FMODE_TTY|FMODE_DUPLEX;
6521 return t;
6522}
6523
6524static VALUE rb_io_internal_encoding(VALUE);
6525static void io_encoding_set(rb_io_t *, VALUE, VALUE, VALUE);
6526
6527static int
6528io_strip_bom(VALUE io)
6529{
6530 VALUE b1, b2, b3, b4;
6531 rb_io_t *fptr;
6532
6533 GetOpenFile(io, fptr);
6534 if (!(fptr->mode & FMODE_READABLE)) return 0;
6535 if (NIL_P(b1 = rb_io_getbyte(io))) return 0;
6536 switch (b1) {
6537 case INT2FIX(0xEF):
6538 if (NIL_P(b2 = rb_io_getbyte(io))) break;
6539 if (b2 == INT2FIX(0xBB) && !NIL_P(b3 = rb_io_getbyte(io))) {
6540 if (b3 == INT2FIX(0xBF)) {
6541 return rb_utf8_encindex();
6542 }
6543 rb_io_ungetbyte(io, b3);
6544 }
6545 rb_io_ungetbyte(io, b2);
6546 break;
6547
6548 case INT2FIX(0xFE):
6549 if (NIL_P(b2 = rb_io_getbyte(io))) break;
6550 if (b2 == INT2FIX(0xFF)) {
6551 return ENCINDEX_UTF_16BE;
6552 }
6553 rb_io_ungetbyte(io, b2);
6554 break;
6555
6556 case INT2FIX(0xFF):
6557 if (NIL_P(b2 = rb_io_getbyte(io))) break;
6558 if (b2 == INT2FIX(0xFE)) {
6559 b3 = rb_io_getbyte(io);
6560 if (b3 == INT2FIX(0) && !NIL_P(b4 = rb_io_getbyte(io))) {
6561 if (b4 == INT2FIX(0)) {
6562 return ENCINDEX_UTF_32LE;
6563 }
6564 rb_io_ungetbyte(io, b4);
6565 }
6566 rb_io_ungetbyte(io, b3);
6567 return ENCINDEX_UTF_16LE;
6568 }
6569 rb_io_ungetbyte(io, b2);
6570 break;
6571
6572 case INT2FIX(0):
6573 if (NIL_P(b2 = rb_io_getbyte(io))) break;
6574 if (b2 == INT2FIX(0) && !NIL_P(b3 = rb_io_getbyte(io))) {
6575 if (b3 == INT2FIX(0xFE) && !NIL_P(b4 = rb_io_getbyte(io))) {
6576 if (b4 == INT2FIX(0xFF)) {
6577 return ENCINDEX_UTF_32BE;
6578 }
6579 rb_io_ungetbyte(io, b4);
6580 }
6581 rb_io_ungetbyte(io, b3);
6582 }
6583 rb_io_ungetbyte(io, b2);
6584 break;
6585 }
6586 rb_io_ungetbyte(io, b1);
6587 return 0;
6588}
6589
6590static rb_encoding *
6591io_set_encoding_by_bom(VALUE io)
6592{
6593 int idx = io_strip_bom(io);
6594 rb_io_t *fptr;
6595 rb_encoding *extenc = NULL;
6596
6597 GetOpenFile(io, fptr);
6598 if (idx) {
6599 extenc = rb_enc_from_index(idx);
6600 io_encoding_set(fptr, rb_enc_from_encoding(extenc),
6601 rb_io_internal_encoding(io), Qnil);
6602 }
6603 else {
6604 fptr->encs.enc2 = NULL;
6605 }
6606 return extenc;
6607}
6608
6609static VALUE
6610rb_file_open_generic(VALUE io, VALUE filename, int oflags, int fmode,
6611 const convconfig_t *convconfig, mode_t perm)
6612{
6613 VALUE pathv;
6614 rb_io_t *fptr;
6615 convconfig_t cc;
6616 if (!convconfig) {
6617 /* Set to default encodings */
6618 rb_io_ext_int_to_encs(NULL, NULL, &cc.enc, &cc.enc2, fmode);
6619 cc.ecflags = 0;
6620 cc.ecopts = Qnil;
6621 convconfig = &cc;
6622 }
6623 validate_enc_binmode(&fmode, convconfig->ecflags,
6624 convconfig->enc, convconfig->enc2);
6625
6626 MakeOpenFile(io, fptr);
6627 fptr->mode = fmode;
6628 fptr->encs = *convconfig;
6629 pathv = rb_str_new_frozen(filename);
6630#ifdef O_TMPFILE
6631 if (!(oflags & O_TMPFILE)) {
6632 fptr->pathv = pathv;
6633 }
6634#else
6635 fptr->pathv = pathv;
6636#endif
6637 fptr->fd = rb_sysopen(pathv, oflags, perm);
6638 io_check_tty(fptr);
6639 if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
6640
6641 return io;
6642}
6643
6644static VALUE
6645rb_file_open_internal(VALUE io, VALUE filename, const char *modestr)
6646{
6647 int fmode = rb_io_modestr_fmode(modestr);
6648 const char *p = strchr(modestr, ':');
6649 convconfig_t convconfig;
6650
6651 if (p) {
6652 parse_mode_enc(p+1, rb_usascii_encoding(),
6653 &convconfig.enc, &convconfig.enc2, &fmode);
6654 convconfig.ecflags = 0;
6655 convconfig.ecopts = Qnil;
6656 }
6657 else {
6658 rb_encoding *e;
6659 /* Set to default encodings */
6660
6661 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
6662 rb_io_ext_int_to_encs(e, NULL, &convconfig.enc, &convconfig.enc2, fmode);
6663 convconfig.ecflags = 0;
6664 convconfig.ecopts = Qnil;
6665 }
6666
6667 return rb_file_open_generic(io, filename,
6668 rb_io_fmode_oflags(fmode),
6669 fmode,
6670 &convconfig,
6671 0666);
6672}
6673
6674VALUE
6675rb_file_open_str(VALUE fname, const char *modestr)
6676{
6677 FilePathValue(fname);
6678 return rb_file_open_internal(io_alloc(rb_cFile), fname, modestr);
6679}
6680
6681VALUE
6682rb_file_open(const char *fname, const char *modestr)
6683{
6684 return rb_file_open_internal(io_alloc(rb_cFile), rb_str_new_cstr(fname), modestr);
6685}
6686
6687#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
6688static struct pipe_list {
6689 rb_io_t *fptr;
6690 struct pipe_list *next;
6691} *pipe_list;
6692
6693static void
6694pipe_add_fptr(rb_io_t *fptr)
6695{
6696 struct pipe_list *list;
6697
6698 list = ALLOC(struct pipe_list);
6699 list->fptr = fptr;
6700 list->next = pipe_list;
6701 pipe_list = list;
6702}
6703
6704static void
6705pipe_del_fptr(rb_io_t *fptr)
6706{
6707 struct pipe_list **prev = &pipe_list;
6708 struct pipe_list *tmp;
6709
6710 while ((tmp = *prev) != 0) {
6711 if (tmp->fptr == fptr) {
6712 *prev = tmp->next;
6713 free(tmp);
6714 return;
6715 }
6716 prev = &tmp->next;
6717 }
6718}
6719
6720#if defined (_WIN32) || defined(__CYGWIN__)
6721static void
6722pipe_atexit(void)
6723{
6724 struct pipe_list *list = pipe_list;
6725 struct pipe_list *tmp;
6726
6727 while (list) {
6728 tmp = list->next;
6729 rb_io_fptr_finalize(list->fptr);
6730 list = tmp;
6731 }
6732}
6733#endif
6734
6735static void
6736pipe_finalize(rb_io_t *fptr, int noraise)
6737{
6738#if !defined(HAVE_WORKING_FORK) && !defined(_WIN32)
6739 int status = 0;
6740 if (fptr->stdio_file) {
6741 status = pclose(fptr->stdio_file);
6742 }
6743 fptr->fd = -1;
6744 fptr->stdio_file = 0;
6745 rb_last_status_set(status, fptr->pid);
6746#else
6747 fptr_finalize(fptr, noraise);
6748#endif
6749 pipe_del_fptr(fptr);
6750}
6751#endif
6752
6753static void
6754fptr_copy_finalizer(rb_io_t *fptr, const rb_io_t *orig)
6755{
6756#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
6757 void (*const old_finalize)(struct rb_io_t*,int) = fptr->finalize;
6758
6759 if (old_finalize == orig->finalize) return;
6760#endif
6761
6762 fptr->finalize = orig->finalize;
6763
6764#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
6765 if (old_finalize != pipe_finalize) {
6766 struct pipe_list *list;
6767 for (list = pipe_list; list; list = list->next) {
6768 if (list->fptr == fptr) break;
6769 }
6770 if (!list) pipe_add_fptr(fptr);
6771 }
6772 else {
6773 pipe_del_fptr(fptr);
6774 }
6775#endif
6776}
6777
6778void
6780{
6782 fptr->mode |= FMODE_SYNC;
6783}
6784
6785void
6786rb_io_unbuffered(rb_io_t *fptr)
6787{
6788 rb_io_synchronized(fptr);
6789}
6790
6791int
6792rb_pipe(int *pipes)
6793{
6794 int ret;
6795 ret = rb_cloexec_pipe(pipes);
6796 if (ret < 0) {
6797 if (rb_gc_for_fd(errno)) {
6798 ret = rb_cloexec_pipe(pipes);
6799 }
6800 }
6801 if (ret == 0) {
6802 rb_update_max_fd(pipes[0]);
6803 rb_update_max_fd(pipes[1]);
6804 }
6805 return ret;
6806}
6807
6808#ifdef _WIN32
6809#define HAVE_SPAWNV 1
6810#define spawnv(mode, cmd, args) rb_w32_uaspawn((mode), (cmd), (args))
6811#define spawn(mode, cmd) rb_w32_uspawn((mode), (cmd), 0)
6812#endif
6813
6814#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
6815struct popen_arg {
6816 VALUE execarg_obj;
6817 struct rb_execarg *eargp;
6818 int modef;
6819 int pair[2];
6820 int write_pair[2];
6821};
6822#endif
6823
6824#ifdef HAVE_WORKING_FORK
6825# ifndef __EMSCRIPTEN__
6826static void
6827popen_redirect(struct popen_arg *p)
6828{
6829 if ((p->modef & FMODE_READABLE) && (p->modef & FMODE_WRITABLE)) {
6830 close(p->write_pair[1]);
6831 if (p->write_pair[0] != 0) {
6832 dup2(p->write_pair[0], 0);
6833 close(p->write_pair[0]);
6834 }
6835 close(p->pair[0]);
6836 if (p->pair[1] != 1) {
6837 dup2(p->pair[1], 1);
6838 close(p->pair[1]);
6839 }
6840 }
6841 else if (p->modef & FMODE_READABLE) {
6842 close(p->pair[0]);
6843 if (p->pair[1] != 1) {
6844 dup2(p->pair[1], 1);
6845 close(p->pair[1]);
6846 }
6847 }
6848 else {
6849 close(p->pair[1]);
6850 if (p->pair[0] != 0) {
6851 dup2(p->pair[0], 0);
6852 close(p->pair[0]);
6853 }
6854 }
6855}
6856# endif
6857
6858#if defined(__linux__)
6859/* Linux /proc/self/status contains a line: "FDSize:\t<nnn>\n"
6860 * Since /proc may not be available, linux_get_maxfd is just a hint.
6861 * This function, linux_get_maxfd, must be async-signal-safe.
6862 * I.e. opendir() is not usable.
6863 *
6864 * Note that memchr() and memcmp is *not* async-signal-safe in POSIX.
6865 * However they are easy to re-implement in async-signal-safe manner.
6866 * (Also note that there is missing/memcmp.c.)
6867 */
6868static int
6869linux_get_maxfd(void)
6870{
6871 int fd;
6872 char buf[4096], *p, *np, *e;
6873 ssize_t ss;
6874 fd = rb_cloexec_open("/proc/self/status", O_RDONLY|O_NOCTTY, 0);
6875 if (fd < 0) return fd;
6876 ss = read(fd, buf, sizeof(buf));
6877 if (ss < 0) goto err;
6878 p = buf;
6879 e = buf + ss;
6880 while ((int)sizeof("FDSize:\t0\n")-1 <= e-p &&
6881 (np = memchr(p, '\n', e-p)) != NULL) {
6882 if (memcmp(p, "FDSize:", sizeof("FDSize:")-1) == 0) {
6883 int fdsize;
6884 p += sizeof("FDSize:")-1;
6885 *np = '\0';
6886 fdsize = (int)ruby_strtoul(p, (char **)NULL, 10);
6887 close(fd);
6888 return fdsize;
6889 }
6890 p = np+1;
6891 }
6892 /* fall through */
6893
6894 err:
6895 close(fd);
6896 return (int)ss;
6897}
6898#endif
6899
6900/* This function should be async-signal-safe. */
6901void
6902rb_close_before_exec(int lowfd, int maxhint, VALUE noclose_fds)
6903{
6904#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
6905 int fd, ret;
6906 int max = (int)max_file_descriptor;
6907# ifdef F_MAXFD
6908 /* F_MAXFD is available since NetBSD 2.0. */
6909 ret = fcntl(0, F_MAXFD); /* async-signal-safe */
6910 if (ret != -1)
6911 maxhint = max = ret;
6912# elif defined(__linux__)
6913 ret = linux_get_maxfd();
6914 if (maxhint < ret)
6915 maxhint = ret;
6916 /* maxhint = max = ret; if (ret == -1) abort(); // test */
6917# endif
6918 if (max < maxhint)
6919 max = maxhint;
6920 for (fd = lowfd; fd <= max; fd++) {
6921 if (!NIL_P(noclose_fds) &&
6922 RTEST(rb_hash_lookup(noclose_fds, INT2FIX(fd)))) /* async-signal-safe */
6923 continue;
6924 ret = fcntl(fd, F_GETFD); /* async-signal-safe */
6925 if (ret != -1 && !(ret & FD_CLOEXEC)) {
6926 fcntl(fd, F_SETFD, ret|FD_CLOEXEC); /* async-signal-safe */
6927 }
6928# define CONTIGUOUS_CLOSED_FDS 20
6929 if (ret != -1) {
6930 if (max < fd + CONTIGUOUS_CLOSED_FDS)
6931 max = fd + CONTIGUOUS_CLOSED_FDS;
6932 }
6933 }
6934#endif
6935}
6936
6937# ifndef __EMSCRIPTEN__
6938static int
6939popen_exec(void *pp, char *errmsg, size_t errmsg_len)
6940{
6941 struct popen_arg *p = (struct popen_arg*)pp;
6942
6943 return rb_exec_async_signal_safe(p->eargp, errmsg, errmsg_len);
6944}
6945# endif
6946#endif
6947
6948#if (defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)) && !defined __EMSCRIPTEN__
6949static VALUE
6950rb_execarg_fixup_v(VALUE execarg_obj)
6951{
6952 rb_execarg_parent_start(execarg_obj);
6953 return Qnil;
6954}
6955#else
6956char *rb_execarg_commandline(const struct rb_execarg *eargp, VALUE *prog);
6957#endif
6958
6959#ifndef __EMSCRIPTEN__
6960static VALUE
6961pipe_open(VALUE execarg_obj, const char *modestr, int fmode,
6962 const convconfig_t *convconfig)
6963{
6964 struct rb_execarg *eargp = NIL_P(execarg_obj) ? NULL : rb_execarg_get(execarg_obj);
6965 VALUE prog = eargp ? (eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name) : Qfalse ;
6966 rb_pid_t pid = 0;
6967 rb_io_t *fptr;
6968 VALUE port;
6969 rb_io_t *write_fptr;
6970 VALUE write_port;
6971#if defined(HAVE_WORKING_FORK)
6972 int status;
6973 char errmsg[80] = { '\0' };
6974#endif
6975#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
6976 int state;
6977 struct popen_arg arg;
6978#endif
6979 int e = 0;
6980#if defined(HAVE_SPAWNV)
6981# if defined(HAVE_SPAWNVE)
6982# define DO_SPAWN(cmd, args, envp) ((args) ? \
6983 spawnve(P_NOWAIT, (cmd), (args), (envp)) : \
6984 spawne(P_NOWAIT, (cmd), (envp)))
6985# else
6986# define DO_SPAWN(cmd, args, envp) ((args) ? \
6987 spawnv(P_NOWAIT, (cmd), (args)) : \
6988 spawn(P_NOWAIT, (cmd)))
6989# endif
6990# if !defined(HAVE_WORKING_FORK)
6991 char **args = NULL;
6992# if defined(HAVE_SPAWNVE)
6993 char **envp = NULL;
6994# endif
6995# endif
6996#endif
6997#if !defined(HAVE_WORKING_FORK)
6998 struct rb_execarg sarg, *sargp = &sarg;
6999#endif
7000 FILE *fp = 0;
7001 int fd = -1;
7002 int write_fd = -1;
7003#if !defined(HAVE_WORKING_FORK)
7004 const char *cmd = 0;
7005
7006 if (prog)
7007 cmd = StringValueCStr(prog);
7008#endif
7009
7010#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7011 arg.execarg_obj = execarg_obj;
7012 arg.eargp = eargp;
7013 arg.modef = fmode;
7014 arg.pair[0] = arg.pair[1] = -1;
7015 arg.write_pair[0] = arg.write_pair[1] = -1;
7016# if !defined(HAVE_WORKING_FORK)
7017 if (eargp && !eargp->use_shell) {
7018 args = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
7019 }
7020# endif
7021 switch (fmode & (FMODE_READABLE|FMODE_WRITABLE)) {
7023 if (rb_pipe(arg.write_pair) < 0)
7024 rb_sys_fail_str(prog);
7025 if (rb_pipe(arg.pair) < 0) {
7026 e = errno;
7027 close(arg.write_pair[0]);
7028 close(arg.write_pair[1]);
7029 rb_syserr_fail_str(e, prog);
7030 }
7031 if (eargp) {
7032 rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.write_pair[0]));
7033 rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
7034 }
7035 break;
7036 case FMODE_READABLE:
7037 if (rb_pipe(arg.pair) < 0)
7038 rb_sys_fail_str(prog);
7039 if (eargp)
7040 rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
7041 break;
7042 case FMODE_WRITABLE:
7043 if (rb_pipe(arg.pair) < 0)
7044 rb_sys_fail_str(prog);
7045 if (eargp)
7046 rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.pair[0]));
7047 break;
7048 default:
7049 rb_sys_fail_str(prog);
7050 }
7051 if (!NIL_P(execarg_obj)) {
7052 rb_protect(rb_execarg_fixup_v, execarg_obj, &state);
7053 if (state) {
7054 if (0 <= arg.write_pair[0]) close(arg.write_pair[0]);
7055 if (0 <= arg.write_pair[1]) close(arg.write_pair[1]);
7056 if (0 <= arg.pair[0]) close(arg.pair[0]);
7057 if (0 <= arg.pair[1]) close(arg.pair[1]);
7058 rb_execarg_parent_end(execarg_obj);
7059 rb_jump_tag(state);
7060 }
7061
7062# if defined(HAVE_WORKING_FORK)
7063 pid = rb_fork_async_signal_safe(&status, popen_exec, &arg, arg.eargp->redirect_fds, errmsg, sizeof(errmsg));
7064# else
7065 rb_execarg_run_options(eargp, sargp, NULL, 0);
7066# if defined(HAVE_SPAWNVE)
7067 if (eargp->envp_str) envp = (char **)RSTRING_PTR(eargp->envp_str);
7068# endif
7069 while ((pid = DO_SPAWN(cmd, args, envp)) < 0) {
7070 /* exec failed */
7071 switch (e = errno) {
7072 case EAGAIN:
7073# if EWOULDBLOCK != EAGAIN
7074 case EWOULDBLOCK:
7075# endif
7076 rb_thread_sleep(1);
7077 continue;
7078 }
7079 break;
7080 }
7081 if (eargp)
7082 rb_execarg_run_options(sargp, NULL, NULL, 0);
7083# endif
7084 rb_execarg_parent_end(execarg_obj);
7085 }
7086 else {
7087# if defined(HAVE_WORKING_FORK)
7088 pid = rb_call_proc__fork();
7089 if (pid == 0) { /* child */
7090 popen_redirect(&arg);
7091 rb_io_synchronized(RFILE(orig_stdout)->fptr);
7092 rb_io_synchronized(RFILE(orig_stderr)->fptr);
7093 return Qnil;
7094 }
7095# else
7097# endif
7098 }
7099
7100 /* parent */
7101 if (pid < 0) {
7102# if defined(HAVE_WORKING_FORK)
7103 e = errno;
7104# endif
7105 close(arg.pair[0]);
7106 close(arg.pair[1]);
7108 close(arg.write_pair[0]);
7109 close(arg.write_pair[1]);
7110 }
7111# if defined(HAVE_WORKING_FORK)
7112 if (errmsg[0])
7113 rb_syserr_fail(e, errmsg);
7114# endif
7115 rb_syserr_fail_str(e, prog);
7116 }
7117 if ((fmode & FMODE_READABLE) && (fmode & FMODE_WRITABLE)) {
7118 close(arg.pair[1]);
7119 fd = arg.pair[0];
7120 close(arg.write_pair[0]);
7121 write_fd = arg.write_pair[1];
7122 }
7123 else if (fmode & FMODE_READABLE) {
7124 close(arg.pair[1]);
7125 fd = arg.pair[0];
7126 }
7127 else {
7128 close(arg.pair[0]);
7129 fd = arg.pair[1];
7130 }
7131#else
7132 cmd = rb_execarg_commandline(eargp, &prog);
7133 if (!NIL_P(execarg_obj)) {
7134 rb_execarg_parent_start(execarg_obj);
7135 rb_execarg_run_options(eargp, sargp, NULL, 0);
7136 }
7137 fp = popen(cmd, modestr);
7138 e = errno;
7139 if (eargp) {
7140 rb_execarg_parent_end(execarg_obj);
7141 rb_execarg_run_options(sargp, NULL, NULL, 0);
7142 }
7143 if (!fp) rb_syserr_fail_path(e, prog);
7144 fd = fileno(fp);
7145#endif
7146
7147 port = io_alloc(rb_cIO);
7148 MakeOpenFile(port, fptr);
7149 fptr->fd = fd;
7150 fptr->stdio_file = fp;
7151 fptr->mode = fmode | FMODE_SYNC|FMODE_DUPLEX;
7152 if (convconfig) {
7153 fptr->encs = *convconfig;
7154#if RUBY_CRLF_ENVIRONMENT
7157 }
7158#endif
7159 }
7160 else {
7161 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
7163 }
7164#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7165 if (NEED_NEWLINE_DECORATOR_ON_WRITE(fptr)) {
7166 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
7167 }
7168#endif
7169 }
7170 fptr->pid = pid;
7171
7172 if (0 <= write_fd) {
7173 write_port = io_alloc(rb_cIO);
7174 MakeOpenFile(write_port, write_fptr);
7175 write_fptr->fd = write_fd;
7176 write_fptr->mode = (fmode & ~FMODE_READABLE)| FMODE_SYNC|FMODE_DUPLEX;
7177 fptr->mode &= ~FMODE_WRITABLE;
7178 fptr->tied_io_for_writing = write_port;
7179 rb_ivar_set(port, rb_intern("@tied_io_for_writing"), write_port);
7180 }
7181
7182#if defined (__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7183 fptr->finalize = pipe_finalize;
7184 pipe_add_fptr(fptr);
7185#endif
7186 return port;
7187}
7188#else
7189static VALUE
7190pipe_open(VALUE execarg_obj, const char *modestr, int fmode,
7191 const convconfig_t *convconfig)
7192{
7193 rb_raise(rb_eNotImpError, "popen() is not available");
7194}
7195#endif
7196
7197static int
7198is_popen_fork(VALUE prog)
7199{
7200 if (RSTRING_LEN(prog) == 1 && RSTRING_PTR(prog)[0] == '-') {
7201#if !defined(HAVE_WORKING_FORK)
7202 rb_raise(rb_eNotImpError,
7203 "fork() function is unimplemented on this machine");
7204#else
7205 return TRUE;
7206#endif
7207 }
7208 return FALSE;
7209}
7210
7211static VALUE
7212pipe_open_s(VALUE prog, const char *modestr, int fmode,
7213 const convconfig_t *convconfig)
7214{
7215 int argc = 1;
7216 VALUE *argv = &prog;
7217 VALUE execarg_obj = Qnil;
7218
7219 if (!is_popen_fork(prog))
7220 execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
7221 return pipe_open(execarg_obj, modestr, fmode, convconfig);
7222}
7223
7224static VALUE
7225pipe_close(VALUE io)
7226{
7227 rb_io_t *fptr = io_close_fptr(io);
7228 if (fptr) {
7229 fptr_waitpid(fptr, rb_thread_to_be_killed(rb_thread_current()));
7230 }
7231 return Qnil;
7232}
7233
7234static VALUE popen_finish(VALUE port, VALUE klass);
7235
7236/*
7237 * call-seq:
7238 * IO.popen([env,] cmd, mode="r" [, opt]) -> io
7239 * IO.popen([env,] cmd, mode="r" [, opt]) {|io| block } -> obj
7240 *
7241 * Runs the specified command as a subprocess; the subprocess's
7242 * standard input and output will be connected to the returned
7243 * IO object.
7244 *
7245 * The PID of the started process can be obtained by IO#pid method.
7246 *
7247 * _cmd_ is a string or an array as follows.
7248 *
7249 * cmd:
7250 * "-" : fork
7251 * commandline : command line string which is passed to a shell
7252 * [env, cmdname, arg1, ..., opts] : command name and zero or more arguments (no shell)
7253 * [env, [cmdname, argv0], arg1, ..., opts] : command name, argv[0] and zero or more arguments (no shell)
7254 * (env and opts are optional.)
7255 *
7256 * If _cmd_ is a +String+ ``<code>-</code>'',
7257 * then a new instance of Ruby is started as the subprocess.
7258 *
7259 * If <i>cmd</i> is an +Array+ of +String+,
7260 * then it will be used as the subprocess's +argv+ bypassing a shell.
7261 * The array can contain a hash at first for environments and
7262 * a hash at last for options similar to #spawn.
7263 *
7264 * The default mode for the new file object is ``r'',
7265 * but <i>mode</i> may be set to any of the modes listed in the description for class IO.
7266 * The last argument <i>opt</i> qualifies <i>mode</i>.
7267 *
7268 * # set IO encoding
7269 * IO.popen("nkf -e filename", :external_encoding=>"EUC-JP") {|nkf_io|
7270 * euc_jp_string = nkf_io.read
7271 * }
7272 *
7273 * # merge standard output and standard error using
7274 * # spawn option. See the document of Kernel.spawn.
7275 * IO.popen(["ls", "/", :err=>[:child, :out]]) {|ls_io|
7276 * ls_result_with_error = ls_io.read
7277 * }
7278 *
7279 * # spawn options can be mixed with IO options
7280 * IO.popen(["ls", "/"], :err=>[:child, :out]) {|ls_io|
7281 * ls_result_with_error = ls_io.read
7282 * }
7283 *
7284 * Raises exceptions which IO.pipe and Kernel.spawn raise.
7285 *
7286 * If a block is given, Ruby will run the command as a child connected
7287 * to Ruby with a pipe. Ruby's end of the pipe will be passed as a
7288 * parameter to the block.
7289 * At the end of block, Ruby closes the pipe and sets <code>$?</code>.
7290 * In this case IO.popen returns the value of the block.
7291 *
7292 * If a block is given with a _cmd_ of ``<code>-</code>'',
7293 * the block will be run in two separate processes: once in the parent,
7294 * and once in a child. The parent process will be passed the pipe
7295 * object as a parameter to the block, the child version of the block
7296 * will be passed +nil+, and the child's standard in and
7297 * standard out will be connected to the parent through the pipe. Not
7298 * available on all platforms.
7299 *
7300 * f = IO.popen("uname")
7301 * p f.readlines
7302 * f.close
7303 * puts "Parent is #{Process.pid}"
7304 * IO.popen("date") {|f| puts f.gets }
7305 * IO.popen("-") {|f| $stderr.puts "#{Process.pid} is here, f is #{f.inspect}"}
7306 * p $?
7307 * IO.popen(%w"sed -e s|^|<foo>| -e s&$&;zot;&", "r+") {|f|
7308 * f.puts "bar"; f.close_write; puts f.gets
7309 * }
7310 *
7311 * <em>produces:</em>
7312 *
7313 * ["Linux\n"]
7314 * Parent is 21346
7315 * Thu Jan 15 22:41:19 JST 2009
7316 * 21346 is here, f is #<IO:fd 3>
7317 * 21352 is here, f is nil
7318 * #<Process::Status: pid 21352 exit 0>
7319 * <foo>bar;zot;
7320 */
7321
7322static VALUE
7323rb_io_s_popen(int argc, VALUE *argv, VALUE klass)
7324{
7325 VALUE pname, pmode = Qnil, opt = Qnil, env = Qnil;
7326
7327 if (argc > 1 && !NIL_P(opt = rb_check_hash_type(argv[argc-1]))) --argc;
7328 if (argc > 1 && !NIL_P(env = rb_check_hash_type(argv[0]))) --argc, ++argv;
7329 switch (argc) {
7330 case 2:
7331 pmode = argv[1];
7332 case 1:
7333 pname = argv[0];
7334 break;
7335 default:
7336 {
7337 int ex = !NIL_P(opt);
7338 rb_error_arity(argc + ex, 1 + ex, 2 + ex);
7339 }
7340 }
7341 return popen_finish(rb_io_popen(pname, pmode, env, opt), klass);
7342}
7343
7344VALUE
7345rb_io_popen(VALUE pname, VALUE pmode, VALUE env, VALUE opt)
7346{
7347 const char *modestr;
7348 VALUE tmp, execarg_obj = Qnil;
7349 int oflags, fmode;
7350 convconfig_t convconfig;
7351
7352 tmp = rb_check_array_type(pname);
7353 if (!NIL_P(tmp)) {
7354 long len = RARRAY_LEN(tmp);
7355#if SIZEOF_LONG > SIZEOF_INT
7356 if (len > INT_MAX) {
7357 rb_raise(rb_eArgError, "too many arguments");
7358 }
7359#endif
7360 execarg_obj = rb_execarg_new((int)len, RARRAY_CONST_PTR(tmp), FALSE, FALSE);
7361 RB_GC_GUARD(tmp);
7362 }
7363 else {
7364 SafeStringValue(pname);
7365 execarg_obj = Qnil;
7366 if (!is_popen_fork(pname))
7367 execarg_obj = rb_execarg_new(1, &pname, TRUE, FALSE);
7368 }
7369 if (!NIL_P(execarg_obj)) {
7370 if (!NIL_P(opt))
7371 opt = rb_execarg_extract_options(execarg_obj, opt);
7372 if (!NIL_P(env))
7373 rb_execarg_setenv(execarg_obj, env);
7374 }
7375 rb_io_extract_modeenc(&pmode, 0, opt, &oflags, &fmode, &convconfig);
7376 modestr = rb_io_oflags_modestr(oflags);
7377
7378 return pipe_open(execarg_obj, modestr, fmode, &convconfig);
7379}
7380
7381static VALUE
7382popen_finish(VALUE port, VALUE klass)
7383{
7384 if (NIL_P(port)) {
7385 /* child */
7386 if (rb_block_given_p()) {
7387 rb_yield(Qnil);
7390 _exit(0);
7391 }
7392 return Qnil;
7393 }
7394 RBASIC_SET_CLASS(port, klass);
7395 if (rb_block_given_p()) {
7396 return rb_ensure(rb_yield, port, pipe_close, port);
7397 }
7398 return port;
7399}
7400
7401static void
7402rb_scan_open_args(int argc, const VALUE *argv,
7403 VALUE *fname_p, int *oflags_p, int *fmode_p,
7404 convconfig_t *convconfig_p, mode_t *perm_p)
7405{
7406 VALUE opt, fname, vmode, vperm;
7407 int oflags, fmode;
7408 mode_t perm;
7409
7410 argc = rb_scan_args(argc, argv, "12:", &fname, &vmode, &vperm, &opt);
7411 FilePathValue(fname);
7412
7413 rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, convconfig_p);
7414
7415 perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
7416
7417 *fname_p = fname;
7418 *oflags_p = oflags;
7419 *fmode_p = fmode;
7420 *perm_p = perm;
7421}
7422
7423static VALUE
7424rb_open_file(int argc, const VALUE *argv, VALUE io)
7425{
7426 VALUE fname;
7427 int oflags, fmode;
7428 convconfig_t convconfig;
7429 mode_t perm;
7430
7431 rb_scan_open_args(argc, argv, &fname, &oflags, &fmode, &convconfig, &perm);
7432 rb_file_open_generic(io, fname, oflags, fmode, &convconfig, perm);
7433
7434 return io;
7435}
7436
7437
7438/*
7439 * Document-method: File::open
7440 *
7441 * call-seq:
7442 * File.open(filename, mode="r" [, opt]) -> file
7443 * File.open(filename [, mode [, perm]] [, opt]) -> file
7444 * File.open(filename, mode="r" [, opt]) {|file| block } -> obj
7445 * File.open(filename [, mode [, perm]] [, opt]) {|file| block } -> obj
7446 *
7447 * With no associated block, File.open is a synonym for
7448 * File.new. If the optional code block is given, it will
7449 * be passed the opened +file+ as an argument and the File object will
7450 * automatically be closed when the block terminates. The value of the block
7451 * will be returned from File.open.
7452 *
7453 * If a file is being created, its initial permissions may be set using the
7454 * +perm+ parameter. See File.new for further discussion.
7455 *
7456 * See IO.new for a description of the +mode+ and +opt+ parameters.
7457 */
7458
7459/*
7460 * Document-method: IO::open
7461 *
7462 * call-seq:
7463 * IO.open(fd, mode="r" [, opt]) -> io
7464 * IO.open(fd, mode="r" [, opt]) {|io| block } -> obj
7465 *
7466 * With no associated block, IO.open is a synonym for IO.new. If
7467 * the optional code block is given, it will be passed +io+ as an argument,
7468 * and the IO object will automatically be closed when the block terminates.
7469 * In this instance, IO.open returns the value of the block.
7470 *
7471 * See IO.new for a description of the +fd+, +mode+ and +opt+ parameters.
7472 */
7473
7474static VALUE
7475rb_io_s_open(int argc, VALUE *argv, VALUE klass)
7476{
7477 VALUE io = rb_class_new_instance_kw(argc, argv, klass, RB_PASS_CALLED_KEYWORDS);
7478
7479 if (rb_block_given_p()) {
7480 return rb_ensure(rb_yield, io, io_close, io);
7481 }
7482
7483 return io;
7484}
7485
7486/*
7487 * call-seq:
7488 * IO.sysopen(path, [mode, [perm]]) -> integer
7489 *
7490 * Opens the given path, returning the underlying file descriptor as a
7491 * Integer.
7492 *
7493 * IO.sysopen("testfile") #=> 3
7494 */
7495
7496static VALUE
7497rb_io_s_sysopen(int argc, VALUE *argv, VALUE _)
7498{
7499 VALUE fname, vmode, vperm;
7500 VALUE intmode;
7501 int oflags, fd;
7502 mode_t perm;
7503
7504 rb_scan_args(argc, argv, "12", &fname, &vmode, &vperm);
7505 FilePathValue(fname);
7506
7507 if (NIL_P(vmode))
7508 oflags = O_RDONLY;
7509 else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int")))
7510 oflags = NUM2INT(intmode);
7511 else {
7512 SafeStringValue(vmode);
7513 oflags = rb_io_modestr_oflags(StringValueCStr(vmode));
7514 }
7515 if (NIL_P(vperm)) perm = 0666;
7516 else perm = NUM2MODET(vperm);
7517
7518 RB_GC_GUARD(fname) = rb_str_new4(fname);
7519 fd = rb_sysopen(fname, oflags, perm);
7520 return INT2NUM(fd);
7521}
7522
7523static VALUE
7524check_pipe_command(VALUE filename_or_command)
7525{
7526 char *s = RSTRING_PTR(filename_or_command);
7527 long l = RSTRING_LEN(filename_or_command);
7528 char *e = s + l;
7529 int chlen;
7530
7531 if (rb_enc_ascget(s, e, &chlen, rb_enc_get(filename_or_command)) == '|') {
7532 VALUE cmd = rb_str_new(s+chlen, l-chlen);
7533 return cmd;
7534 }
7535 return Qnil;
7536}
7537
7538/*
7539 * call-seq:
7540 * open(path [, mode [, perm]] [, opt]) -> io or nil
7541 * open(path [, mode [, perm]] [, opt]) {|io| block } -> obj
7542 *
7543 * Creates an IO object connected to the given stream, file, or subprocess.
7544 *
7545 * If +path+ does not start with a pipe character (<code>|</code>), treat it
7546 * as the name of a file to open using the specified mode (defaulting to
7547 * "r").
7548 *
7549 * The +mode+ is either a string or an integer. If it is an integer, it
7550 * must be bitwise-or of open(2) flags, such as File::RDWR or File::EXCL. If
7551 * it is a string, it is either "fmode", "fmode:ext_enc", or
7552 * "fmode:ext_enc:int_enc".
7553 *
7554 * See the documentation of IO.new for full documentation of the +mode+ string
7555 * directives.
7556 *
7557 * If a file is being created, its initial permissions may be set using the
7558 * +perm+ parameter. See File.new and the open(2) and chmod(2) man pages for
7559 * a description of permissions.
7560 *
7561 * If a block is specified, it will be invoked with the IO object as a
7562 * parameter, and the IO will be automatically closed when the block
7563 * terminates. The call returns the value of the block.
7564 *
7565 * If +path+ starts with a pipe character (<code>"|"</code>), a subprocess is
7566 * created, connected to the caller by a pair of pipes. The returned IO
7567 * object may be used to write to the standard input and read from the
7568 * standard output of this subprocess.
7569 *
7570 * If the command following the pipe is a single minus sign
7571 * (<code>"|-"</code>), Ruby forks, and this subprocess is connected to the
7572 * parent. If the command is not <code>"-"</code>, the subprocess runs the
7573 * command. Note that the command may be processed by shell if it contains
7574 * shell metacharacters.
7575 *
7576 * When the subprocess is Ruby (opened via <code>"|-"</code>), the +open+
7577 * call returns +nil+. If a block is associated with the open call, that
7578 * block will run twice --- once in the parent and once in the child.
7579 *
7580 * The block parameter will be an IO object in the parent and +nil+ in the
7581 * child. The parent's +IO+ object will be connected to the child's $stdin
7582 * and $stdout. The subprocess will be terminated at the end of the block.
7583 *
7584 * === Examples
7585 *
7586 * Reading from "testfile":
7587 *
7588 * open("testfile") do |f|
7589 * print f.gets
7590 * end
7591 *
7592 * Produces:
7593 *
7594 * This is line one
7595 *
7596 * Open a subprocess and read its output:
7597 *
7598 * cmd = open("|date")
7599 * print cmd.gets
7600 * cmd.close
7601 *
7602 * Produces:
7603 *
7604 * Wed Apr 9 08:56:31 CDT 2003
7605 *
7606 * Open a subprocess running the same Ruby program:
7607 *
7608 * f = open("|-", "w+")
7609 * if f.nil?
7610 * puts "in Child"
7611 * exit
7612 * else
7613 * puts "Got: #{f.gets}"
7614 * end
7615 *
7616 * Produces:
7617 *
7618 * Got: in Child
7619 *
7620 * Open a subprocess using a block to receive the IO object:
7621 *
7622 * open "|-" do |f|
7623 * if f then
7624 * # parent process
7625 * puts "Got: #{f.gets}"
7626 * else
7627 * # child process
7628 * puts "in Child"
7629 * end
7630 * end
7631 *
7632 * Produces:
7633 *
7634 * Got: in Child
7635 */
7636
7637static VALUE
7638rb_f_open(int argc, VALUE *argv, VALUE _)
7639{
7640 ID to_open = 0;
7641 int redirect = FALSE;
7642
7643 if (argc >= 1) {
7644 CONST_ID(to_open, "to_open");
7645 if (rb_respond_to(argv[0], to_open)) {
7646 redirect = TRUE;
7647 }
7648 else {
7649 VALUE tmp = argv[0];
7650 FilePathValue(tmp);
7651 if (NIL_P(tmp)) {
7652 redirect = TRUE;
7653 }
7654 else {
7655 VALUE cmd = check_pipe_command(tmp);
7656 if (!NIL_P(cmd)) {
7657 argv[0] = cmd;
7658 return rb_io_s_popen(argc, argv, rb_cIO);
7659 }
7660 }
7661 }
7662 }
7663 if (redirect) {
7664 VALUE io = rb_funcallv_kw(argv[0], to_open, argc-1, argv+1, RB_PASS_CALLED_KEYWORDS);
7665
7666 if (rb_block_given_p()) {
7667 return rb_ensure(rb_yield, io, io_close, io);
7668 }
7669 return io;
7670 }
7671 return rb_io_s_open(argc, argv, rb_cFile);
7672}
7673
7674static VALUE rb_io_open_generic(VALUE, VALUE, int, int, const convconfig_t *, mode_t);
7675
7676static VALUE
7677rb_io_open(VALUE io, VALUE filename, VALUE vmode, VALUE vperm, VALUE opt)
7678{
7679 int oflags, fmode;
7680 convconfig_t convconfig;
7681 mode_t perm;
7682
7683 rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, &convconfig);
7684 perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
7685 return rb_io_open_generic(io, filename, oflags, fmode, &convconfig, perm);
7686}
7687
7688static VALUE
7689rb_io_open_generic(VALUE klass, VALUE filename, int oflags, int fmode,
7690 const convconfig_t *convconfig, mode_t perm)
7691{
7692 VALUE cmd;
7693 if (klass == rb_cIO && !NIL_P(cmd = check_pipe_command(filename))) {
7694 return pipe_open_s(cmd, rb_io_oflags_modestr(oflags), fmode, convconfig);
7695 }
7696 else {
7697 return rb_file_open_generic(io_alloc(klass), filename,
7698 oflags, fmode, convconfig, perm);
7699 }
7700}
7701
7702static VALUE
7703io_reopen(VALUE io, VALUE nfile)
7704{
7705 rb_io_t *fptr, *orig;
7706 int fd, fd2;
7707 off_t pos = 0;
7708
7709 nfile = rb_io_get_io(nfile);
7710 GetOpenFile(io, fptr);
7711 GetOpenFile(nfile, orig);
7712
7713 if (fptr == orig) return io;
7714 if (IS_PREP_STDIO(fptr)) {
7715 if ((fptr->stdio_file == stdin && !(orig->mode & FMODE_READABLE)) ||
7716 (fptr->stdio_file == stdout && !(orig->mode & FMODE_WRITABLE)) ||
7717 (fptr->stdio_file == stderr && !(orig->mode & FMODE_WRITABLE))) {
7718 rb_raise(rb_eArgError,
7719 "%s can't change access mode from \"%s\" to \"%s\"",
7720 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
7721 rb_io_fmode_modestr(orig->mode));
7722 }
7723 }
7724 if (fptr->mode & FMODE_WRITABLE) {
7725 if (io_fflush(fptr) < 0)
7726 rb_sys_fail_on_write(fptr);
7727 }
7728 else {
7729 flush_before_seek(fptr);
7730 }
7731 if (orig->mode & FMODE_READABLE) {
7732 pos = io_tell(orig);
7733 }
7734 if (orig->mode & FMODE_WRITABLE) {
7735 if (io_fflush(orig) < 0)
7736 rb_sys_fail_on_write(fptr);
7737 }
7738
7739 /* copy rb_io_t structure */
7740 fptr->mode = orig->mode | (fptr->mode & FMODE_PREP);
7741 fptr->pid = orig->pid;
7742 fptr->lineno = orig->lineno;
7743 if (RTEST(orig->pathv)) fptr->pathv = orig->pathv;
7744 else if (!IS_PREP_STDIO(fptr)) fptr->pathv = Qnil;
7745 fptr_copy_finalizer(fptr, orig);
7746
7747 fd = fptr->fd;
7748 fd2 = orig->fd;
7749 if (fd != fd2) {
7750 if (IS_PREP_STDIO(fptr) || fd <= 2 || !fptr->stdio_file) {
7751 /* need to keep FILE objects of stdin, stdout and stderr */
7752 if (rb_cloexec_dup2(fd2, fd) < 0)
7753 rb_sys_fail_path(orig->pathv);
7754 rb_update_max_fd(fd);
7755 }
7756 else {
7757 fclose(fptr->stdio_file);
7758 fptr->stdio_file = 0;
7759 fptr->fd = -1;
7760 if (rb_cloexec_dup2(fd2, fd) < 0)
7761 rb_sys_fail_path(orig->pathv);
7762 rb_update_max_fd(fd);
7763 fptr->fd = fd;
7764 }
7766 if ((orig->mode & FMODE_READABLE) && pos >= 0) {
7767 if (io_seek(fptr, pos, SEEK_SET) < 0 && errno) {
7768 rb_sys_fail_path(fptr->pathv);
7769 }
7770 if (io_seek(orig, pos, SEEK_SET) < 0 && errno) {
7771 rb_sys_fail_path(orig->pathv);
7772 }
7773 }
7774 }
7775
7776 if (fptr->mode & FMODE_BINMODE) {
7777 rb_io_binmode(io);
7778 }
7779
7780 RBASIC_SET_CLASS(io, rb_obj_class(nfile));
7781 return io;
7782}
7783
7784#ifdef _WIN32
7785int rb_freopen(VALUE fname, const char *mode, FILE *fp);
7786#else
7787static int
7788rb_freopen(VALUE fname, const char *mode, FILE *fp)
7789{
7790 if (!freopen(RSTRING_PTR(fname), mode, fp)) {
7791 RB_GC_GUARD(fname);
7792 return errno;
7793 }
7794 return 0;
7795}
7796#endif
7797
7798/*
7799 * call-seq:
7800 * ios.reopen(other_IO) -> ios
7801 * ios.reopen(path, mode [, opt]) -> ios
7802 *
7803 * Reassociates <em>ios</em> with the I/O stream given in
7804 * <i>other_IO</i> or to a new stream opened on <i>path</i>. This may
7805 * dynamically change the actual class of this stream.
7806 * The +mode+ and +opt+ parameters accept the same values as IO.open.
7807 *
7808 * f1 = File.new("testfile")
7809 * f2 = File.new("testfile")
7810 * f2.readlines[0] #=> "This is line one\n"
7811 * f2.reopen(f1) #=> #<File:testfile>
7812 * f2.readlines[0] #=> "This is line one\n"
7813 */
7814
7815static VALUE
7816rb_io_reopen(int argc, VALUE *argv, VALUE file)
7817{
7818 VALUE fname, nmode, opt;
7819 int oflags;
7820 rb_io_t *fptr;
7821
7822 if (rb_scan_args(argc, argv, "11:", &fname, &nmode, &opt) == 1) {
7823 VALUE tmp = rb_io_check_io(fname);
7824 if (!NIL_P(tmp)) {
7825 return io_reopen(file, tmp);
7826 }
7827 }
7828
7829 FilePathValue(fname);
7830 rb_io_taint_check(file);
7831 fptr = RFILE(file)->fptr;
7832 if (!fptr) {
7833 fptr = RFILE(file)->fptr = ZALLOC(rb_io_t);
7834 }
7835
7836 if (!NIL_P(nmode) || !NIL_P(opt)) {
7837 int fmode;
7838 convconfig_t convconfig;
7839
7840 rb_io_extract_modeenc(&nmode, 0, opt, &oflags, &fmode, &convconfig);
7841 if (IS_PREP_STDIO(fptr) &&
7842 ((fptr->mode & FMODE_READWRITE) & (fmode & FMODE_READWRITE)) !=
7843 (fptr->mode & FMODE_READWRITE)) {
7844 rb_raise(rb_eArgError,
7845 "%s can't change access mode from \"%s\" to \"%s\"",
7846 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
7847 rb_io_fmode_modestr(fmode));
7848 }
7849 fptr->mode = fmode;
7850 fptr->encs = convconfig;
7851 }
7852 else {
7853 oflags = rb_io_fmode_oflags(fptr->mode);
7854 }
7855
7856 fptr->pathv = fname;
7857 if (fptr->fd < 0) {
7858 fptr->fd = rb_sysopen(fptr->pathv, oflags, 0666);
7859 fptr->stdio_file = 0;
7860 return file;
7861 }
7862
7863 if (fptr->mode & FMODE_WRITABLE) {
7864 if (io_fflush(fptr) < 0)
7865 rb_sys_fail_on_write(fptr);
7866 }
7867 fptr->rbuf.off = fptr->rbuf.len = 0;
7868
7869 if (fptr->stdio_file) {
7870 int e = rb_freopen(rb_str_encode_ospath(fptr->pathv),
7871 rb_io_oflags_modestr(oflags),
7872 fptr->stdio_file);
7873 if (e) rb_syserr_fail_path(e, fptr->pathv);
7874 fptr->fd = fileno(fptr->stdio_file);
7875 rb_fd_fix_cloexec(fptr->fd);
7876#ifdef USE_SETVBUF
7877 if (setvbuf(fptr->stdio_file, NULL, _IOFBF, 0) != 0)
7878 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
7879#endif
7880 if (fptr->stdio_file == stderr) {
7881 if (setvbuf(fptr->stdio_file, NULL, _IONBF, BUFSIZ) != 0)
7882 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
7883 }
7884 else if (fptr->stdio_file == stdout && isatty(fptr->fd)) {
7885 if (setvbuf(fptr->stdio_file, NULL, _IOLBF, BUFSIZ) != 0)
7886 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
7887 }
7888 }
7889 else {
7890 int tmpfd = rb_sysopen(fptr->pathv, oflags, 0666);
7891 int err = 0;
7892 if (rb_cloexec_dup2(tmpfd, fptr->fd) < 0)
7893 err = errno;
7894 (void)close(tmpfd);
7895 if (err) {
7896 rb_syserr_fail_path(err, fptr->pathv);
7897 }
7898 }
7899
7900 return file;
7901}
7902
7903/* :nodoc: */
7904static VALUE
7905rb_io_init_copy(VALUE dest, VALUE io)
7906{
7907 rb_io_t *fptr, *orig;
7908 int fd;
7909 VALUE write_io;
7910 off_t pos;
7911
7912 io = rb_io_get_io(io);
7913 if (!OBJ_INIT_COPY(dest, io)) return dest;
7914 GetOpenFile(io, orig);
7915 MakeOpenFile(dest, fptr);
7916
7917 rb_io_flush(io);
7918
7919 /* copy rb_io_t structure */
7920 fptr->mode = orig->mode & ~FMODE_PREP;
7921 fptr->encs = orig->encs;
7922 fptr->pid = orig->pid;
7923 fptr->lineno = orig->lineno;
7924 if (!NIL_P(orig->pathv)) fptr->pathv = orig->pathv;
7925 fptr_copy_finalizer(fptr, orig);
7926
7927 fd = ruby_dup(orig->fd);
7928 fptr->fd = fd;
7929 pos = io_tell(orig);
7930 if (0 <= pos)
7931 io_seek(fptr, pos, SEEK_SET);
7932 if (fptr->mode & FMODE_BINMODE) {
7933 rb_io_binmode(dest);
7934 }
7935
7936 write_io = GetWriteIO(io);
7937 if (io != write_io) {
7938 write_io = rb_obj_dup(write_io);
7939 fptr->tied_io_for_writing = write_io;
7940 rb_ivar_set(dest, rb_intern("@tied_io_for_writing"), write_io);
7941 }
7942
7943 return dest;
7944}
7945
7946/*
7947 * call-seq:
7948 * ios.printf(format_string [, obj, ...]) -> nil
7949 *
7950 * Formats and writes to <em>ios</em>, converting parameters under
7951 * control of the format string. See Kernel#sprintf for details.
7952 */
7953
7954VALUE
7955rb_io_printf(int argc, const VALUE *argv, VALUE out)
7956{
7957 rb_io_write(out, rb_f_sprintf(argc, argv));
7958 return Qnil;
7959}
7960
7961/*
7962 * call-seq:
7963 * printf(io, string [, obj ... ]) -> nil
7964 * printf(string [, obj ... ]) -> nil
7965 *
7966 * Equivalent to:
7967 * io.write(sprintf(string, obj, ...))
7968 * or
7969 * $stdout.write(sprintf(string, obj, ...))
7970 */
7971
7972static VALUE
7973rb_f_printf(int argc, VALUE *argv, VALUE _)
7974{
7975 VALUE out;
7976
7977 if (argc == 0) return Qnil;
7978 if (RB_TYPE_P(argv[0], T_STRING)) {
7979 out = rb_ractor_stdout();
7980 }
7981 else {
7982 out = argv[0];
7983 argv++;
7984 argc--;
7985 }
7986 rb_io_write(out, rb_f_sprintf(argc, argv));
7987
7988 return Qnil;
7989}
7990
7991static void
7992deprecated_str_setter(VALUE val, ID id, VALUE *var)
7993{
7994 rb_str_setter(val, id, &val);
7995 if (!NIL_P(val)) {
7996 rb_warn_deprecated("`%s'", NULL, rb_id2name(id));
7997 }
7998 *var = val;
7999}
8000
8001/*
8002 * call-seq:
8003 * ios.print -> nil
8004 * ios.print(obj, ...) -> nil
8005 *
8006 * Writes the given object(s) to <em>ios</em>. Returns +nil+.
8007 *
8008 * The stream must be opened for writing.
8009 * Each given object that isn't a string will be converted by calling
8010 * its <code>to_s</code> method.
8011 * When called without arguments, prints the contents of <code>$_</code>.
8012 *
8013 * If the output field separator (<code>$,</code>) is not +nil+,
8014 * it is inserted between objects.
8015 * If the output record separator (<code>$\</code>) is not +nil+,
8016 * it is appended to the output.
8017 *
8018 * $stdout.print("This is ", 100, " percent.\n")
8019 *
8020 * <em>produces:</em>
8021 *
8022 * This is 100 percent.
8023 */
8024
8025VALUE
8026rb_io_print(int argc, const VALUE *argv, VALUE out)
8027{
8028 int i;
8029 VALUE line;
8030
8031 /* if no argument given, print `$_' */
8032 if (argc == 0) {
8033 argc = 1;
8034 line = rb_lastline_get();
8035 argv = &line;
8036 }
8037 if (argc > 1 && !NIL_P(rb_output_fs)) {
8038 rb_category_warn(RB_WARN_CATEGORY_DEPRECATED, "$, is set to non-nil value");
8039 }
8040 for (i=0; i<argc; i++) {
8041 if (!NIL_P(rb_output_fs) && i>0) {
8043 }
8044 rb_io_write(out, argv[i]);
8045 }
8046 if (argc > 0 && !NIL_P(rb_output_rs)) {
8048 }
8049
8050 return Qnil;
8051}
8052
8053/*
8054 * call-seq:
8055 * print(obj, ...) -> nil
8056 *
8057 * Prints each object in turn to <code>$stdout</code>. If the output
8058 * field separator (<code>$,</code>) is not +nil+, its
8059 * contents will appear between each field. If the output record
8060 * separator (<code>$\</code>) is not +nil+, it will be
8061 * appended to the output. If no arguments are given, prints
8062 * <code>$_</code>. Objects that aren't strings will be converted by
8063 * calling their <code>to_s</code> method.
8064 *
8065 * print "cat", [1,2,3], 99, "\n"
8066 * $, = ", "
8067 * $\ = "\n"
8068 * print "cat", [1,2,3], 99
8069 *
8070 * <em>produces:</em>
8071 *
8072 * cat12399
8073 * cat, 1, 2, 3, 99
8074 */
8075
8076static VALUE
8077rb_f_print(int argc, const VALUE *argv, VALUE _)
8078{
8079 rb_io_print(argc, argv, rb_ractor_stdout());
8080 return Qnil;
8081}
8082
8083/*
8084 * call-seq:
8085 * ios.putc(obj) -> obj
8086 *
8087 * If <i>obj</i> is Numeric, write the character whose code is the
8088 * least-significant byte of <i>obj</i>. If <i>obj</i> is String,
8089 * write the first character of <i>obj</i> to <em>ios</em>. Otherwise,
8090 * raise TypeError.
8091 *
8092 * $stdout.putc "A"
8093 * $stdout.putc 65
8094 *
8095 * <em>produces:</em>
8096 *
8097 * AA
8098 */
8099
8100static VALUE
8101rb_io_putc(VALUE io, VALUE ch)
8102{
8103 VALUE str;
8104 if (RB_TYPE_P(ch, T_STRING)) {
8105 str = rb_str_substr(ch, 0, 1);
8106 }
8107 else {
8108 char c = NUM2CHR(ch);
8109 str = rb_str_new(&c, 1);
8110 }
8111 rb_io_write(io, str);
8112 return ch;
8113}
8114
8115#define forward(obj, id, argc, argv) \
8116 rb_funcallv_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8117#define forward_public(obj, id, argc, argv) \
8118 rb_funcallv_public_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8119#define forward_current(id, argc, argv) \
8120 forward_public(ARGF.current_file, id, argc, argv)
8121
8122/*
8123 * call-seq:
8124 * putc(int) -> int
8125 *
8126 * Equivalent to:
8127 *
8128 * $stdout.putc(int)
8129 *
8130 * Refer to the documentation for IO#putc for important information regarding
8131 * multi-byte characters.
8132 */
8133
8134static VALUE
8135rb_f_putc(VALUE recv, VALUE ch)
8136{
8137 VALUE r_stdout = rb_ractor_stdout();
8138 if (recv == r_stdout) {
8139 return rb_io_putc(recv, ch);
8140 }
8141 return forward(r_stdout, rb_intern("putc"), 1, &ch);
8142}
8143
8144
8145int
8146rb_str_end_with_asciichar(VALUE str, int c)
8147{
8148 long len = RSTRING_LEN(str);
8149 const char *ptr = RSTRING_PTR(str);
8151 int n;
8152
8153 if (len == 0) return 0;
8154 if ((n = rb_enc_mbminlen(enc)) == 1) {
8155 return ptr[len - 1] == c;
8156 }
8157 return rb_enc_ascget(ptr + ((len - 1) / n) * n, ptr + len, &n, enc) == c;
8158}
8159
8160static VALUE
8161io_puts_ary(VALUE ary, VALUE out, int recur)
8162{
8163 VALUE tmp;
8164 long i;
8165
8166 if (recur) {
8167 tmp = rb_str_new2("[...]");
8168 rb_io_puts(1, &tmp, out);
8169 return Qtrue;
8170 }
8171 ary = rb_check_array_type(ary);
8172 if (NIL_P(ary)) return Qfalse;
8173 for (i=0; i<RARRAY_LEN(ary); i++) {
8174 tmp = RARRAY_AREF(ary, i);
8175 rb_io_puts(1, &tmp, out);
8176 }
8177 return Qtrue;
8178}
8179
8180/*
8181 * call-seq:
8182 * ios.puts(obj, ...) -> nil
8183 *
8184 * Writes the given object(s) to <em>ios</em>.
8185 * Writes a newline after any that do not already end
8186 * with a newline sequence. Returns +nil+.
8187 *
8188 * The stream must be opened for writing.
8189 * If called with an array argument, writes each element on a new line.
8190 * Each given object that isn't a string or array will be converted
8191 * by calling its +to_s+ method.
8192 * If called without arguments, outputs a single newline.
8193 *
8194 * $stdout.puts("this", "is", ["a", "test"])
8195 *
8196 * <em>produces:</em>
8197 *
8198 * this
8199 * is
8200 * a
8201 * test
8202 *
8203 * Note that +puts+ always uses newlines and is not affected
8204 * by the output record separator (<code>$\</code>).
8205 */
8206
8207VALUE
8208rb_io_puts(int argc, const VALUE *argv, VALUE out)
8209{
8210 int i, n;
8211 VALUE line, args[2];
8212
8213 /* if no argument given, print newline. */
8214 if (argc == 0) {
8216 return Qnil;
8217 }
8218 for (i=0; i<argc; i++) {
8219 if (RB_TYPE_P(argv[i], T_STRING)) {
8220 line = argv[i];
8221 goto string;
8222 }
8223 if (rb_exec_recursive(io_puts_ary, argv[i], out)) {
8224 continue;
8225 }
8226 line = rb_obj_as_string(argv[i]);
8227 string:
8228 n = 0;
8229 args[n++] = line;
8230 if (RSTRING_LEN(line) == 0 ||
8231 !rb_str_end_with_asciichar(line, '\n')) {
8232 args[n++] = rb_default_rs;
8233 }
8234 rb_io_writev(out, n, args);
8235 }
8236
8237 return Qnil;
8238}
8239
8240/*
8241 * call-seq:
8242 * puts(obj, ...) -> nil
8243 *
8244 * Equivalent to
8245 *
8246 * $stdout.puts(obj, ...)
8247 */
8248
8249static VALUE
8250rb_f_puts(int argc, VALUE *argv, VALUE recv)
8251{
8252 VALUE r_stdout = rb_ractor_stdout();
8253 if (recv == r_stdout) {
8254 return rb_io_puts(argc, argv, recv);
8255 }
8256 return forward(r_stdout, rb_intern("puts"), argc, argv);
8257}
8258
8259static VALUE
8260rb_p_write(VALUE str)
8261{
8262 VALUE args[2];
8263 args[0] = str;
8264 args[1] = rb_default_rs;
8265 VALUE r_stdout = rb_ractor_stdout();
8266 if (RB_TYPE_P(r_stdout, T_FILE) &&
8267 rb_method_basic_definition_p(CLASS_OF(r_stdout), id_write)) {
8268 io_writev(2, args, r_stdout);
8269 }
8270 else {
8271 rb_io_writev(r_stdout, 2, args);
8272 }
8273 return Qnil;
8274}
8275
8276void
8277rb_p(VALUE obj) /* for debug print within C code */
8278{
8279 rb_p_write(rb_obj_as_string(rb_inspect(obj)));
8280}
8281
8282static VALUE
8283rb_p_result(int argc, const VALUE *argv)
8284{
8285 VALUE ret = Qnil;
8286
8287 if (argc == 1) {
8288 ret = argv[0];
8289 }
8290 else if (argc > 1) {
8291 ret = rb_ary_new4(argc, argv);
8292 }
8293 VALUE r_stdout = rb_ractor_stdout();
8294 if (RB_TYPE_P(r_stdout, T_FILE)) {
8295 rb_io_flush(r_stdout);
8296 }
8297 return ret;
8298}
8299
8300/*
8301 * call-seq:
8302 * p(obj) -> obj
8303 * p(obj1, obj2, ...) -> [obj, ...]
8304 * p() -> nil
8305 *
8306 * For each object, directly writes _obj_.+inspect+ followed by a
8307 * newline to the program's standard output.
8308 *
8309 * S = Struct.new(:name, :state)
8310 * s = S['dave', 'TX']
8311 * p s
8312 *
8313 * <em>produces:</em>
8314 *
8315 * #<S name="dave", state="TX">
8316 */
8317
8318static VALUE
8319rb_f_p(int argc, VALUE *argv, VALUE self)
8320{
8321 int i;
8322 for (i=0; i<argc; i++) {
8323 VALUE inspected = rb_obj_as_string(rb_inspect(argv[i]));
8324 rb_uninterruptible(rb_p_write, inspected);
8325 }
8326 return rb_p_result(argc, argv);
8327}
8328
8329/*
8330 * call-seq:
8331 * obj.display(port=$>) -> nil
8332 *
8333 * Prints <i>obj</i> on the given port (default <code>$></code>).
8334 * Equivalent to:
8335 *
8336 * def display(port=$>)
8337 * port.write self
8338 * nil
8339 * end
8340 *
8341 * For example:
8342 *
8343 * 1.display
8344 * "cat".display
8345 * [ 4, 5, 6 ].display
8346 * puts
8347 *
8348 * <em>produces:</em>
8349 *
8350 * 1cat[4, 5, 6]
8351 */
8352
8353static VALUE
8354rb_obj_display(int argc, VALUE *argv, VALUE self)
8355{
8356 VALUE out;
8357
8358 out = (!rb_check_arity(argc, 0, 1) ? rb_ractor_stdout() : argv[0]);
8359 rb_io_write(out, self);
8360
8361 return Qnil;
8362}
8363
8364static int
8365rb_stderr_to_original_p(VALUE err)
8366{
8367 return (err == orig_stderr || RFILE(orig_stderr)->fptr->fd < 0);
8368}
8369
8370void
8371rb_write_error2(const char *mesg, long len)
8372{
8373 VALUE out = rb_ractor_stderr();
8374 if (rb_stderr_to_original_p(out)) {
8375#ifdef _WIN32
8376 if (isatty(fileno(stderr))) {
8377 if (rb_w32_write_console(rb_str_new(mesg, len), fileno(stderr)) > 0) return;
8378 }
8379#endif
8380 if (fwrite(mesg, sizeof(char), (size_t)len, stderr) < (size_t)len) {
8381 /* failed to write to stderr, what can we do? */
8382 return;
8383 }
8384 }
8385 else {
8386 rb_io_write(out, rb_str_new(mesg, len));
8387 }
8388}
8389
8390void
8391rb_write_error(const char *mesg)
8392{
8393 rb_write_error2(mesg, strlen(mesg));
8394}
8395
8396void
8397rb_write_error_str(VALUE mesg)
8398{
8399 VALUE out = rb_ractor_stderr();
8400 /* a stopgap measure for the time being */
8401 if (rb_stderr_to_original_p(out)) {
8402 size_t len = (size_t)RSTRING_LEN(mesg);
8403#ifdef _WIN32
8404 if (isatty(fileno(stderr))) {
8405 if (rb_w32_write_console(mesg, fileno(stderr)) > 0) return;
8406 }
8407#endif
8408 if (fwrite(RSTRING_PTR(mesg), sizeof(char), len, stderr) < len) {
8409 RB_GC_GUARD(mesg);
8410 return;
8411 }
8412 }
8413 else {
8414 /* may unlock GVL, and */
8415 rb_io_write(out, mesg);
8416 }
8417}
8418
8419int
8420rb_stderr_tty_p(void)
8421{
8422 if (rb_stderr_to_original_p(rb_ractor_stderr()))
8423 return isatty(fileno(stderr));
8424 return 0;
8425}
8426
8427static void
8428must_respond_to(ID mid, VALUE val, ID id)
8429{
8430 if (!rb_respond_to(val, mid)) {
8431 rb_raise(rb_eTypeError, "%"PRIsVALUE" must have %"PRIsVALUE" method, %"PRIsVALUE" given",
8432 rb_id2str(id), rb_id2str(mid),
8433 rb_obj_class(val));
8434 }
8435}
8436
8437static void
8438stdin_setter(VALUE val, ID id, VALUE *ptr)
8439{
8441}
8442
8443static VALUE
8444stdin_getter(ID id, VALUE *ptr)
8445{
8446 return rb_ractor_stdin();
8447}
8448
8449static void
8450stdout_setter(VALUE val, ID id, VALUE *ptr)
8451{
8452 must_respond_to(id_write, val, id);
8454}
8455
8456static VALUE
8457stdout_getter(ID id, VALUE *ptr)
8458{
8459 return rb_ractor_stdout();
8460}
8461
8462static void
8463stderr_setter(VALUE val, ID id, VALUE *ptr)
8464{
8465 must_respond_to(id_write, val, id);
8467}
8468
8469static VALUE
8470stderr_getter(ID id, VALUE *ptr)
8471{
8472 return rb_ractor_stderr();
8473}
8474
8475static VALUE
8476prep_io(int fd, int fmode, VALUE klass, const char *path)
8477{
8478 rb_io_t *fp;
8479 VALUE io = io_alloc(klass);
8480
8481 MakeOpenFile(io, fp);
8482 fp->self = io;
8483 fp->fd = fd;
8484 fp->mode = fmode;
8485 if (!io_check_tty(fp)) {
8486#ifdef __CYGWIN__
8487 fp->mode |= FMODE_BINMODE;
8488 setmode(fd, O_BINARY);
8489#endif
8490 }
8491 if (path) fp->pathv = rb_obj_freeze(rb_str_new_cstr(path));
8492 rb_update_max_fd(fd);
8493
8494 return io;
8495}
8496
8497VALUE
8498rb_io_fdopen(int fd, int oflags, const char *path)
8499{
8500 VALUE klass = rb_cIO;
8501
8502 if (path && strcmp(path, "-")) klass = rb_cFile;
8503 return prep_io(fd, rb_io_oflags_fmode(oflags), klass, path);
8504}
8505
8506static VALUE
8507prep_stdio(FILE *f, int fmode, VALUE klass, const char *path)
8508{
8509 rb_io_t *fptr;
8510 VALUE io = prep_io(fileno(f), fmode|FMODE_PREP|DEFAULT_TEXTMODE, klass, path);
8511
8512 GetOpenFile(io, fptr);
8514#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
8515 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
8516 if (fmode & FMODE_READABLE) {
8518 }
8519#endif
8520 fptr->stdio_file = f;
8521
8522 return io;
8523}
8524
8525VALUE
8526rb_io_prep_stdin(void)
8527{
8528 return prep_stdio(stdin, FMODE_READABLE, rb_cIO, "<STDIN>");
8529}
8530
8531VALUE
8532rb_io_prep_stdout(void)
8533{
8534 return prep_stdio(stdout, FMODE_WRITABLE|FMODE_SIGNAL_ON_EPIPE, rb_cIO, "<STDOUT>");
8535}
8536
8537VALUE
8538rb_io_prep_stderr(void)
8539{
8540 return prep_stdio(stderr, FMODE_WRITABLE|FMODE_SYNC, rb_cIO, "<STDERR>");
8541}
8542
8543FILE *
8545{
8546 if (!fptr->stdio_file) {
8547 int oflags = rb_io_fmode_oflags(fptr->mode) & ~O_EXCL;
8548 fptr->stdio_file = rb_fdopen(fptr->fd, rb_io_oflags_modestr(oflags));
8549 }
8550 return fptr->stdio_file;
8551}
8552
8553static inline void
8554rb_io_buffer_init(rb_io_buffer_t *buf)
8555{
8556 buf->ptr = NULL;
8557 buf->off = 0;
8558 buf->len = 0;
8559 buf->capa = 0;
8560}
8561
8562static inline rb_io_t *
8563rb_io_fptr_new(void)
8564{
8565 rb_io_t *fp = ALLOC(rb_io_t);
8566 fp->self = Qnil;
8567 fp->fd = -1;
8568 fp->stdio_file = NULL;
8569 fp->mode = 0;
8570 fp->pid = 0;
8571 fp->lineno = 0;
8572 fp->pathv = Qnil;
8573 fp->finalize = 0;
8574 rb_io_buffer_init(&fp->wbuf);
8575 rb_io_buffer_init(&fp->rbuf);
8576 rb_io_buffer_init(&fp->cbuf);
8577 fp->readconv = NULL;
8578 fp->writeconv = NULL;
8580 fp->writeconv_pre_ecflags = 0;
8582 fp->writeconv_initialized = 0;
8583 fp->tied_io_for_writing = 0;
8584 fp->encs.enc = NULL;
8585 fp->encs.enc2 = NULL;
8586 fp->encs.ecflags = 0;
8587 fp->encs.ecopts = Qnil;
8588 fp->write_lock = 0;
8589 return fp;
8590}
8591
8592rb_io_t *
8593rb_io_make_open_file(VALUE obj)
8594{
8595 rb_io_t *fp = 0;
8596
8597 Check_Type(obj, T_FILE);
8598 if (RFILE(obj)->fptr) {
8599 rb_io_close(obj);
8600 rb_io_fptr_finalize(RFILE(obj)->fptr);
8601 RFILE(obj)->fptr = 0;
8602 }
8603 fp = rb_io_fptr_new();
8604 fp->self = obj;
8605 RFILE(obj)->fptr = fp;
8606 return fp;
8607}
8608
8609/*
8610 * call-seq:
8611 * IO.new(fd [, mode] [, opt]) -> io
8612 *
8613 * Returns a new IO object (a stream) for the given integer file descriptor
8614 * +fd+ and +mode+ string. +opt+ may be used to specify parts of +mode+ in a
8615 * more readable fashion. See also IO.sysopen and IO.for_fd.
8616 *
8617 * IO.new is called by various File and IO opening methods such as IO::open,
8618 * Kernel#open, and File::open.
8619 *
8620 * === Open Mode
8621 *
8622 * When +mode+ is an integer it must be combination of the modes defined in
8623 * File::Constants (+File::RDONLY+, <code>File::WRONLY|File::CREAT</code>).
8624 * See the open(2) man page for more information.
8625 *
8626 * When +mode+ is a string it must be in one of the following forms:
8627 *
8628 * fmode
8629 * fmode ":" ext_enc
8630 * fmode ":" ext_enc ":" int_enc
8631 * fmode ":" "BOM|UTF-*"
8632 *
8633 * +fmode+ is an IO open mode string, +ext_enc+ is the external encoding for
8634 * the IO and +int_enc+ is the internal encoding.
8635 *
8636 * ==== IO Open Mode
8637 *
8638 * Ruby allows the following open modes:
8639 *
8640 * "r" Read-only, starts at beginning of file (default mode).
8641 *
8642 * "r+" Read-write, starts at beginning of file.
8643 *
8644 * "w" Write-only, truncates existing file
8645 * to zero length or creates a new file for writing.
8646 *
8647 * "w+" Read-write, truncates existing file to zero length
8648 * or creates a new file for reading and writing.
8649 *
8650 * "a" Write-only, each write call appends data at end of file.
8651 * Creates a new file for writing if file does not exist.
8652 *
8653 * "a+" Read-write, each write call appends data at end of file.
8654 * Creates a new file for reading and writing if file does
8655 * not exist.
8656 *
8657 * The following modes must be used separately, and along with one or more of
8658 * the modes seen above.
8659 *
8660 * "b" Binary file mode
8661 * Suppresses EOL <-> CRLF conversion on Windows. And
8662 * sets external encoding to ASCII-8BIT unless explicitly
8663 * specified.
8664 *
8665 * "t" Text file mode
8666 *
8667 * The exclusive access mode ("x") can be used together with "w" to ensure
8668 * the file is created. Errno::EEXIST is raised when it already exists.
8669 * It may not be supported with all kinds of streams (e.g. pipes).
8670 *
8671 * When the open mode of original IO is read only, the mode cannot be
8672 * changed to be writable. Similarly, the open mode cannot be changed from
8673 * write only to readable.
8674 *
8675 * When such a change is attempted the error is raised in different locations
8676 * according to the platform.
8677 *
8678 * === IO Encoding
8679 *
8680 * When +ext_enc+ is specified, strings read will be tagged by the encoding
8681 * when reading, and strings output will be converted to the specified
8682 * encoding when writing.
8683 *
8684 * When +ext_enc+ and +int_enc+ are specified read strings will be converted
8685 * from +ext_enc+ to +int_enc+ upon input, and written strings will be
8686 * converted from +int_enc+ to +ext_enc+ upon output. See Encoding for
8687 * further details of transcoding on input and output.
8688 *
8689 * If "BOM|UTF-8", "BOM|UTF-16LE" or "BOM|UTF16-BE" are used, Ruby checks for
8690 * a Unicode BOM in the input document to help determine the encoding. For
8691 * UTF-16 encodings the file open mode must be binary. When present, the BOM
8692 * is stripped and the external encoding from the BOM is used. When the BOM
8693 * is missing the given Unicode encoding is used as +ext_enc+. (The BOM-set
8694 * encoding option is case insensitive, so "bom|utf-8" is also valid.)
8695 *
8696 * === Options
8697 *
8698 * +opt+ can be used instead of +mode+ for improved readability. The
8699 * following keys are supported:
8700 *
8701 * :mode ::
8702 * Same as +mode+ parameter
8703 *
8704 * :flags ::
8705 * Specifies file open flags as integer.
8706 * If +mode+ parameter is given, this parameter will be bitwise-ORed.
8707 *
8708 * :\external_encoding ::
8709 * External encoding for the IO.
8710 *
8711 * :\internal_encoding ::
8712 * Internal encoding for the IO. "-" is a synonym for the default internal
8713 * encoding.
8714 *
8715 * If the value is +nil+ no conversion occurs.
8716 *
8717 * :encoding ::
8718 * Specifies external and internal encodings as "extern:intern".
8719 *
8720 * :textmode ::
8721 * If the value is truth value, same as "t" in argument +mode+.
8722 *
8723 * :binmode ::
8724 * If the value is truth value, same as "b" in argument +mode+.
8725 *
8726 * :autoclose ::
8727 * If the value is +false+, the +fd+ will be kept open after this IO
8728 * instance gets finalized.
8729 *
8730 * Also, +opt+ can have same keys in String#encode for controlling conversion
8731 * between the external encoding and the internal encoding.
8732 *
8733 * === Example 1
8734 *
8735 * fd = IO.sysopen("/dev/tty", "w")
8736 * a = IO.new(fd,"w")
8737 * $stderr.puts "Hello"
8738 * a.puts "World"
8739 *
8740 * Produces:
8741 *
8742 * Hello
8743 * World
8744 *
8745 * === Example 2
8746 *
8747 * require 'fcntl'
8748 *
8749 * fd = STDERR.fcntl(Fcntl::F_DUPFD)
8750 * io = IO.new(fd, mode: 'w:UTF-16LE', cr_newline: true)
8751 * io.puts "Hello, World!"
8752 *
8753 * fd = STDERR.fcntl(Fcntl::F_DUPFD)
8754 * io = IO.new(fd, mode: 'w', cr_newline: true,
8755 * external_encoding: Encoding::UTF_16LE)
8756 * io.puts "Hello, World!"
8757 *
8758 * Both of above print "Hello, World!" in UTF-16LE to standard error output
8759 * with converting EOL generated by #puts to CR.
8760 */
8761
8762static VALUE
8763rb_io_initialize(int argc, VALUE *argv, VALUE io)
8764{
8765 VALUE fnum, vmode;
8766 rb_io_t *fp;
8767 int fd, fmode, oflags = O_RDONLY;
8768 convconfig_t convconfig;
8769 VALUE opt;
8770#if defined(HAVE_FCNTL) && defined(F_GETFL)
8771 int ofmode;
8772#else
8773 struct stat st;
8774#endif
8775
8776
8777 argc = rb_scan_args(argc, argv, "11:", &fnum, &vmode, &opt);
8778 rb_io_extract_modeenc(&vmode, 0, opt, &oflags, &fmode, &convconfig);
8779
8780 fd = NUM2INT(fnum);
8781 if (rb_reserved_fd_p(fd)) {
8782 rb_raise(rb_eArgError, "The given fd is not accessible because RubyVM reserves it");
8783 }
8784#if defined(HAVE_FCNTL) && defined(F_GETFL)
8785 oflags = fcntl(fd, F_GETFL);
8786 if (oflags == -1) rb_sys_fail(0);
8787#else
8788 if (fstat(fd, &st) < 0) rb_sys_fail(0);
8789#endif
8790 rb_update_max_fd(fd);
8791#if defined(HAVE_FCNTL) && defined(F_GETFL)
8792 ofmode = rb_io_oflags_fmode(oflags);
8793 if (NIL_P(vmode)) {
8794 fmode = ofmode;
8795 }
8796 else if ((~ofmode & fmode) & FMODE_READWRITE) {
8797 VALUE error = INT2FIX(EINVAL);
8798 rb_exc_raise(rb_class_new_instance(1, &error, rb_eSystemCallError));
8799 }
8800#endif
8801 if (!NIL_P(opt) && rb_hash_aref(opt, sym_autoclose) == Qfalse) {
8802 fmode |= FMODE_PREP;
8803 }
8804 MakeOpenFile(io, fp);
8805 fp->self = io;
8806 fp->fd = fd;
8807 fp->mode = fmode;
8808 fp->encs = convconfig;
8809 clear_codeconv(fp);
8810 io_check_tty(fp);
8811 if (fileno(stdin) == fd)
8812 fp->stdio_file = stdin;
8813 else if (fileno(stdout) == fd)
8814 fp->stdio_file = stdout;
8815 else if (fileno(stderr) == fd)
8816 fp->stdio_file = stderr;
8817
8818 if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
8819 return io;
8820}
8821
8822/*
8823 * call-seq:
8824 * ios.set_encoding_by_bom -> encoding or nil
8825 *
8826 * Checks if +ios+ starts with a BOM, and then consumes it and sets
8827 * the external encoding. Returns the result encoding if found, or
8828 * nil. If +ios+ is not binmode or its encoding has been set
8829 * already, an exception will be raised.
8830 *
8831 * File.write("bom.txt", "\u{FEFF}abc")
8832 * ios = File.open("bom.txt", "rb")
8833 * ios.set_encoding_by_bom #=> #<Encoding:UTF-8>
8834 *
8835 * File.write("nobom.txt", "abc")
8836 * ios = File.open("nobom.txt", "rb")
8837 * ios.set_encoding_by_bom #=> nil
8838 */
8839
8840static VALUE
8841rb_io_set_encoding_by_bom(VALUE io)
8842{
8843 rb_io_t *fptr;
8844
8845 GetOpenFile(io, fptr);
8846 if (!(fptr->mode & FMODE_BINMODE)) {
8847 rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
8848 }
8849 if (fptr->encs.enc2) {
8850 rb_raise(rb_eArgError, "encoding conversion is set");
8851 }
8852 else if (fptr->encs.enc && fptr->encs.enc != rb_ascii8bit_encoding()) {
8853 rb_raise(rb_eArgError, "encoding is set to %s already",
8854 rb_enc_name(fptr->encs.enc));
8855 }
8856 if (!io_set_encoding_by_bom(io)) return Qnil;
8857 return rb_enc_from_encoding(fptr->encs.enc);
8858}
8859
8860/*
8861 * call-seq:
8862 * File.new(filename, mode="r" [, opt]) -> file
8863 * File.new(filename [, mode [, perm]] [, opt]) -> file
8864 *
8865 * Opens the file named by +filename+ according to the given +mode+ and
8866 * returns a new File object.
8867 *
8868 * See IO.new for a description of +mode+ and +opt+.
8869 *
8870 * If a file is being created, permission bits may be given in +perm+. These
8871 * mode and permission bits are platform dependent; on Unix systems, see
8872 * open(2) and chmod(2) man pages for details.
8873 *
8874 * The new File object is buffered mode (or non-sync mode), unless
8875 * +filename+ is a tty.
8876 * See IO#flush, IO#fsync, IO#fdatasync, and IO#sync= about sync mode.
8877 *
8878 * === Examples
8879 *
8880 * f = File.new("testfile", "r")
8881 * f = File.new("newfile", "w+")
8882 * f = File.new("newfile", File::CREAT|File::TRUNC|File::RDWR, 0644)
8883 */
8884
8885static VALUE
8886rb_file_initialize(int argc, VALUE *argv, VALUE io)
8887{
8888 if (RFILE(io)->fptr) {
8889 rb_raise(rb_eRuntimeError, "reinitializing File");
8890 }
8891 if (0 < argc && argc < 3) {
8892 VALUE fd = rb_check_to_int(argv[0]);
8893
8894 if (!NIL_P(fd)) {
8895 argv[0] = fd;
8896 return rb_io_initialize(argc, argv, io);
8897 }
8898 }
8899 rb_open_file(argc, argv, io);
8900
8901 return io;
8902}
8903
8904/* :nodoc: */
8905static VALUE
8906rb_io_s_new(int argc, VALUE *argv, VALUE klass)
8907{
8908 if (rb_block_given_p()) {
8909 VALUE cname = rb_obj_as_string(klass);
8910
8911 rb_warn("%"PRIsVALUE"::new() does not take block; use %"PRIsVALUE"::open() instead",
8912 cname, cname);
8913 }
8914 return rb_class_new_instance_kw(argc, argv, klass, RB_PASS_CALLED_KEYWORDS);
8915}
8916
8917
8918/*
8919 * call-seq:
8920 * IO.for_fd(fd, mode [, opt]) -> io
8921 *
8922 * Synonym for IO.new.
8923 *
8924 */
8925
8926static VALUE
8927rb_io_s_for_fd(int argc, VALUE *argv, VALUE klass)
8928{
8929 VALUE io = rb_obj_alloc(klass);
8930 rb_io_initialize(argc, argv, io);
8931 return io;
8932}
8933
8934/*
8935 * call-seq:
8936 * ios.autoclose? -> true or false
8937 *
8938 * Returns +true+ if the underlying file descriptor of _ios_ will be
8939 * closed automatically at its finalization, otherwise +false+.
8940 */
8941
8942static VALUE
8943rb_io_autoclose_p(VALUE io)
8944{
8945 rb_io_t *fptr = RFILE(io)->fptr;
8946 rb_io_check_closed(fptr);
8947 return (fptr->mode & FMODE_PREP) ? Qfalse : Qtrue;
8948}
8949
8950/*
8951 * call-seq:
8952 * io.autoclose = bool -> true or false
8953 *
8954 * Sets auto-close flag.
8955 *
8956 * f = open("/dev/null")
8957 * IO.for_fd(f.fileno)
8958 * # ...
8959 * f.gets # may cause Errno::EBADF
8960 *
8961 * f = open("/dev/null")
8962 * IO.for_fd(f.fileno).autoclose = false
8963 * # ...
8964 * f.gets # won't cause Errno::EBADF
8965 */
8966
8967static VALUE
8968rb_io_set_autoclose(VALUE io, VALUE autoclose)
8969{
8970 rb_io_t *fptr;
8971 GetOpenFile(io, fptr);
8972 if (!RTEST(autoclose))
8973 fptr->mode |= FMODE_PREP;
8974 else
8975 fptr->mode &= ~FMODE_PREP;
8976 return autoclose;
8977}
8978
8979static void
8980argf_mark(void *ptr)
8981{
8982 struct argf *p = ptr;
8983 rb_gc_mark(p->filename);
8984 rb_gc_mark(p->current_file);
8985 rb_gc_mark(p->argv);
8986 rb_gc_mark(p->inplace);
8987 rb_gc_mark(p->encs.ecopts);
8988}
8989
8990static size_t
8991argf_memsize(const void *ptr)
8992{
8993 const struct argf *p = ptr;
8994 size_t size = sizeof(*p);
8995 return size;
8996}
8997
8998static const rb_data_type_t argf_type = {
8999 "ARGF",
9000 {argf_mark, RUBY_TYPED_DEFAULT_FREE, argf_memsize},
9001 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
9002};
9003
9004static inline void
9005argf_init(struct argf *p, VALUE v)
9006{
9007 p->filename = Qnil;
9008 p->current_file = Qnil;
9009 p->lineno = 0;
9010 p->argv = v;
9011}
9012
9013static VALUE
9014argf_alloc(VALUE klass)
9015{
9016 struct argf *p;
9017 VALUE argf = TypedData_Make_Struct(klass, struct argf, &argf_type, p);
9018
9019 argf_init(p, Qnil);
9020 return argf;
9021}
9022
9023#undef rb_argv
9024
9025/* :nodoc: */
9026static VALUE
9027argf_initialize(VALUE argf, VALUE argv)
9028{
9029 memset(&ARGF, 0, sizeof(ARGF));
9030 argf_init(&ARGF, argv);
9031
9032 return argf;
9033}
9034
9035/* :nodoc: */
9036static VALUE
9037argf_initialize_copy(VALUE argf, VALUE orig)
9038{
9039 if (!OBJ_INIT_COPY(argf, orig)) return argf;
9040 ARGF = argf_of(orig);
9041 ARGF.argv = rb_obj_dup(ARGF.argv);
9042 return argf;
9043}
9044
9045/*
9046 * call-seq:
9047 * ARGF.lineno = integer -> integer
9048 *
9049 * Sets the line number of +ARGF+ as a whole to the given +Integer+.
9050 *
9051 * +ARGF+ sets the line number automatically as you read data, so normally
9052 * you will not need to set it explicitly. To access the current line number
9053 * use +ARGF.lineno+.
9054 *
9055 * For example:
9056 *
9057 * ARGF.lineno #=> 0
9058 * ARGF.readline #=> "This is line 1\n"
9059 * ARGF.lineno #=> 1
9060 * ARGF.lineno = 0 #=> 0
9061 * ARGF.lineno #=> 0
9062 */
9063static VALUE
9064argf_set_lineno(VALUE argf, VALUE val)
9065{
9066 ARGF.lineno = NUM2INT(val);
9067 ARGF.last_lineno = ARGF.lineno;
9068 return Qnil;
9069}
9070
9071/*
9072 * call-seq:
9073 * ARGF.lineno -> integer
9074 *
9075 * Returns the current line number of ARGF as a whole. This value
9076 * can be set manually with +ARGF.lineno=+.
9077 *
9078 * For example:
9079 *
9080 * ARGF.lineno #=> 0
9081 * ARGF.readline #=> "This is line 1\n"
9082 * ARGF.lineno #=> 1
9083 */
9084static VALUE
9085argf_lineno(VALUE argf)
9086{
9087 return INT2FIX(ARGF.lineno);
9088}
9089
9090static VALUE
9091argf_forward(int argc, VALUE *argv, VALUE argf)
9092{
9093 return forward_current(rb_frame_this_func(), argc, argv);
9094}
9095
9096#define next_argv() argf_next_argv(argf)
9097#define ARGF_GENERIC_INPUT_P() \
9098 (ARGF.current_file == rb_stdin && !RB_TYPE_P(ARGF.current_file, T_FILE))
9099#define ARGF_FORWARD(argc, argv) do {\
9100 if (ARGF_GENERIC_INPUT_P())\
9101 return argf_forward((argc), (argv), argf);\
9102} while (0)
9103#define NEXT_ARGF_FORWARD(argc, argv) do {\
9104 if (!next_argv()) return Qnil;\
9105 ARGF_FORWARD((argc), (argv));\
9106} while (0)
9107
9108static void
9109argf_close(VALUE argf)
9110{
9111 VALUE file = ARGF.current_file;
9112 if (file == rb_stdin) return;
9113 if (RB_TYPE_P(file, T_FILE)) {
9114 rb_io_set_write_io(file, Qnil);
9115 }
9116 io_close(file);
9117 ARGF.init_p = -1;
9118}
9119
9120static int
9121argf_next_argv(VALUE argf)
9122{
9123 char *fn;
9124 rb_io_t *fptr;
9125 int stdout_binmode = 0;
9126 int fmode;
9127
9128 VALUE r_stdout = rb_ractor_stdout();
9129
9130 if (RB_TYPE_P(r_stdout, T_FILE)) {
9131 GetOpenFile(r_stdout, fptr);
9132 if (fptr->mode & FMODE_BINMODE)
9133 stdout_binmode = 1;
9134 }
9135
9136 if (ARGF.init_p == 0) {
9137 if (!NIL_P(ARGF.argv) && RARRAY_LEN(ARGF.argv) > 0) {
9138 ARGF.next_p = 1;
9139 }
9140 else {
9141 ARGF.next_p = -1;
9142 }
9143 ARGF.init_p = 1;
9144 }
9145 else {
9146 if (NIL_P(ARGF.argv)) {
9147 ARGF.next_p = -1;
9148 }
9149 else if (ARGF.next_p == -1 && RARRAY_LEN(ARGF.argv) > 0) {
9150 ARGF.next_p = 1;
9151 }
9152 }
9153
9154 if (ARGF.next_p == 1) {
9155 if (ARGF.init_p == 1) argf_close(argf);
9156 retry:
9157 if (RARRAY_LEN(ARGF.argv) > 0) {
9158 VALUE filename = rb_ary_shift(ARGF.argv);
9159 FilePathValue(filename);
9160 ARGF.filename = filename;
9161 filename = rb_str_encode_ospath(filename);
9162 fn = StringValueCStr(filename);
9163 if (RSTRING_LEN(filename) == 1 && fn[0] == '-') {
9164 ARGF.current_file = rb_stdin;
9165 if (ARGF.inplace) {
9166 rb_warn("Can't do inplace edit for stdio; skipping");
9167 goto retry;
9168 }
9169 }
9170 else {
9171 VALUE write_io = Qnil;
9172 int fr = rb_sysopen(filename, O_RDONLY, 0);
9173
9174 if (ARGF.inplace) {
9175 struct stat st;
9176#ifndef NO_SAFE_RENAME
9177 struct stat st2;
9178#endif
9179 VALUE str;
9180 int fw;
9181
9182 if (RB_TYPE_P(r_stdout, T_FILE) && r_stdout != orig_stdout) {
9183 rb_io_close(r_stdout);
9184 }
9185 fstat(fr, &st);
9186 str = filename;
9187 if (!NIL_P(ARGF.inplace)) {
9188 VALUE suffix = ARGF.inplace;
9189 str = rb_str_dup(str);
9190 if (NIL_P(rb_str_cat_conv_enc_opts(str, RSTRING_LEN(str),
9191 RSTRING_PTR(suffix), RSTRING_LEN(suffix),
9192 rb_enc_get(suffix), 0, Qnil))) {
9193 rb_str_append(str, suffix);
9194 }
9195#ifdef NO_SAFE_RENAME
9196 (void)close(fr);
9197 (void)unlink(RSTRING_PTR(str));
9198 if (rename(fn, RSTRING_PTR(str)) < 0) {
9199 rb_warn("Can't rename %"PRIsVALUE" to %"PRIsVALUE": %s, skipping file",
9200 filename, str, strerror(errno));
9201 goto retry;
9202 }
9203 fr = rb_sysopen(str, O_RDONLY, 0);
9204#else
9205 if (rename(fn, RSTRING_PTR(str)) < 0) {
9206 rb_warn("Can't rename %"PRIsVALUE" to %"PRIsVALUE": %s, skipping file",
9207 filename, str, strerror(errno));
9208 close(fr);
9209 goto retry;
9210 }
9211#endif
9212 }
9213 else {
9214#ifdef NO_SAFE_RENAME
9215 rb_fatal("Can't do inplace edit without backup");
9216#else
9217 if (unlink(fn) < 0) {
9218 rb_warn("Can't remove %"PRIsVALUE": %s, skipping file",
9219 filename, strerror(errno));
9220 close(fr);
9221 goto retry;
9222 }
9223#endif
9224 }
9225 fw = rb_sysopen(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666);
9226#ifndef NO_SAFE_RENAME
9227 fstat(fw, &st2);
9228#ifdef HAVE_FCHMOD
9229 fchmod(fw, st.st_mode);
9230#else
9231 chmod(fn, st.st_mode);
9232#endif
9233 if (st.st_uid!=st2.st_uid || st.st_gid!=st2.st_gid) {
9234 int err;
9235#ifdef HAVE_FCHOWN
9236 err = fchown(fw, st.st_uid, st.st_gid);
9237#else
9238 err = chown(fn, st.st_uid, st.st_gid);
9239#endif
9240 if (err && getuid() == 0 && st2.st_uid == 0) {
9241 const char *wkfn = RSTRING_PTR(filename);
9242 rb_warn("Can't set owner/group of %"PRIsVALUE" to same as %"PRIsVALUE": %s, skipping file",
9243 filename, str, strerror(errno));
9244 (void)close(fr);
9245 (void)close(fw);
9246 (void)unlink(wkfn);
9247 goto retry;
9248 }
9249 }
9250#endif
9251 write_io = prep_io(fw, FMODE_WRITABLE, rb_cFile, fn);
9252 rb_ractor_stdout_set(write_io);
9253 if (stdout_binmode) rb_io_binmode(rb_stdout);
9254 }
9255 fmode = FMODE_READABLE;
9256 if (!ARGF.binmode) {
9257 fmode |= DEFAULT_TEXTMODE;
9258 }
9259 ARGF.current_file = prep_io(fr, fmode, rb_cFile, fn);
9260 if (!NIL_P(write_io)) {
9261 rb_io_set_write_io(ARGF.current_file, write_io);
9262 }
9263 RB_GC_GUARD(filename);
9264 }
9265 if (ARGF.binmode) rb_io_ascii8bit_binmode(ARGF.current_file);
9266 GetOpenFile(ARGF.current_file, fptr);
9267 if (ARGF.encs.enc) {
9268 fptr->encs = ARGF.encs;
9269 clear_codeconv(fptr);
9270 }
9271 else {
9272 fptr->encs.ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
9273 if (!ARGF.binmode) {
9275#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9276 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
9277#endif
9278 }
9279 }
9280 ARGF.next_p = 0;
9281 }
9282 else {
9283 ARGF.next_p = 1;
9284 return FALSE;
9285 }
9286 }
9287 else if (ARGF.next_p == -1) {
9288 ARGF.current_file = rb_stdin;
9289 ARGF.filename = rb_str_new2("-");
9290 if (ARGF.inplace) {
9291 rb_warn("Can't do inplace edit for stdio");
9292 rb_ractor_stdout_set(orig_stdout);
9293 }
9294 }
9295 if (ARGF.init_p == -1) ARGF.init_p = 1;
9296 return TRUE;
9297}
9298
9299static VALUE
9300argf_getline(int argc, VALUE *argv, VALUE argf)
9301{
9302 VALUE line;
9303 long lineno = ARGF.lineno;
9304
9305 retry:
9306 if (!next_argv()) return Qnil;
9307 if (ARGF_GENERIC_INPUT_P()) {
9308 line = forward_current(idGets, argc, argv);
9309 }
9310 else {
9311 if (argc == 0 && rb_rs == rb_default_rs) {
9312 line = rb_io_gets(ARGF.current_file);
9313 }
9314 else {
9315 line = rb_io_getline(argc, argv, ARGF.current_file);
9316 }
9317 if (NIL_P(line) && ARGF.next_p != -1) {
9318 argf_close(argf);
9319 ARGF.next_p = 1;
9320 goto retry;
9321 }
9322 }
9323 if (!NIL_P(line)) {
9324 ARGF.lineno = ++lineno;
9325 ARGF.last_lineno = ARGF.lineno;
9326 }
9327 return line;
9328}
9329
9330static VALUE
9331argf_lineno_getter(ID id, VALUE *var)
9332{
9333 VALUE argf = *var;
9334 return INT2FIX(ARGF.last_lineno);
9335}
9336
9337static void
9338argf_lineno_setter(VALUE val, ID id, VALUE *var)
9339{
9340 VALUE argf = *var;
9341 int n = NUM2INT(val);
9342 ARGF.last_lineno = ARGF.lineno = n;
9343}
9344
9345static VALUE argf_gets(int, VALUE *, VALUE);
9346
9347/*
9348 * call-seq:
9349 * gets(sep=$/ [, getline_args]) -> string or nil
9350 * gets(limit [, getline_args]) -> string or nil
9351 * gets(sep, limit [, getline_args]) -> string or nil
9352 *
9353 * Returns (and assigns to <code>$_</code>) the next line from the list
9354 * of files in +ARGV+ (or <code>$*</code>), or from standard input if
9355 * no files are present on the command line. Returns +nil+ at end of
9356 * file. The optional argument specifies the record separator. The
9357 * separator is included with the contents of each record. A separator
9358 * of +nil+ reads the entire contents, and a zero-length separator
9359 * reads the input one paragraph at a time, where paragraphs are
9360 * divided by two consecutive newlines. If the first argument is an
9361 * integer, or optional second argument is given, the returning string
9362 * would not be longer than the given value in bytes. If multiple
9363 * filenames are present in +ARGV+, <code>gets(nil)</code> will read
9364 * the contents one file at a time.
9365 *
9366 * ARGV << "testfile"
9367 * print while gets
9368 *
9369 * <em>produces:</em>
9370 *
9371 * This is line one
9372 * This is line two
9373 * This is line three
9374 * And so on...
9375 *
9376 * The style of programming using <code>$_</code> as an implicit
9377 * parameter is gradually losing favor in the Ruby community.
9378 */
9379
9380static VALUE
9381rb_f_gets(int argc, VALUE *argv, VALUE recv)
9382{
9383 if (recv == argf) {
9384 return argf_gets(argc, argv, argf);
9385 }
9386 return forward(argf, idGets, argc, argv);
9387}
9388
9389/*
9390 * call-seq:
9391 * ARGF.gets(sep=$/ [, getline_args]) -> string or nil
9392 * ARGF.gets(limit [, getline_args]) -> string or nil
9393 * ARGF.gets(sep, limit [, getline_args]) -> string or nil
9394 *
9395 * Returns the next line from the current file in +ARGF+.
9396 *
9397 * By default lines are assumed to be separated by <code>$/</code>;
9398 * to use a different character as a separator, supply it as a +String+
9399 * for the _sep_ argument.
9400 *
9401 * The optional _limit_ argument specifies how many characters of each line
9402 * to return. By default all characters are returned.
9403 *
9404 * See IO.readlines for details about getline_args.
9405 *
9406 */
9407static VALUE
9408argf_gets(int argc, VALUE *argv, VALUE argf)
9409{
9410 VALUE line;
9411
9412 line = argf_getline(argc, argv, argf);
9413 rb_lastline_set(line);
9414
9415 return line;
9416}
9417
9418VALUE
9420{
9421 VALUE line;
9422
9423 if (rb_rs != rb_default_rs) {
9424 return rb_f_gets(0, 0, argf);
9425 }
9426
9427 retry:
9428 if (!next_argv()) return Qnil;
9429 line = rb_io_gets(ARGF.current_file);
9430 if (NIL_P(line) && ARGF.next_p != -1) {
9431 rb_io_close(ARGF.current_file);
9432 ARGF.next_p = 1;
9433 goto retry;
9434 }
9435 rb_lastline_set(line);
9436 if (!NIL_P(line)) {
9437 ARGF.lineno++;
9438 ARGF.last_lineno = ARGF.lineno;
9439 }
9440
9441 return line;
9442}
9443
9444static VALUE argf_readline(int, VALUE *, VALUE);
9445
9446/*
9447 * call-seq:
9448 * readline(sep=$/) -> string
9449 * readline(limit) -> string
9450 * readline(sep, limit) -> string
9451 *
9452 * Equivalent to Kernel::gets, except
9453 * +readline+ raises +EOFError+ at end of file.
9454 */
9455
9456static VALUE
9457rb_f_readline(int argc, VALUE *argv, VALUE recv)
9458{
9459 if (recv == argf) {
9460 return argf_readline(argc, argv, argf);
9461 }
9462 return forward(argf, rb_intern("readline"), argc, argv);
9463}
9464
9465
9466/*
9467 * call-seq:
9468 * ARGF.readline(sep=$/) -> string
9469 * ARGF.readline(limit) -> string
9470 * ARGF.readline(sep, limit) -> string
9471 *
9472 * Returns the next line from the current file in +ARGF+.
9473 *
9474 * By default lines are assumed to be separated by <code>$/</code>;
9475 * to use a different character as a separator, supply it as a +String+
9476 * for the _sep_ argument.
9477 *
9478 * The optional _limit_ argument specifies how many characters of each line
9479 * to return. By default all characters are returned.
9480 *
9481 * An +EOFError+ is raised at the end of the file.
9482 */
9483static VALUE
9484argf_readline(int argc, VALUE *argv, VALUE argf)
9485{
9486 VALUE line;
9487
9488 if (!next_argv()) rb_eof_error();
9489 ARGF_FORWARD(argc, argv);
9490 line = argf_gets(argc, argv, argf);
9491 if (NIL_P(line)) {
9492 rb_eof_error();
9493 }
9494
9495 return line;
9496}
9497
9498static VALUE argf_readlines(int, VALUE *, VALUE);
9499
9500/*
9501 * call-seq:
9502 * readlines(sep=$/) -> array
9503 * readlines(limit) -> array
9504 * readlines(sep, limit) -> array
9505 *
9506 * Returns an array containing the lines returned by calling
9507 * <code>Kernel.gets(<i>sep</i>)</code> until the end of file.
9508 */
9509
9510static VALUE
9511rb_f_readlines(int argc, VALUE *argv, VALUE recv)
9512{
9513 if (recv == argf) {
9514 return argf_readlines(argc, argv, argf);
9515 }
9516 return forward(argf, rb_intern("readlines"), argc, argv);
9517}
9518
9519/*
9520 * call-seq:
9521 * ARGF.readlines(sep = $/) -> array
9522 * ARGF.readlines(limit) -> array
9523 * ARGF.readlines(sep, limit) -> array
9524 *
9525 * ARGF.to_a(sep = $/) -> array
9526 * ARGF.to_a(limit) -> array
9527 * ARGF.to_a(sep, limit) -> array
9528 *
9529 * Reads each file in +ARGF+ in its entirety, returning an +Array+ containing
9530 * lines from the files. Lines are assumed to be separated by _sep_.
9531 *
9532 * lines = ARGF.readlines
9533 * lines[0] #=> "This is line one\n"
9534 */
9535static VALUE
9536argf_readlines(int argc, VALUE *argv, VALUE argf)
9537{
9538 long lineno = ARGF.lineno;
9539 VALUE lines, ary;
9540
9541 ary = rb_ary_new();
9542 while (next_argv()) {
9543 if (ARGF_GENERIC_INPUT_P()) {
9544 lines = forward_current(rb_intern("readlines"), argc, argv);
9545 }
9546 else {
9547 lines = rb_io_readlines(argc, argv, ARGF.current_file);
9548 argf_close(argf);
9549 }
9550 ARGF.next_p = 1;
9551 rb_ary_concat(ary, lines);
9552 ARGF.lineno = lineno + RARRAY_LEN(ary);
9553 ARGF.last_lineno = ARGF.lineno;
9554 }
9555 ARGF.init_p = 0;
9556 return ary;
9557}
9558
9559/*
9560 * call-seq:
9561 * `cmd` -> string
9562 *
9563 * Returns the standard output of running _cmd_ in a subshell.
9564 * The built-in syntax <code>%x{...}</code> uses
9565 * this method. Sets <code>$?</code> to the process status.
9566 *
9567 * `date` #=> "Wed Apr 9 08:56:30 CDT 2003\n"
9568 * `ls testdir`.split[1] #=> "main.rb"
9569 * `echo oops && exit 99` #=> "oops\n"
9570 * $?.exitstatus #=> 99
9571 */
9572
9573static VALUE
9574rb_f_backquote(VALUE obj, VALUE str)
9575{
9576 VALUE port;
9577 VALUE result;
9578 rb_io_t *fptr;
9579
9580 SafeStringValue(str);
9581 rb_last_status_clear();
9582 port = pipe_open_s(str, "r", FMODE_READABLE|DEFAULT_TEXTMODE, NULL);
9583 if (NIL_P(port)) return rb_str_new(0,0);
9584
9585 GetOpenFile(port, fptr);
9586 result = read_all(fptr, remain_size(fptr), Qnil);
9587 rb_io_close(port);
9588 RFILE(port)->fptr = NULL;
9589 rb_io_fptr_finalize(fptr);
9590 RB_GC_GUARD(port);
9591
9592 return result;
9593}
9594
9595#ifdef HAVE_SYS_SELECT_H
9596#include <sys/select.h>
9597#endif
9598
9599static VALUE
9600select_internal(VALUE read, VALUE write, VALUE except, struct timeval *tp, rb_fdset_t *fds)
9601{
9602 VALUE res, list;
9603 rb_fdset_t *rp, *wp, *ep;
9604 rb_io_t *fptr;
9605 long i;
9606 int max = 0, n;
9607 int pending = 0;
9608 struct timeval timerec;
9609
9610 if (!NIL_P(read)) {
9611 Check_Type(read, T_ARRAY);
9612 for (i=0; i<RARRAY_LEN(read); i++) {
9613 GetOpenFile(rb_io_get_io(RARRAY_AREF(read, i)), fptr);
9614 rb_fd_set(fptr->fd, &fds[0]);
9615 if (READ_DATA_PENDING(fptr) || READ_CHAR_PENDING(fptr)) { /* check for buffered data */
9616 pending++;
9617 rb_fd_set(fptr->fd, &fds[3]);
9618 }
9619 if (max < fptr->fd) max = fptr->fd;
9620 }
9621 if (pending) { /* no blocking if there's buffered data */
9622 timerec.tv_sec = timerec.tv_usec = 0;
9623 tp = &timerec;
9624 }
9625 rp = &fds[0];
9626 }
9627 else
9628 rp = 0;
9629
9630 if (!NIL_P(write)) {
9631 Check_Type(write, T_ARRAY);
9632 for (i=0; i<RARRAY_LEN(write); i++) {
9633 VALUE write_io = GetWriteIO(rb_io_get_io(RARRAY_AREF(write, i)));
9634 GetOpenFile(write_io, fptr);
9635 rb_fd_set(fptr->fd, &fds[1]);
9636 if (max < fptr->fd) max = fptr->fd;
9637 }
9638 wp = &fds[1];
9639 }
9640 else
9641 wp = 0;
9642
9643 if (!NIL_P(except)) {
9644 Check_Type(except, T_ARRAY);
9645 for (i=0; i<RARRAY_LEN(except); i++) {
9646 VALUE io = rb_io_get_io(RARRAY_AREF(except, i));
9647 VALUE write_io = GetWriteIO(io);
9648 GetOpenFile(io, fptr);
9649 rb_fd_set(fptr->fd, &fds[2]);
9650 if (max < fptr->fd) max = fptr->fd;
9651 if (io != write_io) {
9652 GetOpenFile(write_io, fptr);
9653 rb_fd_set(fptr->fd, &fds[2]);
9654 if (max < fptr->fd) max = fptr->fd;
9655 }
9656 }
9657 ep = &fds[2];
9658 }
9659 else {
9660 ep = 0;
9661 }
9662
9663 max++;
9664
9665 n = rb_thread_fd_select(max, rp, wp, ep, tp);
9666 if (n < 0) {
9667 rb_sys_fail(0);
9668 }
9669 if (!pending && n == 0) return Qnil; /* returns nil on timeout */
9670
9671 res = rb_ary_new2(3);
9672 rb_ary_push(res, rp?rb_ary_new():rb_ary_new2(0));
9673 rb_ary_push(res, wp?rb_ary_new():rb_ary_new2(0));
9674 rb_ary_push(res, ep?rb_ary_new():rb_ary_new2(0));
9675
9676 if (rp) {
9677 list = RARRAY_AREF(res, 0);
9678 for (i=0; i< RARRAY_LEN(read); i++) {
9679 VALUE obj = rb_ary_entry(read, i);
9680 VALUE io = rb_io_get_io(obj);
9681 GetOpenFile(io, fptr);
9682 if (rb_fd_isset(fptr->fd, &fds[0]) ||
9683 rb_fd_isset(fptr->fd, &fds[3])) {
9684 rb_ary_push(list, obj);
9685 }
9686 }
9687 }
9688
9689 if (wp) {
9690 list = RARRAY_AREF(res, 1);
9691 for (i=0; i< RARRAY_LEN(write); i++) {
9692 VALUE obj = rb_ary_entry(write, i);
9693 VALUE io = rb_io_get_io(obj);
9694 VALUE write_io = GetWriteIO(io);
9695 GetOpenFile(write_io, fptr);
9696 if (rb_fd_isset(fptr->fd, &fds[1])) {
9697 rb_ary_push(list, obj);
9698 }
9699 }
9700 }
9701
9702 if (ep) {
9703 list = RARRAY_AREF(res, 2);
9704 for (i=0; i< RARRAY_LEN(except); i++) {
9705 VALUE obj = rb_ary_entry(except, i);
9706 VALUE io = rb_io_get_io(obj);
9707 VALUE write_io = GetWriteIO(io);
9708 GetOpenFile(io, fptr);
9709 if (rb_fd_isset(fptr->fd, &fds[2])) {
9710 rb_ary_push(list, obj);
9711 }
9712 else if (io != write_io) {
9713 GetOpenFile(write_io, fptr);
9714 if (rb_fd_isset(fptr->fd, &fds[2])) {
9715 rb_ary_push(list, obj);
9716 }
9717 }
9718 }
9719 }
9720
9721 return res; /* returns an empty array on interrupt */
9722}
9723
9725 VALUE read, write, except;
9726 struct timeval *timeout;
9727 rb_fdset_t fdsets[4];
9728};
9729
9730static VALUE
9731select_call(VALUE arg)
9732{
9733 struct select_args *p = (struct select_args *)arg;
9734
9735 return select_internal(p->read, p->write, p->except, p->timeout, p->fdsets);
9736}
9737
9738static VALUE
9739select_end(VALUE arg)
9740{
9741 struct select_args *p = (struct select_args *)arg;
9742 int i;
9743
9744 for (i = 0; i < numberof(p->fdsets); ++i)
9745 rb_fd_term(&p->fdsets[i]);
9746 return Qnil;
9747}
9748
9749static VALUE sym_normal, sym_sequential, sym_random,
9750 sym_willneed, sym_dontneed, sym_noreuse;
9751
9752#ifdef HAVE_POSIX_FADVISE
9753struct io_advise_struct {
9754 int fd;
9755 int advice;
9756 off_t offset;
9757 off_t len;
9758};
9759
9760static VALUE
9761io_advise_internal(void *arg)
9762{
9763 struct io_advise_struct *ptr = arg;
9764 return posix_fadvise(ptr->fd, ptr->offset, ptr->len, ptr->advice);
9765}
9766
9767static VALUE
9768io_advise_sym_to_const(VALUE sym)
9769{
9770#ifdef POSIX_FADV_NORMAL
9771 if (sym == sym_normal)
9772 return INT2NUM(POSIX_FADV_NORMAL);
9773#endif
9774
9775#ifdef POSIX_FADV_RANDOM
9776 if (sym == sym_random)
9777 return INT2NUM(POSIX_FADV_RANDOM);
9778#endif
9779
9780#ifdef POSIX_FADV_SEQUENTIAL
9781 if (sym == sym_sequential)
9782 return INT2NUM(POSIX_FADV_SEQUENTIAL);
9783#endif
9784
9785#ifdef POSIX_FADV_WILLNEED
9786 if (sym == sym_willneed)
9787 return INT2NUM(POSIX_FADV_WILLNEED);
9788#endif
9789
9790#ifdef POSIX_FADV_DONTNEED
9791 if (sym == sym_dontneed)
9792 return INT2NUM(POSIX_FADV_DONTNEED);
9793#endif
9794
9795#ifdef POSIX_FADV_NOREUSE
9796 if (sym == sym_noreuse)
9797 return INT2NUM(POSIX_FADV_NOREUSE);
9798#endif
9799
9800 return Qnil;
9801}
9802
9803static VALUE
9804do_io_advise(rb_io_t *fptr, VALUE advice, off_t offset, off_t len)
9805{
9806 int rv;
9807 struct io_advise_struct ias;
9808 VALUE num_adv;
9809
9810 num_adv = io_advise_sym_to_const(advice);
9811
9812 /*
9813 * The platform doesn't support this hint. We don't raise exception, instead
9814 * silently ignore it. Because IO::advise is only hint.
9815 */
9816 if (NIL_P(num_adv))
9817 return Qnil;
9818
9819 ias.fd = fptr->fd;
9820 ias.advice = NUM2INT(num_adv);
9821 ias.offset = offset;
9822 ias.len = len;
9823
9824 rv = (int)rb_thread_io_blocking_region(io_advise_internal, &ias, fptr->fd);
9825 if (rv && rv != ENOSYS) {
9826 /* posix_fadvise(2) doesn't set errno. On success it returns 0; otherwise
9827 it returns the error code. */
9828 VALUE message = rb_sprintf("%"PRIsVALUE" "
9829 "(%"PRI_OFFT_PREFIX"d, "
9830 "%"PRI_OFFT_PREFIX"d, "
9831 "%"PRIsVALUE")",
9832 fptr->pathv, offset, len, advice);
9833 rb_syserr_fail_str(rv, message);
9834 }
9835
9836 return Qnil;
9837}
9838
9839#endif /* HAVE_POSIX_FADVISE */
9840
9841static void
9842advice_arg_check(VALUE advice)
9843{
9844 if (!SYMBOL_P(advice))
9845 rb_raise(rb_eTypeError, "advice must be a Symbol");
9846
9847 if (advice != sym_normal &&
9848 advice != sym_sequential &&
9849 advice != sym_random &&
9850 advice != sym_willneed &&
9851 advice != sym_dontneed &&
9852 advice != sym_noreuse) {
9853 rb_raise(rb_eNotImpError, "Unsupported advice: %+"PRIsVALUE, advice);
9854 }
9855}
9856
9857/*
9858 * call-seq:
9859 * ios.advise(advice, offset=0, len=0) -> nil
9860 *
9861 * Announce an intention to access data from the current file in a
9862 * specific pattern. On platforms that do not support the
9863 * <em>posix_fadvise(2)</em> system call, this method is a no-op.
9864 *
9865 * _advice_ is one of the following symbols:
9866 *
9867 * :normal:: No advice to give; the default assumption for an open file.
9868 * :sequential:: The data will be accessed sequentially
9869 * with lower offsets read before higher ones.
9870 * :random:: The data will be accessed in random order.
9871 * :willneed:: The data will be accessed in the near future.
9872 * :dontneed:: The data will not be accessed in the near future.
9873 * :noreuse:: The data will only be accessed once.
9874 *
9875 * The semantics of a piece of advice are platform-dependent. See
9876 * <em>man 2 posix_fadvise</em> for details.
9877 *
9878 * "data" means the region of the current file that begins at
9879 * _offset_ and extends for _len_ bytes. If _len_ is 0, the region
9880 * ends at the last byte of the file. By default, both _offset_ and
9881 * _len_ are 0, meaning that the advice applies to the entire file.
9882 *
9883 * If an error occurs, one of the following exceptions will be raised:
9884 *
9885 * IOError:: The IO stream is closed.
9886 * Errno::EBADF::
9887 * The file descriptor of the current file is invalid.
9888 * Errno::EINVAL:: An invalid value for _advice_ was given.
9889 * Errno::ESPIPE::
9890 * The file descriptor of the current file refers to a FIFO or
9891 * pipe. (Linux raises Errno::EINVAL in this case).
9892 * TypeError::
9893 * Either _advice_ was not a Symbol, or one of the
9894 * other arguments was not an Integer.
9895 * RangeError:: One of the arguments given was too big/small.
9896 *
9897 * This list is not exhaustive; other Errno:: exceptions are also possible.
9898 */
9899static VALUE
9900rb_io_advise(int argc, VALUE *argv, VALUE io)
9901{
9902 VALUE advice, offset, len;
9903 off_t off, l;
9904 rb_io_t *fptr;
9905
9906 rb_scan_args(argc, argv, "12", &advice, &offset, &len);
9907 advice_arg_check(advice);
9908
9909 io = GetWriteIO(io);
9910 GetOpenFile(io, fptr);
9911
9912 off = NIL_P(offset) ? 0 : NUM2OFFT(offset);
9913 l = NIL_P(len) ? 0 : NUM2OFFT(len);
9914
9915#ifdef HAVE_POSIX_FADVISE
9916 return do_io_advise(fptr, advice, off, l);
9917#else
9918 ((void)off, (void)l); /* Ignore all hint */
9919 return Qnil;
9920#endif
9921}
9922
9923/*
9924 * call-seq:
9925 * IO.select(read_array [, write_array [, error_array [, timeout]]]) -> array or nil
9926 *
9927 * Calls select(2) system call.
9928 * It monitors given arrays of IO objects, waits until one or more of
9929 * IO objects are ready for reading, are ready for writing, and have
9930 * pending exceptions respectively, and returns an array that contains
9931 * arrays of those IO objects. It will return +nil+ if optional
9932 * <i>timeout</i> value is given and no IO object is ready in
9933 * <i>timeout</i> seconds.
9934 *
9935 * IO.select peeks the buffer of IO objects for testing readability.
9936 * If the IO buffer is not empty, IO.select immediately notifies
9937 * readability. This "peek" only happens for IO objects. It does not
9938 * happen for IO-like objects such as OpenSSL::SSL::SSLSocket.
9939 *
9940 * The best way to use IO.select is invoking it after nonblocking
9941 * methods such as #read_nonblock, #write_nonblock, etc. The methods
9942 * raise an exception which is extended by IO::WaitReadable or
9943 * IO::WaitWritable. The modules notify how the caller should wait
9944 * with IO.select. If IO::WaitReadable is raised, the caller should
9945 * wait for reading. If IO::WaitWritable is raised, the caller should
9946 * wait for writing.
9947 *
9948 * So, blocking read (#readpartial) can be emulated using
9949 * #read_nonblock and IO.select as follows:
9950 *
9951 * begin
9952 * result = io_like.read_nonblock(maxlen)
9953 * rescue IO::WaitReadable
9954 * IO.select([io_like])
9955 * retry
9956 * rescue IO::WaitWritable
9957 * IO.select(nil, [io_like])
9958 * retry
9959 * end
9960 *
9961 * Especially, the combination of nonblocking methods and IO.select is
9962 * preferred for IO like objects such as OpenSSL::SSL::SSLSocket. It
9963 * has #to_io method to return underlying IO object. IO.select calls
9964 * #to_io to obtain the file descriptor to wait.
9965 *
9966 * This means that readability notified by IO.select doesn't mean
9967 * readability from OpenSSL::SSL::SSLSocket object.
9968 *
9969 * The most likely situation is that OpenSSL::SSL::SSLSocket buffers
9970 * some data. IO.select doesn't see the buffer. So IO.select can
9971 * block when OpenSSL::SSL::SSLSocket#readpartial doesn't block.
9972 *
9973 * However, several more complicated situations exist.
9974 *
9975 * SSL is a protocol which is sequence of records.
9976 * The record consists of multiple bytes.
9977 * So, the remote side of SSL sends a partial record, IO.select
9978 * notifies readability but OpenSSL::SSL::SSLSocket cannot decrypt a
9979 * byte and OpenSSL::SSL::SSLSocket#readpartial will block.
9980 *
9981 * Also, the remote side can request SSL renegotiation which forces
9982 * the local SSL engine to write some data.
9983 * This means OpenSSL::SSL::SSLSocket#readpartial may invoke #write
9984 * system call and it can block.
9985 * In such a situation, OpenSSL::SSL::SSLSocket#read_nonblock raises
9986 * IO::WaitWritable instead of blocking.
9987 * So, the caller should wait for ready for writability as above
9988 * example.
9989 *
9990 * The combination of nonblocking methods and IO.select is also useful
9991 * for streams such as tty, pipe socket socket when multiple processes
9992 * read from a stream.
9993 *
9994 * Finally, Linux kernel developers don't guarantee that
9995 * readability of select(2) means readability of following read(2) even
9996 * for a single process.
9997 * See select(2) manual on GNU/Linux system.
9998 *
9999 * Invoking IO.select before IO#readpartial works well as usual.
10000 * However it is not the best way to use IO.select.
10001 *
10002 * The writability notified by select(2) doesn't show
10003 * how many bytes are writable.
10004 * IO#write method blocks until given whole string is written.
10005 * So, <code>IO#write(two or more bytes)</code> can block after
10006 * writability is notified by IO.select. IO#write_nonblock is required
10007 * to avoid the blocking.
10008 *
10009 * Blocking write (#write) can be emulated using #write_nonblock and
10010 * IO.select as follows: IO::WaitReadable should also be rescued for
10011 * SSL renegotiation in OpenSSL::SSL::SSLSocket.
10012 *
10013 * while 0 < string.bytesize
10014 * begin
10015 * written = io_like.write_nonblock(string)
10016 * rescue IO::WaitReadable
10017 * IO.select([io_like])
10018 * retry
10019 * rescue IO::WaitWritable
10020 * IO.select(nil, [io_like])
10021 * retry
10022 * end
10023 * string = string.byteslice(written..-1)
10024 * end
10025 *
10026 * === Parameters
10027 * read_array:: an array of IO objects that wait until ready for read
10028 * write_array:: an array of IO objects that wait until ready for write
10029 * error_array:: an array of IO objects that wait for exceptions
10030 * timeout:: a numeric value in second
10031 *
10032 * === Example
10033 *
10034 * rp, wp = IO.pipe
10035 * mesg = "ping "
10036 * 100.times {
10037 * # IO.select follows IO#read. Not the best way to use IO.select.
10038 * rs, ws, = IO.select([rp], [wp])
10039 * if r = rs[0]
10040 * ret = r.read(5)
10041 * print ret
10042 * case ret
10043 * when /ping/
10044 * mesg = "pong\n"
10045 * when /pong/
10046 * mesg = "ping "
10047 * end
10048 * end
10049 * if w = ws[0]
10050 * w.write(mesg)
10051 * end
10052 * }
10053 *
10054 * <em>produces:</em>
10055 *
10056 * ping pong
10057 * ping pong
10058 * ping pong
10059 * (snipped)
10060 * ping
10061 */
10062
10063static VALUE
10064rb_f_select(int argc, VALUE *argv, VALUE obj)
10065{
10066 VALUE timeout;
10067 struct select_args args;
10068 struct timeval timerec;
10069 int i;
10070
10071 rb_scan_args(argc, argv, "13", &args.read, &args.write, &args.except, &timeout);
10072 if (NIL_P(timeout)) {
10073 args.timeout = 0;
10074 }
10075 else {
10076 timerec = rb_time_interval(timeout);
10077 args.timeout = &timerec;
10078 }
10079
10080 for (i = 0; i < numberof(args.fdsets); ++i)
10081 rb_fd_init(&args.fdsets[i]);
10082
10083 return rb_ensure(select_call, (VALUE)&args, select_end, (VALUE)&args);
10084}
10085
10086#ifdef IOCTL_REQ_TYPE
10087 typedef IOCTL_REQ_TYPE ioctl_req_t;
10088#else
10089 typedef int ioctl_req_t;
10090# define NUM2IOCTLREQ(num) ((int)NUM2LONG(num))
10091#endif
10092
10093#ifdef HAVE_IOCTL
10094struct ioctl_arg {
10095 int fd;
10096 ioctl_req_t cmd;
10097 long narg;
10098};
10099
10100static VALUE
10101nogvl_ioctl(void *ptr)
10102{
10103 struct ioctl_arg *arg = ptr;
10104
10105 return (VALUE)ioctl(arg->fd, arg->cmd, arg->narg);
10106}
10107
10108static int
10109do_ioctl(int fd, ioctl_req_t cmd, long narg)
10110{
10111 int retval;
10112 struct ioctl_arg arg;
10113
10114 arg.fd = fd;
10115 arg.cmd = cmd;
10116 arg.narg = narg;
10117
10118 retval = (int)rb_thread_io_blocking_region(nogvl_ioctl, &arg, fd);
10119
10120 return retval;
10121}
10122#endif
10123
10124#define DEFAULT_IOCTL_NARG_LEN (256)
10125
10126#if defined(__linux__) && defined(_IOC_SIZE)
10127static long
10128linux_iocparm_len(ioctl_req_t cmd)
10129{
10130 long len;
10131
10132 if ((cmd & 0xFFFF0000) == 0) {
10133 /* legacy and unstructured ioctl number. */
10134 return DEFAULT_IOCTL_NARG_LEN;
10135 }
10136
10137 len = _IOC_SIZE(cmd);
10138
10139 /* paranoia check for silly drivers which don't keep ioctl convention */
10140 if (len < DEFAULT_IOCTL_NARG_LEN)
10141 len = DEFAULT_IOCTL_NARG_LEN;
10142
10143 return len;
10144}
10145#endif
10146
10147static long
10148ioctl_narg_len(ioctl_req_t cmd)
10149{
10150 long len;
10151
10152#ifdef IOCPARM_MASK
10153#ifndef IOCPARM_LEN
10154#define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK)
10155#endif
10156#endif
10157#ifdef IOCPARM_LEN
10158 len = IOCPARM_LEN(cmd); /* on BSDish systems we're safe */
10159#elif defined(__linux__) && defined(_IOC_SIZE)
10160 len = linux_iocparm_len(cmd);
10161#else
10162 /* otherwise guess at what's safe */
10163 len = DEFAULT_IOCTL_NARG_LEN;
10164#endif
10165
10166 return len;
10167}
10168
10169#ifdef HAVE_FCNTL
10170#ifdef __linux__
10171typedef long fcntl_arg_t;
10172#else
10173/* posix */
10174typedef int fcntl_arg_t;
10175#endif
10176
10177static long
10178fcntl_narg_len(ioctl_req_t cmd)
10179{
10180 long len;
10181
10182 switch (cmd) {
10183#ifdef F_DUPFD
10184 case F_DUPFD:
10185 len = sizeof(fcntl_arg_t);
10186 break;
10187#endif
10188#ifdef F_DUP2FD /* bsd specific */
10189 case F_DUP2FD:
10190 len = sizeof(int);
10191 break;
10192#endif
10193#ifdef F_DUPFD_CLOEXEC /* linux specific */
10194 case F_DUPFD_CLOEXEC:
10195 len = sizeof(fcntl_arg_t);
10196 break;
10197#endif
10198#ifdef F_GETFD
10199 case F_GETFD:
10200 len = 1;
10201 break;
10202#endif
10203#ifdef F_SETFD
10204 case F_SETFD:
10205 len = sizeof(fcntl_arg_t);
10206 break;
10207#endif
10208#ifdef F_GETFL
10209 case F_GETFL:
10210 len = 1;
10211 break;
10212#endif
10213#ifdef F_SETFL
10214 case F_SETFL:
10215 len = sizeof(fcntl_arg_t);
10216 break;
10217#endif
10218#ifdef F_GETOWN
10219 case F_GETOWN:
10220 len = 1;
10221 break;
10222#endif
10223#ifdef F_SETOWN
10224 case F_SETOWN:
10225 len = sizeof(fcntl_arg_t);
10226 break;
10227#endif
10228#ifdef F_GETOWN_EX /* linux specific */
10229 case F_GETOWN_EX:
10230 len = sizeof(struct f_owner_ex);
10231 break;
10232#endif
10233#ifdef F_SETOWN_EX /* linux specific */
10234 case F_SETOWN_EX:
10235 len = sizeof(struct f_owner_ex);
10236 break;
10237#endif
10238#ifdef F_GETLK
10239 case F_GETLK:
10240 len = sizeof(struct flock);
10241 break;
10242#endif
10243#ifdef F_SETLK
10244 case F_SETLK:
10245 len = sizeof(struct flock);
10246 break;
10247#endif
10248#ifdef F_SETLKW
10249 case F_SETLKW:
10250 len = sizeof(struct flock);
10251 break;
10252#endif
10253#ifdef F_READAHEAD /* bsd specific */
10254 case F_READAHEAD:
10255 len = sizeof(int);
10256 break;
10257#endif
10258#ifdef F_RDAHEAD /* Darwin specific */
10259 case F_RDAHEAD:
10260 len = sizeof(int);
10261 break;
10262#endif
10263#ifdef F_GETSIG /* linux specific */
10264 case F_GETSIG:
10265 len = 1;
10266 break;
10267#endif
10268#ifdef F_SETSIG /* linux specific */
10269 case F_SETSIG:
10270 len = sizeof(fcntl_arg_t);
10271 break;
10272#endif
10273#ifdef F_GETLEASE /* linux specific */
10274 case F_GETLEASE:
10275 len = 1;
10276 break;
10277#endif
10278#ifdef F_SETLEASE /* linux specific */
10279 case F_SETLEASE:
10280 len = sizeof(fcntl_arg_t);
10281 break;
10282#endif
10283#ifdef F_NOTIFY /* linux specific */
10284 case F_NOTIFY:
10285 len = sizeof(fcntl_arg_t);
10286 break;
10287#endif
10288
10289 default:
10290 len = 256;
10291 break;
10292 }
10293
10294 return len;
10295}
10296#else /* HAVE_FCNTL */
10297static long
10298fcntl_narg_len(ioctl_req_t cmd)
10299{
10300 return 0;
10301}
10302#endif /* HAVE_FCNTL */
10303
10304#define NARG_SENTINEL 17
10305
10306static long
10307setup_narg(ioctl_req_t cmd, VALUE *argp, long (*narg_len)(ioctl_req_t))
10308{
10309 long narg = 0;
10310 VALUE arg = *argp;
10311
10312 if (!RTEST(arg)) {
10313 narg = 0;
10314 }
10315 else if (FIXNUM_P(arg)) {
10316 narg = FIX2LONG(arg);
10317 }
10318 else if (arg == Qtrue) {
10319 narg = 1;
10320 }
10321 else {
10322 VALUE tmp = rb_check_string_type(arg);
10323
10324 if (NIL_P(tmp)) {
10325 narg = NUM2LONG(arg);
10326 }
10327 else {
10328 char *ptr;
10329 long len, slen;
10330
10331 *argp = arg = tmp;
10332 len = narg_len(cmd);
10333 rb_str_modify(arg);
10334
10335 slen = RSTRING_LEN(arg);
10336 /* expand for data + sentinel. */
10337 if (slen < len+1) {
10338 rb_str_resize(arg, len+1);
10339 MEMZERO(RSTRING_PTR(arg)+slen, char, len-slen);
10340 slen = len+1;
10341 }
10342 /* a little sanity check here */
10343 ptr = RSTRING_PTR(arg);
10344 ptr[slen - 1] = NARG_SENTINEL;
10345 narg = (long)(SIGNED_VALUE)ptr;
10346 }
10347 }
10348
10349 return narg;
10350}
10351
10352static VALUE
10353finish_narg(int retval, VALUE arg, const rb_io_t *fptr)
10354{
10355 if (retval < 0) rb_sys_fail_path(fptr->pathv);
10356 if (RB_TYPE_P(arg, T_STRING)) {
10357 char *ptr;
10358 long slen;
10359 RSTRING_GETMEM(arg, ptr, slen);
10360 if (ptr[slen-1] != NARG_SENTINEL)
10361 rb_raise(rb_eArgError, "return value overflowed string");
10362 ptr[slen-1] = '\0';
10363 }
10364
10365 return INT2NUM(retval);
10366}
10367
10368#ifdef HAVE_IOCTL
10369static VALUE
10370rb_ioctl(VALUE io, VALUE req, VALUE arg)
10371{
10372 ioctl_req_t cmd = NUM2IOCTLREQ(req);
10373 rb_io_t *fptr;
10374 long narg;
10375 int retval;
10376
10377 narg = setup_narg(cmd, &arg, ioctl_narg_len);
10378 GetOpenFile(io, fptr);
10379 retval = do_ioctl(fptr->fd, cmd, narg);
10380 return finish_narg(retval, arg, fptr);
10381}
10382
10383/*
10384 * call-seq:
10385 * ios.ioctl(integer_cmd, arg) -> integer
10386 *
10387 * Provides a mechanism for issuing low-level commands to control or
10388 * query I/O devices. Arguments and results are platform dependent. If
10389 * <i>arg</i> is a number, its value is passed directly. If it is a
10390 * string, it is interpreted as a binary sequence of bytes. On Unix
10391 * platforms, see <code>ioctl(2)</code> for details. Not implemented on
10392 * all platforms.
10393 */
10394
10395static VALUE
10396rb_io_ioctl(int argc, VALUE *argv, VALUE io)
10397{
10398 VALUE req, arg;
10399
10400 rb_scan_args(argc, argv, "11", &req, &arg);
10401 return rb_ioctl(io, req, arg);
10402}
10403#else
10404#define rb_io_ioctl rb_f_notimplement
10405#endif
10406
10407#ifdef HAVE_FCNTL
10408struct fcntl_arg {
10409 int fd;
10410 int cmd;
10411 long narg;
10412};
10413
10414static VALUE
10415nogvl_fcntl(void *ptr)
10416{
10417 struct fcntl_arg *arg = ptr;
10418
10419#if defined(F_DUPFD)
10420 if (arg->cmd == F_DUPFD)
10421 return (VALUE)rb_cloexec_fcntl_dupfd(arg->fd, (int)arg->narg);
10422#endif
10423 return (VALUE)fcntl(arg->fd, arg->cmd, arg->narg);
10424}
10425
10426static int
10427do_fcntl(int fd, int cmd, long narg)
10428{
10429 int retval;
10430 struct fcntl_arg arg;
10431
10432 arg.fd = fd;
10433 arg.cmd = cmd;
10434 arg.narg = narg;
10435
10436 retval = (int)rb_thread_io_blocking_region(nogvl_fcntl, &arg, fd);
10437 if (retval != -1) {
10438 switch (cmd) {
10439#if defined(F_DUPFD)
10440 case F_DUPFD:
10441#endif
10442#if defined(F_DUPFD_CLOEXEC)
10443 case F_DUPFD_CLOEXEC:
10444#endif
10445 rb_update_max_fd(retval);
10446 }
10447 }
10448
10449 return retval;
10450}
10451
10452static VALUE
10453rb_fcntl(VALUE io, VALUE req, VALUE arg)
10454{
10455 int cmd = NUM2INT(req);
10456 rb_io_t *fptr;
10457 long narg;
10458 int retval;
10459
10460 narg = setup_narg(cmd, &arg, fcntl_narg_len);
10461 GetOpenFile(io, fptr);
10462 retval = do_fcntl(fptr->fd, cmd, narg);
10463 return finish_narg(retval, arg, fptr);
10464}
10465
10466/*
10467 * call-seq:
10468 * ios.fcntl(integer_cmd, arg) -> integer
10469 *
10470 * Provides a mechanism for issuing low-level commands to control or
10471 * query file-oriented I/O streams. Arguments and results are platform
10472 * dependent. If <i>arg</i> is a number, its value is passed
10473 * directly. If it is a string, it is interpreted as a binary sequence
10474 * of bytes (Array#pack might be a useful way to build this string). On
10475 * Unix platforms, see <code>fcntl(2)</code> for details. Not
10476 * implemented on all platforms.
10477 */
10478
10479static VALUE
10480rb_io_fcntl(int argc, VALUE *argv, VALUE io)
10481{
10482 VALUE req, arg;
10483
10484 rb_scan_args(argc, argv, "11", &req, &arg);
10485 return rb_fcntl(io, req, arg);
10486}
10487#else
10488#define rb_io_fcntl rb_f_notimplement
10489#endif
10490
10491#if defined(HAVE_SYSCALL) || defined(HAVE___SYSCALL)
10492/*
10493 * call-seq:
10494 * syscall(num [, args...]) -> integer
10495 *
10496 * Calls the operating system function identified by _num_ and
10497 * returns the result of the function or raises SystemCallError if
10498 * it failed.
10499 *
10500 * Arguments for the function can follow _num_. They must be either
10501 * +String+ objects or +Integer+ objects. A +String+ object is passed
10502 * as a pointer to the byte sequence. An +Integer+ object is passed
10503 * as an integer whose bit size is the same as a pointer.
10504 * Up to nine parameters may be passed.
10505 *
10506 * The function identified by _num_ is system
10507 * dependent. On some Unix systems, the numbers may be obtained from a
10508 * header file called <code>syscall.h</code>.
10509 *
10510 * syscall 4, 1, "hello\n", 6 # '4' is write(2) on our box
10511 *
10512 * <em>produces:</em>
10513 *
10514 * hello
10515 *
10516 * Calling +syscall+ on a platform which does not have any way to
10517 * an arbitrary system function just fails with NotImplementedError.
10518 *
10519 * *Note:*
10520 * +syscall+ is essentially unsafe and unportable.
10521 * Feel free to shoot your foot.
10522 * The DL (Fiddle) library is preferred for safer and a bit
10523 * more portable programming.
10524 */
10525
10526static VALUE
10527rb_f_syscall(int argc, VALUE *argv, VALUE _)
10528{
10529 VALUE arg[8];
10530#if SIZEOF_VOIDP == 8 && defined(HAVE___SYSCALL) && SIZEOF_INT != 8 /* mainly *BSD */
10531# define SYSCALL __syscall
10532# define NUM2SYSCALLID(x) NUM2LONG(x)
10533# define RETVAL2NUM(x) LONG2NUM(x)
10534# if SIZEOF_LONG == 8
10535 long num, retval = -1;
10536# elif SIZEOF_LONG_LONG == 8
10537 long long num, retval = -1;
10538# else
10539# error ---->> it is asserted that __syscall takes the first argument and returns retval in 64bit signed integer. <<----
10540# endif
10541#elif defined(__linux__)
10542# define SYSCALL syscall
10543# define NUM2SYSCALLID(x) NUM2LONG(x)
10544# define RETVAL2NUM(x) LONG2NUM(x)
10545 /*
10546 * Linux man page says, syscall(2) function prototype is below.
10547 *
10548 * int syscall(int number, ...);
10549 *
10550 * But, it's incorrect. Actual one takes and returned long. (see unistd.h)
10551 */
10552 long num, retval = -1;
10553#else
10554# define SYSCALL syscall
10555# define NUM2SYSCALLID(x) NUM2INT(x)
10556# define RETVAL2NUM(x) INT2NUM(x)
10557 int num, retval = -1;
10558#endif
10559 int i;
10560
10561 if (RTEST(ruby_verbose)) {
10563 "We plan to remove a syscall function at future release. DL(Fiddle) provides safer alternative.");
10564 }
10565
10566 if (argc == 0)
10567 rb_raise(rb_eArgError, "too few arguments for syscall");
10568 if (argc > numberof(arg))
10569 rb_raise(rb_eArgError, "too many arguments for syscall");
10570 num = NUM2SYSCALLID(argv[0]); ++argv;
10571 for (i = argc - 1; i--; ) {
10572 VALUE v = rb_check_string_type(argv[i]);
10573
10574 if (!NIL_P(v)) {
10575 SafeStringValue(v);
10576 rb_str_modify(v);
10577 arg[i] = (VALUE)StringValueCStr(v);
10578 }
10579 else {
10580 arg[i] = (VALUE)NUM2LONG(argv[i]);
10581 }
10582 }
10583
10584 switch (argc) {
10585 case 1:
10586 retval = SYSCALL(num);
10587 break;
10588 case 2:
10589 retval = SYSCALL(num, arg[0]);
10590 break;
10591 case 3:
10592 retval = SYSCALL(num, arg[0],arg[1]);
10593 break;
10594 case 4:
10595 retval = SYSCALL(num, arg[0],arg[1],arg[2]);
10596 break;
10597 case 5:
10598 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3]);
10599 break;
10600 case 6:
10601 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4]);
10602 break;
10603 case 7:
10604 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5]);
10605 break;
10606 case 8:
10607 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6]);
10608 break;
10609 }
10610
10611 if (retval == -1)
10612 rb_sys_fail(0);
10613 return RETVAL2NUM(retval);
10614#undef SYSCALL
10615#undef NUM2SYSCALLID
10616#undef RETVAL2NUM
10617}
10618#else
10619#define rb_f_syscall rb_f_notimplement
10620#endif
10621
10622static VALUE
10623io_new_instance(VALUE args)
10624{
10625 return rb_class_new_instance(2, (VALUE*)args+1, *(VALUE*)args);
10626}
10627
10628static rb_encoding *
10629find_encoding(VALUE v)
10630{
10631 rb_encoding *enc = rb_find_encoding(v);
10632 if (!enc) rb_warn("Unsupported encoding %"PRIsVALUE" ignored", v);
10633 return enc;
10634}
10635
10636static void
10637io_encoding_set(rb_io_t *fptr, VALUE v1, VALUE v2, VALUE opt)
10638{
10639 rb_encoding *enc, *enc2;
10640 int ecflags = fptr->encs.ecflags;
10641 VALUE ecopts, tmp;
10642
10643 if (!NIL_P(v2)) {
10644 enc2 = find_encoding(v1);
10645 tmp = rb_check_string_type(v2);
10646 if (!NIL_P(tmp)) {
10647 if (RSTRING_LEN(tmp) == 1 && RSTRING_PTR(tmp)[0] == '-') {
10648 /* Special case - "-" => no transcoding */
10649 enc = enc2;
10650 enc2 = NULL;
10651 }
10652 else
10653 enc = find_encoding(v2);
10654 if (enc == enc2) {
10655 /* Special case - "-" => no transcoding */
10656 enc2 = NULL;
10657 }
10658 }
10659 else {
10660 enc = find_encoding(v2);
10661 if (enc == enc2) {
10662 /* Special case - "-" => no transcoding */
10663 enc2 = NULL;
10664 }
10665 }
10666 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
10667 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
10668 }
10669 else {
10670 if (NIL_P(v1)) {
10671 /* Set to default encodings */
10672 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
10673 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
10674 ecopts = Qnil;
10675 }
10676 else {
10677 tmp = rb_check_string_type(v1);
10678 if (!NIL_P(tmp) && rb_enc_asciicompat(enc = rb_enc_get(tmp))) {
10679 parse_mode_enc(RSTRING_PTR(tmp), enc, &enc, &enc2, NULL);
10680 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
10681 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
10682 }
10683 else {
10684 rb_io_ext_int_to_encs(find_encoding(v1), NULL, &enc, &enc2, 0);
10685 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
10686 ecopts = Qnil;
10687 }
10688 }
10689 }
10690 validate_enc_binmode(&fptr->mode, ecflags, enc, enc2);
10691 fptr->encs.enc = enc;
10692 fptr->encs.enc2 = enc2;
10693 fptr->encs.ecflags = ecflags;
10694 fptr->encs.ecopts = ecopts;
10695 clear_codeconv(fptr);
10696
10697}
10698
10700 rb_io_t *fptr;
10701 VALUE v1;
10702 VALUE v2;
10703 VALUE opt;
10704};
10705
10706static VALUE
10707io_encoding_set_v(VALUE v)
10708{
10709 struct io_encoding_set_args *arg = (struct io_encoding_set_args *)v;
10710 io_encoding_set(arg->fptr, arg->v1, arg->v2, arg->opt);
10711 return Qnil;
10712}
10713
10714static VALUE
10715pipe_pair_close(VALUE rw)
10716{
10717 VALUE *rwp = (VALUE *)rw;
10718 return rb_ensure(io_close, rwp[0], io_close, rwp[1]);
10719}
10720
10721/*
10722 * call-seq:
10723 * IO.pipe -> [read_io, write_io]
10724 * IO.pipe(ext_enc) -> [read_io, write_io]
10725 * IO.pipe("ext_enc:int_enc" [, opt]) -> [read_io, write_io]
10726 * IO.pipe(ext_enc, int_enc [, opt]) -> [read_io, write_io]
10727 *
10728 * IO.pipe(...) {|read_io, write_io| ... }
10729 *
10730 * Creates a pair of pipe endpoints (connected to each other) and
10731 * returns them as a two-element array of IO objects:
10732 * <code>[</code> <i>read_io</i>, <i>write_io</i> <code>]</code>.
10733 *
10734 * If a block is given, the block is called and
10735 * returns the value of the block.
10736 * <i>read_io</i> and <i>write_io</i> are sent to the block as arguments.
10737 * If read_io and write_io are not closed when the block exits, they are closed.
10738 * i.e. closing read_io and/or write_io doesn't cause an error.
10739 *
10740 * Not available on all platforms.
10741 *
10742 * If an encoding (encoding name or encoding object) is specified as an optional argument,
10743 * read string from pipe is tagged with the encoding specified.
10744 * If the argument is a colon separated two encoding names "A:B",
10745 * the read string is converted from encoding A (external encoding)
10746 * to encoding B (internal encoding), then tagged with B.
10747 * If two optional arguments are specified, those must be
10748 * encoding objects or encoding names,
10749 * and the first one is the external encoding,
10750 * and the second one is the internal encoding.
10751 * If the external encoding and the internal encoding is specified,
10752 * optional hash argument specify the conversion option.
10753 *
10754 * In the example below, the two processes close the ends of the pipe
10755 * that they are not using. This is not just a cosmetic nicety. The
10756 * read end of a pipe will not generate an end of file condition if
10757 * there are any writers with the pipe still open. In the case of the
10758 * parent process, the <code>rd.read</code> will never return if it
10759 * does not first issue a <code>wr.close</code>.
10760 *
10761 * rd, wr = IO.pipe
10762 *
10763 * if fork
10764 * wr.close
10765 * puts "Parent got: <#{rd.read}>"
10766 * rd.close
10767 * Process.wait
10768 * else
10769 * rd.close
10770 * puts "Sending message to parent"
10771 * wr.write "Hi Dad"
10772 * wr.close
10773 * end
10774 *
10775 * <em>produces:</em>
10776 *
10777 * Sending message to parent
10778 * Parent got: <Hi Dad>
10779 */
10780
10781static VALUE
10782rb_io_s_pipe(int argc, VALUE *argv, VALUE klass)
10783{
10784 int pipes[2], state;
10785 VALUE r, w, args[3], v1, v2;
10786 VALUE opt;
10787 rb_io_t *fptr, *fptr2;
10788 struct io_encoding_set_args ies_args;
10789 int fmode = 0;
10790 VALUE ret;
10791
10792 argc = rb_scan_args(argc, argv, "02:", &v1, &v2, &opt);
10793 if (rb_pipe(pipes) < 0)
10794 rb_sys_fail(0);
10795
10796 args[0] = klass;
10797 args[1] = INT2NUM(pipes[0]);
10798 args[2] = INT2FIX(O_RDONLY);
10799 r = rb_protect(io_new_instance, (VALUE)args, &state);
10800 if (state) {
10801 close(pipes[0]);
10802 close(pipes[1]);
10803 rb_jump_tag(state);
10804 }
10805 GetOpenFile(r, fptr);
10806
10807 ies_args.fptr = fptr;
10808 ies_args.v1 = v1;
10809 ies_args.v2 = v2;
10810 ies_args.opt = opt;
10811 rb_protect(io_encoding_set_v, (VALUE)&ies_args, &state);
10812 if (state) {
10813 close(pipes[1]);
10814 io_close(r);
10815 rb_jump_tag(state);
10816 }
10817
10818 args[1] = INT2NUM(pipes[1]);
10819 args[2] = INT2FIX(O_WRONLY);
10820 w = rb_protect(io_new_instance, (VALUE)args, &state);
10821 if (state) {
10822 close(pipes[1]);
10823 if (!NIL_P(r)) rb_io_close(r);
10824 rb_jump_tag(state);
10825 }
10826 GetOpenFile(w, fptr2);
10827 rb_io_synchronized(fptr2);
10828
10829 extract_binmode(opt, &fmode);
10830
10831 if ((fmode & FMODE_BINMODE) && NIL_P(v1)) {
10834 }
10835
10836#if DEFAULT_TEXTMODE
10837 if ((fptr->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
10838 fptr->mode &= ~FMODE_TEXTMODE;
10839 setmode(fptr->fd, O_BINARY);
10840 }
10841#if RUBY_CRLF_ENVIRONMENT
10844 }
10845#endif
10846#endif
10847 fptr->mode |= fmode;
10848#if DEFAULT_TEXTMODE
10849 if ((fptr2->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
10850 fptr2->mode &= ~FMODE_TEXTMODE;
10851 setmode(fptr2->fd, O_BINARY);
10852 }
10853#endif
10854 fptr2->mode |= fmode;
10855
10856 ret = rb_assoc_new(r, w);
10857 if (rb_block_given_p()) {
10858 VALUE rw[2];
10859 rw[0] = r;
10860 rw[1] = w;
10861 return rb_ensure(rb_yield, ret, pipe_pair_close, (VALUE)rw);
10862 }
10863 return ret;
10864}
10865
10867 int argc;
10868 VALUE *argv;
10869 VALUE io;
10870};
10871
10872static void
10873open_key_args(VALUE klass, int argc, VALUE *argv, VALUE opt, struct foreach_arg *arg)
10874{
10875 VALUE path, v;
10876 VALUE vmode = Qnil, vperm = Qnil;
10877
10878 path = *argv++;
10879 argc--;
10880 FilePathValue(path);
10881 arg->io = 0;
10882 arg->argc = argc;
10883 arg->argv = argv;
10884 if (NIL_P(opt)) {
10885 vmode = INT2NUM(O_RDONLY);
10886 vperm = INT2FIX(0666);
10887 }
10888 else if (!NIL_P(v = rb_hash_aref(opt, sym_open_args))) {
10889 int n;
10890
10891 v = rb_to_array_type(v);
10892 n = RARRAY_LENINT(v);
10893 rb_check_arity(n, 0, 3); /* rb_io_open */
10894 rb_scan_args_kw(RB_SCAN_ARGS_LAST_HASH_KEYWORDS, n, RARRAY_CONST_PTR(v), "02:", &vmode, &vperm, &opt);
10895 }
10896 arg->io = rb_io_open(klass, path, vmode, vperm, opt);
10897}
10898
10899static VALUE
10900io_s_foreach(VALUE v)
10901{
10902 struct getline_arg *arg = (void *)v;
10903 VALUE str;
10904
10905 while (!NIL_P(str = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, arg->io))) {
10906 rb_lastline_set(str);
10907 rb_yield(str);
10908 }
10910 return Qnil;
10911}
10912
10913/*
10914 * call-seq:
10915 * IO.foreach(name, sep=$/ [, getline_args, open_args]) {|line| block } -> nil
10916 * IO.foreach(name, limit [, getline_args, open_args]) {|line| block } -> nil
10917 * IO.foreach(name, sep, limit [, getline_args, open_args]) {|line| block } -> nil
10918 * IO.foreach(...) -> an_enumerator
10919 * File.foreach(name, sep=$/ [, getline_args, open_args]) {|line| block } -> nil
10920 * File.foreach(name, limit [, getline_args, open_args]) {|line| block } -> nil
10921 * File.foreach(name, sep, limit [, getline_args, open_args]) {|line| block } -> nil
10922 * File.foreach(...) -> an_enumerator
10923 *
10924 * Executes the block for every line in the named I/O port, where lines
10925 * are separated by <em>sep</em>.
10926 *
10927 * If no block is given, an enumerator is returned instead.
10928 *
10929 * If +name+ starts with a pipe character (<code>"|"</code>) and the receiver
10930 * is the IO class, a subprocess is created in the same way as Kernel#open,
10931 * and its output is returned.
10932 * Consider to use File.foreach to disable the behavior of subprocess invocation.
10933 *
10934 * File.foreach("testfile") {|x| print "GOT ", x }
10935 * IO.foreach("| cat testfile") {|x| print "GOT ", x }
10936 *
10937 * <em>produces:</em>
10938 *
10939 * GOT This is line one
10940 * GOT This is line two
10941 * GOT This is line three
10942 * GOT And so on...
10943 *
10944 * If the last argument is a hash, it's the keyword argument to open.
10945 * See IO.readlines for details about getline_args.
10946 * And see also IO.read for details about open_args.
10947 *
10948 */
10949
10950static VALUE
10951rb_io_s_foreach(int argc, VALUE *argv, VALUE self)
10952{
10953 VALUE opt;
10954 int orig_argc = argc;
10955 struct foreach_arg arg;
10956 struct getline_arg garg;
10957
10958 argc = rb_scan_args(argc, argv, "13:", NULL, NULL, NULL, NULL, &opt);
10959 RETURN_ENUMERATOR(self, orig_argc, argv);
10960 extract_getline_args(argc-1, argv+1, &garg);
10961 open_key_args(self, argc, argv, opt, &arg);
10962 if (NIL_P(arg.io)) return Qnil;
10963 extract_getline_opts(opt, &garg);
10964 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
10965 return rb_ensure(io_s_foreach, (VALUE)&garg, rb_io_close, arg.io);
10966}
10967
10968static VALUE
10969io_s_readlines(VALUE v)
10970{
10971 struct getline_arg *arg = (void *)v;
10972 return io_readlines(arg, arg->io);
10973}
10974
10975/*
10976 * call-seq:
10977 * IO.readlines(name, sep=$/ [, getline_args, open_args]) -> array
10978 * IO.readlines(name, limit [, getline_args, open_args]) -> array
10979 * IO.readlines(name, sep, limit [, getline_args, open_args]) -> array
10980 * File.readlines(name, sep=$/ [, getline_args, open_args]) -> array
10981 * File.readlines(name, limit [, getline_args, open_args]) -> array
10982 * File.readlines(name, sep, limit [, getline_args, open_args]) -> array
10983 *
10984 * Reads the entire file specified by <i>name</i> as individual
10985 * lines, and returns those lines in an array. Lines are separated by
10986 * <i>sep</i>.
10987 *
10988 * If +name+ starts with a pipe character (<code>"|"</code>) and the receiver
10989 * is the IO class, a subprocess is created in the same way as Kernel#open,
10990 * and its output is returned.
10991 * Consider to use File.readlines to disable the behavior of subprocess invocation.
10992 *
10993 * a = File.readlines("testfile")
10994 * a[0] #=> "This is line one\n"
10995 *
10996 * b = File.readlines("testfile", chomp: true)
10997 * b[0] #=> "This is line one"
10998 *
10999 * IO.readlines("|ls -a") #=> [".\n", "..\n", ...]
11000 *
11001 * If the last argument is a hash, it's the keyword argument to open.
11002 *
11003 * === Options for getline
11004 *
11005 * The options hash accepts the following keys:
11006 *
11007 * :chomp::
11008 * When the optional +chomp+ keyword argument has a true value,
11009 * <code>\n</code>, <code>\r</code>, and <code>\r\n</code>
11010 * will be removed from the end of each line.
11011 *
11012 * See also IO.read for details about +name+ and open_args.
11013 */
11014
11015static VALUE
11016rb_io_s_readlines(int argc, VALUE *argv, VALUE io)
11017{
11018 VALUE opt;
11019 struct foreach_arg arg;
11020 struct getline_arg garg;
11021
11022 argc = rb_scan_args(argc, argv, "13:", NULL, NULL, NULL, NULL, &opt);
11023 extract_getline_args(argc-1, argv+1, &garg);
11024 open_key_args(io, argc, argv, opt, &arg);
11025 if (NIL_P(arg.io)) return Qnil;
11026 extract_getline_opts(opt, &garg);
11027 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
11028 return rb_ensure(io_s_readlines, (VALUE)&garg, rb_io_close, arg.io);
11029}
11030
11031static VALUE
11032io_s_read(VALUE v)
11033{
11034 struct foreach_arg *arg = (void *)v;
11035 return io_read(arg->argc, arg->argv, arg->io);
11036}
11037
11038struct seek_arg {
11039 VALUE io;
11040 VALUE offset;
11041 int mode;
11042};
11043
11044static VALUE
11045seek_before_access(VALUE argp)
11046{
11047 struct seek_arg *arg = (struct seek_arg *)argp;
11048 rb_io_binmode(arg->io);
11049 return rb_io_seek(arg->io, arg->offset, arg->mode);
11050}
11051
11052/*
11053 * call-seq:
11054 * IO.read(name, [length [, offset]] [, opt]) -> string
11055 * File.read(name, [length [, offset]] [, opt]) -> string
11056 *
11057 * Opens the file, optionally seeks to the given +offset+, then returns
11058 * +length+ bytes (defaulting to the rest of the file). #read ensures
11059 * the file is closed before returning.
11060 *
11061 * If +name+ starts with a pipe character (<code>"|"</code>) and the receiver
11062 * is the IO class, a subprocess is created in the same way as Kernel#open,
11063 * and its output is returned.
11064 * Consider to use File.read to disable the behavior of subprocess invocation.
11065 *
11066 * === Options
11067 *
11068 * The options hash accepts the following keys:
11069 *
11070 * :encoding::
11071 * string or encoding
11072 *
11073 * Specifies the encoding of the read string. +:encoding+ will be ignored
11074 * if +length+ is specified. See Encoding.aliases for possible encodings.
11075 *
11076 * :mode::
11077 * string or integer
11078 *
11079 * Specifies the <i>mode</i> argument for open(). It must start
11080 * with an "r", otherwise it will cause an error.
11081 * See IO.new for the list of possible modes.
11082 *
11083 * :open_args::
11084 * array
11085 *
11086 * Specifies arguments for open() as an array. This key can not be used
11087 * in combination with either +:encoding+ or +:mode+.
11088 *
11089 * Examples:
11090 *
11091 * File.read("testfile") #=> "This is line one\nThis is line two\nThis is line three\nAnd so on...\n"
11092 * File.read("testfile", 20) #=> "This is line one\nThi"
11093 * File.read("testfile", 20, 10) #=> "ne one\nThis is line "
11094 * File.read("binfile", mode: "rb") #=> "\xF7\x00\x00\x0E\x12"
11095 * IO.read("|ls -a") #=> ".\n..\n"...
11096 */
11097
11098static VALUE
11099rb_io_s_read(int argc, VALUE *argv, VALUE io)
11100{
11101 VALUE opt, offset;
11102 struct foreach_arg arg;
11103
11104 argc = rb_scan_args(argc, argv, "13:", NULL, NULL, &offset, NULL, &opt);
11105 open_key_args(io, argc, argv, opt, &arg);
11106 if (NIL_P(arg.io)) return Qnil;
11107 if (!NIL_P(offset)) {
11108 struct seek_arg sarg;
11109 int state = 0;
11110 sarg.io = arg.io;
11111 sarg.offset = offset;
11112 sarg.mode = SEEK_SET;
11113 rb_protect(seek_before_access, (VALUE)&sarg, &state);
11114 if (state) {
11115 rb_io_close(arg.io);
11116 rb_jump_tag(state);
11117 }
11118 if (arg.argc == 2) arg.argc = 1;
11119 }
11120 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
11121}
11122
11123/*
11124 * call-seq:
11125 * IO.binread(name, [length [, offset]]) -> string
11126 * File.binread(name, [length [, offset]]) -> string
11127 *
11128 * Opens the file, optionally seeks to the given <i>offset</i>, then
11129 * returns <i>length</i> bytes (defaulting to the rest of the file).
11130 * #binread ensures the file is closed before returning. The open mode
11131 * would be <code>"rb:ASCII-8BIT"</code>.
11132 *
11133 * If +name+ starts with a pipe character (<code>"|"</code>) and the receiver
11134 * is the IO class, a subprocess is created in the same way as Kernel#open,
11135 * and its output is returned.
11136 * Consider to use File.binread to disable the behavior of subprocess invocation.
11137 *
11138 * File.binread("testfile") #=> "This is line one\nThis is line two\nThis is line three\nAnd so on...\n"
11139 * File.binread("testfile", 20) #=> "This is line one\nThi"
11140 * File.binread("testfile", 20, 10) #=> "ne one\nThis is line "
11141 * IO.binread("| cat testfile") #=> "This is line one\nThis is line two\nThis is line three\nAnd so on...\n"
11142 *
11143 * See also IO.read for details about +name+ and open_args.
11144 */
11145
11146static VALUE
11147rb_io_s_binread(int argc, VALUE *argv, VALUE io)
11148{
11149 VALUE offset;
11150 struct foreach_arg arg;
11151 enum {
11153 oflags = O_RDONLY
11154#ifdef O_BINARY
11155 |O_BINARY
11156#endif
11157 };
11158 convconfig_t convconfig = {NULL, NULL, 0, Qnil};
11159
11160 rb_scan_args(argc, argv, "12", NULL, NULL, &offset);
11161 FilePathValue(argv[0]);
11162 convconfig.enc = rb_ascii8bit_encoding();
11163 arg.io = rb_io_open_generic(io, argv[0], oflags, fmode, &convconfig, 0);
11164 if (NIL_P(arg.io)) return Qnil;
11165 arg.argv = argv+1;
11166 arg.argc = (argc > 1) ? 1 : 0;
11167 if (!NIL_P(offset)) {
11168 struct seek_arg sarg;
11169 int state = 0;
11170 sarg.io = arg.io;
11171 sarg.offset = offset;
11172 sarg.mode = SEEK_SET;
11173 rb_protect(seek_before_access, (VALUE)&sarg, &state);
11174 if (state) {
11175 rb_io_close(arg.io);
11176 rb_jump_tag(state);
11177 }
11178 }
11179 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
11180}
11181
11182static VALUE
11183io_s_write0(VALUE v)
11184{
11185 struct write_arg *arg = (void *)v;
11186 return io_write(arg->io,arg->str,arg->nosync);
11187}
11188
11189static VALUE
11190io_s_write(int argc, VALUE *argv, VALUE klass, int binary)
11191{
11192 VALUE string, offset, opt;
11193 struct foreach_arg arg;
11194 struct write_arg warg;
11195
11196 rb_scan_args(argc, argv, "21:", NULL, &string, &offset, &opt);
11197
11198 if (NIL_P(opt)) opt = rb_hash_new();
11199 else opt = rb_hash_dup(opt);
11200
11201
11202 if (NIL_P(rb_hash_aref(opt,sym_mode))) {
11203 int mode = O_WRONLY|O_CREAT;
11204#ifdef O_BINARY
11205 if (binary) mode |= O_BINARY;
11206#endif
11207 if (NIL_P(offset)) mode |= O_TRUNC;
11208 rb_hash_aset(opt,sym_mode,INT2NUM(mode));
11209 }
11210 open_key_args(klass, argc, argv, opt, &arg);
11211
11212#ifndef O_BINARY
11213 if (binary) rb_io_binmode_m(arg.io);
11214#endif
11215
11216 if (NIL_P(arg.io)) return Qnil;
11217 if (!NIL_P(offset)) {
11218 struct seek_arg sarg;
11219 int state = 0;
11220 sarg.io = arg.io;
11221 sarg.offset = offset;
11222 sarg.mode = SEEK_SET;
11223 rb_protect(seek_before_access, (VALUE)&sarg, &state);
11224 if (state) {
11225 rb_io_close(arg.io);
11226 rb_jump_tag(state);
11227 }
11228 }
11229
11230 warg.io = arg.io;
11231 warg.str = string;
11232 warg.nosync = 0;
11233
11234 return rb_ensure(io_s_write0, (VALUE)&warg, rb_io_close, arg.io);
11235}
11236
11237/*
11238 * call-seq:
11239 * IO.write(name, string [, offset]) -> integer
11240 * IO.write(name, string [, offset] [, opt]) -> integer
11241 * File.write(name, string [, offset]) -> integer
11242 * File.write(name, string [, offset] [, opt]) -> integer
11243 *
11244 * Opens the file, optionally seeks to the given <i>offset</i>, writes
11245 * <i>string</i>, then returns the length written. #write ensures the
11246 * file is closed before returning. If <i>offset</i> is not given in
11247 * write mode, the file is truncated. Otherwise, it is not truncated.
11248 *
11249 * If +name+ starts with a pipe character (<code>"|"</code>) and the receiver
11250 * is the IO class, a subprocess is created in the same way as Kernel#open,
11251 * and its output is returned.
11252 * Consider to use File.write to disable the behavior of subprocess invocation.
11253 *
11254 * File.write("testfile", "0123456789", 20) #=> 10
11255 * # File could contain: "This is line one\nThi0123456789two\nThis is line three\nAnd so on...\n"
11256 * File.write("testfile", "0123456789") #=> 10
11257 * # File would now read: "0123456789"
11258 * IO.write("|tr a-z A-Z", "abc") #=> 3
11259 * # Prints "ABC" to the standard output
11260 *
11261 * If the last argument is a hash, it specifies options for the internal
11262 * open(). It accepts the following keys:
11263 *
11264 * :encoding::
11265 * string or encoding
11266 *
11267 * Specifies the encoding of the read string.
11268 * See Encoding.aliases for possible encodings.
11269 *
11270 * :mode::
11271 * string or integer
11272 *
11273 * Specifies the <i>mode</i> argument for open(). It must start
11274 * with "w", "a", or "r+", otherwise it will cause an error.
11275 * See IO.new for the list of possible modes.
11276 *
11277 * :perm::
11278 * integer
11279 *
11280 * Specifies the <i>perm</i> argument for open().
11281 *
11282 * :open_args::
11283 * array
11284 *
11285 * Specifies arguments for open() as an array.
11286 * This key can not be used in combination with other keys.
11287 *
11288 * See also IO.read for details about +name+ and open_args.
11289 */
11290
11291static VALUE
11292rb_io_s_write(int argc, VALUE *argv, VALUE io)
11293{
11294 return io_s_write(argc, argv, io, 0);
11295}
11296
11297/*
11298 * call-seq:
11299 * IO.binwrite(name, string, [offset]) -> integer
11300 * IO.binwrite(name, string, [offset], open_args) -> integer
11301 * File.binwrite(name, string, [offset]) -> integer
11302 * File.binwrite(name, string, [offset], open_args) -> integer
11303 *
11304 * Same as IO.write except opening the file in binary mode and
11305 * ASCII-8BIT encoding (<code>"wb:ASCII-8BIT"</code>).
11306 *
11307 * If +name+ starts with a pipe character (<code>"|"</code>) and the receiver
11308 * is the IO class, a subprocess is created in the same way as Kernel#open,
11309 * and its output is returned.
11310 * Consider to use File.binwrite to disable the behavior of subprocess invocation.
11311 *
11312 * See also IO.read for details about +name+ and open_args.
11313 */
11314
11315static VALUE
11316rb_io_s_binwrite(int argc, VALUE *argv, VALUE io)
11317{
11318 return io_s_write(argc, argv, io, 1);
11319}
11320
11322 VALUE src;
11323 VALUE dst;
11324 off_t copy_length; /* (off_t)-1 if not specified */
11325 off_t src_offset; /* (off_t)-1 if not specified */
11326
11327 rb_io_t *src_fptr;
11328 rb_io_t *dst_fptr;
11329 unsigned close_src : 1;
11330 unsigned close_dst : 1;
11331 int error_no;
11332 off_t total;
11333 const char *syserr;
11334 const char *notimp;
11335 VALUE th;
11336 struct stat src_stat;
11337 struct stat dst_stat;
11338#ifdef HAVE_FCOPYFILE
11339 copyfile_state_t copyfile_state;
11340#endif
11341};
11342
11343static void *
11344exec_interrupts(void *arg)
11345{
11346 VALUE th = (VALUE)arg;
11347 rb_thread_execute_interrupts(th);
11348 return NULL;
11349}
11350
11351/*
11352 * returns TRUE if the preceding system call was interrupted
11353 * so we can continue. If the thread was interrupted, we
11354 * reacquire the GVL to execute interrupts before continuing.
11355 */
11356static int
11357maygvl_copy_stream_continue_p(int has_gvl, struct copy_stream_struct *stp)
11358{
11359 switch (errno) {
11360 case EINTR:
11361#if defined(ERESTART)
11362 case ERESTART:
11363#endif
11364 if (rb_thread_interrupted(stp->th)) {
11365 if (has_gvl)
11366 rb_thread_execute_interrupts(stp->th);
11367 else
11368 rb_thread_call_with_gvl(exec_interrupts, (void *)stp->th);
11369 }
11370 return TRUE;
11371 }
11372 return FALSE;
11373}
11374
11376 VALUE scheduler;
11377
11378 rb_io_t *fptr;
11379 short events;
11380
11381 VALUE result;
11382};
11383
11384static void *
11385rb_thread_fiber_scheduler_wait_for(void * _args)
11386{
11387 struct wait_for_single_fd *args = (struct wait_for_single_fd *)_args;
11388
11389 args->result = rb_fiber_scheduler_io_wait(args->scheduler, args->fptr->self, INT2NUM(args->events), Qnil);
11390
11391 return NULL;
11392}
11393
11394#if USE_POLL
11395# define IOWAIT_SYSCALL "poll"
11396STATIC_ASSERT(pollin_expected, POLLIN == RB_WAITFD_IN);
11397STATIC_ASSERT(pollout_expected, POLLOUT == RB_WAITFD_OUT);
11398static int
11399nogvl_wait_for(VALUE th, rb_io_t *fptr, short events)
11400{
11401 VALUE scheduler = rb_fiber_scheduler_current_for_thread(th);
11402 if (scheduler != Qnil) {
11403 struct wait_for_single_fd args = {.scheduler = scheduler, .fptr = fptr, .events = events};
11404 rb_thread_call_with_gvl(rb_thread_fiber_scheduler_wait_for, &args);
11405 return RTEST(args.result);
11406 }
11407
11408 int fd = fptr->fd;
11409 if (fd == -1) return 0;
11410
11411 struct pollfd fds;
11412
11413 fds.fd = fd;
11414 fds.events = events;
11415
11416 return poll(&fds, 1, -1);
11417}
11418#else /* !USE_POLL */
11419# define IOWAIT_SYSCALL "select"
11420static int
11421nogvl_wait_for(VALUE th, rb_io_t *fptr, short events)
11422{
11423 VALUE scheduler = rb_fiber_scheduler_current_for_thread(th);
11424 if (scheduler != Qnil) {
11425 struct wait_for_single_fd args = {.scheduler = scheduler, .fptr = fptr, .events = events};
11426 rb_thread_call_with_gvl(rb_thread_fiber_scheduler_wait_for, &args);
11427 return RTEST(args.result);
11428 }
11429
11430 int fd = fptr->fd;
11431 if (fd == -1) return 0;
11432
11433 rb_fdset_t fds;
11434 int ret;
11435
11436 rb_fd_init(&fds);
11437 rb_fd_set(fd, &fds);
11438
11439 switch (events) {
11440 case RB_WAITFD_IN:
11441 ret = rb_fd_select(fd + 1, &fds, 0, 0, 0);
11442 break;
11443 case RB_WAITFD_OUT:
11444 ret = rb_fd_select(fd + 1, 0, &fds, 0, 0);
11445 break;
11446 default:
11447 VM_UNREACHABLE(nogvl_wait_for);
11448 }
11449
11450 rb_fd_term(&fds);
11451 return ret;
11452}
11453#endif /* !USE_POLL */
11454
11455static int
11456maygvl_copy_stream_wait_read(int has_gvl, struct copy_stream_struct *stp)
11457{
11458 int ret;
11459
11460 do {
11461 if (has_gvl) {
11463 }
11464 else {
11465 ret = nogvl_wait_for(stp->th, stp->src_fptr, RB_WAITFD_IN);
11466 }
11467 } while (ret < 0 && maygvl_copy_stream_continue_p(has_gvl, stp));
11468
11469 if (ret < 0) {
11470 stp->syserr = IOWAIT_SYSCALL;
11471 stp->error_no = errno;
11472 return ret;
11473 }
11474 return 0;
11475}
11476
11477static int
11478nogvl_copy_stream_wait_write(struct copy_stream_struct *stp)
11479{
11480 int ret;
11481
11482 do {
11483 ret = nogvl_wait_for(stp->th, stp->dst_fptr, RB_WAITFD_OUT);
11484 } while (ret < 0 && maygvl_copy_stream_continue_p(0, stp));
11485
11486 if (ret < 0) {
11487 stp->syserr = IOWAIT_SYSCALL;
11488 stp->error_no = errno;
11489 return ret;
11490 }
11491 return 0;
11492}
11493
11494#ifdef USE_COPY_FILE_RANGE
11495
11496static ssize_t
11497simple_copy_file_range(int in_fd, off_t *in_offset, int out_fd, off_t *out_offset, size_t count, unsigned int flags)
11498{
11499#ifdef HAVE_COPY_FILE_RANGE
11500 return copy_file_range(in_fd, in_offset, out_fd, out_offset, count, flags);
11501#else
11502 return syscall(__NR_copy_file_range, in_fd, in_offset, out_fd, out_offset, count, flags);
11503#endif
11504}
11505
11506static int
11507nogvl_copy_file_range(struct copy_stream_struct *stp)
11508{
11509 ssize_t ss;
11510 off_t src_size;
11511 off_t copy_length, src_offset, *src_offset_ptr;
11512
11513 if (!S_ISREG(stp->src_stat.st_mode))
11514 return 0;
11515
11516 src_size = stp->src_stat.st_size;
11517 src_offset = stp->src_offset;
11518 if (src_offset >= (off_t)0) {
11519 src_offset_ptr = &src_offset;
11520 }
11521 else {
11522 src_offset_ptr = NULL; /* if src_offset_ptr is NULL, then bytes are read from in_fd starting from the file offset */
11523 }
11524
11525 copy_length = stp->copy_length;
11526 if (copy_length < (off_t)0) {
11527 if (src_offset < (off_t)0) {
11528 off_t current_offset;
11529 errno = 0;
11530 current_offset = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
11531 if (current_offset < (off_t)0 && errno) {
11532 stp->syserr = "lseek";
11533 stp->error_no = errno;
11534 return (int)current_offset;
11535 }
11536 copy_length = src_size - current_offset;
11537 }
11538 else {
11539 copy_length = src_size - src_offset;
11540 }
11541 }
11542
11543 retry_copy_file_range:
11544# if SIZEOF_OFF_T > SIZEOF_SIZE_T
11545 /* we are limited by the 32-bit ssize_t return value on 32-bit */
11546 ss = (copy_length > (off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
11547# else
11548 ss = (ssize_t)copy_length;
11549# endif
11550 ss = simple_copy_file_range(stp->src_fptr->fd, src_offset_ptr, stp->dst_fptr->fd, NULL, ss, 0);
11551 if (0 < ss) {
11552 stp->total += ss;
11553 copy_length -= ss;
11554 if (0 < copy_length) {
11555 goto retry_copy_file_range;
11556 }
11557 }
11558 if (ss < 0) {
11559 if (maygvl_copy_stream_continue_p(0, stp)) {
11560 goto retry_copy_file_range;
11561 }
11562 switch (errno) {
11563 case EINVAL:
11564 case EPERM: /* copy_file_range(2) doesn't exist (may happen in
11565 docker container) */
11566#ifdef ENOSYS
11567 case ENOSYS:
11568#endif
11569#ifdef EXDEV
11570 case EXDEV: /* in_fd and out_fd are not on the same filesystem */
11571#endif
11572 return 0;
11573 case EAGAIN:
11574#if EWOULDBLOCK != EAGAIN
11575 case EWOULDBLOCK:
11576#endif
11577 {
11578 int ret = nogvl_copy_stream_wait_write(stp);
11579 if (ret < 0) return ret;
11580 }
11581 goto retry_copy_file_range;
11582 case EBADF:
11583 {
11584 int e = errno;
11585 int flags = fcntl(stp->dst_fptr->fd, F_GETFL);
11586
11587 if (flags != -1 && flags & O_APPEND) {
11588 return 0;
11589 }
11590 errno = e;
11591 }
11592 }
11593 stp->syserr = "copy_file_range";
11594 stp->error_no = errno;
11595 return (int)ss;
11596 }
11597 return 1;
11598}
11599#endif
11600
11601#ifdef HAVE_FCOPYFILE
11602static int
11603nogvl_fcopyfile(struct copy_stream_struct *stp)
11604{
11605 off_t cur, ss = 0;
11606 const off_t src_offset = stp->src_offset;
11607 int ret;
11608
11609 if (stp->copy_length >= (off_t)0) {
11610 /* copy_length can't be specified in fcopyfile(3) */
11611 return 0;
11612 }
11613
11614 if (!S_ISREG(stp->src_stat.st_mode))
11615 return 0;
11616
11617 if (!S_ISREG(stp->dst_stat.st_mode))
11618 return 0;
11619 if (lseek(stp->dst_fptr->fd, 0, SEEK_CUR) > (off_t)0) /* if dst IO was already written */
11620 return 0;
11621 if (fcntl(stp->dst_fptr->fd, F_GETFL) & O_APPEND) {
11622 /* fcopyfile(3) appends src IO to dst IO and then truncates
11623 * dst IO to src IO's original size. */
11624 off_t end = lseek(stp->dst_fptr->fd, 0, SEEK_END);
11625 lseek(stp->dst_fptr->fd, 0, SEEK_SET);
11626 if (end > (off_t)0) return 0;
11627 }
11628
11629 if (src_offset > (off_t)0) {
11630 off_t r;
11631
11632 /* get current offset */
11633 errno = 0;
11634 cur = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
11635 if (cur < (off_t)0 && errno) {
11636 stp->error_no = errno;
11637 return 1;
11638 }
11639
11640 errno = 0;
11641 r = lseek(stp->src_fptr->fd, src_offset, SEEK_SET);
11642 if (r < (off_t)0 && errno) {
11643 stp->error_no = errno;
11644 return 1;
11645 }
11646 }
11647
11648 stp->copyfile_state = copyfile_state_alloc(); /* this will be freed by copy_stream_finalize() */
11649 ret = fcopyfile(stp->src_fptr->fd, stp->dst_fptr->fd, stp->copyfile_state, COPYFILE_DATA);
11650 copyfile_state_get(stp->copyfile_state, COPYFILE_STATE_COPIED, &ss); /* get copied bytes */
11651
11652 if (ret == 0) { /* success */
11653 stp->total = ss;
11654 if (src_offset > (off_t)0) {
11655 off_t r;
11656 errno = 0;
11657 /* reset offset */
11658 r = lseek(stp->src_fptr->fd, cur, SEEK_SET);
11659 if (r < (off_t)0 && errno) {
11660 stp->error_no = errno;
11661 return 1;
11662 }
11663 }
11664 }
11665 else {
11666 switch (errno) {
11667 case ENOTSUP:
11668 case EPERM:
11669 case EINVAL:
11670 return 0;
11671 }
11672 stp->syserr = "fcopyfile";
11673 stp->error_no = errno;
11674 return (int)ret;
11675 }
11676 return 1;
11677}
11678#endif
11679
11680#ifdef HAVE_SENDFILE
11681
11682# ifdef __linux__
11683# define USE_SENDFILE
11684
11685# ifdef HAVE_SYS_SENDFILE_H
11686# include <sys/sendfile.h>
11687# endif
11688
11689static ssize_t
11690simple_sendfile(int out_fd, int in_fd, off_t *offset, off_t count)
11691{
11692 return sendfile(out_fd, in_fd, offset, (size_t)count);
11693}
11694
11695# elif 0 /* defined(__FreeBSD__) || defined(__DragonFly__) */ || defined(__APPLE__)
11696/* This runs on FreeBSD8.1 r30210, but sendfiles blocks its execution
11697 * without cpuset -l 0.
11698 */
11699# define USE_SENDFILE
11700
11701static ssize_t
11702simple_sendfile(int out_fd, int in_fd, off_t *offset, off_t count)
11703{
11704 int r;
11705 off_t pos = offset ? *offset : lseek(in_fd, 0, SEEK_CUR);
11706 off_t sbytes;
11707# ifdef __APPLE__
11708 r = sendfile(in_fd, out_fd, pos, &count, NULL, 0);
11709 sbytes = count;
11710# else
11711 r = sendfile(in_fd, out_fd, pos, (size_t)count, NULL, &sbytes, 0);
11712# endif
11713 if (r != 0 && sbytes == 0) return r;
11714 if (offset) {
11715 *offset += sbytes;
11716 }
11717 else {
11718 lseek(in_fd, sbytes, SEEK_CUR);
11719 }
11720 return (ssize_t)sbytes;
11721}
11722
11723# endif
11724
11725#endif
11726
11727#ifdef USE_SENDFILE
11728static int
11729nogvl_copy_stream_sendfile(struct copy_stream_struct *stp)
11730{
11731 ssize_t ss;
11732 off_t src_size;
11733 off_t copy_length;
11734 off_t src_offset;
11735 int use_pread;
11736
11737 if (!S_ISREG(stp->src_stat.st_mode))
11738 return 0;
11739
11740 src_size = stp->src_stat.st_size;
11741#ifndef __linux__
11742 if ((stp->dst_stat.st_mode & S_IFMT) != S_IFSOCK)
11743 return 0;
11744#endif
11745
11746 src_offset = stp->src_offset;
11747 use_pread = src_offset >= (off_t)0;
11748
11749 copy_length = stp->copy_length;
11750 if (copy_length < (off_t)0) {
11751 if (use_pread)
11752 copy_length = src_size - src_offset;
11753 else {
11754 off_t cur;
11755 errno = 0;
11756 cur = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
11757 if (cur < (off_t)0 && errno) {
11758 stp->syserr = "lseek";
11759 stp->error_no = errno;
11760 return (int)cur;
11761 }
11762 copy_length = src_size - cur;
11763 }
11764 }
11765
11766 retry_sendfile:
11767# if SIZEOF_OFF_T > SIZEOF_SIZE_T
11768 /* we are limited by the 32-bit ssize_t return value on 32-bit */
11769 ss = (copy_length > (off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
11770# else
11771 ss = (ssize_t)copy_length;
11772# endif
11773 if (use_pread) {
11774 ss = simple_sendfile(stp->dst_fptr->fd, stp->src_fptr->fd, &src_offset, ss);
11775 }
11776 else {
11777 ss = simple_sendfile(stp->dst_fptr->fd, stp->src_fptr->fd, NULL, ss);
11778 }
11779 if (0 < ss) {
11780 stp->total += ss;
11781 copy_length -= ss;
11782 if (0 < copy_length) {
11783 goto retry_sendfile;
11784 }
11785 }
11786 if (ss < 0) {
11787 if (maygvl_copy_stream_continue_p(0, stp))
11788 goto retry_sendfile;
11789 switch (errno) {
11790 case EINVAL:
11791#ifdef ENOSYS
11792 case ENOSYS:
11793#endif
11794#ifdef EOPNOTSUP
11795 /* some RedHat kernels may return EOPNOTSUP on an NFS mount.
11796 see also: [Feature #16965] */
11797 case EOPNOTSUP:
11798#endif
11799 return 0;
11800 case EAGAIN:
11801#if EWOULDBLOCK != EAGAIN
11802 case EWOULDBLOCK:
11803#endif
11804 {
11805 int ret;
11806#ifndef __linux__
11807 /*
11808 * Linux requires stp->src_fptr->fd to be a mmap-able (regular) file,
11809 * select() reports regular files to always be "ready", so
11810 * there is no need to select() on it.
11811 * Other OSes may have the same limitation for sendfile() which
11812 * allow us to bypass maygvl_copy_stream_wait_read()...
11813 */
11814 ret = maygvl_copy_stream_wait_read(0, stp);
11815 if (ret < 0) return ret;
11816#endif
11817 ret = nogvl_copy_stream_wait_write(stp);
11818 if (ret < 0) return ret;
11819 }
11820 goto retry_sendfile;
11821 }
11822 stp->syserr = "sendfile";
11823 stp->error_no = errno;
11824 return (int)ss;
11825 }
11826 return 1;
11827}
11828#endif
11829
11830static ssize_t
11831maygvl_read(int has_gvl, rb_io_t *fptr, void *buf, size_t count)
11832{
11833 if (has_gvl)
11834 return rb_read_internal(fptr, buf, count);
11835 else
11836 return read(fptr->fd, buf, count);
11837}
11838
11839static ssize_t
11840maygvl_copy_stream_read(int has_gvl, struct copy_stream_struct *stp, char *buf, size_t len, off_t offset)
11841{
11842 ssize_t ss;
11843 retry_read:
11844 if (offset < (off_t)0) {
11845 ss = maygvl_read(has_gvl, stp->src_fptr, buf, len);
11846 }
11847 else {
11848#ifdef HAVE_PREAD
11849 ss = pread(stp->src_fptr->fd, buf, len, offset);
11850#else
11851 stp->notimp = "pread";
11852 return -1;
11853#endif
11854 }
11855 if (ss == 0) {
11856 return 0;
11857 }
11858 if (ss < 0) {
11859 if (maygvl_copy_stream_continue_p(has_gvl, stp))
11860 goto retry_read;
11861 switch (errno) {
11862 case EAGAIN:
11863#if EWOULDBLOCK != EAGAIN
11864 case EWOULDBLOCK:
11865#endif
11866 {
11867 int ret = maygvl_copy_stream_wait_read(has_gvl, stp);
11868 if (ret < 0) return ret;
11869 }
11870 goto retry_read;
11871#ifdef ENOSYS
11872 case ENOSYS:
11873 stp->notimp = "pread";
11874 return ss;
11875#endif
11876 }
11877 stp->syserr = offset < (off_t)0 ? "read" : "pread";
11878 stp->error_no = errno;
11879 }
11880 return ss;
11881}
11882
11883static int
11884nogvl_copy_stream_write(struct copy_stream_struct *stp, char *buf, size_t len)
11885{
11886 ssize_t ss;
11887 int off = 0;
11888 while (len) {
11889 ss = write(stp->dst_fptr->fd, buf+off, len);
11890 if (ss < 0) {
11891 if (maygvl_copy_stream_continue_p(0, stp))
11892 continue;
11893 if (io_again_p(errno)) {
11894 int ret = nogvl_copy_stream_wait_write(stp);
11895 if (ret < 0) return ret;
11896 continue;
11897 }
11898 stp->syserr = "write";
11899 stp->error_no = errno;
11900 return (int)ss;
11901 }
11902 off += (int)ss;
11903 len -= (int)ss;
11904 stp->total += ss;
11905 }
11906 return 0;
11907}
11908
11909static void
11910nogvl_copy_stream_read_write(struct copy_stream_struct *stp)
11911{
11912 char buf[1024*16];
11913 size_t len;
11914 ssize_t ss;
11915 int ret;
11916 off_t copy_length;
11917 int use_eof;
11918 off_t src_offset;
11919 int use_pread;
11920
11921 copy_length = stp->copy_length;
11922 use_eof = copy_length < (off_t)0;
11923 src_offset = stp->src_offset;
11924 use_pread = src_offset >= (off_t)0;
11925
11926 if (use_pread && stp->close_src) {
11927 off_t r;
11928 errno = 0;
11929 r = lseek(stp->src_fptr->fd, src_offset, SEEK_SET);
11930 if (r < (off_t)0 && errno) {
11931 stp->syserr = "lseek";
11932 stp->error_no = errno;
11933 return;
11934 }
11935 src_offset = (off_t)-1;
11936 use_pread = 0;
11937 }
11938
11939 while (use_eof || 0 < copy_length) {
11940 if (!use_eof && copy_length < (off_t)sizeof(buf)) {
11941 len = (size_t)copy_length;
11942 }
11943 else {
11944 len = sizeof(buf);
11945 }
11946 if (use_pread) {
11947 ss = maygvl_copy_stream_read(0, stp, buf, len, src_offset);
11948 if (0 < ss)
11949 src_offset += ss;
11950 }
11951 else {
11952 ss = maygvl_copy_stream_read(0, stp, buf, len, (off_t)-1);
11953 }
11954 if (ss <= 0) /* EOF or error */
11955 return;
11956
11957 ret = nogvl_copy_stream_write(stp, buf, ss);
11958 if (ret < 0)
11959 return;
11960
11961 if (!use_eof)
11962 copy_length -= ss;
11963 }
11964}
11965
11966static void *
11967nogvl_copy_stream_func(void *arg)
11968{
11969 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
11970#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
11971 int ret;
11972#endif
11973
11974#ifdef USE_COPY_FILE_RANGE
11975 ret = nogvl_copy_file_range(stp);
11976 if (ret != 0)
11977 goto finish; /* error or success */
11978#endif
11979
11980#ifdef HAVE_FCOPYFILE
11981 ret = nogvl_fcopyfile(stp);
11982 if (ret != 0)
11983 goto finish; /* error or success */
11984#endif
11985
11986#ifdef USE_SENDFILE
11987 ret = nogvl_copy_stream_sendfile(stp);
11988 if (ret != 0)
11989 goto finish; /* error or success */
11990#endif
11991
11992 nogvl_copy_stream_read_write(stp);
11993
11994#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
11995 finish:
11996#endif
11997 return 0;
11998}
11999
12000static VALUE
12001copy_stream_fallback_body(VALUE arg)
12002{
12003 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
12004 const int buflen = 16*1024;
12005 VALUE n;
12006 VALUE buf = rb_str_buf_new(buflen);
12007 off_t rest = stp->copy_length;
12008 off_t off = stp->src_offset;
12009 ID read_method = id_readpartial;
12010
12011 if (!stp->src_fptr) {
12012 if (!rb_respond_to(stp->src, read_method)) {
12013 read_method = id_read;
12014 }
12015 }
12016
12017 while (1) {
12018 long numwrote;
12019 long l;
12020 if (stp->copy_length < (off_t)0) {
12021 l = buflen;
12022 }
12023 else {
12024 if (rest == 0) {
12025 rb_str_resize(buf, 0);
12026 break;
12027 }
12028 l = buflen < rest ? buflen : (long)rest;
12029 }
12030 if (!stp->src_fptr) {
12031 VALUE rc = rb_funcall(stp->src, read_method, 2, INT2FIX(l), buf);
12032
12033 if (read_method == id_read && NIL_P(rc))
12034 break;
12035 }
12036 else {
12037 ssize_t ss;
12038 rb_str_resize(buf, buflen);
12039 ss = maygvl_copy_stream_read(1, stp, RSTRING_PTR(buf), l, off);
12040 rb_str_resize(buf, ss > 0 ? ss : 0);
12041 if (ss < 0)
12042 return Qnil;
12043 if (ss == 0)
12044 rb_eof_error();
12045 if (off >= (off_t)0)
12046 off += ss;
12047 }
12048 n = rb_io_write(stp->dst, buf);
12049 numwrote = NUM2LONG(n);
12050 stp->total += numwrote;
12051 rest -= numwrote;
12052 if (read_method == id_read && RSTRING_LEN(buf) == 0) {
12053 break;
12054 }
12055 }
12056
12057 return Qnil;
12058}
12059
12060static VALUE
12061copy_stream_fallback(struct copy_stream_struct *stp)
12062{
12063 if (!stp->src_fptr && stp->src_offset >= (off_t)0) {
12064 rb_raise(rb_eArgError, "cannot specify src_offset for non-IO");
12065 }
12066 rb_rescue2(copy_stream_fallback_body, (VALUE)stp,
12067 (VALUE (*) (VALUE, VALUE))0, (VALUE)0,
12068 rb_eEOFError, (VALUE)0);
12069 return Qnil;
12070}
12071
12072static VALUE
12073copy_stream_body(VALUE arg)
12074{
12075 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
12076 VALUE src_io = stp->src, dst_io = stp->dst;
12077 const int common_oflags = 0
12078#ifdef O_NOCTTY
12079 | O_NOCTTY
12080#endif
12081 ;
12082
12083 stp->th = rb_thread_current();
12084
12085 stp->total = 0;
12086
12087 if (src_io == argf ||
12088 !(RB_TYPE_P(src_io, T_FILE) ||
12089 RB_TYPE_P(src_io, T_STRING) ||
12090 rb_respond_to(src_io, rb_intern("to_path")))) {
12091 stp->src_fptr = NULL;
12092 }
12093 else {
12094 int stat_ret;
12095 VALUE tmp_io = rb_io_check_io(src_io);
12096 if (!NIL_P(tmp_io)) {
12097 src_io = tmp_io;
12098 }
12099 else if (!RB_TYPE_P(src_io, T_FILE)) {
12100 VALUE args[2];
12101 FilePathValue(src_io);
12102 args[0] = src_io;
12103 args[1] = INT2NUM(O_RDONLY|common_oflags);
12104 src_io = rb_class_new_instance(2, args, rb_cFile);
12105 stp->src = src_io;
12106 stp->close_src = 1;
12107 }
12108 RB_IO_POINTER(src_io, stp->src_fptr);
12109 rb_io_check_byte_readable(stp->src_fptr);
12110
12111 stat_ret = fstat(stp->src_fptr->fd, &stp->src_stat);
12112 if (stat_ret < 0) {
12113 stp->syserr = "fstat";
12114 stp->error_no = errno;
12115 return Qnil;
12116 }
12117 }
12118
12119 if (dst_io == argf ||
12120 !(RB_TYPE_P(dst_io, T_FILE) ||
12121 RB_TYPE_P(dst_io, T_STRING) ||
12122 rb_respond_to(dst_io, rb_intern("to_path")))) {
12123 stp->dst_fptr = NULL;
12124 }
12125 else {
12126 int stat_ret;
12127 VALUE tmp_io = rb_io_check_io(dst_io);
12128 if (!NIL_P(tmp_io)) {
12129 dst_io = GetWriteIO(tmp_io);
12130 }
12131 else if (!RB_TYPE_P(dst_io, T_FILE)) {
12132 VALUE args[3];
12133 FilePathValue(dst_io);
12134 args[0] = dst_io;
12135 args[1] = INT2NUM(O_WRONLY|O_CREAT|O_TRUNC|common_oflags);
12136 args[2] = INT2FIX(0666);
12137 dst_io = rb_class_new_instance(3, args, rb_cFile);
12138 stp->dst = dst_io;
12139 stp->close_dst = 1;
12140 }
12141 else {
12142 dst_io = GetWriteIO(dst_io);
12143 stp->dst = dst_io;
12144 }
12145 RB_IO_POINTER(dst_io, stp->dst_fptr);
12146 rb_io_check_writable(stp->dst_fptr);
12147
12148 stat_ret = fstat(stp->dst_fptr->fd, &stp->dst_stat);
12149 if (stat_ret < 0) {
12150 stp->syserr = "fstat";
12151 stp->error_no = errno;
12152 return Qnil;
12153 }
12154 }
12155
12156#ifdef O_BINARY
12157 if (stp->src_fptr)
12158 SET_BINARY_MODE_WITH_SEEK_CUR(stp->src_fptr);
12159#endif
12160 if (stp->dst_fptr)
12161 io_ascii8bit_binmode(stp->dst_fptr);
12162
12163 if (stp->src_offset < (off_t)0 && stp->src_fptr && stp->src_fptr->rbuf.len) {
12164 size_t len = stp->src_fptr->rbuf.len;
12165 VALUE str;
12166 if (stp->copy_length >= (off_t)0 && stp->copy_length < (off_t)len) {
12167 len = (size_t)stp->copy_length;
12168 }
12169 str = rb_str_buf_new(len);
12170 rb_str_resize(str,len);
12171 read_buffered_data(RSTRING_PTR(str), len, stp->src_fptr);
12172 if (stp->dst_fptr) { /* IO or filename */
12173 if (io_binwrite(str, RSTRING_PTR(str), RSTRING_LEN(str), stp->dst_fptr, 0) < 0)
12174 rb_sys_fail_on_write(stp->dst_fptr);
12175 }
12176 else /* others such as StringIO */
12177 rb_io_write(dst_io, str);
12178 rb_str_resize(str, 0);
12179 stp->total += len;
12180 if (stp->copy_length >= (off_t)0)
12181 stp->copy_length -= len;
12182 }
12183
12184 if (stp->dst_fptr && io_fflush(stp->dst_fptr) < 0) {
12185 rb_raise(rb_eIOError, "flush failed");
12186 }
12187
12188 if (stp->copy_length == 0)
12189 return Qnil;
12190
12191 if (stp->src_fptr == NULL || stp->dst_fptr == NULL) {
12192 return copy_stream_fallback(stp);
12193 }
12194
12195 rb_thread_call_without_gvl(nogvl_copy_stream_func, (void*)stp, RUBY_UBF_IO, 0);
12196 return Qnil;
12197}
12198
12199static VALUE
12200copy_stream_finalize(VALUE arg)
12201{
12202 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
12203
12204#ifdef HAVE_FCOPYFILE
12205 if (stp->copyfile_state) {
12206 copyfile_state_free(stp->copyfile_state);
12207 }
12208#endif
12209
12210 if (stp->close_src) {
12211 rb_io_close_m(stp->src);
12212 }
12213 if (stp->close_dst) {
12214 rb_io_close_m(stp->dst);
12215 }
12216 if (stp->syserr) {
12217 rb_syserr_fail(stp->error_no, stp->syserr);
12218 }
12219 if (stp->notimp) {
12220 rb_raise(rb_eNotImpError, "%s() not implemented", stp->notimp);
12221 }
12222 return Qnil;
12223}
12224
12225/*
12226 * call-seq:
12227 * IO.copy_stream(src, dst)
12228 * IO.copy_stream(src, dst, copy_length)
12229 * IO.copy_stream(src, dst, copy_length, src_offset)
12230 *
12231 * IO.copy_stream copies <i>src</i> to <i>dst</i>.
12232 * <i>src</i> and <i>dst</i> is either a filename or an IO-like object.
12233 * IO-like object for <i>src</i> should have #readpartial or #read
12234 * method. IO-like object for <i>dst</i> should have #write method.
12235 * (Specialized mechanisms, such as sendfile system call, may be used
12236 * on appropriate situation.)
12237 *
12238 * This method returns the number of bytes copied.
12239 *
12240 * If optional arguments are not given,
12241 * the start position of the copy is
12242 * the beginning of the filename or
12243 * the current file offset of the IO.
12244 * The end position of the copy is the end of file.
12245 *
12246 * If <i>copy_length</i> is given,
12247 * No more than <i>copy_length</i> bytes are copied.
12248 *
12249 * If <i>src_offset</i> is given,
12250 * it specifies the start position of the copy.
12251 *
12252 * When <i>src_offset</i> is specified and
12253 * <i>src</i> is an IO,
12254 * IO.copy_stream doesn't move the current file offset.
12255 *
12256 */
12257static VALUE
12258rb_io_s_copy_stream(int argc, VALUE *argv, VALUE io)
12259{
12260 VALUE src, dst, length, src_offset;
12261 struct copy_stream_struct st;
12262
12263 MEMZERO(&st, struct copy_stream_struct, 1);
12264
12265 rb_scan_args(argc, argv, "22", &src, &dst, &length, &src_offset);
12266
12267 st.src = src;
12268 st.dst = dst;
12269
12270 st.src_fptr = NULL;
12271 st.dst_fptr = NULL;
12272
12273 if (NIL_P(length))
12274 st.copy_length = (off_t)-1;
12275 else
12276 st.copy_length = NUM2OFFT(length);
12277
12278 if (NIL_P(src_offset))
12279 st.src_offset = (off_t)-1;
12280 else
12281 st.src_offset = NUM2OFFT(src_offset);
12282
12283 rb_ensure(copy_stream_body, (VALUE)&st, copy_stream_finalize, (VALUE)&st);
12284
12285 return OFFT2NUM(st.total);
12286}
12287
12288/*
12289 * call-seq:
12290 * io.external_encoding -> encoding
12291 *
12292 * Returns the Encoding object that represents the encoding of the file.
12293 * If _io_ is in write mode and no encoding is specified, returns +nil+.
12294 */
12295
12296static VALUE
12297rb_io_external_encoding(VALUE io)
12298{
12299 rb_io_t *fptr = RFILE(rb_io_taint_check(io))->fptr;
12300
12301 if (fptr->encs.enc2) {
12302 return rb_enc_from_encoding(fptr->encs.enc2);
12303 }
12304 if (fptr->mode & FMODE_WRITABLE) {
12305 if (fptr->encs.enc)
12306 return rb_enc_from_encoding(fptr->encs.enc);
12307 return Qnil;
12308 }
12309 return rb_enc_from_encoding(io_read_encoding(fptr));
12310}
12311
12312/*
12313 * call-seq:
12314 * io.internal_encoding -> encoding
12315 *
12316 * Returns the Encoding of the internal string if conversion is
12317 * specified. Otherwise returns +nil+.
12318 */
12319
12320static VALUE
12321rb_io_internal_encoding(VALUE io)
12322{
12323 rb_io_t *fptr = RFILE(rb_io_taint_check(io))->fptr;
12324
12325 if (!fptr->encs.enc2) return Qnil;
12326 return rb_enc_from_encoding(io_read_encoding(fptr));
12327}
12328
12329/*
12330 * call-seq:
12331 * io.set_encoding(ext_enc) -> io
12332 * io.set_encoding("ext_enc:int_enc") -> io
12333 * io.set_encoding(ext_enc, int_enc) -> io
12334 * io.set_encoding("ext_enc:int_enc", opt) -> io
12335 * io.set_encoding(ext_enc, int_enc, opt) -> io
12336 *
12337 * If single argument is specified, read string from io is tagged
12338 * with the encoding specified. If encoding is a colon separated two
12339 * encoding names "A:B", the read string is converted from encoding A
12340 * (external encoding) to encoding B (internal encoding), then tagged
12341 * with B. If two arguments are specified, those must be encoding
12342 * objects or encoding names, and the first one is the external encoding, and the
12343 * second one is the internal encoding.
12344 * If the external encoding and the internal encoding is specified,
12345 * optional hash argument specify the conversion option.
12346 */
12347
12348static VALUE
12349rb_io_set_encoding(int argc, VALUE *argv, VALUE io)
12350{
12351 rb_io_t *fptr;
12352 VALUE v1, v2, opt;
12353
12354 if (!RB_TYPE_P(io, T_FILE)) {
12355 return forward(io, id_set_encoding, argc, argv);
12356 }
12357
12358 argc = rb_scan_args(argc, argv, "11:", &v1, &v2, &opt);
12359 GetOpenFile(io, fptr);
12360 io_encoding_set(fptr, v1, v2, opt);
12361 return io;
12362}
12363
12364void
12365rb_stdio_set_default_encoding(void)
12366{
12367 VALUE val = Qnil;
12368
12369#ifdef _WIN32
12370 if (isatty(fileno(stdin))) {
12371 rb_encoding *external = rb_locale_encoding();
12373 if (!internal) internal = rb_default_external_encoding();
12374 io_encoding_set(RFILE(rb_stdin)->fptr,
12375 rb_enc_from_encoding(external),
12376 rb_enc_from_encoding(internal),
12377 Qnil);
12378 }
12379 else
12380#endif
12381 rb_io_set_encoding(1, &val, rb_stdin);
12382 rb_io_set_encoding(1, &val, rb_stdout);
12383 rb_io_set_encoding(1, &val, rb_stderr);
12384}
12385
12386static inline int
12387global_argf_p(VALUE arg)
12388{
12389 return arg == argf;
12390}
12391
12392/*
12393 * call-seq:
12394 * ARGF.external_encoding -> encoding
12395 *
12396 * Returns the external encoding for files read from +ARGF+ as an +Encoding+
12397 * object. The external encoding is the encoding of the text as stored in a
12398 * file. Contrast with +ARGF.internal_encoding+, which is the encoding used
12399 * to represent this text within Ruby.
12400 *
12401 * To set the external encoding use +ARGF.set_encoding+.
12402 *
12403 * For example:
12404 *
12405 * ARGF.external_encoding #=> #<Encoding:UTF-8>
12406 *
12407 */
12408static VALUE
12409argf_external_encoding(VALUE argf)
12410{
12411 if (!RTEST(ARGF.current_file)) {
12413 }
12414 return rb_io_external_encoding(rb_io_check_io(ARGF.current_file));
12415}
12416
12417/*
12418 * call-seq:
12419 * ARGF.internal_encoding -> encoding
12420 *
12421 * Returns the internal encoding for strings read from +ARGF+ as an
12422 * +Encoding+ object.
12423 *
12424 * If +ARGF.set_encoding+ has been called with two encoding names, the second
12425 * is returned. Otherwise, if +Encoding.default_external+ has been set, that
12426 * value is returned. Failing that, if a default external encoding was
12427 * specified on the command-line, that value is used. If the encoding is
12428 * unknown, +nil+ is returned.
12429 */
12430static VALUE
12431argf_internal_encoding(VALUE argf)
12432{
12433 if (!RTEST(ARGF.current_file)) {
12435 }
12436 return rb_io_internal_encoding(rb_io_check_io(ARGF.current_file));
12437}
12438
12439/*
12440 * call-seq:
12441 * ARGF.set_encoding(ext_enc) -> ARGF
12442 * ARGF.set_encoding("ext_enc:int_enc") -> ARGF
12443 * ARGF.set_encoding(ext_enc, int_enc) -> ARGF
12444 * ARGF.set_encoding("ext_enc:int_enc", opt) -> ARGF
12445 * ARGF.set_encoding(ext_enc, int_enc, opt) -> ARGF
12446 *
12447 * If single argument is specified, strings read from ARGF are tagged with
12448 * the encoding specified.
12449 *
12450 * If two encoding names separated by a colon are given, e.g. "ascii:utf-8",
12451 * the read string is converted from the first encoding (external encoding)
12452 * to the second encoding (internal encoding), then tagged with the second
12453 * encoding.
12454 *
12455 * If two arguments are specified, they must be encoding objects or encoding
12456 * names. Again, the first specifies the external encoding; the second
12457 * specifies the internal encoding.
12458 *
12459 * If the external encoding and the internal encoding are specified, the
12460 * optional +Hash+ argument can be used to adjust the conversion process. The
12461 * structure of this hash is explained in the String#encode documentation.
12462 *
12463 * For example:
12464 *
12465 * ARGF.set_encoding('ascii') # Tag the input as US-ASCII text
12466 * ARGF.set_encoding(Encoding::UTF_8) # Tag the input as UTF-8 text
12467 * ARGF.set_encoding('utf-8','ascii') # Transcode the input from US-ASCII
12468 * # to UTF-8.
12469 */
12470static VALUE
12471argf_set_encoding(int argc, VALUE *argv, VALUE argf)
12472{
12473 rb_io_t *fptr;
12474
12475 if (!next_argv()) {
12476 rb_raise(rb_eArgError, "no stream to set encoding");
12477 }
12478 rb_io_set_encoding(argc, argv, ARGF.current_file);
12479 GetOpenFile(ARGF.current_file, fptr);
12480 ARGF.encs = fptr->encs;
12481 return argf;
12482}
12483
12484/*
12485 * call-seq:
12486 * ARGF.tell -> Integer
12487 * ARGF.pos -> Integer
12488 *
12489 * Returns the current offset (in bytes) of the current file in +ARGF+.
12490 *
12491 * ARGF.pos #=> 0
12492 * ARGF.gets #=> "This is line one\n"
12493 * ARGF.pos #=> 17
12494 *
12495 */
12496static VALUE
12497argf_tell(VALUE argf)
12498{
12499 if (!next_argv()) {
12500 rb_raise(rb_eArgError, "no stream to tell");
12501 }
12502 ARGF_FORWARD(0, 0);
12503 return rb_io_tell(ARGF.current_file);
12504}
12505
12506/*
12507 * call-seq:
12508 * ARGF.seek(amount, whence=IO::SEEK_SET) -> 0
12509 *
12510 * Seeks to offset _amount_ (an +Integer+) in the +ARGF+ stream according to
12511 * the value of _whence_. See IO#seek for further details.
12512 */
12513static VALUE
12514argf_seek_m(int argc, VALUE *argv, VALUE argf)
12515{
12516 if (!next_argv()) {
12517 rb_raise(rb_eArgError, "no stream to seek");
12518 }
12519 ARGF_FORWARD(argc, argv);
12520 return rb_io_seek_m(argc, argv, ARGF.current_file);
12521}
12522
12523/*
12524 * call-seq:
12525 * ARGF.pos = position -> Integer
12526 *
12527 * Seeks to the position given by _position_ (in bytes) in +ARGF+.
12528 *
12529 * For example:
12530 *
12531 * ARGF.pos = 17
12532 * ARGF.gets #=> "This is line two\n"
12533 */
12534static VALUE
12535argf_set_pos(VALUE argf, VALUE offset)
12536{
12537 if (!next_argv()) {
12538 rb_raise(rb_eArgError, "no stream to set position");
12539 }
12540 ARGF_FORWARD(1, &offset);
12541 return rb_io_set_pos(ARGF.current_file, offset);
12542}
12543
12544/*
12545 * call-seq:
12546 * ARGF.rewind -> 0
12547 *
12548 * Positions the current file to the beginning of input, resetting
12549 * +ARGF.lineno+ to zero.
12550 *
12551 * ARGF.readline #=> "This is line one\n"
12552 * ARGF.rewind #=> 0
12553 * ARGF.lineno #=> 0
12554 * ARGF.readline #=> "This is line one\n"
12555 */
12556static VALUE
12557argf_rewind(VALUE argf)
12558{
12559 VALUE ret;
12560 int old_lineno;
12561
12562 if (!next_argv()) {
12563 rb_raise(rb_eArgError, "no stream to rewind");
12564 }
12565 ARGF_FORWARD(0, 0);
12566 old_lineno = RFILE(ARGF.current_file)->fptr->lineno;
12567 ret = rb_io_rewind(ARGF.current_file);
12568 if (!global_argf_p(argf)) {
12569 ARGF.last_lineno = ARGF.lineno -= old_lineno;
12570 }
12571 return ret;
12572}
12573
12574/*
12575 * call-seq:
12576 * ARGF.fileno -> integer
12577 * ARGF.to_i -> integer
12578 *
12579 * Returns an integer representing the numeric file descriptor for
12580 * the current file. Raises an +ArgumentError+ if there isn't a current file.
12581 *
12582 * ARGF.fileno #=> 3
12583 */
12584static VALUE
12585argf_fileno(VALUE argf)
12586{
12587 if (!next_argv()) {
12588 rb_raise(rb_eArgError, "no stream");
12589 }
12590 ARGF_FORWARD(0, 0);
12591 return rb_io_fileno(ARGF.current_file);
12592}
12593
12594/*
12595 * call-seq:
12596 * ARGF.to_io -> IO
12597 *
12598 * Returns an +IO+ object representing the current file. This will be a
12599 * +File+ object unless the current file is a stream such as STDIN.
12600 *
12601 * For example:
12602 *
12603 * ARGF.to_io #=> #<File:glark.txt>
12604 * ARGF.to_io #=> #<IO:<STDIN>>
12605 */
12606static VALUE
12607argf_to_io(VALUE argf)
12608{
12609 next_argv();
12610 ARGF_FORWARD(0, 0);
12611 return ARGF.current_file;
12612}
12613
12614/*
12615 * call-seq:
12616 * ARGF.eof? -> true or false
12617 * ARGF.eof -> true or false
12618 *
12619 * Returns true if the current file in +ARGF+ is at end of file, i.e. it has
12620 * no data to read. The stream must be opened for reading or an +IOError+
12621 * will be raised.
12622 *
12623 * $ echo "eof" | ruby argf.rb
12624 *
12625 * ARGF.eof? #=> false
12626 * 3.times { ARGF.readchar }
12627 * ARGF.eof? #=> false
12628 * ARGF.readchar #=> "\n"
12629 * ARGF.eof? #=> true
12630 */
12631
12632static VALUE
12633argf_eof(VALUE argf)
12634{
12635 next_argv();
12636 if (RTEST(ARGF.current_file)) {
12637 if (ARGF.init_p == 0) return Qtrue;
12638 next_argv();
12639 ARGF_FORWARD(0, 0);
12640 if (rb_io_eof(ARGF.current_file)) {
12641 return Qtrue;
12642 }
12643 }
12644 return Qfalse;
12645}
12646
12647/*
12648 * call-seq:
12649 * ARGF.read([length [, outbuf]]) -> string, outbuf, or nil
12650 *
12651 * Reads _length_ bytes from ARGF. The files named on the command line
12652 * are concatenated and treated as a single file by this method, so when
12653 * called without arguments the contents of this pseudo file are returned in
12654 * their entirety.
12655 *
12656 * _length_ must be a non-negative integer or +nil+.
12657 *
12658 * If _length_ is a positive integer, +read+ tries to read
12659 * _length_ bytes without any conversion (binary mode).
12660 * It returns +nil+ if an EOF is encountered before anything can be read.
12661 * Fewer than _length_ bytes are returned if an EOF is encountered during
12662 * the read.
12663 * In the case of an integer _length_, the resulting string is always
12664 * in ASCII-8BIT encoding.
12665 *
12666 * If _length_ is omitted or is +nil+, it reads until EOF
12667 * and the encoding conversion is applied, if applicable.
12668 * A string is returned even if EOF is encountered before any data is read.
12669 *
12670 * If _length_ is zero, it returns an empty string (<code>""</code>).
12671 *
12672 * If the optional _outbuf_ argument is present,
12673 * it must reference a String, which will receive the data.
12674 * The _outbuf_ will contain only the received data after the method call
12675 * even if it is not empty at the beginning.
12676 *
12677 * For example:
12678 *
12679 * $ echo "small" > small.txt
12680 * $ echo "large" > large.txt
12681 * $ ./glark.rb small.txt large.txt
12682 *
12683 * ARGF.read #=> "small\nlarge"
12684 * ARGF.read(200) #=> "small\nlarge"
12685 * ARGF.read(2) #=> "sm"
12686 * ARGF.read(0) #=> ""
12687 *
12688 * Note that this method behaves like the fread() function in C.
12689 * This means it retries to invoke read(2) system calls to read data
12690 * with the specified length.
12691 * If you need the behavior like a single read(2) system call,
12692 * consider ARGF#readpartial or ARGF#read_nonblock.
12693 */
12694
12695static VALUE
12696argf_read(int argc, VALUE *argv, VALUE argf)
12697{
12698 VALUE tmp, str, length;
12699 long len = 0;
12700
12701 rb_scan_args(argc, argv, "02", &length, &str);
12702 if (!NIL_P(length)) {
12703 len = NUM2LONG(argv[0]);
12704 }
12705 if (!NIL_P(str)) {
12706 StringValue(str);
12707 rb_str_resize(str,0);
12708 argv[1] = Qnil;
12709 }
12710
12711 retry:
12712 if (!next_argv()) {
12713 return str;
12714 }
12715 if (ARGF_GENERIC_INPUT_P()) {
12716 tmp = argf_forward(argc, argv, argf);
12717 }
12718 else {
12719 tmp = io_read(argc, argv, ARGF.current_file);
12720 }
12721 if (NIL_P(str)) str = tmp;
12722 else if (!NIL_P(tmp)) rb_str_append(str, tmp);
12723 if (NIL_P(tmp) || NIL_P(length)) {
12724 if (ARGF.next_p != -1) {
12725 argf_close(argf);
12726 ARGF.next_p = 1;
12727 goto retry;
12728 }
12729 }
12730 else if (argc >= 1) {
12731 long slen = RSTRING_LEN(str);
12732 if (slen < len) {
12733 argv[0] = LONG2NUM(len - slen);
12734 goto retry;
12735 }
12736 }
12737 return str;
12738}
12739
12741 int argc;
12742 VALUE *argv;
12743 VALUE argf;
12744};
12745
12746static VALUE
12747argf_forward_call(VALUE arg)
12748{
12749 struct argf_call_arg *p = (struct argf_call_arg *)arg;
12750 argf_forward(p->argc, p->argv, p->argf);
12751 return Qnil;
12752}
12753
12754static VALUE argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts,
12755 int nonblock);
12756
12757/*
12758 * call-seq:
12759 * ARGF.readpartial(maxlen) -> string
12760 * ARGF.readpartial(maxlen, outbuf) -> outbuf
12761 *
12762 * Reads at most _maxlen_ bytes from the ARGF stream.
12763 *
12764 * If the optional _outbuf_ argument is present,
12765 * it must reference a String, which will receive the data.
12766 * The _outbuf_ will contain only the received data after the method call
12767 * even if it is not empty at the beginning.
12768 *
12769 * It raises EOFError on end of ARGF stream.
12770 * Since ARGF stream is a concatenation of multiple files,
12771 * internally EOF is occur for each file.
12772 * ARGF.readpartial returns empty strings for EOFs except the last one and
12773 * raises EOFError for the last one.
12774 *
12775 */
12776
12777static VALUE
12778argf_readpartial(int argc, VALUE *argv, VALUE argf)
12779{
12780 return argf_getpartial(argc, argv, argf, Qnil, 0);
12781}
12782
12783/*
12784 * call-seq:
12785 * ARGF.read_nonblock(maxlen[, options]) -> string
12786 * ARGF.read_nonblock(maxlen, outbuf[, options]) -> outbuf
12787 *
12788 * Reads at most _maxlen_ bytes from the ARGF stream in non-blocking mode.
12789 */
12790
12791static VALUE
12792argf_read_nonblock(int argc, VALUE *argv, VALUE argf)
12793{
12794 VALUE opts;
12795
12796 rb_scan_args(argc, argv, "11:", NULL, NULL, &opts);
12797
12798 if (!NIL_P(opts))
12799 argc--;
12800
12801 return argf_getpartial(argc, argv, argf, opts, 1);
12802}
12803
12804static VALUE
12805argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts, int nonblock)
12806{
12807 VALUE tmp, str, length;
12808 int no_exception;
12809
12810 rb_scan_args(argc, argv, "11", &length, &str);
12811 if (!NIL_P(str)) {
12812 StringValue(str);
12813 argv[1] = str;
12814 }
12815 no_exception = no_exception_p(opts);
12816
12817 if (!next_argv()) {
12818 if (!NIL_P(str)) {
12819 rb_str_resize(str, 0);
12820 }
12821 rb_eof_error();
12822 }
12823 if (ARGF_GENERIC_INPUT_P()) {
12824 VALUE (*const rescue_does_nothing)(VALUE, VALUE) = 0;
12825 struct argf_call_arg arg;
12826 arg.argc = argc;
12827 arg.argv = argv;
12828 arg.argf = argf;
12829 tmp = rb_rescue2(argf_forward_call, (VALUE)&arg,
12830 rescue_does_nothing, Qnil, rb_eEOFError, (VALUE)0);
12831 }
12832 else {
12833 tmp = io_getpartial(argc, argv, ARGF.current_file, no_exception, nonblock);
12834 }
12835 if (NIL_P(tmp)) {
12836 if (ARGF.next_p == -1) {
12837 return io_nonblock_eof(no_exception);
12838 }
12839 argf_close(argf);
12840 ARGF.next_p = 1;
12841 if (RARRAY_LEN(ARGF.argv) == 0) {
12842 return io_nonblock_eof(no_exception);
12843 }
12844 if (NIL_P(str))
12845 str = rb_str_new(NULL, 0);
12846 return str;
12847 }
12848 return tmp;
12849}
12850
12851/*
12852 * call-seq:
12853 * ARGF.getc -> String or nil
12854 *
12855 * Reads the next character from +ARGF+ and returns it as a +String+. Returns
12856 * +nil+ at the end of the stream.
12857 *
12858 * +ARGF+ treats the files named on the command line as a single file created
12859 * by concatenating their contents. After returning the last character of the
12860 * first file, it returns the first character of the second file, and so on.
12861 *
12862 * For example:
12863 *
12864 * $ echo "foo" > file
12865 * $ ruby argf.rb file
12866 *
12867 * ARGF.getc #=> "f"
12868 * ARGF.getc #=> "o"
12869 * ARGF.getc #=> "o"
12870 * ARGF.getc #=> "\n"
12871 * ARGF.getc #=> nil
12872 * ARGF.getc #=> nil
12873 */
12874static VALUE
12875argf_getc(VALUE argf)
12876{
12877 VALUE ch;
12878
12879 retry:
12880 if (!next_argv()) return Qnil;
12881 if (ARGF_GENERIC_INPUT_P()) {
12882 ch = forward_current(rb_intern("getc"), 0, 0);
12883 }
12884 else {
12885 ch = rb_io_getc(ARGF.current_file);
12886 }
12887 if (NIL_P(ch) && ARGF.next_p != -1) {
12888 argf_close(argf);
12889 ARGF.next_p = 1;
12890 goto retry;
12891 }
12892
12893 return ch;
12894}
12895
12896/*
12897 * call-seq:
12898 * ARGF.getbyte -> Integer or nil
12899 *
12900 * Gets the next 8-bit byte (0..255) from +ARGF+. Returns +nil+ if called at
12901 * the end of the stream.
12902 *
12903 * For example:
12904 *
12905 * $ echo "foo" > file
12906 * $ ruby argf.rb file
12907 *
12908 * ARGF.getbyte #=> 102
12909 * ARGF.getbyte #=> 111
12910 * ARGF.getbyte #=> 111
12911 * ARGF.getbyte #=> 10
12912 * ARGF.getbyte #=> nil
12913 */
12914static VALUE
12915argf_getbyte(VALUE argf)
12916{
12917 VALUE ch;
12918
12919 retry:
12920 if (!next_argv()) return Qnil;
12921 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
12922 ch = forward_current(rb_intern("getbyte"), 0, 0);
12923 }
12924 else {
12925 ch = rb_io_getbyte(ARGF.current_file);
12926 }
12927 if (NIL_P(ch) && ARGF.next_p != -1) {
12928 argf_close(argf);
12929 ARGF.next_p = 1;
12930 goto retry;
12931 }
12932
12933 return ch;
12934}
12935
12936/*
12937 * call-seq:
12938 * ARGF.readchar -> String or nil
12939 *
12940 * Reads the next character from +ARGF+ and returns it as a +String+. Raises
12941 * an +EOFError+ after the last character of the last file has been read.
12942 *
12943 * For example:
12944 *
12945 * $ echo "foo" > file
12946 * $ ruby argf.rb file
12947 *
12948 * ARGF.readchar #=> "f"
12949 * ARGF.readchar #=> "o"
12950 * ARGF.readchar #=> "o"
12951 * ARGF.readchar #=> "\n"
12952 * ARGF.readchar #=> end of file reached (EOFError)
12953 */
12954static VALUE
12955argf_readchar(VALUE argf)
12956{
12957 VALUE ch;
12958
12959 retry:
12960 if (!next_argv()) rb_eof_error();
12961 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
12962 ch = forward_current(rb_intern("getc"), 0, 0);
12963 }
12964 else {
12965 ch = rb_io_getc(ARGF.current_file);
12966 }
12967 if (NIL_P(ch) && ARGF.next_p != -1) {
12968 argf_close(argf);
12969 ARGF.next_p = 1;
12970 goto retry;
12971 }
12972
12973 return ch;
12974}
12975
12976/*
12977 * call-seq:
12978 * ARGF.readbyte -> Integer
12979 *
12980 * Reads the next 8-bit byte from ARGF and returns it as an +Integer+. Raises
12981 * an +EOFError+ after the last byte of the last file has been read.
12982 *
12983 * For example:
12984 *
12985 * $ echo "foo" > file
12986 * $ ruby argf.rb file
12987 *
12988 * ARGF.readbyte #=> 102
12989 * ARGF.readbyte #=> 111
12990 * ARGF.readbyte #=> 111
12991 * ARGF.readbyte #=> 10
12992 * ARGF.readbyte #=> end of file reached (EOFError)
12993 */
12994static VALUE
12995argf_readbyte(VALUE argf)
12996{
12997 VALUE c;
12998
12999 NEXT_ARGF_FORWARD(0, 0);
13000 c = argf_getbyte(argf);
13001 if (NIL_P(c)) {
13002 rb_eof_error();
13003 }
13004 return c;
13005}
13006
13007#define FOREACH_ARGF() while (next_argv())
13008
13009static VALUE
13010argf_block_call_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
13011{
13012 const VALUE current = ARGF.current_file;
13013 rb_yield_values2(argc, argv);
13014 if (ARGF.init_p == -1 || current != ARGF.current_file) {
13016 }
13017 return Qnil;
13018}
13019
13020#define ARGF_block_call(mid, argc, argv, func, argf) \
13021 rb_block_call_kw(ARGF.current_file, mid, argc, argv, \
13022 func, argf, rb_keyword_given_p())
13023
13024static void
13025argf_block_call(ID mid, int argc, VALUE *argv, VALUE argf)
13026{
13027 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_i, argf);
13028 if (ret != Qundef) ARGF.next_p = 1;
13029}
13030
13031static VALUE
13032argf_block_call_line_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
13033{
13034 if (!global_argf_p(argf)) {
13035 ARGF.last_lineno = ++ARGF.lineno;
13036 }
13037 return argf_block_call_i(i, argf, argc, argv, blockarg);
13038}
13039
13040static void
13041argf_block_call_line(ID mid, int argc, VALUE *argv, VALUE argf)
13042{
13043 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_line_i, argf);
13044 if (ret != Qundef) ARGF.next_p = 1;
13045}
13046
13047/*
13048 * call-seq:
13049 * ARGF.each(sep=$/) {|line| block } -> ARGF
13050 * ARGF.each(sep=$/, limit) {|line| block } -> ARGF
13051 * ARGF.each(...) -> an_enumerator
13052 *
13053 * ARGF.each_line(sep=$/) {|line| block } -> ARGF
13054 * ARGF.each_line(sep=$/, limit) {|line| block } -> ARGF
13055 * ARGF.each_line(...) -> an_enumerator
13056 *
13057 * Returns an enumerator which iterates over each line (separated by _sep_,
13058 * which defaults to your platform's newline character) of each file in
13059 * +ARGV+. If a block is supplied, each line in turn will be yielded to the
13060 * block, otherwise an enumerator is returned.
13061 * The optional _limit_ argument is an +Integer+ specifying the maximum
13062 * length of each line; longer lines will be split according to this limit.
13063 *
13064 * This method allows you to treat the files supplied on the command line as
13065 * a single file consisting of the concatenation of each named file. After
13066 * the last line of the first file has been returned, the first line of the
13067 * second file is returned. The +ARGF.filename+ and +ARGF.lineno+ methods can
13068 * be used to determine the filename of the current line and line number of
13069 * the whole input, respectively.
13070 *
13071 * For example, the following code prints out each line of each named file
13072 * prefixed with its line number, displaying the filename once per file:
13073 *
13074 * ARGF.each_line do |line|
13075 * puts ARGF.filename if ARGF.file.lineno == 1
13076 * puts "#{ARGF.file.lineno}: #{line}"
13077 * end
13078 *
13079 * While the following code prints only the first file's name at first, and
13080 * the contents with line number counted through all named files.
13081 *
13082 * ARGF.each_line do |line|
13083 * puts ARGF.filename if ARGF.lineno == 1
13084 * puts "#{ARGF.lineno}: #{line}"
13085 * end
13086 */
13087static VALUE
13088argf_each_line(int argc, VALUE *argv, VALUE argf)
13089{
13090 RETURN_ENUMERATOR(argf, argc, argv);
13091 FOREACH_ARGF() {
13092 argf_block_call_line(rb_intern("each_line"), argc, argv, argf);
13093 }
13094 return argf;
13095}
13096
13097/*
13098 * call-seq:
13099 * ARGF.each_byte {|byte| block } -> ARGF
13100 * ARGF.each_byte -> an_enumerator
13101 *
13102 * Iterates over each byte of each file in +ARGV+.
13103 * A byte is returned as an +Integer+ in the range 0..255.
13104 *
13105 * This method allows you to treat the files supplied on the command line as
13106 * a single file consisting of the concatenation of each named file. After
13107 * the last byte of the first file has been returned, the first byte of the
13108 * second file is returned. The +ARGF.filename+ method can be used to
13109 * determine the filename of the current byte.
13110 *
13111 * If no block is given, an enumerator is returned instead.
13112 *
13113 * For example:
13114 *
13115 * ARGF.bytes.to_a #=> [35, 32, ... 95, 10]
13116 *
13117 */
13118static VALUE
13119argf_each_byte(VALUE argf)
13120{
13121 RETURN_ENUMERATOR(argf, 0, 0);
13122 FOREACH_ARGF() {
13123 argf_block_call(rb_intern("each_byte"), 0, 0, argf);
13124 }
13125 return argf;
13126}
13127
13128/*
13129 * call-seq:
13130 * ARGF.each_char {|char| block } -> ARGF
13131 * ARGF.each_char -> an_enumerator
13132 *
13133 * Iterates over each character of each file in +ARGF+.
13134 *
13135 * This method allows you to treat the files supplied on the command line as
13136 * a single file consisting of the concatenation of each named file. After
13137 * the last character of the first file has been returned, the first
13138 * character of the second file is returned. The +ARGF.filename+ method can
13139 * be used to determine the name of the file in which the current character
13140 * appears.
13141 *
13142 * If no block is given, an enumerator is returned instead.
13143 */
13144static VALUE
13145argf_each_char(VALUE argf)
13146{
13147 RETURN_ENUMERATOR(argf, 0, 0);
13148 FOREACH_ARGF() {
13149 argf_block_call(rb_intern("each_char"), 0, 0, argf);
13150 }
13151 return argf;
13152}
13153
13154/*
13155 * call-seq:
13156 * ARGF.each_codepoint {|codepoint| block } -> ARGF
13157 * ARGF.each_codepoint -> an_enumerator
13158 *
13159 * Iterates over each codepoint of each file in +ARGF+.
13160 *
13161 * This method allows you to treat the files supplied on the command line as
13162 * a single file consisting of the concatenation of each named file. After
13163 * the last codepoint of the first file has been returned, the first
13164 * codepoint of the second file is returned. The +ARGF.filename+ method can
13165 * be used to determine the name of the file in which the current codepoint
13166 * appears.
13167 *
13168 * If no block is given, an enumerator is returned instead.
13169 */
13170static VALUE
13171argf_each_codepoint(VALUE argf)
13172{
13173 RETURN_ENUMERATOR(argf, 0, 0);
13174 FOREACH_ARGF() {
13175 argf_block_call(rb_intern("each_codepoint"), 0, 0, argf);
13176 }
13177 return argf;
13178}
13179
13180/*
13181 * call-seq:
13182 * ARGF.filename -> String
13183 * ARGF.path -> String
13184 *
13185 * Returns the current filename. "-" is returned when the current file is
13186 * STDIN.
13187 *
13188 * For example:
13189 *
13190 * $ echo "foo" > foo
13191 * $ echo "bar" > bar
13192 * $ echo "glark" > glark
13193 *
13194 * $ ruby argf.rb foo bar glark
13195 *
13196 * ARGF.filename #=> "foo"
13197 * ARGF.read(5) #=> "foo\nb"
13198 * ARGF.filename #=> "bar"
13199 * ARGF.skip
13200 * ARGF.filename #=> "glark"
13201 */
13202static VALUE
13203argf_filename(VALUE argf)
13204{
13205 next_argv();
13206 return ARGF.filename;
13207}
13208
13209static VALUE
13210argf_filename_getter(ID id, VALUE *var)
13211{
13212 return argf_filename(*var);
13213}
13214
13215/*
13216 * call-seq:
13217 * ARGF.file -> IO or File object
13218 *
13219 * Returns the current file as an +IO+ or +File+ object.
13220 * <code>$stdin</code> is returned when the current file is STDIN.
13221 *
13222 * For example:
13223 *
13224 * $ echo "foo" > foo
13225 * $ echo "bar" > bar
13226 *
13227 * $ ruby argf.rb foo bar
13228 *
13229 * ARGF.file #=> #<File:foo>
13230 * ARGF.read(5) #=> "foo\nb"
13231 * ARGF.file #=> #<File:bar>
13232 */
13233static VALUE
13234argf_file(VALUE argf)
13235{
13236 next_argv();
13237 return ARGF.current_file;
13238}
13239
13240/*
13241 * call-seq:
13242 * ARGF.binmode -> ARGF
13243 *
13244 * Puts +ARGF+ into binary mode. Once a stream is in binary mode, it cannot
13245 * be reset to non-binary mode. This option has the following effects:
13246 *
13247 * * Newline conversion is disabled.
13248 * * Encoding conversion is disabled.
13249 * * Content is treated as ASCII-8BIT.
13250 */
13251static VALUE
13252argf_binmode_m(VALUE argf)
13253{
13254 ARGF.binmode = 1;
13255 next_argv();
13256 ARGF_FORWARD(0, 0);
13257 rb_io_ascii8bit_binmode(ARGF.current_file);
13258 return argf;
13259}
13260
13261/*
13262 * call-seq:
13263 * ARGF.binmode? -> true or false
13264 *
13265 * Returns true if +ARGF+ is being read in binary mode; false otherwise.
13266 * To enable binary mode use +ARGF.binmode+.
13267 *
13268 * For example:
13269 *
13270 * ARGF.binmode? #=> false
13271 * ARGF.binmode
13272 * ARGF.binmode? #=> true
13273 */
13274static VALUE
13275argf_binmode_p(VALUE argf)
13276{
13277 return RBOOL(ARGF.binmode);
13278}
13279
13280/*
13281 * call-seq:
13282 * ARGF.skip -> ARGF
13283 *
13284 * Sets the current file to the next file in ARGV. If there aren't any more
13285 * files it has no effect.
13286 *
13287 * For example:
13288 *
13289 * $ ruby argf.rb foo bar
13290 * ARGF.filename #=> "foo"
13291 * ARGF.skip
13292 * ARGF.filename #=> "bar"
13293 */
13294static VALUE
13295argf_skip(VALUE argf)
13296{
13297 if (ARGF.init_p && ARGF.next_p == 0) {
13298 argf_close(argf);
13299 ARGF.next_p = 1;
13300 }
13301 return argf;
13302}
13303
13304/*
13305 * call-seq:
13306 * ARGF.close -> ARGF
13307 *
13308 * Closes the current file and skips to the next file in ARGV. If there are
13309 * no more files to open, just closes the current file. +STDIN+ will not be
13310 * closed.
13311 *
13312 * For example:
13313 *
13314 * $ ruby argf.rb foo bar
13315 *
13316 * ARGF.filename #=> "foo"
13317 * ARGF.close
13318 * ARGF.filename #=> "bar"
13319 * ARGF.close
13320 */
13321static VALUE
13322argf_close_m(VALUE argf)
13323{
13324 next_argv();
13325 argf_close(argf);
13326 if (ARGF.next_p != -1) {
13327 ARGF.next_p = 1;
13328 }
13329 ARGF.lineno = 0;
13330 return argf;
13331}
13332
13333/*
13334 * call-seq:
13335 * ARGF.closed? -> true or false
13336 *
13337 * Returns _true_ if the current file has been closed; _false_ otherwise. Use
13338 * +ARGF.close+ to actually close the current file.
13339 */
13340static VALUE
13341argf_closed(VALUE argf)
13342{
13343 next_argv();
13344 ARGF_FORWARD(0, 0);
13345 return rb_io_closed(ARGF.current_file);
13346}
13347
13348/*
13349 * call-seq:
13350 * ARGF.to_s -> String
13351 *
13352 * Returns "ARGF".
13353 */
13354static VALUE
13355argf_to_s(VALUE argf)
13356{
13357 return rb_str_new2("ARGF");
13358}
13359
13360/*
13361 * call-seq:
13362 * ARGF.inplace_mode -> String
13363 *
13364 * Returns the file extension appended to the names of modified files under
13365 * in-place edit mode. This value can be set using +ARGF.inplace_mode=+ or
13366 * passing the +-i+ switch to the Ruby binary.
13367 */
13368static VALUE
13369argf_inplace_mode_get(VALUE argf)
13370{
13371 if (!ARGF.inplace) return Qnil;
13372 if (NIL_P(ARGF.inplace)) return rb_str_new(0, 0);
13373 return rb_str_dup(ARGF.inplace);
13374}
13375
13376static VALUE
13377opt_i_get(ID id, VALUE *var)
13378{
13379 return argf_inplace_mode_get(*var);
13380}
13381
13382/*
13383 * call-seq:
13384 * ARGF.inplace_mode = ext -> ARGF
13385 *
13386 * Sets the filename extension for in-place editing mode to the given String.
13387 * Each file being edited has this value appended to its filename. The
13388 * modified file is saved under this new name.
13389 *
13390 * For example:
13391 *
13392 * $ ruby argf.rb file.txt
13393 *
13394 * ARGF.inplace_mode = '.bak'
13395 * ARGF.each_line do |line|
13396 * print line.sub("foo","bar")
13397 * end
13398 *
13399 * Each line of _file.txt_ has the first occurrence of "foo" replaced with
13400 * "bar", then the new line is written out to _file.txt.bak_.
13401 */
13402static VALUE
13403argf_inplace_mode_set(VALUE argf, VALUE val)
13404{
13405 if (!RTEST(val)) {
13406 ARGF.inplace = Qfalse;
13407 }
13408 else if (StringValueCStr(val), !RSTRING_LEN(val)) {
13409 ARGF.inplace = Qnil;
13410 }
13411 else {
13412 ARGF.inplace = rb_str_new_frozen(val);
13413 }
13414 return argf;
13415}
13416
13417static void
13418opt_i_set(VALUE val, ID id, VALUE *var)
13419{
13420 argf_inplace_mode_set(*var, val);
13421}
13422
13423void
13424ruby_set_inplace_mode(const char *suffix)
13425{
13426 ARGF.inplace = !suffix ? Qfalse : !*suffix ? Qnil : rb_str_new(suffix, strlen(suffix));
13427}
13428
13429/*
13430 * call-seq:
13431 * ARGF.argv -> ARGV
13432 *
13433 * Returns the +ARGV+ array, which contains the arguments passed to your
13434 * script, one per element.
13435 *
13436 * For example:
13437 *
13438 * $ ruby argf.rb -v glark.txt
13439 *
13440 * ARGF.argv #=> ["-v", "glark.txt"]
13441 *
13442 */
13443static VALUE
13444argf_argv(VALUE argf)
13445{
13446 return ARGF.argv;
13447}
13448
13449static VALUE
13450argf_argv_getter(ID id, VALUE *var)
13451{
13452 return argf_argv(*var);
13453}
13454
13455VALUE
13457{
13458 return ARGF.argv;
13459}
13460
13461/*
13462 * call-seq:
13463 * ARGF.to_write_io -> io
13464 *
13465 * Returns IO instance tied to _ARGF_ for writing if inplace mode is
13466 * enabled.
13467 */
13468static VALUE
13469argf_write_io(VALUE argf)
13470{
13471 if (!RTEST(ARGF.current_file)) {
13472 rb_raise(rb_eIOError, "not opened for writing");
13473 }
13474 return GetWriteIO(ARGF.current_file);
13475}
13476
13477/*
13478 * call-seq:
13479 * ARGF.write(string) -> integer
13480 *
13481 * Writes _string_ if inplace mode.
13482 */
13483static VALUE
13484argf_write(VALUE argf, VALUE str)
13485{
13486 return rb_io_write(argf_write_io(argf), str);
13487}
13488
13489void
13490rb_readwrite_sys_fail(enum rb_io_wait_readwrite waiting, const char *mesg)
13491{
13492 rb_readwrite_syserr_fail(waiting, errno, mesg);
13493}
13494
13495void
13496rb_readwrite_syserr_fail(enum rb_io_wait_readwrite waiting, int n, const char *mesg)
13497{
13498 VALUE arg, c = Qnil;
13499 arg = mesg ? rb_str_new2(mesg) : Qnil;
13500 switch (waiting) {
13501 case RB_IO_WAIT_WRITABLE:
13502 switch (n) {
13503 case EAGAIN:
13504 c = rb_eEAGAINWaitWritable;
13505 break;
13506#if EAGAIN != EWOULDBLOCK
13507 case EWOULDBLOCK:
13508 c = rb_eEWOULDBLOCKWaitWritable;
13509 break;
13510#endif
13511 case EINPROGRESS:
13512 c = rb_eEINPROGRESSWaitWritable;
13513 break;
13514 default:
13516 }
13517 break;
13518 case RB_IO_WAIT_READABLE:
13519 switch (n) {
13520 case EAGAIN:
13521 c = rb_eEAGAINWaitReadable;
13522 break;
13523#if EAGAIN != EWOULDBLOCK
13524 case EWOULDBLOCK:
13525 c = rb_eEWOULDBLOCKWaitReadable;
13526 break;
13527#endif
13528 case EINPROGRESS:
13529 c = rb_eEINPROGRESSWaitReadable;
13530 break;
13531 default:
13533 }
13534 break;
13535 default:
13536 rb_bug("invalid read/write type passed to rb_readwrite_sys_fail: %d", waiting);
13537 }
13538 rb_exc_raise(rb_class_new_instance(1, &arg, c));
13539}
13540
13541static VALUE
13542get_LAST_READ_LINE(ID _x, VALUE *_y)
13543{
13544 return rb_lastline_get();
13545}
13546
13547static void
13548set_LAST_READ_LINE(VALUE val, ID _x, VALUE *_y)
13549{
13550 rb_lastline_set(val);
13551}
13552
13553/*
13554 * Document-class: IOError
13555 *
13556 * Raised when an IO operation fails.
13557 *
13558 * File.open("/etc/hosts") {|f| f << "example"}
13559 * #=> IOError: not opened for writing
13560 *
13561 * File.open("/etc/hosts") {|f| f.close; f.read }
13562 * #=> IOError: closed stream
13563 *
13564 * Note that some IO failures raise <code>SystemCallError</code>s
13565 * and these are not subclasses of IOError:
13566 *
13567 * File.open("does/not/exist")
13568 * #=> Errno::ENOENT: No such file or directory - does/not/exist
13569 */
13570
13571/*
13572 * Document-class: EOFError
13573 *
13574 * Raised by some IO operations when reaching the end of file. Many IO
13575 * methods exist in two forms,
13576 *
13577 * one that returns +nil+ when the end of file is reached, the other
13578 * raises +EOFError+.
13579 *
13580 * +EOFError+ is a subclass of +IOError+.
13581 *
13582 * file = File.open("/etc/hosts")
13583 * file.read
13584 * file.gets #=> nil
13585 * file.readline #=> EOFError: end of file reached
13586 */
13587
13588/*
13589 * Document-class: ARGF
13590 *
13591 * +ARGF+ is a stream designed for use in scripts that process files given as
13592 * command-line arguments or passed in via STDIN.
13593 *
13594 * The arguments passed to your script are stored in the +ARGV+ Array, one
13595 * argument per element. +ARGF+ assumes that any arguments that aren't
13596 * filenames have been removed from +ARGV+. For example:
13597 *
13598 * $ ruby argf.rb --verbose file1 file2
13599 *
13600 * ARGV #=> ["--verbose", "file1", "file2"]
13601 * option = ARGV.shift #=> "--verbose"
13602 * ARGV #=> ["file1", "file2"]
13603 *
13604 * You can now use +ARGF+ to work with a concatenation of each of these named
13605 * files. For instance, +ARGF.read+ will return the contents of _file1_
13606 * followed by the contents of _file2_.
13607 *
13608 * After a file in +ARGV+ has been read +ARGF+ removes it from the Array.
13609 * Thus, after all files have been read +ARGV+ will be empty.
13610 *
13611 * You can manipulate +ARGV+ yourself to control what +ARGF+ operates on. If
13612 * you remove a file from +ARGV+, it is ignored by +ARGF+; if you add files to
13613 * +ARGV+, they are treated as if they were named on the command line. For
13614 * example:
13615 *
13616 * ARGV.replace ["file1"]
13617 * ARGF.readlines # Returns the contents of file1 as an Array
13618 * ARGV #=> []
13619 * ARGV.replace ["file2", "file3"]
13620 * ARGF.read # Returns the contents of file2 and file3
13621 *
13622 * If +ARGV+ is empty, +ARGF+ acts as if it contained STDIN, i.e. the data
13623 * piped to your script. For example:
13624 *
13625 * $ echo "glark" | ruby -e 'p ARGF.read'
13626 * "glark\n"
13627 */
13628
13629/*
13630 * The IO class is the basis for all input and output in Ruby.
13631 * An I/O stream may be <em>duplexed</em> (that is, bidirectional), and
13632 * so may use more than one native operating system stream.
13633 *
13634 * Many of the examples in this section use the File class, the only standard
13635 * subclass of IO. The two classes are closely associated. Like the File
13636 * class, the Socket library subclasses from IO (such as TCPSocket or
13637 * UDPSocket).
13638 *
13639 * The Kernel#open method can create an IO (or File) object for these types
13640 * of arguments:
13641 *
13642 * * A plain string represents a filename suitable for the underlying
13643 * operating system.
13644 *
13645 * * A string starting with <code>"|"</code> indicates a subprocess.
13646 * The remainder of the string following the <code>"|"</code> is
13647 * invoked as a process with appropriate input/output channels
13648 * connected to it.
13649 *
13650 * * A string equal to <code>"|-"</code> will create another Ruby
13651 * instance as a subprocess.
13652 *
13653 * The IO may be opened with different file modes (read-only, write-only) and
13654 * encodings for proper conversion. See IO.new for these options. See
13655 * Kernel#open for details of the various command formats described above.
13656 *
13657 * IO.popen, the Open3 library, or Process#spawn may also be used to
13658 * communicate with subprocesses through an IO.
13659 *
13660 * Ruby will convert pathnames between different operating system
13661 * conventions if possible. For instance, on a Windows system the
13662 * filename <code>"/gumby/ruby/test.rb"</code> will be opened as
13663 * <code>"\gumby\ruby\test.rb"</code>. When specifying a Windows-style
13664 * filename in a Ruby string, remember to escape the backslashes:
13665 *
13666 * "C:\\gumby\\ruby\\test.rb"
13667 *
13668 * Our examples here will use the Unix-style forward slashes;
13669 * File::ALT_SEPARATOR can be used to get the platform-specific separator
13670 * character.
13671 *
13672 * The global constant ARGF (also accessible as <code>$<</code>) provides an
13673 * IO-like stream which allows access to all files mentioned on the
13674 * command line (or STDIN if no files are mentioned). ARGF#path and its alias
13675 * ARGF#filename are provided to access the name of the file currently being
13676 * read.
13677 *
13678 * == io/console
13679 *
13680 * The io/console extension provides methods for interacting with the
13681 * console. The console can be accessed from IO.console or the standard
13682 * input/output/error IO objects.
13683 *
13684 * Requiring io/console adds the following methods:
13685 *
13686 * * IO::console
13687 * * IO#raw
13688 * * IO#raw!
13689 * * IO#cooked
13690 * * IO#cooked!
13691 * * IO#getch
13692 * * IO#echo=
13693 * * IO#echo?
13694 * * IO#noecho
13695 * * IO#winsize
13696 * * IO#winsize=
13697 * * IO#iflush
13698 * * IO#ioflush
13699 * * IO#oflush
13700 *
13701 * Example:
13702 *
13703 * require 'io/console'
13704 * rows, columns = $stdout.winsize
13705 * puts "Your screen is #{columns} wide and #{rows} tall"
13706 *
13707 * == Example Files
13708 *
13709 * Many examples here use these filenames and their corresponding files:
13710 *
13711 * - <tt>t.txt</tt>: A text-only file that is assumed to exist via:
13712 *
13713 * text = <<~EOT
13714 * This is line one.
13715 * This is the second line.
13716 * This is the third line.
13717 * EOT
13718 * File.write('t.txt', text)
13719 *
13720 * - <tt>t.dat</tt>: A data file that is assumed to exist via:
13721 *
13722 * data = "\u9990\u9991\u9992\u9993\u9994"
13723 * f = File.open('t.dat', 'wb:UTF-16')
13724 * f.write(data)
13725 * f.close
13726 *
13727 * - <tt>t.rus</tt>: A Russian-language text file that is assumed to exist via:
13728 *
13729 * File.write('t.rus', "\u{442 435 441 442}")
13730 *
13731 * - <tt>t.tmp</tt>: A file that is assumed _not_ to exist.
13732 *
13733 * == Modes
13734 *
13735 * A number of \IO method calls must or may specify a _mode_ for the stream;
13736 * the mode determines how stream is to be accessible, including:
13737 *
13738 * - Whether the stream is to be read-only, write-only, or read-write.
13739 * - Whether the stream is positioned at its beginning or its end.
13740 * - Whether the stream treats data as text-only or binary.
13741 * - The external and internal encodings.
13742 *
13743 * === Mode Specified as an \Integer
13744 *
13745 * When +mode+ is an integer it must be one or more (combined by bitwise OR (<tt>|</tt>)
13746 * of the modes defined in File::Constants:
13747 *
13748 * - +File::RDONLY+: Open for reading only.
13749 * - +File::WRONLY+: Open for writing only.
13750 * - +File::RDWR+: Open for reading and writing.
13751 * - +File::APPEND+: Open for appending only.
13752 * - +File::CREAT+: Create file if it does not exist.
13753 * - +File::EXCL+: Raise an exception if +File::CREAT+ is given and the file exists.
13754 *
13755 * Examples:
13756 *
13757 * File.new('t.txt', File::RDONLY)
13758 * File.new('t.tmp', File::RDWR | File::CREAT | File::EXCL)
13759 *
13760 * Note: Method IO#set_encoding does not allow the mode to be specified as an integer.
13761 *
13762 * === Mode Specified As a \String
13763 *
13764 * When +mode+ is a string it must begin with one of the following:
13765 *
13766 * - <tt>'r'</tt>: Read-only stream, positioned at the beginning;
13767 * the stream cannot be changed to writable.
13768 * - <tt>'w'</tt>: Write-only stream, positioned at the beginning;
13769 * the stream cannot be changed to readable.
13770 * - <tt>'a'</tt>: Write-only stream, positioned at the end;
13771 * every write appends to the end;
13772 * the stream cannot be changed to readable.
13773 * - <tt>'r+'</tt>: Read-write stream, positioned at the beginning.
13774 * - <tt>'w+'</tt>: Read-write stream, positioned at the end.
13775 * - <tt>'a+'</tt>: Read-write stream, positioned at the end.
13776 *
13777 * For a writable file stream (that is, any except read-only),
13778 * the file is truncated to zero if it exists,
13779 * and is created if it does not exist.
13780 *
13781 * Examples:
13782 *
13783 * File.open('t.txt', 'r')
13784 * File.open('t.tmp', 'w')
13785 *
13786 * Either of the following may be suffixed to any of the above:
13787 *
13788 * - <tt>'t'</tt>: Text data; sets the default external encoding to +Encoding::UTF_8+;
13789 * on Windows, enables conversion between EOL and CRLF.
13790 * - <tt>'b'</tt>: Binary data; sets the default external encoding to +Encoding::ASCII_8BIT+;
13791 * on Windows, suppresses conversion between EOL and CRLF.
13792 *
13793 * If neither is given, the stream defaults to text data.
13794 *
13795 * Examples:
13796 *
13797 * File.open('t.txt', 'rt')
13798 * File.open('t.dat', 'rb')
13799 *
13800 * The following may be suffixed to any writable mode above:
13801 *
13802 * - <tt>'x'</tt>: Creates the file if it does not exist;
13803 * raises an exception if the file exists.
13804 *
13805 * Example:
13806 *
13807 * File.open('t.tmp', 'wx')
13808 *
13809 * Finally, the mode string may specify encodings --
13810 * either external encoding only or both external and internal encodings --
13811 * by appending one or both encoding names, separated by colons:
13812 *
13813 * f = File.new('t.dat', 'rb')
13814 * f.external_encoding # => #<Encoding:ASCII-8BIT>
13815 * f.internal_encoding # => nil
13816 * f = File.new('t.dat', 'rb:UTF-16')
13817 * f.external_encoding # => #<Encoding:UTF-16 (dummy)>
13818 * f.internal_encoding # => nil
13819 * f = File.new('t.dat', 'rb:UTF-16:UTF-16')
13820 * f.external_encoding # => #<Encoding:UTF-16 (dummy)>
13821 * f.internal_encoding # => #<Encoding:UTF-16>
13822 *
13823 * The numerous encoding names are available in array Encoding.name_list:
13824 *
13825 * Encoding.name_list.size # => 175
13826 * Encoding.name_list.take(3) # => ["ASCII-8BIT", "UTF-8", "US-ASCII"]
13827 *
13828 * == Encodings
13829 *
13830 * When the external encoding is set,
13831 * strings read are tagged by that encoding
13832 * when reading, and strings written are converted to that
13833 * encoding when writing.
13834 *
13835 * When both external and internal encodings are set,
13836 * strings read are converted from external to internal encoding,
13837 * and strings written are converted from internal to external encoding.
13838 * For further details about transcoding input and output, see Encoding.
13839 *
13840 * If the external encoding is <tt>'BOM|UTF-8'</tt>, <tt>'BOM|UTF-16LE'</tt>
13841 * or <tt>'BOM|UTF16-BE'</tt>, Ruby checks for
13842 * a Unicode BOM in the input document to help determine the encoding. For
13843 * UTF-16 encodings the file open mode must be binary.
13844 * If the BOM is found, it is stripped and the external encoding from the BOM is used.
13845 *
13846 * Note that the BOM-style encoding option is case insensitive,
13847 * so 'bom|utf-8' is also valid.)
13848 *
13849 * == Open Options
13850 *
13851 * A number of \IO methods accept an optional parameter +opts+,
13852 * which determines how a new stream is to be opened:
13853 *
13854 * - +:mode+: Stream mode.
13855 * - +:flags+: \Integer file open flags;
13856 * If +mode+ is also given, the two are bitwise-ORed.
13857 * - +:external_encoding+: External encoding for the stream.
13858 * - +:internal_encoding+: Internal encoding for the stream.
13859 * <tt>'-'</tt> is a synonym for the default internal encoding.
13860 * If the value is +nil+ no conversion occurs.
13861 * - +:encoding+: Specifies external and internal encodings as <tt>'extern:intern'</tt>.
13862 * - +:textmode+: If a truthy value, specifies the mode as text-only, binary otherwise.
13863 * - +:binmode+: If a truthy value, specifies the mode as binary, text-only otherwise.
13864 * - +:autoclose+: If a truthy value, specifies that the +fd+ will close
13865 * when the stream closes; otherwise it remains open.
13866 *
13867 * Also available are the options offered in String#encode,
13868 * which may control conversion between external internal encoding.
13869 *
13870 * == Getline Options
13871 *
13872 * A number of \IO methods accept optional keyword arguments
13873 * that determine how a stream is to be treated:
13874 *
13875 * - +:chomp+: If +true+, line separators are omitted; default is +false+.
13876 *
13877 * == Position
13878 *
13879 * An \IO stream has a _position_, which is the non-negative integer offset
13880 * (in bytes) in the stream where the next read or write will occur.
13881 *
13882 * Note that a text stream may have multi-byte characters,
13883 * so a text stream whose position is +n+ (_bytes_) may not have +n+ _characters_
13884 * preceding the current position -- there may be fewer.
13885 *
13886 * A new stream is initially positioned:
13887 *
13888 * - At the beginning (position +0+)
13889 * if its mode is <tt>'r'</tt>, <tt>'w'</tt>, or <tt>'r+'</tt>.
13890 * - At the end (position <tt>self.size</tt>)
13891 * if its mode is <tt>'a'</tt>, <tt>'w+'</tt>, or <tt>'a+'</tt>.
13892 *
13893 * Methods to query the position:
13894 *
13895 * - IO#tell and its alias IO#pos return the position for an open stream.
13896 * - IO#eof? and its alias IO#eof return whether the position is at the end
13897 * of a readable stream.
13898 *
13899 * Reading from a stream usually changes its position:
13900 *
13901 * f = File.open('t.txt')
13902 * f.tell # => 0
13903 * f.readline # => "This is line one.\n"
13904 * f.tell # => 19
13905 * f.readline # => "This is the second line.\n"
13906 * f.tell # => 45
13907 * f.eof? # => false
13908 * f.readline # => "Here's the third line.\n"
13909 * f.eof? # => true
13910 *
13911 *
13912 * Writing to a stream usually changes its position:
13913 *
13914 * f = File.open('t.tmp', 'w')
13915 * f.tell # => 0
13916 * f.write('foo') # => 3
13917 * f.tell # => 3
13918 * f.write('bar') # => 3
13919 * f.tell # => 6
13920 *
13921 *
13922 * Iterating over a stream usually changes its position:
13923 *
13924 * f = File.open('t.txt')
13925 * f.each do |line|
13926 * p "position=#{f.pos} eof?=#{f.eof?} line=#{line}"
13927 * end
13928 *
13929 * Output:
13930 *
13931 * "position=19 eof?=false line=This is line one.\n"
13932 * "position=45 eof?=false line=This is the second line.\n"
13933 * "position=70 eof?=true line=This is the third line.\n"
13934 *
13935 * The position may also be changed by certain other methods:
13936 *
13937 * - IO#pos= and IO#seek change the position to a specified offset.
13938 * - IO#rewind changes the position to the beginning.
13939 *
13940 * == Line Number
13941 *
13942 * A readable \IO stream has a _line_ _number_,
13943 * which is the non-negative integer line number
13944 * in the stream where the next read will occur.
13945 *
13946 * A new stream is initially has line number +0+.
13947 *
13948 * \Method IO#lineno returns the line number.
13949 *
13950 * Reading lines from a stream usually changes its line number:
13951 *
13952 * f = File.open('t.txt', 'r')
13953 * f.lineno # => 0
13954 * f.readline # => "This is line one.\n"
13955 * f.lineno # => 1
13956 * f.readline # => "This is the second line.\n"
13957 * f.lineno # => 2
13958 * f.readline # => "Here's the third line.\n"
13959 * f.lineno # => 3
13960 * f.eof? # => true
13961 *
13962 * Iterating over lines in a stream usually changes its line number:
13963 *
13964 * f = File.open('t.txt')
13965 * f.each_line do |line|
13966 * p "position=#{f.pos} eof?=#{f.eof?} line=#{line}"
13967 * end
13968 *
13969 * Output:
13970 *
13971 * "position=19 eof?=false line=This is line one.\n"
13972 * "position=45 eof?=false line=This is the second line.\n"
13973 * "position=70 eof?=true line=This is the third line.\n"
13974 *
13975 * == What's Here
13976 *
13977 * First, what's elsewhere. \Class \IO:
13978 *
13979 * - Inherits from {class Object}[Object.html#class-Object-label-What-27s+Here].
13980 * - Includes {module Enumerable}[Enumerable.html#module-Enumerable-label-What-27s+Here],
13981 * which provides dozens of additional methods.
13982 *
13983 * Here, class \IO provides methods that are useful for:
13984 *
13985 * - {Creating}[#class-IO-label-Creating]
13986 * - {Reading}[#class-IO-label-Reading]
13987 * - {Writing}[#class-IO-label-Writing]
13988 * - {Positioning}[#class-IO-label-Positioning]
13989 * - {Iterating}[#class-IO-label-Iterating]
13990 * - {Settings}[#class-IO-label-Settings]
13991 * - {Querying}[#class-IO-label-Querying]
13992 * - {Buffering}[#class-IO-label-Buffering]
13993 * - {Low-Level Access}[#class-IO-label-Low-Level+Access]
13994 * - {Other}[#class-IO-label-Other]
13995 *
13996 * === Creating
13997 *
13998 * - ::new (aliased as ::for_fd):: Creates and returns a new \IO object for the given
13999 * integer file descriptor.
14000 * - ::open:: Creates a new \IO object.
14001 * - ::pipe:: Creates a connected pair of reader and writer \IO objects.
14002 * - ::popen:: Creates an \IO object to interact with a subprocess.
14003 * - ::select:: Selects which given \IO instances are ready for reading,
14004 * writing, or have pending exceptions.
14005 *
14006 * === Reading
14007 *
14008 * - ::binread:: Returns a binary string with all or a subset of bytes
14009 * from the given file.
14010 * - ::read:: Returns a string with all or a subset of bytes from the given file.
14011 * - ::readlines:: Returns an array of strings, which are the lines from the given file.
14012 * - #getbyte:: Returns the next 8-bit byte read from +self+ as an integer.
14013 * - #getc:: Returns the next character read from +self+ as a string.
14014 * - #gets:: Returns the line read from +self+.
14015 * - #pread:: Returns all or the next _n_ bytes read from +self+,
14016 * not updating the receiver's offset.
14017 * - #read:: Returns all remaining or the next _n_ bytes read from +self+
14018 * for a given _n_.
14019 * - #read_nonblock:: the next _n_ bytes read from +self+ for a given _n_,
14020 * in non-block mode.
14021 * - #readbyte:: Returns the next byte read from +self+;
14022 * same as #getbyte, but raises an exception on end-of-file.
14023 * - #readchar:: Returns the next character read from +self+;
14024 * same as #getc, but raises an exception on end-of-file.
14025 * - #readline:: Returns the next line read from +self+;
14026 * same as #getline, but raises an exception of end-of-file.
14027 * - #readlines:: Returns an array of all lines read read from +self+.
14028 * - #readpartial:: Returns up to the given number of bytes from +self+.
14029 *
14030 * === Writing
14031 *
14032 * - ::binwrite:: Writes the given string to the file at the given filepath,
14033 in binary mode.
14034 * - ::write:: Writes the given string to +self+.
14035 * - {::<<}[#method-i-3C-3C]:: Appends the given string to +self+.
14036 * - #print:: Prints last read line or given objects to +self+.
14037 * - #printf:: Writes to +self+ based on the given format string and objects.
14038 * - #putc:: Writes a character to +self+.
14039 * - #puts:: Writes lines to +self+, making sure line ends with a newline.
14040 * - #pwrite:: Writes the given string at the given offset,
14041 * not updating the receiver's offset.
14042 * - #write:: Writes one or more given strings to +self+.
14043 * - #write_nonblock:: Writes one or more given strings to +self+ in non-blocking mode.
14044 *
14045 * === Positioning
14046 *
14047 * - #lineno:: Returns the current line number in +self+.
14048 * - #lineno=:: Sets the line number is +self+.
14049 * - #pos (aliased as #tell):: Returns the current byte offset in +self+.
14050 * - #pos=:: Sets the byte offset in +self+.
14051 * - #reopen:: Reassociates +self+ with a new or existing \IO stream.
14052 * - #rewind:: Positions +self+ to the beginning of input.
14053 * - #seek:: Sets the offset for +self+ relative to given position.
14054 *
14055 * === Iterating
14056 *
14057 * - ::foreach:: Yields each line of given file to the block.
14058 * - #each (aliased as #each_line):: Calls the given block
14059 * with each successive line in +self+.
14060 * - #each_byte:: Calls the given block with each successive byte in +self+
14061 * as an integer.
14062 * - #each_char:: Calls the given block with each successive character in +self+
14063 * as a string.
14064 * - #each_codepoint:: Calls the given block with each successive codepoint in +self+
14065 * as an integer.
14066 *
14067 * === Settings
14068 *
14069 * - #autoclose=:: Sets whether +self+ auto-closes.
14070 * - #binmode:: Sets +self+ to binary mode.
14071 * - #close:: Closes +self+.
14072 * - #close_on_exec=:: Sets the close-on-exec flag.
14073 * - #close_read:: Closes +self+ for reading.
14074 * - #close_write:: Closes +self+ for writing.
14075 * - #set_encoding:: Sets the encoding for +self+.
14076 * - #set_encoding_by_bom:: Sets the encoding for +self+, based on its
14077 * Unicode byte-order-mark.
14078 * - #sync=:: Sets the sync-mode to the given value.
14079 *
14080 * === Querying
14081 *
14082 * - #autoclose?:: Returns whether +self+ auto-closes.
14083 * - #binmode?:: Returns whether +self+ is in binary mode.
14084 * - #close_on_exec?:: Returns the close-on-exec flag for +self+.
14085 * - #closed?:: Returns whether +self+ is closed.
14086 * - #eof? (aliased as #eof):: Returns whether +self+ is at end-of-file.
14087 * - #external_encoding:: Returns the external encoding object for +self+.
14088 * - #fileno (aliased as #to_i):: Returns the integer file descriptor for +self+
14089 * - #internal_encoding:: Returns the internal encoding object for +self+.
14090 * - #pid:: Returns the process ID of a child process associated with +self+,
14091 * if +self+ was created by ::popen.
14092 * - #stat:: Returns the File::Stat object containing status information for +self+.
14093 * - #sync:: Returns whether +self+ is in sync-mode.
14094 * - #tty (aliased as #isatty):: Returns whether +self+ is a terminal.
14095 *
14096 * === Buffering
14097 *
14098 * - #fdatasync:: Immediately writes all buffered data in +self+ to disk.
14099 * - #flush:: Flushes any buffered data within +self+ to the underlying
14100 * operating system.
14101 * - #fsync:: Immediately writes all buffered data and attributes in +self+ to disk.
14102 * - #ungetbyte:: Prepends buffer for +self+ with given integer byte or string.
14103 * - #ungetc:: Prepends buffer for +self+ with given string.
14104 *
14105 * === Low-Level Access
14106 *
14107 * - ::sysopen:: Opens the file given by its path,
14108 * returning the integer file descriptor.
14109 * - #advise:: Announces the intention to access data from +self+ in a specific way.
14110 * - #fcntl:: Passes a low-level command to the file specified
14111 * by the given file descriptor.
14112 * - #ioctl:: Passes a low-level command to the device specified
14113 * by the given file descriptor.
14114 * - #sysread:: Returns up to the next _n_ bytes read from self using a low-level read.
14115 * - #sysseek:: Sets the offset for +self+.
14116 * - #syswrite:: Writes the given string to +self+ using a low-level write.
14117 *
14118 * === Other
14119 *
14120 * - ::copy_stream:: Copies data from a source to a destination,
14121 * each of which is a filepath or an \IO-like object.
14122 * - ::try_convert:: Returns a new \IO object resulting from converting
14123 * the given object.
14124 * - #inspect:: Returns the string representation of +self+.
14125 *
14126 */
14127
14128void
14129Init_IO(void)
14130{
14131 VALUE rb_cARGF;
14132#ifdef __CYGWIN__
14133#include <sys/cygwin.h>
14134 static struct __cygwin_perfile pf[] =
14135 {
14136 {"", O_RDONLY | O_BINARY},
14137 {"", O_WRONLY | O_BINARY},
14138 {"", O_RDWR | O_BINARY},
14139 {"", O_APPEND | O_BINARY},
14140 {NULL, 0}
14141 };
14142 cygwin_internal(CW_PERFILE, pf);
14143#endif
14144
14145 rb_eIOError = rb_define_class("IOError", rb_eStandardError);
14147
14148 id_write = rb_intern_const("write");
14149 id_read = rb_intern_const("read");
14150 id_getc = rb_intern_const("getc");
14151 id_flush = rb_intern_const("flush");
14152 id_readpartial = rb_intern_const("readpartial");
14153 id_set_encoding = rb_intern_const("set_encoding");
14154 id_fileno = rb_intern_const("fileno");
14155
14156 rb_define_global_function("syscall", rb_f_syscall, -1);
14157
14158 rb_define_global_function("open", rb_f_open, -1);
14159 rb_define_global_function("printf", rb_f_printf, -1);
14160 rb_define_global_function("print", rb_f_print, -1);
14161 rb_define_global_function("putc", rb_f_putc, 1);
14162 rb_define_global_function("puts", rb_f_puts, -1);
14163 rb_define_global_function("gets", rb_f_gets, -1);
14164 rb_define_global_function("readline", rb_f_readline, -1);
14165 rb_define_global_function("select", rb_f_select, -1);
14166
14167 rb_define_global_function("readlines", rb_f_readlines, -1);
14168
14169 rb_define_global_function("`", rb_f_backquote, 1);
14170
14171 rb_define_global_function("p", rb_f_p, -1);
14172 rb_define_method(rb_mKernel, "display", rb_obj_display, -1);
14173
14174 rb_cIO = rb_define_class("IO", rb_cObject);
14176
14180
14181 /* exception to wait for reading. see IO.select. */
14183 /* exception to wait for writing. see IO.select. */
14185 /* exception to wait for reading by EAGAIN. see IO.select. */
14186 rb_eEAGAINWaitReadable = rb_define_class_under(rb_cIO, "EAGAINWaitReadable", rb_eEAGAIN);
14187 rb_include_module(rb_eEAGAINWaitReadable, rb_mWaitReadable);
14188 /* exception to wait for writing by EAGAIN. see IO.select. */
14189 rb_eEAGAINWaitWritable = rb_define_class_under(rb_cIO, "EAGAINWaitWritable", rb_eEAGAIN);
14190 rb_include_module(rb_eEAGAINWaitWritable, rb_mWaitWritable);
14191#if EAGAIN == EWOULDBLOCK
14192 rb_eEWOULDBLOCKWaitReadable = rb_eEAGAINWaitReadable;
14193 /* same as IO::EAGAINWaitReadable */
14194 rb_define_const(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEAGAINWaitReadable);
14195 rb_eEWOULDBLOCKWaitWritable = rb_eEAGAINWaitWritable;
14196 /* same as IO::EAGAINWaitWritable */
14197 rb_define_const(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEAGAINWaitWritable);
14198#else
14199 /* exception to wait for reading by EWOULDBLOCK. see IO.select. */
14200 rb_eEWOULDBLOCKWaitReadable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEWOULDBLOCK);
14201 rb_include_module(rb_eEWOULDBLOCKWaitReadable, rb_mWaitReadable);
14202 /* exception to wait for writing by EWOULDBLOCK. see IO.select. */
14203 rb_eEWOULDBLOCKWaitWritable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEWOULDBLOCK);
14204 rb_include_module(rb_eEWOULDBLOCKWaitWritable, rb_mWaitWritable);
14205#endif
14206 /* exception to wait for reading by EINPROGRESS. see IO.select. */
14207 rb_eEINPROGRESSWaitReadable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitReadable", rb_eEINPROGRESS);
14208 rb_include_module(rb_eEINPROGRESSWaitReadable, rb_mWaitReadable);
14209 /* exception to wait for writing by EINPROGRESS. see IO.select. */
14210 rb_eEINPROGRESSWaitWritable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitWritable", rb_eEINPROGRESS);
14211 rb_include_module(rb_eEINPROGRESSWaitWritable, rb_mWaitWritable);
14212
14213#if 0
14214 /* This is necessary only for forcing rdoc handle File::open */
14215 rb_define_singleton_method(rb_cFile, "open", rb_io_s_open, -1);
14216#endif
14217
14218 rb_define_alloc_func(rb_cIO, io_alloc);
14219 rb_define_singleton_method(rb_cIO, "new", rb_io_s_new, -1);
14220 rb_define_singleton_method(rb_cIO, "open", rb_io_s_open, -1);
14221 rb_define_singleton_method(rb_cIO, "sysopen", rb_io_s_sysopen, -1);
14222 rb_define_singleton_method(rb_cIO, "for_fd", rb_io_s_for_fd, -1);
14223 rb_define_singleton_method(rb_cIO, "popen", rb_io_s_popen, -1);
14224 rb_define_singleton_method(rb_cIO, "foreach", rb_io_s_foreach, -1);
14225 rb_define_singleton_method(rb_cIO, "readlines", rb_io_s_readlines, -1);
14226 rb_define_singleton_method(rb_cIO, "read", rb_io_s_read, -1);
14227 rb_define_singleton_method(rb_cIO, "binread", rb_io_s_binread, -1);
14228 rb_define_singleton_method(rb_cIO, "write", rb_io_s_write, -1);
14229 rb_define_singleton_method(rb_cIO, "binwrite", rb_io_s_binwrite, -1);
14230 rb_define_singleton_method(rb_cIO, "select", rb_f_select, -1);
14231 rb_define_singleton_method(rb_cIO, "pipe", rb_io_s_pipe, -1);
14232 rb_define_singleton_method(rb_cIO, "try_convert", rb_io_s_try_convert, 1);
14233 rb_define_singleton_method(rb_cIO, "copy_stream", rb_io_s_copy_stream, -1);
14234
14235 rb_define_method(rb_cIO, "initialize", rb_io_initialize, -1);
14236
14238 rb_define_hooked_variable("$,", &rb_output_fs, 0, deprecated_str_setter);
14239
14240 rb_default_rs = rb_fstring_lit("\n"); /* avoid modifying RS_default */
14244 rb_define_hooked_variable("$/", &rb_rs, 0, deprecated_str_setter);
14245 rb_define_hooked_variable("$-0", &rb_rs, 0, deprecated_str_setter);
14246 rb_define_hooked_variable("$\\", &rb_output_rs, 0, deprecated_str_setter);
14247
14248 rb_define_virtual_variable("$_", get_LAST_READ_LINE, set_LAST_READ_LINE);
14249 rb_gvar_ractor_local("$_");
14250
14251 rb_define_method(rb_cIO, "initialize_copy", rb_io_init_copy, 1);
14252 rb_define_method(rb_cIO, "reopen", rb_io_reopen, -1);
14253
14254 rb_define_method(rb_cIO, "print", rb_io_print, -1);
14255 rb_define_method(rb_cIO, "putc", rb_io_putc, 1);
14256 rb_define_method(rb_cIO, "puts", rb_io_puts, -1);
14257 rb_define_method(rb_cIO, "printf", rb_io_printf, -1);
14258
14259 rb_define_method(rb_cIO, "each", rb_io_each_line, -1);
14260 rb_define_method(rb_cIO, "each_line", rb_io_each_line, -1);
14261 rb_define_method(rb_cIO, "each_byte", rb_io_each_byte, 0);
14262 rb_define_method(rb_cIO, "each_char", rb_io_each_char, 0);
14263 rb_define_method(rb_cIO, "each_codepoint", rb_io_each_codepoint, 0);
14264
14265 rb_define_method(rb_cIO, "syswrite", rb_io_syswrite, 1);
14266 rb_define_method(rb_cIO, "sysread", rb_io_sysread, -1);
14267
14268 rb_define_method(rb_cIO, "pread", rb_io_pread, -1);
14269 rb_define_method(rb_cIO, "pwrite", rb_io_pwrite, 2);
14270
14271 rb_define_method(rb_cIO, "fileno", rb_io_fileno, 0);
14272 rb_define_alias(rb_cIO, "to_i", "fileno");
14273 rb_define_method(rb_cIO, "to_io", rb_io_to_io, 0);
14274
14275 rb_define_method(rb_cIO, "fsync", rb_io_fsync, 0);
14276 rb_define_method(rb_cIO, "fdatasync", rb_io_fdatasync, 0);
14277 rb_define_method(rb_cIO, "sync", rb_io_sync, 0);
14278 rb_define_method(rb_cIO, "sync=", rb_io_set_sync, 1);
14279
14280 rb_define_method(rb_cIO, "lineno", rb_io_lineno, 0);
14281 rb_define_method(rb_cIO, "lineno=", rb_io_set_lineno, 1);
14282
14283 rb_define_method(rb_cIO, "readlines", rb_io_readlines, -1);
14284
14285 rb_define_method(rb_cIO, "readpartial", io_readpartial, -1);
14286 rb_define_method(rb_cIO, "read", io_read, -1);
14287 rb_define_method(rb_cIO, "write", io_write_m, -1);
14288 rb_define_method(rb_cIO, "gets", rb_io_gets_m, -1);
14289 rb_define_method(rb_cIO, "readline", rb_io_readline, -1);
14290 rb_define_method(rb_cIO, "getc", rb_io_getc, 0);
14291 rb_define_method(rb_cIO, "getbyte", rb_io_getbyte, 0);
14292 rb_define_method(rb_cIO, "readchar", rb_io_readchar, 0);
14293 rb_define_method(rb_cIO, "readbyte", rb_io_readbyte, 0);
14294 rb_define_method(rb_cIO, "ungetbyte",rb_io_ungetbyte, 1);
14295 rb_define_method(rb_cIO, "ungetc",rb_io_ungetc, 1);
14297 rb_define_method(rb_cIO, "flush", rb_io_flush, 0);
14298 rb_define_method(rb_cIO, "tell", rb_io_tell, 0);
14299 rb_define_method(rb_cIO, "seek", rb_io_seek_m, -1);
14300 /* Set I/O position from the beginning */
14301 rb_define_const(rb_cIO, "SEEK_SET", INT2FIX(SEEK_SET));
14302 /* Set I/O position from the current position */
14303 rb_define_const(rb_cIO, "SEEK_CUR", INT2FIX(SEEK_CUR));
14304 /* Set I/O position from the end */
14305 rb_define_const(rb_cIO, "SEEK_END", INT2FIX(SEEK_END));
14306#ifdef SEEK_DATA
14307 /* Set I/O position to the next location containing data */
14308 rb_define_const(rb_cIO, "SEEK_DATA", INT2FIX(SEEK_DATA));
14309#endif
14310#ifdef SEEK_HOLE
14311 /* Set I/O position to the next hole */
14312 rb_define_const(rb_cIO, "SEEK_HOLE", INT2FIX(SEEK_HOLE));
14313#endif
14314 rb_define_method(rb_cIO, "rewind", rb_io_rewind, 0);
14315 rb_define_method(rb_cIO, "pos", rb_io_tell, 0);
14316 rb_define_method(rb_cIO, "pos=", rb_io_set_pos, 1);
14317 rb_define_method(rb_cIO, "eof", rb_io_eof, 0);
14318 rb_define_method(rb_cIO, "eof?", rb_io_eof, 0);
14319
14320 rb_define_method(rb_cIO, "close_on_exec?", rb_io_close_on_exec_p, 0);
14321 rb_define_method(rb_cIO, "close_on_exec=", rb_io_set_close_on_exec, 1);
14322
14323 rb_define_method(rb_cIO, "close", rb_io_close_m, 0);
14324 rb_define_method(rb_cIO, "closed?", rb_io_closed, 0);
14325 rb_define_method(rb_cIO, "close_read", rb_io_close_read, 0);
14326 rb_define_method(rb_cIO, "close_write", rb_io_close_write, 0);
14327
14328 rb_define_method(rb_cIO, "isatty", rb_io_isatty, 0);
14329 rb_define_method(rb_cIO, "tty?", rb_io_isatty, 0);
14330 rb_define_method(rb_cIO, "binmode", rb_io_binmode_m, 0);
14331 rb_define_method(rb_cIO, "binmode?", rb_io_binmode_p, 0);
14332 rb_define_method(rb_cIO, "sysseek", rb_io_sysseek, -1);
14333 rb_define_method(rb_cIO, "advise", rb_io_advise, -1);
14334
14335 rb_define_method(rb_cIO, "ioctl", rb_io_ioctl, -1);
14336 rb_define_method(rb_cIO, "fcntl", rb_io_fcntl, -1);
14337 rb_define_method(rb_cIO, "pid", rb_io_pid, 0);
14338 rb_define_method(rb_cIO, "inspect", rb_io_inspect, 0);
14339
14340 rb_define_method(rb_cIO, "external_encoding", rb_io_external_encoding, 0);
14341 rb_define_method(rb_cIO, "internal_encoding", rb_io_internal_encoding, 0);
14342 rb_define_method(rb_cIO, "set_encoding", rb_io_set_encoding, -1);
14343 rb_define_method(rb_cIO, "set_encoding_by_bom", rb_io_set_encoding_by_bom, 0);
14344
14345 rb_define_method(rb_cIO, "autoclose?", rb_io_autoclose_p, 0);
14346 rb_define_method(rb_cIO, "autoclose=", rb_io_set_autoclose, 1);
14347
14348 rb_define_virtual_variable("$stdin", stdin_getter, stdin_setter);
14349 rb_define_virtual_variable("$stdout", stdout_getter, stdout_setter);
14350 rb_define_virtual_variable("$>", stdout_getter, stdout_setter);
14351 rb_define_virtual_variable("$stderr", stderr_getter, stderr_setter);
14352
14353 rb_gvar_ractor_local("$stdin");
14354 rb_gvar_ractor_local("$stdout");
14355 rb_gvar_ractor_local("$>");
14356 rb_gvar_ractor_local("$stderr");
14357
14358 rb_stdin = rb_io_prep_stdin();
14359 rb_stdout = rb_io_prep_stdout();
14360 rb_stderr = rb_io_prep_stderr();
14361
14365
14366 orig_stdout = rb_stdout;
14367 orig_stderr = rb_stderr;
14368
14369 /* Holds the original stdin */
14371 /* Holds the original stdout */
14373 /* Holds the original stderr */
14375
14376#if 0
14377 /* Hack to get rdoc to regard ARGF as a class: */
14378 rb_cARGF = rb_define_class("ARGF", rb_cObject);
14379#endif
14380
14381 rb_cARGF = rb_class_new(rb_cObject);
14382 rb_set_class_path(rb_cARGF, rb_cObject, "ARGF.class");
14383 rb_define_alloc_func(rb_cARGF, argf_alloc);
14384
14386
14387 rb_define_method(rb_cARGF, "initialize", argf_initialize, -2);
14388 rb_define_method(rb_cARGF, "initialize_copy", argf_initialize_copy, 1);
14389 rb_define_method(rb_cARGF, "to_s", argf_to_s, 0);
14390 rb_define_alias(rb_cARGF, "inspect", "to_s");
14391 rb_define_method(rb_cARGF, "argv", argf_argv, 0);
14392
14393 rb_define_method(rb_cARGF, "fileno", argf_fileno, 0);
14394 rb_define_method(rb_cARGF, "to_i", argf_fileno, 0);
14395 rb_define_method(rb_cARGF, "to_io", argf_to_io, 0);
14396 rb_define_method(rb_cARGF, "to_write_io", argf_write_io, 0);
14397 rb_define_method(rb_cARGF, "each", argf_each_line, -1);
14398 rb_define_method(rb_cARGF, "each_line", argf_each_line, -1);
14399 rb_define_method(rb_cARGF, "each_byte", argf_each_byte, 0);
14400 rb_define_method(rb_cARGF, "each_char", argf_each_char, 0);
14401 rb_define_method(rb_cARGF, "each_codepoint", argf_each_codepoint, 0);
14402
14403 rb_define_method(rb_cARGF, "read", argf_read, -1);
14404 rb_define_method(rb_cARGF, "readpartial", argf_readpartial, -1);
14405 rb_define_method(rb_cARGF, "read_nonblock", argf_read_nonblock, -1);
14406 rb_define_method(rb_cARGF, "readlines", argf_readlines, -1);
14407 rb_define_method(rb_cARGF, "to_a", argf_readlines, -1);
14408 rb_define_method(rb_cARGF, "gets", argf_gets, -1);
14409 rb_define_method(rb_cARGF, "readline", argf_readline, -1);
14410 rb_define_method(rb_cARGF, "getc", argf_getc, 0);
14411 rb_define_method(rb_cARGF, "getbyte", argf_getbyte, 0);
14412 rb_define_method(rb_cARGF, "readchar", argf_readchar, 0);
14413 rb_define_method(rb_cARGF, "readbyte", argf_readbyte, 0);
14414 rb_define_method(rb_cARGF, "tell", argf_tell, 0);
14415 rb_define_method(rb_cARGF, "seek", argf_seek_m, -1);
14416 rb_define_method(rb_cARGF, "rewind", argf_rewind, 0);
14417 rb_define_method(rb_cARGF, "pos", argf_tell, 0);
14418 rb_define_method(rb_cARGF, "pos=", argf_set_pos, 1);
14419 rb_define_method(rb_cARGF, "eof", argf_eof, 0);
14420 rb_define_method(rb_cARGF, "eof?", argf_eof, 0);
14421 rb_define_method(rb_cARGF, "binmode", argf_binmode_m, 0);
14422 rb_define_method(rb_cARGF, "binmode?", argf_binmode_p, 0);
14423
14424 rb_define_method(rb_cARGF, "write", argf_write, 1);
14425 rb_define_method(rb_cARGF, "print", rb_io_print, -1);
14426 rb_define_method(rb_cARGF, "putc", rb_io_putc, 1);
14427 rb_define_method(rb_cARGF, "puts", rb_io_puts, -1);
14428 rb_define_method(rb_cARGF, "printf", rb_io_printf, -1);
14429
14430 rb_define_method(rb_cARGF, "filename", argf_filename, 0);
14431 rb_define_method(rb_cARGF, "path", argf_filename, 0);
14432 rb_define_method(rb_cARGF, "file", argf_file, 0);
14433 rb_define_method(rb_cARGF, "skip", argf_skip, 0);
14434 rb_define_method(rb_cARGF, "close", argf_close_m, 0);
14435 rb_define_method(rb_cARGF, "closed?", argf_closed, 0);
14436
14437 rb_define_method(rb_cARGF, "lineno", argf_lineno, 0);
14438 rb_define_method(rb_cARGF, "lineno=", argf_set_lineno, 1);
14439
14440 rb_define_method(rb_cARGF, "inplace_mode", argf_inplace_mode_get, 0);
14441 rb_define_method(rb_cARGF, "inplace_mode=", argf_inplace_mode_set, 1);
14442
14443 rb_define_method(rb_cARGF, "external_encoding", argf_external_encoding, 0);
14444 rb_define_method(rb_cARGF, "internal_encoding", argf_internal_encoding, 0);
14445 rb_define_method(rb_cARGF, "set_encoding", argf_set_encoding, -1);
14446
14447 argf = rb_class_new_instance(0, 0, rb_cARGF);
14448
14450 /*
14451 * ARGF is a stream designed for use in scripts that process files given
14452 * as command-line arguments or passed in via STDIN.
14453 *
14454 * See ARGF (the class) for more details.
14455 */
14457
14458 rb_define_hooked_variable("$.", &argf, argf_lineno_getter, argf_lineno_setter);
14459 rb_define_hooked_variable("$FILENAME", &argf, argf_filename_getter, rb_gvar_readonly_setter);
14460 ARGF.filename = rb_str_new2("-");
14461
14462 rb_define_hooked_variable("$-i", &argf, opt_i_get, opt_i_set);
14463 rb_gvar_ractor_local("$-i");
14464
14465 rb_define_hooked_variable("$*", &argf, argf_argv_getter, rb_gvar_readonly_setter);
14466
14467#if defined (_WIN32) || defined(__CYGWIN__)
14468 atexit(pipe_atexit);
14469#endif
14470
14471 Init_File();
14472
14473 rb_define_method(rb_cFile, "initialize", rb_file_initialize, -1);
14474
14475 sym_mode = ID2SYM(rb_intern_const("mode"));
14476 sym_perm = ID2SYM(rb_intern_const("perm"));
14477 sym_flags = ID2SYM(rb_intern_const("flags"));
14478 sym_extenc = ID2SYM(rb_intern_const("external_encoding"));
14479 sym_intenc = ID2SYM(rb_intern_const("internal_encoding"));
14480 sym_encoding = ID2SYM(rb_id_encoding());
14481 sym_open_args = ID2SYM(rb_intern_const("open_args"));
14482 sym_textmode = ID2SYM(rb_intern_const("textmode"));
14483 sym_binmode = ID2SYM(rb_intern_const("binmode"));
14484 sym_autoclose = ID2SYM(rb_intern_const("autoclose"));
14485 sym_normal = ID2SYM(rb_intern_const("normal"));
14486 sym_sequential = ID2SYM(rb_intern_const("sequential"));
14487 sym_random = ID2SYM(rb_intern_const("random"));
14488 sym_willneed = ID2SYM(rb_intern_const("willneed"));
14489 sym_dontneed = ID2SYM(rb_intern_const("dontneed"));
14490 sym_noreuse = ID2SYM(rb_intern_const("noreuse"));
14491 sym_SET = ID2SYM(rb_intern_const("SET"));
14492 sym_CUR = ID2SYM(rb_intern_const("CUR"));
14493 sym_END = ID2SYM(rb_intern_const("END"));
14494#ifdef SEEK_DATA
14495 sym_DATA = ID2SYM(rb_intern_const("DATA"));
14496#endif
14497#ifdef SEEK_HOLE
14498 sym_HOLE = ID2SYM(rb_intern_const("HOLE"));
14499#endif
14500 sym_wait_readable = ID2SYM(rb_intern_const("wait_readable"));
14501 sym_wait_writable = ID2SYM(rb_intern_const("wait_writable"));
14502}
14503
14504#include "io.rbinc"
std::atomic< unsigned > rb_atomic_t
Type that is eligible for atomic operations.
Definition: atomic.h:69
unsigned long ruby_strtoul(const char *str, char **endptr, int base)
Our own locale-insensitive version of strtoul(3).
Definition: util.c:133
#define rb_define_singleton_method(klass, mid, func, arity)
Defines klass.mid.
Definition: cxxanyargs.hpp:685
void rb_include_module(VALUE klass, VALUE module)
Includes a module to a class.
Definition: class.c:1043
VALUE rb_define_class(const char *name, VALUE super)
Defines a top-level class.
Definition: class.c:837
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
Definition: class.c:869
VALUE rb_define_module_under(VALUE outer, const char *name)
Defines a module under the namespace of outer.
Definition: class.c:972
void rb_define_alias(VALUE klass, const char *name1, const char *name2)
Defines an alias of a method.
Definition: class.c:2116
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:2419
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:2406
void rb_define_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a method.
Definition: class.c:1914
int rb_block_given_p(void)
Determines if the current method is given a block.
Definition: eval.c:850
int rb_get_kwargs(VALUE keyword_hash, const ID *table, int required, int optional, VALUE *values)
Keyword argument deconstructor.
Definition: class.c:2195
void rb_define_global_function(const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a global function.
Definition: class.c:2110
#define ECONV_AFTER_OUTPUT
Old name of RUBY_ECONV_AFTER_OUTPUT.
Definition: transcode.h:551
#define rb_str_new2
Old name of rb_str_new_cstr.
Definition: string.h:1738
#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:529
#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 T_NIL
Old name of RUBY_T_NIL.
Definition: value_type.h:72
#define UNREACHABLE
Old name of RBIMPL_UNREACHABLE.
Definition: assume.h:30
#define ID2SYM
Old name of RB_ID2SYM.
Definition: symbol.h:44
#define T_BIGNUM
Old name of RUBY_T_BIGNUM.
Definition: value_type.h:57
#define OBJ_FREEZE
Old name of RB_OBJ_FREEZE.
Definition: fl_type.h:143
#define T_FIXNUM
Old name of RUBY_T_FIXNUM.
Definition: value_type.h:63
#define UNREACHABLE_RETURN
Old name of RBIMPL_UNREACHABLE_RETURN.
Definition: assume.h:31
#define FIX2UINT
Old name of RB_FIX2UINT.
Definition: int.h:42
#define SSIZET2NUM
Old name of RB_SSIZE2NUM.
Definition: size_t.h:64
#define ZALLOC
Old name of RB_ZALLOC.
Definition: memory.h:396
#define CLASS_OF
Old name of rb_class_of.
Definition: globals.h:203
#define rb_ary_new4
Old name of rb_ary_new_from_values.
Definition: array.h:653
#define ENCODING_MAXNAMELEN
Old name of RUBY_ENCODING_MAXNAMELEN.
Definition: encoding.h:110
#define MBCLEN_NEEDMORE_LEN(ret)
Old name of ONIGENC_MBCLEN_NEEDMORE_LEN.
Definition: encoding.h:536
#define ENCODING_GET(obj)
Old name of RB_ENCODING_GET.
Definition: encoding.h:108
#define LONG2FIX
Old name of RB_INT2FIX.
Definition: long.h:49
#define NUM2UINT
Old name of RB_NUM2UINT.
Definition: int.h:45
#define ALLOC_N
Old name of RB_ALLOC_N.
Definition: memory.h:393
#define MBCLEN_CHARFOUND_LEN(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_LEN.
Definition: encoding.h:533
#define LONG2NUM
Old name of RB_LONG2NUM.
Definition: long.h:50
#define rb_exc_new3
Old name of rb_exc_new_str.
Definition: error.h:38
#define STRNCASECMP
Old name of st_locale_insensitive_strncasecmp.
Definition: ctype.h:103
#define MBCLEN_INVALID_P(ret)
Old name of ONIGENC_MBCLEN_INVALID_P.
Definition: encoding.h:534
#define ISASCII
Old name of rb_isascii.
Definition: ctype.h:85
#define ECONV_STATEFUL_DECORATOR_MASK
Old name of RUBY_ECONV_STATEFUL_DECORATOR_MASK.
Definition: transcode.h:534
#define Qtrue
Old name of RUBY_Qtrue.
#define MBCLEN_NEEDMORE_P(ret)
Old name of ONIGENC_MBCLEN_NEEDMORE_P.
Definition: encoding.h:535
#define ECONV_PARTIAL_INPUT
Old name of RUBY_ECONV_PARTIAL_INPUT.
Definition: transcode.h:550
#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:519
#define INT2NUM
Old name of RB_INT2NUM.
Definition: int.h:43
#define Qnil
Old name of RUBY_Qnil.
#define Qfalse
Old name of RUBY_Qfalse.
#define FIX2LONG
Old name of RB_FIX2LONG.
Definition: long.h:46
#define ENC_CODERANGE_BROKEN
Old name of RUBY_ENC_CODERANGE_BROKEN.
Definition: coderange.h:182
#define T_ARRAY
Old name of RUBY_T_ARRAY.
Definition: value_type.h:56
#define NIL_P
Old name of RB_NIL_P.
#define ALLOCV_N
Old name of RB_ALLOCV_N.
Definition: memory.h:399
#define MBCLEN_CHARFOUND_P(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_P.
Definition: encoding.h:532
#define NUM2CHR
Old name of RB_NUM2CHR.
Definition: char.h:33
#define FL_TEST
Old name of RB_FL_TEST.
Definition: fl_type.h:139
#define NUM2LONG
Old name of RB_NUM2LONG.
Definition: long.h:51
#define UINT2NUM
Old name of RB_UINT2NUM.
Definition: int.h:46
#define FIXNUM_P
Old name of RB_FIXNUM_P.
#define ECONV_NEWLINE_DECORATOR_MASK
Old name of RUBY_ECONV_NEWLINE_DECORATOR_MASK.
Definition: transcode.h:526
#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:1740
#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:536
void rb_notimplement(void)
Definition: error.c:3064
void rb_category_warn(rb_warning_category_t cat, const char *fmt,...)
Identical to rb_category_warning(), except it reports always regardless of runtime -W flag.
Definition: error.c:428
void rb_raise(VALUE exc, const char *fmt,...)
Exception entry point.
Definition: error.c:3021
void rb_category_warning(rb_warning_category_t cat, const char *fmt,...)
Identical to rb_warning(), except it takes additional "category" parameter.
Definition: error.c:460
VALUE rb_rescue2(VALUE(*b_proc)(VALUE), VALUE data1, VALUE(*r_proc)(VALUE, VALUE), VALUE data2,...)
An equivalent of rescue clause.
Definition: eval.c:879
void rb_exc_raise(VALUE mesg)
Raises an exception in the current thread.
Definition: eval.c:671
void rb_syserr_fail(int e, const char *mesg)
Raises appropriate exception that represents a C errno.
Definition: error.c:3133
void rb_bug(const char *fmt,...)
Interpreter panic switch.
Definition: error.c:802
void rb_sys_fail(const char *mesg)
Converts a C errno into a Ruby exception, then raises it.
Definition: error.c:3145
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:13496
VALUE rb_eIOError
IOError exception.
Definition: io.c:187
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:3221
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:3139
#define ruby_verbose
This variable controls whether the interpreter is in debug mode.
Definition: error.h:459
VALUE rb_eEOFError
EOFError exception.
Definition: io.c:186
void rb_fatal(const char *fmt,...)
Raises the unsung "fatal" exception.
Definition: error.c:3072
void rb_readwrite_sys_fail(enum rb_io_wait_readwrite waiting, const char *mesg)
Raises appropriate exception using the parameters.
Definition: io.c:13490
void rb_iter_break_value(VALUE val)
Identical to rb_iter_break(), except it additionally takes the "value" of this breakage.
Definition: vm.c:1827
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports always regardless of runtime -W flag.
Definition: error.c:418
VALUE rb_ensure(VALUE(*b_proc)(VALUE), VALUE data1, VALUE(*e_proc)(VALUE), VALUE data2)
An equivalent to ensure clause.
Definition: eval.c:979
void rb_sys_fail_str(VALUE mesg)
Identical to rb_sys_fail(), except it takes the message in Ruby's String instead of C's.
Definition: error.c:3151
@ RB_WARN_CATEGORY_DEPRECATED
Warning is for deprecated features.
Definition: error.h:48
VALUE rb_cIO
IO class.
Definition: io.c:185
VALUE rb_mEnumerable
Enumerable module.
Definition: enum.c:27
VALUE rb_stdin
STDIN constant.
Definition: io.c:198
VALUE rb_stderr
STDERR constant.
Definition: io.c:198
VALUE rb_mWaitReadable
IO::WaitReadable module.
Definition: io.c:188
VALUE rb_mWaitWritable
IO::WaitReadable module.
Definition: io.c:189
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:2985
VALUE rb_cFile
File class.
Definition: file.c:174
VALUE rb_stdout
STDOUT constant.
Definition: io.c:198
int rb_enc_precise_mbclen(const char *p, const char *e, rb_encoding *enc)
Queries the number of bytes of the character at the passed pointer.
Definition: encoding.c:1234
int rb_to_encoding_index(VALUE obj)
Obtains a encoding index from a wider range of objects (than rb_enc_find_index()).
Definition: encoding.c:267
VALUE rb_enc_associate(VALUE obj, rb_encoding *enc)
Identical to rb_enc_associate(), except it takes an encoding itself instead of its index.
Definition: encoding.c:1066
rb_encoding * rb_ascii8bit_encoding(void)
Queries the encoding that represents ASCII-8BIT a.k.a.
Definition: encoding.c:1515
rb_encoding * rb_to_encoding(VALUE obj)
Identical to rb_find_encoding(), except it raises an exception instead of returning NULL.
Definition: encoding.c:329
static const char * rb_enc_name(rb_encoding *enc)
Queries the (canonical) name of the passed encoding.
Definition: encoding.h:433
rb_encoding * rb_default_internal_encoding(void)
Queries the "default internal" encoding.
Definition: encoding.c:1724
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:697
int rb_utf8_encindex(void)
Identical to rb_utf8_encoding(), except it returns the encoding's index instead of the encoding itsel...
Definition: encoding.c:1533
rb_encoding * rb_enc_get(VALUE obj)
Identical to rb_enc_get_index(), except the return type.
Definition: encoding.c:1072
rb_encoding * rb_enc_from_index(int idx)
Identical to rb_find_encoding(), except it takes an encoding index instead of a Ruby object.
Definition: encoding.c:414
VALUE rb_enc_from_encoding(rb_encoding *enc)
Queries the Ruby-level counterpart instance of rb_cEncoding that corresponds to the passed encoding.
Definition: encoding.c:188
rb_encoding * rb_find_encoding(VALUE obj)
Identical to rb_to_encoding_index(), except the return type.
Definition: encoding.c:336
static bool rb_enc_asciicompat(rb_encoding *enc)
Queries if the passed encoding is in some sense compatible with ASCII.
Definition: encoding.h:782
static unsigned int rb_enc_codepoint(const char *p, const char *e, rb_encoding *enc)
Queries the code point of character pointed by the passed pointer.
Definition: encoding.h:587
rb_encoding * rb_default_external_encoding(void)
Queries the "default external" encoding.
Definition: encoding.c:1637
int rb_enc_mbclen(const char *p, const char *e, rb_encoding *enc)
Queries the number of bytes of the character at the passed pointer.
Definition: encoding.c:1222
rb_encoding * rb_locale_encoding(void)
Queries the encoding that represents the current locale.
Definition: encoding.c:1573
rb_encoding * rb_usascii_encoding(void)
Queries the encoding that represents US-ASCII.
Definition: encoding.c:1539
int rb_enc_find_index(const char *name)
Queries the index of the encoding.
Definition: encoding.c:881
static int rb_enc_mbminlen(rb_encoding *enc)
Queries the minimum number of bytes that the passed encoding needs to represent a character.
Definition: encoding.h:448
int rb_enc_ascget(const char *p, const char *e, int *len, rb_encoding *enc)
Queries the code point of character pointed by the passed pointer.
Definition: encoding.c:1246
int rb_enc_str_coderange(VALUE str)
Scans the passed string to collect its code range.
Definition: string.c:776
VALUE rb_enc_uint_chr(unsigned int code, rb_encoding *enc)
Encodes the passed code point into a series of bytes.
Definition: numeric.c:3751
VALUE rb_enc_str_new(const char *ptr, long len, rb_encoding *enc)
Identical to rb_enc_str_new(), except it additionally takes an encoding.
Definition: string.c:940
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:668
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:2563
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:2065
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:1449
@ 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:1745
const char * rb_econv_asciicompat_encoding(const char *encname)
Queries the passed encoding's corresponding ASCII compatible encoding.
Definition: transcode.c:1789
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:1906
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:2614
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:1971
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:2929
VALUE rb_econv_make_exception(rb_econv_t *ec)
This function makes sense right after rb_econv_convert() returns.
Definition: transcode.c:4281
void rb_econv_check_error(rb_econv_t *ec)
This is a rb_econv_make_exception() + rb_exc_raise() combo.
Definition: transcode.c:4287
void rb_econv_close(rb_econv_t *ec)
Destructs a converter.
Definition: transcode.c:1705
void rb_econv_putback(rb_econv_t *ec, unsigned char *p, int n)
Puts back the bytes.
Definition: transcode.c:1756
VALUE rb_funcall(VALUE recv, ID mid, int n,...)
Calls a method.
Definition: vm_eval.c:1102
VALUE rb_funcallv_kw(VALUE recv, ID mid, int argc, const VALUE *argv, int kw_splat)
Identical to rb_funcallv(), except you can specify how to handle the last element of the given array.
Definition: vm_eval.c:1069
VALUE rb_funcallv(VALUE recv, ID mid, int argc, const VALUE *argv)
Identical to rb_funcall(), except it takes the method arguments as a C array.
Definition: vm_eval.c:1061
void rb_global_variable(VALUE *)
An alias for rb_gc_register_address().
Definition: gc.c:8742
void rb_gc_register_mark_object(VALUE object)
Inform the garbage collector that object is a live Ruby object that should not be moved.
Definition: gc.c:8686
Defines RBIMPL_HAS_BUILTIN.
VALUE rb_ary_concat(VALUE lhs, VALUE rhs)
Destructively appends the contents of latter into the end of former.
Definition: array.c:4790
VALUE rb_ary_shift(VALUE ary)
Destructively deletes an element from the beginning of the passed array and returns what was deleted.
Definition: array.c:1420
VALUE rb_check_array_type(VALUE obj)
Try converting an object to its array representation using its to_ary method, if any.
Definition: array.c:989
VALUE rb_ary_new(void)
Allocates a new, empty array.
Definition: array.c:750
VALUE rb_ary_push(VALUE ary, VALUE elem)
Special case of rb_ary_cat() that it adds only one element.
Definition: array.c:1308
VALUE rb_ary_entry(VALUE ary, long off)
Queries an element of an array.
Definition: array.c:1679
VALUE rb_assoc_new(VALUE car, VALUE cdr)
Identical to rb_ary_new_from_values(), except it expects exactly two parameters.
Definition: array.c:976
#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:278
static int rb_check_arity(int argc, int min, int max)
Ensures that the passed integer is in the passed range.
Definition: error.h:294
ID rb_frame_this_func(void)
Queries the name of the Ruby level method that is calling this function.
Definition: eval.c:1035
void rb_jump_tag(int state)
This function is to re-throw global escapes.
Definition: eval.c:841
VALUE rb_str_encode_ospath(VALUE path)
Converts a string into an "OS Path" encoding, if any.
Definition: file.c:251
void rb_gc_mark(VALUE obj)
Marks an object.
Definition: gc.c:6774
void rb_gc(void)
Triggers a GC process.
Definition: gc.c:10292
VALUE rb_check_hash_type(VALUE obj)
Try converting an object to its hash representation using its to_hash method, if any.
Definition: hash.c:1896
VALUE rb_hash_lookup2(VALUE hash, VALUE key, VALUE def)
Identical to rb_hash_lookup(), except you can specify what to return on misshits.
Definition: hash.c:2095
VALUE rb_hash_aref(VALUE hash, VALUE key)
Queries the given key in the given hash table.
Definition: hash.c:2082
VALUE rb_hash_aset(VALUE hash, VALUE key, VALUE val)
Inserts or replaces ("upsert"s) the objects into the given hash table.
Definition: hash.c:2903
VALUE rb_hash_lookup(VALUE hash, VALUE key)
Identical to rb_hash_aref(), except it always returns RUBY_Qnil for misshits.
Definition: hash.c:2108
VALUE rb_hash_dup(VALUE hash)
Duplicates a hash.
Definition: hash.c:1585
VALUE rb_hash_new(void)
Creates a new, empty hash object.
Definition: hash.c:1529
VALUE rb_io_printf(int argc, const VALUE *argv, VALUE io)
This is a rb_f_sprintf() + rb_io_write() combo.
Definition: io.c:7955
VALUE rb_io_gets(VALUE io)
Reads a "line" from the given IO.
Definition: io.c:3955
int rb_cloexec_pipe(int fildes[2])
Opens a pipe with closing on exec.
Definition: io.c:413
VALUE rb_rs
The record separator character for inputs, or the $/.
Definition: io.c:202
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:8026
VALUE rb_io_addstr(VALUE io, VALUE str)
Identical to rb_io_write(), except it always returns the passed IO.
Definition: io.c:2106
void rb_write_error(const char *str)
Writes the given error message to somewhere applicable.
Definition: io.c:8391
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:4668
VALUE rb_io_getbyte(VALUE io)
Reads a byte from the given IO.
Definition: io.c:4587
VALUE rb_io_puts(int argc, const VALUE *argv, VALUE io)
Iterates over the passed array to apply rb_io_write() individually.
Definition: io.c:8208
int rb_cloexec_dup2(int oldfd, int newfd)
Identical to rb_cloexec_dup(), except you can specify the destination file descriptor.
Definition: io.c:360
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:8498
void rb_update_max_fd(int fd)
Informs the interpreter that the passed fd can be the max.
Definition: io.c:234
VALUE rb_io_write(VALUE io, VALUE str)
Writes the given string to the given IO.
Definition: io.c:2063
int rb_cloexec_open(const char *pathname, int flags, mode_t mode)
Opens a file that closes on exec.
Definition: io.c:314
VALUE rb_output_rs
The record separator character for outputs, or the $\.
Definition: io.c:203
VALUE rb_io_eof(VALUE io)
Queries if the passed IO is at the end of file.
Definition: io.c:2450
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:8371
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:284
VALUE rb_io_flush(VALUE io)
Flushes any buffered data within the passed IO to the underlying operating system.
Definition: io.c:2162
VALUE rb_io_ascii8bit_binmode(VALUE io)
Forces no conversions be applied to the passed IO.
Definition: io.c:5788
VALUE rb_io_binmode(VALUE io)
Sets the binmode.
Definition: io.c:5742
VALUE rb_io_ungetc(VALUE io, VALUE c)
"Unget"s a string.
Definition: io.c:4723
int rb_pipe(int *pipes)
This is an rb_cloexec_pipe() + rb_update_max_fd() combo.
Definition: io.c:6792
VALUE rb_gets(void)
Much like rb_io_gets(), but it reads from the mysterious ARGF object.
Definition: io.c:9419
int rb_cloexec_fcntl_dupfd(int fd, int minfd)
Duplicates a file descriptor with closing on exec.
Definition: io.c:447
VALUE rb_output_fs
The field separator character for outputs, or the $,.
Definition: io.c:201
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:6675
int rb_cloexec_dup(int oldfd)
Identical to rb_cloexec_fcntl_dupfd(), except it implies minfd is 3.
Definition: io.c:353
VALUE rb_file_open(const char *fname, const char *fmode)
Opens a file located at the given path.
Definition: io.c:6682
VALUE rb_io_close(VALUE io)
Closes the IO.
Definition: io.c:5234
VALUE rb_default_rs
This is the default value of rb_rs, i.e.
Definition: io.c:204
void rb_lastline_set(VALUE str)
Updates $_.
Definition: vm.c:1598
VALUE rb_lastline_get(void)
Queries the last line, or the $_.
Definition: vm.c:1592
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:2825
VALUE rb_protect(VALUE(*func)(VALUE args), VALUE args, int *state)
Protects a function call from potential global escapes from the function.
rb_pid_t rb_waitpid(rb_pid_t pid, int *status, int flags)
Waits for a process, with releasing GVL.
Definition: process.c:1426
void rb_last_status_set(int status, rb_pid_t pid)
Sets the "last status", or the $?.
Definition: process.c:663
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:3317
VALUE rb_str_buf_cat(VALUE, const char *, long)
Just another name of rb_str_cat.
size_t rb_str_capacity(VALUE str)
Queries the capacity of the given string.
Definition: string.c:828
VALUE rb_str_new_frozen(VALUE str)
Creates a frozen copy of the string, if necessary.
Definition: string.c:1356
VALUE rb_str_cat2(VALUE, const char *)
Just another name of rb_str_cat_cstr.
VALUE rb_str_dup(VALUE str)
Duplicates a string.
Definition: string.c:1808
void rb_str_modify(VALUE str)
Declares that the string is about to be modified.
Definition: string.c:2459
VALUE rb_str_cat(VALUE dst, const char *src, long srclen)
Destructively appends the passed contents to the string.
Definition: string.c:3161
VALUE rb_str_locktmp(VALUE str)
Obtains a "temporary lock" of the string.
VALUE rb_usascii_str_new(const char *ptr, long len)
Identical to rb_str_new(), except it generates a string of "US ASCII" encoding.
Definition: string.c:924
rb_gvar_setter_t rb_str_setter
This is a rb_gvar_setter_t that refutes non-string assignments.
Definition: string.h:1177
void rb_str_set_len(VALUE str, long len)
Overwrites the length of the string.
Definition: string.c:3039
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:3278
VALUE rb_str_new(const char *ptr, long len)
Allocates an instance of rb_cString.
Definition: string.c:918
VALUE rb_check_string_type(VALUE obj)
Try converting an object to its stringised representation using its to_str method,...
Definition: string.c:2659
VALUE rb_str_substr(VALUE str, long beg, long len)
This is the implementation of two-argumented String#slice.
Definition: string.c:2931
VALUE rb_str_unlocktmp(VALUE str)
Releases a lock formerly obtained by rb_str_locktmp().
Definition: string.c:3022
VALUE rb_str_new_cstr(const char *ptr)
Identical to rb_str_new(), except it assumes the passed pointer is a pointer to a C string.
Definition: string.c:952
VALUE rb_str_resize(VALUE str, long len)
Overwrites the length of the string.
Definition: string.c:3056
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:2467
VALUE rb_str_buf_new(long capa)
Allocates a "string buffer".
Definition: string.c:1506
VALUE rb_obj_as_string(VALUE obj)
Try converting an object to its stringised representation using its to_s method, if any.
Definition: string.c:1657
int rb_thread_interrupted(VALUE thval)
Checks if the thread's execution was recently interrupted.
Definition: thread.c:1590
VALUE rb_mutex_new(void)
Creates a mutex.
Definition: thread_sync.c:172
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:1440
#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.
Definition: thread_sync.c:601
void rb_thread_check_ints(void)
Checks for interrupts.
Definition: thread.c:1573
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:1434
void rb_thread_schedule(void)
Tries to switch to another thread.
Definition: thread.c:1619
void rb_thread_sleep(int sec)
Blocks for the given period of time.
Definition: thread.c:1596
struct timeval rb_time_interval(VALUE num)
Creates a "time interval".
Definition: time.c:2643
VALUE rb_attr_get(VALUE obj, ID name)
Identical to rb_ivar_get()
Definition: variable.c:1293
void rb_set_class_path(VALUE klass, VALUE space, const char *name)
Names a class.
Definition: variable.c:235
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:1575
VALUE rb_class_name(VALUE obj)
Queries the name of the given object's class.
Definition: variable.c:294
int rb_respond_to(VALUE obj, ID mid)
Queries if the object responds to the method.
Definition: vm_method.c:2765
int rb_method_basic_definition_p(VALUE klass, ID mid)
Well... Let us hesitate from describing what a "basic definition" is.
Definition: vm_method.c:2643
VALUE rb_check_funcall(VALUE recv, ID mid, int argc, const VALUE *argv)
Identical to rb_funcallv(), except it returns RUBY_Qundef instead of raising rb_eNoMethodError.
Definition: vm_eval.c:664
void rb_define_alloc_func(VALUE klass, rb_alloc_func_t func)
Sets the allocator function of a class.
static ID rb_intern_const(const char *str)
This is a "tiny optimisation" over rb_intern().
Definition: symbol.h:276
ID rb_intern(const char *name)
Finds or creates a symbol of the given name.
Definition: symbol.c:782
const char * rb_id2name(ID id)
Retrieves the name mapped to the given id.
Definition: symbol.c:941
VALUE rb_id2str(ID id)
Identical to rb_id2name(), except it returns a Ruby's String instead of C's.
Definition: symbol.c:935
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:3265
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:588
rb_gvar_setter_t rb_gvar_readonly_setter
This function just raises rb_eNameError.
Definition: variable.h:135
void rb_define_virtual_variable(const char *name, rb_gvar_getter_t *getter, rb_gvar_setter_t *setter)
Defines a global variable that is purely function-backended.
Definition: variable.c:594
void rb_define_const(VALUE klass, const char *name, VALUE val)
Defines a Ruby level constant under a namespace.
Definition: variable.c:3253
void rb_define_hooked_variable(const char *name, VALUE *var, rb_gvar_getter_t *getter, rb_gvar_setter_t *setter)
Identical to rb_define_virtual_variable(), but can also specify a storage.
Definition: variable.c:563
#define FMODE_READABLE
The IO is opened for reading.
Definition: io.h:232
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:5873
VALUE rb_io_get_io(VALUE io)
Identical to rb_io_check_io(), except it raises exceptions on conversion failures.
Definition: io.c:801
VALUE rb_io_taint_check(VALUE obj)
Definition: io.c:771
void rb_io_read_check(rb_io_t *fptr)
Blocks until there is a pending read in the passed IO.
Definition: io.c:1007
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:6006
#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:321
#define FMODE_READWRITE
The IO is opened for both read/write.
Definition: io.h:238
#define GetOpenFile
This is an old name of RB_IO_POINTER.
Definition: io.h:343
void rb_io_check_byte_readable(rb_io_t *fptr)
Asserts that an IO is opened for byte-based reading.
Definition: io.c:953
#define FMODE_TTY
The IO is a TTY.
Definition: io.h:262
#define FMODE_CREATE
The IO is opened for creating.
Definition: io.h:285
void rb_io_check_readable(rb_io_t *fptr)
Just another name of rb_io_check_byte_readable.
Definition: io.c:962
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:6155
struct rb_io_t rb_io_t
Ruby's IO, metadata and buffers.
int rb_wait_for_single_fd(int fd, int events, struct timeval *tv)
Blocks until the passed file descriptor is ready for the passed events.
Definition: io.c:1428
struct rb_io_enc_t rb_io_enc_t
Just another name of rb_io_enc_t.
Definition: io.h:214
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:6476
int rb_io_descriptor(VALUE io)
Returns an integer representing the numeric file descriptor for io.
Definition: io.c:2650
#define FMODE_WRITABLE
The IO is opened for writing.
Definition: io.h:235
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:8544
#define FMODE_APPEND
The IO is opened for appending.
Definition: io.h:277
#define MakeOpenFile
This is an old name of RB_IO_OPEN.
Definition: io.h:366
#define FMODE_DUPLEX
Ruby eventually detects that the IO is bidirectional.
Definition: io.h:270
#define FMODE_BINMODE
The IO is in "binary mode".
Definition: io.h:249
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:1487
#define RB_IO_POINTER(obj, fp)
Queries the underlying IO pointer.
Definition: io.h:337
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:1446
#define FMODE_SYNC
The IO is in "sync mode".
Definition: io.h:256
void rb_io_check_initialized(rb_io_t *fptr)
Asserts that the passed IO is initialised.
Definition: io.c:778
#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:293
#define FMODE_TEXTMODE
The IO is in "text mode".
Definition: io.h:313
int rb_io_fptr_finalize(rb_io_t *fptr)
Destroys the given IO.
Definition: io.c:5161
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:807
ssize_t rb_io_bufwrite(VALUE io, const void *buf, size_t size)
Buffered write to the passed IO.
Definition: io.c:1807
void rb_io_check_char_readable(rb_io_t *fptr)
Asserts that an IO is opened for character-based reading.
Definition: io.c:934
#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:299
VALUE rb_io_get_write_io(VALUE io)
Queries the tied IO for writing.
Definition: io.c:813
void rb_io_set_nonblock(rb_io_t *fptr)
Sets an IO to a "nonblock mode".
Definition: io.c:3121
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:6282
int rb_io_wait_writable(int fd)
Blocks until the passed file descriptor gets writable.
Definition: io.c:1385
VALUE rb_io_set_write_io(VALUE io, VALUE w)
Assigns the tied IO for writing.
Definition: io.c:824
void rb_io_check_writable(rb_io_t *fptr)
Asserts that an IO is opened for writing.
Definition: io.c:986
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:1500
void rb_io_check_closed(rb_io_t *fptr)
This badly named function asserts that the passed IO is open.
Definition: io.c:786
@ RUBY_IO_READABLE
IO::READABLE
Definition: io.h:67
@ RUBY_IO_PRIORITY
IO::PRIORITY
Definition: io.h:69
@ RUBY_IO_WRITABLE
IO::WRITABLE
Definition: io.h:68
int rb_io_wait_readable(int fd)
Blocks until the passed file descriptor gets readable.
Definition: io.c:1351
void rb_io_synchronized(rb_io_t *fptr)
Sets FMODE_SYNC.
Definition: io.c:6779
VALUE rb_io_wait(VALUE io, VALUE events, VALUE timeout)
Blocks until the passed IO is ready for the passed events.
Definition: io.c:1294
void * rb_thread_call_with_gvl(void *(*func)(void *), void *data1)
(Re-)acquires the GVL.
Definition: thread.c:1888
void * rb_thread_call_without_gvl2(void *(*func)(void *), void *data1, rb_unblock_function_t *ubf, void *data2)
Identical to rb_thread_call_without_gvl(), except it does not interface with signals etc.
Definition: thread.c:1797
void * rb_thread_call_without_gvl(void *(*func)(void *), void *data1, rb_unblock_function_t *ubf, void *data2)
Allows the passed function to run in parallel with other Ruby threads.
#define RB_NUM2INT
Just another name of rb_num2int_inline.
Definition: int.h:38
#define RB_INT2NUM
Just another name of rb_int2num_inline.
Definition: int.h:37
VALUE rb_f_sprintf(int argc, const VALUE *argv)
Identical to rb_str_format(), except how the arguments are arranged.
Definition: sprintf.c:208
VALUE rb_sprintf(const char *fmt,...)
Ruby's extended sprintf(3).
Definition: sprintf.c:1201
VALUE rb_str_catf(VALUE dst, const char *fmt,...)
Identical to rb_sprintf(), except it renders the output to the specified object rather than creating ...
Definition: sprintf.c:1241
#define RB_BLOCK_CALL_FUNC_ARGLIST(yielded_arg, callback_arg)
Shim for block function parameters.
Definition: iterator.h:58
VALUE rb_yield_values2(int n, const VALUE *argv)
Identical to rb_yield_values(), except it takes the parameters as a C array instead of variadic argum...
Definition: vm_eval.c:1391
VALUE rb_yield(VALUE val)
Yields the block.
Definition: vm_eval.c:1357
int rb_fd_select(int nfds, rb_fdset_t *rfds, rb_fdset_t *wfds, rb_fdset_t *efds, struct timeval *timeout)
Waits for multiple file descriptors at once.
int rb_fd_isset(int fd, const rb_fdset_t *f)
Queries if the given FD is in the given set.
void rb_fd_term(rb_fdset_t *f)
Destroys the rb_fdset_t, releasing any memory and resources it used.
#define MEMZERO(p, type, n)
Handy macro to erase a region of memory.
Definition: memory.h: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
#define PRI_OFFT_PREFIX
A rb_sprintf() format prefix to be used for an off_t parameter.
Definition: off_t.h:55
#define OFFT2NUM
Converts a C's off_t into an instance of rb_cInteger.
Definition: off_t.h:33
#define NUM2OFFT
Converts an instance of rb_cNumeric into C's off_t.
Definition: off_t.h:44
#define PIDT2NUM
Converts a C's pid_t into an instance of rb_cInteger.
Definition: pid_t.h:28
#define rb_fd_init
Initialises the :given :rb_fdset_t.
Definition: posix.h:63
#define rb_fd_set
Sets the given fd to the rb_fdset_t.
Definition: posix.h:54
VALUE rb_ractor_stderr(void)
Queries the standard error of the current Ractor that is calling this function.
Definition: ractor.c:2146
VALUE rb_ractor_stdin(void)
Queries the standard input of the current Ractor that is calling this function.
Definition: ractor.c:2122
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:2182
VALUE rb_ractor_stdout(void)
Queries the standard output of the current Ractor that is calling this function.
Definition: ractor.c:2134
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:2170
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:2158
#define RARRAY_LEN
Just another name of rb_array_len.
Definition: rarray.h:68
static int RARRAY_LENINT(VALUE ary)
Identical to rb_array_len(), except it differs for the return type.
Definition: rarray.h:324
#define RARRAY_AREF(a, i)
Definition: rarray.h:588
#define RARRAY_CONST_PTR
Just another name of rb_array_const_ptr.
Definition: rarray.h:69
#define RFILE(obj)
Convenient casting macro.
Definition: rfile.h:50
#define SafeStringValue(v)
Definition: rstring.h:104
#define StringValue(v)
Ensures that the parameter object is a String.
Definition: rstring.h:72
static char * RSTRING_END(VALUE str)
Queries the end of the contents pointer of the string.
Definition: rstring.h:527
#define RSTRING_GETMEM(str, ptrvar, lenvar)
Convenient macro to obtain the contents and length at once.
Definition: rstring.h:573
static long RSTRING_LEN(VALUE str)
Queries the length of the string.
Definition: rstring.h:483
static char * RSTRING_PTR(VALUE str)
Queries the contents pointer of the string.
Definition: rstring.h:497
#define StringValueCStr(v)
Identical to StringValuePtr, except it additionally checks for the contents for viability as a C stri...
Definition: rstring.h:95
#define RUBY_TYPED_DEFAULT_FREE
This is a value you can set to rb_data_type_struct::dfree.
Definition: rtypeddata.h:79
#define TypedData_Make_Struct(klass, type, data_type, sval)
Identical to TypedData_Wrap_Struct, except it allocates a new data region internally instead of takin...
Definition: rtypeddata.h:489
VALUE rb_get_argv(void)
Queries the arguments passed to the current process that you can access from Ruby as ARGV.
Definition: io.c:13456
void rb_p(VALUE obj)
Inspects an object.
Definition: io.c:8277
#define FilePathValue(v)
Ensures that the parameter object is a path.
Definition: ruby.h:90
#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:126
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:153
VALUE rb_fiber_scheduler_io_wait_readable(VALUE scheduler, VALUE io)
Nonblocking wait until the passed IO is ready for reading.
Definition: scheduler.c:223
VALUE rb_fiber_scheduler_io_wait(VALUE scheduler, VALUE io, VALUE events, VALUE timeout)
Nonblocking version of rb_io_wait().
Definition: scheduler.c:217
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:66
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:131
VALUE rb_fiber_scheduler_io_wait_writable(VALUE scheduler, VALUE io)
Nonblocking wait until the passed IO is ready for writing.
Definition: scheduler.c:229
VALUE rb_fiber_scheduler_io_write_memory(VALUE scheduler, VALUE io, const void *buffer, size_t size, size_t length)
Nonblocking write to the passed IO using a native buffer.
Definition: scheduler.c:288
VALUE rb_fiber_scheduler_io_read_memory(VALUE scheduler, VALUE io, void *buffer, size_t size, size_t length)
Nonblocking read from the passed IO using a native buffer.
Definition: scheduler.c:275
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:4299
#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: io.c:222
Definition: win32.h:218
Definition: io.c:6688
This is the struct that holds necessary info for a struct.
The data structure which wraps the fd_set bitmap used by select(2).
IO buffers.
Definition: io.h:89
int len
Length of the buffer.
Definition: io.h:89
char * ptr
Pointer to the underlying memory region, of at least capa bytes.
Definition: io.h:89
int off
Offset inside of ptr.
Definition: io.h:89
int capa
Designed capacity of the buffer.
Definition: io.h:89
int ecflags
Flags.
Definition: io.h:156
rb_encoding * enc
Internal encoding.
Definition: io.h:146
rb_encoding * enc2
External encoding.
Definition: io.h:149
VALUE ecopts
Flags as Ruby hash.
Definition: io.h:165
Ruby's IO, metadata and buffers.
Definition: io.h:95
int fd
file descriptor.
Definition: io.h:104
struct rb_io_t::rb_io_enc_t encs
Decomposed encoding flags.
int lineno
number of lines read
Definition: io.h:113
rb_econv_t * writeconv
Encoding converter used when writing to this IO.
Definition: io.h:178
rb_pid_t pid
child's pid (for pipes)
Definition: io.h:110
rb_io_buffer_t wbuf
Write buffer.
Definition: io.h:122
rb_econv_t * readconv
Encoding converter used when reading from this IO.
Definition: io.h:169
VALUE writeconv_asciicompat
This is, when set, an instance of rb_cString which holds the "common" encoding.
Definition: io.h:186
FILE * stdio_file
stdio ptr for read/write, if available.
Definition: io.h:101
int writeconv_initialized
Whether rb_io_t::writeconv is already set up.
Definition: io.h:189
VALUE pathv
pathname for file
Definition: io.h:116
int mode
mode flags: FMODE_XXXs
Definition: io.h:107
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:195
VALUE write_lock
This is a Ruby level mutex.
Definition: io.h:210
rb_io_buffer_t cbuf
rb_io_ungetc() destination.
Definition: io.h:175
VALUE self
The IO's Ruby level counterpart.
Definition: io.h:98
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:201
VALUE tied_io_for_writing
Duplex IO object, if set.
Definition: io.h:135
void(* finalize)(struct rb_io_t *, int)
finalize proc
Definition: io.h:119
rb_io_buffer_t rbuf
(Byte) read buffer.
Definition: io.h:128
Definition: io.c:11038
Definition: io.c:1575
intptr_t SIGNED_VALUE
A signed integer type that has the same width with VALUE.
Definition: value.h:63
uintptr_t VALUE
Type that represents a Ruby object.
Definition: value.h:40
static void Check_Type(VALUE v, enum ruby_value_type t)
Identical to RB_TYPE_P(), except it raises exceptions on predication failure.
Definition: value_type.h:432
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.
Definition: value_type.h:375