00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #include "ruby/ruby.h"
00015 #include "ruby/io.h"
00016 #include "ruby/thread.h"
00017 #include "dln.h"
00018 #include "internal.h"
00019 #include "id.h"
00020 #include <ctype.h>
00021 #include <errno.h>
00022 #include "ruby_atomic.h"
00023
00024 #define free(x) xfree(x)
00025
00026 #if defined(DOSISH) || defined(__CYGWIN__)
00027 #include <io.h>
00028 #endif
00029
00030 #include <sys/types.h>
00031 #if defined HAVE_NET_SOCKET_H
00032 # include <net/socket.h>
00033 #elif defined HAVE_SYS_SOCKET_H
00034 # ifndef __native_client__
00035 # include <sys/socket.h>
00036 # endif
00037 #endif
00038
00039 #if defined(__BOW__) || defined(__CYGWIN__) || defined(_WIN32) || defined(__EMX__) || defined(__BEOS__) || defined(__HAIKU__)
00040 # define NO_SAFE_RENAME
00041 #endif
00042
00043 #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__sun) || defined(_nec_ews)
00044 # define USE_SETVBUF
00045 #endif
00046
00047 #ifdef __QNXNTO__
00048 #include "unix.h"
00049 #endif
00050
00051 #include <sys/types.h>
00052 #if defined(HAVE_SYS_IOCTL_H) && !defined(_WIN32)
00053 #include <sys/ioctl.h>
00054 #endif
00055 #if defined(__native_client__) && defined(NACL_NEWLIB)
00056 # include "nacl/ioctl.h"
00057 #endif
00058 #if defined(HAVE_FCNTL_H) || defined(_WIN32)
00059 #include <fcntl.h>
00060 #elif defined(HAVE_SYS_FCNTL_H)
00061 #include <sys/fcntl.h>
00062 #endif
00063
00064 #if !HAVE_OFF_T && !defined(off_t)
00065 # define off_t long
00066 #endif
00067
00068 #include <sys/stat.h>
00069
00070
00071 #if defined(HAVE_SYS_PARAM_H) && !(defined(__EMX__) || defined(__HIUX_MPP__))
00072 # include <sys/param.h>
00073 #endif
00074
00075 #if !defined NOFILE
00076 # define NOFILE 64
00077 #endif
00078
00079 #ifdef HAVE_UNISTD_H
00080 #include <unistd.h>
00081 #endif
00082
00083 #ifdef HAVE_SYSCALL_H
00084 #include <syscall.h>
00085 #elif defined HAVE_SYS_SYSCALL_H
00086 #include <sys/syscall.h>
00087 #endif
00088
00089 #if defined(__BEOS__) || defined(__HAIKU__)
00090 # ifndef NOFILE
00091 # define NOFILE (OPEN_MAX)
00092 # endif
00093 #endif
00094
00095 #include "ruby/util.h"
00096
00097 #ifndef O_ACCMODE
00098 #define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR)
00099 #endif
00100
00101 #if SIZEOF_OFF_T > SIZEOF_LONG && !defined(HAVE_LONG_LONG)
00102 # error off_t is bigger than long, but you have no long long...
00103 #endif
00104
00105 #ifndef PIPE_BUF
00106 # ifdef _POSIX_PIPE_BUF
00107 # define PIPE_BUF _POSIX_PIPE_BUF
00108 # else
00109 # define PIPE_BUF 512
00110 # endif
00111 #endif
00112
00113 #if defined(HAVE___SYSCALL) && (defined(__APPLE__) || defined(__OpenBSD__))
00114
00115 off_t __syscall(quad_t number, ...);
00116 #endif
00117
00118 #define numberof(array) (int)(sizeof(array) / sizeof((array)[0]))
00119
00120 #define IO_RBUF_CAPA_MIN 8192
00121 #define IO_CBUF_CAPA_MIN (128*1024)
00122 #define IO_RBUF_CAPA_FOR(fptr) (NEED_READCONV(fptr) ? IO_CBUF_CAPA_MIN : IO_RBUF_CAPA_MIN)
00123 #define IO_WBUF_CAPA_MIN 8192
00124
00125
00126 #ifdef _WIN32
00127 #undef open
00128 #define open rb_w32_uopen
00129 #endif
00130
00131 VALUE rb_cIO;
00132 VALUE rb_eEOFError;
00133 VALUE rb_eIOError;
00134 VALUE rb_mWaitReadable;
00135 VALUE rb_mWaitWritable;
00136
00137 VALUE rb_stdin, rb_stdout, rb_stderr;
00138 VALUE rb_deferr;
00139 static VALUE orig_stdout, orig_stderr;
00140
00141 VALUE rb_output_fs;
00142 VALUE rb_rs;
00143 VALUE rb_output_rs;
00144 VALUE rb_default_rs;
00145
00146 static VALUE argf;
00147
00148 static ID id_write, id_read, id_getc, id_flush, id_readpartial, id_set_encoding;
00149 static VALUE sym_mode, sym_perm, sym_extenc, sym_intenc, sym_encoding, sym_open_args;
00150 static VALUE sym_textmode, sym_binmode, sym_autoclose;
00151
00152 struct argf {
00153 VALUE filename, current_file;
00154 long last_lineno;
00155 long lineno;
00156 VALUE argv;
00157 char *inplace;
00158 struct rb_io_enc_t encs;
00159 int8_t init_p, next_p, binmode;
00160 };
00161
00162 static rb_atomic_t max_file_descriptor = NOFILE;
00163 void
00164 rb_update_max_fd(int fd)
00165 {
00166 struct stat buf;
00167 rb_atomic_t afd = (rb_atomic_t)fd;
00168
00169 if (fstat(fd, &buf) != 0 && errno == EBADF) {
00170 rb_bug("rb_update_max_fd: invalid fd (%d) given.", fd);
00171 }
00172
00173 while (max_file_descriptor < afd) {
00174 ATOMIC_CAS(max_file_descriptor, max_file_descriptor, afd);
00175 }
00176 }
00177
00178 void
00179 rb_maygvl_fd_fix_cloexec(int fd)
00180 {
00181
00182 #if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
00183 int flags, flags2, ret;
00184 flags = fcntl(fd, F_GETFD);
00185 if (flags == -1) {
00186 rb_bug("rb_maygvl_fd_fix_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(errno));
00187 }
00188 if (fd <= 2)
00189 flags2 = flags & ~FD_CLOEXEC;
00190 else
00191 flags2 = flags | FD_CLOEXEC;
00192 if (flags != flags2) {
00193 ret = fcntl(fd, F_SETFD, flags2);
00194 if (ret == -1) {
00195 rb_bug("rb_maygvl_fd_fix_cloexec: fcntl(%d, F_SETFD, %d) failed: %s", fd, flags2, strerror(errno));
00196 }
00197 }
00198 #endif
00199 }
00200
00201 void
00202 rb_fd_fix_cloexec(int fd)
00203 {
00204 rb_maygvl_fd_fix_cloexec(fd);
00205 rb_update_max_fd(fd);
00206 }
00207
00208 int
00209 rb_cloexec_open(const char *pathname, int flags, mode_t mode)
00210 {
00211 int ret;
00212 #ifdef O_CLOEXEC
00213
00214 flags |= O_CLOEXEC;
00215 #elif defined O_NOINHERIT
00216 flags |= O_NOINHERIT;
00217 #endif
00218 ret = open(pathname, flags, mode);
00219 if (ret == -1) return -1;
00220 rb_maygvl_fd_fix_cloexec(ret);
00221 return ret;
00222 }
00223
00224 int
00225 rb_cloexec_dup(int oldfd)
00226 {
00227
00228 return rb_cloexec_fcntl_dupfd(oldfd, 3);
00229 }
00230
00231 int
00232 rb_cloexec_dup2(int oldfd, int newfd)
00233 {
00234 int ret;
00235
00236
00237
00238 if (oldfd == newfd) {
00239 ret = newfd;
00240 }
00241 else {
00242 #if defined(HAVE_DUP3) && defined(O_CLOEXEC)
00243 static int try_dup3 = 1;
00244 if (2 < newfd && try_dup3) {
00245 ret = dup3(oldfd, newfd, O_CLOEXEC);
00246 if (ret != -1)
00247 return ret;
00248
00249 if (errno == ENOSYS) {
00250 try_dup3 = 0;
00251 ret = dup2(oldfd, newfd);
00252 }
00253 }
00254 else {
00255 ret = dup2(oldfd, newfd);
00256 }
00257 #else
00258 ret = dup2(oldfd, newfd);
00259 # ifdef _WIN32
00260 if (newfd >= 0 && newfd <= 2)
00261 SetStdHandle(newfd == 0 ? STD_INPUT_HANDLE : newfd == 1 ? STD_OUTPUT_HANDLE : STD_ERROR_HANDLE, (HANDLE)rb_w32_get_osfhandle(newfd));
00262 # endif
00263 #endif
00264 if (ret == -1) return -1;
00265 }
00266 rb_maygvl_fd_fix_cloexec(ret);
00267 return ret;
00268 }
00269
00270 int
00271 rb_cloexec_pipe(int fildes[2])
00272 {
00273 int ret;
00274
00275 #if defined(HAVE_PIPE2)
00276 static int try_pipe2 = 1;
00277 if (try_pipe2) {
00278 ret = pipe2(fildes, O_CLOEXEC);
00279 if (ret != -1)
00280 return ret;
00281
00282 if (errno == ENOSYS) {
00283 try_pipe2 = 0;
00284 ret = pipe(fildes);
00285 }
00286 }
00287 else {
00288 ret = pipe(fildes);
00289 }
00290 #else
00291 ret = pipe(fildes);
00292 #endif
00293 if (ret == -1) return -1;
00294 #ifdef __CYGWIN__
00295 if (ret == 0 && fildes[1] == -1) {
00296 close(fildes[0]);
00297 fildes[0] = -1;
00298 errno = ENFILE;
00299 return -1;
00300 }
00301 #endif
00302 rb_maygvl_fd_fix_cloexec(fildes[0]);
00303 rb_maygvl_fd_fix_cloexec(fildes[1]);
00304 return ret;
00305 }
00306
00307 int
00308 rb_cloexec_fcntl_dupfd(int fd, int minfd)
00309 {
00310 int ret;
00311
00312 #if defined(HAVE_FCNTL) && defined(F_DUPFD_CLOEXEC) && defined(F_DUPFD)
00313 static int try_dupfd_cloexec = 1;
00314 if (try_dupfd_cloexec) {
00315 ret = fcntl(fd, F_DUPFD_CLOEXEC, minfd);
00316 if (ret != -1) {
00317 if (ret <= 2)
00318 rb_maygvl_fd_fix_cloexec(ret);
00319 return ret;
00320 }
00321
00322 if (errno == EINVAL) {
00323 ret = fcntl(fd, F_DUPFD, minfd);
00324 if (ret != -1) {
00325 try_dupfd_cloexec = 0;
00326 }
00327 }
00328 }
00329 else {
00330 ret = fcntl(fd, F_DUPFD, minfd);
00331 }
00332 #elif defined(HAVE_FCNTL) && defined(F_DUPFD)
00333 ret = fcntl(fd, F_DUPFD, minfd);
00334 #elif defined(HAVE_DUP)
00335 ret = dup(fd);
00336 if (ret != -1 && ret < minfd) {
00337 const int prev_fd = ret;
00338 ret = rb_cloexec_fcntl_dupfd(fd, minfd);
00339 close(prev_fd);
00340 }
00341 return ret;
00342 #else
00343 # error "dup() or fcntl(F_DUPFD) must be supported."
00344 #endif
00345 if (ret == -1) return -1;
00346 rb_maygvl_fd_fix_cloexec(ret);
00347 return ret;
00348 }
00349
00350 #define argf_of(obj) (*(struct argf *)DATA_PTR(obj))
00351 #define ARGF argf_of(argf)
00352
00353 #ifdef _STDIO_USES_IOSTREAM
00354 # ifdef _IO_fpos_t
00355 # define STDIO_READ_DATA_PENDING(fp) ((fp)->_IO_read_ptr != (fp)->_IO_read_end)
00356 # else
00357 # define STDIO_READ_DATA_PENDING(fp) ((fp)->_gptr < (fp)->_egptr)
00358 # endif
00359 #elif defined(FILE_COUNT)
00360 # define STDIO_READ_DATA_PENDING(fp) ((fp)->FILE_COUNT > 0)
00361 #elif defined(FILE_READEND)
00362 # define STDIO_READ_DATA_PENDING(fp) ((fp)->FILE_READPTR < (fp)->FILE_READEND)
00363 #elif defined(__BEOS__) || defined(__HAIKU__)
00364 # define STDIO_READ_DATA_PENDING(fp) ((fp)->_state._eof == 0)
00365 #else
00366 # define STDIO_READ_DATA_PENDING(fp) (!feof(fp))
00367 #endif
00368
00369 #define GetWriteIO(io) rb_io_get_write_io(io)
00370
00371 #define READ_DATA_PENDING(fptr) ((fptr)->rbuf.len)
00372 #define READ_DATA_PENDING_COUNT(fptr) ((fptr)->rbuf.len)
00373 #define READ_DATA_PENDING_PTR(fptr) ((fptr)->rbuf.ptr+(fptr)->rbuf.off)
00374 #define READ_DATA_BUFFERED(fptr) READ_DATA_PENDING(fptr)
00375
00376 #define READ_CHAR_PENDING(fptr) ((fptr)->cbuf.len)
00377 #define READ_CHAR_PENDING_COUNT(fptr) ((fptr)->cbuf.len)
00378 #define READ_CHAR_PENDING_PTR(fptr) ((fptr)->cbuf.ptr+(fptr)->cbuf.off)
00379
00380 #if defined(_WIN32)
00381 #define WAIT_FD_IN_WIN32(fptr) \
00382 (rb_w32_io_cancelable_p((fptr)->fd) ? 0 : rb_thread_wait_fd((fptr)->fd))
00383 #else
00384 #define WAIT_FD_IN_WIN32(fptr)
00385 #endif
00386
00387 #define READ_CHECK(fptr) do {\
00388 if (!READ_DATA_PENDING(fptr)) {\
00389 WAIT_FD_IN_WIN32(fptr);\
00390 rb_io_check_closed(fptr);\
00391 }\
00392 } while(0)
00393
00394 #ifndef S_ISSOCK
00395 # ifdef _S_ISSOCK
00396 # define S_ISSOCK(m) _S_ISSOCK(m)
00397 # else
00398 # ifdef _S_IFSOCK
00399 # define S_ISSOCK(m) (((m) & S_IFMT) == _S_IFSOCK)
00400 # else
00401 # ifdef S_IFSOCK
00402 # define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
00403 # endif
00404 # endif
00405 # endif
00406 #endif
00407
00408 #define rb_sys_fail_path(path) rb_sys_fail_str(path)
00409
00410 static int io_fflush(rb_io_t *);
00411 static rb_io_t *flush_before_seek(rb_io_t *fptr);
00412
00413 #define NEED_NEWLINE_DECORATOR_ON_READ(fptr) ((fptr)->mode & FMODE_TEXTMODE)
00414 #define NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) ((fptr)->mode & FMODE_TEXTMODE)
00415 #if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)
00416
00417 # define DEFAULT_TEXTMODE FMODE_TEXTMODE
00418 # define TEXTMODE_NEWLINE_DECORATOR_ON_WRITE ECONV_CRLF_NEWLINE_DECORATOR
00419
00420
00421
00422
00423
00424
00425
00426 #define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || (fptr)->encs.ecflags & ~ECONV_CRLF_NEWLINE_DECORATOR)
00427 #define NEED_WRITECONV(fptr) (((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || ((fptr)->encs.ecflags & ((ECONV_DECORATOR_MASK & ~ECONV_CRLF_NEWLINE_DECORATOR)|ECONV_STATEFUL_DECORATOR_MASK)))
00428 #define SET_BINARY_MODE(fptr) setmode((fptr)->fd, O_BINARY)
00429
00430 #define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) do {\
00431 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {\
00432 if (((fptr)->mode & FMODE_READABLE) &&\
00433 !((fptr)->encs.ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {\
00434 setmode((fptr)->fd, O_BINARY);\
00435 }\
00436 else {\
00437 setmode((fptr)->fd, O_TEXT);\
00438 }\
00439 }\
00440 } while(0)
00441
00442 #define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) do {\
00443 if ((enc2) && ((ecflags) & ECONV_DEFAULT_NEWLINE_DECORATOR)) {\
00444 (ecflags) |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;\
00445 }\
00446 } while(0)
00447
00448
00449
00450
00451 static void
00452 io_unread(rb_io_t *fptr)
00453 {
00454 off_t r, pos;
00455 ssize_t read_size;
00456 long i;
00457 long newlines = 0;
00458 long extra_max;
00459 char *p;
00460 char *buf;
00461
00462 rb_io_check_closed(fptr);
00463 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX) {
00464 return;
00465 }
00466
00467 errno = 0;
00468 if (!rb_w32_fd_is_text(fptr->fd)) {
00469 r = lseek(fptr->fd, -fptr->rbuf.len, SEEK_CUR);
00470 if (r < 0 && errno) {
00471 if (errno == ESPIPE)
00472 fptr->mode |= FMODE_DUPLEX;
00473 return;
00474 }
00475
00476 fptr->rbuf.off = 0;
00477 fptr->rbuf.len = 0;
00478 return;
00479 }
00480
00481 pos = lseek(fptr->fd, 0, SEEK_CUR);
00482 if (pos < 0 && errno) {
00483 if (errno == ESPIPE)
00484 fptr->mode |= FMODE_DUPLEX;
00485 return;
00486 }
00487
00488
00489 extra_max = (long)(pos - fptr->rbuf.len);
00490 p = fptr->rbuf.ptr + fptr->rbuf.off;
00491
00492
00493 if (*(fptr->rbuf.ptr + fptr->rbuf.capa - 1) == '\r') {
00494 newlines++;
00495 }
00496
00497 for (i = 0; i < fptr->rbuf.len; i++) {
00498 if (*p == '\n') newlines++;
00499 if (extra_max == newlines) break;
00500 p++;
00501 }
00502
00503 buf = ALLOC_N(char, fptr->rbuf.len + newlines);
00504 while (newlines >= 0) {
00505 r = lseek(fptr->fd, pos - fptr->rbuf.len - newlines, SEEK_SET);
00506 if (newlines == 0) break;
00507 if (r < 0) {
00508 newlines--;
00509 continue;
00510 }
00511 read_size = _read(fptr->fd, buf, fptr->rbuf.len + newlines);
00512 if (read_size < 0) {
00513 free(buf);
00514 rb_sys_fail_path(fptr->pathv);
00515 }
00516 if (read_size == fptr->rbuf.len) {
00517 lseek(fptr->fd, r, SEEK_SET);
00518 break;
00519 }
00520 else {
00521 newlines--;
00522 }
00523 }
00524 free(buf);
00525 fptr->rbuf.off = 0;
00526 fptr->rbuf.len = 0;
00527 return;
00528 }
00529
00530
00531
00532
00533
00534
00535
00536
00537 static inline int
00538 set_binary_mode_with_seek_cur(rb_io_t *fptr)
00539 {
00540 if (!rb_w32_fd_is_text(fptr->fd)) return O_BINARY;
00541
00542 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX) {
00543 return setmode(fptr->fd, O_BINARY);
00544 }
00545 flush_before_seek(fptr);
00546 return setmode(fptr->fd, O_BINARY);
00547 }
00548 #define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) set_binary_mode_with_seek_cur(fptr)
00549
00550 #else
00551
00552 # define DEFAULT_TEXTMODE 0
00553 #define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || NEED_NEWLINE_DECORATOR_ON_READ(fptr))
00554 #define NEED_WRITECONV(fptr) (((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) || ((fptr)->encs.ecflags & (ECONV_DECORATOR_MASK|ECONV_STATEFUL_DECORATOR_MASK)))
00555 #define SET_BINARY_MODE(fptr) (void)(fptr)
00556 #define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) (void)(fptr)
00557 #define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) ((void)(enc2), (void)(ecflags))
00558 #define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) (void)(fptr)
00559 #endif
00560
00561 #if !defined HAVE_SHUTDOWN && !defined shutdown
00562 #define shutdown(a,b) 0
00563 #endif
00564
00565 #if defined(_WIN32)
00566 #define is_socket(fd, path) rb_w32_is_socket(fd)
00567 #elif !defined(S_ISSOCK)
00568 #define is_socket(fd, path) 0
00569 #else
00570 static int
00571 is_socket(int fd, VALUE path)
00572 {
00573 struct stat sbuf;
00574 if (fstat(fd, &sbuf) < 0)
00575 rb_sys_fail_path(path);
00576 return S_ISSOCK(sbuf.st_mode);
00577 }
00578 #endif
00579
00580 static const char closed_stream[] = "closed stream";
00581
00582 void
00583 rb_eof_error(void)
00584 {
00585 rb_raise(rb_eEOFError, "end of file reached");
00586 }
00587
00588 static VALUE
00589 taint_check(VALUE io)
00590 {
00591 if (!OBJ_UNTRUSTED(io) && rb_safe_level() >= 4)
00592 rb_raise(rb_eSecurityError, "Insecure: operation on trusted IO");
00593 return io;
00594 }
00595
00596 VALUE
00597 rb_io_taint_check(VALUE io)
00598 {
00599 rb_check_frozen(taint_check(io));
00600 return io;
00601 }
00602
00603 void
00604 rb_io_check_initialized(rb_io_t *fptr)
00605 {
00606 if (!fptr) {
00607 rb_raise(rb_eIOError, "uninitialized stream");
00608 }
00609 }
00610
00611 void
00612 rb_io_check_closed(rb_io_t *fptr)
00613 {
00614 rb_io_check_initialized(fptr);
00615 if (fptr->fd < 0) {
00616 rb_raise(rb_eIOError, closed_stream);
00617 }
00618 }
00619
00620
00621 VALUE
00622 rb_io_get_io(VALUE io)
00623 {
00624 return rb_convert_type(io, T_FILE, "IO", "to_io");
00625 }
00626
00627 VALUE
00628 rb_io_check_io(VALUE io)
00629 {
00630 return rb_check_convert_type(io, T_FILE, "IO", "to_io");
00631 }
00632
00633 VALUE
00634 rb_io_get_write_io(VALUE io)
00635 {
00636 VALUE write_io;
00637 rb_io_check_initialized(RFILE(io)->fptr);
00638 write_io = RFILE(io)->fptr->tied_io_for_writing;
00639 if (write_io) {
00640 return write_io;
00641 }
00642 return io;
00643 }
00644
00645 VALUE
00646 rb_io_set_write_io(VALUE io, VALUE w)
00647 {
00648 VALUE write_io;
00649 rb_io_check_initialized(RFILE(io)->fptr);
00650 if (!RTEST(w)) {
00651 w = 0;
00652 }
00653 else {
00654 GetWriteIO(w);
00655 }
00656 write_io = RFILE(io)->fptr->tied_io_for_writing;
00657 RFILE(io)->fptr->tied_io_for_writing = w;
00658 return write_io ? write_io : Qnil;
00659 }
00660
00661
00662
00663
00664
00665
00666
00667
00668
00669
00670
00671
00672
00673
00674
00675
00676
00677
00678 static VALUE
00679 rb_io_s_try_convert(VALUE dummy, VALUE io)
00680 {
00681 return rb_io_check_io(io);
00682 }
00683
00684 #if !(defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32))
00685 static void
00686 io_unread(rb_io_t *fptr)
00687 {
00688 off_t r;
00689 rb_io_check_closed(fptr);
00690 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX)
00691 return;
00692
00693 errno = 0;
00694 r = lseek(fptr->fd, -fptr->rbuf.len, SEEK_CUR);
00695 if (r < 0 && errno) {
00696 if (errno == ESPIPE)
00697 fptr->mode |= FMODE_DUPLEX;
00698 return;
00699 }
00700 fptr->rbuf.off = 0;
00701 fptr->rbuf.len = 0;
00702 return;
00703 }
00704 #endif
00705
00706 static rb_encoding *io_input_encoding(rb_io_t *fptr);
00707
00708 static void
00709 io_ungetbyte(VALUE str, rb_io_t *fptr)
00710 {
00711 long len = RSTRING_LEN(str);
00712
00713 if (fptr->rbuf.ptr == NULL) {
00714 const int min_capa = IO_RBUF_CAPA_FOR(fptr);
00715 fptr->rbuf.off = 0;
00716 fptr->rbuf.len = 0;
00717 #if SIZEOF_LONG > SIZEOF_INT
00718 if (len > INT_MAX)
00719 rb_raise(rb_eIOError, "ungetbyte failed");
00720 #endif
00721 if (len > min_capa)
00722 fptr->rbuf.capa = (int)len;
00723 else
00724 fptr->rbuf.capa = min_capa;
00725 fptr->rbuf.ptr = ALLOC_N(char, fptr->rbuf.capa);
00726 }
00727 if (fptr->rbuf.capa < len + fptr->rbuf.len) {
00728 rb_raise(rb_eIOError, "ungetbyte failed");
00729 }
00730 if (fptr->rbuf.off < len) {
00731 MEMMOVE(fptr->rbuf.ptr+fptr->rbuf.capa-fptr->rbuf.len,
00732 fptr->rbuf.ptr+fptr->rbuf.off,
00733 char, fptr->rbuf.len);
00734 fptr->rbuf.off = fptr->rbuf.capa-fptr->rbuf.len;
00735 }
00736 fptr->rbuf.off-=(int)len;
00737 fptr->rbuf.len+=(int)len;
00738 MEMMOVE(fptr->rbuf.ptr+fptr->rbuf.off, RSTRING_PTR(str), char, len);
00739 }
00740
00741 static rb_io_t *
00742 flush_before_seek(rb_io_t *fptr)
00743 {
00744 if (io_fflush(fptr) < 0)
00745 rb_sys_fail(0);
00746 io_unread(fptr);
00747 errno = 0;
00748 return fptr;
00749 }
00750
00751 #define io_seek(fptr, ofs, whence) (errno = 0, lseek(flush_before_seek(fptr)->fd, (ofs), (whence)))
00752 #define io_tell(fptr) lseek(flush_before_seek(fptr)->fd, 0, SEEK_CUR)
00753
00754 #ifndef SEEK_CUR
00755 # define SEEK_SET 0
00756 # define SEEK_CUR 1
00757 # define SEEK_END 2
00758 #endif
00759
00760 void
00761 rb_io_check_char_readable(rb_io_t *fptr)
00762 {
00763 rb_io_check_closed(fptr);
00764 if (!(fptr->mode & FMODE_READABLE)) {
00765 rb_raise(rb_eIOError, "not opened for reading");
00766 }
00767 if (fptr->wbuf.len) {
00768 if (io_fflush(fptr) < 0)
00769 rb_sys_fail(0);
00770 }
00771 if (fptr->tied_io_for_writing) {
00772 rb_io_t *wfptr;
00773 GetOpenFile(fptr->tied_io_for_writing, wfptr);
00774 if (io_fflush(wfptr) < 0)
00775 rb_sys_fail(0);
00776 }
00777 }
00778
00779 void
00780 rb_io_check_byte_readable(rb_io_t *fptr)
00781 {
00782 rb_io_check_char_readable(fptr);
00783 if (READ_CHAR_PENDING(fptr)) {
00784 rb_raise(rb_eIOError, "byte oriented read for character buffered IO");
00785 }
00786 }
00787
00788 void
00789 rb_io_check_readable(rb_io_t *fptr)
00790 {
00791 rb_io_check_byte_readable(fptr);
00792 }
00793
00794 static rb_encoding*
00795 io_read_encoding(rb_io_t *fptr)
00796 {
00797 if (fptr->encs.enc) {
00798 return fptr->encs.enc;
00799 }
00800 return rb_default_external_encoding();
00801 }
00802
00803 static rb_encoding*
00804 io_input_encoding(rb_io_t *fptr)
00805 {
00806 if (fptr->encs.enc2) {
00807 return fptr->encs.enc2;
00808 }
00809 return io_read_encoding(fptr);
00810 }
00811
00812 void
00813 rb_io_check_writable(rb_io_t *fptr)
00814 {
00815 rb_io_check_closed(fptr);
00816 if (!(fptr->mode & FMODE_WRITABLE)) {
00817 rb_raise(rb_eIOError, "not opened for writing");
00818 }
00819 if (fptr->rbuf.len) {
00820 io_unread(fptr);
00821 }
00822 }
00823
00824 int
00825 rb_io_read_pending(rb_io_t *fptr)
00826 {
00827
00828 if (READ_CHAR_PENDING(fptr))
00829 return 1;
00830 return READ_DATA_PENDING(fptr);
00831 }
00832
00833 void
00834 rb_read_check(FILE *fp)
00835 {
00836 if (!STDIO_READ_DATA_PENDING(fp)) {
00837 rb_thread_wait_fd(fileno(fp));
00838 }
00839 }
00840
00841 void
00842 rb_io_read_check(rb_io_t *fptr)
00843 {
00844 if (!READ_DATA_PENDING(fptr)) {
00845 rb_thread_wait_fd(fptr->fd);
00846 }
00847 return;
00848 }
00849
00850 static int
00851 ruby_dup(int orig)
00852 {
00853 int fd;
00854
00855 fd = rb_cloexec_dup(orig);
00856 if (fd < 0) {
00857 if (errno == EMFILE || errno == ENFILE || errno == ENOMEM) {
00858 rb_gc();
00859 fd = rb_cloexec_dup(orig);
00860 }
00861 if (fd < 0) {
00862 rb_sys_fail(0);
00863 }
00864 }
00865 rb_update_max_fd(fd);
00866 return fd;
00867 }
00868
00869 static VALUE
00870 io_alloc(VALUE klass)
00871 {
00872 NEWOBJ_OF(io, struct RFile, klass, T_FILE);
00873
00874 io->fptr = 0;
00875
00876 return (VALUE)io;
00877 }
00878
00879 #ifndef S_ISREG
00880 # define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
00881 #endif
00882
00883 static int
00884 wsplit_p(rb_io_t *fptr)
00885 {
00886 #if defined(HAVE_FCNTL) && defined(F_GETFL) && defined(O_NONBLOCK)
00887 int r;
00888 #endif
00889
00890 if (!(fptr->mode & FMODE_WSPLIT_INITIALIZED)) {
00891 struct stat buf;
00892 if (fstat(fptr->fd, &buf) == 0 &&
00893 !S_ISREG(buf.st_mode)
00894 #if defined(HAVE_FCNTL) && defined(F_GETFL) && defined(O_NONBLOCK)
00895 && (r = fcntl(fptr->fd, F_GETFL)) != -1 &&
00896 !(r & O_NONBLOCK)
00897 #endif
00898 ) {
00899 fptr->mode |= FMODE_WSPLIT;
00900 }
00901 fptr->mode |= FMODE_WSPLIT_INITIALIZED;
00902 }
00903 return fptr->mode & FMODE_WSPLIT;
00904 }
00905
00906 struct io_internal_read_struct {
00907 int fd;
00908 void *buf;
00909 size_t capa;
00910 };
00911
00912 struct io_internal_write_struct {
00913 int fd;
00914 const void *buf;
00915 size_t capa;
00916 };
00917
00918 static VALUE
00919 internal_read_func(void *ptr)
00920 {
00921 struct io_internal_read_struct *iis = ptr;
00922 return read(iis->fd, iis->buf, iis->capa);
00923 }
00924
00925 static VALUE
00926 internal_write_func(void *ptr)
00927 {
00928 struct io_internal_write_struct *iis = ptr;
00929 return write(iis->fd, iis->buf, iis->capa);
00930 }
00931
00932 static void*
00933 internal_write_func2(void *ptr)
00934 {
00935 struct io_internal_write_struct *iis = ptr;
00936 return (void*)(intptr_t)write(iis->fd, iis->buf, iis->capa);
00937 }
00938
00939 static ssize_t
00940 rb_read_internal(int fd, void *buf, size_t count)
00941 {
00942 struct io_internal_read_struct iis;
00943 iis.fd = fd;
00944 iis.buf = buf;
00945 iis.capa = count;
00946
00947 return (ssize_t)rb_thread_io_blocking_region(internal_read_func, &iis, fd);
00948 }
00949
00950 static ssize_t
00951 rb_write_internal(int fd, const void *buf, size_t count)
00952 {
00953 struct io_internal_write_struct iis;
00954 iis.fd = fd;
00955 iis.buf = buf;
00956 iis.capa = count;
00957
00958 return (ssize_t)rb_thread_io_blocking_region(internal_write_func, &iis, fd);
00959 }
00960
00961 static ssize_t
00962 rb_write_internal2(int fd, const void *buf, size_t count)
00963 {
00964 struct io_internal_write_struct iis;
00965 iis.fd = fd;
00966 iis.buf = buf;
00967 iis.capa = count;
00968
00969 return (ssize_t)rb_thread_call_without_gvl2(internal_write_func2, &iis,
00970 RUBY_UBF_IO, NULL);
00971 }
00972
00973 static long
00974 io_writable_length(rb_io_t *fptr, long l)
00975 {
00976 if (PIPE_BUF < l &&
00977 !rb_thread_alone() &&
00978 wsplit_p(fptr)) {
00979 l = PIPE_BUF;
00980 }
00981 return l;
00982 }
00983
00984 static VALUE
00985 io_flush_buffer_sync(void *arg)
00986 {
00987 rb_io_t *fptr = arg;
00988 long l = io_writable_length(fptr, fptr->wbuf.len);
00989 ssize_t r = write(fptr->fd, fptr->wbuf.ptr+fptr->wbuf.off, (size_t)l);
00990
00991 if (fptr->wbuf.len <= r) {
00992 fptr->wbuf.off = 0;
00993 fptr->wbuf.len = 0;
00994 return 0;
00995 }
00996 if (0 <= r) {
00997 fptr->wbuf.off += (int)r;
00998 fptr->wbuf.len -= (int)r;
00999 errno = EAGAIN;
01000 }
01001 return (VALUE)-1;
01002 }
01003
01004 static void*
01005 io_flush_buffer_sync2(void *arg)
01006 {
01007 VALUE result = io_flush_buffer_sync(arg);
01008
01009
01010
01011
01012
01013 return !result ? (void*)1 : (void*)result;
01014 }
01015
01016 static VALUE
01017 io_flush_buffer_async(VALUE arg)
01018 {
01019 rb_io_t *fptr = (rb_io_t *)arg;
01020 return rb_thread_io_blocking_region(io_flush_buffer_sync, fptr, fptr->fd);
01021 }
01022
01023 static VALUE
01024 io_flush_buffer_async2(VALUE arg)
01025 {
01026 rb_io_t *fptr = (rb_io_t *)arg;
01027 VALUE ret;
01028
01029 ret = (VALUE)rb_thread_call_without_gvl2(io_flush_buffer_sync2, fptr,
01030 RUBY_UBF_IO, NULL);
01031
01032 if (!ret) {
01033
01034 errno = EAGAIN;
01035 return -1;
01036 } else if (ret == 1) {
01037 return 0;
01038 } else
01039 return ret;
01040 }
01041
01042 static inline int
01043 io_flush_buffer(rb_io_t *fptr)
01044 {
01045 if (fptr->write_lock) {
01046 if (rb_mutex_owned_p(fptr->write_lock))
01047 return (int)io_flush_buffer_async2((VALUE)fptr);
01048 else
01049 return (int)rb_mutex_synchronize(fptr->write_lock, io_flush_buffer_async2, (VALUE)fptr);
01050 }
01051 else {
01052 return (int)io_flush_buffer_async((VALUE)fptr);
01053 }
01054 }
01055
01056 static int
01057 io_fflush(rb_io_t *fptr)
01058 {
01059 rb_io_check_closed(fptr);
01060 if (fptr->wbuf.len == 0)
01061 return 0;
01062 rb_io_check_closed(fptr);
01063 while (fptr->wbuf.len > 0 && io_flush_buffer(fptr) != 0) {
01064 if (!rb_io_wait_writable(fptr->fd))
01065 return -1;
01066 rb_io_check_closed(fptr);
01067 }
01068 return 0;
01069 }
01070
01071 int
01072 rb_io_wait_readable(int f)
01073 {
01074 if (f < 0) {
01075 rb_raise(rb_eIOError, closed_stream);
01076 }
01077 switch (errno) {
01078 case EINTR:
01079 #if defined(ERESTART)
01080 case ERESTART:
01081 #endif
01082 rb_thread_check_ints();
01083 return TRUE;
01084
01085 case EAGAIN:
01086 #if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
01087 case EWOULDBLOCK:
01088 #endif
01089 rb_thread_wait_fd(f);
01090 return TRUE;
01091
01092 default:
01093 return FALSE;
01094 }
01095 }
01096
01097 int
01098 rb_io_wait_writable(int f)
01099 {
01100 if (f < 0) {
01101 rb_raise(rb_eIOError, closed_stream);
01102 }
01103 switch (errno) {
01104 case EINTR:
01105 #if defined(ERESTART)
01106 case ERESTART:
01107 #endif
01108
01109
01110
01111
01112
01113
01114
01115
01116
01117 rb_thread_check_ints();
01118 return TRUE;
01119
01120 case EAGAIN:
01121 #if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
01122 case EWOULDBLOCK:
01123 #endif
01124 rb_thread_fd_writable(f);
01125 return TRUE;
01126
01127 default:
01128 return FALSE;
01129 }
01130 }
01131
01132 static void
01133 make_writeconv(rb_io_t *fptr)
01134 {
01135 if (!fptr->writeconv_initialized) {
01136 const char *senc, *denc;
01137 rb_encoding *enc;
01138 int ecflags;
01139 VALUE ecopts;
01140
01141 fptr->writeconv_initialized = 1;
01142
01143 ecflags = fptr->encs.ecflags & ~ECONV_NEWLINE_DECORATOR_READ_MASK;
01144 ecopts = fptr->encs.ecopts;
01145
01146 if (!fptr->encs.enc || (fptr->encs.enc == rb_ascii8bit_encoding() && !fptr->encs.enc2)) {
01147
01148 fptr->writeconv_pre_ecflags = 0;
01149 fptr->writeconv_pre_ecopts = Qnil;
01150 fptr->writeconv = rb_econv_open_opts("", "", ecflags, ecopts);
01151 if (!fptr->writeconv)
01152 rb_exc_raise(rb_econv_open_exc("", "", ecflags));
01153 fptr->writeconv_asciicompat = Qnil;
01154 }
01155 else {
01156 enc = fptr->encs.enc2 ? fptr->encs.enc2 : fptr->encs.enc;
01157 senc = rb_econv_asciicompat_encoding(rb_enc_name(enc));
01158 if (!senc && !(fptr->encs.ecflags & ECONV_STATEFUL_DECORATOR_MASK)) {
01159
01160 fptr->writeconv_pre_ecflags = ecflags;
01161 fptr->writeconv_pre_ecopts = ecopts;
01162 fptr->writeconv = NULL;
01163 fptr->writeconv_asciicompat = Qnil;
01164 }
01165 else {
01166
01167 fptr->writeconv_pre_ecflags = ecflags & ~ECONV_STATEFUL_DECORATOR_MASK;
01168 fptr->writeconv_pre_ecopts = ecopts;
01169 if (senc) {
01170 denc = rb_enc_name(enc);
01171 fptr->writeconv_asciicompat = rb_str_new2(senc);
01172 }
01173 else {
01174 senc = denc = "";
01175 fptr->writeconv_asciicompat = rb_str_new2(rb_enc_name(enc));
01176 }
01177 ecflags = fptr->encs.ecflags & (ECONV_ERROR_HANDLER_MASK|ECONV_STATEFUL_DECORATOR_MASK);
01178 ecopts = fptr->encs.ecopts;
01179 fptr->writeconv = rb_econv_open_opts(senc, denc, ecflags, ecopts);
01180 if (!fptr->writeconv)
01181 rb_exc_raise(rb_econv_open_exc(senc, denc, ecflags));
01182 }
01183 }
01184 }
01185 }
01186
01187
01188 struct binwrite_arg {
01189 rb_io_t *fptr;
01190 VALUE str;
01191 const char *ptr;
01192 long length;
01193 };
01194
01195 struct write_arg {
01196 VALUE io;
01197 VALUE str;
01198 int nosync;
01199 };
01200
01201 static VALUE
01202 io_binwrite_string(VALUE arg)
01203 {
01204 struct binwrite_arg *p = (struct binwrite_arg *)arg;
01205 long l = io_writable_length(p->fptr, p->length);
01206 return rb_write_internal2(p->fptr->fd, p->ptr, l);
01207 }
01208
01209 static long
01210 io_binwrite(VALUE str, const char *ptr, long len, rb_io_t *fptr, int nosync)
01211 {
01212 long n, r, offset = 0;
01213
01214
01215 rb_thread_check_ints();
01216
01217 if ((n = len) <= 0) return n;
01218 if (fptr->wbuf.ptr == NULL && !(!nosync && (fptr->mode & FMODE_SYNC))) {
01219 fptr->wbuf.off = 0;
01220 fptr->wbuf.len = 0;
01221 fptr->wbuf.capa = IO_WBUF_CAPA_MIN;
01222 fptr->wbuf.ptr = ALLOC_N(char, fptr->wbuf.capa);
01223 fptr->write_lock = rb_mutex_new();
01224 rb_mutex_allow_trap(fptr->write_lock, 1);
01225 }
01226 if ((!nosync && (fptr->mode & (FMODE_SYNC|FMODE_TTY))) ||
01227 (fptr->wbuf.ptr && fptr->wbuf.capa <= fptr->wbuf.len + len)) {
01228 struct binwrite_arg arg;
01229
01230
01231
01232
01233
01234
01235
01236 if (fptr->wbuf.len && fptr->wbuf.len+len <= fptr->wbuf.capa) {
01237 if (fptr->wbuf.capa < fptr->wbuf.off+fptr->wbuf.len+len) {
01238 MEMMOVE(fptr->wbuf.ptr, fptr->wbuf.ptr+fptr->wbuf.off, char, fptr->wbuf.len);
01239 fptr->wbuf.off = 0;
01240 }
01241 MEMMOVE(fptr->wbuf.ptr+fptr->wbuf.off+fptr->wbuf.len, ptr+offset, char, len);
01242 fptr->wbuf.len += (int)len;
01243 n = 0;
01244 }
01245 if (io_fflush(fptr) < 0)
01246 return -1L;
01247 if (n == 0)
01248 return len;
01249
01250 rb_io_check_closed(fptr);
01251 arg.fptr = fptr;
01252 arg.str = str;
01253 retry:
01254 arg.ptr = ptr + offset;
01255 arg.length = n;
01256 if (fptr->write_lock) {
01257 r = rb_mutex_synchronize(fptr->write_lock, io_binwrite_string, (VALUE)&arg);
01258 }
01259 else {
01260 long l = io_writable_length(fptr, n);
01261 r = rb_write_internal(fptr->fd, ptr+offset, l);
01262 }
01263
01264 if (r == n) return len;
01265 if (0 <= r) {
01266 offset += r;
01267 n -= r;
01268 errno = EAGAIN;
01269 }
01270 if (rb_io_wait_writable(fptr->fd)) {
01271 rb_io_check_closed(fptr);
01272 if (offset < len)
01273 goto retry;
01274 }
01275 return -1L;
01276 }
01277
01278 if (fptr->wbuf.off) {
01279 if (fptr->wbuf.len)
01280 MEMMOVE(fptr->wbuf.ptr, fptr->wbuf.ptr+fptr->wbuf.off, char, fptr->wbuf.len);
01281 fptr->wbuf.off = 0;
01282 }
01283 MEMMOVE(fptr->wbuf.ptr+fptr->wbuf.off+fptr->wbuf.len, ptr+offset, char, len);
01284 fptr->wbuf.len += (int)len;
01285 return len;
01286 }
01287
01288 # define MODE_BTMODE(a,b,c) ((fmode & FMODE_BINMODE) ? (b) : \
01289 (fmode & FMODE_TEXTMODE) ? (c) : (a))
01290 static VALUE
01291 do_writeconv(VALUE str, rb_io_t *fptr)
01292 {
01293 if (NEED_WRITECONV(fptr)) {
01294 VALUE common_encoding = Qnil;
01295 SET_BINARY_MODE(fptr);
01296
01297 make_writeconv(fptr);
01298
01299 if (fptr->writeconv) {
01300 #define fmode (fptr->mode)
01301 if (!NIL_P(fptr->writeconv_asciicompat))
01302 common_encoding = fptr->writeconv_asciicompat;
01303 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1) && !rb_enc_asciicompat(rb_enc_get(str))) {
01304 rb_raise(rb_eArgError, "ASCII incompatible string written for text mode IO without encoding conversion: %s",
01305 rb_enc_name(rb_enc_get(str)));
01306 }
01307 #undef fmode
01308 }
01309 else {
01310 if (fptr->encs.enc2)
01311 common_encoding = rb_enc_from_encoding(fptr->encs.enc2);
01312 else if (fptr->encs.enc != rb_ascii8bit_encoding())
01313 common_encoding = rb_enc_from_encoding(fptr->encs.enc);
01314 }
01315
01316 if (!NIL_P(common_encoding)) {
01317 str = rb_str_encode(str, common_encoding,
01318 fptr->writeconv_pre_ecflags, fptr->writeconv_pre_ecopts);
01319 }
01320
01321 if (fptr->writeconv) {
01322 str = rb_econv_str_convert(fptr->writeconv, str, ECONV_PARTIAL_INPUT);
01323 }
01324 }
01325 #if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)
01326 #define fmode (fptr->mode)
01327 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1)) {
01328 if ((fptr->mode & FMODE_READABLE) &&
01329 !(fptr->encs.ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
01330 setmode(fptr->fd, O_BINARY);
01331 }
01332 else {
01333 setmode(fptr->fd, O_TEXT);
01334 }
01335 if (!rb_enc_asciicompat(rb_enc_get(str))) {
01336 rb_raise(rb_eArgError, "ASCII incompatible string written for text mode IO without encoding conversion: %s",
01337 rb_enc_name(rb_enc_get(str)));
01338 }
01339 }
01340 #undef fmode
01341 #endif
01342 return str;
01343 }
01344
01345 static long
01346 io_fwrite(VALUE str, rb_io_t *fptr, int nosync)
01347 {
01348 #ifdef _WIN32
01349 if (fptr->mode & FMODE_TTY) {
01350 long len = rb_w32_write_console(str, fptr->fd);
01351 if (len > 0) return len;
01352 }
01353 #endif
01354 str = do_writeconv(str, fptr);
01355 return io_binwrite(str, RSTRING_PTR(str), RSTRING_LEN(str),
01356 fptr, nosync);
01357 }
01358
01359 ssize_t
01360 rb_io_bufwrite(VALUE io, const void *buf, size_t size)
01361 {
01362 rb_io_t *fptr;
01363
01364 GetOpenFile(io, fptr);
01365 rb_io_check_writable(fptr);
01366 return (ssize_t)io_binwrite(0, buf, (long)size, fptr, 0);
01367 }
01368
01369 static VALUE
01370 io_write(VALUE io, VALUE str, int nosync)
01371 {
01372 rb_io_t *fptr;
01373 long n;
01374 VALUE tmp;
01375
01376 rb_secure(4);
01377 io = GetWriteIO(io);
01378 str = rb_obj_as_string(str);
01379 tmp = rb_io_check_io(io);
01380 if (NIL_P(tmp)) {
01381
01382 return rb_funcall(io, id_write, 1, str);
01383 }
01384 io = tmp;
01385 if (RSTRING_LEN(str) == 0) return INT2FIX(0);
01386
01387 str = rb_str_new_frozen(str);
01388
01389 GetOpenFile(io, fptr);
01390 rb_io_check_writable(fptr);
01391
01392 n = io_fwrite(str, fptr, nosync);
01393 if (n == -1L) rb_sys_fail_path(fptr->pathv);
01394
01395 return LONG2FIX(n);
01396 }
01397
01398
01399
01400
01401
01402
01403
01404
01405
01406
01407
01408
01409
01410
01411
01412
01413
01414
01415
01416 static VALUE
01417 io_write_m(VALUE io, VALUE str)
01418 {
01419 return io_write(io, str, 0);
01420 }
01421
01422 VALUE
01423 rb_io_write(VALUE io, VALUE str)
01424 {
01425 return rb_funcall(io, id_write, 1, str);
01426 }
01427
01428
01429
01430
01431
01432
01433
01434
01435
01436
01437
01438
01439
01440
01441
01442
01443
01444 VALUE
01445 rb_io_addstr(VALUE io, VALUE str)
01446 {
01447 rb_io_write(io, str);
01448 return io;
01449 }
01450
01451 #ifdef HAVE_FSYNC
01452 static VALUE
01453 nogvl_fsync(void *ptr)
01454 {
01455 rb_io_t *fptr = ptr;
01456
01457 return (VALUE)fsync(fptr->fd);
01458 }
01459 #endif
01460
01461
01462
01463
01464
01465
01466
01467
01468
01469
01470
01471
01472
01473
01474
01475
01476
01477 VALUE
01478 rb_io_flush(VALUE io)
01479 {
01480 rb_io_t *fptr;
01481
01482 if (!RB_TYPE_P(io, T_FILE)) {
01483 return rb_funcall(io, id_flush, 0);
01484 }
01485
01486 io = GetWriteIO(io);
01487 GetOpenFile(io, fptr);
01488
01489 if (fptr->mode & FMODE_WRITABLE) {
01490 if (io_fflush(fptr) < 0)
01491 rb_sys_fail(0);
01492 #ifdef _WIN32
01493 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->fd)) == FILE_TYPE_DISK) {
01494 rb_thread_io_blocking_region(nogvl_fsync, fptr, fptr->fd);
01495 }
01496 #endif
01497 }
01498 if (fptr->mode & FMODE_READABLE) {
01499 io_unread(fptr);
01500 }
01501
01502 return io;
01503 }
01504
01505
01506
01507
01508
01509
01510
01511
01512
01513
01514
01515
01516
01517
01518 static VALUE
01519 rb_io_tell(VALUE io)
01520 {
01521 rb_io_t *fptr;
01522 off_t pos;
01523
01524 GetOpenFile(io, fptr);
01525 pos = io_tell(fptr);
01526 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
01527 pos -= fptr->rbuf.len;
01528 return OFFT2NUM(pos);
01529 }
01530
01531 static VALUE
01532 rb_io_seek(VALUE io, VALUE offset, int whence)
01533 {
01534 rb_io_t *fptr;
01535 off_t pos;
01536
01537 pos = NUM2OFFT(offset);
01538 GetOpenFile(io, fptr);
01539 pos = io_seek(fptr, pos, whence);
01540 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
01541
01542 return INT2FIX(0);
01543 }
01544
01545
01546
01547
01548
01549
01550
01551
01552
01553
01554
01555
01556
01557
01558
01559
01560
01561
01562
01563
01564
01565
01566 static VALUE
01567 rb_io_seek_m(int argc, VALUE *argv, VALUE io)
01568 {
01569 VALUE offset, ptrname;
01570 int whence = SEEK_SET;
01571
01572 if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
01573 whence = NUM2INT(ptrname);
01574 }
01575
01576 return rb_io_seek(io, offset, whence);
01577 }
01578
01579
01580
01581
01582
01583
01584
01585
01586
01587
01588
01589
01590
01591
01592 static VALUE
01593 rb_io_set_pos(VALUE io, VALUE offset)
01594 {
01595 rb_io_t *fptr;
01596 off_t pos;
01597
01598 pos = NUM2OFFT(offset);
01599 GetOpenFile(io, fptr);
01600 pos = io_seek(fptr, pos, SEEK_SET);
01601 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
01602
01603 return OFFT2NUM(pos);
01604 }
01605
01606 static void clear_readconv(rb_io_t *fptr);
01607
01608
01609
01610
01611
01612
01613
01614
01615
01616
01617
01618
01619
01620
01621
01622
01623
01624 static VALUE
01625 rb_io_rewind(VALUE io)
01626 {
01627 rb_io_t *fptr;
01628
01629 GetOpenFile(io, fptr);
01630 if (io_seek(fptr, 0L, 0) < 0 && errno) rb_sys_fail_path(fptr->pathv);
01631 #ifdef _WIN32
01632 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->fd)) == FILE_TYPE_DISK) {
01633 fsync(fptr->fd);
01634 }
01635 #endif
01636 if (io == ARGF.current_file) {
01637 ARGF.lineno -= fptr->lineno;
01638 }
01639 fptr->lineno = 0;
01640 if (fptr->readconv) {
01641 clear_readconv(fptr);
01642 }
01643
01644 return INT2FIX(0);
01645 }
01646
01647 static int
01648 io_fillbuf(rb_io_t *fptr)
01649 {
01650 ssize_t r;
01651
01652 if (fptr->rbuf.ptr == NULL) {
01653 fptr->rbuf.off = 0;
01654 fptr->rbuf.len = 0;
01655 fptr->rbuf.capa = IO_RBUF_CAPA_FOR(fptr);
01656 fptr->rbuf.ptr = ALLOC_N(char, fptr->rbuf.capa);
01657 #ifdef _WIN32
01658 fptr->rbuf.capa--;
01659 #endif
01660 }
01661 if (fptr->rbuf.len == 0) {
01662 retry:
01663 {
01664 r = rb_read_internal(fptr->fd, fptr->rbuf.ptr, fptr->rbuf.capa);
01665 }
01666 if (r < 0) {
01667 if (rb_io_wait_readable(fptr->fd))
01668 goto retry;
01669 rb_sys_fail_path(fptr->pathv);
01670 }
01671 fptr->rbuf.off = 0;
01672 fptr->rbuf.len = (int)r;
01673 if (r == 0)
01674 return -1;
01675 }
01676 return 0;
01677 }
01678
01679
01680
01681
01682
01683
01684
01685
01686
01687
01688
01689
01690
01691
01692
01693
01694
01695
01696
01697
01698
01699
01700
01701
01702
01703
01704
01705
01706
01707
01708
01709
01710
01711
01712
01713 VALUE
01714 rb_io_eof(VALUE io)
01715 {
01716 rb_io_t *fptr;
01717
01718 GetOpenFile(io, fptr);
01719 rb_io_check_char_readable(fptr);
01720
01721 if (READ_CHAR_PENDING(fptr)) return Qfalse;
01722 if (READ_DATA_PENDING(fptr)) return Qfalse;
01723 READ_CHECK(fptr);
01724 #if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)
01725 if (!NEED_READCONV(fptr) && NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
01726 return eof(fptr->fd) ? Qtrue : Qfalse;
01727 }
01728 #endif
01729 if (io_fillbuf(fptr) < 0) {
01730 return Qtrue;
01731 }
01732 return Qfalse;
01733 }
01734
01735
01736
01737
01738
01739
01740
01741
01742
01743
01744
01745
01746
01747
01748 static VALUE
01749 rb_io_sync(VALUE io)
01750 {
01751 rb_io_t *fptr;
01752
01753 io = GetWriteIO(io);
01754 GetOpenFile(io, fptr);
01755 return (fptr->mode & FMODE_SYNC) ? Qtrue : Qfalse;
01756 }
01757
01758 #ifdef HAVE_FSYNC
01759
01760
01761
01762
01763
01764
01765
01766
01767
01768
01769
01770
01771
01772
01773
01774
01775 static VALUE
01776 rb_io_set_sync(VALUE io, VALUE sync)
01777 {
01778 rb_io_t *fptr;
01779
01780 io = GetWriteIO(io);
01781 GetOpenFile(io, fptr);
01782 if (RTEST(sync)) {
01783 fptr->mode |= FMODE_SYNC;
01784 }
01785 else {
01786 fptr->mode &= ~FMODE_SYNC;
01787 }
01788 return sync;
01789 }
01790
01791
01792
01793
01794
01795
01796
01797
01798
01799
01800
01801
01802
01803
01804
01805 static VALUE
01806 rb_io_fsync(VALUE io)
01807 {
01808 rb_io_t *fptr;
01809
01810 io = GetWriteIO(io);
01811 GetOpenFile(io, fptr);
01812
01813 if (io_fflush(fptr) < 0)
01814 rb_sys_fail(0);
01815 # ifndef _WIN32
01816 if ((int)rb_thread_io_blocking_region(nogvl_fsync, fptr, fptr->fd) < 0)
01817 rb_sys_fail_path(fptr->pathv);
01818 # endif
01819 return INT2FIX(0);
01820 }
01821 #else
01822 # define rb_io_fsync rb_f_notimplement
01823 # define rb_io_sync rb_f_notimplement
01824 static VALUE
01825 rb_io_set_sync(VALUE io, VALUE sync)
01826 {
01827 rb_notimplement();
01828 UNREACHABLE;
01829 }
01830 #endif
01831
01832 #ifdef HAVE_FDATASYNC
01833 static VALUE
01834 nogvl_fdatasync(void *ptr)
01835 {
01836 rb_io_t *fptr = ptr;
01837
01838 return (VALUE)fdatasync(fptr->fd);
01839 }
01840
01841
01842
01843
01844
01845
01846
01847
01848
01849
01850
01851
01852 static VALUE
01853 rb_io_fdatasync(VALUE io)
01854 {
01855 rb_io_t *fptr;
01856
01857 io = GetWriteIO(io);
01858 GetOpenFile(io, fptr);
01859
01860 if (io_fflush(fptr) < 0)
01861 rb_sys_fail(0);
01862
01863 if ((int)rb_thread_io_blocking_region(nogvl_fdatasync, fptr, fptr->fd) == 0)
01864 return INT2FIX(0);
01865
01866
01867 return rb_io_fsync(io);
01868 }
01869 #else
01870 #define rb_io_fdatasync rb_io_fsync
01871 #endif
01872
01873
01874
01875
01876
01877
01878
01879
01880
01881
01882
01883
01884
01885 static VALUE
01886 rb_io_fileno(VALUE io)
01887 {
01888 rb_io_t *fptr = RFILE(io)->fptr;
01889 int fd;
01890
01891 rb_io_check_closed(fptr);
01892 fd = fptr->fd;
01893 return INT2FIX(fd);
01894 }
01895
01896
01897
01898
01899
01900
01901
01902
01903
01904
01905
01906
01907
01908
01909
01910
01911
01912
01913
01914
01915
01916
01917 static VALUE
01918 rb_io_pid(VALUE io)
01919 {
01920 rb_io_t *fptr;
01921
01922 GetOpenFile(io, fptr);
01923 if (!fptr->pid)
01924 return Qnil;
01925 return PIDT2NUM(fptr->pid);
01926 }
01927
01928
01929
01930
01931
01932
01933
01934
01935
01936 static VALUE
01937 rb_io_inspect(VALUE obj)
01938 {
01939 rb_io_t *fptr;
01940 VALUE result;
01941 static const char closed[] = " (closed)";
01942
01943 fptr = RFILE(taint_check(obj))->fptr;
01944 if (!fptr) return rb_any_to_s(obj);
01945 result = rb_str_new_cstr("#<");
01946 rb_str_append(result, rb_class_name(CLASS_OF(obj)));
01947 rb_str_cat2(result, ":");
01948 if (NIL_P(fptr->pathv)) {
01949 if (fptr->fd < 0) {
01950 rb_str_cat(result, closed+1, strlen(closed)-1);
01951 }
01952 else {
01953 rb_str_catf(result, "fd %d", fptr->fd);
01954 }
01955 }
01956 else {
01957 rb_str_append(result, fptr->pathv);
01958 if (fptr->fd < 0) {
01959 rb_str_cat(result, closed, strlen(closed));
01960 }
01961 }
01962 return rb_str_cat2(result, ">");
01963 }
01964
01965
01966
01967
01968
01969
01970
01971
01972 static VALUE
01973 rb_io_to_io(VALUE io)
01974 {
01975 return io;
01976 }
01977
01978
01979 static long
01980 read_buffered_data(char *ptr, long len, rb_io_t *fptr)
01981 {
01982 int n;
01983
01984 n = READ_DATA_PENDING_COUNT(fptr);
01985 if (n <= 0) return 0;
01986 if (n > len) n = (int)len;
01987 MEMMOVE(ptr, fptr->rbuf.ptr+fptr->rbuf.off, char, n);
01988 fptr->rbuf.off += n;
01989 fptr->rbuf.len -= n;
01990 return n;
01991 }
01992
01993 static long
01994 io_bufread(char *ptr, long len, rb_io_t *fptr)
01995 {
01996 long offset = 0;
01997 long n = len;
01998 long c;
01999
02000 if (READ_DATA_PENDING(fptr) == 0) {
02001 while (n > 0) {
02002 again:
02003 c = rb_read_internal(fptr->fd, ptr+offset, n);
02004 if (c == 0) break;
02005 if (c < 0) {
02006 if (rb_io_wait_readable(fptr->fd))
02007 goto again;
02008 return -1;
02009 }
02010 offset += c;
02011 if ((n -= c) <= 0) break;
02012 }
02013 return len - n;
02014 }
02015
02016 while (n > 0) {
02017 c = read_buffered_data(ptr+offset, n, fptr);
02018 if (c > 0) {
02019 offset += c;
02020 if ((n -= c) <= 0) break;
02021 }
02022 rb_io_check_closed(fptr);
02023 if (io_fillbuf(fptr) < 0) {
02024 break;
02025 }
02026 }
02027 return len - n;
02028 }
02029
02030 static void io_setstrbuf(VALUE *str, long len);
02031
02032 struct bufread_arg {
02033 char *str_ptr;
02034 long len;
02035 rb_io_t *fptr;
02036 };
02037
02038 static VALUE
02039 bufread_call(VALUE arg)
02040 {
02041 struct bufread_arg *p = (struct bufread_arg *)arg;
02042 p->len = io_bufread(p->str_ptr, p->len, p->fptr);
02043 return Qundef;
02044 }
02045
02046 static long
02047 io_fread(VALUE str, long offset, long size, rb_io_t *fptr)
02048 {
02049 long len;
02050 struct bufread_arg arg;
02051
02052 io_setstrbuf(&str, offset + size);
02053 arg.str_ptr = RSTRING_PTR(str) + offset;
02054 arg.len = size;
02055 arg.fptr = fptr;
02056 rb_str_locktmp_ensure(str, bufread_call, (VALUE)&arg);
02057 len = arg.len;
02058 if (len < 0) rb_sys_fail_path(fptr->pathv);
02059 return len;
02060 }
02061
02062 ssize_t
02063 rb_io_bufread(VALUE io, void *buf, size_t size)
02064 {
02065 rb_io_t *fptr;
02066
02067 GetOpenFile(io, fptr);
02068 rb_io_check_readable(fptr);
02069 return (ssize_t)io_bufread(buf, (long)size, fptr);
02070 }
02071
02072 #define SMALLBUF 100
02073
02074 static long
02075 remain_size(rb_io_t *fptr)
02076 {
02077 struct stat st;
02078 off_t siz = READ_DATA_PENDING_COUNT(fptr);
02079 off_t pos;
02080
02081 if (fstat(fptr->fd, &st) == 0 && S_ISREG(st.st_mode)
02082 #if defined(__BEOS__) || defined(__HAIKU__)
02083 && (st.st_dev > 3)
02084 #endif
02085 )
02086 {
02087 if (io_fflush(fptr) < 0)
02088 rb_sys_fail(0);
02089 pos = lseek(fptr->fd, 0, SEEK_CUR);
02090 if (st.st_size >= pos && pos >= 0) {
02091 siz += st.st_size - pos;
02092 if (siz > LONG_MAX) {
02093 rb_raise(rb_eIOError, "file too big for single read");
02094 }
02095 }
02096 }
02097 else {
02098 siz += BUFSIZ;
02099 }
02100 return (long)siz;
02101 }
02102
02103 static VALUE
02104 io_enc_str(VALUE str, rb_io_t *fptr)
02105 {
02106 OBJ_TAINT(str);
02107 rb_enc_associate(str, io_read_encoding(fptr));
02108 return str;
02109 }
02110
02111 static void
02112 make_readconv(rb_io_t *fptr, int size)
02113 {
02114 if (!fptr->readconv) {
02115 int ecflags;
02116 VALUE ecopts;
02117 const char *sname, *dname;
02118 ecflags = fptr->encs.ecflags & ~ECONV_NEWLINE_DECORATOR_WRITE_MASK;
02119 ecopts = fptr->encs.ecopts;
02120 if (fptr->encs.enc2) {
02121 sname = rb_enc_name(fptr->encs.enc2);
02122 dname = rb_enc_name(fptr->encs.enc);
02123 }
02124 else {
02125 sname = dname = "";
02126 }
02127 fptr->readconv = rb_econv_open_opts(sname, dname, ecflags, ecopts);
02128 if (!fptr->readconv)
02129 rb_exc_raise(rb_econv_open_exc(sname, dname, ecflags));
02130 fptr->cbuf.off = 0;
02131 fptr->cbuf.len = 0;
02132 if (size < IO_CBUF_CAPA_MIN) size = IO_CBUF_CAPA_MIN;
02133 fptr->cbuf.capa = size;
02134 fptr->cbuf.ptr = ALLOC_N(char, fptr->cbuf.capa);
02135 }
02136 }
02137
02138 #define MORE_CHAR_SUSPENDED Qtrue
02139 #define MORE_CHAR_FINISHED Qnil
02140 static VALUE
02141 fill_cbuf(rb_io_t *fptr, int ec_flags)
02142 {
02143 const unsigned char *ss, *sp, *se;
02144 unsigned char *ds, *dp, *de;
02145 rb_econv_result_t res;
02146 int putbackable;
02147 int cbuf_len0;
02148 VALUE exc;
02149
02150 ec_flags |= ECONV_PARTIAL_INPUT;
02151
02152 if (fptr->cbuf.len == fptr->cbuf.capa)
02153 return MORE_CHAR_SUSPENDED;
02154 if (fptr->cbuf.len == 0)
02155 fptr->cbuf.off = 0;
02156 else if (fptr->cbuf.off + fptr->cbuf.len == fptr->cbuf.capa) {
02157 memmove(fptr->cbuf.ptr, fptr->cbuf.ptr+fptr->cbuf.off, fptr->cbuf.len);
02158 fptr->cbuf.off = 0;
02159 }
02160
02161 cbuf_len0 = fptr->cbuf.len;
02162
02163 while (1) {
02164 ss = sp = (const unsigned char *)fptr->rbuf.ptr + fptr->rbuf.off;
02165 se = sp + fptr->rbuf.len;
02166 ds = dp = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.off + fptr->cbuf.len;
02167 de = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.capa;
02168 res = rb_econv_convert(fptr->readconv, &sp, se, &dp, de, ec_flags);
02169 fptr->rbuf.off += (int)(sp - ss);
02170 fptr->rbuf.len -= (int)(sp - ss);
02171 fptr->cbuf.len += (int)(dp - ds);
02172
02173 putbackable = rb_econv_putbackable(fptr->readconv);
02174 if (putbackable) {
02175 rb_econv_putback(fptr->readconv, (unsigned char *)fptr->rbuf.ptr + fptr->rbuf.off - putbackable, putbackable);
02176 fptr->rbuf.off -= putbackable;
02177 fptr->rbuf.len += putbackable;
02178 }
02179
02180 exc = rb_econv_make_exception(fptr->readconv);
02181 if (!NIL_P(exc))
02182 return exc;
02183
02184 if (cbuf_len0 != fptr->cbuf.len)
02185 return MORE_CHAR_SUSPENDED;
02186
02187 if (res == econv_finished) {
02188 return MORE_CHAR_FINISHED;
02189 }
02190
02191 if (res == econv_source_buffer_empty) {
02192 if (fptr->rbuf.len == 0) {
02193 READ_CHECK(fptr);
02194 if (io_fillbuf(fptr) == -1) {
02195 if (!fptr->readconv) {
02196 return MORE_CHAR_FINISHED;
02197 }
02198 ds = dp = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.off + fptr->cbuf.len;
02199 de = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.capa;
02200 res = rb_econv_convert(fptr->readconv, NULL, NULL, &dp, de, 0);
02201 fptr->cbuf.len += (int)(dp - ds);
02202 rb_econv_check_error(fptr->readconv);
02203 break;
02204 }
02205 }
02206 }
02207 }
02208 if (cbuf_len0 != fptr->cbuf.len)
02209 return MORE_CHAR_SUSPENDED;
02210
02211 return MORE_CHAR_FINISHED;
02212 }
02213
02214 static VALUE
02215 more_char(rb_io_t *fptr)
02216 {
02217 VALUE v;
02218 v = fill_cbuf(fptr, ECONV_AFTER_OUTPUT);
02219 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED)
02220 rb_exc_raise(v);
02221 return v;
02222 }
02223
02224 static VALUE
02225 io_shift_cbuf(rb_io_t *fptr, int len, VALUE *strp)
02226 {
02227 VALUE str = Qnil;
02228 if (strp) {
02229 str = *strp;
02230 if (NIL_P(str)) {
02231 *strp = str = rb_str_new(fptr->cbuf.ptr+fptr->cbuf.off, len);
02232 }
02233 else {
02234 rb_str_cat(str, fptr->cbuf.ptr+fptr->cbuf.off, len);
02235 }
02236 OBJ_TAINT(str);
02237 rb_enc_associate(str, fptr->encs.enc);
02238 }
02239 fptr->cbuf.off += len;
02240 fptr->cbuf.len -= len;
02241
02242 if (fptr->cbuf.len == 0)
02243 fptr->cbuf.off = 0;
02244 else if (fptr->cbuf.capa/2 < fptr->cbuf.off) {
02245 memmove(fptr->cbuf.ptr, fptr->cbuf.ptr+fptr->cbuf.off, fptr->cbuf.len);
02246 fptr->cbuf.off = 0;
02247 }
02248 return str;
02249 }
02250
02251 static void
02252 io_setstrbuf(VALUE *str, long len)
02253 {
02254 #ifdef _WIN32
02255 len = (len + 1) & ~1L;
02256 #endif
02257 if (NIL_P(*str)) {
02258 *str = rb_str_new(0, 0);
02259 }
02260 else {
02261 VALUE s = StringValue(*str);
02262 long clen = RSTRING_LEN(s);
02263 if (clen >= len) {
02264 rb_str_modify(s);
02265 return;
02266 }
02267 len -= clen;
02268 }
02269 rb_str_modify_expand(*str, len);
02270 }
02271
02272 static void
02273 io_set_read_length(VALUE str, long n)
02274 {
02275 if (RSTRING_LEN(str) != n) {
02276 rb_str_modify(str);
02277 rb_str_set_len(str, n);
02278 }
02279 }
02280
02281 static VALUE
02282 read_all(rb_io_t *fptr, long siz, VALUE str)
02283 {
02284 long bytes;
02285 long n;
02286 long pos;
02287 rb_encoding *enc;
02288 int cr;
02289
02290 if (NEED_READCONV(fptr)) {
02291 int first = !NIL_P(str);
02292 SET_BINARY_MODE(fptr);
02293 io_setstrbuf(&str,0);
02294 make_readconv(fptr, 0);
02295 while (1) {
02296 VALUE v;
02297 if (fptr->cbuf.len) {
02298 if (first) rb_str_set_len(str, first = 0);
02299 io_shift_cbuf(fptr, fptr->cbuf.len, &str);
02300 }
02301 v = fill_cbuf(fptr, 0);
02302 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED) {
02303 if (fptr->cbuf.len) {
02304 if (first) rb_str_set_len(str, first = 0);
02305 io_shift_cbuf(fptr, fptr->cbuf.len, &str);
02306 }
02307 rb_exc_raise(v);
02308 }
02309 if (v == MORE_CHAR_FINISHED) {
02310 clear_readconv(fptr);
02311 if (first) rb_str_set_len(str, first = 0);
02312 return io_enc_str(str, fptr);
02313 }
02314 }
02315 }
02316
02317 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
02318 bytes = 0;
02319 pos = 0;
02320
02321 enc = io_read_encoding(fptr);
02322 cr = 0;
02323
02324 if (siz == 0) siz = BUFSIZ;
02325 io_setstrbuf(&str,siz);
02326 for (;;) {
02327 READ_CHECK(fptr);
02328 n = io_fread(str, bytes, siz - bytes, fptr);
02329 if (n == 0 && bytes == 0) {
02330 rb_str_set_len(str, 0);
02331 break;
02332 }
02333 bytes += n;
02334 rb_str_set_len(str, bytes);
02335 if (cr != ENC_CODERANGE_BROKEN)
02336 pos += rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + bytes, enc, &cr);
02337 if (bytes < siz) break;
02338 siz += BUFSIZ;
02339 rb_str_modify_expand(str, BUFSIZ);
02340 }
02341 str = io_enc_str(str, fptr);
02342 ENC_CODERANGE_SET(str, cr);
02343 return str;
02344 }
02345
02346 void
02347 rb_io_set_nonblock(rb_io_t *fptr)
02348 {
02349 int oflags;
02350 #ifdef F_GETFL
02351 oflags = fcntl(fptr->fd, F_GETFL);
02352 if (oflags == -1) {
02353 rb_sys_fail_path(fptr->pathv);
02354 }
02355 #else
02356 oflags = 0;
02357 #endif
02358 if ((oflags & O_NONBLOCK) == 0) {
02359 oflags |= O_NONBLOCK;
02360 if (fcntl(fptr->fd, F_SETFL, oflags) == -1) {
02361 rb_sys_fail_path(fptr->pathv);
02362 }
02363 }
02364 }
02365
02366 struct read_internal_arg {
02367 int fd;
02368 char *str_ptr;
02369 long len;
02370 };
02371
02372 static VALUE
02373 read_internal_call(VALUE arg)
02374 {
02375 struct read_internal_arg *p = (struct read_internal_arg *)arg;
02376 p->len = rb_read_internal(p->fd, p->str_ptr, p->len);
02377 return Qundef;
02378 }
02379
02380 static VALUE
02381 io_getpartial(int argc, VALUE *argv, VALUE io, int nonblock)
02382 {
02383 rb_io_t *fptr;
02384 VALUE length, str;
02385 long n, len;
02386 struct read_internal_arg arg;
02387
02388 rb_scan_args(argc, argv, "11", &length, &str);
02389
02390 if ((len = NUM2LONG(length)) < 0) {
02391 rb_raise(rb_eArgError, "negative length %ld given", len);
02392 }
02393
02394 io_setstrbuf(&str,len);
02395 OBJ_TAINT(str);
02396
02397 GetOpenFile(io, fptr);
02398 rb_io_check_byte_readable(fptr);
02399
02400 if (len == 0)
02401 return str;
02402
02403 if (!nonblock)
02404 READ_CHECK(fptr);
02405 n = read_buffered_data(RSTRING_PTR(str), len, fptr);
02406 if (n <= 0) {
02407 again:
02408 if (nonblock) {
02409 rb_io_set_nonblock(fptr);
02410 }
02411 io_setstrbuf(&str, len);
02412 arg.fd = fptr->fd;
02413 arg.str_ptr = RSTRING_PTR(str);
02414 arg.len = len;
02415 rb_str_locktmp_ensure(str, read_internal_call, (VALUE)&arg);
02416 n = arg.len;
02417 if (n < 0) {
02418 if (!nonblock && rb_io_wait_readable(fptr->fd))
02419 goto again;
02420 if (nonblock && (errno == EWOULDBLOCK || errno == EAGAIN))
02421 rb_mod_sys_fail(rb_mWaitReadable, "read would block");
02422 rb_sys_fail_path(fptr->pathv);
02423 }
02424 }
02425 io_set_read_length(str, n);
02426
02427 if (n == 0)
02428 return Qnil;
02429 else
02430 return str;
02431 }
02432
02433
02434
02435
02436
02437
02438
02439
02440
02441
02442
02443
02444
02445
02446
02447
02448
02449
02450
02451
02452
02453
02454
02455
02456
02457
02458
02459
02460
02461
02462
02463
02464
02465
02466
02467
02468
02469
02470
02471
02472
02473
02474
02475
02476
02477
02478
02479
02480
02481
02482
02483
02484
02485
02486
02487
02488
02489
02490
02491
02492 static VALUE
02493 io_readpartial(int argc, VALUE *argv, VALUE io)
02494 {
02495 VALUE ret;
02496
02497 ret = io_getpartial(argc, argv, io, 0);
02498 if (NIL_P(ret))
02499 rb_eof_error();
02500 return ret;
02501 }
02502
02503
02504
02505
02506
02507
02508
02509
02510
02511
02512
02513
02514
02515
02516
02517
02518
02519
02520
02521
02522
02523
02524
02525
02526
02527
02528
02529
02530
02531
02532
02533
02534
02535
02536
02537
02538
02539
02540
02541
02542
02543
02544
02545
02546
02547
02548
02549
02550
02551
02552
02553
02554 static VALUE
02555 io_read_nonblock(int argc, VALUE *argv, VALUE io)
02556 {
02557 VALUE ret;
02558
02559 ret = io_getpartial(argc, argv, io, 1);
02560 if (NIL_P(ret))
02561 rb_eof_error();
02562 return ret;
02563 }
02564
02565
02566
02567
02568
02569
02570
02571
02572
02573
02574
02575
02576
02577
02578
02579
02580
02581
02582
02583
02584
02585
02586
02587
02588
02589
02590
02591
02592
02593
02594
02595
02596
02597
02598
02599
02600
02601
02602
02603
02604
02605
02606
02607
02608
02609
02610
02611
02612
02613
02614
02615
02616
02617
02618 static VALUE
02619 rb_io_write_nonblock(VALUE io, VALUE str)
02620 {
02621 rb_io_t *fptr;
02622 long n;
02623
02624 rb_secure(4);
02625 if (!RB_TYPE_P(str, T_STRING))
02626 str = rb_obj_as_string(str);
02627
02628 io = GetWriteIO(io);
02629 GetOpenFile(io, fptr);
02630 rb_io_check_writable(fptr);
02631
02632 if (io_fflush(fptr) < 0)
02633 rb_sys_fail(0);
02634
02635 rb_io_set_nonblock(fptr);
02636 n = write(fptr->fd, RSTRING_PTR(str), RSTRING_LEN(str));
02637
02638 if (n == -1) {
02639 if (errno == EWOULDBLOCK || errno == EAGAIN)
02640 rb_mod_sys_fail(rb_mWaitWritable, "write would block");
02641 rb_sys_fail_path(fptr->pathv);
02642 }
02643
02644 return LONG2FIX(n);
02645 }
02646
02647
02648
02649
02650
02651
02652
02653
02654
02655
02656
02657
02658
02659
02660
02661
02662
02663
02664
02665
02666
02667
02668
02669
02670
02671
02672
02673
02674
02675
02676
02677
02678
02679
02680
02681
02682
02683
02684
02685
02686
02687
02688
02689
02690
02691
02692
02693
02694
02695
02696
02697
02698
02699
02700
02701
02702
02703
02704
02705
02706
02707
02708
02709
02710
02711
02712
02713 static VALUE
02714 io_read(int argc, VALUE *argv, VALUE io)
02715 {
02716 rb_io_t *fptr;
02717 long n, len;
02718 VALUE length, str;
02719 #if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)
02720 int previous_mode;
02721 #endif
02722
02723 rb_scan_args(argc, argv, "02", &length, &str);
02724
02725 if (NIL_P(length)) {
02726 GetOpenFile(io, fptr);
02727 rb_io_check_char_readable(fptr);
02728 return read_all(fptr, remain_size(fptr), str);
02729 }
02730 len = NUM2LONG(length);
02731 if (len < 0) {
02732 rb_raise(rb_eArgError, "negative length %ld given", len);
02733 }
02734
02735 io_setstrbuf(&str,len);
02736
02737 GetOpenFile(io, fptr);
02738 rb_io_check_byte_readable(fptr);
02739 if (len == 0) {
02740 io_set_read_length(str, 0);
02741 return str;
02742 }
02743
02744 READ_CHECK(fptr);
02745 #if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)
02746 previous_mode = set_binary_mode_with_seek_cur(fptr);
02747 #endif
02748 n = io_fread(str, 0, len, fptr);
02749 io_set_read_length(str, n);
02750 #if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)
02751 if (previous_mode == O_TEXT) {
02752 setmode(fptr->fd, O_TEXT);
02753 }
02754 #endif
02755 if (n == 0) return Qnil;
02756 OBJ_TAINT(str);
02757
02758 return str;
02759 }
02760
02761 static void
02762 rscheck(const char *rsptr, long rslen, VALUE rs)
02763 {
02764 if (!rs) return;
02765 if (RSTRING_PTR(rs) != rsptr && RSTRING_LEN(rs) != rslen)
02766 rb_raise(rb_eRuntimeError, "rs modified");
02767 }
02768
02769 static int
02770 appendline(rb_io_t *fptr, int delim, VALUE *strp, long *lp)
02771 {
02772 VALUE str = *strp;
02773 long limit = *lp;
02774
02775 if (NEED_READCONV(fptr)) {
02776 SET_BINARY_MODE(fptr);
02777 make_readconv(fptr, 0);
02778 do {
02779 const char *p, *e;
02780 int searchlen;
02781 if (fptr->cbuf.len) {
02782 p = fptr->cbuf.ptr+fptr->cbuf.off;
02783 searchlen = fptr->cbuf.len;
02784 if (0 < limit && limit < searchlen)
02785 searchlen = (int)limit;
02786 e = memchr(p, delim, searchlen);
02787 if (e) {
02788 int len = (int)(e-p+1);
02789 if (NIL_P(str))
02790 *strp = str = rb_str_new(p, len);
02791 else
02792 rb_str_buf_cat(str, p, len);
02793 fptr->cbuf.off += len;
02794 fptr->cbuf.len -= len;
02795 limit -= len;
02796 *lp = limit;
02797 return delim;
02798 }
02799
02800 if (NIL_P(str))
02801 *strp = str = rb_str_new(p, searchlen);
02802 else
02803 rb_str_buf_cat(str, p, searchlen);
02804 fptr->cbuf.off += searchlen;
02805 fptr->cbuf.len -= searchlen;
02806 limit -= searchlen;
02807
02808 if (limit == 0) {
02809 *lp = limit;
02810 return (unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
02811 }
02812 }
02813 } while (more_char(fptr) != MORE_CHAR_FINISHED);
02814 clear_readconv(fptr);
02815 *lp = limit;
02816 return EOF;
02817 }
02818
02819 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
02820 do {
02821 long pending = READ_DATA_PENDING_COUNT(fptr);
02822 if (pending > 0) {
02823 const char *p = READ_DATA_PENDING_PTR(fptr);
02824 const char *e;
02825 long last;
02826
02827 if (limit > 0 && pending > limit) pending = limit;
02828 e = memchr(p, delim, pending);
02829 if (e) pending = e - p + 1;
02830 if (!NIL_P(str)) {
02831 last = RSTRING_LEN(str);
02832 rb_str_resize(str, last + pending);
02833 }
02834 else {
02835 last = 0;
02836 *strp = str = rb_str_buf_new(pending);
02837 rb_str_set_len(str, pending);
02838 }
02839 read_buffered_data(RSTRING_PTR(str) + last, pending, fptr);
02840 limit -= pending;
02841 *lp = limit;
02842 if (e) return delim;
02843 if (limit == 0)
02844 return (unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
02845 }
02846 READ_CHECK(fptr);
02847 } while (io_fillbuf(fptr) >= 0);
02848 *lp = limit;
02849 return EOF;
02850 }
02851
02852 static inline int
02853 swallow(rb_io_t *fptr, int term)
02854 {
02855 if (NEED_READCONV(fptr)) {
02856 rb_encoding *enc = io_read_encoding(fptr);
02857 int needconv = rb_enc_mbminlen(enc) != 1;
02858 SET_BINARY_MODE(fptr);
02859 make_readconv(fptr, 0);
02860 do {
02861 size_t cnt;
02862 while ((cnt = READ_CHAR_PENDING_COUNT(fptr)) > 0) {
02863 const char *p = READ_CHAR_PENDING_PTR(fptr);
02864 int i;
02865 if (!needconv) {
02866 if (*p != term) return TRUE;
02867 i = (int)cnt;
02868 while (--i && *++p == term);
02869 }
02870 else {
02871 const char *e = p + cnt;
02872 if (rb_enc_ascget(p, e, &i, enc) != term) return TRUE;
02873 while ((p += i) < e && rb_enc_ascget(p, e, &i, enc) == term);
02874 i = (int)(e - p);
02875 }
02876 io_shift_cbuf(fptr, (int)cnt - i, NULL);
02877 }
02878 } while (more_char(fptr) != MORE_CHAR_FINISHED);
02879 return FALSE;
02880 }
02881
02882 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
02883 do {
02884 size_t cnt;
02885 while ((cnt = READ_DATA_PENDING_COUNT(fptr)) > 0) {
02886 char buf[1024];
02887 const char *p = READ_DATA_PENDING_PTR(fptr);
02888 int i;
02889 if (cnt > sizeof buf) cnt = sizeof buf;
02890 if (*p != term) return TRUE;
02891 i = (int)cnt;
02892 while (--i && *++p == term);
02893 if (!read_buffered_data(buf, cnt - i, fptr))
02894 rb_sys_fail_path(fptr->pathv);
02895 }
02896 READ_CHECK(fptr);
02897 } while (io_fillbuf(fptr) == 0);
02898 return FALSE;
02899 }
02900
02901 static VALUE
02902 rb_io_getline_fast(rb_io_t *fptr, rb_encoding *enc, VALUE io)
02903 {
02904 VALUE str = Qnil;
02905 int len = 0;
02906 long pos = 0;
02907 int cr = 0;
02908
02909 for (;;) {
02910 int pending = READ_DATA_PENDING_COUNT(fptr);
02911
02912 if (pending > 0) {
02913 const char *p = READ_DATA_PENDING_PTR(fptr);
02914 const char *e;
02915
02916 e = memchr(p, '\n', pending);
02917 if (e) {
02918 pending = (int)(e - p + 1);
02919 }
02920 if (NIL_P(str)) {
02921 str = rb_str_new(p, pending);
02922 fptr->rbuf.off += pending;
02923 fptr->rbuf.len -= pending;
02924 }
02925 else {
02926 rb_str_resize(str, len + pending);
02927 read_buffered_data(RSTRING_PTR(str)+len, pending, fptr);
02928 }
02929 len += pending;
02930 if (cr != ENC_CODERANGE_BROKEN)
02931 pos += rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + len, enc, &cr);
02932 if (e) break;
02933 }
02934 READ_CHECK(fptr);
02935 if (io_fillbuf(fptr) < 0) {
02936 if (NIL_P(str)) return Qnil;
02937 break;
02938 }
02939 }
02940
02941 str = io_enc_str(str, fptr);
02942 ENC_CODERANGE_SET(str, cr);
02943 fptr->lineno++;
02944 if (io == ARGF.current_file) {
02945 ARGF.lineno++;
02946 ARGF.last_lineno = ARGF.lineno;
02947 }
02948 else {
02949 ARGF.last_lineno = fptr->lineno;
02950 }
02951
02952 return str;
02953 }
02954
02955 static void
02956 prepare_getline_args(int argc, VALUE *argv, VALUE *rsp, long *limit, VALUE io)
02957 {
02958 VALUE rs = rb_rs, lim = Qnil;
02959 rb_io_t *fptr;
02960
02961 if (argc == 1) {
02962 VALUE tmp = Qnil;
02963
02964 if (NIL_P(argv[0]) || !NIL_P(tmp = rb_check_string_type(argv[0]))) {
02965 rs = tmp;
02966 }
02967 else {
02968 lim = argv[0];
02969 }
02970 }
02971 else if (2 <= argc) {
02972 rb_scan_args(argc, argv, "2", &rs, &lim);
02973 if (!NIL_P(rs))
02974 StringValue(rs);
02975 }
02976 if (!NIL_P(rs)) {
02977 rb_encoding *enc_rs, *enc_io;
02978
02979 GetOpenFile(io, fptr);
02980 enc_rs = rb_enc_get(rs);
02981 enc_io = io_read_encoding(fptr);
02982 if (enc_io != enc_rs &&
02983 (rb_enc_str_coderange(rs) != ENC_CODERANGE_7BIT ||
02984 (RSTRING_LEN(rs) > 0 && !rb_enc_asciicompat(enc_io)))) {
02985 if (rs == rb_default_rs) {
02986 rs = rb_enc_str_new(0, 0, enc_io);
02987 rb_str_buf_cat_ascii(rs, "\n");
02988 }
02989 else {
02990 rb_raise(rb_eArgError, "encoding mismatch: %s IO with %s RS",
02991 rb_enc_name(enc_io),
02992 rb_enc_name(enc_rs));
02993 }
02994 }
02995 }
02996 *rsp = rs;
02997 *limit = NIL_P(lim) ? -1L : NUM2LONG(lim);
02998 }
02999
03000 static VALUE
03001 rb_io_getline_1(VALUE rs, long limit, VALUE io)
03002 {
03003 VALUE str = Qnil;
03004 rb_io_t *fptr;
03005 int nolimit = 0;
03006 rb_encoding *enc;
03007
03008 GetOpenFile(io, fptr);
03009 rb_io_check_char_readable(fptr);
03010 if (NIL_P(rs) && limit < 0) {
03011 str = read_all(fptr, 0, Qnil);
03012 if (RSTRING_LEN(str) == 0) return Qnil;
03013 }
03014 else if (limit == 0) {
03015 return rb_enc_str_new(0, 0, io_read_encoding(fptr));
03016 }
03017 else if (rs == rb_default_rs && limit < 0 && !NEED_READCONV(fptr) &&
03018 rb_enc_asciicompat(enc = io_read_encoding(fptr))) {
03019 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
03020 return rb_io_getline_fast(fptr, enc, io);
03021 }
03022 else {
03023 int c, newline = -1;
03024 const char *rsptr = 0;
03025 long rslen = 0;
03026 int rspara = 0;
03027 int extra_limit = 16;
03028
03029 SET_BINARY_MODE(fptr);
03030 enc = io_read_encoding(fptr);
03031
03032 if (!NIL_P(rs)) {
03033 rslen = RSTRING_LEN(rs);
03034 if (rslen == 0) {
03035 rsptr = "\n\n";
03036 rslen = 2;
03037 rspara = 1;
03038 swallow(fptr, '\n');
03039 rs = 0;
03040 if (!rb_enc_asciicompat(enc)) {
03041 rs = rb_usascii_str_new(rsptr, rslen);
03042 rs = rb_str_encode(rs, rb_enc_from_encoding(enc), 0, Qnil);
03043 OBJ_FREEZE(rs);
03044 rsptr = RSTRING_PTR(rs);
03045 rslen = RSTRING_LEN(rs);
03046 }
03047 }
03048 else {
03049 rsptr = RSTRING_PTR(rs);
03050 }
03051 newline = (unsigned char)rsptr[rslen - 1];
03052 }
03053
03054
03055 while ((c = appendline(fptr, newline, &str, &limit)) != EOF) {
03056 const char *s, *p, *pp, *e;
03057
03058 if (c == newline) {
03059 if (RSTRING_LEN(str) < rslen) continue;
03060 s = RSTRING_PTR(str);
03061 e = s + RSTRING_LEN(str);
03062 p = e - rslen;
03063 pp = rb_enc_left_char_head(s, p, e, enc);
03064 if (pp != p) continue;
03065 if (!rspara) rscheck(rsptr, rslen, rs);
03066 if (memcmp(p, rsptr, rslen) == 0) break;
03067 }
03068 if (limit == 0) {
03069 s = RSTRING_PTR(str);
03070 p = s + RSTRING_LEN(str);
03071 pp = rb_enc_left_char_head(s, p-1, p, enc);
03072 if (extra_limit &&
03073 MBCLEN_NEEDMORE_P(rb_enc_precise_mbclen(pp, p, enc))) {
03074
03075
03076 limit = 1;
03077 extra_limit--;
03078 }
03079 else {
03080 nolimit = 1;
03081 break;
03082 }
03083 }
03084 }
03085
03086 if (rspara) {
03087 if (c != EOF) {
03088 swallow(fptr, '\n');
03089 }
03090 }
03091 if (!NIL_P(str))
03092 str = io_enc_str(str, fptr);
03093 }
03094
03095 if (!NIL_P(str)) {
03096 if (!nolimit) {
03097 fptr->lineno++;
03098 if (io == ARGF.current_file) {
03099 ARGF.lineno++;
03100 ARGF.last_lineno = ARGF.lineno;
03101 }
03102 else {
03103 ARGF.last_lineno = fptr->lineno;
03104 }
03105 }
03106 }
03107
03108 return str;
03109 }
03110
03111 static VALUE
03112 rb_io_getline(int argc, VALUE *argv, VALUE io)
03113 {
03114 VALUE rs;
03115 long limit;
03116
03117 prepare_getline_args(argc, argv, &rs, &limit, io);
03118 return rb_io_getline_1(rs, limit, io);
03119 }
03120
03121 VALUE
03122 rb_io_gets(VALUE io)
03123 {
03124 return rb_io_getline_1(rb_default_rs, -1, io);
03125 }
03126
03127
03128
03129
03130
03131
03132
03133
03134
03135
03136
03137
03138
03139
03140
03141
03142
03143
03144
03145
03146
03147
03148 static VALUE
03149 rb_io_gets_m(int argc, VALUE *argv, VALUE io)
03150 {
03151 VALUE str;
03152
03153 str = rb_io_getline(argc, argv, io);
03154 rb_lastline_set(str);
03155
03156 return str;
03157 }
03158
03159
03160
03161
03162
03163
03164
03165
03166
03167
03168
03169
03170
03171
03172
03173
03174
03175
03176
03177
03178
03179
03180
03181 static VALUE
03182 rb_io_lineno(VALUE io)
03183 {
03184 rb_io_t *fptr;
03185
03186 GetOpenFile(io, fptr);
03187 rb_io_check_char_readable(fptr);
03188 return INT2NUM(fptr->lineno);
03189 }
03190
03191
03192
03193
03194
03195
03196
03197
03198
03199
03200
03201
03202
03203
03204
03205
03206
03207
03208 static VALUE
03209 rb_io_set_lineno(VALUE io, VALUE lineno)
03210 {
03211 rb_io_t *fptr;
03212
03213 GetOpenFile(io, fptr);
03214 rb_io_check_char_readable(fptr);
03215 fptr->lineno = NUM2INT(lineno);
03216 return lineno;
03217 }
03218
03219
03220
03221
03222
03223
03224
03225
03226
03227
03228
03229 static VALUE
03230 rb_io_readline(int argc, VALUE *argv, VALUE io)
03231 {
03232 VALUE line = rb_io_gets_m(argc, argv, io);
03233
03234 if (NIL_P(line)) {
03235 rb_eof_error();
03236 }
03237 return line;
03238 }
03239
03240
03241
03242
03243
03244
03245
03246
03247
03248
03249
03250
03251
03252
03253
03254
03255
03256
03257
03258 static VALUE
03259 rb_io_readlines(int argc, VALUE *argv, VALUE io)
03260 {
03261 VALUE line, ary, rs;
03262 long limit;
03263
03264 prepare_getline_args(argc, argv, &rs, &limit, io);
03265 if (limit == 0)
03266 rb_raise(rb_eArgError, "invalid limit: 0 for readlines");
03267 ary = rb_ary_new();
03268 while (!NIL_P(line = rb_io_getline_1(rs, limit, io))) {
03269 rb_ary_push(ary, line);
03270 }
03271 return ary;
03272 }
03273
03274
03275
03276
03277
03278
03279
03280
03281
03282
03283
03284
03285
03286
03287
03288
03289
03290
03291
03292
03293
03294
03295
03296
03297
03298
03299
03300
03301
03302
03303 static VALUE
03304 rb_io_each_line(int argc, VALUE *argv, VALUE io)
03305 {
03306 VALUE str, rs;
03307 long limit;
03308
03309 RETURN_ENUMERATOR(io, argc, argv);
03310 prepare_getline_args(argc, argv, &rs, &limit, io);
03311 if (limit == 0)
03312 rb_raise(rb_eArgError, "invalid limit: 0 for each_line");
03313 while (!NIL_P(str = rb_io_getline_1(rs, limit, io))) {
03314 rb_yield(str);
03315 }
03316 return io;
03317 }
03318
03319
03320
03321
03322
03323 static VALUE
03324 rb_io_lines(int argc, VALUE *argv, VALUE io)
03325 {
03326 rb_warn("IO#lines is deprecated; use #each_line instead");
03327 if (!rb_block_given_p())
03328 return rb_enumeratorize(io, ID2SYM(rb_intern("each_line")), argc, argv);
03329 return rb_io_each_line(argc, argv, io);
03330 }
03331
03332
03333
03334
03335
03336
03337
03338
03339
03340
03341
03342
03343
03344
03345
03346
03347
03348
03349 static VALUE
03350 rb_io_each_byte(VALUE io)
03351 {
03352 rb_io_t *fptr;
03353
03354 RETURN_ENUMERATOR(io, 0, 0);
03355 GetOpenFile(io, fptr);
03356
03357 for (;;) {
03358 while (fptr->rbuf.len > 0) {
03359 char *p = fptr->rbuf.ptr + fptr->rbuf.off++;
03360 fptr->rbuf.len--;
03361 rb_yield(INT2FIX(*p & 0xff));
03362 errno = 0;
03363 }
03364 rb_io_check_byte_readable(fptr);
03365 READ_CHECK(fptr);
03366 if (io_fillbuf(fptr) < 0) {
03367 break;
03368 }
03369 }
03370 return io;
03371 }
03372
03373
03374
03375
03376
03377 static VALUE
03378 rb_io_bytes(VALUE io)
03379 {
03380 rb_warn("IO#bytes is deprecated; use #each_byte instead");
03381 if (!rb_block_given_p())
03382 return rb_enumeratorize(io, ID2SYM(rb_intern("each_byte")), 0, 0);
03383 return rb_io_each_byte(io);
03384 }
03385
03386 static VALUE
03387 io_getc(rb_io_t *fptr, rb_encoding *enc)
03388 {
03389 int r, n, cr = 0;
03390 VALUE str;
03391
03392 if (NEED_READCONV(fptr)) {
03393 VALUE str = Qnil;
03394 rb_encoding *read_enc = io_read_encoding(fptr);
03395
03396 SET_BINARY_MODE(fptr);
03397 make_readconv(fptr, 0);
03398
03399 while (1) {
03400 if (fptr->cbuf.len) {
03401 r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
03402 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
03403 read_enc);
03404 if (!MBCLEN_NEEDMORE_P(r))
03405 break;
03406 if (fptr->cbuf.len == fptr->cbuf.capa) {
03407 rb_raise(rb_eIOError, "too long character");
03408 }
03409 }
03410
03411 if (more_char(fptr) == MORE_CHAR_FINISHED) {
03412 if (fptr->cbuf.len == 0) {
03413 clear_readconv(fptr);
03414 return Qnil;
03415 }
03416
03417 str = rb_enc_str_new(fptr->cbuf.ptr+fptr->cbuf.off, 1, read_enc);
03418 fptr->cbuf.off += 1;
03419 fptr->cbuf.len -= 1;
03420 if (fptr->cbuf.len == 0) clear_readconv(fptr);
03421 ENC_CODERANGE_SET(str, ENC_CODERANGE_BROKEN);
03422 return str;
03423 }
03424 }
03425 if (MBCLEN_INVALID_P(r)) {
03426 r = rb_enc_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
03427 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
03428 read_enc);
03429 io_shift_cbuf(fptr, r, &str);
03430 cr = ENC_CODERANGE_BROKEN;
03431 }
03432 else {
03433 io_shift_cbuf(fptr, MBCLEN_CHARFOUND_LEN(r), &str);
03434 cr = ENC_CODERANGE_VALID;
03435 if (MBCLEN_CHARFOUND_LEN(r) == 1 && rb_enc_asciicompat(read_enc) &&
03436 ISASCII(RSTRING_PTR(str)[0])) {
03437 cr = ENC_CODERANGE_7BIT;
03438 }
03439 }
03440 str = io_enc_str(str, fptr);
03441 ENC_CODERANGE_SET(str, cr);
03442 return str;
03443 }
03444
03445 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
03446 if (io_fillbuf(fptr) < 0) {
03447 return Qnil;
03448 }
03449 if (rb_enc_asciicompat(enc) && ISASCII(fptr->rbuf.ptr[fptr->rbuf.off])) {
03450 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, 1);
03451 fptr->rbuf.off += 1;
03452 fptr->rbuf.len -= 1;
03453 cr = ENC_CODERANGE_7BIT;
03454 }
03455 else {
03456 r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off, fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
03457 if (MBCLEN_CHARFOUND_P(r) &&
03458 (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
03459 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, n);
03460 fptr->rbuf.off += n;
03461 fptr->rbuf.len -= n;
03462 cr = ENC_CODERANGE_VALID;
03463 }
03464 else if (MBCLEN_NEEDMORE_P(r)) {
03465 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, fptr->rbuf.len);
03466 fptr->rbuf.len = 0;
03467 getc_needmore:
03468 if (io_fillbuf(fptr) != -1) {
03469 rb_str_cat(str, fptr->rbuf.ptr+fptr->rbuf.off, 1);
03470 fptr->rbuf.off++;
03471 fptr->rbuf.len--;
03472 r = rb_enc_precise_mbclen(RSTRING_PTR(str), RSTRING_PTR(str)+RSTRING_LEN(str), enc);
03473 if (MBCLEN_NEEDMORE_P(r)) {
03474 goto getc_needmore;
03475 }
03476 else if (MBCLEN_CHARFOUND_P(r)) {
03477 cr = ENC_CODERANGE_VALID;
03478 }
03479 }
03480 }
03481 else {
03482 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, 1);
03483 fptr->rbuf.off++;
03484 fptr->rbuf.len--;
03485 }
03486 }
03487 if (!cr) cr = ENC_CODERANGE_BROKEN;
03488 str = io_enc_str(str, fptr);
03489 ENC_CODERANGE_SET(str, cr);
03490 return str;
03491 }
03492
03493
03494
03495
03496
03497
03498
03499
03500
03501
03502
03503
03504
03505
03506
03507
03508 static VALUE
03509 rb_io_each_char(VALUE io)
03510 {
03511 rb_io_t *fptr;
03512 rb_encoding *enc;
03513 VALUE c;
03514
03515 RETURN_ENUMERATOR(io, 0, 0);
03516 GetOpenFile(io, fptr);
03517 rb_io_check_char_readable(fptr);
03518
03519 enc = io_input_encoding(fptr);
03520 READ_CHECK(fptr);
03521 while (!NIL_P(c = io_getc(fptr, enc))) {
03522 rb_yield(c);
03523 }
03524 return io;
03525 }
03526
03527
03528
03529
03530
03531 static VALUE
03532 rb_io_chars(VALUE io)
03533 {
03534 rb_warn("IO#chars is deprecated; use #each_char instead");
03535 if (!rb_block_given_p())
03536 return rb_enumeratorize(io, ID2SYM(rb_intern("each_char")), 0, 0);
03537 return rb_io_each_char(io);
03538 }
03539
03540
03541
03542
03543
03544
03545
03546
03547
03548
03549
03550
03551
03552
03553
03554
03555
03556 static VALUE
03557 rb_io_each_codepoint(VALUE io)
03558 {
03559 rb_io_t *fptr;
03560 rb_encoding *enc;
03561 unsigned int c;
03562 int r, n;
03563
03564 RETURN_ENUMERATOR(io, 0, 0);
03565 GetOpenFile(io, fptr);
03566 rb_io_check_char_readable(fptr);
03567
03568 READ_CHECK(fptr);
03569 if (NEED_READCONV(fptr)) {
03570 SET_BINARY_MODE(fptr);
03571 for (;;) {
03572 make_readconv(fptr, 0);
03573 for (;;) {
03574 if (fptr->cbuf.len) {
03575 if (fptr->encs.enc)
03576 r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
03577 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
03578 fptr->encs.enc);
03579 else
03580 r = ONIGENC_CONSTRUCT_MBCLEN_CHARFOUND(1);
03581 if (!MBCLEN_NEEDMORE_P(r))
03582 break;
03583 if (fptr->cbuf.len == fptr->cbuf.capa) {
03584 rb_raise(rb_eIOError, "too long character");
03585 }
03586 }
03587 if (more_char(fptr) == MORE_CHAR_FINISHED) {
03588 clear_readconv(fptr);
03589
03590 return io;
03591 }
03592 }
03593 if (MBCLEN_INVALID_P(r)) {
03594 rb_raise(rb_eArgError, "invalid byte sequence in %s",
03595 rb_enc_name(fptr->encs.enc));
03596 }
03597 n = MBCLEN_CHARFOUND_LEN(r);
03598 if (fptr->encs.enc) {
03599 c = rb_enc_codepoint(fptr->cbuf.ptr+fptr->cbuf.off,
03600 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
03601 fptr->encs.enc);
03602 }
03603 else {
03604 c = (unsigned char)fptr->cbuf.ptr[fptr->cbuf.off];
03605 }
03606 fptr->cbuf.off += n;
03607 fptr->cbuf.len -= n;
03608 rb_yield(UINT2NUM(c));
03609 }
03610 }
03611 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
03612 enc = io_input_encoding(fptr);
03613 for (;;) {
03614 if (io_fillbuf(fptr) < 0) {
03615 return io;
03616 }
03617 r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off,
03618 fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
03619 if (MBCLEN_CHARFOUND_P(r) &&
03620 (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
03621 c = rb_enc_codepoint(fptr->rbuf.ptr+fptr->rbuf.off,
03622 fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
03623 fptr->rbuf.off += n;
03624 fptr->rbuf.len -= n;
03625 rb_yield(UINT2NUM(c));
03626 }
03627 else if (MBCLEN_INVALID_P(r)) {
03628 rb_raise(rb_eArgError, "invalid byte sequence in %s", rb_enc_name(enc));
03629 }
03630 else {
03631 continue;
03632 }
03633 }
03634 return io;
03635 }
03636
03637
03638
03639
03640
03641 static VALUE
03642 rb_io_codepoints(VALUE io)
03643 {
03644 rb_warn("IO#codepoints is deprecated; use #each_codepoint instead");
03645 if (!rb_block_given_p())
03646 return rb_enumeratorize(io, ID2SYM(rb_intern("each_codepoint")), 0, 0);
03647 return rb_io_each_codepoint(io);
03648 }
03649
03650
03651
03652
03653
03654
03655
03656
03657
03658
03659
03660
03661
03662
03663 static VALUE
03664 rb_io_getc(VALUE io)
03665 {
03666 rb_io_t *fptr;
03667 rb_encoding *enc;
03668
03669 GetOpenFile(io, fptr);
03670 rb_io_check_char_readable(fptr);
03671
03672 enc = io_input_encoding(fptr);
03673 READ_CHECK(fptr);
03674 return io_getc(fptr, enc);
03675 }
03676
03677
03678
03679
03680
03681
03682
03683
03684
03685
03686
03687
03688
03689 static VALUE
03690 rb_io_readchar(VALUE io)
03691 {
03692 VALUE c = rb_io_getc(io);
03693
03694 if (NIL_P(c)) {
03695 rb_eof_error();
03696 }
03697 return c;
03698 }
03699
03700
03701
03702
03703
03704
03705
03706
03707
03708
03709
03710
03711
03712 VALUE
03713 rb_io_getbyte(VALUE io)
03714 {
03715 rb_io_t *fptr;
03716 int c;
03717
03718 GetOpenFile(io, fptr);
03719 rb_io_check_byte_readable(fptr);
03720 READ_CHECK(fptr);
03721 if (fptr->fd == 0 && (fptr->mode & FMODE_TTY) && RB_TYPE_P(rb_stdout, T_FILE)) {
03722 rb_io_t *ofp;
03723 GetOpenFile(rb_stdout, ofp);
03724 if (ofp->mode & FMODE_TTY) {
03725 rb_io_flush(rb_stdout);
03726 }
03727 }
03728 if (io_fillbuf(fptr) < 0) {
03729 return Qnil;
03730 }
03731 fptr->rbuf.off++;
03732 fptr->rbuf.len--;
03733 c = (unsigned char)fptr->rbuf.ptr[fptr->rbuf.off-1];
03734 return INT2FIX(c & 0xff);
03735 }
03736
03737
03738
03739
03740
03741
03742
03743
03744
03745 static VALUE
03746 rb_io_readbyte(VALUE io)
03747 {
03748 VALUE c = rb_io_getbyte(io);
03749
03750 if (NIL_P(c)) {
03751 rb_eof_error();
03752 }
03753 return c;
03754 }
03755
03756
03757
03758
03759
03760
03761
03762
03763
03764
03765
03766
03767
03768
03769
03770
03771
03772
03773 VALUE
03774 rb_io_ungetbyte(VALUE io, VALUE b)
03775 {
03776 rb_io_t *fptr;
03777
03778 GetOpenFile(io, fptr);
03779 rb_io_check_byte_readable(fptr);
03780 if (NIL_P(b)) return Qnil;
03781 if (FIXNUM_P(b)) {
03782 char cc = FIX2INT(b);
03783 b = rb_str_new(&cc, 1);
03784 }
03785 else {
03786 SafeStringValue(b);
03787 }
03788 io_ungetbyte(b, fptr);
03789 return Qnil;
03790 }
03791
03792
03793
03794
03795
03796
03797
03798
03799
03800
03801
03802
03803
03804
03805
03806
03807
03808 VALUE
03809 rb_io_ungetc(VALUE io, VALUE c)
03810 {
03811 rb_io_t *fptr;
03812 long len;
03813
03814 GetOpenFile(io, fptr);
03815 rb_io_check_char_readable(fptr);
03816 if (NIL_P(c)) return Qnil;
03817 if (FIXNUM_P(c)) {
03818 c = rb_enc_uint_chr(FIX2UINT(c), io_read_encoding(fptr));
03819 }
03820 else if (RB_TYPE_P(c, T_BIGNUM)) {
03821 c = rb_enc_uint_chr(NUM2UINT(c), io_read_encoding(fptr));
03822 }
03823 else {
03824 SafeStringValue(c);
03825 }
03826 if (NEED_READCONV(fptr)) {
03827 SET_BINARY_MODE(fptr);
03828 len = RSTRING_LEN(c);
03829 #if SIZEOF_LONG > SIZEOF_INT
03830 if (len > INT_MAX)
03831 rb_raise(rb_eIOError, "ungetc failed");
03832 #endif
03833 make_readconv(fptr, (int)len);
03834 if (fptr->cbuf.capa - fptr->cbuf.len < len)
03835 rb_raise(rb_eIOError, "ungetc failed");
03836 if (fptr->cbuf.off < len) {
03837 MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.capa-fptr->cbuf.len,
03838 fptr->cbuf.ptr+fptr->cbuf.off,
03839 char, fptr->cbuf.len);
03840 fptr->cbuf.off = fptr->cbuf.capa-fptr->cbuf.len;
03841 }
03842 fptr->cbuf.off -= (int)len;
03843 fptr->cbuf.len += (int)len;
03844 MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.off, RSTRING_PTR(c), char, len);
03845 }
03846 else {
03847 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
03848 io_ungetbyte(c, fptr);
03849 }
03850 return Qnil;
03851 }
03852
03853
03854
03855
03856
03857
03858
03859
03860
03861
03862
03863
03864
03865 static VALUE
03866 rb_io_isatty(VALUE io)
03867 {
03868 rb_io_t *fptr;
03869
03870 GetOpenFile(io, fptr);
03871 if (isatty(fptr->fd) == 0)
03872 return Qfalse;
03873 return Qtrue;
03874 }
03875
03876 #if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
03877
03878
03879
03880
03881
03882
03883
03884
03885
03886
03887
03888
03889
03890
03891 static VALUE
03892 rb_io_close_on_exec_p(VALUE io)
03893 {
03894 rb_io_t *fptr;
03895 VALUE write_io;
03896 int fd, ret;
03897
03898 write_io = GetWriteIO(io);
03899 if (io != write_io) {
03900 GetOpenFile(write_io, fptr);
03901 if (fptr && 0 <= (fd = fptr->fd)) {
03902 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
03903 if (!(ret & FD_CLOEXEC)) return Qfalse;
03904 }
03905 }
03906
03907 GetOpenFile(io, fptr);
03908 if (fptr && 0 <= (fd = fptr->fd)) {
03909 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
03910 if (!(ret & FD_CLOEXEC)) return Qfalse;
03911 }
03912 return Qtrue;
03913 }
03914 #else
03915 #define rb_io_close_on_exec_p rb_f_notimplement
03916 #endif
03917
03918 #if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
03919
03920
03921
03922
03923
03924
03925
03926
03927
03928
03929
03930
03931
03932
03933
03934
03935
03936
03937
03938
03939 static VALUE
03940 rb_io_set_close_on_exec(VALUE io, VALUE arg)
03941 {
03942 int flag = RTEST(arg) ? FD_CLOEXEC : 0;
03943 rb_io_t *fptr;
03944 VALUE write_io;
03945 int fd, ret;
03946
03947 write_io = GetWriteIO(io);
03948 if (io != write_io) {
03949 GetOpenFile(write_io, fptr);
03950 if (fptr && 0 <= (fd = fptr->fd)) {
03951 if ((ret = fcntl(fptr->fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
03952 if ((ret & FD_CLOEXEC) != flag) {
03953 ret = (ret & ~FD_CLOEXEC) | flag;
03954 ret = fcntl(fd, F_SETFD, ret);
03955 if (ret == -1) rb_sys_fail_path(fptr->pathv);
03956 }
03957 }
03958
03959 }
03960
03961 GetOpenFile(io, fptr);
03962 if (fptr && 0 <= (fd = fptr->fd)) {
03963 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
03964 if ((ret & FD_CLOEXEC) != flag) {
03965 ret = (ret & ~FD_CLOEXEC) | flag;
03966 ret = fcntl(fd, F_SETFD, ret);
03967 if (ret == -1) rb_sys_fail_path(fptr->pathv);
03968 }
03969 }
03970 return Qnil;
03971 }
03972 #else
03973 #define rb_io_set_close_on_exec rb_f_notimplement
03974 #endif
03975
03976 #define FMODE_PREP (1<<16)
03977 #define IS_PREP_STDIO(f) ((f)->mode & FMODE_PREP)
03978 #define PREP_STDIO_NAME(f) (RSTRING_PTR((f)->pathv))
03979
03980 static VALUE
03981 finish_writeconv(rb_io_t *fptr, int noalloc)
03982 {
03983 unsigned char *ds, *dp, *de;
03984 rb_econv_result_t res;
03985
03986 if (!fptr->wbuf.ptr) {
03987 unsigned char buf[1024];
03988 long r;
03989
03990 res = econv_destination_buffer_full;
03991 while (res == econv_destination_buffer_full) {
03992 ds = dp = buf;
03993 de = buf + sizeof(buf);
03994 res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
03995 while (dp-ds) {
03996 retry:
03997 if (fptr->write_lock && rb_mutex_owned_p(fptr->write_lock))
03998 r = rb_write_internal2(fptr->fd, ds, dp-ds);
03999 else
04000 r = rb_write_internal(fptr->fd, ds, dp-ds);
04001 if (r == dp-ds)
04002 break;
04003 if (0 <= r) {
04004 ds += r;
04005 }
04006 if (rb_io_wait_writable(fptr->fd)) {
04007 if (fptr->fd < 0)
04008 return noalloc ? Qtrue : rb_exc_new3(rb_eIOError, rb_str_new_cstr(closed_stream));
04009 goto retry;
04010 }
04011 return noalloc ? Qtrue : INT2NUM(errno);
04012 }
04013 if (res == econv_invalid_byte_sequence ||
04014 res == econv_incomplete_input ||
04015 res == econv_undefined_conversion) {
04016 return noalloc ? Qtrue : rb_econv_make_exception(fptr->writeconv);
04017 }
04018 }
04019
04020 return Qnil;
04021 }
04022
04023 res = econv_destination_buffer_full;
04024 while (res == econv_destination_buffer_full) {
04025 if (fptr->wbuf.len == fptr->wbuf.capa) {
04026 if (io_fflush(fptr) < 0)
04027 return noalloc ? Qtrue : INT2NUM(errno);
04028 }
04029
04030 ds = dp = (unsigned char *)fptr->wbuf.ptr + fptr->wbuf.off + fptr->wbuf.len;
04031 de = (unsigned char *)fptr->wbuf.ptr + fptr->wbuf.capa;
04032 res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
04033 fptr->wbuf.len += (int)(dp - ds);
04034 if (res == econv_invalid_byte_sequence ||
04035 res == econv_incomplete_input ||
04036 res == econv_undefined_conversion) {
04037 return noalloc ? Qtrue : rb_econv_make_exception(fptr->writeconv);
04038 }
04039 }
04040 return Qnil;
04041 }
04042
04043 struct finish_writeconv_arg {
04044 rb_io_t *fptr;
04045 int noalloc;
04046 };
04047
04048 static VALUE
04049 finish_writeconv_sync(VALUE arg)
04050 {
04051 struct finish_writeconv_arg *p = (struct finish_writeconv_arg *)arg;
04052 return finish_writeconv(p->fptr, p->noalloc);
04053 }
04054
04055 static void*
04056 nogvl_close(void *ptr)
04057 {
04058 int *fd = ptr;
04059
04060 return (void*)(intptr_t)close(*fd);
04061 }
04062
04063 static int
04064 maygvl_close(int fd, int keepgvl)
04065 {
04066 if (keepgvl)
04067 return close(fd);
04068
04069
04070
04071
04072
04073 return (int)(intptr_t)rb_thread_call_without_gvl(nogvl_close, &fd, RUBY_UBF_IO, 0);
04074 }
04075
04076 static void*
04077 nogvl_fclose(void *ptr)
04078 {
04079 FILE *file = ptr;
04080
04081 return (void*)(intptr_t)fclose(file);
04082 }
04083
04084 static int
04085 maygvl_fclose(FILE *file, int keepgvl)
04086 {
04087 if (keepgvl)
04088 return fclose(file);
04089
04090 return (int)(intptr_t)rb_thread_call_without_gvl(nogvl_fclose, file, RUBY_UBF_IO, 0);
04091 }
04092
04093 static void
04094 fptr_finalize(rb_io_t *fptr, int noraise)
04095 {
04096 VALUE err = Qnil;
04097 int fd = fptr->fd;
04098 FILE *stdio_file = fptr->stdio_file;
04099
04100 if (fptr->writeconv) {
04101 if (fptr->write_lock && !noraise) {
04102 struct finish_writeconv_arg arg;
04103 arg.fptr = fptr;
04104 arg.noalloc = noraise;
04105 err = rb_mutex_synchronize(fptr->write_lock, finish_writeconv_sync, (VALUE)&arg);
04106 }
04107 else {
04108 err = finish_writeconv(fptr, noraise);
04109 }
04110 }
04111 if (fptr->wbuf.len) {
04112 if (noraise) {
04113 if ((int)io_flush_buffer_sync(fptr) < 0 && NIL_P(err))
04114 err = Qtrue;
04115 }
04116 else {
04117 if (io_fflush(fptr) < 0 && NIL_P(err))
04118 err = INT2NUM(errno);
04119 }
04120 }
04121
04122 fptr->fd = -1;
04123 fptr->stdio_file = 0;
04124 fptr->mode &= ~(FMODE_READABLE|FMODE_WRITABLE);
04125
04126 if (IS_PREP_STDIO(fptr) || fd <= 2) {
04127
04128 }
04129 else if (stdio_file) {
04130
04131
04132 if ((maygvl_fclose(stdio_file, noraise) < 0) && NIL_P(err))
04133 err = noraise ? Qtrue : INT2NUM(errno);
04134 }
04135 else if (0 <= fd) {
04136
04137
04138
04139 if ((maygvl_close(fd, noraise) < 0) && NIL_P(err))
04140 err = noraise ? Qtrue : INT2NUM(errno);
04141 }
04142
04143 if (!NIL_P(err) && !noraise) {
04144 switch (TYPE(err)) {
04145 case T_FIXNUM:
04146 case T_BIGNUM:
04147 errno = NUM2INT(err);
04148 rb_sys_fail_path(fptr->pathv);
04149
04150 default:
04151 rb_exc_raise(err);
04152 }
04153 }
04154 }
04155
04156 static void
04157 rb_io_fptr_cleanup(rb_io_t *fptr, int noraise)
04158 {
04159 if (fptr->finalize) {
04160 (*fptr->finalize)(fptr, noraise);
04161 }
04162 else {
04163 fptr_finalize(fptr, noraise);
04164 }
04165 }
04166
04167 static void
04168 clear_readconv(rb_io_t *fptr)
04169 {
04170 if (fptr->readconv) {
04171 rb_econv_close(fptr->readconv);
04172 fptr->readconv = NULL;
04173 }
04174 if (fptr->cbuf.ptr) {
04175 free(fptr->cbuf.ptr);
04176 fptr->cbuf.ptr = NULL;
04177 }
04178 }
04179
04180 static void
04181 clear_writeconv(rb_io_t *fptr)
04182 {
04183 if (fptr->writeconv) {
04184 rb_econv_close(fptr->writeconv);
04185 fptr->writeconv = NULL;
04186 }
04187 fptr->writeconv_initialized = 0;
04188 }
04189
04190 static void
04191 clear_codeconv(rb_io_t *fptr)
04192 {
04193 clear_readconv(fptr);
04194 clear_writeconv(fptr);
04195 }
04196
04197 int
04198 rb_io_fptr_finalize(rb_io_t *fptr)
04199 {
04200 if (!fptr) return 0;
04201 fptr->pathv = Qnil;
04202 if (0 <= fptr->fd)
04203 rb_io_fptr_cleanup(fptr, TRUE);
04204 fptr->write_lock = 0;
04205 if (fptr->rbuf.ptr) {
04206 free(fptr->rbuf.ptr);
04207 fptr->rbuf.ptr = 0;
04208 }
04209 if (fptr->wbuf.ptr) {
04210 free(fptr->wbuf.ptr);
04211 fptr->wbuf.ptr = 0;
04212 }
04213 clear_codeconv(fptr);
04214 free(fptr);
04215 return 1;
04216 }
04217
04218 size_t rb_econv_memsize(rb_econv_t *);
04219
04220 RUBY_FUNC_EXPORTED size_t
04221 rb_io_memsize(const rb_io_t *fptr)
04222 {
04223 size_t size = sizeof(rb_io_t);
04224 size += fptr->rbuf.capa;
04225 size += fptr->wbuf.capa;
04226 size += fptr->cbuf.capa;
04227 if (fptr->readconv) size += rb_econv_memsize(fptr->readconv);
04228 if (fptr->writeconv) size += rb_econv_memsize(fptr->writeconv);
04229 return size;
04230 }
04231
04232 VALUE
04233 rb_io_close(VALUE io)
04234 {
04235 rb_io_t *fptr;
04236 int fd;
04237 VALUE write_io;
04238 rb_io_t *write_fptr;
04239
04240 write_io = GetWriteIO(io);
04241 if (io != write_io) {
04242 write_fptr = RFILE(write_io)->fptr;
04243 if (write_fptr && 0 <= write_fptr->fd) {
04244 rb_io_fptr_cleanup(write_fptr, TRUE);
04245 }
04246 }
04247
04248 fptr = RFILE(io)->fptr;
04249 if (!fptr) return Qnil;
04250 if (fptr->fd < 0) return Qnil;
04251
04252 fd = fptr->fd;
04253 rb_thread_fd_close(fd);
04254 rb_io_fptr_cleanup(fptr, FALSE);
04255
04256 if (fptr->pid) {
04257 rb_last_status_clear();
04258 rb_syswait(fptr->pid);
04259 fptr->pid = 0;
04260 }
04261
04262 return Qnil;
04263 }
04264
04265
04266
04267
04268
04269
04270
04271
04272
04273
04274
04275
04276
04277
04278
04279 static VALUE
04280 rb_io_close_m(VALUE io)
04281 {
04282 if (rb_safe_level() >= 4 && !OBJ_UNTRUSTED(io)) {
04283 rb_raise(rb_eSecurityError, "Insecure: can't close");
04284 }
04285 rb_io_check_closed(RFILE(io)->fptr);
04286 rb_io_close(io);
04287 return Qnil;
04288 }
04289
04290 static VALUE
04291 io_call_close(VALUE io)
04292 {
04293 rb_check_funcall(io, rb_intern("close"), 0, 0);
04294 return io;
04295 }
04296
04297 static VALUE
04298 ignore_closed_stream(VALUE io, VALUE exc)
04299 {
04300 enum {mesg_len = sizeof(closed_stream)-1};
04301 VALUE mesg = rb_attr_get(exc, rb_intern("mesg"));
04302 if (!RB_TYPE_P(mesg, T_STRING) ||
04303 RSTRING_LEN(mesg) != mesg_len ||
04304 memcmp(RSTRING_PTR(mesg), closed_stream, mesg_len)) {
04305 rb_exc_raise(exc);
04306 }
04307 return io;
04308 }
04309
04310 static VALUE
04311 io_close(VALUE io)
04312 {
04313 VALUE closed = rb_check_funcall(io, rb_intern("closed?"), 0, 0);
04314 if (closed != Qundef && RTEST(closed)) return io;
04315 rb_rescue2(io_call_close, io, ignore_closed_stream, io,
04316 rb_eIOError, (VALUE)0);
04317 return io;
04318 }
04319
04320
04321
04322
04323
04324
04325
04326
04327
04328
04329
04330
04331
04332
04333
04334
04335
04336
04337
04338
04339 static VALUE
04340 rb_io_closed(VALUE io)
04341 {
04342 rb_io_t *fptr;
04343 VALUE write_io;
04344 rb_io_t *write_fptr;
04345
04346 write_io = GetWriteIO(io);
04347 if (io != write_io) {
04348 write_fptr = RFILE(write_io)->fptr;
04349 if (write_fptr && 0 <= write_fptr->fd) {
04350 return Qfalse;
04351 }
04352 }
04353
04354 fptr = RFILE(io)->fptr;
04355 rb_io_check_initialized(fptr);
04356 return 0 <= fptr->fd ? Qfalse : Qtrue;
04357 }
04358
04359
04360
04361
04362
04363
04364
04365
04366
04367
04368
04369
04370
04371
04372
04373
04374
04375
04376
04377 static VALUE
04378 rb_io_close_read(VALUE io)
04379 {
04380 rb_io_t *fptr;
04381 VALUE write_io;
04382
04383 if (rb_safe_level() >= 4 && !OBJ_UNTRUSTED(io)) {
04384 rb_raise(rb_eSecurityError, "Insecure: can't close");
04385 }
04386 GetOpenFile(io, fptr);
04387 if (is_socket(fptr->fd, fptr->pathv)) {
04388 #ifndef SHUT_RD
04389 # define SHUT_RD 0
04390 #endif
04391 if (shutdown(fptr->fd, SHUT_RD) < 0)
04392 rb_sys_fail_path(fptr->pathv);
04393 fptr->mode &= ~FMODE_READABLE;
04394 if (!(fptr->mode & FMODE_WRITABLE))
04395 return rb_io_close(io);
04396 return Qnil;
04397 }
04398
04399 write_io = GetWriteIO(io);
04400 if (io != write_io) {
04401 rb_io_t *wfptr;
04402 GetOpenFile(write_io, wfptr);
04403 wfptr->pid = fptr->pid;
04404 fptr->pid = 0;
04405 RFILE(io)->fptr = wfptr;
04406
04407 fptr->tied_io_for_writing = 0;
04408 fptr->mode &= ~FMODE_DUPLEX;
04409 RFILE(write_io)->fptr = fptr;
04410 rb_io_fptr_cleanup(fptr, FALSE);
04411
04412 return Qnil;
04413 }
04414
04415 if (fptr->mode & FMODE_WRITABLE) {
04416 rb_raise(rb_eIOError, "closing non-duplex IO for reading");
04417 }
04418 return rb_io_close(io);
04419 }
04420
04421
04422
04423
04424
04425
04426
04427
04428
04429
04430
04431
04432
04433
04434
04435
04436
04437
04438
04439
04440 static VALUE
04441 rb_io_close_write(VALUE io)
04442 {
04443 rb_io_t *fptr;
04444 VALUE write_io;
04445
04446 if (rb_safe_level() >= 4 && !OBJ_UNTRUSTED(io)) {
04447 rb_raise(rb_eSecurityError, "Insecure: can't close");
04448 }
04449 write_io = GetWriteIO(io);
04450 GetOpenFile(write_io, fptr);
04451 if (is_socket(fptr->fd, fptr->pathv)) {
04452 #ifndef SHUT_WR
04453 # define SHUT_WR 1
04454 #endif
04455 if (shutdown(fptr->fd, SHUT_WR) < 0)
04456 rb_sys_fail_path(fptr->pathv);
04457 fptr->mode &= ~FMODE_WRITABLE;
04458 if (!(fptr->mode & FMODE_READABLE))
04459 return rb_io_close(write_io);
04460 return Qnil;
04461 }
04462
04463 if (fptr->mode & FMODE_READABLE) {
04464 rb_raise(rb_eIOError, "closing non-duplex IO for writing");
04465 }
04466
04467 if (io != write_io) {
04468 GetOpenFile(io, fptr);
04469 fptr->tied_io_for_writing = 0;
04470 fptr->mode &= ~FMODE_DUPLEX;
04471 }
04472 rb_io_close(write_io);
04473 return Qnil;
04474 }
04475
04476
04477
04478
04479
04480
04481
04482
04483
04484
04485
04486
04487
04488
04489 static VALUE
04490 rb_io_sysseek(int argc, VALUE *argv, VALUE io)
04491 {
04492 VALUE offset, ptrname;
04493 int whence = SEEK_SET;
04494 rb_io_t *fptr;
04495 off_t pos;
04496
04497 if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
04498 whence = NUM2INT(ptrname);
04499 }
04500 pos = NUM2OFFT(offset);
04501 GetOpenFile(io, fptr);
04502 if ((fptr->mode & FMODE_READABLE) &&
04503 (READ_DATA_BUFFERED(fptr) || READ_CHAR_PENDING(fptr))) {
04504 rb_raise(rb_eIOError, "sysseek for buffered IO");
04505 }
04506 if ((fptr->mode & FMODE_WRITABLE) && fptr->wbuf.len) {
04507 rb_warn("sysseek for buffered IO");
04508 }
04509 errno = 0;
04510 pos = lseek(fptr->fd, pos, whence);
04511 if (pos == -1 && errno) rb_sys_fail_path(fptr->pathv);
04512
04513 return OFFT2NUM(pos);
04514 }
04515
04516
04517
04518
04519
04520
04521
04522
04523
04524
04525
04526
04527
04528
04529 static VALUE
04530 rb_io_syswrite(VALUE io, VALUE str)
04531 {
04532 rb_io_t *fptr;
04533 long n;
04534
04535 rb_secure(4);
04536 if (!RB_TYPE_P(str, T_STRING))
04537 str = rb_obj_as_string(str);
04538
04539 io = GetWriteIO(io);
04540 GetOpenFile(io, fptr);
04541 rb_io_check_writable(fptr);
04542
04543 str = rb_str_new_frozen(str);
04544
04545 if (fptr->wbuf.len) {
04546 rb_warn("syswrite for buffered IO");
04547 }
04548
04549 n = rb_write_internal(fptr->fd, RSTRING_PTR(str), RSTRING_LEN(str));
04550 RB_GC_GUARD(str);
04551
04552 if (n == -1) rb_sys_fail_path(fptr->pathv);
04553
04554 return LONG2FIX(n);
04555 }
04556
04557
04558
04559
04560
04561
04562
04563
04564
04565
04566
04567
04568
04569
04570
04571
04572
04573
04574
04575 static VALUE
04576 rb_io_sysread(int argc, VALUE *argv, VALUE io)
04577 {
04578 VALUE len, str;
04579 rb_io_t *fptr;
04580 long n, ilen;
04581 struct read_internal_arg arg;
04582
04583 rb_scan_args(argc, argv, "11", &len, &str);
04584 ilen = NUM2LONG(len);
04585
04586 io_setstrbuf(&str,ilen);
04587 if (ilen == 0) return str;
04588
04589 GetOpenFile(io, fptr);
04590 rb_io_check_byte_readable(fptr);
04591
04592 if (READ_DATA_BUFFERED(fptr)) {
04593 rb_raise(rb_eIOError, "sysread for buffered IO");
04594 }
04595
04596 n = fptr->fd;
04597
04598
04599
04600
04601
04602
04603
04604
04605 rb_thread_wait_fd(fptr->fd);
04606
04607 rb_io_check_closed(fptr);
04608
04609 io_setstrbuf(&str, ilen);
04610 rb_str_locktmp(str);
04611 arg.fd = fptr->fd;
04612 arg.str_ptr = RSTRING_PTR(str);
04613 arg.len = ilen;
04614 rb_ensure(read_internal_call, (VALUE)&arg, rb_str_unlocktmp, str);
04615 n = arg.len;
04616
04617 if (n == -1) {
04618 rb_sys_fail_path(fptr->pathv);
04619 }
04620 io_set_read_length(str, n);
04621 if (n == 0 && ilen > 0) {
04622 rb_eof_error();
04623 }
04624 OBJ_TAINT(str);
04625
04626 return str;
04627 }
04628
04629 VALUE
04630 rb_io_binmode(VALUE io)
04631 {
04632 rb_io_t *fptr;
04633
04634 GetOpenFile(io, fptr);
04635 if (fptr->readconv)
04636 rb_econv_binmode(fptr->readconv);
04637 if (fptr->writeconv)
04638 rb_econv_binmode(fptr->writeconv);
04639 fptr->mode |= FMODE_BINMODE;
04640 fptr->mode &= ~FMODE_TEXTMODE;
04641 fptr->writeconv_pre_ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
04642 #ifdef O_BINARY
04643 if (!fptr->readconv) {
04644 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
04645 }
04646 else {
04647 setmode(fptr->fd, O_BINARY);
04648 }
04649 #endif
04650 return io;
04651 }
04652
04653 VALUE
04654 rb_io_ascii8bit_binmode(VALUE io)
04655 {
04656 rb_io_t *fptr;
04657
04658 GetOpenFile(io, fptr);
04659 if (fptr->readconv) {
04660 rb_econv_close(fptr->readconv);
04661 fptr->readconv = NULL;
04662 }
04663 if (fptr->writeconv) {
04664 rb_econv_close(fptr->writeconv);
04665 fptr->writeconv = NULL;
04666 }
04667 fptr->mode |= FMODE_BINMODE;
04668 fptr->mode &= ~FMODE_TEXTMODE;
04669 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
04670
04671 fptr->encs.enc = rb_ascii8bit_encoding();
04672 fptr->encs.enc2 = NULL;
04673 fptr->encs.ecflags = 0;
04674 fptr->encs.ecopts = Qnil;
04675 clear_codeconv(fptr);
04676
04677 return io;
04678 }
04679
04680
04681
04682
04683
04684
04685
04686
04687
04688
04689
04690
04691
04692
04693 static VALUE
04694 rb_io_binmode_m(VALUE io)
04695 {
04696 VALUE write_io;
04697
04698 rb_io_ascii8bit_binmode(io);
04699
04700 write_io = GetWriteIO(io);
04701 if (write_io != io)
04702 rb_io_ascii8bit_binmode(write_io);
04703 return io;
04704 }
04705
04706
04707
04708
04709
04710
04711
04712 static VALUE
04713 rb_io_binmode_p(VALUE io)
04714 {
04715 rb_io_t *fptr;
04716 GetOpenFile(io, fptr);
04717 return fptr->mode & FMODE_BINMODE ? Qtrue : Qfalse;
04718 }
04719
04720 static const char*
04721 rb_io_fmode_modestr(int fmode)
04722 {
04723 if (fmode & FMODE_APPEND) {
04724 if ((fmode & FMODE_READWRITE) == FMODE_READWRITE) {
04725 return MODE_BTMODE("a+", "ab+", "at+");
04726 }
04727 return MODE_BTMODE("a", "ab", "at");
04728 }
04729 switch (fmode & FMODE_READWRITE) {
04730 default:
04731 rb_raise(rb_eArgError, "invalid access fmode 0x%x", fmode);
04732 case FMODE_READABLE:
04733 return MODE_BTMODE("r", "rb", "rt");
04734 case FMODE_WRITABLE:
04735 return MODE_BTMODE("w", "wb", "wt");
04736 case FMODE_READWRITE:
04737 if (fmode & FMODE_CREATE) {
04738 return MODE_BTMODE("w+", "wb+", "wt+");
04739 }
04740 return MODE_BTMODE("r+", "rb+", "rt+");
04741 }
04742 }
04743
04744 static int
04745 io_encname_bom_p(const char *name, long len)
04746 {
04747 static const char bom_prefix[] = "bom|utf-";
04748 enum {bom_prefix_len = (int)sizeof(bom_prefix) - 1};
04749 if (!len) {
04750 const char *p = strchr(name, ':');
04751 len = p ? (long)(p - name) : (long)strlen(name);
04752 }
04753 return len > bom_prefix_len && STRNCASECMP(name, bom_prefix, bom_prefix_len) == 0;
04754 }
04755
04756 int
04757 rb_io_modestr_fmode(const char *modestr)
04758 {
04759 int fmode = 0;
04760 const char *m = modestr, *p = NULL;
04761
04762 switch (*m++) {
04763 case 'r':
04764 fmode |= FMODE_READABLE;
04765 break;
04766 case 'w':
04767 fmode |= FMODE_WRITABLE | FMODE_TRUNC | FMODE_CREATE;
04768 break;
04769 case 'a':
04770 fmode |= FMODE_WRITABLE | FMODE_APPEND | FMODE_CREATE;
04771 break;
04772 default:
04773 error:
04774 rb_raise(rb_eArgError, "invalid access mode %s", modestr);
04775 }
04776
04777 while (*m) {
04778 switch (*m++) {
04779 case 'b':
04780 fmode |= FMODE_BINMODE;
04781 break;
04782 case 't':
04783 fmode |= FMODE_TEXTMODE;
04784 break;
04785 case '+':
04786 fmode |= FMODE_READWRITE;
04787 break;
04788 default:
04789 goto error;
04790 case ':':
04791 p = m;
04792 goto finished;
04793 }
04794 }
04795
04796 finished:
04797 if ((fmode & FMODE_BINMODE) && (fmode & FMODE_TEXTMODE))
04798 goto error;
04799 if (p && io_encname_bom_p(p, 0))
04800 fmode |= FMODE_SETENC_BY_BOM;
04801
04802 return fmode;
04803 }
04804
04805 int
04806 rb_io_oflags_fmode(int oflags)
04807 {
04808 int fmode = 0;
04809
04810 switch (oflags & (O_RDONLY|O_WRONLY|O_RDWR)) {
04811 case O_RDONLY:
04812 fmode = FMODE_READABLE;
04813 break;
04814 case O_WRONLY:
04815 fmode = FMODE_WRITABLE;
04816 break;
04817 case O_RDWR:
04818 fmode = FMODE_READWRITE;
04819 break;
04820 }
04821
04822 if (oflags & O_APPEND) {
04823 fmode |= FMODE_APPEND;
04824 }
04825 if (oflags & O_TRUNC) {
04826 fmode |= FMODE_TRUNC;
04827 }
04828 if (oflags & O_CREAT) {
04829 fmode |= FMODE_CREATE;
04830 }
04831 #ifdef O_BINARY
04832 if (oflags & O_BINARY) {
04833 fmode |= FMODE_BINMODE;
04834 }
04835 #endif
04836
04837 return fmode;
04838 }
04839
04840 static int
04841 rb_io_fmode_oflags(int fmode)
04842 {
04843 int oflags = 0;
04844
04845 switch (fmode & FMODE_READWRITE) {
04846 case FMODE_READABLE:
04847 oflags |= O_RDONLY;
04848 break;
04849 case FMODE_WRITABLE:
04850 oflags |= O_WRONLY;
04851 break;
04852 case FMODE_READWRITE:
04853 oflags |= O_RDWR;
04854 break;
04855 }
04856
04857 if (fmode & FMODE_APPEND) {
04858 oflags |= O_APPEND;
04859 }
04860 if (fmode & FMODE_TRUNC) {
04861 oflags |= O_TRUNC;
04862 }
04863 if (fmode & FMODE_CREATE) {
04864 oflags |= O_CREAT;
04865 }
04866 #ifdef O_BINARY
04867 if (fmode & FMODE_BINMODE) {
04868 oflags |= O_BINARY;
04869 }
04870 #endif
04871
04872 return oflags;
04873 }
04874
04875 int
04876 rb_io_modestr_oflags(const char *modestr)
04877 {
04878 return rb_io_fmode_oflags(rb_io_modestr_fmode(modestr));
04879 }
04880
04881 static const char*
04882 rb_io_oflags_modestr(int oflags)
04883 {
04884 #ifdef O_BINARY
04885 # define MODE_BINARY(a,b) ((oflags & O_BINARY) ? (b) : (a))
04886 #else
04887 # define MODE_BINARY(a,b) (a)
04888 #endif
04889 int accmode = oflags & (O_RDONLY|O_WRONLY|O_RDWR);
04890 if (oflags & O_APPEND) {
04891 if (accmode == O_WRONLY) {
04892 return MODE_BINARY("a", "ab");
04893 }
04894 if (accmode == O_RDWR) {
04895 return MODE_BINARY("a+", "ab+");
04896 }
04897 }
04898 switch (oflags & (O_RDONLY|O_WRONLY|O_RDWR)) {
04899 default:
04900 rb_raise(rb_eArgError, "invalid access oflags 0x%x", oflags);
04901 case O_RDONLY:
04902 return MODE_BINARY("r", "rb");
04903 case O_WRONLY:
04904 return MODE_BINARY("w", "wb");
04905 case O_RDWR:
04906 return MODE_BINARY("r+", "rb+");
04907 }
04908 }
04909
04910
04911
04912
04913
04914
04915 static void
04916 rb_io_ext_int_to_encs(rb_encoding *ext, rb_encoding *intern, rb_encoding **enc, rb_encoding **enc2, int fmode)
04917 {
04918 int default_ext = 0;
04919
04920 if (ext == NULL) {
04921 ext = rb_default_external_encoding();
04922 default_ext = 1;
04923 }
04924 if (intern == NULL && ext != rb_ascii8bit_encoding())
04925
04926 intern = rb_default_internal_encoding();
04927 if (intern == NULL || intern == (rb_encoding *)Qnil ||
04928 (!(fmode & FMODE_SETENC_BY_BOM) && (intern == ext))) {
04929
04930 *enc = (default_ext && intern != ext) ? NULL : ext;
04931 *enc2 = NULL;
04932 }
04933 else {
04934 *enc = intern;
04935 *enc2 = ext;
04936 }
04937 }
04938
04939 static void
04940 unsupported_encoding(const char *name)
04941 {
04942 rb_warn("Unsupported encoding %s ignored", name);
04943 }
04944
04945 static void
04946 parse_mode_enc(const char *estr, rb_encoding **enc_p, rb_encoding **enc2_p, int *fmode_p)
04947 {
04948 const char *p;
04949 char encname[ENCODING_MAXNAMELEN+1];
04950 int idx, idx2;
04951 int fmode = fmode_p ? *fmode_p : 0;
04952 rb_encoding *ext_enc, *int_enc;
04953
04954
04955
04956 p = strrchr(estr, ':');
04957 if (p) {
04958 long len = (p++) - estr;
04959 if (len == 0 || len > ENCODING_MAXNAMELEN)
04960 idx = -1;
04961 else {
04962 if (io_encname_bom_p(estr, len)) {
04963 fmode |= FMODE_SETENC_BY_BOM;
04964 estr += 4;
04965 len -= 4;
04966 }
04967 memcpy(encname, estr, len);
04968 encname[len] = '\0';
04969 estr = encname;
04970 idx = rb_enc_find_index(encname);
04971 }
04972 }
04973 else {
04974 long len = strlen(estr);
04975 if (io_encname_bom_p(estr, len)) {
04976 fmode |= FMODE_SETENC_BY_BOM;
04977 estr += 4;
04978 len -= 4;
04979 memcpy(encname, estr, len);
04980 encname[len] = '\0';
04981 estr = encname;
04982 }
04983 idx = rb_enc_find_index(estr);
04984 }
04985 if (fmode_p) *fmode_p = fmode;
04986
04987 if (idx >= 0)
04988 ext_enc = rb_enc_from_index(idx);
04989 else {
04990 if (idx != -2)
04991 unsupported_encoding(estr);
04992 ext_enc = NULL;
04993 }
04994
04995 int_enc = NULL;
04996 if (p) {
04997 if (*p == '-' && *(p+1) == '\0') {
04998
04999 int_enc = (rb_encoding *)Qnil;
05000 }
05001 else {
05002 idx2 = rb_enc_find_index(p);
05003 if (idx2 < 0)
05004 unsupported_encoding(p);
05005 else if (!(fmode & FMODE_SETENC_BY_BOM) && (idx2 == idx)) {
05006 int_enc = (rb_encoding *)Qnil;
05007 }
05008 else
05009 int_enc = rb_enc_from_index(idx2);
05010 }
05011 }
05012
05013 rb_io_ext_int_to_encs(ext_enc, int_enc, enc_p, enc2_p, fmode);
05014 }
05015
05016 int
05017 rb_io_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding **enc2_p, int *fmode_p)
05018 {
05019 VALUE encoding=Qnil, extenc=Qundef, intenc=Qundef, tmp;
05020 int extracted = 0;
05021 rb_encoding *extencoding = NULL;
05022 rb_encoding *intencoding = NULL;
05023
05024 if (!NIL_P(opt)) {
05025 VALUE v;
05026 v = rb_hash_lookup2(opt, sym_encoding, Qnil);
05027 if (v != Qnil) encoding = v;
05028 v = rb_hash_lookup2(opt, sym_extenc, Qundef);
05029 if (v != Qnil) extenc = v;
05030 v = rb_hash_lookup2(opt, sym_intenc, Qundef);
05031 if (v != Qundef) intenc = v;
05032 }
05033 if ((extenc != Qundef || intenc != Qundef) && !NIL_P(encoding)) {
05034 if (!NIL_P(ruby_verbose)) {
05035 int idx = rb_to_encoding_index(encoding);
05036 rb_warn("Ignoring encoding parameter '%s': %s_encoding is used",
05037 idx < 0 ? StringValueCStr(encoding) : rb_enc_name(rb_enc_from_index(idx)),
05038 extenc == Qundef ? "internal" : "external");
05039 }
05040 encoding = Qnil;
05041 }
05042 if (extenc != Qundef && !NIL_P(extenc)) {
05043 extencoding = rb_to_encoding(extenc);
05044 }
05045 if (intenc != Qundef) {
05046 if (NIL_P(intenc)) {
05047
05048 intencoding = (rb_encoding *)Qnil;
05049 }
05050 else if (!NIL_P(tmp = rb_check_string_type(intenc))) {
05051 char *p = StringValueCStr(tmp);
05052
05053 if (*p == '-' && *(p+1) == '\0') {
05054
05055 intencoding = (rb_encoding *)Qnil;
05056 }
05057 else {
05058 intencoding = rb_to_encoding(intenc);
05059 }
05060 }
05061 else {
05062 intencoding = rb_to_encoding(intenc);
05063 }
05064 if (extencoding == intencoding) {
05065 intencoding = (rb_encoding *)Qnil;
05066 }
05067 }
05068 if (!NIL_P(encoding)) {
05069 extracted = 1;
05070 if (!NIL_P(tmp = rb_check_string_type(encoding))) {
05071 parse_mode_enc(StringValueCStr(tmp), enc_p, enc2_p, fmode_p);
05072 }
05073 else {
05074 rb_io_ext_int_to_encs(rb_to_encoding(encoding), NULL, enc_p, enc2_p, 0);
05075 }
05076 }
05077 else if (extenc != Qundef || intenc != Qundef) {
05078 extracted = 1;
05079 rb_io_ext_int_to_encs(extencoding, intencoding, enc_p, enc2_p, 0);
05080 }
05081 return extracted;
05082 }
05083
05084 typedef struct rb_io_enc_t convconfig_t;
05085
05086 static void
05087 validate_enc_binmode(int *fmode_p, int ecflags, rb_encoding *enc, rb_encoding *enc2)
05088 {
05089 int fmode = *fmode_p;
05090
05091 if ((fmode & FMODE_READABLE) &&
05092 !enc2 &&
05093 !(fmode & FMODE_BINMODE) &&
05094 !rb_enc_asciicompat(enc ? enc : rb_default_external_encoding()))
05095 rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
05096
05097 if (!(fmode & FMODE_BINMODE) &&
05098 (DEFAULT_TEXTMODE || (ecflags & ECONV_NEWLINE_DECORATOR_MASK))) {
05099 fmode |= DEFAULT_TEXTMODE;
05100 *fmode_p = fmode;
05101 }
05102 #if !DEFAULT_TEXTMODE
05103 else if (!(ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
05104 fmode &= ~FMODE_TEXTMODE;
05105 *fmode_p = fmode;
05106 }
05107 #endif
05108 }
05109
05110 static void
05111 extract_binmode(VALUE opthash, int *fmode)
05112 {
05113 if (!NIL_P(opthash)) {
05114 VALUE v;
05115 v = rb_hash_aref(opthash, sym_textmode);
05116 if (!NIL_P(v)) {
05117 if (*fmode & FMODE_TEXTMODE)
05118 rb_raise(rb_eArgError, "textmode specified twice");
05119 if (RTEST(v))
05120 *fmode |= FMODE_TEXTMODE;
05121 }
05122 v = rb_hash_aref(opthash, sym_binmode);
05123 if (!NIL_P(v)) {
05124 if (*fmode & FMODE_BINMODE)
05125 rb_raise(rb_eArgError, "binmode specified twice");
05126 if (RTEST(v))
05127 *fmode |= FMODE_BINMODE;
05128 }
05129
05130 if ((*fmode & FMODE_BINMODE) && (*fmode & FMODE_TEXTMODE))
05131 rb_raise(rb_eArgError, "both textmode and binmode specified");
05132 }
05133 }
05134
05135 static void
05136 rb_io_extract_modeenc(VALUE *vmode_p, VALUE *vperm_p, VALUE opthash,
05137 int *oflags_p, int *fmode_p, convconfig_t *convconfig_p)
05138 {
05139 VALUE vmode;
05140 int oflags, fmode;
05141 rb_encoding *enc, *enc2;
05142 int ecflags;
05143 VALUE ecopts;
05144 int has_enc = 0, has_vmode = 0;
05145 VALUE intmode;
05146
05147 vmode = *vmode_p;
05148
05149
05150 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
05151
05152 vmode_handle:
05153 if (NIL_P(vmode)) {
05154 fmode = FMODE_READABLE;
05155 oflags = O_RDONLY;
05156 }
05157 else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int"))) {
05158 vmode = intmode;
05159 oflags = NUM2INT(intmode);
05160 fmode = rb_io_oflags_fmode(oflags);
05161 }
05162 else {
05163 const char *p;
05164
05165 SafeStringValue(vmode);
05166 p = StringValueCStr(vmode);
05167 fmode = rb_io_modestr_fmode(p);
05168 oflags = rb_io_fmode_oflags(fmode);
05169 p = strchr(p, ':');
05170 if (p) {
05171 has_enc = 1;
05172 parse_mode_enc(p+1, &enc, &enc2, &fmode);
05173 }
05174 else {
05175 rb_encoding *e;
05176
05177 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
05178 rb_io_ext_int_to_encs(e, NULL, &enc, &enc2, fmode);
05179 }
05180 }
05181
05182 if (NIL_P(opthash)) {
05183 ecflags = (fmode & FMODE_READABLE) ?
05184 MODE_BTMODE(ECONV_DEFAULT_NEWLINE_DECORATOR,
05185 0, ECONV_UNIVERSAL_NEWLINE_DECORATOR) : 0;
05186 #ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
05187 ecflags |= (fmode & FMODE_WRITABLE) ?
05188 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
05189 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
05190 #endif
05191 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
05192 ecopts = Qnil;
05193 }
05194 else {
05195 VALUE v;
05196 extract_binmode(opthash, &fmode);
05197 if (fmode & FMODE_BINMODE) {
05198 #ifdef O_BINARY
05199 oflags |= O_BINARY;
05200 #endif
05201 if (!has_enc)
05202 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
05203 }
05204 #if DEFAULT_TEXTMODE
05205 else if (NIL_P(vmode)) {
05206 fmode |= DEFAULT_TEXTMODE;
05207 }
05208 #endif
05209 if (!has_vmode) {
05210 v = rb_hash_aref(opthash, sym_mode);
05211 if (!NIL_P(v)) {
05212 if (!NIL_P(vmode)) {
05213 rb_raise(rb_eArgError, "mode specified twice");
05214 }
05215 has_vmode = 1;
05216 vmode = v;
05217 goto vmode_handle;
05218 }
05219 }
05220 v = rb_hash_aref(opthash, sym_perm);
05221 if (!NIL_P(v)) {
05222 if (vperm_p) {
05223 if (!NIL_P(*vperm_p)) {
05224 rb_raise(rb_eArgError, "perm specified twice");
05225 }
05226 *vperm_p = v;
05227 }
05228 else {
05229
05230 }
05231 }
05232 ecflags = (fmode & FMODE_READABLE) ?
05233 MODE_BTMODE(ECONV_DEFAULT_NEWLINE_DECORATOR,
05234 0, ECONV_UNIVERSAL_NEWLINE_DECORATOR) : 0;
05235 #ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
05236 ecflags |= (fmode & FMODE_WRITABLE) ?
05237 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
05238 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
05239 #endif
05240
05241 if (rb_io_extract_encoding_option(opthash, &enc, &enc2, &fmode)) {
05242 if (has_enc) {
05243 rb_raise(rb_eArgError, "encoding specified twice");
05244 }
05245 }
05246 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
05247 ecflags = rb_econv_prepare_options(opthash, &ecopts, ecflags);
05248 }
05249
05250 validate_enc_binmode(&fmode, ecflags, enc, enc2);
05251
05252 *vmode_p = vmode;
05253
05254 *oflags_p = oflags;
05255 *fmode_p = fmode;
05256 convconfig_p->enc = enc;
05257 convconfig_p->enc2 = enc2;
05258 convconfig_p->ecflags = ecflags;
05259 convconfig_p->ecopts = ecopts;
05260 }
05261
05262 struct sysopen_struct {
05263 VALUE fname;
05264 int oflags;
05265 mode_t perm;
05266 };
05267
05268 static void *
05269 sysopen_func(void *ptr)
05270 {
05271 const struct sysopen_struct *data = ptr;
05272 const char *fname = RSTRING_PTR(data->fname);
05273 return (void *)(VALUE)rb_cloexec_open(fname, data->oflags, data->perm);
05274 }
05275
05276 static inline int
05277 rb_sysopen_internal(struct sysopen_struct *data)
05278 {
05279 int fd;
05280 fd = (int)(VALUE)rb_thread_call_without_gvl(sysopen_func, data, RUBY_UBF_IO, 0);
05281 if (0 <= fd)
05282 rb_update_max_fd(fd);
05283 return fd;
05284 }
05285
05286 static int
05287 rb_sysopen(VALUE fname, int oflags, mode_t perm)
05288 {
05289 int fd;
05290 struct sysopen_struct data;
05291
05292 data.fname = rb_str_encode_ospath(fname);
05293 data.oflags = oflags;
05294 data.perm = perm;
05295
05296 fd = rb_sysopen_internal(&data);
05297 if (fd < 0) {
05298 if (errno == EMFILE || errno == ENFILE) {
05299 rb_gc();
05300 fd = rb_sysopen_internal(&data);
05301 }
05302 if (fd < 0) {
05303 rb_sys_fail_path(fname);
05304 }
05305 }
05306 return fd;
05307 }
05308
05309 FILE *
05310 rb_fdopen(int fd, const char *modestr)
05311 {
05312 FILE *file;
05313
05314 #if defined(__sun)
05315 errno = 0;
05316 #endif
05317 file = fdopen(fd, modestr);
05318 if (!file) {
05319 if (
05320 #if defined(__sun)
05321 errno == 0 ||
05322 #endif
05323 errno == EMFILE || errno == ENFILE) {
05324 rb_gc();
05325 #if defined(__sun)
05326 errno = 0;
05327 #endif
05328 file = fdopen(fd, modestr);
05329 }
05330 if (!file) {
05331 #ifdef _WIN32
05332 if (errno == 0) errno = EINVAL;
05333 #elif defined(__sun)
05334 if (errno == 0) errno = EMFILE;
05335 #endif
05336 rb_sys_fail(0);
05337 }
05338 }
05339
05340
05341 #ifdef USE_SETVBUF
05342 if (setvbuf(file, NULL, _IOFBF, 0) != 0)
05343 rb_warn("setvbuf() can't be honoured (fd=%d)", fd);
05344 #endif
05345 return file;
05346 }
05347
05348 static void
05349 io_check_tty(rb_io_t *fptr)
05350 {
05351 if (isatty(fptr->fd))
05352 fptr->mode |= FMODE_TTY|FMODE_DUPLEX;
05353 }
05354
05355 static VALUE rb_io_internal_encoding(VALUE);
05356 static void io_encoding_set(rb_io_t *, VALUE, VALUE, VALUE);
05357
05358 static int
05359 io_strip_bom(VALUE io)
05360 {
05361 VALUE b1, b2, b3, b4;
05362
05363 if (NIL_P(b1 = rb_io_getbyte(io))) return 0;
05364 switch (b1) {
05365 case INT2FIX(0xEF):
05366 if (NIL_P(b2 = rb_io_getbyte(io))) break;
05367 if (b2 == INT2FIX(0xBB) && !NIL_P(b3 = rb_io_getbyte(io))) {
05368 if (b3 == INT2FIX(0xBF)) {
05369 return rb_utf8_encindex();
05370 }
05371 rb_io_ungetbyte(io, b3);
05372 }
05373 rb_io_ungetbyte(io, b2);
05374 break;
05375
05376 case INT2FIX(0xFE):
05377 if (NIL_P(b2 = rb_io_getbyte(io))) break;
05378 if (b2 == INT2FIX(0xFF)) {
05379 return rb_enc_find_index("UTF-16BE");
05380 }
05381 rb_io_ungetbyte(io, b2);
05382 break;
05383
05384 case INT2FIX(0xFF):
05385 if (NIL_P(b2 = rb_io_getbyte(io))) break;
05386 if (b2 == INT2FIX(0xFE)) {
05387 b3 = rb_io_getbyte(io);
05388 if (b3 == INT2FIX(0) && !NIL_P(b4 = rb_io_getbyte(io))) {
05389 if (b4 == INT2FIX(0)) {
05390 return rb_enc_find_index("UTF-32LE");
05391 }
05392 rb_io_ungetbyte(io, b4);
05393 rb_io_ungetbyte(io, b3);
05394 }
05395 else {
05396 rb_io_ungetbyte(io, b3);
05397 return rb_enc_find_index("UTF-16LE");
05398 }
05399 }
05400 rb_io_ungetbyte(io, b2);
05401 break;
05402
05403 case INT2FIX(0):
05404 if (NIL_P(b2 = rb_io_getbyte(io))) break;
05405 if (b2 == INT2FIX(0) && !NIL_P(b3 = rb_io_getbyte(io))) {
05406 if (b3 == INT2FIX(0xFE) && !NIL_P(b4 = rb_io_getbyte(io))) {
05407 if (b4 == INT2FIX(0xFF)) {
05408 return rb_enc_find_index("UTF-32BE");
05409 }
05410 rb_io_ungetbyte(io, b4);
05411 }
05412 rb_io_ungetbyte(io, b3);
05413 }
05414 rb_io_ungetbyte(io, b2);
05415 break;
05416 }
05417 rb_io_ungetbyte(io, b1);
05418 return 0;
05419 }
05420
05421 static void
05422 io_set_encoding_by_bom(VALUE io)
05423 {
05424 int idx = io_strip_bom(io);
05425 rb_io_t *fptr;
05426
05427 GetOpenFile(io, fptr);
05428 if (idx) {
05429 io_encoding_set(fptr, rb_enc_from_encoding(rb_enc_from_index(idx)),
05430 rb_io_internal_encoding(io), Qnil);
05431 }
05432 else {
05433 fptr->encs.enc2 = NULL;
05434 }
05435 }
05436
05437 static VALUE
05438 rb_file_open_generic(VALUE io, VALUE filename, int oflags, int fmode, convconfig_t *convconfig, mode_t perm)
05439 {
05440 rb_io_t *fptr;
05441 convconfig_t cc;
05442 if (!convconfig) {
05443
05444 rb_io_ext_int_to_encs(NULL, NULL, &cc.enc, &cc.enc2, fmode);
05445 cc.ecflags = 0;
05446 cc.ecopts = Qnil;
05447 convconfig = &cc;
05448 }
05449 validate_enc_binmode(&fmode, convconfig->ecflags,
05450 convconfig->enc, convconfig->enc2);
05451
05452 MakeOpenFile(io, fptr);
05453 fptr->mode = fmode;
05454 fptr->encs = *convconfig;
05455 fptr->pathv = rb_str_new_frozen(filename);
05456 fptr->fd = rb_sysopen(fptr->pathv, oflags, perm);
05457 io_check_tty(fptr);
05458 if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
05459
05460 return io;
05461 }
05462
05463 static VALUE
05464 rb_file_open_internal(VALUE io, VALUE filename, const char *modestr)
05465 {
05466 int fmode = rb_io_modestr_fmode(modestr);
05467 const char *p = strchr(modestr, ':');
05468 convconfig_t convconfig;
05469
05470 if (p) {
05471 parse_mode_enc(p+1, &convconfig.enc, &convconfig.enc2, &fmode);
05472 }
05473 else {
05474 rb_encoding *e;
05475
05476
05477 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
05478 rb_io_ext_int_to_encs(e, NULL, &convconfig.enc, &convconfig.enc2, fmode);
05479 convconfig.ecflags = 0;
05480 convconfig.ecopts = Qnil;
05481 }
05482
05483 return rb_file_open_generic(io, filename,
05484 rb_io_fmode_oflags(fmode),
05485 fmode,
05486 &convconfig,
05487 0666);
05488 }
05489
05490 VALUE
05491 rb_file_open_str(VALUE fname, const char *modestr)
05492 {
05493 FilePathValue(fname);
05494 return rb_file_open_internal(io_alloc(rb_cFile), fname, modestr);
05495 }
05496
05497 VALUE
05498 rb_file_open(const char *fname, const char *modestr)
05499 {
05500 return rb_file_open_internal(io_alloc(rb_cFile), rb_str_new_cstr(fname), modestr);
05501 }
05502
05503 #if defined(__CYGWIN__) || !defined(HAVE_FORK)
05504 static struct pipe_list {
05505 rb_io_t *fptr;
05506 struct pipe_list *next;
05507 } *pipe_list;
05508
05509 static void
05510 pipe_add_fptr(rb_io_t *fptr)
05511 {
05512 struct pipe_list *list;
05513
05514 list = ALLOC(struct pipe_list);
05515 list->fptr = fptr;
05516 list->next = pipe_list;
05517 pipe_list = list;
05518 }
05519
05520 static void
05521 pipe_del_fptr(rb_io_t *fptr)
05522 {
05523 struct pipe_list *list = pipe_list;
05524 struct pipe_list *tmp;
05525
05526 if (list->fptr == fptr) {
05527 pipe_list = list->next;
05528 free(list);
05529 return;
05530 }
05531
05532 while (list->next) {
05533 if (list->next->fptr == fptr) {
05534 tmp = list->next;
05535 list->next = list->next->next;
05536 free(tmp);
05537 return;
05538 }
05539 list = list->next;
05540 }
05541 }
05542
05543 static void
05544 pipe_atexit(void)
05545 {
05546 struct pipe_list *list = pipe_list;
05547 struct pipe_list *tmp;
05548
05549 while (list) {
05550 tmp = list->next;
05551 rb_io_fptr_finalize(list->fptr);
05552 list = tmp;
05553 }
05554 }
05555
05556 static void
05557 pipe_finalize(rb_io_t *fptr, int noraise)
05558 {
05559 #if !defined(HAVE_FORK) && !defined(_WIN32)
05560 int status = 0;
05561 if (fptr->stdio_file) {
05562 status = pclose(fptr->stdio_file);
05563 }
05564 fptr->fd = -1;
05565 fptr->stdio_file = 0;
05566 rb_last_status_set(status, fptr->pid);
05567 #else
05568 fptr_finalize(fptr, noraise);
05569 #endif
05570 pipe_del_fptr(fptr);
05571 }
05572 #endif
05573
05574 void
05575 rb_io_synchronized(rb_io_t *fptr)
05576 {
05577 rb_io_check_initialized(fptr);
05578 fptr->mode |= FMODE_SYNC;
05579 }
05580
05581 void
05582 rb_io_unbuffered(rb_io_t *fptr)
05583 {
05584 rb_io_synchronized(fptr);
05585 }
05586
05587 int
05588 rb_pipe(int *pipes)
05589 {
05590 int ret;
05591 ret = rb_cloexec_pipe(pipes);
05592 if (ret == -1) {
05593 if (errno == EMFILE || errno == ENFILE) {
05594 rb_gc();
05595 ret = rb_cloexec_pipe(pipes);
05596 }
05597 }
05598 if (ret == 0) {
05599 rb_update_max_fd(pipes[0]);
05600 rb_update_max_fd(pipes[1]);
05601 }
05602 return ret;
05603 }
05604
05605 #ifdef _WIN32
05606 #define HAVE_SPAWNV 1
05607 #define spawnv(mode, cmd, args) rb_w32_aspawn((mode), (cmd), (args))
05608 #define spawn(mode, cmd) rb_w32_spawn((mode), (cmd), 0)
05609 #endif
05610
05611 #if defined(HAVE_FORK) || defined(HAVE_SPAWNV)
05612 struct popen_arg {
05613 VALUE execarg_obj;
05614 struct rb_execarg *eargp;
05615 int modef;
05616 int pair[2];
05617 int write_pair[2];
05618 };
05619 #endif
05620
05621 #ifdef HAVE_FORK
05622 static void
05623 popen_redirect(struct popen_arg *p)
05624 {
05625 if ((p->modef & FMODE_READABLE) && (p->modef & FMODE_WRITABLE)) {
05626 close(p->write_pair[1]);
05627 if (p->write_pair[0] != 0) {
05628 dup2(p->write_pair[0], 0);
05629 close(p->write_pair[0]);
05630 }
05631 close(p->pair[0]);
05632 if (p->pair[1] != 1) {
05633 dup2(p->pair[1], 1);
05634 close(p->pair[1]);
05635 }
05636 }
05637 else if (p->modef & FMODE_READABLE) {
05638 close(p->pair[0]);
05639 if (p->pair[1] != 1) {
05640 dup2(p->pair[1], 1);
05641 close(p->pair[1]);
05642 }
05643 }
05644 else {
05645 close(p->pair[1]);
05646 if (p->pair[0] != 0) {
05647 dup2(p->pair[0], 0);
05648 close(p->pair[0]);
05649 }
05650 }
05651 }
05652
05653 #if defined(__linux__)
05654
05655
05656
05657
05658
05659
05660
05661
05662
05663 static int
05664 linux_get_maxfd(void)
05665 {
05666 int fd;
05667 char buf[4096], *p, *np, *e;
05668 ssize_t ss;
05669 fd = rb_cloexec_open("/proc/self/status", O_RDONLY|O_NOCTTY, 0);
05670 if (fd == -1) return -1;
05671 ss = read(fd, buf, sizeof(buf));
05672 if (ss == -1) goto err;
05673 p = buf;
05674 e = buf + ss;
05675 while ((int)sizeof("FDSize:\t0\n")-1 <= e-p &&
05676 (np = memchr(p, '\n', e-p)) != NULL) {
05677 if (memcmp(p, "FDSize:", sizeof("FDSize:")-1) == 0) {
05678 int fdsize;
05679 p += sizeof("FDSize:")-1;
05680 *np = '\0';
05681 fdsize = (int)ruby_strtoul(p, (char **)NULL, 10);
05682 close(fd);
05683 return fdsize;
05684 }
05685 p = np+1;
05686 }
05687
05688
05689 err:
05690 close(fd);
05691 return -1;
05692 }
05693 #endif
05694
05695
05696 void
05697 rb_close_before_exec(int lowfd, int maxhint, VALUE noclose_fds)
05698 {
05699 int fd, ret;
05700 int max = (int)max_file_descriptor;
05701 #ifdef F_MAXFD
05702
05703 ret = fcntl(0, F_MAXFD);
05704 if (ret != -1)
05705 maxhint = max = ret;
05706 #elif defined(__linux__)
05707 ret = linux_get_maxfd();
05708 if (maxhint < ret)
05709 maxhint = ret;
05710
05711 #endif
05712 if (max < maxhint)
05713 max = maxhint;
05714 for (fd = lowfd; fd <= max; fd++) {
05715 if (!NIL_P(noclose_fds) &&
05716 RTEST(rb_hash_lookup(noclose_fds, INT2FIX(fd))))
05717 continue;
05718 ret = fcntl(fd, F_GETFD);
05719 if (ret != -1 && !(ret & FD_CLOEXEC)) {
05720 fcntl(fd, F_SETFD, ret|FD_CLOEXEC);
05721 }
05722 #define CONTIGUOUS_CLOSED_FDS 20
05723 if (ret != -1) {
05724 if (max < fd + CONTIGUOUS_CLOSED_FDS)
05725 max = fd + CONTIGUOUS_CLOSED_FDS;
05726 }
05727 }
05728 }
05729
05730 static int
05731 popen_exec(void *pp, char *errmsg, size_t errmsg_len)
05732 {
05733 struct popen_arg *p = (struct popen_arg*)pp;
05734
05735 return rb_exec_async_signal_safe(p->eargp, errmsg, errmsg_len);
05736 }
05737 #endif
05738
05739 static VALUE
05740 pipe_open(VALUE execarg_obj, const char *modestr, int fmode, convconfig_t *convconfig)
05741 {
05742 struct rb_execarg *eargp = NIL_P(execarg_obj) ? NULL : rb_execarg_get(execarg_obj);
05743 VALUE prog = eargp ? (eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name) : Qfalse ;
05744 rb_pid_t pid = 0;
05745 rb_io_t *fptr;
05746 VALUE port;
05747 rb_io_t *write_fptr;
05748 VALUE write_port;
05749 #if defined(HAVE_FORK)
05750 int status;
05751 char errmsg[80] = { '\0' };
05752 #endif
05753 #if defined(HAVE_FORK) || defined(HAVE_SPAWNV)
05754 struct popen_arg arg;
05755 int e = 0;
05756 #endif
05757 #if defined(HAVE_SPAWNV)
05758 # if defined(HAVE_SPAWNVE)
05759 # define DO_SPAWN(cmd, args, envp) ((args) ? \
05760 spawnve(P_NOWAIT, (cmd), (args), (envp)) : \
05761 spawne(P_NOWAIT, (cmd), (envp)))
05762 # else
05763 # define DO_SPAWN(cmd, args, envp) ((args) ? \
05764 spawnv(P_NOWAIT, (cmd), (args)) : \
05765 spawn(P_NOWAIT, (cmd)))
05766 # endif
05767 # if !defined(HAVE_FORK)
05768 char **args = NULL;
05769 # if defined(HAVE_SPAWNVE)
05770 char **envp = NULL;
05771 # endif
05772 # endif
05773 #endif
05774 #if !defined(HAVE_FORK)
05775 struct rb_execarg sarg, *sargp = &sarg;
05776 #endif
05777 FILE *fp = 0;
05778 int fd = -1;
05779 int write_fd = -1;
05780 #if !defined(HAVE_FORK)
05781 const char *cmd = 0;
05782 #if !defined(HAVE_SPAWNV)
05783 int argc;
05784 VALUE *argv;
05785 #endif
05786
05787 if (prog)
05788 cmd = StringValueCStr(prog);
05789 #endif
05790
05791 #if defined(HAVE_FORK) || defined(HAVE_SPAWNV)
05792 arg.execarg_obj = execarg_obj;
05793 arg.eargp = eargp;
05794 arg.modef = fmode;
05795 arg.pair[0] = arg.pair[1] = -1;
05796 arg.write_pair[0] = arg.write_pair[1] = -1;
05797 # if !defined(HAVE_FORK)
05798 if (eargp && !eargp->use_shell) {
05799 args = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
05800 }
05801 # endif
05802 switch (fmode & (FMODE_READABLE|FMODE_WRITABLE)) {
05803 case FMODE_READABLE|FMODE_WRITABLE:
05804 if (rb_pipe(arg.write_pair) < 0)
05805 rb_sys_fail_str(prog);
05806 if (rb_pipe(arg.pair) < 0) {
05807 int e = errno;
05808 close(arg.write_pair[0]);
05809 close(arg.write_pair[1]);
05810 errno = e;
05811 rb_sys_fail_str(prog);
05812 }
05813 if (eargp) {
05814 rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.write_pair[0]));
05815 rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
05816 }
05817 break;
05818 case FMODE_READABLE:
05819 if (rb_pipe(arg.pair) < 0)
05820 rb_sys_fail_str(prog);
05821 if (eargp)
05822 rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
05823 break;
05824 case FMODE_WRITABLE:
05825 if (rb_pipe(arg.pair) < 0)
05826 rb_sys_fail_str(prog);
05827 if (eargp)
05828 rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.pair[0]));
05829 break;
05830 default:
05831 rb_sys_fail_str(prog);
05832 }
05833 if (!NIL_P(execarg_obj)) {
05834 rb_execarg_fixup(execarg_obj);
05835 # if defined(HAVE_FORK)
05836 pid = rb_fork_async_signal_safe(&status, popen_exec, &arg, arg.eargp->redirect_fds, errmsg, sizeof(errmsg));
05837 # else
05838 rb_execarg_run_options(eargp, sargp, NULL, 0);
05839 # if defined(HAVE_SPAWNVE)
05840 if (eargp->envp_str) envp = (char **)RSTRING_PTR(eargp->envp_str);
05841 # endif
05842 while ((pid = DO_SPAWN(cmd, args, envp)) == -1) {
05843
05844 switch (e = errno) {
05845 case EAGAIN:
05846 # if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
05847 case EWOULDBLOCK:
05848 # endif
05849 rb_thread_sleep(1);
05850 continue;
05851 }
05852 break;
05853 }
05854 if (eargp)
05855 rb_execarg_run_options(sargp, NULL, NULL, 0);
05856 # endif
05857 }
05858 else {
05859 # if defined(HAVE_FORK)
05860 pid = rb_fork_ruby(&status);
05861 if (pid == 0) {
05862 rb_thread_atfork();
05863 popen_redirect(&arg);
05864 rb_io_synchronized(RFILE(orig_stdout)->fptr);
05865 rb_io_synchronized(RFILE(orig_stderr)->fptr);
05866 return Qnil;
05867 }
05868 # else
05869 rb_notimplement();
05870 # endif
05871 }
05872
05873
05874 if (pid == -1) {
05875 # if defined(HAVE_FORK)
05876 e = errno;
05877 # endif
05878 close(arg.pair[0]);
05879 close(arg.pair[1]);
05880 if ((fmode & (FMODE_READABLE|FMODE_WRITABLE)) == (FMODE_READABLE|FMODE_WRITABLE)) {
05881 close(arg.write_pair[0]);
05882 close(arg.write_pair[1]);
05883 }
05884 errno = e;
05885 # if defined(HAVE_FORK)
05886 if (errmsg[0])
05887 rb_sys_fail(errmsg);
05888 # endif
05889 rb_sys_fail_str(prog);
05890 }
05891 if ((fmode & FMODE_READABLE) && (fmode & FMODE_WRITABLE)) {
05892 close(arg.pair[1]);
05893 fd = arg.pair[0];
05894 close(arg.write_pair[0]);
05895 write_fd = arg.write_pair[1];
05896 }
05897 else if (fmode & FMODE_READABLE) {
05898 close(arg.pair[1]);
05899 fd = arg.pair[0];
05900 }
05901 else {
05902 close(arg.pair[0]);
05903 fd = arg.pair[1];
05904 }
05905 #else
05906 if (argc) {
05907 prog = rb_ary_join(rb_ary_new4(argc, argv), rb_str_new2(" "));
05908 cmd = StringValueCStr(prog);
05909 }
05910 if (!NIL_P(execarg_obj)) {
05911 rb_execarg_fixup(execarg_obj);
05912 rb_execarg_run_options(eargp, sargp, NULL, 0);
05913 }
05914 fp = popen(cmd, modestr);
05915 if (eargp)
05916 rb_execarg_run_options(sargp, NULL, NULL, 0);
05917 if (!fp) rb_sys_fail_path(prog);
05918 fd = fileno(fp);
05919 #endif
05920
05921 port = io_alloc(rb_cIO);
05922 MakeOpenFile(port, fptr);
05923 fptr->fd = fd;
05924 fptr->stdio_file = fp;
05925 fptr->mode = fmode | FMODE_SYNC|FMODE_DUPLEX;
05926 if (convconfig) {
05927 fptr->encs = *convconfig;
05928 #if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)
05929 if (fptr->encs.ecflags & ECONV_DEFAULT_NEWLINE_DECORATOR) {
05930 fptr->encs.ecflags |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;
05931 }
05932 #endif
05933 }
05934 else {
05935 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
05936 fptr->encs.ecflags |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;
05937 }
05938 #ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
05939 if (NEED_NEWLINE_DECORATOR_ON_WRITE(fptr)) {
05940 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
05941 }
05942 #endif
05943 }
05944 fptr->pid = pid;
05945
05946 if (0 <= write_fd) {
05947 write_port = io_alloc(rb_cIO);
05948 MakeOpenFile(write_port, write_fptr);
05949 write_fptr->fd = write_fd;
05950 write_fptr->mode = (fmode & ~FMODE_READABLE)| FMODE_SYNC|FMODE_DUPLEX;
05951 fptr->mode &= ~FMODE_WRITABLE;
05952 fptr->tied_io_for_writing = write_port;
05953 rb_ivar_set(port, rb_intern("@tied_io_for_writing"), write_port);
05954 }
05955
05956 #if defined (__CYGWIN__) || !defined(HAVE_FORK)
05957 fptr->finalize = pipe_finalize;
05958 pipe_add_fptr(fptr);
05959 #endif
05960 return port;
05961 }
05962
05963 static int
05964 is_popen_fork(VALUE prog)
05965 {
05966 if (RSTRING_LEN(prog) == 1 && RSTRING_PTR(prog)[0] == '-') {
05967 #if !defined(HAVE_FORK)
05968 rb_raise(rb_eNotImpError,
05969 "fork() function is unimplemented on this machine");
05970 #else
05971 return TRUE;
05972 #endif
05973 }
05974 return FALSE;
05975 }
05976
05977 static VALUE
05978 pipe_open_s(VALUE prog, const char *modestr, int fmode, convconfig_t *convconfig)
05979 {
05980 int argc = 1;
05981 VALUE *argv = &prog;
05982 VALUE execarg_obj = Qnil;
05983
05984 if (!is_popen_fork(prog))
05985 execarg_obj = rb_execarg_new(argc, argv, TRUE);
05986 return pipe_open(execarg_obj, modestr, fmode, convconfig);
05987 }
05988
05989
05990
05991
05992
05993
05994
05995
05996
05997
05998
05999
06000
06001
06002
06003
06004
06005
06006
06007
06008
06009
06010
06011
06012
06013
06014
06015
06016
06017
06018
06019
06020
06021
06022
06023
06024
06025
06026
06027
06028
06029
06030
06031
06032
06033
06034
06035
06036
06037
06038
06039
06040
06041
06042
06043
06044
06045
06046
06047
06048
06049
06050
06051
06052
06053
06054
06055
06056
06057
06058
06059
06060
06061
06062
06063
06064
06065
06066
06067
06068
06069
06070
06071
06072
06073
06074
06075
06076
06077 static VALUE
06078 rb_io_s_popen(int argc, VALUE *argv, VALUE klass)
06079 {
06080 const char *modestr;
06081 VALUE pname, pmode = Qnil, port, tmp, opt = Qnil, env = Qnil, execarg_obj = Qnil;
06082 int oflags, fmode;
06083 convconfig_t convconfig;
06084
06085 if (argc > 1 && !NIL_P(opt = rb_check_hash_type(argv[argc-1]))) --argc;
06086 if (argc > 1 && !NIL_P(env = rb_check_hash_type(argv[0]))) --argc, ++argv;
06087 switch (argc) {
06088 case 2:
06089 pmode = argv[1];
06090 case 1:
06091 pname = argv[0];
06092 break;
06093 default:
06094 {
06095 int ex = !NIL_P(opt);
06096 rb_error_arity(argc + ex, 1 + ex, 2 + ex);
06097 }
06098 }
06099
06100 tmp = rb_check_array_type(pname);
06101 if (!NIL_P(tmp)) {
06102 long len = RARRAY_LEN(tmp);
06103 #if SIZEOF_LONG > SIZEOF_INT
06104 if (len > INT_MAX) {
06105 rb_raise(rb_eArgError, "too many arguments");
06106 }
06107 #endif
06108 tmp = rb_ary_dup(tmp);
06109 RBASIC(tmp)->klass = 0;
06110 execarg_obj = rb_execarg_new((int)len, RARRAY_PTR(tmp), FALSE);
06111 rb_ary_clear(tmp);
06112 }
06113 else {
06114 SafeStringValue(pname);
06115 execarg_obj = Qnil;
06116 if (!is_popen_fork(pname))
06117 execarg_obj = rb_execarg_new(1, &pname, TRUE);
06118 }
06119 if (!NIL_P(execarg_obj)) {
06120 if (!NIL_P(opt))
06121 opt = rb_execarg_extract_options(execarg_obj, opt);
06122 if (!NIL_P(env))
06123 rb_execarg_setenv(execarg_obj, env);
06124 }
06125 rb_io_extract_modeenc(&pmode, 0, opt, &oflags, &fmode, &convconfig);
06126 modestr = rb_io_oflags_modestr(oflags);
06127
06128 port = pipe_open(execarg_obj, modestr, fmode, &convconfig);
06129 if (NIL_P(port)) {
06130
06131 if (rb_block_given_p()) {
06132 rb_yield(Qnil);
06133 rb_io_flush(rb_stdout);
06134 rb_io_flush(rb_stderr);
06135 _exit(0);
06136 }
06137 return Qnil;
06138 }
06139 RBASIC(port)->klass = klass;
06140 if (rb_block_given_p()) {
06141 return rb_ensure(rb_yield, port, io_close, port);
06142 }
06143 return port;
06144 }
06145
06146 static void
06147 rb_scan_open_args(int argc, VALUE *argv,
06148 VALUE *fname_p, int *oflags_p, int *fmode_p,
06149 convconfig_t *convconfig_p, mode_t *perm_p)
06150 {
06151 VALUE opt, fname, vmode, vperm;
06152 int oflags, fmode;
06153 mode_t perm;
06154
06155 argc = rb_scan_args(argc, argv, "12:", &fname, &vmode, &vperm, &opt);
06156 FilePathValue(fname);
06157
06158 rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, convconfig_p);
06159
06160 perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
06161
06162 *fname_p = fname;
06163 *oflags_p = oflags;
06164 *fmode_p = fmode;
06165 *perm_p = perm;
06166 }
06167
06168 static VALUE
06169 rb_open_file(int argc, VALUE *argv, VALUE io)
06170 {
06171 VALUE fname;
06172 int oflags, fmode;
06173 convconfig_t convconfig;
06174 mode_t perm;
06175
06176 rb_scan_open_args(argc, argv, &fname, &oflags, &fmode, &convconfig, &perm);
06177 rb_file_open_generic(io, fname, oflags, fmode, &convconfig, perm);
06178
06179 return io;
06180 }
06181
06182
06183
06184
06185
06186
06187
06188
06189
06190
06191
06192
06193
06194
06195
06196
06197
06198
06199
06200
06201
06202
06203
06204
06205
06206
06207
06208
06209
06210
06211
06212
06213
06214
06215
06216
06217
06218
06219 static VALUE
06220 rb_io_s_open(int argc, VALUE *argv, VALUE klass)
06221 {
06222 VALUE io = rb_class_new_instance(argc, argv, klass);
06223
06224 if (rb_block_given_p()) {
06225 return rb_ensure(rb_yield, io, io_close, io);
06226 }
06227
06228 return io;
06229 }
06230
06231
06232
06233
06234
06235
06236
06237
06238
06239
06240
06241 static VALUE
06242 rb_io_s_sysopen(int argc, VALUE *argv)
06243 {
06244 VALUE fname, vmode, vperm;
06245 VALUE intmode;
06246 int oflags, fd;
06247 mode_t perm;
06248
06249 rb_scan_args(argc, argv, "12", &fname, &vmode, &vperm);
06250 FilePathValue(fname);
06251
06252 if (NIL_P(vmode))
06253 oflags = O_RDONLY;
06254 else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int")))
06255 oflags = NUM2INT(intmode);
06256 else {
06257 SafeStringValue(vmode);
06258 oflags = rb_io_modestr_oflags(StringValueCStr(vmode));
06259 }
06260 if (NIL_P(vperm)) perm = 0666;
06261 else perm = NUM2MODET(vperm);
06262
06263 RB_GC_GUARD(fname) = rb_str_new4(fname);
06264 fd = rb_sysopen(fname, oflags, perm);
06265 return INT2NUM(fd);
06266 }
06267
06268 static VALUE
06269 check_pipe_command(VALUE filename_or_command)
06270 {
06271 char *s = RSTRING_PTR(filename_or_command);
06272 long l = RSTRING_LEN(filename_or_command);
06273 char *e = s + l;
06274 int chlen;
06275
06276 if (rb_enc_ascget(s, e, &chlen, rb_enc_get(filename_or_command)) == '|') {
06277 VALUE cmd = rb_str_new(s+chlen, l-chlen);
06278 OBJ_INFECT(cmd, filename_or_command);
06279 return cmd;
06280 }
06281 return Qnil;
06282 }
06283
06284
06285
06286
06287
06288
06289
06290
06291
06292
06293
06294
06295
06296
06297
06298
06299
06300
06301
06302
06303
06304
06305
06306
06307
06308
06309
06310
06311
06312
06313
06314
06315
06316
06317
06318
06319
06320
06321
06322
06323
06324
06325
06326
06327
06328
06329
06330
06331
06332
06333
06334
06335
06336
06337
06338
06339
06340
06341
06342
06343
06344
06345
06346
06347
06348
06349
06350
06351
06352
06353
06354
06355
06356
06357
06358
06359
06360
06361
06362
06363
06364
06365
06366
06367
06368
06369
06370
06371
06372
06373
06374
06375
06376
06377
06378
06379
06380
06381
06382 static VALUE
06383 rb_f_open(int argc, VALUE *argv)
06384 {
06385 ID to_open = 0;
06386 int redirect = FALSE;
06387
06388 if (argc >= 1) {
06389 CONST_ID(to_open, "to_open");
06390 if (rb_respond_to(argv[0], to_open)) {
06391 redirect = TRUE;
06392 }
06393 else {
06394 VALUE tmp = argv[0];
06395 FilePathValue(tmp);
06396 if (NIL_P(tmp)) {
06397 redirect = TRUE;
06398 }
06399 else {
06400 VALUE cmd = check_pipe_command(tmp);
06401 if (!NIL_P(cmd)) {
06402 argv[0] = cmd;
06403 return rb_io_s_popen(argc, argv, rb_cIO);
06404 }
06405 }
06406 }
06407 }
06408 if (redirect) {
06409 VALUE io = rb_funcall2(argv[0], to_open, argc-1, argv+1);
06410
06411 if (rb_block_given_p()) {
06412 return rb_ensure(rb_yield, io, io_close, io);
06413 }
06414 return io;
06415 }
06416 return rb_io_s_open(argc, argv, rb_cFile);
06417 }
06418
06419 static VALUE
06420 rb_io_open(VALUE filename, VALUE vmode, VALUE vperm, VALUE opt)
06421 {
06422 VALUE cmd;
06423 int oflags, fmode;
06424 convconfig_t convconfig;
06425 mode_t perm;
06426
06427 rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, &convconfig);
06428 perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
06429
06430 if (!NIL_P(cmd = check_pipe_command(filename))) {
06431 return pipe_open_s(cmd, rb_io_oflags_modestr(oflags), fmode, &convconfig);
06432 }
06433 else {
06434 return rb_file_open_generic(io_alloc(rb_cFile), filename,
06435 oflags, fmode, &convconfig, perm);
06436 }
06437 }
06438
06439 static VALUE
06440 rb_io_open_with_args(int argc, VALUE *argv)
06441 {
06442 VALUE io;
06443
06444 io = io_alloc(rb_cFile);
06445 rb_open_file(argc, argv, io);
06446 return io;
06447 }
06448
06449 static VALUE
06450 io_reopen(VALUE io, VALUE nfile)
06451 {
06452 rb_io_t *fptr, *orig;
06453 int fd, fd2;
06454 off_t pos = 0;
06455
06456 nfile = rb_io_get_io(nfile);
06457 if (rb_safe_level() >= 4 &&
06458 (!OBJ_UNTRUSTED(io) || !OBJ_UNTRUSTED(nfile))) {
06459 rb_raise(rb_eSecurityError, "Insecure: can't reopen");
06460 }
06461 GetOpenFile(io, fptr);
06462 GetOpenFile(nfile, orig);
06463
06464 if (fptr == orig) return io;
06465 if (IS_PREP_STDIO(fptr)) {
06466 if ((fptr->stdio_file == stdin && !(orig->mode & FMODE_READABLE)) ||
06467 (fptr->stdio_file == stdout && !(orig->mode & FMODE_WRITABLE)) ||
06468 (fptr->stdio_file == stderr && !(orig->mode & FMODE_WRITABLE))) {
06469 rb_raise(rb_eArgError,
06470 "%s can't change access mode from \"%s\" to \"%s\"",
06471 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
06472 rb_io_fmode_modestr(orig->mode));
06473 }
06474 }
06475 if (fptr->mode & FMODE_WRITABLE) {
06476 if (io_fflush(fptr) < 0)
06477 rb_sys_fail(0);
06478 }
06479 else {
06480 io_tell(fptr);
06481 }
06482 if (orig->mode & FMODE_READABLE) {
06483 pos = io_tell(orig);
06484 }
06485 if (orig->mode & FMODE_WRITABLE) {
06486 if (io_fflush(orig) < 0)
06487 rb_sys_fail(0);
06488 }
06489
06490
06491 fptr->mode = orig->mode | (fptr->mode & FMODE_PREP);
06492 fptr->pid = orig->pid;
06493 fptr->lineno = orig->lineno;
06494 if (RTEST(orig->pathv)) fptr->pathv = orig->pathv;
06495 else if (!IS_PREP_STDIO(fptr)) fptr->pathv = Qnil;
06496 fptr->finalize = orig->finalize;
06497 #if defined (__CYGWIN__) || !defined(HAVE_FORK)
06498 if (fptr->finalize == pipe_finalize)
06499 pipe_add_fptr(fptr);
06500 #endif
06501
06502 fd = fptr->fd;
06503 fd2 = orig->fd;
06504 if (fd != fd2) {
06505 if (IS_PREP_STDIO(fptr) || fd <= 2 || !fptr->stdio_file) {
06506
06507 if (rb_cloexec_dup2(fd2, fd) < 0)
06508 rb_sys_fail_path(orig->pathv);
06509 rb_update_max_fd(fd);
06510 }
06511 else {
06512 fclose(fptr->stdio_file);
06513 fptr->stdio_file = 0;
06514 fptr->fd = -1;
06515 if (rb_cloexec_dup2(fd2, fd) < 0)
06516 rb_sys_fail_path(orig->pathv);
06517 rb_update_max_fd(fd);
06518 fptr->fd = fd;
06519 }
06520 rb_thread_fd_close(fd);
06521 if ((orig->mode & FMODE_READABLE) && pos >= 0) {
06522 if (io_seek(fptr, pos, SEEK_SET) < 0 && errno) {
06523 rb_sys_fail_path(fptr->pathv);
06524 }
06525 if (io_seek(orig, pos, SEEK_SET) < 0 && errno) {
06526 rb_sys_fail_path(orig->pathv);
06527 }
06528 }
06529 }
06530
06531 if (fptr->mode & FMODE_BINMODE) {
06532 rb_io_binmode(io);
06533 }
06534
06535 RBASIC(io)->klass = rb_obj_class(nfile);
06536 return io;
06537 }
06538
06539
06540
06541
06542
06543
06544
06545
06546
06547
06548
06549
06550
06551
06552
06553
06554
06555 static VALUE
06556 rb_io_reopen(int argc, VALUE *argv, VALUE file)
06557 {
06558 VALUE fname, nmode, opt;
06559 int oflags;
06560 rb_io_t *fptr;
06561
06562 rb_secure(4);
06563 if (rb_scan_args(argc, argv, "11:", &fname, &nmode, &opt) == 1) {
06564 VALUE tmp = rb_io_check_io(fname);
06565 if (!NIL_P(tmp)) {
06566 return io_reopen(file, tmp);
06567 }
06568 }
06569
06570 FilePathValue(fname);
06571 rb_io_taint_check(file);
06572 fptr = RFILE(file)->fptr;
06573 if (!fptr) {
06574 fptr = RFILE(file)->fptr = ALLOC(rb_io_t);
06575 MEMZERO(fptr, rb_io_t, 1);
06576 }
06577
06578 if (!NIL_P(nmode) || !NIL_P(opt)) {
06579 int fmode;
06580 convconfig_t convconfig;
06581
06582 rb_io_extract_modeenc(&nmode, 0, opt, &oflags, &fmode, &convconfig);
06583 if (IS_PREP_STDIO(fptr) &&
06584 ((fptr->mode & FMODE_READWRITE) & (fmode & FMODE_READWRITE)) !=
06585 (fptr->mode & FMODE_READWRITE)) {
06586 rb_raise(rb_eArgError,
06587 "%s can't change access mode from \"%s\" to \"%s\"",
06588 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
06589 rb_io_fmode_modestr(fmode));
06590 }
06591 fptr->mode = fmode;
06592 fptr->encs = convconfig;
06593 }
06594 else {
06595 oflags = rb_io_fmode_oflags(fptr->mode);
06596 }
06597
06598 fptr->pathv = rb_str_new_frozen(fname);
06599 if (fptr->fd < 0) {
06600 fptr->fd = rb_sysopen(fptr->pathv, oflags, 0666);
06601 fptr->stdio_file = 0;
06602 return file;
06603 }
06604
06605 if (fptr->mode & FMODE_WRITABLE) {
06606 if (io_fflush(fptr) < 0)
06607 rb_sys_fail(0);
06608 }
06609 fptr->rbuf.off = fptr->rbuf.len = 0;
06610
06611 if (fptr->stdio_file) {
06612 if (freopen(RSTRING_PTR(fptr->pathv), rb_io_oflags_modestr(oflags), fptr->stdio_file) == 0) {
06613 rb_sys_fail_path(fptr->pathv);
06614 }
06615 fptr->fd = fileno(fptr->stdio_file);
06616 rb_fd_fix_cloexec(fptr->fd);
06617 #ifdef USE_SETVBUF
06618 if (setvbuf(fptr->stdio_file, NULL, _IOFBF, 0) != 0)
06619 rb_warn("setvbuf() can't be honoured for %s", RSTRING_PTR(fptr->pathv));
06620 #endif
06621 if (fptr->stdio_file == stderr) {
06622 if (setvbuf(fptr->stdio_file, NULL, _IONBF, BUFSIZ) != 0)
06623 rb_warn("setvbuf() can't be honoured for %s", RSTRING_PTR(fptr->pathv));
06624 }
06625 else if (fptr->stdio_file == stdout && isatty(fptr->fd)) {
06626 if (setvbuf(fptr->stdio_file, NULL, _IOLBF, BUFSIZ) != 0)
06627 rb_warn("setvbuf() can't be honoured for %s", RSTRING_PTR(fptr->pathv));
06628 }
06629 }
06630 else {
06631 int tmpfd = rb_sysopen(fptr->pathv, oflags, 0666);
06632 int err = 0;
06633 if (rb_cloexec_dup2(tmpfd, fptr->fd) < 0)
06634 err = errno;
06635 (void)close(tmpfd);
06636 if (err) {
06637 rb_sys_fail_path(fptr->pathv);
06638 }
06639 }
06640
06641 return file;
06642 }
06643
06644
06645 static VALUE
06646 rb_io_init_copy(VALUE dest, VALUE io)
06647 {
06648 rb_io_t *fptr, *orig;
06649 int fd;
06650 VALUE write_io;
06651 off_t pos;
06652
06653 io = rb_io_get_io(io);
06654 if (!OBJ_INIT_COPY(dest, io)) return dest;
06655 GetOpenFile(io, orig);
06656 MakeOpenFile(dest, fptr);
06657
06658 rb_io_flush(io);
06659
06660
06661 fptr->mode = orig->mode & ~FMODE_PREP;
06662 fptr->encs = orig->encs;
06663 fptr->pid = orig->pid;
06664 fptr->lineno = orig->lineno;
06665 if (!NIL_P(orig->pathv)) fptr->pathv = orig->pathv;
06666 fptr->finalize = orig->finalize;
06667 #if defined (__CYGWIN__) || !defined(HAVE_FORK)
06668 if (fptr->finalize == pipe_finalize)
06669 pipe_add_fptr(fptr);
06670 #endif
06671
06672 fd = ruby_dup(orig->fd);
06673 fptr->fd = fd;
06674 pos = io_tell(orig);
06675 if (0 <= pos)
06676 io_seek(fptr, pos, SEEK_SET);
06677 if (fptr->mode & FMODE_BINMODE) {
06678 rb_io_binmode(dest);
06679 }
06680
06681 write_io = GetWriteIO(io);
06682 if (io != write_io) {
06683 write_io = rb_obj_dup(write_io);
06684 fptr->tied_io_for_writing = write_io;
06685 rb_ivar_set(dest, rb_intern("@tied_io_for_writing"), write_io);
06686 }
06687
06688 return dest;
06689 }
06690
06691
06692
06693
06694
06695
06696
06697
06698
06699
06700 VALUE
06701 rb_io_printf(int argc, VALUE *argv, VALUE out)
06702 {
06703 rb_io_write(out, rb_f_sprintf(argc, argv));
06704 return Qnil;
06705 }
06706
06707
06708
06709
06710
06711
06712
06713
06714
06715
06716
06717
06718 static VALUE
06719 rb_f_printf(int argc, VALUE *argv)
06720 {
06721 VALUE out;
06722
06723 if (argc == 0) return Qnil;
06724 if (RB_TYPE_P(argv[0], T_STRING)) {
06725 out = rb_stdout;
06726 }
06727 else {
06728 out = argv[0];
06729 argv++;
06730 argc--;
06731 }
06732 rb_io_write(out, rb_f_sprintf(argc, argv));
06733
06734 return Qnil;
06735 }
06736
06737
06738
06739
06740
06741
06742
06743
06744
06745
06746
06747
06748
06749
06750
06751
06752
06753
06754
06755
06756
06757
06758
06759 VALUE
06760 rb_io_print(int argc, VALUE *argv, VALUE out)
06761 {
06762 int i;
06763 VALUE line;
06764
06765
06766 if (argc == 0) {
06767 argc = 1;
06768 line = rb_lastline_get();
06769 argv = &line;
06770 }
06771 for (i=0; i<argc; i++) {
06772 if (!NIL_P(rb_output_fs) && i>0) {
06773 rb_io_write(out, rb_output_fs);
06774 }
06775 rb_io_write(out, argv[i]);
06776 }
06777 if (argc > 0 && !NIL_P(rb_output_rs)) {
06778 rb_io_write(out, rb_output_rs);
06779 }
06780
06781 return Qnil;
06782 }
06783
06784
06785
06786
06787
06788
06789
06790
06791
06792
06793
06794
06795
06796
06797
06798
06799
06800
06801
06802
06803
06804
06805
06806
06807 static VALUE
06808 rb_f_print(int argc, VALUE *argv)
06809 {
06810 rb_io_print(argc, argv, rb_stdout);
06811 return Qnil;
06812 }
06813
06814
06815
06816
06817
06818
06819
06820
06821
06822
06823
06824
06825
06826
06827
06828
06829
06830
06831
06832 static VALUE
06833 rb_io_putc(VALUE io, VALUE ch)
06834 {
06835 VALUE str;
06836 if (RB_TYPE_P(ch, T_STRING)) {
06837 str = rb_str_substr(ch, 0, 1);
06838 }
06839 else {
06840 char c = NUM2CHR(ch);
06841 str = rb_str_new(&c, 1);
06842 }
06843 rb_io_write(io, str);
06844 return ch;
06845 }
06846
06847
06848
06849
06850
06851
06852
06853
06854
06855
06856
06857
06858
06859 static VALUE
06860 rb_f_putc(VALUE recv, VALUE ch)
06861 {
06862 if (recv == rb_stdout) {
06863 return rb_io_putc(recv, ch);
06864 }
06865 return rb_funcall2(rb_stdout, rb_intern("putc"), 1, &ch);
06866 }
06867
06868
06869 static int
06870 str_end_with_asciichar(VALUE str, int c)
06871 {
06872 long len = RSTRING_LEN(str);
06873 const char *ptr = RSTRING_PTR(str);
06874 rb_encoding *enc = rb_enc_from_index(ENCODING_GET(str));
06875 int n;
06876
06877 if (len == 0) return 0;
06878 if ((n = rb_enc_mbminlen(enc)) == 1) {
06879 return ptr[len - 1] == c;
06880 }
06881 return rb_enc_ascget(ptr + ((len - 1) / n) * n, ptr + len, &n, enc) == c;
06882 }
06883
06884 static VALUE
06885 io_puts_ary(VALUE ary, VALUE out, int recur)
06886 {
06887 VALUE tmp;
06888 long i;
06889
06890 if (recur) {
06891 tmp = rb_str_new2("[...]");
06892 rb_io_puts(1, &tmp, out);
06893 return Qtrue;
06894 }
06895 ary = rb_check_array_type(ary);
06896 if (NIL_P(ary)) return Qfalse;
06897 for (i=0; i<RARRAY_LEN(ary); i++) {
06898 tmp = RARRAY_PTR(ary)[i];
06899 rb_io_puts(1, &tmp, out);
06900 }
06901 return Qtrue;
06902 }
06903
06904
06905
06906
06907
06908
06909
06910
06911
06912
06913
06914
06915
06916
06917
06918
06919
06920
06921
06922
06923
06924 VALUE
06925 rb_io_puts(int argc, VALUE *argv, VALUE out)
06926 {
06927 int i;
06928 VALUE line;
06929
06930
06931 if (argc == 0) {
06932 rb_io_write(out, rb_default_rs);
06933 return Qnil;
06934 }
06935 for (i=0; i<argc; i++) {
06936 if (RB_TYPE_P(argv[i], T_STRING)) {
06937 line = argv[i];
06938 goto string;
06939 }
06940 if (rb_exec_recursive(io_puts_ary, argv[i], out)) {
06941 continue;
06942 }
06943 line = rb_obj_as_string(argv[i]);
06944 string:
06945 rb_io_write(out, line);
06946 if (RSTRING_LEN(line) == 0 ||
06947 !str_end_with_asciichar(line, '\n')) {
06948 rb_io_write(out, rb_default_rs);
06949 }
06950 }
06951
06952 return Qnil;
06953 }
06954
06955
06956
06957
06958
06959
06960
06961
06962
06963
06964 static VALUE
06965 rb_f_puts(int argc, VALUE *argv, VALUE recv)
06966 {
06967 if (recv == rb_stdout) {
06968 return rb_io_puts(argc, argv, recv);
06969 }
06970 return rb_funcall2(rb_stdout, rb_intern("puts"), argc, argv);
06971 }
06972
06973 void
06974 rb_p(VALUE obj)
06975 {
06976 VALUE str = rb_obj_as_string(rb_inspect(obj));
06977 if (RB_TYPE_P(rb_stdout, T_FILE) &&
06978 rb_method_basic_definition_p(CLASS_OF(rb_stdout), id_write)) {
06979 io_write(rb_stdout, str, 1);
06980 io_write(rb_stdout, rb_default_rs, 0);
06981 }
06982 else {
06983 rb_io_write(rb_stdout, str);
06984 rb_io_write(rb_stdout, rb_default_rs);
06985 }
06986 }
06987
06988 struct rb_f_p_arg {
06989 int argc;
06990 VALUE *argv;
06991 };
06992
06993 static VALUE
06994 rb_f_p_internal(VALUE arg)
06995 {
06996 struct rb_f_p_arg *arg1 = (struct rb_f_p_arg*)arg;
06997 int argc = arg1->argc;
06998 VALUE *argv = arg1->argv;
06999 int i;
07000 VALUE ret = Qnil;
07001
07002 for (i=0; i<argc; i++) {
07003 rb_p(argv[i]);
07004 }
07005 if (argc == 1) {
07006 ret = argv[0];
07007 }
07008 else if (argc > 1) {
07009 ret = rb_ary_new4(argc, argv);
07010 }
07011 if (RB_TYPE_P(rb_stdout, T_FILE)) {
07012 rb_io_flush(rb_stdout);
07013 }
07014 return ret;
07015 }
07016
07017
07018
07019
07020
07021
07022
07023
07024
07025
07026
07027
07028
07029
07030
07031
07032
07033
07034
07035 static VALUE
07036 rb_f_p(int argc, VALUE *argv, VALUE self)
07037 {
07038 struct rb_f_p_arg arg;
07039 arg.argc = argc;
07040 arg.argv = argv;
07041
07042 return rb_uninterruptible(rb_f_p_internal, (VALUE)&arg);
07043 }
07044
07045
07046
07047
07048
07049
07050
07051
07052
07053
07054
07055
07056
07057
07058
07059
07060
07061
07062
07063
07064
07065
07066
07067
07068 static VALUE
07069 rb_obj_display(int argc, VALUE *argv, VALUE self)
07070 {
07071 VALUE out;
07072
07073 if (argc == 0) {
07074 out = rb_stdout;
07075 }
07076 else {
07077 rb_scan_args(argc, argv, "01", &out);
07078 }
07079 rb_io_write(out, self);
07080
07081 return Qnil;
07082 }
07083
07084 void
07085 rb_write_error2(const char *mesg, long len)
07086 {
07087 if (rb_stderr == orig_stderr || RFILE(orig_stderr)->fptr->fd < 0) {
07088 if (fwrite(mesg, sizeof(char), (size_t)len, stderr) < (size_t)len) {
07089
07090 return;
07091 }
07092 }
07093 else {
07094 rb_io_write(rb_stderr, rb_str_new(mesg, len));
07095 }
07096 }
07097
07098 void
07099 rb_write_error(const char *mesg)
07100 {
07101 rb_write_error2(mesg, strlen(mesg));
07102 }
07103
07104 void
07105 rb_write_error_str(VALUE mesg)
07106 {
07107
07108 if (rb_stderr == orig_stderr || RFILE(orig_stderr)->fptr->fd < 0) {
07109 size_t len = (size_t)RSTRING_LEN(mesg);
07110 if (fwrite(RSTRING_PTR(mesg), sizeof(char), len, stderr) < len) {
07111 RB_GC_GUARD(mesg);
07112 return;
07113 }
07114 }
07115 else {
07116
07117 rb_io_write(rb_stderr, mesg);
07118 }
07119 }
07120
07121 static void
07122 must_respond_to(ID mid, VALUE val, ID id)
07123 {
07124 if (!rb_respond_to(val, mid)) {
07125 rb_raise(rb_eTypeError, "%s must have %s method, %s given",
07126 rb_id2name(id), rb_id2name(mid),
07127 rb_obj_classname(val));
07128 }
07129 }
07130
07131 static void
07132 stdout_setter(VALUE val, ID id, VALUE *variable)
07133 {
07134 must_respond_to(id_write, val, id);
07135 *variable = val;
07136 }
07137
07138 static VALUE
07139 prep_io(int fd, int fmode, VALUE klass, const char *path)
07140 {
07141 rb_io_t *fp;
07142 VALUE io = io_alloc(klass);
07143
07144 MakeOpenFile(io, fp);
07145 fp->fd = fd;
07146 #ifdef __CYGWIN__
07147 if (!isatty(fd)) {
07148 fmode |= FMODE_BINMODE;
07149 setmode(fd, O_BINARY);
07150 }
07151 #endif
07152 fp->mode = fmode;
07153 io_check_tty(fp);
07154 if (path) fp->pathv = rb_obj_freeze(rb_str_new_cstr(path));
07155 rb_update_max_fd(fd);
07156
07157 return io;
07158 }
07159
07160 VALUE
07161 rb_io_fdopen(int fd, int oflags, const char *path)
07162 {
07163 VALUE klass = rb_cIO;
07164
07165 if (path && strcmp(path, "-")) klass = rb_cFile;
07166 return prep_io(fd, rb_io_oflags_fmode(oflags), klass, path);
07167 }
07168
07169 static VALUE
07170 prep_stdio(FILE *f, int fmode, VALUE klass, const char *path)
07171 {
07172 rb_io_t *fptr;
07173 VALUE io = prep_io(fileno(f), fmode|FMODE_PREP|DEFAULT_TEXTMODE, klass, path);
07174
07175 GetOpenFile(io, fptr);
07176 fptr->encs.ecflags |= ECONV_DEFAULT_NEWLINE_DECORATOR;
07177 #ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
07178 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
07179 if (fmode & FMODE_READABLE) {
07180 fptr->encs.ecflags |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;
07181 }
07182 #endif
07183 fptr->stdio_file = f;
07184
07185 return io;
07186 }
07187
07188 FILE *
07189 rb_io_stdio_file(rb_io_t *fptr)
07190 {
07191 if (!fptr->stdio_file) {
07192 int oflags = rb_io_fmode_oflags(fptr->mode);
07193 fptr->stdio_file = rb_fdopen(fptr->fd, rb_io_oflags_modestr(oflags));
07194 }
07195 return fptr->stdio_file;
07196 }
07197
07198
07199
07200
07201
07202
07203
07204
07205
07206
07207
07208
07209
07210
07211
07212
07213
07214
07215
07216
07217
07218
07219
07220
07221
07222
07223
07224
07225
07226
07227
07228
07229
07230
07231
07232
07233
07234
07235
07236
07237
07238
07239
07240
07241
07242
07243
07244
07245
07246
07247
07248
07249
07250
07251
07252
07253
07254
07255
07256
07257
07258
07259
07260
07261
07262
07263
07264
07265
07266
07267
07268
07269
07270
07271
07272
07273
07274
07275
07276
07277
07278
07279
07280
07281
07282
07283
07284
07285
07286
07287
07288
07289
07290
07291
07292
07293
07294
07295
07296
07297
07298
07299
07300
07301
07302
07303
07304
07305
07306
07307
07308
07309
07310
07311
07312
07313
07314
07315
07316
07317
07318
07319
07320
07321
07322
07323
07324
07325
07326
07327
07328
07329
07330
07331
07332
07333
07334
07335
07336
07337
07338
07339
07340
07341
07342
07343
07344 static VALUE
07345 rb_io_initialize(int argc, VALUE *argv, VALUE io)
07346 {
07347 VALUE fnum, vmode;
07348 rb_io_t *fp;
07349 int fd, fmode, oflags = O_RDONLY;
07350 convconfig_t convconfig;
07351 VALUE opt;
07352 #if defined(HAVE_FCNTL) && defined(F_GETFL)
07353 int ofmode;
07354 #else
07355 struct stat st;
07356 #endif
07357
07358 rb_secure(4);
07359
07360 argc = rb_scan_args(argc, argv, "11:", &fnum, &vmode, &opt);
07361 rb_io_extract_modeenc(&vmode, 0, opt, &oflags, &fmode, &convconfig);
07362
07363 fd = NUM2INT(fnum);
07364 if (rb_reserved_fd_p(fd)) {
07365 rb_raise(rb_eArgError, "The given fd is not accessible because RubyVM reserves it");
07366 }
07367 #if defined(HAVE_FCNTL) && defined(F_GETFL)
07368 oflags = fcntl(fd, F_GETFL);
07369 if (oflags == -1) rb_sys_fail(0);
07370 #else
07371 if (fstat(fd, &st) == -1) rb_sys_fail(0);
07372 #endif
07373 rb_update_max_fd(fd);
07374 #if defined(HAVE_FCNTL) && defined(F_GETFL)
07375 ofmode = rb_io_oflags_fmode(oflags);
07376 if (NIL_P(vmode)) {
07377 fmode = ofmode;
07378 }
07379 else if ((~ofmode & fmode) & FMODE_READWRITE) {
07380 VALUE error = INT2FIX(EINVAL);
07381 rb_exc_raise(rb_class_new_instance(1, &error, rb_eSystemCallError));
07382 }
07383 #endif
07384 if (!NIL_P(opt) && rb_hash_aref(opt, sym_autoclose) == Qfalse) {
07385 fmode |= FMODE_PREP;
07386 }
07387 MakeOpenFile(io, fp);
07388 fp->fd = fd;
07389 fp->mode = fmode;
07390 fp->encs = convconfig;
07391 clear_codeconv(fp);
07392 io_check_tty(fp);
07393 if (fileno(stdin) == fd)
07394 fp->stdio_file = stdin;
07395 else if (fileno(stdout) == fd)
07396 fp->stdio_file = stdout;
07397 else if (fileno(stderr) == fd)
07398 fp->stdio_file = stderr;
07399
07400 if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
07401 return io;
07402 }
07403
07404
07405
07406
07407
07408
07409
07410
07411
07412
07413
07414
07415
07416
07417
07418
07419
07420
07421
07422
07423
07424
07425 static VALUE
07426 rb_file_initialize(int argc, VALUE *argv, VALUE io)
07427 {
07428 if (RFILE(io)->fptr) {
07429 rb_raise(rb_eRuntimeError, "reinitializing File");
07430 }
07431 if (0 < argc && argc < 3) {
07432 VALUE fd = rb_check_convert_type(argv[0], T_FIXNUM, "Fixnum", "to_int");
07433
07434 if (!NIL_P(fd)) {
07435 argv[0] = fd;
07436 return rb_io_initialize(argc, argv, io);
07437 }
07438 }
07439 rb_open_file(argc, argv, io);
07440
07441 return io;
07442 }
07443
07444
07445 static VALUE
07446 rb_io_s_new(int argc, VALUE *argv, VALUE klass)
07447 {
07448 if (rb_block_given_p()) {
07449 const char *cname = rb_class2name(klass);
07450
07451 rb_warn("%s::new() does not take block; use %s::open() instead",
07452 cname, cname);
07453 }
07454 return rb_class_new_instance(argc, argv, klass);
07455 }
07456
07457
07458
07459
07460
07461
07462
07463
07464
07465
07466 static VALUE
07467 rb_io_s_for_fd(int argc, VALUE *argv, VALUE klass)
07468 {
07469 VALUE io = rb_obj_alloc(klass);
07470 rb_io_initialize(argc, argv, io);
07471 return io;
07472 }
07473
07474
07475
07476
07477
07478
07479
07480
07481
07482 static VALUE
07483 rb_io_autoclose_p(VALUE io)
07484 {
07485 rb_io_t *fptr = RFILE(io)->fptr;
07486 rb_secure(4);
07487 rb_io_check_closed(fptr);
07488 return (fptr->mode & FMODE_PREP) ? Qfalse : Qtrue;
07489 }
07490
07491
07492
07493
07494
07495
07496
07497
07498
07499
07500
07501
07502
07503
07504
07505
07506
07507
07508 static VALUE
07509 rb_io_set_autoclose(VALUE io, VALUE autoclose)
07510 {
07511 rb_io_t *fptr;
07512 rb_secure(4);
07513 GetOpenFile(io, fptr);
07514 if (!RTEST(autoclose))
07515 fptr->mode |= FMODE_PREP;
07516 else
07517 fptr->mode &= ~FMODE_PREP;
07518 return io;
07519 }
07520
07521 static void
07522 argf_mark(void *ptr)
07523 {
07524 struct argf *p = ptr;
07525 rb_gc_mark(p->filename);
07526 rb_gc_mark(p->current_file);
07527 rb_gc_mark(p->argv);
07528 rb_gc_mark(p->encs.ecopts);
07529 }
07530
07531 static void
07532 argf_free(void *ptr)
07533 {
07534 struct argf *p = ptr;
07535 xfree(p->inplace);
07536 xfree(p);
07537 }
07538
07539 static size_t
07540 argf_memsize(const void *ptr)
07541 {
07542 const struct argf *p = ptr;
07543 size_t size = sizeof(*p);
07544 if (!ptr) return 0;
07545 if (p->inplace) size += strlen(p->inplace) + 1;
07546 return size;
07547 }
07548
07549 static const rb_data_type_t argf_type = {
07550 "ARGF",
07551 {argf_mark, argf_free, argf_memsize},
07552 };
07553
07554 static inline void
07555 argf_init(struct argf *p, VALUE v)
07556 {
07557 p->filename = Qnil;
07558 p->current_file = Qnil;
07559 p->lineno = 0;
07560 p->argv = v;
07561 }
07562
07563 static VALUE
07564 argf_alloc(VALUE klass)
07565 {
07566 struct argf *p;
07567 VALUE argf = TypedData_Make_Struct(klass, struct argf, &argf_type, p);
07568
07569 argf_init(p, Qnil);
07570 return argf;
07571 }
07572
07573 #undef rb_argv
07574
07575
07576 static VALUE
07577 argf_initialize(VALUE argf, VALUE argv)
07578 {
07579 memset(&ARGF, 0, sizeof(ARGF));
07580 argf_init(&ARGF, argv);
07581
07582 return argf;
07583 }
07584
07585
07586 static VALUE
07587 argf_initialize_copy(VALUE argf, VALUE orig)
07588 {
07589 if (!OBJ_INIT_COPY(argf, orig)) return argf;
07590 ARGF = argf_of(orig);
07591 ARGF.argv = rb_obj_dup(ARGF.argv);
07592 if (ARGF.inplace) {
07593 const char *inplace = ARGF.inplace;
07594 ARGF.inplace = 0;
07595 ARGF.inplace = ruby_strdup(inplace);
07596 }
07597 return argf;
07598 }
07599
07600
07601
07602
07603
07604
07605
07606
07607
07608
07609
07610
07611
07612
07613
07614
07615
07616
07617
07618 static VALUE
07619 argf_set_lineno(VALUE argf, VALUE val)
07620 {
07621 ARGF.lineno = NUM2INT(val);
07622 ARGF.last_lineno = ARGF.lineno;
07623 return Qnil;
07624 }
07625
07626
07627
07628
07629
07630
07631
07632
07633
07634
07635
07636
07637
07638
07639 static VALUE
07640 argf_lineno(VALUE argf)
07641 {
07642 return INT2FIX(ARGF.lineno);
07643 }
07644
07645 static VALUE
07646 argf_forward(int argc, VALUE *argv, VALUE argf)
07647 {
07648 return rb_funcall3(ARGF.current_file, rb_frame_this_func(), argc, argv);
07649 }
07650
07651 #define next_argv() argf_next_argv(argf)
07652 #define ARGF_GENERIC_INPUT_P() \
07653 (ARGF.current_file == rb_stdin && !RB_TYPE_P(ARGF.current_file, T_FILE))
07654 #define ARGF_FORWARD(argc, argv) do {\
07655 if (ARGF_GENERIC_INPUT_P())\
07656 return argf_forward((argc), (argv), argf);\
07657 } while (0)
07658 #define NEXT_ARGF_FORWARD(argc, argv) do {\
07659 if (!next_argv()) return Qnil;\
07660 ARGF_FORWARD((argc), (argv));\
07661 } while (0)
07662
07663 static void
07664 argf_close(VALUE file)
07665 {
07666 if (file == rb_stdin) return;
07667 if (RB_TYPE_P(file, T_FILE)) {
07668 rb_io_set_write_io(file, Qnil);
07669 }
07670 rb_funcall3(file, rb_intern("close"), 0, 0);
07671 }
07672
07673 static int
07674 argf_next_argv(VALUE argf)
07675 {
07676 char *fn;
07677 rb_io_t *fptr;
07678 int stdout_binmode = 0;
07679 int fmode;
07680
07681 if (RB_TYPE_P(rb_stdout, T_FILE)) {
07682 GetOpenFile(rb_stdout, fptr);
07683 if (fptr->mode & FMODE_BINMODE)
07684 stdout_binmode = 1;
07685 }
07686
07687 if (ARGF.init_p == 0) {
07688 if (!NIL_P(ARGF.argv) && RARRAY_LEN(ARGF.argv) > 0) {
07689 ARGF.next_p = 1;
07690 }
07691 else {
07692 ARGF.next_p = -1;
07693 }
07694 ARGF.init_p = 1;
07695 }
07696 else {
07697 if (NIL_P(ARGF.argv)) {
07698 ARGF.next_p = -1;
07699 }
07700 else if (ARGF.next_p == -1 && RARRAY_LEN(ARGF.argv) > 0) {
07701 ARGF.next_p = 1;
07702 }
07703 }
07704
07705 if (ARGF.next_p == 1) {
07706 retry:
07707 if (RARRAY_LEN(ARGF.argv) > 0) {
07708 ARGF.filename = rb_ary_shift(ARGF.argv);
07709 fn = StringValueCStr(ARGF.filename);
07710 if (strlen(fn) == 1 && fn[0] == '-') {
07711 ARGF.current_file = rb_stdin;
07712 if (ARGF.inplace) {
07713 rb_warn("Can't do inplace edit for stdio; skipping");
07714 goto retry;
07715 }
07716 }
07717 else {
07718 VALUE write_io = Qnil;
07719 int fr = rb_sysopen(ARGF.filename, O_RDONLY, 0);
07720
07721 if (ARGF.inplace) {
07722 struct stat st;
07723 #ifndef NO_SAFE_RENAME
07724 struct stat st2;
07725 #endif
07726 VALUE str;
07727 int fw;
07728
07729 if (RB_TYPE_P(rb_stdout, T_FILE) && rb_stdout != orig_stdout) {
07730 rb_io_close(rb_stdout);
07731 }
07732 fstat(fr, &st);
07733 if (*ARGF.inplace) {
07734 str = rb_str_new2(fn);
07735 rb_str_cat2(str, ARGF.inplace);
07736 #ifdef NO_SAFE_RENAME
07737 (void)close(fr);
07738 (void)unlink(RSTRING_PTR(str));
07739 if (rename(fn, RSTRING_PTR(str)) < 0) {
07740 rb_warn("Can't rename %s to %s: %s, skipping file",
07741 fn, RSTRING_PTR(str), strerror(errno));
07742 goto retry;
07743 }
07744 fr = rb_sysopen(str, O_RDONLY, 0);
07745 #else
07746 if (rename(fn, RSTRING_PTR(str)) < 0) {
07747 rb_warn("Can't rename %s to %s: %s, skipping file",
07748 fn, RSTRING_PTR(str), strerror(errno));
07749 close(fr);
07750 goto retry;
07751 }
07752 #endif
07753 }
07754 else {
07755 #ifdef NO_SAFE_RENAME
07756 rb_fatal("Can't do inplace edit without backup");
07757 #else
07758 if (unlink(fn) < 0) {
07759 rb_warn("Can't remove %s: %s, skipping file",
07760 fn, strerror(errno));
07761 close(fr);
07762 goto retry;
07763 }
07764 #endif
07765 }
07766 fw = rb_sysopen(ARGF.filename, O_WRONLY|O_CREAT|O_TRUNC, 0666);
07767 #ifndef NO_SAFE_RENAME
07768 fstat(fw, &st2);
07769 #ifdef HAVE_FCHMOD
07770 fchmod(fw, st.st_mode);
07771 #else
07772 chmod(fn, st.st_mode);
07773 #endif
07774 if (st.st_uid!=st2.st_uid || st.st_gid!=st2.st_gid) {
07775 int err;
07776 #ifdef HAVE_FCHOWN
07777 err = fchown(fw, st.st_uid, st.st_gid);
07778 #else
07779 err = chown(fn, st.st_uid, st.st_gid);
07780 #endif
07781 if (err && getuid() == 0 && st2.st_uid == 0) {
07782 const char *wkfn = RSTRING_PTR(ARGF.filename);
07783 rb_warn("Can't set owner/group of %s to same as %s: %s, skipping file",
07784 wkfn, fn, strerror(errno));
07785 (void)close(fr);
07786 (void)close(fw);
07787 (void)unlink(wkfn);
07788 goto retry;
07789 }
07790 }
07791 #endif
07792 write_io = prep_io(fw, FMODE_WRITABLE, rb_cFile, fn);
07793 rb_stdout = write_io;
07794 if (stdout_binmode) rb_io_binmode(rb_stdout);
07795 }
07796 fmode = FMODE_READABLE;
07797 if (!ARGF.binmode) {
07798 fmode |= DEFAULT_TEXTMODE;
07799 }
07800 ARGF.current_file = prep_io(fr, fmode, rb_cFile, fn);
07801 if (!NIL_P(write_io)) {
07802 rb_io_set_write_io(ARGF.current_file, write_io);
07803 }
07804 }
07805 if (ARGF.binmode) rb_io_ascii8bit_binmode(ARGF.current_file);
07806 GetOpenFile(ARGF.current_file, fptr);
07807 if (ARGF.encs.enc) {
07808 fptr->encs = ARGF.encs;
07809 clear_codeconv(fptr);
07810 }
07811 else {
07812 fptr->encs.ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
07813 if (!ARGF.binmode) {
07814 fptr->encs.ecflags |= ECONV_DEFAULT_NEWLINE_DECORATOR;
07815 #ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
07816 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
07817 #endif
07818 }
07819 }
07820 ARGF.next_p = 0;
07821 }
07822 else {
07823 ARGF.next_p = 1;
07824 return FALSE;
07825 }
07826 }
07827 else if (ARGF.next_p == -1) {
07828 ARGF.current_file = rb_stdin;
07829 ARGF.filename = rb_str_new2("-");
07830 if (ARGF.inplace) {
07831 rb_warn("Can't do inplace edit for stdio");
07832 rb_stdout = orig_stdout;
07833 }
07834 }
07835 return TRUE;
07836 }
07837
07838 static VALUE
07839 argf_getline(int argc, VALUE *argv, VALUE argf)
07840 {
07841 VALUE line;
07842 long lineno = ARGF.lineno;
07843
07844 retry:
07845 if (!next_argv()) return Qnil;
07846 if (ARGF_GENERIC_INPUT_P()) {
07847 line = rb_funcall3(ARGF.current_file, idGets, argc, argv);
07848 }
07849 else {
07850 if (argc == 0 && rb_rs == rb_default_rs) {
07851 line = rb_io_gets(ARGF.current_file);
07852 }
07853 else {
07854 line = rb_io_getline(argc, argv, ARGF.current_file);
07855 }
07856 if (NIL_P(line) && ARGF.next_p != -1) {
07857 argf_close(ARGF.current_file);
07858 ARGF.next_p = 1;
07859 goto retry;
07860 }
07861 }
07862 if (!NIL_P(line)) {
07863 ARGF.lineno = ++lineno;
07864 ARGF.last_lineno = ARGF.lineno;
07865 }
07866 return line;
07867 }
07868
07869 static VALUE
07870 argf_lineno_getter(ID id, VALUE *var)
07871 {
07872 VALUE argf = *var;
07873 return INT2FIX(ARGF.last_lineno);
07874 }
07875
07876 static void
07877 argf_lineno_setter(VALUE val, ID id, VALUE *var)
07878 {
07879 VALUE argf = *var;
07880 int n = NUM2INT(val);
07881 ARGF.last_lineno = ARGF.lineno = n;
07882 }
07883
07884 static VALUE argf_gets(int, VALUE *, VALUE);
07885
07886
07887
07888
07889
07890
07891
07892
07893
07894
07895
07896
07897
07898
07899
07900
07901
07902
07903
07904
07905
07906
07907
07908
07909
07910
07911
07912
07913
07914
07915
07916
07917
07918
07919 static VALUE
07920 rb_f_gets(int argc, VALUE *argv, VALUE recv)
07921 {
07922 if (recv == argf) {
07923 return argf_gets(argc, argv, argf);
07924 }
07925 return rb_funcall2(argf, idGets, argc, argv);
07926 }
07927
07928
07929
07930
07931
07932
07933
07934
07935
07936
07937
07938
07939
07940
07941
07942
07943 static VALUE
07944 argf_gets(int argc, VALUE *argv, VALUE argf)
07945 {
07946 VALUE line;
07947
07948 line = argf_getline(argc, argv, argf);
07949 rb_lastline_set(line);
07950
07951 return line;
07952 }
07953
07954 VALUE
07955 rb_gets(void)
07956 {
07957 VALUE line;
07958
07959 if (rb_rs != rb_default_rs) {
07960 return rb_f_gets(0, 0, argf);
07961 }
07962
07963 retry:
07964 if (!next_argv()) return Qnil;
07965 line = rb_io_gets(ARGF.current_file);
07966 if (NIL_P(line) && ARGF.next_p != -1) {
07967 rb_io_close(ARGF.current_file);
07968 ARGF.next_p = 1;
07969 goto retry;
07970 }
07971 rb_lastline_set(line);
07972 if (!NIL_P(line)) {
07973 ARGF.lineno++;
07974 ARGF.last_lineno = ARGF.lineno;
07975 }
07976
07977 return line;
07978 }
07979
07980 static VALUE argf_readline(int, VALUE *, VALUE);
07981
07982
07983
07984
07985
07986
07987
07988
07989
07990
07991
07992 static VALUE
07993 rb_f_readline(int argc, VALUE *argv, VALUE recv)
07994 {
07995 if (recv == argf) {
07996 return argf_readline(argc, argv, argf);
07997 }
07998 return rb_funcall2(argf, rb_intern("readline"), argc, argv);
07999 }
08000
08001
08002
08003
08004
08005
08006
08007
08008
08009
08010
08011
08012
08013
08014
08015
08016
08017
08018 static VALUE
08019 argf_readline(int argc, VALUE *argv, VALUE argf)
08020 {
08021 VALUE line;
08022
08023 if (!next_argv()) rb_eof_error();
08024 ARGF_FORWARD(argc, argv);
08025 line = argf_gets(argc, argv, argf);
08026 if (NIL_P(line)) {
08027 rb_eof_error();
08028 }
08029
08030 return line;
08031 }
08032
08033 static VALUE argf_readlines(int, VALUE *, VALUE);
08034
08035
08036
08037
08038
08039
08040
08041
08042
08043
08044
08045 static VALUE
08046 rb_f_readlines(int argc, VALUE *argv, VALUE recv)
08047 {
08048 if (recv == argf) {
08049 return argf_readlines(argc, argv, argf);
08050 }
08051 return rb_funcall2(argf, rb_intern("readlines"), argc, argv);
08052 }
08053
08054
08055
08056
08057
08058
08059
08060
08061
08062
08063
08064
08065
08066
08067
08068
08069
08070 static VALUE
08071 argf_readlines(int argc, VALUE *argv, VALUE argf)
08072 {
08073 long lineno = ARGF.lineno;
08074 VALUE lines, ary;
08075
08076 ary = rb_ary_new();
08077 while (next_argv()) {
08078 if (ARGF_GENERIC_INPUT_P()) {
08079 lines = rb_funcall3(ARGF.current_file, rb_intern("readlines"), argc, argv);
08080 }
08081 else {
08082 lines = rb_io_readlines(argc, argv, ARGF.current_file);
08083 argf_close(ARGF.current_file);
08084 }
08085 ARGF.next_p = 1;
08086 rb_ary_concat(ary, lines);
08087 ARGF.lineno = lineno + RARRAY_LEN(ary);
08088 ARGF.last_lineno = ARGF.lineno;
08089 }
08090 ARGF.init_p = 0;
08091 return ary;
08092 }
08093
08094
08095
08096
08097
08098
08099
08100
08101
08102
08103
08104
08105
08106
08107
08108 static VALUE
08109 rb_f_backquote(VALUE obj, VALUE str)
08110 {
08111 volatile VALUE port;
08112 VALUE result;
08113 rb_io_t *fptr;
08114
08115 SafeStringValue(str);
08116 rb_last_status_clear();
08117 port = pipe_open_s(str, "r", FMODE_READABLE|DEFAULT_TEXTMODE, NULL);
08118 if (NIL_P(port)) return rb_str_new(0,0);
08119
08120 GetOpenFile(port, fptr);
08121 result = read_all(fptr, remain_size(fptr), Qnil);
08122 rb_io_close(port);
08123
08124 return result;
08125 }
08126
08127 #ifdef HAVE_SYS_SELECT_H
08128 #include <sys/select.h>
08129 #endif
08130
08131 static VALUE
08132 select_internal(VALUE read, VALUE write, VALUE except, struct timeval *tp, rb_fdset_t *fds)
08133 {
08134 VALUE res, list;
08135 rb_fdset_t *rp, *wp, *ep;
08136 rb_io_t *fptr;
08137 long i;
08138 int max = 0, n;
08139 int pending = 0;
08140 struct timeval timerec;
08141
08142 if (!NIL_P(read)) {
08143 Check_Type(read, T_ARRAY);
08144 for (i=0; i<RARRAY_LEN(read); i++) {
08145 GetOpenFile(rb_io_get_io(RARRAY_PTR(read)[i]), fptr);
08146 rb_fd_set(fptr->fd, &fds[0]);
08147 if (READ_DATA_PENDING(fptr) || READ_CHAR_PENDING(fptr)) {
08148 pending++;
08149 rb_fd_set(fptr->fd, &fds[3]);
08150 }
08151 if (max < fptr->fd) max = fptr->fd;
08152 }
08153 if (pending) {
08154 timerec.tv_sec = timerec.tv_usec = 0;
08155 tp = &timerec;
08156 }
08157 rp = &fds[0];
08158 }
08159 else
08160 rp = 0;
08161
08162 if (!NIL_P(write)) {
08163 Check_Type(write, T_ARRAY);
08164 for (i=0; i<RARRAY_LEN(write); i++) {
08165 VALUE write_io = GetWriteIO(rb_io_get_io(RARRAY_PTR(write)[i]));
08166 GetOpenFile(write_io, fptr);
08167 rb_fd_set(fptr->fd, &fds[1]);
08168 if (max < fptr->fd) max = fptr->fd;
08169 }
08170 wp = &fds[1];
08171 }
08172 else
08173 wp = 0;
08174
08175 if (!NIL_P(except)) {
08176 Check_Type(except, T_ARRAY);
08177 for (i=0; i<RARRAY_LEN(except); i++) {
08178 VALUE io = rb_io_get_io(RARRAY_PTR(except)[i]);
08179 VALUE write_io = GetWriteIO(io);
08180 GetOpenFile(io, fptr);
08181 rb_fd_set(fptr->fd, &fds[2]);
08182 if (max < fptr->fd) max = fptr->fd;
08183 if (io != write_io) {
08184 GetOpenFile(write_io, fptr);
08185 rb_fd_set(fptr->fd, &fds[2]);
08186 if (max < fptr->fd) max = fptr->fd;
08187 }
08188 }
08189 ep = &fds[2];
08190 }
08191 else {
08192 ep = 0;
08193 }
08194
08195 max++;
08196
08197 n = rb_thread_fd_select(max, rp, wp, ep, tp);
08198 if (n < 0) {
08199 rb_sys_fail(0);
08200 }
08201 if (!pending && n == 0) return Qnil;
08202
08203 res = rb_ary_new2(3);
08204 rb_ary_push(res, rp?rb_ary_new():rb_ary_new2(0));
08205 rb_ary_push(res, wp?rb_ary_new():rb_ary_new2(0));
08206 rb_ary_push(res, ep?rb_ary_new():rb_ary_new2(0));
08207
08208 if (rp) {
08209 list = RARRAY_PTR(res)[0];
08210 for (i=0; i< RARRAY_LEN(read); i++) {
08211 VALUE obj = rb_ary_entry(read, i);
08212 VALUE io = rb_io_get_io(obj);
08213 GetOpenFile(io, fptr);
08214 if (rb_fd_isset(fptr->fd, &fds[0]) ||
08215 rb_fd_isset(fptr->fd, &fds[3])) {
08216 rb_ary_push(list, obj);
08217 }
08218 }
08219 }
08220
08221 if (wp) {
08222 list = RARRAY_PTR(res)[1];
08223 for (i=0; i< RARRAY_LEN(write); i++) {
08224 VALUE obj = rb_ary_entry(write, i);
08225 VALUE io = rb_io_get_io(obj);
08226 VALUE write_io = GetWriteIO(io);
08227 GetOpenFile(write_io, fptr);
08228 if (rb_fd_isset(fptr->fd, &fds[1])) {
08229 rb_ary_push(list, obj);
08230 }
08231 }
08232 }
08233
08234 if (ep) {
08235 list = RARRAY_PTR(res)[2];
08236 for (i=0; i< RARRAY_LEN(except); i++) {
08237 VALUE obj = rb_ary_entry(except, i);
08238 VALUE io = rb_io_get_io(obj);
08239 VALUE write_io = GetWriteIO(io);
08240 GetOpenFile(io, fptr);
08241 if (rb_fd_isset(fptr->fd, &fds[2])) {
08242 rb_ary_push(list, obj);
08243 }
08244 else if (io != write_io) {
08245 GetOpenFile(write_io, fptr);
08246 if (rb_fd_isset(fptr->fd, &fds[2])) {
08247 rb_ary_push(list, obj);
08248 }
08249 }
08250 }
08251 }
08252
08253 return res;
08254 }
08255
08256 struct select_args {
08257 VALUE read, write, except;
08258 struct timeval *timeout;
08259 rb_fdset_t fdsets[4];
08260 };
08261
08262 static VALUE
08263 select_call(VALUE arg)
08264 {
08265 struct select_args *p = (struct select_args *)arg;
08266
08267 return select_internal(p->read, p->write, p->except, p->timeout, p->fdsets);
08268 }
08269
08270 static VALUE
08271 select_end(VALUE arg)
08272 {
08273 struct select_args *p = (struct select_args *)arg;
08274 int i;
08275
08276 for (i = 0; i < numberof(p->fdsets); ++i)
08277 rb_fd_term(&p->fdsets[i]);
08278 return Qnil;
08279 }
08280
08281 static VALUE sym_normal, sym_sequential, sym_random,
08282 sym_willneed, sym_dontneed, sym_noreuse;
08283
08284 #ifdef HAVE_POSIX_FADVISE
08285 struct io_advise_struct {
08286 int fd;
08287 off_t offset;
08288 off_t len;
08289 int advice;
08290 };
08291
08292 static VALUE
08293 io_advise_internal(void *arg)
08294 {
08295 struct io_advise_struct *ptr = arg;
08296 return posix_fadvise(ptr->fd, ptr->offset, ptr->len, ptr->advice);
08297 }
08298
08299 static VALUE
08300 io_advise_sym_to_const(VALUE sym)
08301 {
08302 #ifdef POSIX_FADV_NORMAL
08303 if (sym == sym_normal)
08304 return INT2NUM(POSIX_FADV_NORMAL);
08305 #endif
08306
08307 #ifdef POSIX_FADV_RANDOM
08308 if (sym == sym_random)
08309 return INT2NUM(POSIX_FADV_RANDOM);
08310 #endif
08311
08312 #ifdef POSIX_FADV_SEQUENTIAL
08313 if (sym == sym_sequential)
08314 return INT2NUM(POSIX_FADV_SEQUENTIAL);
08315 #endif
08316
08317 #ifdef POSIX_FADV_WILLNEED
08318 if (sym == sym_willneed)
08319 return INT2NUM(POSIX_FADV_WILLNEED);
08320 #endif
08321
08322 #ifdef POSIX_FADV_DONTNEED
08323 if (sym == sym_dontneed)
08324 return INT2NUM(POSIX_FADV_DONTNEED);
08325 #endif
08326
08327 #ifdef POSIX_FADV_NOREUSE
08328 if (sym == sym_noreuse)
08329 return INT2NUM(POSIX_FADV_NOREUSE);
08330 #endif
08331
08332 return Qnil;
08333 }
08334
08335 static VALUE
08336 do_io_advise(rb_io_t *fptr, VALUE advice, off_t offset, off_t len)
08337 {
08338 int rv;
08339 struct io_advise_struct ias;
08340 VALUE num_adv;
08341
08342 num_adv = io_advise_sym_to_const(advice);
08343
08344
08345
08346
08347
08348 if (NIL_P(num_adv))
08349 return Qnil;
08350
08351 ias.fd = fptr->fd;
08352 ias.advice = NUM2INT(num_adv);
08353 ias.offset = offset;
08354 ias.len = len;
08355
08356 rv = (int)rb_thread_io_blocking_region(io_advise_internal, &ias, fptr->fd);
08357 if (rv) {
08358
08359
08360 rb_syserr_fail_str(rv, fptr->pathv);
08361 }
08362
08363 return Qnil;
08364 }
08365
08366 #endif
08367
08368 static void
08369 advice_arg_check(VALUE advice)
08370 {
08371 if (!SYMBOL_P(advice))
08372 rb_raise(rb_eTypeError, "advice must be a Symbol");
08373
08374 if (advice != sym_normal &&
08375 advice != sym_sequential &&
08376 advice != sym_random &&
08377 advice != sym_willneed &&
08378 advice != sym_dontneed &&
08379 advice != sym_noreuse) {
08380 VALUE symname = rb_inspect(advice);
08381 rb_raise(rb_eNotImpError, "Unsupported advice: %s",
08382 StringValuePtr(symname));
08383 }
08384 }
08385
08386
08387
08388
08389
08390
08391
08392
08393
08394
08395
08396
08397
08398
08399
08400
08401
08402
08403
08404
08405
08406
08407
08408
08409
08410
08411
08412
08413
08414
08415
08416
08417
08418
08419
08420
08421
08422
08423
08424
08425
08426
08427 static VALUE
08428 rb_io_advise(int argc, VALUE *argv, VALUE io)
08429 {
08430 VALUE advice, offset, len;
08431 off_t off, l;
08432 rb_io_t *fptr;
08433
08434 rb_scan_args(argc, argv, "12", &advice, &offset, &len);
08435 advice_arg_check(advice);
08436
08437 io = GetWriteIO(io);
08438 GetOpenFile(io, fptr);
08439
08440 off = NIL_P(offset) ? 0 : NUM2OFFT(offset);
08441 l = NIL_P(len) ? 0 : NUM2OFFT(len);
08442
08443 #ifdef HAVE_POSIX_FADVISE
08444 return do_io_advise(fptr, advice, off, l);
08445 #else
08446 ((void)off, (void)l);
08447 return Qnil;
08448 #endif
08449 }
08450
08451
08452
08453
08454
08455
08456
08457
08458
08459
08460
08461
08462
08463
08464
08465
08466
08467
08468
08469
08470
08471
08472
08473
08474
08475
08476
08477
08478
08479
08480
08481
08482
08483
08484
08485
08486
08487
08488
08489
08490
08491
08492
08493
08494
08495
08496
08497
08498
08499
08500
08501
08502 static VALUE
08503 rb_f_select(int argc, VALUE *argv, VALUE obj)
08504 {
08505 VALUE timeout;
08506 struct select_args args;
08507 struct timeval timerec;
08508 int i;
08509
08510 rb_scan_args(argc, argv, "13", &args.read, &args.write, &args.except, &timeout);
08511 if (NIL_P(timeout)) {
08512 args.timeout = 0;
08513 }
08514 else {
08515 timerec = rb_time_interval(timeout);
08516 args.timeout = &timerec;
08517 }
08518
08519 for (i = 0; i < numberof(args.fdsets); ++i)
08520 rb_fd_init(&args.fdsets[i]);
08521
08522 return rb_ensure(select_call, (VALUE)&args, select_end, (VALUE)&args);
08523 }
08524
08525 #if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
08526 typedef unsigned long ioctl_req_t;
08527 # define NUM2IOCTLREQ(num) NUM2ULONG(num)
08528 #else
08529 typedef int ioctl_req_t;
08530 # define NUM2IOCTLREQ(num) NUM2INT(num)
08531 #endif
08532
08533 struct ioctl_arg {
08534 int fd;
08535 ioctl_req_t cmd;
08536 long narg;
08537 };
08538
08539 static VALUE
08540 nogvl_ioctl(void *ptr)
08541 {
08542 struct ioctl_arg *arg = ptr;
08543
08544 return (VALUE)ioctl(arg->fd, arg->cmd, arg->narg);
08545 }
08546
08547 static int
08548 do_ioctl(int fd, ioctl_req_t cmd, long narg)
08549 {
08550 int retval;
08551 struct ioctl_arg arg;
08552
08553 arg.fd = fd;
08554 arg.cmd = cmd;
08555 arg.narg = narg;
08556
08557 retval = (int)rb_thread_io_blocking_region(nogvl_ioctl, &arg, fd);
08558
08559 return retval;
08560 }
08561
08562 #define DEFULT_IOCTL_NARG_LEN (256)
08563
08564 #ifdef __linux__
08565 static long
08566 linux_iocparm_len(ioctl_req_t cmd)
08567 {
08568 long len;
08569
08570 if ((cmd & 0xFFFF0000) == 0) {
08571
08572 return DEFULT_IOCTL_NARG_LEN;
08573 }
08574
08575 len = _IOC_SIZE(cmd);
08576
08577
08578 if (len < DEFULT_IOCTL_NARG_LEN)
08579 len = DEFULT_IOCTL_NARG_LEN;
08580
08581 return len;
08582 }
08583 #endif
08584
08585 static long
08586 ioctl_narg_len(ioctl_req_t cmd)
08587 {
08588 long len;
08589
08590 #ifdef IOCPARM_MASK
08591 #ifndef IOCPARM_LEN
08592 #define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK)
08593 #endif
08594 #endif
08595 #ifdef IOCPARM_LEN
08596 len = IOCPARM_LEN(cmd);
08597 #elif defined(__linux__)
08598 len = linux_iocparm_len(cmd);
08599 #else
08600
08601 len = DEFULT_IOCTL_NARG_LEN;
08602 #endif
08603
08604 return len;
08605 }
08606
08607 #ifdef HAVE_FCNTL
08608 #ifdef __linux__
08609 typedef long fcntl_arg_t;
08610 #else
08611
08612 typedef int fcntl_arg_t;
08613 #endif
08614
08615 static long
08616 fcntl_narg_len(int cmd)
08617 {
08618 long len;
08619
08620 switch (cmd) {
08621 #ifdef F_DUPFD
08622 case F_DUPFD:
08623 len = sizeof(fcntl_arg_t);
08624 break;
08625 #endif
08626 #ifdef F_DUP2FD
08627 case F_DUP2FD:
08628 len = sizeof(int);
08629 break;
08630 #endif
08631 #ifdef F_DUPFD_CLOEXEC
08632 case F_DUPFD_CLOEXEC:
08633 len = sizeof(fcntl_arg_t);
08634 break;
08635 #endif
08636 #ifdef F_GETFD
08637 case F_GETFD:
08638 len = 1;
08639 break;
08640 #endif
08641 #ifdef F_SETFD
08642 case F_SETFD:
08643 len = sizeof(fcntl_arg_t);
08644 break;
08645 #endif
08646 #ifdef F_GETFL
08647 case F_GETFL:
08648 len = 1;
08649 break;
08650 #endif
08651 #ifdef F_SETFL
08652 case F_SETFL:
08653 len = sizeof(fcntl_arg_t);
08654 break;
08655 #endif
08656 #ifdef F_GETOWN
08657 case F_GETOWN:
08658 len = 1;
08659 break;
08660 #endif
08661 #ifdef F_SETOWN
08662 case F_SETOWN:
08663 len = sizeof(fcntl_arg_t);
08664 break;
08665 #endif
08666 #ifdef F_GETOWN_EX
08667 case F_GETOWN_EX:
08668 len = sizeof(struct f_owner_ex);
08669 break;
08670 #endif
08671 #ifdef F_SETOWN_EX
08672 case F_SETOWN_EX:
08673 len = sizeof(struct f_owner_ex);
08674 break;
08675 #endif
08676 #ifdef F_GETLK
08677 case F_GETLK:
08678 len = sizeof(struct flock);
08679 break;
08680 #endif
08681 #ifdef F_SETLK
08682 case F_SETLK:
08683 len = sizeof(struct flock);
08684 break;
08685 #endif
08686 #ifdef F_SETLKW
08687 case F_SETLKW:
08688 len = sizeof(struct flock);
08689 break;
08690 #endif
08691 #ifdef F_READAHEAD
08692 case F_READAHEAD:
08693 len = sizeof(int);
08694 break;
08695 #endif
08696 #ifdef F_RDAHEAD
08697 case F_RDAHEAD:
08698 len = sizeof(int);
08699 break;
08700 #endif
08701 #ifdef F_GETSIG
08702 case F_GETSIG:
08703 len = 1;
08704 break;
08705 #endif
08706 #ifdef F_SETSIG
08707 case F_SETSIG:
08708 len = sizeof(fcntl_arg_t);
08709 break;
08710 #endif
08711 #ifdef F_GETLEASE
08712 case F_GETLEASE:
08713 len = 1;
08714 break;
08715 #endif
08716 #ifdef F_SETLEASE
08717 case F_SETLEASE:
08718 len = sizeof(fcntl_arg_t);
08719 break;
08720 #endif
08721 #ifdef F_NOTIFY
08722 case F_NOTIFY:
08723 len = sizeof(fcntl_arg_t);
08724 break;
08725 #endif
08726
08727 default:
08728 len = 256;
08729 break;
08730 }
08731
08732 return len;
08733 }
08734 #else
08735 static long
08736 fcntl_narg_len(int cmd)
08737 {
08738 return 0;
08739 }
08740 #endif
08741
08742 static long
08743 setup_narg(ioctl_req_t cmd, VALUE *argp, int io_p)
08744 {
08745 long narg = 0;
08746 VALUE arg = *argp;
08747
08748 if (NIL_P(arg) || arg == Qfalse) {
08749 narg = 0;
08750 }
08751 else if (FIXNUM_P(arg)) {
08752 narg = FIX2LONG(arg);
08753 }
08754 else if (arg == Qtrue) {
08755 narg = 1;
08756 }
08757 else {
08758 VALUE tmp = rb_check_string_type(arg);
08759
08760 if (NIL_P(tmp)) {
08761 narg = NUM2LONG(arg);
08762 }
08763 else {
08764 long len;
08765
08766 *argp = arg = tmp;
08767 if (io_p)
08768 len = ioctl_narg_len(cmd);
08769 else
08770 len = fcntl_narg_len((int)cmd);
08771 rb_str_modify(arg);
08772
08773
08774 if (RSTRING_LEN(arg) < len+1) {
08775 rb_str_resize(arg, len+1);
08776 }
08777
08778 RSTRING_PTR(arg)[RSTRING_LEN(arg) - 1] = 17;
08779 narg = (long)(SIGNED_VALUE)RSTRING_PTR(arg);
08780 }
08781 }
08782
08783 return narg;
08784 }
08785
08786 static VALUE
08787 rb_ioctl(VALUE io, VALUE req, VALUE arg)
08788 {
08789 ioctl_req_t cmd = NUM2IOCTLREQ(req);
08790 rb_io_t *fptr;
08791 long narg;
08792 int retval;
08793
08794 rb_secure(2);
08795
08796 narg = setup_narg(cmd, &arg, 1);
08797 GetOpenFile(io, fptr);
08798 retval = do_ioctl(fptr->fd, cmd, narg);
08799 if (retval < 0) rb_sys_fail_path(fptr->pathv);
08800 if (RB_TYPE_P(arg, T_STRING)) {
08801 if (RSTRING_PTR(arg)[RSTRING_LEN(arg)-1] != 17)
08802 rb_raise(rb_eArgError, "return value overflowed string");
08803 RSTRING_PTR(arg)[RSTRING_LEN(arg)-1] = '\0';
08804 }
08805
08806 return INT2NUM(retval);
08807 }
08808
08809
08810
08811
08812
08813
08814
08815
08816
08817
08818
08819
08820
08821 static VALUE
08822 rb_io_ioctl(int argc, VALUE *argv, VALUE io)
08823 {
08824 VALUE req, arg;
08825
08826 rb_scan_args(argc, argv, "11", &req, &arg);
08827 return rb_ioctl(io, req, arg);
08828 }
08829
08830 #ifdef HAVE_FCNTL
08831 struct fcntl_arg {
08832 int fd;
08833 int cmd;
08834 long narg;
08835 };
08836
08837 static VALUE
08838 nogvl_fcntl(void *ptr)
08839 {
08840 struct fcntl_arg *arg = ptr;
08841
08842 #if defined(F_DUPFD)
08843 if (arg->cmd == F_DUPFD)
08844 return (VALUE)rb_cloexec_fcntl_dupfd(arg->fd, (int)arg->narg);
08845 #endif
08846 return (VALUE)fcntl(arg->fd, arg->cmd, arg->narg);
08847 }
08848
08849 static int
08850 do_fcntl(int fd, int cmd, long narg)
08851 {
08852 int retval;
08853 struct fcntl_arg arg;
08854
08855 arg.fd = fd;
08856 arg.cmd = cmd;
08857 arg.narg = narg;
08858
08859 retval = (int)rb_thread_io_blocking_region(nogvl_fcntl, &arg, fd);
08860 #if defined(F_DUPFD)
08861 if (retval != -1 && cmd == F_DUPFD) {
08862 rb_update_max_fd(retval);
08863 }
08864 #endif
08865
08866 return retval;
08867 }
08868
08869 static VALUE
08870 rb_fcntl(VALUE io, VALUE req, VALUE arg)
08871 {
08872 int cmd = NUM2INT(req);
08873 rb_io_t *fptr;
08874 long narg;
08875 int retval;
08876
08877 rb_secure(2);
08878
08879 narg = setup_narg(cmd, &arg, 0);
08880 GetOpenFile(io, fptr);
08881 retval = do_fcntl(fptr->fd, cmd, narg);
08882 if (retval < 0) rb_sys_fail_path(fptr->pathv);
08883 if (RB_TYPE_P(arg, T_STRING)) {
08884 if (RSTRING_PTR(arg)[RSTRING_LEN(arg)-1] != 17)
08885 rb_raise(rb_eArgError, "return value overflowed string");
08886 RSTRING_PTR(arg)[RSTRING_LEN(arg)-1] = '\0';
08887 }
08888
08889 if (cmd == F_SETFL) {
08890 if (narg & O_NONBLOCK) {
08891 fptr->mode |= FMODE_WSPLIT_INITIALIZED;
08892 fptr->mode &= ~FMODE_WSPLIT;
08893 }
08894 else {
08895 fptr->mode &= ~(FMODE_WSPLIT_INITIALIZED|FMODE_WSPLIT);
08896 }
08897 }
08898
08899 return INT2NUM(retval);
08900 }
08901
08902
08903
08904
08905
08906
08907
08908
08909
08910
08911
08912
08913
08914
08915 static VALUE
08916 rb_io_fcntl(int argc, VALUE *argv, VALUE io)
08917 {
08918 VALUE req, arg;
08919
08920 rb_scan_args(argc, argv, "11", &req, &arg);
08921 return rb_fcntl(io, req, arg);
08922 }
08923 #else
08924 #define rb_io_fcntl rb_f_notimplement
08925 #endif
08926
08927 #if defined(HAVE_SYSCALL) || defined(HAVE___SYSCALL)
08928
08929
08930
08931
08932
08933
08934
08935
08936
08937
08938
08939
08940
08941
08942
08943
08944
08945
08946
08947
08948
08949
08950
08951
08952
08953
08954
08955
08956
08957
08958
08959
08960
08961 static VALUE
08962 rb_f_syscall(int argc, VALUE *argv)
08963 {
08964 #ifdef atarist
08965 VALUE arg[13];
08966 #else
08967 VALUE arg[8];
08968 #endif
08969 #if SIZEOF_VOIDP == 8 && defined(HAVE___SYSCALL) && SIZEOF_INT != 8
08970 # define SYSCALL __syscall
08971 # define NUM2SYSCALLID(x) NUM2LONG(x)
08972 # define RETVAL2NUM(x) LONG2NUM(x)
08973 # if SIZEOF_LONG == 8
08974 long num, retval = -1;
08975 # elif SIZEOF_LONG_LONG == 8
08976 long long num, retval = -1;
08977 # else
08978 # error ---->> it is asserted that __syscall takes the first argument and returns retval in 64bit signed integer. <<----
08979 # endif
08980 #elif defined(__linux__)
08981 # define SYSCALL syscall
08982 # define NUM2SYSCALLID(x) NUM2LONG(x)
08983 # define RETVAL2NUM(x) LONG2NUM(x)
08984
08985
08986
08987
08988
08989
08990
08991 long num, retval = -1;
08992 #else
08993 # define SYSCALL syscall
08994 # define NUM2SYSCALLID(x) NUM2INT(x)
08995 # define RETVAL2NUM(x) INT2NUM(x)
08996 int num, retval = -1;
08997 #endif
08998 int i;
08999
09000 if (RTEST(ruby_verbose)) {
09001 rb_warning("We plan to remove a syscall function at future release. DL(Fiddle) provides safer alternative.");
09002 }
09003
09004 rb_secure(2);
09005 if (argc == 0)
09006 rb_raise(rb_eArgError, "too few arguments for syscall");
09007 if (argc > numberof(arg))
09008 rb_raise(rb_eArgError, "too many arguments for syscall");
09009 num = NUM2SYSCALLID(argv[0]); ++argv;
09010 for (i = argc - 1; i--; ) {
09011 VALUE v = rb_check_string_type(argv[i]);
09012
09013 if (!NIL_P(v)) {
09014 SafeStringValue(v);
09015 rb_str_modify(v);
09016 arg[i] = (VALUE)StringValueCStr(v);
09017 }
09018 else {
09019 arg[i] = (VALUE)NUM2LONG(argv[i]);
09020 }
09021 }
09022
09023 switch (argc) {
09024 case 1:
09025 retval = SYSCALL(num);
09026 break;
09027 case 2:
09028 retval = SYSCALL(num, arg[0]);
09029 break;
09030 case 3:
09031 retval = SYSCALL(num, arg[0],arg[1]);
09032 break;
09033 case 4:
09034 retval = SYSCALL(num, arg[0],arg[1],arg[2]);
09035 break;
09036 case 5:
09037 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3]);
09038 break;
09039 case 6:
09040 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4]);
09041 break;
09042 case 7:
09043 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5]);
09044 break;
09045 case 8:
09046 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6]);
09047 break;
09048 #ifdef atarist
09049 case 9:
09050 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6],
09051 arg[7]);
09052 break;
09053 case 10:
09054 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6],
09055 arg[7], arg[8]);
09056 break;
09057 case 11:
09058 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6],
09059 arg[7], arg[8], arg[9]);
09060 break;
09061 case 12:
09062 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6],
09063 arg[7], arg[8], arg[9], arg[10]);
09064 break;
09065 case 13:
09066 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6],
09067 arg[7], arg[8], arg[9], arg[10], arg[11]);
09068 break;
09069 case 14:
09070 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6],
09071 arg[7], arg[8], arg[9], arg[10], arg[11], arg[12]);
09072 break;
09073 #endif
09074 }
09075
09076 if (retval == -1)
09077 rb_sys_fail(0);
09078 return RETVAL2NUM(retval);
09079 #undef SYSCALL
09080 #undef NUM2SYSCALLID
09081 #undef RETVAL2NUM
09082 }
09083 #else
09084 #define rb_f_syscall rb_f_notimplement
09085 #endif
09086
09087 static VALUE
09088 io_new_instance(VALUE args)
09089 {
09090 return rb_class_new_instance(2, (VALUE*)args+1, *(VALUE*)args);
09091 }
09092
09093 static rb_encoding *
09094 find_encoding(VALUE v)
09095 {
09096 rb_encoding *enc = rb_find_encoding(v);
09097 if (!enc) unsupported_encoding(StringValueCStr(v));
09098 return enc;
09099 }
09100
09101 static void
09102 io_encoding_set(rb_io_t *fptr, VALUE v1, VALUE v2, VALUE opt)
09103 {
09104 rb_encoding *enc, *enc2;
09105 int ecflags = fptr->encs.ecflags;
09106 VALUE ecopts, tmp;
09107
09108 if (!NIL_P(v2)) {
09109 enc2 = find_encoding(v1);
09110 tmp = rb_check_string_type(v2);
09111 if (!NIL_P(tmp)) {
09112 if (RSTRING_LEN(tmp) == 1 && RSTRING_PTR(tmp)[0] == '-') {
09113
09114 enc = enc2;
09115 enc2 = NULL;
09116 }
09117 else
09118 enc = find_encoding(v2);
09119 if (enc == enc2) {
09120
09121 enc2 = NULL;
09122 }
09123 }
09124 else {
09125 enc = find_encoding(v2);
09126 if (enc == enc2) {
09127
09128 enc2 = NULL;
09129 }
09130 }
09131 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
09132 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
09133 }
09134 else {
09135 if (NIL_P(v1)) {
09136
09137 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
09138 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
09139 ecopts = Qnil;
09140 }
09141 else {
09142 tmp = rb_check_string_type(v1);
09143 if (!NIL_P(tmp) && rb_enc_asciicompat(rb_enc_get(tmp))) {
09144 parse_mode_enc(RSTRING_PTR(tmp), &enc, &enc2, NULL);
09145 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
09146 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
09147 }
09148 else {
09149 rb_io_ext_int_to_encs(find_encoding(v1), NULL, &enc, &enc2, 0);
09150 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
09151 ecopts = Qnil;
09152 }
09153 }
09154 }
09155 validate_enc_binmode(&fptr->mode, ecflags, enc, enc2);
09156 fptr->encs.enc = enc;
09157 fptr->encs.enc2 = enc2;
09158 fptr->encs.ecflags = ecflags;
09159 fptr->encs.ecopts = ecopts;
09160 clear_codeconv(fptr);
09161
09162 }
09163
09164 static VALUE
09165 pipe_pair_close(VALUE rw)
09166 {
09167 VALUE *rwp = (VALUE *)rw;
09168 return rb_ensure(io_close, rwp[0], io_close, rwp[1]);
09169 }
09170
09171
09172
09173
09174
09175
09176
09177
09178
09179
09180
09181
09182
09183
09184
09185
09186
09187
09188
09189
09190
09191
09192
09193
09194
09195
09196
09197
09198
09199
09200
09201
09202
09203
09204
09205
09206
09207
09208
09209
09210
09211
09212
09213
09214
09215
09216
09217
09218
09219
09220
09221
09222
09223
09224
09225
09226
09227
09228
09229
09230
09231 static VALUE
09232 rb_io_s_pipe(int argc, VALUE *argv, VALUE klass)
09233 {
09234 int pipes[2], state;
09235 VALUE r, w, args[3], v1, v2;
09236 VALUE opt;
09237 rb_io_t *fptr, *fptr2;
09238 int fmode = 0;
09239 VALUE ret;
09240
09241 argc = rb_scan_args(argc, argv, "02:", &v1, &v2, &opt);
09242 if (rb_pipe(pipes) == -1)
09243 rb_sys_fail(0);
09244
09245 args[0] = klass;
09246 args[1] = INT2NUM(pipes[0]);
09247 args[2] = INT2FIX(O_RDONLY);
09248 r = rb_protect(io_new_instance, (VALUE)args, &state);
09249 if (state) {
09250 close(pipes[0]);
09251 close(pipes[1]);
09252 rb_jump_tag(state);
09253 }
09254 GetOpenFile(r, fptr);
09255 io_encoding_set(fptr, v1, v2, opt);
09256 args[1] = INT2NUM(pipes[1]);
09257 args[2] = INT2FIX(O_WRONLY);
09258 w = rb_protect(io_new_instance, (VALUE)args, &state);
09259 if (state) {
09260 close(pipes[1]);
09261 if (!NIL_P(r)) rb_io_close(r);
09262 rb_jump_tag(state);
09263 }
09264 GetOpenFile(w, fptr2);
09265 rb_io_synchronized(fptr2);
09266
09267 extract_binmode(opt, &fmode);
09268 #if DEFAULT_TEXTMODE
09269 if ((fptr->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
09270 fptr->mode &= ~FMODE_TEXTMODE;
09271 setmode(fptr->fd, O_BINARY);
09272 }
09273 #if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)
09274 if (fptr->encs.ecflags & ECONV_DEFAULT_NEWLINE_DECORATOR) {
09275 fptr->encs.ecflags |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;
09276 }
09277 #endif
09278 #endif
09279 fptr->mode |= fmode;
09280 #if DEFAULT_TEXTMODE
09281 if ((fptr2->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
09282 fptr2->mode &= ~FMODE_TEXTMODE;
09283 setmode(fptr2->fd, O_BINARY);
09284 }
09285 #endif
09286 fptr2->mode |= fmode;
09287
09288 ret = rb_assoc_new(r, w);
09289 if (rb_block_given_p()) {
09290 VALUE rw[2];
09291 rw[0] = r;
09292 rw[1] = w;
09293 return rb_ensure(rb_yield, ret, pipe_pair_close, (VALUE)rw);
09294 }
09295 return ret;
09296 }
09297
09298 struct foreach_arg {
09299 int argc;
09300 VALUE *argv;
09301 VALUE io;
09302 };
09303
09304 static void
09305 open_key_args(int argc, VALUE *argv, VALUE opt, struct foreach_arg *arg)
09306 {
09307 VALUE path, v;
09308
09309 path = *argv++;
09310 argc--;
09311 FilePathValue(path);
09312 arg->io = 0;
09313 arg->argc = argc;
09314 arg->argv = argv;
09315 if (NIL_P(opt)) {
09316 arg->io = rb_io_open(path, INT2NUM(O_RDONLY), INT2FIX(0666), Qnil);
09317 return;
09318 }
09319 v = rb_hash_aref(opt, sym_open_args);
09320 if (!NIL_P(v)) {
09321 VALUE args;
09322 long n;
09323
09324 v = rb_convert_type(v, T_ARRAY, "Array", "to_ary");
09325 n = RARRAY_LEN(v) + 1;
09326 #if SIZEOF_LONG > SIZEOF_INT
09327 if (n > INT_MAX) {
09328 rb_raise(rb_eArgError, "too many arguments");
09329 }
09330 #endif
09331 args = rb_ary_tmp_new(n);
09332 rb_ary_push(args, path);
09333 rb_ary_concat(args, v);
09334 arg->io = rb_io_open_with_args((int)n, RARRAY_PTR(args));
09335 rb_ary_clear(args);
09336 return;
09337 }
09338 arg->io = rb_io_open(path, Qnil, Qnil, opt);
09339 }
09340
09341 static VALUE
09342 io_s_foreach(struct foreach_arg *arg)
09343 {
09344 VALUE str;
09345
09346 while (!NIL_P(str = rb_io_gets_m(arg->argc, arg->argv, arg->io))) {
09347 rb_yield(str);
09348 }
09349 return Qnil;
09350 }
09351
09352
09353
09354
09355
09356
09357
09358
09359
09360
09361
09362
09363
09364
09365
09366
09367
09368
09369
09370
09371
09372
09373
09374
09375
09376
09377
09378 static VALUE
09379 rb_io_s_foreach(int argc, VALUE *argv, VALUE self)
09380 {
09381 VALUE opt;
09382 int orig_argc = argc;
09383 struct foreach_arg arg;
09384
09385 argc = rb_scan_args(argc, argv, "13:", NULL, NULL, NULL, NULL, &opt);
09386 RETURN_ENUMERATOR(self, orig_argc, argv);
09387 open_key_args(argc, argv, opt, &arg);
09388 if (NIL_P(arg.io)) return Qnil;
09389 return rb_ensure(io_s_foreach, (VALUE)&arg, rb_io_close, arg.io);
09390 }
09391
09392 static VALUE
09393 io_s_readlines(struct foreach_arg *arg)
09394 {
09395 return rb_io_readlines(arg->argc, arg->argv, arg->io);
09396 }
09397
09398
09399
09400
09401
09402
09403
09404
09405
09406
09407
09408
09409
09410
09411
09412
09413
09414
09415
09416 static VALUE
09417 rb_io_s_readlines(int argc, VALUE *argv, VALUE io)
09418 {
09419 VALUE opt;
09420 struct foreach_arg arg;
09421
09422 argc = rb_scan_args(argc, argv, "13:", NULL, NULL, NULL, NULL, &opt);
09423 open_key_args(argc, argv, opt, &arg);
09424 if (NIL_P(arg.io)) return Qnil;
09425 return rb_ensure(io_s_readlines, (VALUE)&arg, rb_io_close, arg.io);
09426 }
09427
09428 static VALUE
09429 io_s_read(struct foreach_arg *arg)
09430 {
09431 return io_read(arg->argc, arg->argv, arg->io);
09432 }
09433
09434 struct seek_arg {
09435 VALUE io;
09436 VALUE offset;
09437 int mode;
09438 };
09439
09440 static VALUE
09441 seek_before_access(VALUE argp)
09442 {
09443 struct seek_arg *arg = (struct seek_arg *)argp;
09444 rb_io_binmode(arg->io);
09445 return rb_io_seek(arg->io, arg->offset, arg->mode);
09446 }
09447
09448
09449
09450
09451
09452
09453
09454
09455
09456
09457
09458
09459
09460
09461
09462
09463
09464
09465
09466
09467
09468
09469
09470
09471
09472
09473
09474
09475
09476
09477
09478
09479
09480
09481
09482
09483
09484 static VALUE
09485 rb_io_s_read(int argc, VALUE *argv, VALUE io)
09486 {
09487 VALUE opt, offset;
09488 struct foreach_arg arg;
09489
09490 argc = rb_scan_args(argc, argv, "13:", NULL, NULL, &offset, NULL, &opt);
09491 open_key_args(argc, argv, opt, &arg);
09492 if (NIL_P(arg.io)) return Qnil;
09493 if (!NIL_P(offset)) {
09494 struct seek_arg sarg;
09495 int state = 0;
09496 sarg.io = arg.io;
09497 sarg.offset = offset;
09498 sarg.mode = SEEK_SET;
09499 rb_protect(seek_before_access, (VALUE)&sarg, &state);
09500 if (state) {
09501 rb_io_close(arg.io);
09502 rb_jump_tag(state);
09503 }
09504 if (arg.argc == 2) arg.argc = 1;
09505 }
09506 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
09507 }
09508
09509
09510
09511
09512
09513
09514
09515
09516
09517
09518
09519
09520
09521
09522
09523 static VALUE
09524 rb_io_s_binread(int argc, VALUE *argv, VALUE io)
09525 {
09526 VALUE offset;
09527 struct foreach_arg arg;
09528
09529 rb_scan_args(argc, argv, "12", NULL, NULL, &offset);
09530 FilePathValue(argv[0]);
09531 arg.io = rb_io_open(argv[0], rb_str_new_cstr("rb:ASCII-8BIT"), Qnil, Qnil);
09532 if (NIL_P(arg.io)) return Qnil;
09533 arg.argv = argv+1;
09534 arg.argc = (argc > 1) ? 1 : 0;
09535 if (!NIL_P(offset)) {
09536 rb_io_seek(arg.io, offset, SEEK_SET);
09537 }
09538 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
09539 }
09540
09541 static VALUE
09542 io_s_write0(struct write_arg *arg)
09543 {
09544 return io_write(arg->io,arg->str,arg->nosync);
09545 }
09546
09547 static VALUE
09548 io_s_write(int argc, VALUE *argv, int binary)
09549 {
09550 VALUE string, offset, opt;
09551 struct foreach_arg arg;
09552 struct write_arg warg;
09553
09554 rb_scan_args(argc, argv, "21:", NULL, &string, &offset, &opt);
09555
09556 if (NIL_P(opt)) opt = rb_hash_new();
09557 else opt = rb_hash_dup(opt);
09558
09559
09560 if (NIL_P(rb_hash_aref(opt,sym_mode))) {
09561 int mode = O_WRONLY|O_CREAT;
09562 #ifdef O_BINARY
09563 if (binary) mode |= O_BINARY;
09564 #endif
09565 if (NIL_P(offset)) mode |= O_TRUNC;
09566 rb_hash_aset(opt,sym_mode,INT2NUM(mode));
09567 }
09568 open_key_args(argc,argv,opt,&arg);
09569
09570 #ifndef O_BINARY
09571 if (binary) rb_io_binmode_m(arg.io);
09572 #endif
09573
09574 if (NIL_P(arg.io)) return Qnil;
09575 if (!NIL_P(offset)) {
09576 struct seek_arg sarg;
09577 int state = 0;
09578 sarg.io = arg.io;
09579 sarg.offset = offset;
09580 sarg.mode = SEEK_SET;
09581 rb_protect(seek_before_access, (VALUE)&sarg, &state);
09582 if (state) {
09583 rb_io_close(arg.io);
09584 rb_jump_tag(state);
09585 }
09586 }
09587
09588 warg.io = arg.io;
09589 warg.str = string;
09590 warg.nosync = 0;
09591
09592 return rb_ensure(io_s_write0, (VALUE)&warg, rb_io_close, arg.io);
09593 }
09594
09595
09596
09597
09598
09599
09600
09601
09602
09603
09604
09605
09606
09607
09608
09609
09610
09611
09612
09613
09614
09615
09616
09617
09618
09619
09620
09621
09622
09623
09624
09625
09626
09627
09628
09629
09630
09631
09632
09633
09634 static VALUE
09635 rb_io_s_write(int argc, VALUE *argv, VALUE io)
09636 {
09637 return io_s_write(argc, argv, 0);
09638 }
09639
09640
09641
09642
09643
09644
09645
09646
09647
09648
09649
09650 static VALUE
09651 rb_io_s_binwrite(int argc, VALUE *argv, VALUE io)
09652 {
09653 return io_s_write(argc, argv, 1);
09654 }
09655
09656 struct copy_stream_struct {
09657 VALUE src;
09658 VALUE dst;
09659 off_t copy_length;
09660 off_t src_offset;
09661
09662 int src_fd;
09663 int dst_fd;
09664 int close_src;
09665 int close_dst;
09666 off_t total;
09667 const char *syserr;
09668 int error_no;
09669 const char *notimp;
09670 rb_fdset_t fds;
09671 VALUE th;
09672 };
09673
09674 static void *
09675 exec_interrupts(void *arg)
09676 {
09677 VALUE th = (VALUE)arg;
09678 rb_thread_execute_interrupts(th);
09679 return NULL;
09680 }
09681
09682
09683
09684
09685
09686
09687 static int
09688 maygvl_copy_stream_continue_p(int has_gvl, struct copy_stream_struct *stp)
09689 {
09690 switch (errno) {
09691 case EINTR:
09692 #if defined(ERESTART)
09693 case ERESTART:
09694 #endif
09695 if (rb_thread_interrupted(stp->th)) {
09696 if (has_gvl)
09697 rb_thread_execute_interrupts(stp->th);
09698 else
09699 rb_thread_call_with_gvl(exec_interrupts, (void *)stp->th);
09700 }
09701 return TRUE;
09702 }
09703 return FALSE;
09704 }
09705
09706 static int
09707 maygvl_select(int has_gvl, int n, rb_fdset_t *rfds, rb_fdset_t *wfds, rb_fdset_t *efds, struct timeval *timeout)
09708 {
09709 if (has_gvl)
09710 return rb_thread_fd_select(n, rfds, wfds, efds, timeout);
09711 else
09712 return rb_fd_select(n, rfds, wfds, efds, timeout);
09713 }
09714
09715 static int
09716 maygvl_copy_stream_wait_read(int has_gvl, struct copy_stream_struct *stp)
09717 {
09718 int ret;
09719
09720 do {
09721 rb_fd_zero(&stp->fds);
09722 rb_fd_set(stp->src_fd, &stp->fds);
09723 ret = maygvl_select(has_gvl, rb_fd_max(&stp->fds), &stp->fds, NULL, NULL, NULL);
09724 } while (ret == -1 && maygvl_copy_stream_continue_p(has_gvl, stp));
09725
09726 if (ret == -1) {
09727 stp->syserr = "select";
09728 stp->error_no = errno;
09729 return -1;
09730 }
09731 return 0;
09732 }
09733
09734 static int
09735 nogvl_copy_stream_wait_write(struct copy_stream_struct *stp)
09736 {
09737 int ret;
09738
09739 do {
09740 rb_fd_zero(&stp->fds);
09741 rb_fd_set(stp->dst_fd, &stp->fds);
09742 ret = rb_fd_select(rb_fd_max(&stp->fds), NULL, &stp->fds, NULL, NULL);
09743 } while (ret == -1 && maygvl_copy_stream_continue_p(0, stp));
09744
09745 if (ret == -1) {
09746 stp->syserr = "select";
09747 stp->error_no = errno;
09748 return -1;
09749 }
09750 return 0;
09751 }
09752
09753 #ifdef HAVE_SENDFILE
09754
09755 # ifdef __linux__
09756 # define USE_SENDFILE
09757
09758 # ifdef HAVE_SYS_SENDFILE_H
09759 # include <sys/sendfile.h>
09760 # endif
09761
09762 static ssize_t
09763 simple_sendfile(int out_fd, int in_fd, off_t *offset, off_t count)
09764 {
09765 return sendfile(out_fd, in_fd, offset, (size_t)count);
09766 }
09767
09768 # elif 0 || defined(__APPLE__)
09769
09770
09771
09772 # define USE_SENDFILE
09773
09774 # ifdef HAVE_SYS_UIO_H
09775 # include <sys/uio.h>
09776 # endif
09777
09778 static ssize_t
09779 simple_sendfile(int out_fd, int in_fd, off_t *offset, off_t count)
09780 {
09781 int r;
09782 off_t pos = offset ? *offset : lseek(in_fd, 0, SEEK_CUR);
09783 off_t sbytes;
09784 # ifdef __APPLE__
09785 r = sendfile(in_fd, out_fd, pos, &count, NULL, 0);
09786 sbytes = count;
09787 # else
09788 r = sendfile(in_fd, out_fd, pos, (size_t)count, NULL, &sbytes, 0);
09789 # endif
09790 if (r != 0 && sbytes == 0) return -1;
09791 if (offset) {
09792 *offset += sbytes;
09793 }
09794 else {
09795 lseek(in_fd, sbytes, SEEK_CUR);
09796 }
09797 return (ssize_t)sbytes;
09798 }
09799
09800 # endif
09801
09802 #endif
09803
09804 #ifdef USE_SENDFILE
09805 static int
09806 nogvl_copy_stream_sendfile(struct copy_stream_struct *stp)
09807 {
09808 struct stat src_stat, dst_stat;
09809 ssize_t ss;
09810 int ret;
09811
09812 off_t copy_length;
09813 off_t src_offset;
09814 int use_pread;
09815
09816 ret = fstat(stp->src_fd, &src_stat);
09817 if (ret == -1) {
09818 stp->syserr = "fstat";
09819 stp->error_no = errno;
09820 return -1;
09821 }
09822 if (!S_ISREG(src_stat.st_mode))
09823 return 0;
09824
09825 ret = fstat(stp->dst_fd, &dst_stat);
09826 if (ret == -1) {
09827 stp->syserr = "fstat";
09828 stp->error_no = errno;
09829 return -1;
09830 }
09831 if ((dst_stat.st_mode & S_IFMT) != S_IFSOCK)
09832 return 0;
09833
09834 src_offset = stp->src_offset;
09835 use_pread = src_offset != (off_t)-1;
09836
09837 copy_length = stp->copy_length;
09838 if (copy_length == (off_t)-1) {
09839 if (use_pread)
09840 copy_length = src_stat.st_size - src_offset;
09841 else {
09842 off_t cur;
09843 errno = 0;
09844 cur = lseek(stp->src_fd, 0, SEEK_CUR);
09845 if (cur == (off_t)-1 && errno) {
09846 stp->syserr = "lseek";
09847 stp->error_no = errno;
09848 return -1;
09849 }
09850 copy_length = src_stat.st_size - cur;
09851 }
09852 }
09853
09854 retry_sendfile:
09855 # if SIZEOF_OFF_T > SIZEOF_SIZE_T
09856
09857 ss = (copy_length > (off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
09858 # else
09859 ss = (ssize_t)copy_length;
09860 # endif
09861 if (use_pread) {
09862 ss = simple_sendfile(stp->dst_fd, stp->src_fd, &src_offset, ss);
09863 }
09864 else {
09865 ss = simple_sendfile(stp->dst_fd, stp->src_fd, NULL, ss);
09866 }
09867 if (0 < ss) {
09868 stp->total += ss;
09869 copy_length -= ss;
09870 if (0 < copy_length) {
09871 goto retry_sendfile;
09872 }
09873 }
09874 if (ss == -1) {
09875 if (maygvl_copy_stream_continue_p(0, stp))
09876 goto retry_sendfile;
09877 switch (errno) {
09878 case EINVAL:
09879 #ifdef ENOSYS
09880 case ENOSYS:
09881 #endif
09882 return 0;
09883 case EAGAIN:
09884 #if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
09885 case EWOULDBLOCK:
09886 #endif
09887 #ifndef __linux__
09888
09889
09890
09891
09892
09893
09894
09895 if (maygvl_copy_stream_wait_read(0, stp) == -1)
09896 return -1;
09897 #endif
09898 if (nogvl_copy_stream_wait_write(stp) == -1)
09899 return -1;
09900 goto retry_sendfile;
09901 }
09902 stp->syserr = "sendfile";
09903 stp->error_no = errno;
09904 return -1;
09905 }
09906 return 1;
09907 }
09908 #endif
09909
09910 static ssize_t
09911 maygvl_read(int has_gvl, int fd, void *buf, size_t count)
09912 {
09913 if (has_gvl)
09914 return rb_read_internal(fd, buf, count);
09915 else
09916 return read(fd, buf, count);
09917 }
09918
09919 static ssize_t
09920 maygvl_copy_stream_read(int has_gvl, struct copy_stream_struct *stp, char *buf, size_t len, off_t offset)
09921 {
09922 ssize_t ss;
09923 retry_read:
09924 if (offset == (off_t)-1) {
09925 ss = maygvl_read(has_gvl, stp->src_fd, buf, len);
09926 }
09927 else {
09928 #ifdef HAVE_PREAD
09929 ss = pread(stp->src_fd, buf, len, offset);
09930 #else
09931 stp->notimp = "pread";
09932 return -1;
09933 #endif
09934 }
09935 if (ss == 0) {
09936 return 0;
09937 }
09938 if (ss == -1) {
09939 if (maygvl_copy_stream_continue_p(has_gvl, stp))
09940 goto retry_read;
09941 switch (errno) {
09942 case EAGAIN:
09943 #if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
09944 case EWOULDBLOCK:
09945 #endif
09946 if (maygvl_copy_stream_wait_read(has_gvl, stp) == -1)
09947 return -1;
09948 goto retry_read;
09949 #ifdef ENOSYS
09950 case ENOSYS:
09951 #endif
09952 stp->notimp = "pread";
09953 return -1;
09954 }
09955 stp->syserr = offset == (off_t)-1 ? "read" : "pread";
09956 stp->error_no = errno;
09957 return -1;
09958 }
09959 return ss;
09960 }
09961
09962 static int
09963 nogvl_copy_stream_write(struct copy_stream_struct *stp, char *buf, size_t len)
09964 {
09965 ssize_t ss;
09966 int off = 0;
09967 while (len) {
09968 ss = write(stp->dst_fd, buf+off, len);
09969 if (ss == -1) {
09970 if (maygvl_copy_stream_continue_p(0, stp))
09971 continue;
09972 if (errno == EAGAIN || errno == EWOULDBLOCK) {
09973 if (nogvl_copy_stream_wait_write(stp) == -1)
09974 return -1;
09975 continue;
09976 }
09977 stp->syserr = "write";
09978 stp->error_no = errno;
09979 return -1;
09980 }
09981 off += (int)ss;
09982 len -= (int)ss;
09983 stp->total += ss;
09984 }
09985 return 0;
09986 }
09987
09988 static void
09989 nogvl_copy_stream_read_write(struct copy_stream_struct *stp)
09990 {
09991 char buf[1024*16];
09992 size_t len;
09993 ssize_t ss;
09994 int ret;
09995 off_t copy_length;
09996 int use_eof;
09997 off_t src_offset;
09998 int use_pread;
09999
10000 copy_length = stp->copy_length;
10001 use_eof = copy_length == (off_t)-1;
10002 src_offset = stp->src_offset;
10003 use_pread = src_offset != (off_t)-1;
10004
10005 if (use_pread && stp->close_src) {
10006 off_t r;
10007 errno = 0;
10008 r = lseek(stp->src_fd, src_offset, SEEK_SET);
10009 if (r == (off_t)-1 && errno) {
10010 stp->syserr = "lseek";
10011 stp->error_no = errno;
10012 return;
10013 }
10014 src_offset = (off_t)-1;
10015 use_pread = 0;
10016 }
10017
10018 while (use_eof || 0 < copy_length) {
10019 if (!use_eof && copy_length < (off_t)sizeof(buf)) {
10020 len = (size_t)copy_length;
10021 }
10022 else {
10023 len = sizeof(buf);
10024 }
10025 if (use_pread) {
10026 ss = maygvl_copy_stream_read(0, stp, buf, len, src_offset);
10027 if (0 < ss)
10028 src_offset += ss;
10029 }
10030 else {
10031 ss = maygvl_copy_stream_read(0, stp, buf, len, (off_t)-1);
10032 }
10033 if (ss <= 0)
10034 return;
10035
10036 ret = nogvl_copy_stream_write(stp, buf, ss);
10037 if (ret < 0)
10038 return;
10039
10040 if (!use_eof)
10041 copy_length -= ss;
10042 }
10043 }
10044
10045 static void *
10046 nogvl_copy_stream_func(void *arg)
10047 {
10048 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
10049 #ifdef USE_SENDFILE
10050 int ret;
10051 #endif
10052
10053 #ifdef USE_SENDFILE
10054 ret = nogvl_copy_stream_sendfile(stp);
10055 if (ret != 0)
10056 goto finish;
10057 #endif
10058
10059 nogvl_copy_stream_read_write(stp);
10060
10061 #ifdef USE_SENDFILE
10062 finish:
10063 #endif
10064 return 0;
10065 }
10066
10067 static VALUE
10068 copy_stream_fallback_body(VALUE arg)
10069 {
10070 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
10071 const int buflen = 16*1024;
10072 VALUE n;
10073 VALUE buf = rb_str_buf_new(buflen);
10074 off_t rest = stp->copy_length;
10075 off_t off = stp->src_offset;
10076 ID read_method = id_readpartial;
10077
10078 if (stp->src_fd == -1) {
10079 if (!rb_respond_to(stp->src, read_method)) {
10080 read_method = id_read;
10081 }
10082 }
10083
10084 while (1) {
10085 long numwrote;
10086 long l;
10087 if (stp->copy_length == (off_t)-1) {
10088 l = buflen;
10089 }
10090 else {
10091 if (rest == 0)
10092 break;
10093 l = buflen < rest ? buflen : (long)rest;
10094 }
10095 if (stp->src_fd == -1) {
10096 VALUE rc = rb_funcall(stp->src, read_method, 2, INT2FIX(l), buf);
10097
10098 if (read_method == id_read && NIL_P(rc))
10099 break;
10100 }
10101 else {
10102 ssize_t ss;
10103 rb_str_resize(buf, buflen);
10104 ss = maygvl_copy_stream_read(1, stp, RSTRING_PTR(buf), l, off);
10105 if (ss == -1)
10106 return Qnil;
10107 if (ss == 0)
10108 rb_eof_error();
10109 rb_str_resize(buf, ss);
10110 if (off != (off_t)-1)
10111 off += ss;
10112 }
10113 n = rb_io_write(stp->dst, buf);
10114 numwrote = NUM2LONG(n);
10115 stp->total += numwrote;
10116 rest -= numwrote;
10117 if (read_method == id_read && RSTRING_LEN(buf) == 0) {
10118 break;
10119 }
10120 }
10121
10122 return Qnil;
10123 }
10124
10125 static VALUE
10126 copy_stream_fallback(struct copy_stream_struct *stp)
10127 {
10128 if (stp->src_fd == -1 && stp->src_offset != (off_t)-1) {
10129 rb_raise(rb_eArgError, "cannot specify src_offset for non-IO");
10130 }
10131 rb_rescue2(copy_stream_fallback_body, (VALUE)stp,
10132 (VALUE (*) (ANYARGS))0, (VALUE)0,
10133 rb_eEOFError, (VALUE)0);
10134 return Qnil;
10135 }
10136
10137 static VALUE
10138 copy_stream_body(VALUE arg)
10139 {
10140 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
10141 VALUE src_io, dst_io;
10142 rb_io_t *src_fptr = 0, *dst_fptr = 0;
10143 int src_fd, dst_fd;
10144
10145 stp->th = rb_thread_current();
10146
10147 stp->total = 0;
10148
10149 if (stp->src == argf ||
10150 !(RB_TYPE_P(stp->src, T_FILE) ||
10151 RB_TYPE_P(stp->src, T_STRING) ||
10152 rb_respond_to(stp->src, rb_intern("to_path")))) {
10153 src_fd = -1;
10154 }
10155 else {
10156 src_io = RB_TYPE_P(stp->src, T_FILE) ? stp->src : Qnil;
10157 if (NIL_P(src_io)) {
10158 VALUE args[2];
10159 int oflags = O_RDONLY;
10160 #ifdef O_NOCTTY
10161 oflags |= O_NOCTTY;
10162 #endif
10163 FilePathValue(stp->src);
10164 args[0] = stp->src;
10165 args[1] = INT2NUM(oflags);
10166 src_io = rb_class_new_instance(2, args, rb_cFile);
10167 stp->src = src_io;
10168 stp->close_src = 1;
10169 }
10170 GetOpenFile(src_io, src_fptr);
10171 rb_io_check_byte_readable(src_fptr);
10172 src_fd = src_fptr->fd;
10173 }
10174 stp->src_fd = src_fd;
10175
10176 if (stp->dst == argf ||
10177 !(RB_TYPE_P(stp->dst, T_FILE) ||
10178 RB_TYPE_P(stp->dst, T_STRING) ||
10179 rb_respond_to(stp->dst, rb_intern("to_path")))) {
10180 dst_fd = -1;
10181 }
10182 else {
10183 dst_io = RB_TYPE_P(stp->dst, T_FILE) ? stp->dst : Qnil;
10184 if (NIL_P(dst_io)) {
10185 VALUE args[3];
10186 int oflags = O_WRONLY|O_CREAT|O_TRUNC;
10187 #ifdef O_NOCTTY
10188 oflags |= O_NOCTTY;
10189 #endif
10190 FilePathValue(stp->dst);
10191 args[0] = stp->dst;
10192 args[1] = INT2NUM(oflags);
10193 args[2] = INT2FIX(0666);
10194 dst_io = rb_class_new_instance(3, args, rb_cFile);
10195 stp->dst = dst_io;
10196 stp->close_dst = 1;
10197 }
10198 else {
10199 dst_io = GetWriteIO(dst_io);
10200 stp->dst = dst_io;
10201 }
10202 GetOpenFile(dst_io, dst_fptr);
10203 rb_io_check_writable(dst_fptr);
10204 dst_fd = dst_fptr->fd;
10205 }
10206 stp->dst_fd = dst_fd;
10207
10208 #ifdef O_BINARY
10209 if (src_fptr)
10210 SET_BINARY_MODE_WITH_SEEK_CUR(src_fptr);
10211 #endif
10212 if (dst_fptr)
10213 rb_io_ascii8bit_binmode(dst_io);
10214
10215 if (stp->src_offset == (off_t)-1 && src_fptr && src_fptr->rbuf.len) {
10216 size_t len = src_fptr->rbuf.len;
10217 VALUE str;
10218 if (stp->copy_length != (off_t)-1 && stp->copy_length < (off_t)len) {
10219 len = (size_t)stp->copy_length;
10220 }
10221 str = rb_str_buf_new(len);
10222 rb_str_resize(str,len);
10223 read_buffered_data(RSTRING_PTR(str), len, src_fptr);
10224 if (dst_fptr) {
10225 if (io_binwrite(str, RSTRING_PTR(str), RSTRING_LEN(str), dst_fptr, 0) < 0)
10226 rb_sys_fail(0);
10227 }
10228 else
10229 rb_io_write(stp->dst, str);
10230 stp->total += len;
10231 if (stp->copy_length != (off_t)-1)
10232 stp->copy_length -= len;
10233 }
10234
10235 if (dst_fptr && io_fflush(dst_fptr) < 0) {
10236 rb_raise(rb_eIOError, "flush failed");
10237 }
10238
10239 if (stp->copy_length == 0)
10240 return Qnil;
10241
10242 if (src_fd == -1 || dst_fd == -1) {
10243 return copy_stream_fallback(stp);
10244 }
10245
10246 rb_fd_set(src_fd, &stp->fds);
10247 rb_fd_set(dst_fd, &stp->fds);
10248
10249 rb_thread_call_without_gvl(nogvl_copy_stream_func, (void*)stp, RUBY_UBF_IO, 0);
10250 return Qnil;
10251 }
10252
10253 static VALUE
10254 copy_stream_finalize(VALUE arg)
10255 {
10256 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
10257 if (stp->close_src) {
10258 rb_io_close_m(stp->src);
10259 }
10260 if (stp->close_dst) {
10261 rb_io_close_m(stp->dst);
10262 }
10263 rb_fd_term(&stp->fds);
10264 if (stp->syserr) {
10265 errno = stp->error_no;
10266 rb_sys_fail(stp->syserr);
10267 }
10268 if (stp->notimp) {
10269 rb_raise(rb_eNotImpError, "%s() not implemented", stp->notimp);
10270 }
10271 return Qnil;
10272 }
10273
10274
10275
10276
10277
10278
10279
10280
10281
10282
10283
10284
10285
10286
10287
10288
10289
10290
10291
10292
10293
10294
10295
10296
10297
10298
10299
10300
10301
10302 static VALUE
10303 rb_io_s_copy_stream(int argc, VALUE *argv, VALUE io)
10304 {
10305 VALUE src, dst, length, src_offset;
10306 struct copy_stream_struct st;
10307
10308 MEMZERO(&st, struct copy_stream_struct, 1);
10309
10310 rb_scan_args(argc, argv, "22", &src, &dst, &length, &src_offset);
10311
10312 st.src = src;
10313 st.dst = dst;
10314
10315 if (NIL_P(length))
10316 st.copy_length = (off_t)-1;
10317 else
10318 st.copy_length = NUM2OFFT(length);
10319
10320 if (NIL_P(src_offset))
10321 st.src_offset = (off_t)-1;
10322 else
10323 st.src_offset = NUM2OFFT(src_offset);
10324
10325 rb_fd_init(&st.fds);
10326 rb_ensure(copy_stream_body, (VALUE)&st, copy_stream_finalize, (VALUE)&st);
10327
10328 return OFFT2NUM(st.total);
10329 }
10330
10331
10332
10333
10334
10335
10336
10337
10338
10339 static VALUE
10340 rb_io_external_encoding(VALUE io)
10341 {
10342 rb_io_t *fptr;
10343
10344 GetOpenFile(io, fptr);
10345 if (fptr->encs.enc2) {
10346 return rb_enc_from_encoding(fptr->encs.enc2);
10347 }
10348 if (fptr->mode & FMODE_WRITABLE) {
10349 if (fptr->encs.enc)
10350 return rb_enc_from_encoding(fptr->encs.enc);
10351 return Qnil;
10352 }
10353 return rb_enc_from_encoding(io_read_encoding(fptr));
10354 }
10355
10356
10357
10358
10359
10360
10361
10362
10363
10364 static VALUE
10365 rb_io_internal_encoding(VALUE io)
10366 {
10367 rb_io_t *fptr;
10368
10369 GetOpenFile(io, fptr);
10370 if (!fptr->encs.enc2) return Qnil;
10371 return rb_enc_from_encoding(io_read_encoding(fptr));
10372 }
10373
10374
10375
10376
10377
10378
10379
10380
10381
10382
10383
10384
10385
10386
10387
10388
10389
10390
10391
10392
10393 static VALUE
10394 rb_io_set_encoding(int argc, VALUE *argv, VALUE io)
10395 {
10396 rb_io_t *fptr;
10397 VALUE v1, v2, opt;
10398
10399 if (!RB_TYPE_P(io, T_FILE)) {
10400 return rb_funcall2(io, id_set_encoding, argc, argv);
10401 }
10402
10403 argc = rb_scan_args(argc, argv, "11:", &v1, &v2, &opt);
10404 GetOpenFile(io, fptr);
10405 io_encoding_set(fptr, v1, v2, opt);
10406 return io;
10407 }
10408
10409 void
10410 rb_stdio_set_default_encoding(void)
10411 {
10412 extern VALUE rb_stdin, rb_stdout, rb_stderr;
10413 VALUE val = Qnil;
10414
10415 rb_io_set_encoding(1, &val, rb_stdin);
10416 rb_io_set_encoding(1, &val, rb_stdout);
10417 rb_io_set_encoding(1, &val, rb_stderr);
10418 }
10419
10420
10421
10422
10423
10424
10425
10426
10427
10428
10429
10430
10431
10432
10433
10434
10435
10436 static VALUE
10437 argf_external_encoding(VALUE argf)
10438 {
10439 if (!RTEST(ARGF.current_file)) {
10440 return rb_enc_from_encoding(rb_default_external_encoding());
10441 }
10442 return rb_io_external_encoding(rb_io_check_io(ARGF.current_file));
10443 }
10444
10445
10446
10447
10448
10449
10450
10451
10452
10453
10454
10455
10456
10457
10458 static VALUE
10459 argf_internal_encoding(VALUE argf)
10460 {
10461 if (!RTEST(ARGF.current_file)) {
10462 return rb_enc_from_encoding(rb_default_external_encoding());
10463 }
10464 return rb_io_internal_encoding(rb_io_check_io(ARGF.current_file));
10465 }
10466
10467
10468
10469
10470
10471
10472
10473
10474
10475
10476
10477
10478
10479
10480
10481
10482
10483
10484
10485
10486
10487
10488
10489
10490
10491
10492
10493
10494
10495
10496
10497
10498 static VALUE
10499 argf_set_encoding(int argc, VALUE *argv, VALUE argf)
10500 {
10501 rb_io_t *fptr;
10502
10503 if (!next_argv()) {
10504 rb_raise(rb_eArgError, "no stream to set encoding");
10505 }
10506 rb_io_set_encoding(argc, argv, ARGF.current_file);
10507 GetOpenFile(ARGF.current_file, fptr);
10508 ARGF.encs = fptr->encs;
10509 return argf;
10510 }
10511
10512
10513
10514
10515
10516
10517
10518
10519
10520
10521
10522
10523
10524 static VALUE
10525 argf_tell(VALUE argf)
10526 {
10527 if (!next_argv()) {
10528 rb_raise(rb_eArgError, "no stream to tell");
10529 }
10530 ARGF_FORWARD(0, 0);
10531 return rb_io_tell(ARGF.current_file);
10532 }
10533
10534
10535
10536
10537
10538
10539
10540
10541 static VALUE
10542 argf_seek_m(int argc, VALUE *argv, VALUE argf)
10543 {
10544 if (!next_argv()) {
10545 rb_raise(rb_eArgError, "no stream to seek");
10546 }
10547 ARGF_FORWARD(argc, argv);
10548 return rb_io_seek_m(argc, argv, ARGF.current_file);
10549 }
10550
10551
10552
10553
10554
10555
10556
10557
10558
10559
10560
10561
10562 static VALUE
10563 argf_set_pos(VALUE argf, VALUE offset)
10564 {
10565 if (!next_argv()) {
10566 rb_raise(rb_eArgError, "no stream to set position");
10567 }
10568 ARGF_FORWARD(1, &offset);
10569 return rb_io_set_pos(ARGF.current_file, offset);
10570 }
10571
10572
10573
10574
10575
10576
10577
10578
10579
10580
10581
10582
10583
10584 static VALUE
10585 argf_rewind(VALUE argf)
10586 {
10587 if (!next_argv()) {
10588 rb_raise(rb_eArgError, "no stream to rewind");
10589 }
10590 ARGF_FORWARD(0, 0);
10591 return rb_io_rewind(ARGF.current_file);
10592 }
10593
10594
10595
10596
10597
10598
10599
10600
10601
10602
10603
10604 static VALUE
10605 argf_fileno(VALUE argf)
10606 {
10607 if (!next_argv()) {
10608 rb_raise(rb_eArgError, "no stream");
10609 }
10610 ARGF_FORWARD(0, 0);
10611 return rb_io_fileno(ARGF.current_file);
10612 }
10613
10614
10615
10616
10617
10618
10619
10620
10621
10622
10623
10624
10625
10626 static VALUE
10627 argf_to_io(VALUE argf)
10628 {
10629 next_argv();
10630 ARGF_FORWARD(0, 0);
10631 return ARGF.current_file;
10632 }
10633
10634
10635
10636
10637
10638
10639
10640
10641
10642
10643
10644
10645
10646
10647
10648
10649
10650
10651
10652 static VALUE
10653 argf_eof(VALUE argf)
10654 {
10655 next_argv();
10656 if (RTEST(ARGF.current_file)) {
10657 if (ARGF.init_p == 0) return Qtrue;
10658 next_argv();
10659 ARGF_FORWARD(0, 0);
10660 if (rb_io_eof(ARGF.current_file)) {
10661 return Qtrue;
10662 }
10663 }
10664 return Qfalse;
10665 }
10666
10667
10668
10669
10670
10671
10672
10673
10674
10675
10676
10677
10678
10679
10680
10681
10682
10683
10684
10685
10686
10687
10688
10689
10690
10691
10692
10693
10694
10695
10696
10697
10698
10699
10700
10701
10702
10703
10704
10705
10706 static VALUE
10707 argf_read(int argc, VALUE *argv, VALUE argf)
10708 {
10709 VALUE tmp, str, length;
10710 long len = 0;
10711
10712 rb_scan_args(argc, argv, "02", &length, &str);
10713 if (!NIL_P(length)) {
10714 len = NUM2LONG(argv[0]);
10715 }
10716 if (!NIL_P(str)) {
10717 StringValue(str);
10718 rb_str_resize(str,0);
10719 argv[1] = Qnil;
10720 }
10721
10722 retry:
10723 if (!next_argv()) {
10724 return str;
10725 }
10726 if (ARGF_GENERIC_INPUT_P()) {
10727 tmp = argf_forward(argc, argv, argf);
10728 }
10729 else {
10730 tmp = io_read(argc, argv, ARGF.current_file);
10731 }
10732 if (NIL_P(str)) str = tmp;
10733 else if (!NIL_P(tmp)) rb_str_append(str, tmp);
10734 if (NIL_P(tmp) || NIL_P(length)) {
10735 if (ARGF.next_p != -1) {
10736 argf_close(ARGF.current_file);
10737 ARGF.next_p = 1;
10738 goto retry;
10739 }
10740 }
10741 else if (argc >= 1) {
10742 if (RSTRING_LEN(str) < len) {
10743 len -= RSTRING_LEN(str);
10744 argv[0] = INT2NUM(len);
10745 goto retry;
10746 }
10747 }
10748 return str;
10749 }
10750
10751 struct argf_call_arg {
10752 int argc;
10753 VALUE *argv;
10754 VALUE argf;
10755 };
10756
10757 static VALUE
10758 argf_forward_call(VALUE arg)
10759 {
10760 struct argf_call_arg *p = (struct argf_call_arg *)arg;
10761 argf_forward(p->argc, p->argv, p->argf);
10762 return Qnil;
10763 }
10764
10765 static VALUE argf_getpartial(int argc, VALUE *argv, VALUE argf, int nonblock);
10766
10767
10768
10769
10770
10771
10772
10773
10774
10775
10776
10777
10778
10779
10780
10781
10782
10783
10784
10785
10786
10787
10788
10789
10790
10791
10792
10793
10794
10795
10796
10797
10798 static VALUE
10799 argf_readpartial(int argc, VALUE *argv, VALUE argf)
10800 {
10801 return argf_getpartial(argc, argv, argf, 0);
10802 }
10803
10804
10805
10806
10807
10808
10809
10810
10811
10812 static VALUE
10813 argf_read_nonblock(int argc, VALUE *argv, VALUE argf)
10814 {
10815 return argf_getpartial(argc, argv, argf, 1);
10816 }
10817
10818 static VALUE
10819 argf_getpartial(int argc, VALUE *argv, VALUE argf, int nonblock)
10820 {
10821 VALUE tmp, str, length;
10822
10823 rb_scan_args(argc, argv, "11", &length, &str);
10824 if (!NIL_P(str)) {
10825 StringValue(str);
10826 argv[1] = str;
10827 }
10828
10829 if (!next_argv()) {
10830 rb_str_resize(str, 0);
10831 rb_eof_error();
10832 }
10833 if (ARGF_GENERIC_INPUT_P()) {
10834 struct argf_call_arg arg;
10835 arg.argc = argc;
10836 arg.argv = argv;
10837 arg.argf = argf;
10838 tmp = rb_rescue2(argf_forward_call, (VALUE)&arg,
10839 RUBY_METHOD_FUNC(0), Qnil, rb_eEOFError, (VALUE)0);
10840 }
10841 else {
10842 tmp = io_getpartial(argc, argv, ARGF.current_file, nonblock);
10843 }
10844 if (NIL_P(tmp)) {
10845 if (ARGF.next_p == -1) {
10846 rb_eof_error();
10847 }
10848 argf_close(ARGF.current_file);
10849 ARGF.next_p = 1;
10850 if (RARRAY_LEN(ARGF.argv) == 0)
10851 rb_eof_error();
10852 if (NIL_P(str))
10853 str = rb_str_new(NULL, 0);
10854 return str;
10855 }
10856 return tmp;
10857 }
10858
10859
10860
10861
10862
10863
10864
10865
10866
10867
10868
10869
10870
10871
10872
10873
10874
10875
10876
10877
10878
10879
10880
10881
10882 static VALUE
10883 argf_getc(VALUE argf)
10884 {
10885 VALUE ch;
10886
10887 retry:
10888 if (!next_argv()) return Qnil;
10889 if (ARGF_GENERIC_INPUT_P()) {
10890 ch = rb_funcall3(ARGF.current_file, rb_intern("getc"), 0, 0);
10891 }
10892 else {
10893 ch = rb_io_getc(ARGF.current_file);
10894 }
10895 if (NIL_P(ch) && ARGF.next_p != -1) {
10896 argf_close(ARGF.current_file);
10897 ARGF.next_p = 1;
10898 goto retry;
10899 }
10900
10901 return ch;
10902 }
10903
10904
10905
10906
10907
10908
10909
10910
10911
10912
10913
10914
10915
10916
10917
10918
10919
10920
10921
10922 static VALUE
10923 argf_getbyte(VALUE argf)
10924 {
10925 VALUE ch;
10926
10927 retry:
10928 if (!next_argv()) return Qnil;
10929 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
10930 ch = rb_funcall3(ARGF.current_file, rb_intern("getbyte"), 0, 0);
10931 }
10932 else {
10933 ch = rb_io_getbyte(ARGF.current_file);
10934 }
10935 if (NIL_P(ch) && ARGF.next_p != -1) {
10936 argf_close(ARGF.current_file);
10937 ARGF.next_p = 1;
10938 goto retry;
10939 }
10940
10941 return ch;
10942 }
10943
10944
10945
10946
10947
10948
10949
10950
10951
10952
10953
10954
10955
10956
10957
10958
10959
10960
10961
10962 static VALUE
10963 argf_readchar(VALUE argf)
10964 {
10965 VALUE ch;
10966
10967 retry:
10968 if (!next_argv()) rb_eof_error();
10969 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
10970 ch = rb_funcall3(ARGF.current_file, rb_intern("getc"), 0, 0);
10971 }
10972 else {
10973 ch = rb_io_getc(ARGF.current_file);
10974 }
10975 if (NIL_P(ch) && ARGF.next_p != -1) {
10976 argf_close(ARGF.current_file);
10977 ARGF.next_p = 1;
10978 goto retry;
10979 }
10980
10981 return ch;
10982 }
10983
10984
10985
10986
10987
10988
10989
10990
10991
10992
10993
10994
10995
10996
10997
10998
10999
11000
11001
11002 static VALUE
11003 argf_readbyte(VALUE argf)
11004 {
11005 VALUE c;
11006
11007 NEXT_ARGF_FORWARD(0, 0);
11008 c = argf_getbyte(argf);
11009 if (NIL_P(c)) {
11010 rb_eof_error();
11011 }
11012 return c;
11013 }
11014
11015
11016
11017
11018
11019
11020
11021
11022
11023
11024
11025
11026
11027
11028
11029
11030
11031
11032
11033
11034
11035
11036
11037
11038
11039
11040
11041
11042
11043
11044
11045
11046
11047 static VALUE
11048 argf_each_line(int argc, VALUE *argv, VALUE argf)
11049 {
11050 RETURN_ENUMERATOR(argf, argc, argv);
11051 for (;;) {
11052 if (!next_argv()) return argf;
11053 rb_block_call(ARGF.current_file, rb_intern("each_line"), argc, argv, 0, 0);
11054 ARGF.next_p = 1;
11055 }
11056 }
11057
11058
11059
11060
11061
11062 static VALUE
11063 argf_lines(int argc, VALUE *argv, VALUE argf)
11064 {
11065 rb_warn("ARGF#lines is deprecated; use #each_line instead");
11066 if (!rb_block_given_p())
11067 return rb_enumeratorize(argf, ID2SYM(rb_intern("each_line")), argc, argv);
11068 return argf_each_line(argc, argv, argf);
11069 }
11070
11071
11072
11073
11074
11075
11076
11077
11078
11079
11080
11081
11082
11083
11084
11085
11086
11087
11088
11089
11090
11091
11092
11093
11094
11095 static VALUE
11096 argf_each_byte(VALUE argf)
11097 {
11098 RETURN_ENUMERATOR(argf, 0, 0);
11099 for (;;) {
11100 if (!next_argv()) return argf;
11101 rb_block_call(ARGF.current_file, rb_intern("each_byte"), 0, 0, 0, 0);
11102 ARGF.next_p = 1;
11103 }
11104 }
11105
11106
11107
11108
11109
11110 static VALUE
11111 argf_bytes(VALUE argf)
11112 {
11113 rb_warn("ARGF#bytes is deprecated; use #each_byte instead");
11114 if (!rb_block_given_p())
11115 return rb_enumeratorize(argf, ID2SYM(rb_intern("each_byte")), 0, 0);
11116 return argf_each_byte(argf);
11117 }
11118
11119
11120
11121
11122
11123
11124
11125
11126
11127
11128
11129
11130
11131
11132
11133
11134
11135 static VALUE
11136 argf_each_char(VALUE argf)
11137 {
11138 RETURN_ENUMERATOR(argf, 0, 0);
11139 for (;;) {
11140 if (!next_argv()) return argf;
11141 rb_block_call(ARGF.current_file, rb_intern("each_char"), 0, 0, 0, 0);
11142 ARGF.next_p = 1;
11143 }
11144 }
11145
11146
11147
11148
11149
11150 static VALUE
11151 argf_chars(VALUE argf)
11152 {
11153 rb_warn("ARGF#chars is deprecated; use #each_char instead");
11154 if (!rb_block_given_p())
11155 return rb_enumeratorize(argf, ID2SYM(rb_intern("each_char")), 0, 0);
11156 return argf_each_char(argf);
11157 }
11158
11159
11160
11161
11162
11163
11164
11165
11166
11167
11168
11169
11170
11171
11172
11173
11174
11175 static VALUE
11176 argf_each_codepoint(VALUE argf)
11177 {
11178 RETURN_ENUMERATOR(argf, 0, 0);
11179 for (;;) {
11180 if (!next_argv()) return argf;
11181 rb_block_call(ARGF.current_file, rb_intern("each_codepoint"), 0, 0, 0, 0);
11182 ARGF.next_p = 1;
11183 }
11184 }
11185
11186
11187
11188
11189
11190 static VALUE
11191 argf_codepoints(VALUE argf)
11192 {
11193 rb_warn("ARGF#codepoints is deprecated; use #each_codepoint instead");
11194 if (!rb_block_given_p())
11195 return rb_enumeratorize(argf, ID2SYM(rb_intern("each_codepoint")), 0, 0);
11196 return argf_each_codepoint(argf);
11197 }
11198
11199
11200
11201
11202
11203
11204
11205
11206
11207
11208
11209
11210
11211
11212
11213
11214
11215
11216
11217
11218
11219
11220
11221 static VALUE
11222 argf_filename(VALUE argf)
11223 {
11224 next_argv();
11225 return ARGF.filename;
11226 }
11227
11228 static VALUE
11229 argf_filename_getter(ID id, VALUE *var)
11230 {
11231 return argf_filename(*var);
11232 }
11233
11234
11235
11236
11237
11238
11239
11240
11241
11242
11243
11244
11245
11246
11247
11248
11249
11250
11251
11252 static VALUE
11253 argf_file(VALUE argf)
11254 {
11255 next_argv();
11256 return ARGF.current_file;
11257 }
11258
11259
11260
11261
11262
11263
11264
11265
11266
11267
11268
11269
11270 static VALUE
11271 argf_binmode_m(VALUE argf)
11272 {
11273 ARGF.binmode = 1;
11274 next_argv();
11275 ARGF_FORWARD(0, 0);
11276 rb_io_ascii8bit_binmode(ARGF.current_file);
11277 return argf;
11278 }
11279
11280
11281
11282
11283
11284
11285
11286
11287
11288
11289
11290
11291
11292
11293 static VALUE
11294 argf_binmode_p(VALUE argf)
11295 {
11296 return ARGF.binmode ? Qtrue : Qfalse;
11297 }
11298
11299
11300
11301
11302
11303
11304
11305
11306
11307
11308
11309
11310
11311
11312
11313 static VALUE
11314 argf_skip(VALUE argf)
11315 {
11316 if (ARGF.init_p && ARGF.next_p == 0) {
11317 argf_close(ARGF.current_file);
11318 ARGF.next_p = 1;
11319 }
11320 return argf;
11321 }
11322
11323
11324
11325
11326
11327
11328
11329
11330
11331
11332
11333
11334
11335
11336
11337
11338
11339
11340
11341 static VALUE
11342 argf_close_m(VALUE argf)
11343 {
11344 next_argv();
11345 argf_close(ARGF.current_file);
11346 if (ARGF.next_p != -1) {
11347 ARGF.next_p = 1;
11348 }
11349 ARGF.lineno = 0;
11350 return argf;
11351 }
11352
11353
11354
11355
11356
11357
11358
11359
11360 static VALUE
11361 argf_closed(VALUE argf)
11362 {
11363 next_argv();
11364 ARGF_FORWARD(0, 0);
11365 return rb_io_closed(ARGF.current_file);
11366 }
11367
11368
11369
11370
11371
11372
11373
11374 static VALUE
11375 argf_to_s(VALUE argf)
11376 {
11377 return rb_str_new2("ARGF");
11378 }
11379
11380
11381
11382
11383
11384
11385
11386
11387
11388 static VALUE
11389 argf_inplace_mode_get(VALUE argf)
11390 {
11391 if (!ARGF.inplace) return Qnil;
11392 return rb_str_new2(ARGF.inplace);
11393 }
11394
11395 static VALUE
11396 opt_i_get(ID id, VALUE *var)
11397 {
11398 return argf_inplace_mode_get(*var);
11399 }
11400
11401
11402
11403
11404
11405
11406
11407
11408
11409
11410
11411
11412
11413
11414
11415
11416
11417
11418
11419
11420
11421 static VALUE
11422 argf_inplace_mode_set(VALUE argf, VALUE val)
11423 {
11424 if (rb_safe_level() >= 1 && OBJ_TAINTED(val))
11425 rb_insecure_operation();
11426
11427 if (!RTEST(val)) {
11428 if (ARGF.inplace) free(ARGF.inplace);
11429 ARGF.inplace = 0;
11430 }
11431 else {
11432 StringValue(val);
11433 if (ARGF.inplace) free(ARGF.inplace);
11434 ARGF.inplace = 0;
11435 ARGF.inplace = strdup(RSTRING_PTR(val));
11436 }
11437 return argf;
11438 }
11439
11440 static void
11441 opt_i_set(VALUE val, ID id, VALUE *var)
11442 {
11443 argf_inplace_mode_set(*var, val);
11444 }
11445
11446 const char *
11447 ruby_get_inplace_mode(void)
11448 {
11449 return ARGF.inplace;
11450 }
11451
11452 void
11453 ruby_set_inplace_mode(const char *suffix)
11454 {
11455 if (ARGF.inplace) free(ARGF.inplace);
11456 ARGF.inplace = 0;
11457 if (suffix) ARGF.inplace = strdup(suffix);
11458 }
11459
11460
11461
11462
11463
11464
11465
11466
11467
11468
11469
11470
11471
11472
11473
11474 static VALUE
11475 argf_argv(VALUE argf)
11476 {
11477 return ARGF.argv;
11478 }
11479
11480 static VALUE
11481 argf_argv_getter(ID id, VALUE *var)
11482 {
11483 return argf_argv(*var);
11484 }
11485
11486 VALUE
11487 rb_get_argv(void)
11488 {
11489 return ARGF.argv;
11490 }
11491
11492
11493
11494
11495
11496
11497
11498
11499 static VALUE
11500 argf_write_io(VALUE argf)
11501 {
11502 if (!RTEST(ARGF.current_file)) {
11503 rb_raise(rb_eIOError, "not opened for writing");
11504 }
11505 return GetWriteIO(ARGF.current_file);
11506 }
11507
11508
11509
11510
11511
11512
11513
11514 static VALUE
11515 argf_write(VALUE argf, VALUE str)
11516 {
11517 return rb_io_write(argf_write_io(argf), str);
11518 }
11519
11520
11521
11522
11523
11524
11525
11526
11527
11528
11529
11530
11531
11532
11533
11534
11535
11536
11537
11538
11539
11540
11541
11542
11543
11544
11545
11546
11547
11548
11549
11550
11551
11552
11553
11554
11555
11556
11557
11558
11559
11560
11561
11562
11563
11564
11565
11566
11567
11568
11569
11570
11571
11572
11573
11574
11575
11576
11577
11578
11579
11580
11581
11582
11583
11584
11585
11586
11587
11588
11589
11590
11591
11592
11593
11594
11595
11596
11597
11598
11599
11600
11601
11602
11603
11604
11605
11606
11607
11608
11609
11610
11611
11612
11613
11614
11615
11616
11617
11618
11619
11620
11621
11622
11623
11624
11625
11626
11627
11628
11629
11630
11631
11632
11633
11634
11635
11636
11637
11638
11639
11640
11641
11642
11643
11644
11645
11646
11647
11648
11649
11650
11651
11652
11653
11654
11655
11656
11657
11658
11659
11660
11661
11662
11663
11664
11665
11666
11667
11668
11669
11670
11671
11672
11673
11674
11675 void
11676 Init_IO(void)
11677 {
11678 #undef rb_intern
11679 #define rb_intern(str) rb_intern_const(str)
11680
11681 VALUE rb_cARGF;
11682 #ifdef __CYGWIN__
11683 #include <sys/cygwin.h>
11684 static struct __cygwin_perfile pf[] =
11685 {
11686 {"", O_RDONLY | O_BINARY},
11687 {"", O_WRONLY | O_BINARY},
11688 {"", O_RDWR | O_BINARY},
11689 {"", O_APPEND | O_BINARY},
11690 {NULL, 0}
11691 };
11692 cygwin_internal(CW_PERFILE, pf);
11693 #endif
11694
11695 rb_eIOError = rb_define_class("IOError", rb_eStandardError);
11696 rb_eEOFError = rb_define_class("EOFError", rb_eIOError);
11697
11698 id_write = rb_intern("write");
11699 id_read = rb_intern("read");
11700 id_getc = rb_intern("getc");
11701 id_flush = rb_intern("flush");
11702 id_readpartial = rb_intern("readpartial");
11703 id_set_encoding = rb_intern("set_encoding");
11704
11705 rb_define_global_function("syscall", rb_f_syscall, -1);
11706
11707 rb_define_global_function("open", rb_f_open, -1);
11708 rb_define_global_function("printf", rb_f_printf, -1);
11709 rb_define_global_function("print", rb_f_print, -1);
11710 rb_define_global_function("putc", rb_f_putc, 1);
11711 rb_define_global_function("puts", rb_f_puts, -1);
11712 rb_define_global_function("gets", rb_f_gets, -1);
11713 rb_define_global_function("readline", rb_f_readline, -1);
11714 rb_define_global_function("select", rb_f_select, -1);
11715
11716 rb_define_global_function("readlines", rb_f_readlines, -1);
11717
11718 rb_define_global_function("`", rb_f_backquote, 1);
11719
11720 rb_define_global_function("p", rb_f_p, -1);
11721 rb_define_method(rb_mKernel, "display", rb_obj_display, -1);
11722
11723 rb_cIO = rb_define_class("IO", rb_cObject);
11724 rb_include_module(rb_cIO, rb_mEnumerable);
11725
11726 rb_mWaitReadable = rb_define_module_under(rb_cIO, "WaitReadable");
11727 rb_mWaitWritable = rb_define_module_under(rb_cIO, "WaitWritable");
11728
11729 #if 0
11730
11731 rb_define_singleton_method(rb_cFile, "open", rb_io_s_open, -1);
11732 #endif
11733
11734 rb_define_alloc_func(rb_cIO, io_alloc);
11735 rb_define_singleton_method(rb_cIO, "new", rb_io_s_new, -1);
11736 rb_define_singleton_method(rb_cIO, "open", rb_io_s_open, -1);
11737 rb_define_singleton_method(rb_cIO, "sysopen", rb_io_s_sysopen, -1);
11738 rb_define_singleton_method(rb_cIO, "for_fd", rb_io_s_for_fd, -1);
11739 rb_define_singleton_method(rb_cIO, "popen", rb_io_s_popen, -1);
11740 rb_define_singleton_method(rb_cIO, "foreach", rb_io_s_foreach, -1);
11741 rb_define_singleton_method(rb_cIO, "readlines", rb_io_s_readlines, -1);
11742 rb_define_singleton_method(rb_cIO, "read", rb_io_s_read, -1);
11743 rb_define_singleton_method(rb_cIO, "binread", rb_io_s_binread, -1);
11744 rb_define_singleton_method(rb_cIO, "write", rb_io_s_write, -1);
11745 rb_define_singleton_method(rb_cIO, "binwrite", rb_io_s_binwrite, -1);
11746 rb_define_singleton_method(rb_cIO, "select", rb_f_select, -1);
11747 rb_define_singleton_method(rb_cIO, "pipe", rb_io_s_pipe, -1);
11748 rb_define_singleton_method(rb_cIO, "try_convert", rb_io_s_try_convert, 1);
11749 rb_define_singleton_method(rb_cIO, "copy_stream", rb_io_s_copy_stream, -1);
11750
11751 rb_define_method(rb_cIO, "initialize", rb_io_initialize, -1);
11752
11753 rb_output_fs = Qnil;
11754 rb_define_hooked_variable("$,", &rb_output_fs, 0, rb_str_setter);
11755
11756 rb_rs = rb_default_rs = rb_usascii_str_new2("\n");
11757 rb_gc_register_mark_object(rb_default_rs);
11758 rb_output_rs = Qnil;
11759 OBJ_FREEZE(rb_default_rs);
11760 rb_define_hooked_variable("$/", &rb_rs, 0, rb_str_setter);
11761 rb_define_hooked_variable("$-0", &rb_rs, 0, rb_str_setter);
11762 rb_define_hooked_variable("$\\", &rb_output_rs, 0, rb_str_setter);
11763
11764 rb_define_virtual_variable("$_", rb_lastline_get, rb_lastline_set);
11765
11766 rb_define_method(rb_cIO, "initialize_copy", rb_io_init_copy, 1);
11767 rb_define_method(rb_cIO, "reopen", rb_io_reopen, -1);
11768
11769 rb_define_method(rb_cIO, "print", rb_io_print, -1);
11770 rb_define_method(rb_cIO, "putc", rb_io_putc, 1);
11771 rb_define_method(rb_cIO, "puts", rb_io_puts, -1);
11772 rb_define_method(rb_cIO, "printf", rb_io_printf, -1);
11773
11774 rb_define_method(rb_cIO, "each", rb_io_each_line, -1);
11775 rb_define_method(rb_cIO, "each_line", rb_io_each_line, -1);
11776 rb_define_method(rb_cIO, "each_byte", rb_io_each_byte, 0);
11777 rb_define_method(rb_cIO, "each_char", rb_io_each_char, 0);
11778 rb_define_method(rb_cIO, "each_codepoint", rb_io_each_codepoint, 0);
11779 rb_define_method(rb_cIO, "lines", rb_io_lines, -1);
11780 rb_define_method(rb_cIO, "bytes", rb_io_bytes, 0);
11781 rb_define_method(rb_cIO, "chars", rb_io_chars, 0);
11782 rb_define_method(rb_cIO, "codepoints", rb_io_codepoints, 0);
11783
11784 rb_define_method(rb_cIO, "syswrite", rb_io_syswrite, 1);
11785 rb_define_method(rb_cIO, "sysread", rb_io_sysread, -1);
11786
11787 rb_define_method(rb_cIO, "fileno", rb_io_fileno, 0);
11788 rb_define_alias(rb_cIO, "to_i", "fileno");
11789 rb_define_method(rb_cIO, "to_io", rb_io_to_io, 0);
11790
11791 rb_define_method(rb_cIO, "fsync", rb_io_fsync, 0);
11792 rb_define_method(rb_cIO, "fdatasync", rb_io_fdatasync, 0);
11793 rb_define_method(rb_cIO, "sync", rb_io_sync, 0);
11794 rb_define_method(rb_cIO, "sync=", rb_io_set_sync, 1);
11795
11796 rb_define_method(rb_cIO, "lineno", rb_io_lineno, 0);
11797 rb_define_method(rb_cIO, "lineno=", rb_io_set_lineno, 1);
11798
11799 rb_define_method(rb_cIO, "readlines", rb_io_readlines, -1);
11800
11801 rb_define_method(rb_cIO, "read_nonblock", io_read_nonblock, -1);
11802 rb_define_method(rb_cIO, "write_nonblock", rb_io_write_nonblock, 1);
11803 rb_define_method(rb_cIO, "readpartial", io_readpartial, -1);
11804 rb_define_method(rb_cIO, "read", io_read, -1);
11805 rb_define_method(rb_cIO, "write", io_write_m, 1);
11806 rb_define_method(rb_cIO, "gets", rb_io_gets_m, -1);
11807 rb_define_method(rb_cIO, "readline", rb_io_readline, -1);
11808 rb_define_method(rb_cIO, "getc", rb_io_getc, 0);
11809 rb_define_method(rb_cIO, "getbyte", rb_io_getbyte, 0);
11810 rb_define_method(rb_cIO, "readchar", rb_io_readchar, 0);
11811 rb_define_method(rb_cIO, "readbyte", rb_io_readbyte, 0);
11812 rb_define_method(rb_cIO, "ungetbyte",rb_io_ungetbyte, 1);
11813 rb_define_method(rb_cIO, "ungetc",rb_io_ungetc, 1);
11814 rb_define_method(rb_cIO, "<<", rb_io_addstr, 1);
11815 rb_define_method(rb_cIO, "flush", rb_io_flush, 0);
11816 rb_define_method(rb_cIO, "tell", rb_io_tell, 0);
11817 rb_define_method(rb_cIO, "seek", rb_io_seek_m, -1);
11818 rb_define_const(rb_cIO, "SEEK_SET", INT2FIX(SEEK_SET));
11819 rb_define_const(rb_cIO, "SEEK_CUR", INT2FIX(SEEK_CUR));
11820 rb_define_const(rb_cIO, "SEEK_END", INT2FIX(SEEK_END));
11821 rb_define_method(rb_cIO, "rewind", rb_io_rewind, 0);
11822 rb_define_method(rb_cIO, "pos", rb_io_tell, 0);
11823 rb_define_method(rb_cIO, "pos=", rb_io_set_pos, 1);
11824 rb_define_method(rb_cIO, "eof", rb_io_eof, 0);
11825 rb_define_method(rb_cIO, "eof?", rb_io_eof, 0);
11826
11827 rb_define_method(rb_cIO, "close_on_exec?", rb_io_close_on_exec_p, 0);
11828 rb_define_method(rb_cIO, "close_on_exec=", rb_io_set_close_on_exec, 1);
11829
11830 rb_define_method(rb_cIO, "close", rb_io_close_m, 0);
11831 rb_define_method(rb_cIO, "closed?", rb_io_closed, 0);
11832 rb_define_method(rb_cIO, "close_read", rb_io_close_read, 0);
11833 rb_define_method(rb_cIO, "close_write", rb_io_close_write, 0);
11834
11835 rb_define_method(rb_cIO, "isatty", rb_io_isatty, 0);
11836 rb_define_method(rb_cIO, "tty?", rb_io_isatty, 0);
11837 rb_define_method(rb_cIO, "binmode", rb_io_binmode_m, 0);
11838 rb_define_method(rb_cIO, "binmode?", rb_io_binmode_p, 0);
11839 rb_define_method(rb_cIO, "sysseek", rb_io_sysseek, -1);
11840 rb_define_method(rb_cIO, "advise", rb_io_advise, -1);
11841
11842 rb_define_method(rb_cIO, "ioctl", rb_io_ioctl, -1);
11843 rb_define_method(rb_cIO, "fcntl", rb_io_fcntl, -1);
11844 rb_define_method(rb_cIO, "pid", rb_io_pid, 0);
11845 rb_define_method(rb_cIO, "inspect", rb_io_inspect, 0);
11846
11847 rb_define_method(rb_cIO, "external_encoding", rb_io_external_encoding, 0);
11848 rb_define_method(rb_cIO, "internal_encoding", rb_io_internal_encoding, 0);
11849 rb_define_method(rb_cIO, "set_encoding", rb_io_set_encoding, -1);
11850
11851 rb_define_method(rb_cIO, "autoclose?", rb_io_autoclose_p, 0);
11852 rb_define_method(rb_cIO, "autoclose=", rb_io_set_autoclose, 1);
11853
11854 rb_define_variable("$stdin", &rb_stdin);
11855 rb_stdin = prep_stdio(stdin, FMODE_READABLE, rb_cIO, "<STDIN>");
11856 rb_define_hooked_variable("$stdout", &rb_stdout, 0, stdout_setter);
11857 rb_stdout = prep_stdio(stdout, FMODE_WRITABLE, rb_cIO, "<STDOUT>");
11858 rb_define_hooked_variable("$stderr", &rb_stderr, 0, stdout_setter);
11859 rb_stderr = prep_stdio(stderr, FMODE_WRITABLE|FMODE_SYNC, rb_cIO, "<STDERR>");
11860 rb_define_hooked_variable("$>", &rb_stdout, 0, stdout_setter);
11861 orig_stdout = rb_stdout;
11862 rb_deferr = orig_stderr = rb_stderr;
11863
11864
11865 rb_define_global_const("STDIN", rb_stdin);
11866
11867 rb_define_global_const("STDOUT", rb_stdout);
11868
11869 rb_define_global_const("STDERR", rb_stderr);
11870
11871 #if 0
11872
11873 rb_cARGF = rb_define_class("ARGF", rb_cObject);
11874 #endif
11875
11876 rb_cARGF = rb_class_new(rb_cObject);
11877 rb_set_class_path(rb_cARGF, rb_cObject, "ARGF.class");
11878 rb_define_alloc_func(rb_cARGF, argf_alloc);
11879
11880 rb_include_module(rb_cARGF, rb_mEnumerable);
11881
11882 rb_define_method(rb_cARGF, "initialize", argf_initialize, -2);
11883 rb_define_method(rb_cARGF, "initialize_copy", argf_initialize_copy, 1);
11884 rb_define_method(rb_cARGF, "to_s", argf_to_s, 0);
11885 rb_define_alias(rb_cARGF, "inspect", "to_s");
11886 rb_define_method(rb_cARGF, "argv", argf_argv, 0);
11887
11888 rb_define_method(rb_cARGF, "fileno", argf_fileno, 0);
11889 rb_define_method(rb_cARGF, "to_i", argf_fileno, 0);
11890 rb_define_method(rb_cARGF, "to_io", argf_to_io, 0);
11891 rb_define_method(rb_cARGF, "to_write_io", argf_write_io, 0);
11892 rb_define_method(rb_cARGF, "each", argf_each_line, -1);
11893 rb_define_method(rb_cARGF, "each_line", argf_each_line, -1);
11894 rb_define_method(rb_cARGF, "each_byte", argf_each_byte, 0);
11895 rb_define_method(rb_cARGF, "each_char", argf_each_char, 0);
11896 rb_define_method(rb_cARGF, "each_codepoint", argf_each_codepoint, 0);
11897 rb_define_method(rb_cARGF, "lines", argf_lines, -1);
11898 rb_define_method(rb_cARGF, "bytes", argf_bytes, 0);
11899 rb_define_method(rb_cARGF, "chars", argf_chars, 0);
11900 rb_define_method(rb_cARGF, "codepoints", argf_codepoints, 0);
11901
11902 rb_define_method(rb_cARGF, "read", argf_read, -1);
11903 rb_define_method(rb_cARGF, "readpartial", argf_readpartial, -1);
11904 rb_define_method(rb_cARGF, "read_nonblock", argf_read_nonblock, -1);
11905 rb_define_method(rb_cARGF, "readlines", argf_readlines, -1);
11906 rb_define_method(rb_cARGF, "to_a", argf_readlines, -1);
11907 rb_define_method(rb_cARGF, "gets", argf_gets, -1);
11908 rb_define_method(rb_cARGF, "readline", argf_readline, -1);
11909 rb_define_method(rb_cARGF, "getc", argf_getc, 0);
11910 rb_define_method(rb_cARGF, "getbyte", argf_getbyte, 0);
11911 rb_define_method(rb_cARGF, "readchar", argf_readchar, 0);
11912 rb_define_method(rb_cARGF, "readbyte", argf_readbyte, 0);
11913 rb_define_method(rb_cARGF, "tell", argf_tell, 0);
11914 rb_define_method(rb_cARGF, "seek", argf_seek_m, -1);
11915 rb_define_method(rb_cARGF, "rewind", argf_rewind, 0);
11916 rb_define_method(rb_cARGF, "pos", argf_tell, 0);
11917 rb_define_method(rb_cARGF, "pos=", argf_set_pos, 1);
11918 rb_define_method(rb_cARGF, "eof", argf_eof, 0);
11919 rb_define_method(rb_cARGF, "eof?", argf_eof, 0);
11920 rb_define_method(rb_cARGF, "binmode", argf_binmode_m, 0);
11921 rb_define_method(rb_cARGF, "binmode?", argf_binmode_p, 0);
11922
11923 rb_define_method(rb_cARGF, "write", argf_write, 1);
11924 rb_define_method(rb_cARGF, "print", rb_io_print, -1);
11925 rb_define_method(rb_cARGF, "putc", rb_io_putc, 1);
11926 rb_define_method(rb_cARGF, "puts", rb_io_puts, -1);
11927 rb_define_method(rb_cARGF, "printf", rb_io_printf, -1);
11928
11929 rb_define_method(rb_cARGF, "filename", argf_filename, 0);
11930 rb_define_method(rb_cARGF, "path", argf_filename, 0);
11931 rb_define_method(rb_cARGF, "file", argf_file, 0);
11932 rb_define_method(rb_cARGF, "skip", argf_skip, 0);
11933 rb_define_method(rb_cARGF, "close", argf_close_m, 0);
11934 rb_define_method(rb_cARGF, "closed?", argf_closed, 0);
11935
11936 rb_define_method(rb_cARGF, "lineno", argf_lineno, 0);
11937 rb_define_method(rb_cARGF, "lineno=", argf_set_lineno, 1);
11938
11939 rb_define_method(rb_cARGF, "inplace_mode", argf_inplace_mode_get, 0);
11940 rb_define_method(rb_cARGF, "inplace_mode=", argf_inplace_mode_set, 1);
11941
11942 rb_define_method(rb_cARGF, "external_encoding", argf_external_encoding, 0);
11943 rb_define_method(rb_cARGF, "internal_encoding", argf_internal_encoding, 0);
11944 rb_define_method(rb_cARGF, "set_encoding", argf_set_encoding, -1);
11945
11946 argf = rb_class_new_instance(0, 0, rb_cARGF);
11947
11948 rb_define_readonly_variable("$<", &argf);
11949
11950
11951
11952
11953
11954
11955 rb_define_global_const("ARGF", argf);
11956
11957 rb_define_hooked_variable("$.", &argf, argf_lineno_getter, argf_lineno_setter);
11958 rb_define_hooked_variable("$FILENAME", &argf, argf_filename_getter, rb_gvar_readonly_setter);
11959 ARGF.filename = rb_str_new2("-");
11960
11961 rb_define_hooked_variable("$-i", &argf, opt_i_get, opt_i_set);
11962 rb_define_hooked_variable("$*", &argf, argf_argv_getter, rb_gvar_readonly_setter);
11963
11964 #if defined (_WIN32) || defined(__CYGWIN__)
11965 atexit(pipe_atexit);
11966 #endif
11967
11968 Init_File();
11969
11970 rb_define_method(rb_cFile, "initialize", rb_file_initialize, -1);
11971
11972 sym_mode = ID2SYM(rb_intern("mode"));
11973 sym_perm = ID2SYM(rb_intern("perm"));
11974 sym_extenc = ID2SYM(rb_intern("external_encoding"));
11975 sym_intenc = ID2SYM(rb_intern("internal_encoding"));
11976 sym_encoding = ID2SYM(rb_intern("encoding"));
11977 sym_open_args = ID2SYM(rb_intern("open_args"));
11978 sym_textmode = ID2SYM(rb_intern("textmode"));
11979 sym_binmode = ID2SYM(rb_intern("binmode"));
11980 sym_autoclose = ID2SYM(rb_intern("autoclose"));
11981 sym_normal = ID2SYM(rb_intern("normal"));
11982 sym_sequential = ID2SYM(rb_intern("sequential"));
11983 sym_random = ID2SYM(rb_intern("random"));
11984 sym_willneed = ID2SYM(rb_intern("willneed"));
11985 sym_dontneed = ID2SYM(rb_intern("dontneed"));
11986 sym_noreuse = ID2SYM(rb_intern("noreuse"));
11987 }
11988