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