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, NULL);
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
02604 ret = io_getpartial(argc, argv, io, 1, no_exception);
02605
02606 if (NIL_P(ret)) {
02607 if (no_exception)
02608 return Qnil;
02609 else
02610 rb_eof_error();
02611 }
02612 return ret;
02613 }
02614
02615 static VALUE
02616 io_write_nonblock(VALUE io, VALUE str, int no_exception)
02617 {
02618 rb_io_t *fptr;
02619 long n;
02620
02621 if (!RB_TYPE_P(str, T_STRING))
02622 str = rb_obj_as_string(str);
02623
02624 io = GetWriteIO(io);
02625 GetOpenFile(io, fptr);
02626 rb_io_check_writable(fptr);
02627
02628 if (io_fflush(fptr) < 0)
02629 rb_sys_fail(0);
02630
02631 rb_io_set_nonblock(fptr);
02632 n = write(fptr->fd, RSTRING_PTR(str), RSTRING_LEN(str));
02633
02634 if (n == -1) {
02635 if (errno == EWOULDBLOCK || errno == EAGAIN) {
02636 if (no_exception) {
02637 return ID2SYM(rb_intern("wait_writable"));
02638 } else {
02639 rb_readwrite_sys_fail(RB_IO_WAIT_WRITABLE, "write would block");
02640 }
02641 }
02642 rb_sys_fail_path(fptr->pathv);
02643 }
02644
02645 return LONG2FIX(n);
02646 }
02647
02648
02649
02650
02651
02652
02653
02654
02655
02656
02657
02658
02659
02660
02661
02662
02663
02664
02665
02666
02667
02668
02669
02670
02671
02672
02673
02674
02675
02676
02677
02678
02679
02680
02681
02682
02683
02684
02685
02686
02687
02688
02689
02690
02691
02692
02693
02694
02695
02696
02697
02698
02699
02700
02701
02702
02703
02704
02705
02706 static VALUE
02707 rb_io_write_nonblock(int argc, VALUE *argv, VALUE io)
02708 {
02709 VALUE str;
02710 VALUE opts = Qnil;
02711 int no_exceptions = 0;
02712
02713 rb_scan_args(argc, argv, "10:", &str, &opts);
02714
02715 if (!NIL_P(opts) && Qfalse == rb_hash_aref(opts, sym_exception))
02716 no_exceptions = 1;
02717
02718 return io_write_nonblock(io, str, no_exceptions);
02719 }
02720
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 static VALUE
02788 io_read(int argc, VALUE *argv, VALUE io)
02789 {
02790 rb_io_t *fptr;
02791 long n, len;
02792 VALUE length, str;
02793 #if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)
02794 int previous_mode;
02795 #endif
02796
02797 rb_scan_args(argc, argv, "02", &length, &str);
02798
02799 if (NIL_P(length)) {
02800 GetOpenFile(io, fptr);
02801 rb_io_check_char_readable(fptr);
02802 return read_all(fptr, remain_size(fptr), str);
02803 }
02804 len = NUM2LONG(length);
02805 if (len < 0) {
02806 rb_raise(rb_eArgError, "negative length %ld given", len);
02807 }
02808
02809 io_setstrbuf(&str,len);
02810
02811 GetOpenFile(io, fptr);
02812 rb_io_check_byte_readable(fptr);
02813 if (len == 0) {
02814 io_set_read_length(str, 0);
02815 return str;
02816 }
02817
02818 READ_CHECK(fptr);
02819 #if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)
02820 previous_mode = set_binary_mode_with_seek_cur(fptr);
02821 #endif
02822 n = io_fread(str, 0, len, fptr);
02823 io_set_read_length(str, n);
02824 #if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)
02825 if (previous_mode == O_TEXT) {
02826 setmode(fptr->fd, O_TEXT);
02827 }
02828 #endif
02829 if (n == 0) return Qnil;
02830 OBJ_TAINT(str);
02831
02832 return str;
02833 }
02834
02835 static void
02836 rscheck(const char *rsptr, long rslen, VALUE rs)
02837 {
02838 if (!rs) return;
02839 if (RSTRING_PTR(rs) != rsptr && RSTRING_LEN(rs) != rslen)
02840 rb_raise(rb_eRuntimeError, "rs modified");
02841 }
02842
02843 static int
02844 appendline(rb_io_t *fptr, int delim, VALUE *strp, long *lp)
02845 {
02846 VALUE str = *strp;
02847 long limit = *lp;
02848
02849 if (NEED_READCONV(fptr)) {
02850 SET_BINARY_MODE(fptr);
02851 make_readconv(fptr, 0);
02852 do {
02853 const char *p, *e;
02854 int searchlen = READ_CHAR_PENDING_COUNT(fptr);
02855 if (searchlen) {
02856 p = READ_CHAR_PENDING_PTR(fptr);
02857 if (0 < limit && limit < searchlen)
02858 searchlen = (int)limit;
02859 e = memchr(p, delim, searchlen);
02860 if (e) {
02861 int len = (int)(e-p+1);
02862 if (NIL_P(str))
02863 *strp = str = rb_str_new(p, len);
02864 else
02865 rb_str_buf_cat(str, p, len);
02866 fptr->cbuf.off += len;
02867 fptr->cbuf.len -= len;
02868 limit -= len;
02869 *lp = limit;
02870 return delim;
02871 }
02872
02873 if (NIL_P(str))
02874 *strp = str = rb_str_new(p, searchlen);
02875 else
02876 rb_str_buf_cat(str, p, searchlen);
02877 fptr->cbuf.off += searchlen;
02878 fptr->cbuf.len -= searchlen;
02879 limit -= searchlen;
02880
02881 if (limit == 0) {
02882 *lp = limit;
02883 return (unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
02884 }
02885 }
02886 } while (more_char(fptr) != MORE_CHAR_FINISHED);
02887 clear_readconv(fptr);
02888 *lp = limit;
02889 return EOF;
02890 }
02891
02892 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
02893 do {
02894 long pending = READ_DATA_PENDING_COUNT(fptr);
02895 if (pending > 0) {
02896 const char *p = READ_DATA_PENDING_PTR(fptr);
02897 const char *e;
02898 long last;
02899
02900 if (limit > 0 && pending > limit) pending = limit;
02901 e = memchr(p, delim, pending);
02902 if (e) pending = e - p + 1;
02903 if (!NIL_P(str)) {
02904 last = RSTRING_LEN(str);
02905 rb_str_resize(str, last + pending);
02906 }
02907 else {
02908 last = 0;
02909 *strp = str = rb_str_buf_new(pending);
02910 rb_str_set_len(str, pending);
02911 }
02912 read_buffered_data(RSTRING_PTR(str) + last, pending, fptr);
02913 limit -= pending;
02914 *lp = limit;
02915 if (e) return delim;
02916 if (limit == 0)
02917 return (unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
02918 }
02919 READ_CHECK(fptr);
02920 } while (io_fillbuf(fptr) >= 0);
02921 *lp = limit;
02922 return EOF;
02923 }
02924
02925 static inline int
02926 swallow(rb_io_t *fptr, int term)
02927 {
02928 if (NEED_READCONV(fptr)) {
02929 rb_encoding *enc = io_read_encoding(fptr);
02930 int needconv = rb_enc_mbminlen(enc) != 1;
02931 SET_BINARY_MODE(fptr);
02932 make_readconv(fptr, 0);
02933 do {
02934 size_t cnt;
02935 while ((cnt = READ_CHAR_PENDING_COUNT(fptr)) > 0) {
02936 const char *p = READ_CHAR_PENDING_PTR(fptr);
02937 int i;
02938 if (!needconv) {
02939 if (*p != term) return TRUE;
02940 i = (int)cnt;
02941 while (--i && *++p == term);
02942 }
02943 else {
02944 const char *e = p + cnt;
02945 if (rb_enc_ascget(p, e, &i, enc) != term) return TRUE;
02946 while ((p += i) < e && rb_enc_ascget(p, e, &i, enc) == term);
02947 i = (int)(e - p);
02948 }
02949 io_shift_cbuf(fptr, (int)cnt - i, NULL);
02950 }
02951 } while (more_char(fptr) != MORE_CHAR_FINISHED);
02952 return FALSE;
02953 }
02954
02955 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
02956 do {
02957 size_t cnt;
02958 while ((cnt = READ_DATA_PENDING_COUNT(fptr)) > 0) {
02959 char buf[1024];
02960 const char *p = READ_DATA_PENDING_PTR(fptr);
02961 int i;
02962 if (cnt > sizeof buf) cnt = sizeof buf;
02963 if (*p != term) return TRUE;
02964 i = (int)cnt;
02965 while (--i && *++p == term);
02966 if (!read_buffered_data(buf, cnt - i, fptr))
02967 rb_sys_fail_path(fptr->pathv);
02968 }
02969 READ_CHECK(fptr);
02970 } while (io_fillbuf(fptr) == 0);
02971 return FALSE;
02972 }
02973
02974 static VALUE
02975 rb_io_getline_fast(rb_io_t *fptr, rb_encoding *enc, VALUE io)
02976 {
02977 VALUE str = Qnil;
02978 int len = 0;
02979 long pos = 0;
02980 int cr = 0;
02981
02982 do {
02983 int pending = READ_DATA_PENDING_COUNT(fptr);
02984
02985 if (pending > 0) {
02986 const char *p = READ_DATA_PENDING_PTR(fptr);
02987 const char *e;
02988
02989 e = memchr(p, '\n', pending);
02990 if (e) {
02991 pending = (int)(e - p + 1);
02992 }
02993 if (NIL_P(str)) {
02994 str = rb_str_new(p, pending);
02995 fptr->rbuf.off += pending;
02996 fptr->rbuf.len -= pending;
02997 }
02998 else {
02999 rb_str_resize(str, len + pending);
03000 read_buffered_data(RSTRING_PTR(str)+len, pending, fptr);
03001 }
03002 len += pending;
03003 if (cr != ENC_CODERANGE_BROKEN)
03004 pos += rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + len, enc, &cr);
03005 if (e) break;
03006 }
03007 READ_CHECK(fptr);
03008 } while (io_fillbuf(fptr) >= 0);
03009 if (NIL_P(str)) return Qnil;
03010
03011 str = io_enc_str(str, fptr);
03012 ENC_CODERANGE_SET(str, cr);
03013 fptr->lineno++;
03014 if (io == ARGF.current_file) {
03015 ARGF.lineno++;
03016 ARGF.last_lineno = ARGF.lineno;
03017 }
03018 else {
03019 ARGF.last_lineno = fptr->lineno;
03020 }
03021
03022 return str;
03023 }
03024
03025 static void
03026 prepare_getline_args(int argc, VALUE *argv, VALUE *rsp, long *limit, VALUE io)
03027 {
03028 VALUE rs = rb_rs, lim = Qnil;
03029 rb_io_t *fptr;
03030
03031 if (argc == 1) {
03032 VALUE tmp = Qnil;
03033
03034 if (NIL_P(argv[0]) || !NIL_P(tmp = rb_check_string_type(argv[0]))) {
03035 rs = tmp;
03036 }
03037 else {
03038 lim = argv[0];
03039 }
03040 }
03041 else if (2 <= argc) {
03042 rb_scan_args(argc, argv, "2", &rs, &lim);
03043 if (!NIL_P(rs))
03044 StringValue(rs);
03045 }
03046 if (!NIL_P(rs)) {
03047 rb_encoding *enc_rs, *enc_io;
03048
03049 GetOpenFile(io, fptr);
03050 enc_rs = rb_enc_get(rs);
03051 enc_io = io_read_encoding(fptr);
03052 if (enc_io != enc_rs &&
03053 (rb_enc_str_coderange(rs) != ENC_CODERANGE_7BIT ||
03054 (RSTRING_LEN(rs) > 0 && !rb_enc_asciicompat(enc_io)))) {
03055 if (rs == rb_default_rs) {
03056 rs = rb_enc_str_new(0, 0, enc_io);
03057 rb_str_buf_cat_ascii(rs, "\n");
03058 }
03059 else {
03060 rb_raise(rb_eArgError, "encoding mismatch: %s IO with %s RS",
03061 rb_enc_name(enc_io),
03062 rb_enc_name(enc_rs));
03063 }
03064 }
03065 }
03066 *rsp = rs;
03067 *limit = NIL_P(lim) ? -1L : NUM2LONG(lim);
03068 }
03069
03070 static VALUE
03071 rb_io_getline_1(VALUE rs, long limit, VALUE io)
03072 {
03073 VALUE str = Qnil;
03074 rb_io_t *fptr;
03075 int nolimit = 0;
03076 rb_encoding *enc;
03077
03078 GetOpenFile(io, fptr);
03079 rb_io_check_char_readable(fptr);
03080 if (NIL_P(rs) && limit < 0) {
03081 str = read_all(fptr, 0, Qnil);
03082 if (RSTRING_LEN(str) == 0) return Qnil;
03083 }
03084 else if (limit == 0) {
03085 return rb_enc_str_new(0, 0, io_read_encoding(fptr));
03086 }
03087 else if (rs == rb_default_rs && limit < 0 && !NEED_READCONV(fptr) &&
03088 rb_enc_asciicompat(enc = io_read_encoding(fptr))) {
03089 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
03090 return rb_io_getline_fast(fptr, enc, io);
03091 }
03092 else {
03093 int c, newline = -1;
03094 const char *rsptr = 0;
03095 long rslen = 0;
03096 int rspara = 0;
03097 int extra_limit = 16;
03098
03099 SET_BINARY_MODE(fptr);
03100 enc = io_read_encoding(fptr);
03101
03102 if (!NIL_P(rs)) {
03103 rslen = RSTRING_LEN(rs);
03104 if (rslen == 0) {
03105 rsptr = "\n\n";
03106 rslen = 2;
03107 rspara = 1;
03108 swallow(fptr, '\n');
03109 rs = 0;
03110 if (!rb_enc_asciicompat(enc)) {
03111 rs = rb_usascii_str_new(rsptr, rslen);
03112 rs = rb_str_encode(rs, rb_enc_from_encoding(enc), 0, Qnil);
03113 OBJ_FREEZE(rs);
03114 rsptr = RSTRING_PTR(rs);
03115 rslen = RSTRING_LEN(rs);
03116 }
03117 }
03118 else {
03119 rsptr = RSTRING_PTR(rs);
03120 }
03121 newline = (unsigned char)rsptr[rslen - 1];
03122 }
03123
03124
03125 while ((c = appendline(fptr, newline, &str, &limit)) != EOF) {
03126 const char *s, *p, *pp, *e;
03127
03128 if (c == newline) {
03129 if (RSTRING_LEN(str) < rslen) continue;
03130 s = RSTRING_PTR(str);
03131 e = RSTRING_END(str);
03132 p = e - rslen;
03133 pp = rb_enc_left_char_head(s, p, e, enc);
03134 if (pp != p) continue;
03135 if (!rspara) rscheck(rsptr, rslen, rs);
03136 if (memcmp(p, rsptr, rslen) == 0) break;
03137 }
03138 if (limit == 0) {
03139 s = RSTRING_PTR(str);
03140 p = RSTRING_END(str);
03141 pp = rb_enc_left_char_head(s, p-1, p, enc);
03142 if (extra_limit &&
03143 MBCLEN_NEEDMORE_P(rb_enc_precise_mbclen(pp, p, enc))) {
03144
03145
03146 limit = 1;
03147 extra_limit--;
03148 }
03149 else {
03150 nolimit = 1;
03151 break;
03152 }
03153 }
03154 }
03155
03156 if (rspara && c != EOF)
03157 swallow(fptr, '\n');
03158 if (!NIL_P(str))
03159 str = io_enc_str(str, fptr);
03160 }
03161
03162 if (!NIL_P(str) && !nolimit) {
03163 fptr->lineno++;
03164 if (io == ARGF.current_file) {
03165 ARGF.lineno++;
03166 ARGF.last_lineno = ARGF.lineno;
03167 }
03168 else {
03169 ARGF.last_lineno = fptr->lineno;
03170 }
03171 }
03172
03173 return str;
03174 }
03175
03176 static VALUE
03177 rb_io_getline(int argc, VALUE *argv, VALUE io)
03178 {
03179 VALUE rs;
03180 long limit;
03181
03182 prepare_getline_args(argc, argv, &rs, &limit, io);
03183 return rb_io_getline_1(rs, limit, io);
03184 }
03185
03186 VALUE
03187 rb_io_gets(VALUE io)
03188 {
03189 return rb_io_getline_1(rb_default_rs, -1, io);
03190 }
03191
03192
03193
03194
03195
03196
03197
03198
03199
03200
03201
03202
03203
03204
03205
03206
03207
03208
03209
03210
03211
03212
03213 static VALUE
03214 rb_io_gets_m(int argc, VALUE *argv, VALUE io)
03215 {
03216 VALUE str;
03217
03218 str = rb_io_getline(argc, argv, io);
03219 rb_lastline_set(str);
03220
03221 return str;
03222 }
03223
03224
03225
03226
03227
03228
03229
03230
03231
03232
03233
03234
03235
03236
03237
03238
03239
03240
03241
03242
03243
03244
03245
03246 static VALUE
03247 rb_io_lineno(VALUE io)
03248 {
03249 rb_io_t *fptr;
03250
03251 GetOpenFile(io, fptr);
03252 rb_io_check_char_readable(fptr);
03253 return INT2NUM(fptr->lineno);
03254 }
03255
03256
03257
03258
03259
03260
03261
03262
03263
03264
03265
03266
03267
03268
03269
03270
03271
03272
03273 static VALUE
03274 rb_io_set_lineno(VALUE io, VALUE lineno)
03275 {
03276 rb_io_t *fptr;
03277
03278 GetOpenFile(io, fptr);
03279 rb_io_check_char_readable(fptr);
03280 fptr->lineno = NUM2INT(lineno);
03281 return lineno;
03282 }
03283
03284
03285
03286
03287
03288
03289
03290
03291
03292
03293
03294 static VALUE
03295 rb_io_readline(int argc, VALUE *argv, VALUE io)
03296 {
03297 VALUE line = rb_io_gets_m(argc, argv, io);
03298
03299 if (NIL_P(line)) {
03300 rb_eof_error();
03301 }
03302 return line;
03303 }
03304
03305
03306
03307
03308
03309
03310
03311
03312
03313
03314
03315
03316
03317
03318
03319
03320
03321
03322
03323 static VALUE
03324 rb_io_readlines(int argc, VALUE *argv, VALUE io)
03325 {
03326 VALUE line, ary, rs;
03327 long limit;
03328
03329 prepare_getline_args(argc, argv, &rs, &limit, io);
03330 if (limit == 0)
03331 rb_raise(rb_eArgError, "invalid limit: 0 for readlines");
03332 ary = rb_ary_new();
03333 while (!NIL_P(line = rb_io_getline_1(rs, limit, io))) {
03334 rb_ary_push(ary, line);
03335 }
03336 return ary;
03337 }
03338
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 static VALUE
03369 rb_io_each_line(int argc, VALUE *argv, VALUE io)
03370 {
03371 VALUE str, rs;
03372 long limit;
03373
03374 RETURN_ENUMERATOR(io, argc, argv);
03375 prepare_getline_args(argc, argv, &rs, &limit, io);
03376 if (limit == 0)
03377 rb_raise(rb_eArgError, "invalid limit: 0 for each_line");
03378 while (!NIL_P(str = rb_io_getline_1(rs, limit, io))) {
03379 rb_yield(str);
03380 }
03381 return io;
03382 }
03383
03384
03385
03386
03387
03388 static VALUE
03389 rb_io_lines(int argc, VALUE *argv, VALUE io)
03390 {
03391 rb_warn("IO#lines is deprecated; use #each_line instead");
03392 if (!rb_block_given_p())
03393 return rb_enumeratorize(io, ID2SYM(rb_intern("each_line")), argc, argv);
03394 return rb_io_each_line(argc, argv, io);
03395 }
03396
03397
03398
03399
03400
03401
03402
03403
03404
03405
03406
03407
03408
03409
03410
03411
03412
03413
03414 static VALUE
03415 rb_io_each_byte(VALUE io)
03416 {
03417 rb_io_t *fptr;
03418
03419 RETURN_ENUMERATOR(io, 0, 0);
03420 GetOpenFile(io, fptr);
03421
03422 do {
03423 while (fptr->rbuf.len > 0) {
03424 char *p = fptr->rbuf.ptr + fptr->rbuf.off++;
03425 fptr->rbuf.len--;
03426 rb_yield(INT2FIX(*p & 0xff));
03427 errno = 0;
03428 }
03429 rb_io_check_byte_readable(fptr);
03430 READ_CHECK(fptr);
03431 } while (io_fillbuf(fptr) >= 0);
03432 return io;
03433 }
03434
03435
03436
03437
03438
03439 static VALUE
03440 rb_io_bytes(VALUE io)
03441 {
03442 rb_warn("IO#bytes is deprecated; use #each_byte instead");
03443 if (!rb_block_given_p())
03444 return rb_enumeratorize(io, ID2SYM(rb_intern("each_byte")), 0, 0);
03445 return rb_io_each_byte(io);
03446 }
03447
03448 static VALUE
03449 io_getc(rb_io_t *fptr, rb_encoding *enc)
03450 {
03451 int r, n, cr = 0;
03452 VALUE str;
03453
03454 if (NEED_READCONV(fptr)) {
03455 VALUE str = Qnil;
03456 rb_encoding *read_enc = io_read_encoding(fptr);
03457
03458 SET_BINARY_MODE(fptr);
03459 make_readconv(fptr, 0);
03460
03461 while (1) {
03462 if (fptr->cbuf.len) {
03463 r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
03464 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
03465 read_enc);
03466 if (!MBCLEN_NEEDMORE_P(r))
03467 break;
03468 if (fptr->cbuf.len == fptr->cbuf.capa) {
03469 rb_raise(rb_eIOError, "too long character");
03470 }
03471 }
03472
03473 if (more_char(fptr) == MORE_CHAR_FINISHED) {
03474 if (fptr->cbuf.len == 0) {
03475 clear_readconv(fptr);
03476 return Qnil;
03477 }
03478
03479 str = rb_enc_str_new(fptr->cbuf.ptr+fptr->cbuf.off, 1, read_enc);
03480 fptr->cbuf.off += 1;
03481 fptr->cbuf.len -= 1;
03482 if (fptr->cbuf.len == 0) clear_readconv(fptr);
03483 ENC_CODERANGE_SET(str, ENC_CODERANGE_BROKEN);
03484 return str;
03485 }
03486 }
03487 if (MBCLEN_INVALID_P(r)) {
03488 r = rb_enc_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
03489 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
03490 read_enc);
03491 io_shift_cbuf(fptr, r, &str);
03492 cr = ENC_CODERANGE_BROKEN;
03493 }
03494 else {
03495 io_shift_cbuf(fptr, MBCLEN_CHARFOUND_LEN(r), &str);
03496 cr = ENC_CODERANGE_VALID;
03497 if (MBCLEN_CHARFOUND_LEN(r) == 1 && rb_enc_asciicompat(read_enc) &&
03498 ISASCII(RSTRING_PTR(str)[0])) {
03499 cr = ENC_CODERANGE_7BIT;
03500 }
03501 }
03502 str = io_enc_str(str, fptr);
03503 ENC_CODERANGE_SET(str, cr);
03504 return str;
03505 }
03506
03507 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
03508 if (io_fillbuf(fptr) < 0) {
03509 return Qnil;
03510 }
03511 if (rb_enc_asciicompat(enc) && ISASCII(fptr->rbuf.ptr[fptr->rbuf.off])) {
03512 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, 1);
03513 fptr->rbuf.off += 1;
03514 fptr->rbuf.len -= 1;
03515 cr = ENC_CODERANGE_7BIT;
03516 }
03517 else {
03518 r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off, fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
03519 if (MBCLEN_CHARFOUND_P(r) &&
03520 (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
03521 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, n);
03522 fptr->rbuf.off += n;
03523 fptr->rbuf.len -= n;
03524 cr = ENC_CODERANGE_VALID;
03525 }
03526 else if (MBCLEN_NEEDMORE_P(r)) {
03527 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, fptr->rbuf.len);
03528 fptr->rbuf.len = 0;
03529 getc_needmore:
03530 if (io_fillbuf(fptr) != -1) {
03531 rb_str_cat(str, fptr->rbuf.ptr+fptr->rbuf.off, 1);
03532 fptr->rbuf.off++;
03533 fptr->rbuf.len--;
03534 r = rb_enc_precise_mbclen(RSTRING_PTR(str), RSTRING_PTR(str)+RSTRING_LEN(str), enc);
03535 if (MBCLEN_NEEDMORE_P(r)) {
03536 goto getc_needmore;
03537 }
03538 else if (MBCLEN_CHARFOUND_P(r)) {
03539 cr = ENC_CODERANGE_VALID;
03540 }
03541 }
03542 }
03543 else {
03544 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, 1);
03545 fptr->rbuf.off++;
03546 fptr->rbuf.len--;
03547 }
03548 }
03549 if (!cr) cr = ENC_CODERANGE_BROKEN;
03550 str = io_enc_str(str, fptr);
03551 ENC_CODERANGE_SET(str, cr);
03552 return str;
03553 }
03554
03555
03556
03557
03558
03559
03560
03561
03562
03563
03564
03565
03566
03567
03568
03569
03570 static VALUE
03571 rb_io_each_char(VALUE io)
03572 {
03573 rb_io_t *fptr;
03574 rb_encoding *enc;
03575 VALUE c;
03576
03577 RETURN_ENUMERATOR(io, 0, 0);
03578 GetOpenFile(io, fptr);
03579 rb_io_check_char_readable(fptr);
03580
03581 enc = io_input_encoding(fptr);
03582 READ_CHECK(fptr);
03583 while (!NIL_P(c = io_getc(fptr, enc))) {
03584 rb_yield(c);
03585 }
03586 return io;
03587 }
03588
03589
03590
03591
03592
03593 static VALUE
03594 rb_io_chars(VALUE io)
03595 {
03596 rb_warn("IO#chars is deprecated; use #each_char instead");
03597 if (!rb_block_given_p())
03598 return rb_enumeratorize(io, ID2SYM(rb_intern("each_char")), 0, 0);
03599 return rb_io_each_char(io);
03600 }
03601
03602
03603
03604
03605
03606
03607
03608
03609
03610
03611
03612
03613
03614
03615
03616
03617
03618 static VALUE
03619 rb_io_each_codepoint(VALUE io)
03620 {
03621 rb_io_t *fptr;
03622 rb_encoding *enc;
03623 unsigned int c;
03624 int r, n;
03625
03626 RETURN_ENUMERATOR(io, 0, 0);
03627 GetOpenFile(io, fptr);
03628 rb_io_check_char_readable(fptr);
03629
03630 READ_CHECK(fptr);
03631 if (NEED_READCONV(fptr)) {
03632 SET_BINARY_MODE(fptr);
03633 for (;;) {
03634 make_readconv(fptr, 0);
03635 for (;;) {
03636 if (fptr->cbuf.len) {
03637 if (fptr->encs.enc)
03638 r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
03639 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
03640 fptr->encs.enc);
03641 else
03642 r = ONIGENC_CONSTRUCT_MBCLEN_CHARFOUND(1);
03643 if (!MBCLEN_NEEDMORE_P(r))
03644 break;
03645 if (fptr->cbuf.len == fptr->cbuf.capa) {
03646 rb_raise(rb_eIOError, "too long character");
03647 }
03648 }
03649 if (more_char(fptr) == MORE_CHAR_FINISHED) {
03650 clear_readconv(fptr);
03651
03652 return io;
03653 }
03654 }
03655 if (MBCLEN_INVALID_P(r)) {
03656 rb_raise(rb_eArgError, "invalid byte sequence in %s",
03657 rb_enc_name(fptr->encs.enc));
03658 }
03659 n = MBCLEN_CHARFOUND_LEN(r);
03660 if (fptr->encs.enc) {
03661 c = rb_enc_codepoint(fptr->cbuf.ptr+fptr->cbuf.off,
03662 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
03663 fptr->encs.enc);
03664 }
03665 else {
03666 c = (unsigned char)fptr->cbuf.ptr[fptr->cbuf.off];
03667 }
03668 fptr->cbuf.off += n;
03669 fptr->cbuf.len -= n;
03670 rb_yield(UINT2NUM(c));
03671 }
03672 }
03673 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
03674 enc = io_input_encoding(fptr);
03675 while (io_fillbuf(fptr) >= 0) {
03676 r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off,
03677 fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
03678 if (MBCLEN_CHARFOUND_P(r) &&
03679 (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
03680 c = rb_enc_codepoint(fptr->rbuf.ptr+fptr->rbuf.off,
03681 fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
03682 fptr->rbuf.off += n;
03683 fptr->rbuf.len -= n;
03684 rb_yield(UINT2NUM(c));
03685 }
03686 else if (MBCLEN_INVALID_P(r)) {
03687 rb_raise(rb_eArgError, "invalid byte sequence in %s", rb_enc_name(enc));
03688 }
03689 else {
03690 continue;
03691 }
03692 }
03693 return io;
03694 }
03695
03696
03697
03698
03699
03700 static VALUE
03701 rb_io_codepoints(VALUE io)
03702 {
03703 rb_warn("IO#codepoints is deprecated; use #each_codepoint instead");
03704 if (!rb_block_given_p())
03705 return rb_enumeratorize(io, ID2SYM(rb_intern("each_codepoint")), 0, 0);
03706 return rb_io_each_codepoint(io);
03707 }
03708
03709
03710
03711
03712
03713
03714
03715
03716
03717
03718
03719
03720
03721
03722 static VALUE
03723 rb_io_getc(VALUE io)
03724 {
03725 rb_io_t *fptr;
03726 rb_encoding *enc;
03727
03728 GetOpenFile(io, fptr);
03729 rb_io_check_char_readable(fptr);
03730
03731 enc = io_input_encoding(fptr);
03732 READ_CHECK(fptr);
03733 return io_getc(fptr, enc);
03734 }
03735
03736
03737
03738
03739
03740
03741
03742
03743
03744
03745
03746
03747
03748 static VALUE
03749 rb_io_readchar(VALUE io)
03750 {
03751 VALUE c = rb_io_getc(io);
03752
03753 if (NIL_P(c)) {
03754 rb_eof_error();
03755 }
03756 return c;
03757 }
03758
03759
03760
03761
03762
03763
03764
03765
03766
03767
03768
03769
03770
03771 VALUE
03772 rb_io_getbyte(VALUE io)
03773 {
03774 rb_io_t *fptr;
03775 int c;
03776
03777 GetOpenFile(io, fptr);
03778 rb_io_check_byte_readable(fptr);
03779 READ_CHECK(fptr);
03780 if (fptr->fd == 0 && (fptr->mode & FMODE_TTY) && RB_TYPE_P(rb_stdout, T_FILE)) {
03781 rb_io_t *ofp;
03782 GetOpenFile(rb_stdout, ofp);
03783 if (ofp->mode & FMODE_TTY) {
03784 rb_io_flush(rb_stdout);
03785 }
03786 }
03787 if (io_fillbuf(fptr) < 0) {
03788 return Qnil;
03789 }
03790 fptr->rbuf.off++;
03791 fptr->rbuf.len--;
03792 c = (unsigned char)fptr->rbuf.ptr[fptr->rbuf.off-1];
03793 return INT2FIX(c & 0xff);
03794 }
03795
03796
03797
03798
03799
03800
03801
03802
03803
03804 static VALUE
03805 rb_io_readbyte(VALUE io)
03806 {
03807 VALUE c = rb_io_getbyte(io);
03808
03809 if (NIL_P(c)) {
03810 rb_eof_error();
03811 }
03812 return c;
03813 }
03814
03815
03816
03817
03818
03819
03820
03821
03822
03823
03824
03825
03826
03827
03828
03829
03830
03831
03832 VALUE
03833 rb_io_ungetbyte(VALUE io, VALUE b)
03834 {
03835 rb_io_t *fptr;
03836
03837 GetOpenFile(io, fptr);
03838 rb_io_check_byte_readable(fptr);
03839 if (NIL_P(b)) return Qnil;
03840 if (FIXNUM_P(b)) {
03841 char cc = FIX2INT(b);
03842 b = rb_str_new(&cc, 1);
03843 }
03844 else {
03845 SafeStringValue(b);
03846 }
03847 io_ungetbyte(b, fptr);
03848 return Qnil;
03849 }
03850
03851
03852
03853
03854
03855
03856
03857
03858
03859
03860
03861
03862
03863
03864
03865
03866
03867 VALUE
03868 rb_io_ungetc(VALUE io, VALUE c)
03869 {
03870 rb_io_t *fptr;
03871 long len;
03872
03873 GetOpenFile(io, fptr);
03874 rb_io_check_char_readable(fptr);
03875 if (NIL_P(c)) return Qnil;
03876 if (FIXNUM_P(c)) {
03877 c = rb_enc_uint_chr(FIX2UINT(c), io_read_encoding(fptr));
03878 }
03879 else if (RB_TYPE_P(c, T_BIGNUM)) {
03880 c = rb_enc_uint_chr(NUM2UINT(c), io_read_encoding(fptr));
03881 }
03882 else {
03883 SafeStringValue(c);
03884 }
03885 if (NEED_READCONV(fptr)) {
03886 SET_BINARY_MODE(fptr);
03887 len = RSTRING_LEN(c);
03888 #if SIZEOF_LONG > SIZEOF_INT
03889 if (len > INT_MAX)
03890 rb_raise(rb_eIOError, "ungetc failed");
03891 #endif
03892 make_readconv(fptr, (int)len);
03893 if (fptr->cbuf.capa - fptr->cbuf.len < len)
03894 rb_raise(rb_eIOError, "ungetc failed");
03895 if (fptr->cbuf.off < len) {
03896 MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.capa-fptr->cbuf.len,
03897 fptr->cbuf.ptr+fptr->cbuf.off,
03898 char, fptr->cbuf.len);
03899 fptr->cbuf.off = fptr->cbuf.capa-fptr->cbuf.len;
03900 }
03901 fptr->cbuf.off -= (int)len;
03902 fptr->cbuf.len += (int)len;
03903 MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.off, RSTRING_PTR(c), char, len);
03904 }
03905 else {
03906 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
03907 io_ungetbyte(c, fptr);
03908 }
03909 return Qnil;
03910 }
03911
03912
03913
03914
03915
03916
03917
03918
03919
03920
03921
03922
03923
03924 static VALUE
03925 rb_io_isatty(VALUE io)
03926 {
03927 rb_io_t *fptr;
03928
03929 GetOpenFile(io, fptr);
03930 if (isatty(fptr->fd) == 0)
03931 return Qfalse;
03932 return Qtrue;
03933 }
03934
03935 #if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
03936
03937
03938
03939
03940
03941
03942
03943
03944
03945
03946
03947
03948
03949
03950 static VALUE
03951 rb_io_close_on_exec_p(VALUE io)
03952 {
03953 rb_io_t *fptr;
03954 VALUE write_io;
03955 int fd, ret;
03956
03957 write_io = GetWriteIO(io);
03958 if (io != write_io) {
03959 GetOpenFile(write_io, fptr);
03960 if (fptr && 0 <= (fd = fptr->fd)) {
03961 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
03962 if (!(ret & FD_CLOEXEC)) return Qfalse;
03963 }
03964 }
03965
03966 GetOpenFile(io, fptr);
03967 if (fptr && 0 <= (fd = fptr->fd)) {
03968 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
03969 if (!(ret & FD_CLOEXEC)) return Qfalse;
03970 }
03971 return Qtrue;
03972 }
03973 #else
03974 #define rb_io_close_on_exec_p rb_f_notimplement
03975 #endif
03976
03977 #if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
03978
03979
03980
03981
03982
03983
03984
03985
03986
03987
03988
03989
03990
03991
03992
03993
03994
03995
03996
03997
03998 static VALUE
03999 rb_io_set_close_on_exec(VALUE io, VALUE arg)
04000 {
04001 int flag = RTEST(arg) ? FD_CLOEXEC : 0;
04002 rb_io_t *fptr;
04003 VALUE write_io;
04004 int fd, ret;
04005
04006 write_io = GetWriteIO(io);
04007 if (io != write_io) {
04008 GetOpenFile(write_io, fptr);
04009 if (fptr && 0 <= (fd = fptr->fd)) {
04010 if ((ret = fcntl(fptr->fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
04011 if ((ret & FD_CLOEXEC) != flag) {
04012 ret = (ret & ~FD_CLOEXEC) | flag;
04013 ret = fcntl(fd, F_SETFD, ret);
04014 if (ret == -1) rb_sys_fail_path(fptr->pathv);
04015 }
04016 }
04017
04018 }
04019
04020 GetOpenFile(io, fptr);
04021 if (fptr && 0 <= (fd = fptr->fd)) {
04022 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
04023 if ((ret & FD_CLOEXEC) != flag) {
04024 ret = (ret & ~FD_CLOEXEC) | flag;
04025 ret = fcntl(fd, F_SETFD, ret);
04026 if (ret == -1) rb_sys_fail_path(fptr->pathv);
04027 }
04028 }
04029 return Qnil;
04030 }
04031 #else
04032 #define rb_io_set_close_on_exec rb_f_notimplement
04033 #endif
04034
04035 #define FMODE_PREP (1<<16)
04036 #define IS_PREP_STDIO(f) ((f)->mode & FMODE_PREP)
04037 #define PREP_STDIO_NAME(f) (RSTRING_PTR((f)->pathv))
04038
04039 static VALUE
04040 finish_writeconv(rb_io_t *fptr, int noalloc)
04041 {
04042 unsigned char *ds, *dp, *de;
04043 rb_econv_result_t res;
04044
04045 if (!fptr->wbuf.ptr) {
04046 unsigned char buf[1024];
04047 long r;
04048
04049 res = econv_destination_buffer_full;
04050 while (res == econv_destination_buffer_full) {
04051 ds = dp = buf;
04052 de = buf + sizeof(buf);
04053 res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
04054 while (dp-ds) {
04055 retry:
04056 if (fptr->write_lock && rb_mutex_owned_p(fptr->write_lock))
04057 r = rb_write_internal2(fptr->fd, ds, dp-ds);
04058 else
04059 r = rb_write_internal(fptr->fd, ds, dp-ds);
04060 if (r == dp-ds)
04061 break;
04062 if (0 <= r) {
04063 ds += r;
04064 }
04065 if (rb_io_wait_writable(fptr->fd)) {
04066 if (fptr->fd < 0)
04067 return noalloc ? Qtrue : rb_exc_new3(rb_eIOError, rb_str_new_cstr(closed_stream));
04068 goto retry;
04069 }
04070 return noalloc ? Qtrue : INT2NUM(errno);
04071 }
04072 if (res == econv_invalid_byte_sequence ||
04073 res == econv_incomplete_input ||
04074 res == econv_undefined_conversion) {
04075 return noalloc ? Qtrue : rb_econv_make_exception(fptr->writeconv);
04076 }
04077 }
04078
04079 return Qnil;
04080 }
04081
04082 res = econv_destination_buffer_full;
04083 while (res == econv_destination_buffer_full) {
04084 if (fptr->wbuf.len == fptr->wbuf.capa) {
04085 if (io_fflush(fptr) < 0)
04086 return noalloc ? Qtrue : INT2NUM(errno);
04087 }
04088
04089 ds = dp = (unsigned char *)fptr->wbuf.ptr + fptr->wbuf.off + fptr->wbuf.len;
04090 de = (unsigned char *)fptr->wbuf.ptr + fptr->wbuf.capa;
04091 res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
04092 fptr->wbuf.len += (int)(dp - ds);
04093 if (res == econv_invalid_byte_sequence ||
04094 res == econv_incomplete_input ||
04095 res == econv_undefined_conversion) {
04096 return noalloc ? Qtrue : rb_econv_make_exception(fptr->writeconv);
04097 }
04098 }
04099 return Qnil;
04100 }
04101
04102 struct finish_writeconv_arg {
04103 rb_io_t *fptr;
04104 int noalloc;
04105 };
04106
04107 static VALUE
04108 finish_writeconv_sync(VALUE arg)
04109 {
04110 struct finish_writeconv_arg *p = (struct finish_writeconv_arg *)arg;
04111 return finish_writeconv(p->fptr, p->noalloc);
04112 }
04113
04114 static void*
04115 nogvl_close(void *ptr)
04116 {
04117 int *fd = ptr;
04118
04119 return (void*)(intptr_t)close(*fd);
04120 }
04121
04122 static int
04123 maygvl_close(int fd, int keepgvl)
04124 {
04125 if (keepgvl)
04126 return close(fd);
04127
04128
04129
04130
04131
04132 return (int)(intptr_t)rb_thread_call_without_gvl(nogvl_close, &fd, RUBY_UBF_IO, 0);
04133 }
04134
04135 static void*
04136 nogvl_fclose(void *ptr)
04137 {
04138 FILE *file = ptr;
04139
04140 return (void*)(intptr_t)fclose(file);
04141 }
04142
04143 static int
04144 maygvl_fclose(FILE *file, int keepgvl)
04145 {
04146 if (keepgvl)
04147 return fclose(file);
04148
04149 return (int)(intptr_t)rb_thread_call_without_gvl(nogvl_fclose, file, RUBY_UBF_IO, 0);
04150 }
04151
04152 static void
04153 fptr_finalize(rb_io_t *fptr, int noraise)
04154 {
04155 VALUE err = Qnil;
04156 int fd = fptr->fd;
04157 FILE *stdio_file = fptr->stdio_file;
04158
04159 if (fptr->writeconv) {
04160 if (fptr->write_lock && !noraise) {
04161 struct finish_writeconv_arg arg;
04162 arg.fptr = fptr;
04163 arg.noalloc = noraise;
04164 err = rb_mutex_synchronize(fptr->write_lock, finish_writeconv_sync, (VALUE)&arg);
04165 }
04166 else {
04167 err = finish_writeconv(fptr, noraise);
04168 }
04169 }
04170 if (fptr->wbuf.len) {
04171 if (noraise) {
04172 if ((int)io_flush_buffer_sync(fptr) < 0 && NIL_P(err))
04173 err = Qtrue;
04174 }
04175 else {
04176 if (io_fflush(fptr) < 0 && NIL_P(err))
04177 err = INT2NUM(errno);
04178 }
04179 }
04180
04181 fptr->fd = -1;
04182 fptr->stdio_file = 0;
04183 fptr->mode &= ~(FMODE_READABLE|FMODE_WRITABLE);
04184
04185 if (IS_PREP_STDIO(fptr) || fd <= 2) {
04186
04187 }
04188 else if (stdio_file) {
04189
04190
04191 if ((maygvl_fclose(stdio_file, noraise) < 0) && NIL_P(err))
04192 err = noraise ? Qtrue : INT2NUM(errno);
04193 }
04194 else if (0 <= fd) {
04195
04196
04197
04198 if ((maygvl_close(fd, noraise) < 0) && NIL_P(err))
04199 err = noraise ? Qtrue : INT2NUM(errno);
04200 }
04201
04202 if (!NIL_P(err) && !noraise) {
04203 switch (TYPE(err)) {
04204 case T_FIXNUM:
04205 case T_BIGNUM:
04206 errno = NUM2INT(err);
04207 rb_sys_fail_path(fptr->pathv);
04208
04209 default:
04210 rb_exc_raise(err);
04211 }
04212 }
04213 }
04214
04215 static void
04216 rb_io_fptr_cleanup(rb_io_t *fptr, int noraise)
04217 {
04218 if (fptr->finalize) {
04219 (*fptr->finalize)(fptr, noraise);
04220 }
04221 else {
04222 fptr_finalize(fptr, noraise);
04223 }
04224 }
04225
04226 static void
04227 clear_readconv(rb_io_t *fptr)
04228 {
04229 if (fptr->readconv) {
04230 rb_econv_close(fptr->readconv);
04231 fptr->readconv = NULL;
04232 }
04233 if (fptr->cbuf.ptr) {
04234 free(fptr->cbuf.ptr);
04235 fptr->cbuf.ptr = NULL;
04236 }
04237 }
04238
04239 static void
04240 clear_writeconv(rb_io_t *fptr)
04241 {
04242 if (fptr->writeconv) {
04243 rb_econv_close(fptr->writeconv);
04244 fptr->writeconv = NULL;
04245 }
04246 fptr->writeconv_initialized = 0;
04247 }
04248
04249 static void
04250 clear_codeconv(rb_io_t *fptr)
04251 {
04252 clear_readconv(fptr);
04253 clear_writeconv(fptr);
04254 }
04255
04256 int
04257 rb_io_fptr_finalize(rb_io_t *fptr)
04258 {
04259 if (!fptr) return 0;
04260 fptr->pathv = Qnil;
04261 if (0 <= fptr->fd)
04262 rb_io_fptr_cleanup(fptr, TRUE);
04263 fptr->write_lock = 0;
04264 if (fptr->rbuf.ptr) {
04265 free(fptr->rbuf.ptr);
04266 fptr->rbuf.ptr = 0;
04267 }
04268 if (fptr->wbuf.ptr) {
04269 free(fptr->wbuf.ptr);
04270 fptr->wbuf.ptr = 0;
04271 }
04272 clear_codeconv(fptr);
04273 free(fptr);
04274 return 1;
04275 }
04276
04277 size_t rb_econv_memsize(rb_econv_t *);
04278
04279 RUBY_FUNC_EXPORTED size_t
04280 rb_io_memsize(const rb_io_t *fptr)
04281 {
04282 size_t size = sizeof(rb_io_t);
04283 size += fptr->rbuf.capa;
04284 size += fptr->wbuf.capa;
04285 size += fptr->cbuf.capa;
04286 if (fptr->readconv) size += rb_econv_memsize(fptr->readconv);
04287 if (fptr->writeconv) size += rb_econv_memsize(fptr->writeconv);
04288 return size;
04289 }
04290
04291 VALUE
04292 rb_io_close(VALUE io)
04293 {
04294 rb_io_t *fptr;
04295 int fd;
04296 VALUE write_io;
04297 rb_io_t *write_fptr;
04298
04299 write_io = GetWriteIO(io);
04300 if (io != write_io) {
04301 write_fptr = RFILE(write_io)->fptr;
04302 if (write_fptr && 0 <= write_fptr->fd) {
04303 rb_io_fptr_cleanup(write_fptr, TRUE);
04304 }
04305 }
04306
04307 fptr = RFILE(io)->fptr;
04308 if (!fptr) return Qnil;
04309 if (fptr->fd < 0) return Qnil;
04310
04311 fd = fptr->fd;
04312 rb_thread_fd_close(fd);
04313 rb_io_fptr_cleanup(fptr, FALSE);
04314
04315 if (fptr->pid) {
04316 rb_last_status_clear();
04317 rb_syswait(fptr->pid);
04318 fptr->pid = 0;
04319 }
04320
04321 return Qnil;
04322 }
04323
04324
04325
04326
04327
04328
04329
04330
04331
04332
04333
04334
04335
04336
04337
04338 static VALUE
04339 rb_io_close_m(VALUE io)
04340 {
04341 rb_io_check_closed(RFILE(io)->fptr);
04342 rb_io_close(io);
04343 return Qnil;
04344 }
04345
04346 static VALUE
04347 io_call_close(VALUE io)
04348 {
04349 rb_check_funcall(io, rb_intern("close"), 0, 0);
04350 return io;
04351 }
04352
04353 static VALUE
04354 ignore_closed_stream(VALUE io, VALUE exc)
04355 {
04356 enum {mesg_len = sizeof(closed_stream)-1};
04357 VALUE mesg = rb_attr_get(exc, rb_intern("mesg"));
04358 if (!RB_TYPE_P(mesg, T_STRING) ||
04359 RSTRING_LEN(mesg) != mesg_len ||
04360 memcmp(RSTRING_PTR(mesg), closed_stream, mesg_len)) {
04361 rb_exc_raise(exc);
04362 }
04363 return io;
04364 }
04365
04366 static VALUE
04367 io_close(VALUE io)
04368 {
04369 VALUE closed = rb_check_funcall(io, rb_intern("closed?"), 0, 0);
04370 if (closed != Qundef && RTEST(closed)) return io;
04371 rb_rescue2(io_call_close, io, ignore_closed_stream, io,
04372 rb_eIOError, (VALUE)0);
04373 return io;
04374 }
04375
04376
04377
04378
04379
04380
04381
04382
04383
04384
04385
04386
04387
04388
04389
04390
04391
04392
04393
04394
04395 static VALUE
04396 rb_io_closed(VALUE io)
04397 {
04398 rb_io_t *fptr;
04399 VALUE write_io;
04400 rb_io_t *write_fptr;
04401
04402 write_io = GetWriteIO(io);
04403 if (io != write_io) {
04404 write_fptr = RFILE(write_io)->fptr;
04405 if (write_fptr && 0 <= write_fptr->fd) {
04406 return Qfalse;
04407 }
04408 }
04409
04410 fptr = RFILE(io)->fptr;
04411 rb_io_check_initialized(fptr);
04412 return 0 <= fptr->fd ? Qfalse : Qtrue;
04413 }
04414
04415
04416
04417
04418
04419
04420
04421
04422
04423
04424
04425
04426
04427
04428
04429
04430
04431
04432
04433 static VALUE
04434 rb_io_close_read(VALUE io)
04435 {
04436 rb_io_t *fptr;
04437 VALUE write_io;
04438
04439 GetOpenFile(io, fptr);
04440 if (is_socket(fptr->fd, fptr->pathv)) {
04441 #ifndef SHUT_RD
04442 # define SHUT_RD 0
04443 #endif
04444 if (shutdown(fptr->fd, SHUT_RD) < 0)
04445 rb_sys_fail_path(fptr->pathv);
04446 fptr->mode &= ~FMODE_READABLE;
04447 if (!(fptr->mode & FMODE_WRITABLE))
04448 return rb_io_close(io);
04449 return Qnil;
04450 }
04451
04452 write_io = GetWriteIO(io);
04453 if (io != write_io) {
04454 rb_io_t *wfptr;
04455 GetOpenFile(write_io, wfptr);
04456 wfptr->pid = fptr->pid;
04457 fptr->pid = 0;
04458 RFILE(io)->fptr = wfptr;
04459
04460 fptr->tied_io_for_writing = 0;
04461 fptr->mode &= ~FMODE_DUPLEX;
04462 RFILE(write_io)->fptr = fptr;
04463 rb_io_fptr_cleanup(fptr, FALSE);
04464
04465 return Qnil;
04466 }
04467
04468 if (fptr->mode & FMODE_WRITABLE) {
04469 rb_raise(rb_eIOError, "closing non-duplex IO for reading");
04470 }
04471 return rb_io_close(io);
04472 }
04473
04474
04475
04476
04477
04478
04479
04480
04481
04482
04483
04484
04485
04486
04487
04488
04489
04490
04491
04492
04493 static VALUE
04494 rb_io_close_write(VALUE io)
04495 {
04496 rb_io_t *fptr;
04497 VALUE write_io;
04498
04499 write_io = GetWriteIO(io);
04500 GetOpenFile(write_io, fptr);
04501 if (is_socket(fptr->fd, fptr->pathv)) {
04502 #ifndef SHUT_WR
04503 # define SHUT_WR 1
04504 #endif
04505 if (shutdown(fptr->fd, SHUT_WR) < 0)
04506 rb_sys_fail_path(fptr->pathv);
04507 fptr->mode &= ~FMODE_WRITABLE;
04508 if (!(fptr->mode & FMODE_READABLE))
04509 return rb_io_close(write_io);
04510 return Qnil;
04511 }
04512
04513 if (fptr->mode & FMODE_READABLE) {
04514 rb_raise(rb_eIOError, "closing non-duplex IO for writing");
04515 }
04516
04517 if (io != write_io) {
04518 GetOpenFile(io, fptr);
04519 fptr->tied_io_for_writing = 0;
04520 fptr->mode &= ~FMODE_DUPLEX;
04521 }
04522 rb_io_close(write_io);
04523 return Qnil;
04524 }
04525
04526
04527
04528
04529
04530
04531
04532
04533
04534
04535
04536
04537
04538
04539 static VALUE
04540 rb_io_sysseek(int argc, VALUE *argv, VALUE io)
04541 {
04542 VALUE offset, ptrname;
04543 int whence = SEEK_SET;
04544 rb_io_t *fptr;
04545 off_t pos;
04546
04547 if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
04548 whence = interpret_seek_whence(ptrname);
04549 }
04550 pos = NUM2OFFT(offset);
04551 GetOpenFile(io, fptr);
04552 if ((fptr->mode & FMODE_READABLE) &&
04553 (READ_DATA_BUFFERED(fptr) || READ_CHAR_PENDING(fptr))) {
04554 rb_raise(rb_eIOError, "sysseek for buffered IO");
04555 }
04556 if ((fptr->mode & FMODE_WRITABLE) && fptr->wbuf.len) {
04557 rb_warn("sysseek for buffered IO");
04558 }
04559 errno = 0;
04560 pos = lseek(fptr->fd, pos, whence);
04561 if (pos == -1 && errno) rb_sys_fail_path(fptr->pathv);
04562
04563 return OFFT2NUM(pos);
04564 }
04565
04566
04567
04568
04569
04570
04571
04572
04573
04574
04575
04576
04577
04578
04579 static VALUE
04580 rb_io_syswrite(VALUE io, VALUE str)
04581 {
04582 rb_io_t *fptr;
04583 long n;
04584
04585 if (!RB_TYPE_P(str, T_STRING))
04586 str = rb_obj_as_string(str);
04587
04588 io = GetWriteIO(io);
04589 GetOpenFile(io, fptr);
04590 rb_io_check_writable(fptr);
04591
04592 str = rb_str_new_frozen(str);
04593
04594 if (fptr->wbuf.len) {
04595 rb_warn("syswrite for buffered IO");
04596 }
04597
04598 n = rb_write_internal(fptr->fd, RSTRING_PTR(str), RSTRING_LEN(str));
04599 RB_GC_GUARD(str);
04600
04601 if (n == -1) rb_sys_fail_path(fptr->pathv);
04602
04603 return LONG2FIX(n);
04604 }
04605
04606
04607
04608
04609
04610
04611
04612
04613
04614
04615
04616
04617
04618
04619
04620
04621
04622
04623
04624 static VALUE
04625 rb_io_sysread(int argc, VALUE *argv, VALUE io)
04626 {
04627 VALUE len, str;
04628 rb_io_t *fptr;
04629 long n, ilen;
04630 struct read_internal_arg arg;
04631
04632 rb_scan_args(argc, argv, "11", &len, &str);
04633 ilen = NUM2LONG(len);
04634
04635 io_setstrbuf(&str,ilen);
04636 if (ilen == 0) return str;
04637
04638 GetOpenFile(io, fptr);
04639 rb_io_check_byte_readable(fptr);
04640
04641 if (READ_DATA_BUFFERED(fptr)) {
04642 rb_raise(rb_eIOError, "sysread for buffered IO");
04643 }
04644
04645 n = fptr->fd;
04646
04647
04648
04649
04650
04651
04652
04653
04654 rb_thread_wait_fd(fptr->fd);
04655
04656 rb_io_check_closed(fptr);
04657
04658 io_setstrbuf(&str, ilen);
04659 rb_str_locktmp(str);
04660 arg.fd = fptr->fd;
04661 arg.str_ptr = RSTRING_PTR(str);
04662 arg.len = ilen;
04663 rb_ensure(read_internal_call, (VALUE)&arg, rb_str_unlocktmp, str);
04664 n = arg.len;
04665
04666 if (n == -1) {
04667 rb_sys_fail_path(fptr->pathv);
04668 }
04669 io_set_read_length(str, n);
04670 if (n == 0 && ilen > 0) {
04671 rb_eof_error();
04672 }
04673 OBJ_TAINT(str);
04674
04675 return str;
04676 }
04677
04678 VALUE
04679 rb_io_binmode(VALUE io)
04680 {
04681 rb_io_t *fptr;
04682
04683 GetOpenFile(io, fptr);
04684 if (fptr->readconv)
04685 rb_econv_binmode(fptr->readconv);
04686 if (fptr->writeconv)
04687 rb_econv_binmode(fptr->writeconv);
04688 fptr->mode |= FMODE_BINMODE;
04689 fptr->mode &= ~FMODE_TEXTMODE;
04690 fptr->writeconv_pre_ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
04691 #ifdef O_BINARY
04692 if (!fptr->readconv) {
04693 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
04694 }
04695 else {
04696 setmode(fptr->fd, O_BINARY);
04697 }
04698 #endif
04699 return io;
04700 }
04701
04702 static void
04703 io_ascii8bit_binmode(rb_io_t *fptr)
04704 {
04705 if (fptr->readconv) {
04706 rb_econv_close(fptr->readconv);
04707 fptr->readconv = NULL;
04708 }
04709 if (fptr->writeconv) {
04710 rb_econv_close(fptr->writeconv);
04711 fptr->writeconv = NULL;
04712 }
04713 fptr->mode |= FMODE_BINMODE;
04714 fptr->mode &= ~FMODE_TEXTMODE;
04715 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
04716
04717 fptr->encs.enc = rb_ascii8bit_encoding();
04718 fptr->encs.enc2 = NULL;
04719 fptr->encs.ecflags = 0;
04720 fptr->encs.ecopts = Qnil;
04721 clear_codeconv(fptr);
04722 }
04723
04724 VALUE
04725 rb_io_ascii8bit_binmode(VALUE io)
04726 {
04727 rb_io_t *fptr;
04728
04729 GetOpenFile(io, fptr);
04730 io_ascii8bit_binmode(fptr);
04731
04732 return io;
04733 }
04734
04735
04736
04737
04738
04739
04740
04741
04742
04743
04744
04745
04746
04747
04748 static VALUE
04749 rb_io_binmode_m(VALUE io)
04750 {
04751 VALUE write_io;
04752
04753 rb_io_ascii8bit_binmode(io);
04754
04755 write_io = GetWriteIO(io);
04756 if (write_io != io)
04757 rb_io_ascii8bit_binmode(write_io);
04758 return io;
04759 }
04760
04761
04762
04763
04764
04765
04766
04767 static VALUE
04768 rb_io_binmode_p(VALUE io)
04769 {
04770 rb_io_t *fptr;
04771 GetOpenFile(io, fptr);
04772 return fptr->mode & FMODE_BINMODE ? Qtrue : Qfalse;
04773 }
04774
04775 static const char*
04776 rb_io_fmode_modestr(int fmode)
04777 {
04778 if (fmode & FMODE_APPEND) {
04779 if ((fmode & FMODE_READWRITE) == FMODE_READWRITE) {
04780 return MODE_BTMODE("a+", "ab+", "at+");
04781 }
04782 return MODE_BTMODE("a", "ab", "at");
04783 }
04784 switch (fmode & FMODE_READWRITE) {
04785 default:
04786 rb_raise(rb_eArgError, "invalid access fmode 0x%x", fmode);
04787 case FMODE_READABLE:
04788 return MODE_BTMODE("r", "rb", "rt");
04789 case FMODE_WRITABLE:
04790 return MODE_BTMODE("w", "wb", "wt");
04791 case FMODE_READWRITE:
04792 if (fmode & FMODE_CREATE) {
04793 return MODE_BTMODE("w+", "wb+", "wt+");
04794 }
04795 return MODE_BTMODE("r+", "rb+", "rt+");
04796 }
04797 }
04798
04799 static int
04800 io_encname_bom_p(const char *name, long len)
04801 {
04802 static const char bom_prefix[] = "bom|utf-";
04803 enum {bom_prefix_len = (int)sizeof(bom_prefix) - 1};
04804 if (!len) {
04805 const char *p = strchr(name, ':');
04806 len = p ? (long)(p - name) : (long)strlen(name);
04807 }
04808 return len > bom_prefix_len && STRNCASECMP(name, bom_prefix, bom_prefix_len) == 0;
04809 }
04810
04811 int
04812 rb_io_modestr_fmode(const char *modestr)
04813 {
04814 int fmode = 0;
04815 const char *m = modestr, *p = NULL;
04816
04817 switch (*m++) {
04818 case 'r':
04819 fmode |= FMODE_READABLE;
04820 break;
04821 case 'w':
04822 fmode |= FMODE_WRITABLE | FMODE_TRUNC | FMODE_CREATE;
04823 break;
04824 case 'a':
04825 fmode |= FMODE_WRITABLE | FMODE_APPEND | FMODE_CREATE;
04826 break;
04827 default:
04828 error:
04829 rb_raise(rb_eArgError, "invalid access mode %s", modestr);
04830 }
04831
04832 while (*m) {
04833 switch (*m++) {
04834 case 'b':
04835 fmode |= FMODE_BINMODE;
04836 break;
04837 case 't':
04838 fmode |= FMODE_TEXTMODE;
04839 break;
04840 case '+':
04841 fmode |= FMODE_READWRITE;
04842 break;
04843 default:
04844 goto error;
04845 case ':':
04846 p = m;
04847 goto finished;
04848 }
04849 }
04850
04851 finished:
04852 if ((fmode & FMODE_BINMODE) && (fmode & FMODE_TEXTMODE))
04853 goto error;
04854 if (p && io_encname_bom_p(p, 0))
04855 fmode |= FMODE_SETENC_BY_BOM;
04856
04857 return fmode;
04858 }
04859
04860 int
04861 rb_io_oflags_fmode(int oflags)
04862 {
04863 int fmode = 0;
04864
04865 switch (oflags & (O_RDONLY|O_WRONLY|O_RDWR)) {
04866 case O_RDONLY:
04867 fmode = FMODE_READABLE;
04868 break;
04869 case O_WRONLY:
04870 fmode = FMODE_WRITABLE;
04871 break;
04872 case O_RDWR:
04873 fmode = FMODE_READWRITE;
04874 break;
04875 }
04876
04877 if (oflags & O_APPEND) {
04878 fmode |= FMODE_APPEND;
04879 }
04880 if (oflags & O_TRUNC) {
04881 fmode |= FMODE_TRUNC;
04882 }
04883 if (oflags & O_CREAT) {
04884 fmode |= FMODE_CREATE;
04885 }
04886 #ifdef O_BINARY
04887 if (oflags & O_BINARY) {
04888 fmode |= FMODE_BINMODE;
04889 }
04890 #endif
04891
04892 return fmode;
04893 }
04894
04895 static int
04896 rb_io_fmode_oflags(int fmode)
04897 {
04898 int oflags = 0;
04899
04900 switch (fmode & FMODE_READWRITE) {
04901 case FMODE_READABLE:
04902 oflags |= O_RDONLY;
04903 break;
04904 case FMODE_WRITABLE:
04905 oflags |= O_WRONLY;
04906 break;
04907 case FMODE_READWRITE:
04908 oflags |= O_RDWR;
04909 break;
04910 }
04911
04912 if (fmode & FMODE_APPEND) {
04913 oflags |= O_APPEND;
04914 }
04915 if (fmode & FMODE_TRUNC) {
04916 oflags |= O_TRUNC;
04917 }
04918 if (fmode & FMODE_CREATE) {
04919 oflags |= O_CREAT;
04920 }
04921 #ifdef O_BINARY
04922 if (fmode & FMODE_BINMODE) {
04923 oflags |= O_BINARY;
04924 }
04925 #endif
04926
04927 return oflags;
04928 }
04929
04930 int
04931 rb_io_modestr_oflags(const char *modestr)
04932 {
04933 return rb_io_fmode_oflags(rb_io_modestr_fmode(modestr));
04934 }
04935
04936 static const char*
04937 rb_io_oflags_modestr(int oflags)
04938 {
04939 #ifdef O_BINARY
04940 # define MODE_BINARY(a,b) ((oflags & O_BINARY) ? (b) : (a))
04941 #else
04942 # define MODE_BINARY(a,b) (a)
04943 #endif
04944 int accmode = oflags & (O_RDONLY|O_WRONLY|O_RDWR);
04945 if (oflags & O_APPEND) {
04946 if (accmode == O_WRONLY) {
04947 return MODE_BINARY("a", "ab");
04948 }
04949 if (accmode == O_RDWR) {
04950 return MODE_BINARY("a+", "ab+");
04951 }
04952 }
04953 switch (oflags & (O_RDONLY|O_WRONLY|O_RDWR)) {
04954 default:
04955 rb_raise(rb_eArgError, "invalid access oflags 0x%x", oflags);
04956 case O_RDONLY:
04957 return MODE_BINARY("r", "rb");
04958 case O_WRONLY:
04959 return MODE_BINARY("w", "wb");
04960 case O_RDWR:
04961 return MODE_BINARY("r+", "rb+");
04962 }
04963 }
04964
04965
04966
04967
04968
04969
04970 static void
04971 rb_io_ext_int_to_encs(rb_encoding *ext, rb_encoding *intern, rb_encoding **enc, rb_encoding **enc2, int fmode)
04972 {
04973 int default_ext = 0;
04974
04975 if (ext == NULL) {
04976 ext = rb_default_external_encoding();
04977 default_ext = 1;
04978 }
04979 if (ext == rb_ascii8bit_encoding()) {
04980
04981 intern = NULL;
04982 }
04983 else if (intern == NULL) {
04984 intern = rb_default_internal_encoding();
04985 }
04986 if (intern == NULL || intern == (rb_encoding *)Qnil ||
04987 (!(fmode & FMODE_SETENC_BY_BOM) && (intern == ext))) {
04988
04989 *enc = (default_ext && intern != ext) ? NULL : ext;
04990 *enc2 = NULL;
04991 }
04992 else {
04993 *enc = intern;
04994 *enc2 = ext;
04995 }
04996 }
04997
04998 static void
04999 unsupported_encoding(const char *name)
05000 {
05001 rb_warn("Unsupported encoding %s ignored", name);
05002 }
05003
05004 static void
05005 parse_mode_enc(const char *estr, rb_encoding **enc_p, rb_encoding **enc2_p, int *fmode_p)
05006 {
05007 const char *p;
05008 char encname[ENCODING_MAXNAMELEN+1];
05009 int idx, idx2;
05010 int fmode = fmode_p ? *fmode_p : 0;
05011 rb_encoding *ext_enc, *int_enc;
05012
05013
05014
05015 p = strrchr(estr, ':');
05016 if (p) {
05017 long len = (p++) - estr;
05018 if (len == 0 || len > ENCODING_MAXNAMELEN)
05019 idx = -1;
05020 else {
05021 if (io_encname_bom_p(estr, len)) {
05022 fmode |= FMODE_SETENC_BY_BOM;
05023 estr += 4;
05024 len -= 4;
05025 }
05026 memcpy(encname, estr, len);
05027 encname[len] = '\0';
05028 estr = encname;
05029 idx = rb_enc_find_index(encname);
05030 }
05031 }
05032 else {
05033 long len = strlen(estr);
05034 if (io_encname_bom_p(estr, len)) {
05035 fmode |= FMODE_SETENC_BY_BOM;
05036 estr += 4;
05037 len -= 4;
05038 memcpy(encname, estr, len);
05039 encname[len] = '\0';
05040 estr = encname;
05041 }
05042 idx = rb_enc_find_index(estr);
05043 }
05044 if (fmode_p) *fmode_p = fmode;
05045
05046 if (idx >= 0)
05047 ext_enc = rb_enc_from_index(idx);
05048 else {
05049 if (idx != -2)
05050 unsupported_encoding(estr);
05051 ext_enc = NULL;
05052 }
05053
05054 int_enc = NULL;
05055 if (p) {
05056 if (*p == '-' && *(p+1) == '\0') {
05057
05058 int_enc = (rb_encoding *)Qnil;
05059 }
05060 else {
05061 idx2 = rb_enc_find_index(p);
05062 if (idx2 < 0)
05063 unsupported_encoding(p);
05064 else if (!(fmode & FMODE_SETENC_BY_BOM) && (idx2 == idx)) {
05065 int_enc = (rb_encoding *)Qnil;
05066 }
05067 else
05068 int_enc = rb_enc_from_index(idx2);
05069 }
05070 }
05071
05072 rb_io_ext_int_to_encs(ext_enc, int_enc, enc_p, enc2_p, fmode);
05073 }
05074
05075 int
05076 rb_io_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding **enc2_p, int *fmode_p)
05077 {
05078 VALUE encoding=Qnil, extenc=Qundef, intenc=Qundef, tmp;
05079 int extracted = 0;
05080 rb_encoding *extencoding = NULL;
05081 rb_encoding *intencoding = NULL;
05082
05083 if (!NIL_P(opt)) {
05084 VALUE v;
05085 v = rb_hash_lookup2(opt, sym_encoding, Qnil);
05086 if (v != Qnil) encoding = v;
05087 v = rb_hash_lookup2(opt, sym_extenc, Qundef);
05088 if (v != Qnil) extenc = v;
05089 v = rb_hash_lookup2(opt, sym_intenc, Qundef);
05090 if (v != Qundef) intenc = v;
05091 }
05092 if ((extenc != Qundef || intenc != Qundef) && !NIL_P(encoding)) {
05093 if (!NIL_P(ruby_verbose)) {
05094 int idx = rb_to_encoding_index(encoding);
05095 rb_warn("Ignoring encoding parameter '%s': %s_encoding is used",
05096 idx < 0 ? StringValueCStr(encoding) : rb_enc_name(rb_enc_from_index(idx)),
05097 extenc == Qundef ? "internal" : "external");
05098 }
05099 encoding = Qnil;
05100 }
05101 if (extenc != Qundef && !NIL_P(extenc)) {
05102 extencoding = rb_to_encoding(extenc);
05103 }
05104 if (intenc != Qundef) {
05105 if (NIL_P(intenc)) {
05106
05107 intencoding = (rb_encoding *)Qnil;
05108 }
05109 else if (!NIL_P(tmp = rb_check_string_type(intenc))) {
05110 char *p = StringValueCStr(tmp);
05111
05112 if (*p == '-' && *(p+1) == '\0') {
05113
05114 intencoding = (rb_encoding *)Qnil;
05115 }
05116 else {
05117 intencoding = rb_to_encoding(intenc);
05118 }
05119 }
05120 else {
05121 intencoding = rb_to_encoding(intenc);
05122 }
05123 if (extencoding == intencoding) {
05124 intencoding = (rb_encoding *)Qnil;
05125 }
05126 }
05127 if (!NIL_P(encoding)) {
05128 extracted = 1;
05129 if (!NIL_P(tmp = rb_check_string_type(encoding))) {
05130 parse_mode_enc(StringValueCStr(tmp), enc_p, enc2_p, fmode_p);
05131 }
05132 else {
05133 rb_io_ext_int_to_encs(rb_to_encoding(encoding), NULL, enc_p, enc2_p, 0);
05134 }
05135 }
05136 else if (extenc != Qundef || intenc != Qundef) {
05137 extracted = 1;
05138 rb_io_ext_int_to_encs(extencoding, intencoding, enc_p, enc2_p, 0);
05139 }
05140 return extracted;
05141 }
05142
05143 typedef struct rb_io_enc_t convconfig_t;
05144
05145 static void
05146 validate_enc_binmode(int *fmode_p, int ecflags, rb_encoding *enc, rb_encoding *enc2)
05147 {
05148 int fmode = *fmode_p;
05149
05150 if ((fmode & FMODE_READABLE) &&
05151 !enc2 &&
05152 !(fmode & FMODE_BINMODE) &&
05153 !rb_enc_asciicompat(enc ? enc : rb_default_external_encoding()))
05154 rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
05155
05156 if (!(fmode & FMODE_BINMODE) &&
05157 (DEFAULT_TEXTMODE || (ecflags & ECONV_NEWLINE_DECORATOR_MASK))) {
05158 fmode |= DEFAULT_TEXTMODE;
05159 *fmode_p = fmode;
05160 }
05161 #if !DEFAULT_TEXTMODE
05162 else if (!(ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
05163 fmode &= ~FMODE_TEXTMODE;
05164 *fmode_p = fmode;
05165 }
05166 #endif
05167 }
05168
05169 static void
05170 extract_binmode(VALUE opthash, int *fmode)
05171 {
05172 if (!NIL_P(opthash)) {
05173 VALUE v;
05174 v = rb_hash_aref(opthash, sym_textmode);
05175 if (!NIL_P(v)) {
05176 if (*fmode & FMODE_TEXTMODE)
05177 rb_raise(rb_eArgError, "textmode specified twice");
05178 if (*fmode & FMODE_BINMODE)
05179 rb_raise(rb_eArgError, "both textmode and binmode specified");
05180 if (RTEST(v))
05181 *fmode |= FMODE_TEXTMODE;
05182 }
05183 v = rb_hash_aref(opthash, sym_binmode);
05184 if (!NIL_P(v)) {
05185 if (*fmode & FMODE_BINMODE)
05186 rb_raise(rb_eArgError, "binmode specified twice");
05187 if (*fmode & FMODE_TEXTMODE)
05188 rb_raise(rb_eArgError, "both textmode and binmode specified");
05189 if (RTEST(v))
05190 *fmode |= FMODE_BINMODE;
05191 }
05192
05193 if ((*fmode & FMODE_BINMODE) && (*fmode & FMODE_TEXTMODE))
05194 rb_raise(rb_eArgError, "both textmode and binmode specified");
05195 }
05196 }
05197
05198 static void
05199 rb_io_extract_modeenc(VALUE *vmode_p, VALUE *vperm_p, VALUE opthash,
05200 int *oflags_p, int *fmode_p, convconfig_t *convconfig_p)
05201 {
05202 VALUE vmode;
05203 int oflags, fmode;
05204 rb_encoding *enc, *enc2;
05205 int ecflags;
05206 VALUE ecopts;
05207 int has_enc = 0, has_vmode = 0;
05208 VALUE intmode;
05209
05210 vmode = *vmode_p;
05211
05212
05213 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
05214
05215 vmode_handle:
05216 if (NIL_P(vmode)) {
05217 fmode = FMODE_READABLE;
05218 oflags = O_RDONLY;
05219 }
05220 else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int"))) {
05221 vmode = intmode;
05222 oflags = NUM2INT(intmode);
05223 fmode = rb_io_oflags_fmode(oflags);
05224 }
05225 else {
05226 const char *p;
05227
05228 SafeStringValue(vmode);
05229 p = StringValueCStr(vmode);
05230 fmode = rb_io_modestr_fmode(p);
05231 oflags = rb_io_fmode_oflags(fmode);
05232 p = strchr(p, ':');
05233 if (p) {
05234 has_enc = 1;
05235 parse_mode_enc(p+1, &enc, &enc2, &fmode);
05236 }
05237 else {
05238 rb_encoding *e;
05239
05240 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
05241 rb_io_ext_int_to_encs(e, NULL, &enc, &enc2, fmode);
05242 }
05243 }
05244
05245 if (NIL_P(opthash)) {
05246 ecflags = (fmode & FMODE_READABLE) ?
05247 MODE_BTMODE(ECONV_DEFAULT_NEWLINE_DECORATOR,
05248 0, ECONV_UNIVERSAL_NEWLINE_DECORATOR) : 0;
05249 #ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
05250 ecflags |= (fmode & FMODE_WRITABLE) ?
05251 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
05252 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
05253 #endif
05254 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
05255 ecopts = Qnil;
05256 }
05257 else {
05258 VALUE v;
05259 extract_binmode(opthash, &fmode);
05260 if (fmode & FMODE_BINMODE) {
05261 #ifdef O_BINARY
05262 oflags |= O_BINARY;
05263 #endif
05264 if (!has_enc)
05265 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
05266 }
05267 #if DEFAULT_TEXTMODE
05268 else if (NIL_P(vmode)) {
05269 fmode |= DEFAULT_TEXTMODE;
05270 }
05271 #endif
05272 if (!has_vmode) {
05273 v = rb_hash_aref(opthash, sym_mode);
05274 if (!NIL_P(v)) {
05275 if (!NIL_P(vmode)) {
05276 rb_raise(rb_eArgError, "mode specified twice");
05277 }
05278 has_vmode = 1;
05279 vmode = v;
05280 goto vmode_handle;
05281 }
05282 }
05283 v = rb_hash_aref(opthash, sym_perm);
05284 if (!NIL_P(v)) {
05285 if (vperm_p) {
05286 if (!NIL_P(*vperm_p)) {
05287 rb_raise(rb_eArgError, "perm specified twice");
05288 }
05289 *vperm_p = v;
05290 }
05291 else {
05292
05293 }
05294 }
05295 ecflags = (fmode & FMODE_READABLE) ?
05296 MODE_BTMODE(ECONV_DEFAULT_NEWLINE_DECORATOR,
05297 0, ECONV_UNIVERSAL_NEWLINE_DECORATOR) : 0;
05298 #ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
05299 ecflags |= (fmode & FMODE_WRITABLE) ?
05300 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
05301 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
05302 #endif
05303
05304 if (rb_io_extract_encoding_option(opthash, &enc, &enc2, &fmode)) {
05305 if (has_enc) {
05306 rb_raise(rb_eArgError, "encoding specified twice");
05307 }
05308 }
05309 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
05310 ecflags = rb_econv_prepare_options(opthash, &ecopts, ecflags);
05311 }
05312
05313 validate_enc_binmode(&fmode, ecflags, enc, enc2);
05314
05315 *vmode_p = vmode;
05316
05317 *oflags_p = oflags;
05318 *fmode_p = fmode;
05319 convconfig_p->enc = enc;
05320 convconfig_p->enc2 = enc2;
05321 convconfig_p->ecflags = ecflags;
05322 convconfig_p->ecopts = ecopts;
05323 }
05324
05325 struct sysopen_struct {
05326 VALUE fname;
05327 int oflags;
05328 mode_t perm;
05329 };
05330
05331 static void *
05332 sysopen_func(void *ptr)
05333 {
05334 const struct sysopen_struct *data = ptr;
05335 const char *fname = RSTRING_PTR(data->fname);
05336 return (void *)(VALUE)rb_cloexec_open(fname, data->oflags, data->perm);
05337 }
05338
05339 static inline int
05340 rb_sysopen_internal(struct sysopen_struct *data)
05341 {
05342 int fd;
05343 fd = (int)(VALUE)rb_thread_call_without_gvl(sysopen_func, data, RUBY_UBF_IO, 0);
05344 if (0 <= fd)
05345 rb_update_max_fd(fd);
05346 return fd;
05347 }
05348
05349 static int
05350 rb_sysopen(VALUE fname, int oflags, mode_t perm)
05351 {
05352 int fd;
05353 struct sysopen_struct data;
05354
05355 data.fname = rb_str_encode_ospath(fname);
05356 data.oflags = oflags;
05357 data.perm = perm;
05358
05359 fd = rb_sysopen_internal(&data);
05360 if (fd < 0) {
05361 if (errno == EMFILE || errno == ENFILE) {
05362 rb_gc();
05363 fd = rb_sysopen_internal(&data);
05364 }
05365 if (fd < 0) {
05366 rb_sys_fail_path(fname);
05367 }
05368 }
05369 return fd;
05370 }
05371
05372 FILE *
05373 rb_fdopen(int fd, const char *modestr)
05374 {
05375 FILE *file;
05376
05377 #if defined(__sun)
05378 errno = 0;
05379 #endif
05380 file = fdopen(fd, modestr);
05381 if (!file) {
05382 if (
05383 #if defined(__sun)
05384 errno == 0 ||
05385 #endif
05386 errno == EMFILE || errno == ENFILE) {
05387 rb_gc();
05388 #if defined(__sun)
05389 errno = 0;
05390 #endif
05391 file = fdopen(fd, modestr);
05392 }
05393 if (!file) {
05394 #ifdef _WIN32
05395 if (errno == 0) errno = EINVAL;
05396 #elif defined(__sun)
05397 if (errno == 0) errno = EMFILE;
05398 #endif
05399 rb_sys_fail(0);
05400 }
05401 }
05402
05403
05404 #ifdef USE_SETVBUF
05405 if (setvbuf(file, NULL, _IOFBF, 0) != 0)
05406 rb_warn("setvbuf() can't be honoured (fd=%d)", fd);
05407 #endif
05408 return file;
05409 }
05410
05411 static void
05412 io_check_tty(rb_io_t *fptr)
05413 {
05414 if (isatty(fptr->fd))
05415 fptr->mode |= FMODE_TTY|FMODE_DUPLEX;
05416 }
05417
05418 static VALUE rb_io_internal_encoding(VALUE);
05419 static void io_encoding_set(rb_io_t *, VALUE, VALUE, VALUE);
05420
05421 static int
05422 io_strip_bom(VALUE io)
05423 {
05424 VALUE b1, b2, b3, b4;
05425
05426 if (NIL_P(b1 = rb_io_getbyte(io))) return 0;
05427 switch (b1) {
05428 case INT2FIX(0xEF):
05429 if (NIL_P(b2 = rb_io_getbyte(io))) break;
05430 if (b2 == INT2FIX(0xBB) && !NIL_P(b3 = rb_io_getbyte(io))) {
05431 if (b3 == INT2FIX(0xBF)) {
05432 return rb_utf8_encindex();
05433 }
05434 rb_io_ungetbyte(io, b3);
05435 }
05436 rb_io_ungetbyte(io, b2);
05437 break;
05438
05439 case INT2FIX(0xFE):
05440 if (NIL_P(b2 = rb_io_getbyte(io))) break;
05441 if (b2 == INT2FIX(0xFF)) {
05442 return ENCINDEX_UTF_16BE;
05443 }
05444 rb_io_ungetbyte(io, b2);
05445 break;
05446
05447 case INT2FIX(0xFF):
05448 if (NIL_P(b2 = rb_io_getbyte(io))) break;
05449 if (b2 == INT2FIX(0xFE)) {
05450 b3 = rb_io_getbyte(io);
05451 if (b3 == INT2FIX(0) && !NIL_P(b4 = rb_io_getbyte(io))) {
05452 if (b4 == INT2FIX(0)) {
05453 return ENCINDEX_UTF_32LE;
05454 }
05455 rb_io_ungetbyte(io, b4);
05456 rb_io_ungetbyte(io, b3);
05457 }
05458 else {
05459 rb_io_ungetbyte(io, b3);
05460 return ENCINDEX_UTF_16LE;
05461 }
05462 }
05463 rb_io_ungetbyte(io, b2);
05464 break;
05465
05466 case INT2FIX(0):
05467 if (NIL_P(b2 = rb_io_getbyte(io))) break;
05468 if (b2 == INT2FIX(0) && !NIL_P(b3 = rb_io_getbyte(io))) {
05469 if (b3 == INT2FIX(0xFE) && !NIL_P(b4 = rb_io_getbyte(io))) {
05470 if (b4 == INT2FIX(0xFF)) {
05471 return ENCINDEX_UTF_32BE;
05472 }
05473 rb_io_ungetbyte(io, b4);
05474 }
05475 rb_io_ungetbyte(io, b3);
05476 }
05477 rb_io_ungetbyte(io, b2);
05478 break;
05479 }
05480 rb_io_ungetbyte(io, b1);
05481 return 0;
05482 }
05483
05484 static void
05485 io_set_encoding_by_bom(VALUE io)
05486 {
05487 int idx = io_strip_bom(io);
05488 rb_io_t *fptr;
05489
05490 GetOpenFile(io, fptr);
05491 if (idx) {
05492 io_encoding_set(fptr, rb_enc_from_encoding(rb_enc_from_index(idx)),
05493 rb_io_internal_encoding(io), Qnil);
05494 }
05495 else {
05496 fptr->encs.enc2 = NULL;
05497 }
05498 }
05499
05500 static VALUE
05501 rb_file_open_generic(VALUE io, VALUE filename, int oflags, int fmode, convconfig_t *convconfig, mode_t perm)
05502 {
05503 rb_io_t *fptr;
05504 convconfig_t cc;
05505 if (!convconfig) {
05506
05507 rb_io_ext_int_to_encs(NULL, NULL, &cc.enc, &cc.enc2, fmode);
05508 cc.ecflags = 0;
05509 cc.ecopts = Qnil;
05510 convconfig = &cc;
05511 }
05512 validate_enc_binmode(&fmode, convconfig->ecflags,
05513 convconfig->enc, convconfig->enc2);
05514
05515 MakeOpenFile(io, fptr);
05516 fptr->mode = fmode;
05517 fptr->encs = *convconfig;
05518 fptr->pathv = rb_str_new_frozen(filename);
05519 fptr->fd = rb_sysopen(fptr->pathv, oflags, perm);
05520 io_check_tty(fptr);
05521 if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
05522
05523 return io;
05524 }
05525
05526 static VALUE
05527 rb_file_open_internal(VALUE io, VALUE filename, const char *modestr)
05528 {
05529 int fmode = rb_io_modestr_fmode(modestr);
05530 const char *p = strchr(modestr, ':');
05531 convconfig_t convconfig;
05532
05533 if (p) {
05534 parse_mode_enc(p+1, &convconfig.enc, &convconfig.enc2, &fmode);
05535 }
05536 else {
05537 rb_encoding *e;
05538
05539
05540 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
05541 rb_io_ext_int_to_encs(e, NULL, &convconfig.enc, &convconfig.enc2, fmode);
05542 convconfig.ecflags = 0;
05543 convconfig.ecopts = Qnil;
05544 }
05545
05546 return rb_file_open_generic(io, filename,
05547 rb_io_fmode_oflags(fmode),
05548 fmode,
05549 &convconfig,
05550 0666);
05551 }
05552
05553 VALUE
05554 rb_file_open_str(VALUE fname, const char *modestr)
05555 {
05556 FilePathValue(fname);
05557 return rb_file_open_internal(io_alloc(rb_cFile), fname, modestr);
05558 }
05559
05560 VALUE
05561 rb_file_open(const char *fname, const char *modestr)
05562 {
05563 return rb_file_open_internal(io_alloc(rb_cFile), rb_str_new_cstr(fname), modestr);
05564 }
05565
05566 #if defined(__CYGWIN__) || !defined(HAVE_FORK)
05567 static struct pipe_list {
05568 rb_io_t *fptr;
05569 struct pipe_list *next;
05570 } *pipe_list;
05571
05572 static void
05573 pipe_add_fptr(rb_io_t *fptr)
05574 {
05575 struct pipe_list *list;
05576
05577 list = ALLOC(struct pipe_list);
05578 list->fptr = fptr;
05579 list->next = pipe_list;
05580 pipe_list = list;
05581 }
05582
05583 static void
05584 pipe_del_fptr(rb_io_t *fptr)
05585 {
05586 struct pipe_list *list = pipe_list;
05587 struct pipe_list *tmp;
05588
05589 if (list->fptr == fptr) {
05590 pipe_list = list->next;
05591 free(list);
05592 return;
05593 }
05594
05595 while (list->next) {
05596 if (list->next->fptr == fptr) {
05597 tmp = list->next;
05598 list->next = list->next->next;
05599 free(tmp);
05600 return;
05601 }
05602 list = list->next;
05603 }
05604 }
05605
05606 static void
05607 pipe_atexit(void)
05608 {
05609 struct pipe_list *list = pipe_list;
05610 struct pipe_list *tmp;
05611
05612 while (list) {
05613 tmp = list->next;
05614 rb_io_fptr_finalize(list->fptr);
05615 list = tmp;
05616 }
05617 }
05618
05619 static void
05620 pipe_finalize(rb_io_t *fptr, int noraise)
05621 {
05622 #if !defined(HAVE_FORK) && !defined(_WIN32)
05623 int status = 0;
05624 if (fptr->stdio_file) {
05625 status = pclose(fptr->stdio_file);
05626 }
05627 fptr->fd = -1;
05628 fptr->stdio_file = 0;
05629 rb_last_status_set(status, fptr->pid);
05630 #else
05631 fptr_finalize(fptr, noraise);
05632 #endif
05633 pipe_del_fptr(fptr);
05634 }
05635 #endif
05636
05637 void
05638 rb_io_synchronized(rb_io_t *fptr)
05639 {
05640 rb_io_check_initialized(fptr);
05641 fptr->mode |= FMODE_SYNC;
05642 }
05643
05644 void
05645 rb_io_unbuffered(rb_io_t *fptr)
05646 {
05647 rb_io_synchronized(fptr);
05648 }
05649
05650 int
05651 rb_pipe(int *pipes)
05652 {
05653 int ret;
05654 ret = rb_cloexec_pipe(pipes);
05655 if (ret == -1) {
05656 if (errno == EMFILE || errno == ENFILE) {
05657 rb_gc();
05658 ret = rb_cloexec_pipe(pipes);
05659 }
05660 }
05661 if (ret == 0) {
05662 rb_update_max_fd(pipes[0]);
05663 rb_update_max_fd(pipes[1]);
05664 }
05665 return ret;
05666 }
05667
05668 #ifdef _WIN32
05669 #define HAVE_SPAWNV 1
05670 #define spawnv(mode, cmd, args) rb_w32_uaspawn((mode), (cmd), (args))
05671 #define spawn(mode, cmd) rb_w32_uspawn((mode), (cmd), 0)
05672 #endif
05673
05674 #if defined(HAVE_FORK) || defined(HAVE_SPAWNV)
05675 struct popen_arg {
05676 VALUE execarg_obj;
05677 struct rb_execarg *eargp;
05678 int modef;
05679 int pair[2];
05680 int write_pair[2];
05681 };
05682 #endif
05683
05684 #ifdef HAVE_FORK
05685 static void
05686 popen_redirect(struct popen_arg *p)
05687 {
05688 if ((p->modef & FMODE_READABLE) && (p->modef & FMODE_WRITABLE)) {
05689 close(p->write_pair[1]);
05690 if (p->write_pair[0] != 0) {
05691 dup2(p->write_pair[0], 0);
05692 close(p->write_pair[0]);
05693 }
05694 close(p->pair[0]);
05695 if (p->pair[1] != 1) {
05696 dup2(p->pair[1], 1);
05697 close(p->pair[1]);
05698 }
05699 }
05700 else if (p->modef & FMODE_READABLE) {
05701 close(p->pair[0]);
05702 if (p->pair[1] != 1) {
05703 dup2(p->pair[1], 1);
05704 close(p->pair[1]);
05705 }
05706 }
05707 else {
05708 close(p->pair[1]);
05709 if (p->pair[0] != 0) {
05710 dup2(p->pair[0], 0);
05711 close(p->pair[0]);
05712 }
05713 }
05714 }
05715
05716 #if defined(__linux__)
05717
05718
05719
05720
05721
05722
05723
05724
05725
05726 static int
05727 linux_get_maxfd(void)
05728 {
05729 int fd;
05730 char buf[4096], *p, *np, *e;
05731 ssize_t ss;
05732 fd = rb_cloexec_open("/proc/self/status", O_RDONLY|O_NOCTTY, 0);
05733 if (fd == -1) return -1;
05734 ss = read(fd, buf, sizeof(buf));
05735 if (ss == -1) goto err;
05736 p = buf;
05737 e = buf + ss;
05738 while ((int)sizeof("FDSize:\t0\n")-1 <= e-p &&
05739 (np = memchr(p, '\n', e-p)) != NULL) {
05740 if (memcmp(p, "FDSize:", sizeof("FDSize:")-1) == 0) {
05741 int fdsize;
05742 p += sizeof("FDSize:")-1;
05743 *np = '\0';
05744 fdsize = (int)ruby_strtoul(p, (char **)NULL, 10);
05745 close(fd);
05746 return fdsize;
05747 }
05748 p = np+1;
05749 }
05750
05751
05752 err:
05753 close(fd);
05754 return -1;
05755 }
05756 #endif
05757
05758
05759 void
05760 rb_close_before_exec(int lowfd, int maxhint, VALUE noclose_fds)
05761 {
05762 int fd, ret;
05763 int max = (int)max_file_descriptor;
05764 #ifdef F_MAXFD
05765
05766 ret = fcntl(0, F_MAXFD);
05767 if (ret != -1)
05768 maxhint = max = ret;
05769 #elif defined(__linux__)
05770 ret = linux_get_maxfd();
05771 if (maxhint < ret)
05772 maxhint = ret;
05773
05774 #endif
05775 if (max < maxhint)
05776 max = maxhint;
05777 for (fd = lowfd; fd <= max; fd++) {
05778 if (!NIL_P(noclose_fds) &&
05779 RTEST(rb_hash_lookup(noclose_fds, INT2FIX(fd))))
05780 continue;
05781 ret = fcntl(fd, F_GETFD);
05782 if (ret != -1 && !(ret & FD_CLOEXEC)) {
05783 fcntl(fd, F_SETFD, ret|FD_CLOEXEC);
05784 }
05785 #define CONTIGUOUS_CLOSED_FDS 20
05786 if (ret != -1) {
05787 if (max < fd + CONTIGUOUS_CLOSED_FDS)
05788 max = fd + CONTIGUOUS_CLOSED_FDS;
05789 }
05790 }
05791 }
05792
05793 static int
05794 popen_exec(void *pp, char *errmsg, size_t errmsg_len)
05795 {
05796 struct popen_arg *p = (struct popen_arg*)pp;
05797
05798 return rb_exec_async_signal_safe(p->eargp, errmsg, errmsg_len);
05799 }
05800 #endif
05801
05802 static VALUE
05803 pipe_open(VALUE execarg_obj, const char *modestr, int fmode, convconfig_t *convconfig)
05804 {
05805 struct rb_execarg *eargp = NIL_P(execarg_obj) ? NULL : rb_execarg_get(execarg_obj);
05806 VALUE prog = eargp ? (eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name) : Qfalse ;
05807 rb_pid_t pid = 0;
05808 rb_io_t *fptr;
05809 VALUE port;
05810 rb_io_t *write_fptr;
05811 VALUE write_port;
05812 #if defined(HAVE_FORK)
05813 int status;
05814 char errmsg[80] = { '\0' };
05815 #endif
05816 #if defined(HAVE_FORK) || defined(HAVE_SPAWNV)
05817 struct popen_arg arg;
05818 int e = 0;
05819 #endif
05820 #if defined(HAVE_SPAWNV)
05821 # if defined(HAVE_SPAWNVE)
05822 # define DO_SPAWN(cmd, args, envp) ((args) ? \
05823 spawnve(P_NOWAIT, (cmd), (args), (envp)) : \
05824 spawne(P_NOWAIT, (cmd), (envp)))
05825 # else
05826 # define DO_SPAWN(cmd, args, envp) ((args) ? \
05827 spawnv(P_NOWAIT, (cmd), (args)) : \
05828 spawn(P_NOWAIT, (cmd)))
05829 # endif
05830 # if !defined(HAVE_FORK)
05831 char **args = NULL;
05832 # if defined(HAVE_SPAWNVE)
05833 char **envp = NULL;
05834 # endif
05835 # endif
05836 #endif
05837 #if !defined(HAVE_FORK)
05838 struct rb_execarg sarg, *sargp = &sarg;
05839 #endif
05840 FILE *fp = 0;
05841 int fd = -1;
05842 int write_fd = -1;
05843 #if !defined(HAVE_FORK)
05844 const char *cmd = 0;
05845 #if !defined(HAVE_SPAWNV)
05846 int argc;
05847 VALUE *argv;
05848 #endif
05849
05850 if (prog)
05851 cmd = StringValueCStr(prog);
05852 #endif
05853
05854 #if defined(HAVE_FORK) || defined(HAVE_SPAWNV)
05855 arg.execarg_obj = execarg_obj;
05856 arg.eargp = eargp;
05857 arg.modef = fmode;
05858 arg.pair[0] = arg.pair[1] = -1;
05859 arg.write_pair[0] = arg.write_pair[1] = -1;
05860 # if !defined(HAVE_FORK)
05861 if (eargp && !eargp->use_shell) {
05862 args = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
05863 }
05864 # endif
05865 switch (fmode & (FMODE_READABLE|FMODE_WRITABLE)) {
05866 case FMODE_READABLE|FMODE_WRITABLE:
05867 if (rb_pipe(arg.write_pair) < 0)
05868 rb_sys_fail_str(prog);
05869 if (rb_pipe(arg.pair) < 0) {
05870 int e = errno;
05871 close(arg.write_pair[0]);
05872 close(arg.write_pair[1]);
05873 errno = e;
05874 rb_sys_fail_str(prog);
05875 }
05876 if (eargp) {
05877 rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.write_pair[0]));
05878 rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
05879 }
05880 break;
05881 case FMODE_READABLE:
05882 if (rb_pipe(arg.pair) < 0)
05883 rb_sys_fail_str(prog);
05884 if (eargp)
05885 rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
05886 break;
05887 case FMODE_WRITABLE:
05888 if (rb_pipe(arg.pair) < 0)
05889 rb_sys_fail_str(prog);
05890 if (eargp)
05891 rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.pair[0]));
05892 break;
05893 default:
05894 rb_sys_fail_str(prog);
05895 }
05896 if (!NIL_P(execarg_obj)) {
05897 rb_execarg_fixup(execarg_obj);
05898 # if defined(HAVE_FORK)
05899 pid = rb_fork_async_signal_safe(&status, popen_exec, &arg, arg.eargp->redirect_fds, errmsg, sizeof(errmsg));
05900 # else
05901 rb_execarg_run_options(eargp, sargp, NULL, 0);
05902 # if defined(HAVE_SPAWNVE)
05903 if (eargp->envp_str) envp = (char **)RSTRING_PTR(eargp->envp_str);
05904 # endif
05905 while ((pid = DO_SPAWN(cmd, args, envp)) == -1) {
05906
05907 switch (e = errno) {
05908 case EAGAIN:
05909 # if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
05910 case EWOULDBLOCK:
05911 # endif
05912 rb_thread_sleep(1);
05913 continue;
05914 }
05915 break;
05916 }
05917 if (eargp)
05918 rb_execarg_run_options(sargp, NULL, NULL, 0);
05919 # endif
05920 }
05921 else {
05922 # if defined(HAVE_FORK)
05923 pid = rb_fork_ruby(&status);
05924 if (pid == 0) {
05925 rb_thread_atfork();
05926 popen_redirect(&arg);
05927 rb_io_synchronized(RFILE(orig_stdout)->fptr);
05928 rb_io_synchronized(RFILE(orig_stderr)->fptr);
05929 return Qnil;
05930 }
05931 # else
05932 rb_notimplement();
05933 # endif
05934 }
05935
05936
05937 if (pid == -1) {
05938 # if defined(HAVE_FORK)
05939 e = errno;
05940 # endif
05941 close(arg.pair[0]);
05942 close(arg.pair[1]);
05943 if ((fmode & (FMODE_READABLE|FMODE_WRITABLE)) == (FMODE_READABLE|FMODE_WRITABLE)) {
05944 close(arg.write_pair[0]);
05945 close(arg.write_pair[1]);
05946 }
05947 errno = e;
05948 # if defined(HAVE_FORK)
05949 if (errmsg[0])
05950 rb_sys_fail(errmsg);
05951 # endif
05952 rb_sys_fail_str(prog);
05953 }
05954 if ((fmode & FMODE_READABLE) && (fmode & FMODE_WRITABLE)) {
05955 close(arg.pair[1]);
05956 fd = arg.pair[0];
05957 close(arg.write_pair[0]);
05958 write_fd = arg.write_pair[1];
05959 }
05960 else if (fmode & FMODE_READABLE) {
05961 close(arg.pair[1]);
05962 fd = arg.pair[0];
05963 }
05964 else {
05965 close(arg.pair[0]);
05966 fd = arg.pair[1];
05967 }
05968 #else
05969 if (argc) {
05970 prog = rb_ary_join(rb_ary_new4(argc, argv), rb_str_new2(" "));
05971 cmd = StringValueCStr(prog);
05972 }
05973 if (!NIL_P(execarg_obj)) {
05974 rb_execarg_fixup(execarg_obj);
05975 rb_execarg_run_options(eargp, sargp, NULL, 0);
05976 }
05977 fp = popen(cmd, modestr);
05978 if (eargp)
05979 rb_execarg_run_options(sargp, NULL, NULL, 0);
05980 if (!fp) rb_sys_fail_path(prog);
05981 fd = fileno(fp);
05982 #endif
05983
05984 port = io_alloc(rb_cIO);
05985 MakeOpenFile(port, fptr);
05986 fptr->fd = fd;
05987 fptr->stdio_file = fp;
05988 fptr->mode = fmode | FMODE_SYNC|FMODE_DUPLEX;
05989 if (convconfig) {
05990 fptr->encs = *convconfig;
05991 #if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)
05992 if (fptr->encs.ecflags & ECONV_DEFAULT_NEWLINE_DECORATOR) {
05993 fptr->encs.ecflags |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;
05994 }
05995 #endif
05996 }
05997 else {
05998 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
05999 fptr->encs.ecflags |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;
06000 }
06001 #ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
06002 if (NEED_NEWLINE_DECORATOR_ON_WRITE(fptr)) {
06003 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
06004 }
06005 #endif
06006 }
06007 fptr->pid = pid;
06008
06009 if (0 <= write_fd) {
06010 write_port = io_alloc(rb_cIO);
06011 MakeOpenFile(write_port, write_fptr);
06012 write_fptr->fd = write_fd;
06013 write_fptr->mode = (fmode & ~FMODE_READABLE)| FMODE_SYNC|FMODE_DUPLEX;
06014 fptr->mode &= ~FMODE_WRITABLE;
06015 fptr->tied_io_for_writing = write_port;
06016 rb_ivar_set(port, rb_intern("@tied_io_for_writing"), write_port);
06017 }
06018
06019 #if defined (__CYGWIN__) || !defined(HAVE_FORK)
06020 fptr->finalize = pipe_finalize;
06021 pipe_add_fptr(fptr);
06022 #endif
06023 return port;
06024 }
06025
06026 static int
06027 is_popen_fork(VALUE prog)
06028 {
06029 if (RSTRING_LEN(prog) == 1 && RSTRING_PTR(prog)[0] == '-') {
06030 #if !defined(HAVE_FORK)
06031 rb_raise(rb_eNotImpError,
06032 "fork() function is unimplemented on this machine");
06033 #else
06034 return TRUE;
06035 #endif
06036 }
06037 return FALSE;
06038 }
06039
06040 static VALUE
06041 pipe_open_s(VALUE prog, const char *modestr, int fmode, convconfig_t *convconfig)
06042 {
06043 int argc = 1;
06044 VALUE *argv = &prog;
06045 VALUE execarg_obj = Qnil;
06046
06047 if (!is_popen_fork(prog))
06048 execarg_obj = rb_execarg_new(argc, argv, TRUE);
06049 return pipe_open(execarg_obj, modestr, fmode, convconfig);
06050 }
06051
06052
06053
06054
06055
06056
06057
06058
06059
06060
06061
06062
06063
06064
06065
06066
06067
06068
06069
06070
06071
06072
06073
06074
06075
06076
06077
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 static VALUE
06141 rb_io_s_popen(int argc, VALUE *argv, VALUE klass)
06142 {
06143 const char *modestr;
06144 VALUE pname, pmode = Qnil, port, tmp, opt = Qnil, env = Qnil, execarg_obj = Qnil;
06145 int oflags, fmode;
06146 convconfig_t convconfig;
06147
06148 if (argc > 1 && !NIL_P(opt = rb_check_hash_type(argv[argc-1]))) --argc;
06149 if (argc > 1 && !NIL_P(env = rb_check_hash_type(argv[0]))) --argc, ++argv;
06150 switch (argc) {
06151 case 2:
06152 pmode = argv[1];
06153 case 1:
06154 pname = argv[0];
06155 break;
06156 default:
06157 {
06158 int ex = !NIL_P(opt);
06159 rb_error_arity(argc + ex, 1 + ex, 2 + ex);
06160 }
06161 }
06162
06163 tmp = rb_check_array_type(pname);
06164 if (!NIL_P(tmp)) {
06165 long len = RARRAY_LEN(tmp);
06166 #if SIZEOF_LONG > SIZEOF_INT
06167 if (len > INT_MAX) {
06168 rb_raise(rb_eArgError, "too many arguments");
06169 }
06170 #endif
06171 tmp = rb_ary_dup(tmp);
06172 RBASIC_CLEAR_CLASS(tmp);
06173 execarg_obj = rb_execarg_new((int)len, RARRAY_PTR(tmp), FALSE);
06174 rb_ary_clear(tmp);
06175 }
06176 else {
06177 SafeStringValue(pname);
06178 execarg_obj = Qnil;
06179 if (!is_popen_fork(pname))
06180 execarg_obj = rb_execarg_new(1, &pname, TRUE);
06181 }
06182 if (!NIL_P(execarg_obj)) {
06183 if (!NIL_P(opt))
06184 opt = rb_execarg_extract_options(execarg_obj, opt);
06185 if (!NIL_P(env))
06186 rb_execarg_setenv(execarg_obj, env);
06187 }
06188 rb_io_extract_modeenc(&pmode, 0, opt, &oflags, &fmode, &convconfig);
06189 modestr = rb_io_oflags_modestr(oflags);
06190
06191 port = pipe_open(execarg_obj, modestr, fmode, &convconfig);
06192 if (NIL_P(port)) {
06193
06194 if (rb_block_given_p()) {
06195 rb_yield(Qnil);
06196 rb_io_flush(rb_stdout);
06197 rb_io_flush(rb_stderr);
06198 _exit(0);
06199 }
06200 return Qnil;
06201 }
06202 RBASIC_SET_CLASS(port, klass);
06203 if (rb_block_given_p()) {
06204 return rb_ensure(rb_yield, port, io_close, port);
06205 }
06206 return port;
06207 }
06208
06209 static void
06210 rb_scan_open_args(int argc, const VALUE *argv,
06211 VALUE *fname_p, int *oflags_p, int *fmode_p,
06212 convconfig_t *convconfig_p, mode_t *perm_p)
06213 {
06214 VALUE opt, fname, vmode, vperm;
06215 int oflags, fmode;
06216 mode_t perm;
06217
06218 argc = rb_scan_args(argc, argv, "12:", &fname, &vmode, &vperm, &opt);
06219 FilePathValue(fname);
06220
06221 rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, convconfig_p);
06222
06223 perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
06224
06225 *fname_p = fname;
06226 *oflags_p = oflags;
06227 *fmode_p = fmode;
06228 *perm_p = perm;
06229 }
06230
06231 static VALUE
06232 rb_open_file(int argc, const VALUE *argv, VALUE io)
06233 {
06234 VALUE fname;
06235 int oflags, fmode;
06236 convconfig_t convconfig;
06237 mode_t perm;
06238
06239 rb_scan_open_args(argc, argv, &fname, &oflags, &fmode, &convconfig, &perm);
06240 rb_file_open_generic(io, fname, oflags, fmode, &convconfig, perm);
06241
06242 return io;
06243 }
06244
06245
06246
06247
06248
06249
06250
06251
06252
06253
06254
06255
06256
06257
06258
06259
06260
06261
06262
06263
06264
06265
06266
06267
06268
06269
06270
06271
06272
06273
06274
06275
06276
06277
06278
06279
06280
06281
06282 static VALUE
06283 rb_io_s_open(int argc, VALUE *argv, VALUE klass)
06284 {
06285 VALUE io = rb_class_new_instance(argc, argv, klass);
06286
06287 if (rb_block_given_p()) {
06288 return rb_ensure(rb_yield, io, io_close, io);
06289 }
06290
06291 return io;
06292 }
06293
06294
06295
06296
06297
06298
06299
06300
06301
06302
06303
06304 static VALUE
06305 rb_io_s_sysopen(int argc, VALUE *argv)
06306 {
06307 VALUE fname, vmode, vperm;
06308 VALUE intmode;
06309 int oflags, fd;
06310 mode_t perm;
06311
06312 rb_scan_args(argc, argv, "12", &fname, &vmode, &vperm);
06313 FilePathValue(fname);
06314
06315 if (NIL_P(vmode))
06316 oflags = O_RDONLY;
06317 else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int")))
06318 oflags = NUM2INT(intmode);
06319 else {
06320 SafeStringValue(vmode);
06321 oflags = rb_io_modestr_oflags(StringValueCStr(vmode));
06322 }
06323 if (NIL_P(vperm)) perm = 0666;
06324 else perm = NUM2MODET(vperm);
06325
06326 RB_GC_GUARD(fname) = rb_str_new4(fname);
06327 fd = rb_sysopen(fname, oflags, perm);
06328 return INT2NUM(fd);
06329 }
06330
06331 static VALUE
06332 check_pipe_command(VALUE filename_or_command)
06333 {
06334 char *s = RSTRING_PTR(filename_or_command);
06335 long l = RSTRING_LEN(filename_or_command);
06336 char *e = s + l;
06337 int chlen;
06338
06339 if (rb_enc_ascget(s, e, &chlen, rb_enc_get(filename_or_command)) == '|') {
06340 VALUE cmd = rb_str_new(s+chlen, l-chlen);
06341 OBJ_INFECT(cmd, filename_or_command);
06342 return cmd;
06343 }
06344 return Qnil;
06345 }
06346
06347
06348
06349
06350
06351
06352
06353
06354
06355
06356
06357
06358
06359
06360
06361
06362
06363
06364
06365
06366
06367
06368
06369
06370
06371
06372
06373
06374
06375
06376
06377
06378
06379
06380
06381
06382
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 static VALUE
06446 rb_f_open(int argc, VALUE *argv)
06447 {
06448 ID to_open = 0;
06449 int redirect = FALSE;
06450
06451 if (argc >= 1) {
06452 CONST_ID(to_open, "to_open");
06453 if (rb_respond_to(argv[0], to_open)) {
06454 redirect = TRUE;
06455 }
06456 else {
06457 VALUE tmp = argv[0];
06458 FilePathValue(tmp);
06459 if (NIL_P(tmp)) {
06460 redirect = TRUE;
06461 }
06462 else {
06463 VALUE cmd = check_pipe_command(tmp);
06464 if (!NIL_P(cmd)) {
06465 argv[0] = cmd;
06466 return rb_io_s_popen(argc, argv, rb_cIO);
06467 }
06468 }
06469 }
06470 }
06471 if (redirect) {
06472 VALUE io = rb_funcall2(argv[0], to_open, argc-1, argv+1);
06473
06474 if (rb_block_given_p()) {
06475 return rb_ensure(rb_yield, io, io_close, io);
06476 }
06477 return io;
06478 }
06479 return rb_io_s_open(argc, argv, rb_cFile);
06480 }
06481
06482 static VALUE
06483 rb_io_open(VALUE filename, VALUE vmode, VALUE vperm, VALUE opt)
06484 {
06485 VALUE cmd;
06486 int oflags, fmode;
06487 convconfig_t convconfig;
06488 mode_t perm;
06489
06490 rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, &convconfig);
06491 perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
06492
06493 if (!NIL_P(cmd = check_pipe_command(filename))) {
06494 return pipe_open_s(cmd, rb_io_oflags_modestr(oflags), fmode, &convconfig);
06495 }
06496 else {
06497 return rb_file_open_generic(io_alloc(rb_cFile), filename,
06498 oflags, fmode, &convconfig, perm);
06499 }
06500 }
06501
06502 static VALUE
06503 rb_io_open_with_args(int argc, const VALUE *argv)
06504 {
06505 VALUE io;
06506
06507 io = io_alloc(rb_cFile);
06508 rb_open_file(argc, argv, io);
06509 return io;
06510 }
06511
06512 static VALUE
06513 io_reopen(VALUE io, VALUE nfile)
06514 {
06515 rb_io_t *fptr, *orig;
06516 int fd, fd2;
06517 off_t pos = 0;
06518
06519 nfile = rb_io_get_io(nfile);
06520 GetOpenFile(io, fptr);
06521 GetOpenFile(nfile, orig);
06522
06523 if (fptr == orig) return io;
06524 if (IS_PREP_STDIO(fptr)) {
06525 if ((fptr->stdio_file == stdin && !(orig->mode & FMODE_READABLE)) ||
06526 (fptr->stdio_file == stdout && !(orig->mode & FMODE_WRITABLE)) ||
06527 (fptr->stdio_file == stderr && !(orig->mode & FMODE_WRITABLE))) {
06528 rb_raise(rb_eArgError,
06529 "%s can't change access mode from \"%s\" to \"%s\"",
06530 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
06531 rb_io_fmode_modestr(orig->mode));
06532 }
06533 }
06534 if (fptr->mode & FMODE_WRITABLE) {
06535 if (io_fflush(fptr) < 0)
06536 rb_sys_fail(0);
06537 }
06538 else {
06539 io_tell(fptr);
06540 }
06541 if (orig->mode & FMODE_READABLE) {
06542 pos = io_tell(orig);
06543 }
06544 if (orig->mode & FMODE_WRITABLE) {
06545 if (io_fflush(orig) < 0)
06546 rb_sys_fail(0);
06547 }
06548
06549
06550 fptr->mode = orig->mode | (fptr->mode & FMODE_PREP);
06551 fptr->pid = orig->pid;
06552 fptr->lineno = orig->lineno;
06553 if (RTEST(orig->pathv)) fptr->pathv = orig->pathv;
06554 else if (!IS_PREP_STDIO(fptr)) fptr->pathv = Qnil;
06555 fptr->finalize = orig->finalize;
06556 #if defined (__CYGWIN__) || !defined(HAVE_FORK)
06557 if (fptr->finalize == pipe_finalize)
06558 pipe_add_fptr(fptr);
06559 #endif
06560
06561 fd = fptr->fd;
06562 fd2 = orig->fd;
06563 if (fd != fd2) {
06564 if (IS_PREP_STDIO(fptr) || fd <= 2 || !fptr->stdio_file) {
06565
06566 if (rb_cloexec_dup2(fd2, fd) < 0)
06567 rb_sys_fail_path(orig->pathv);
06568 rb_update_max_fd(fd);
06569 }
06570 else {
06571 fclose(fptr->stdio_file);
06572 fptr->stdio_file = 0;
06573 fptr->fd = -1;
06574 if (rb_cloexec_dup2(fd2, fd) < 0)
06575 rb_sys_fail_path(orig->pathv);
06576 rb_update_max_fd(fd);
06577 fptr->fd = fd;
06578 }
06579 rb_thread_fd_close(fd);
06580 if ((orig->mode & FMODE_READABLE) && pos >= 0) {
06581 if (io_seek(fptr, pos, SEEK_SET) < 0 && errno) {
06582 rb_sys_fail_path(fptr->pathv);
06583 }
06584 if (io_seek(orig, pos, SEEK_SET) < 0 && errno) {
06585 rb_sys_fail_path(orig->pathv);
06586 }
06587 }
06588 }
06589
06590 if (fptr->mode & FMODE_BINMODE) {
06591 rb_io_binmode(io);
06592 }
06593
06594 RBASIC_SET_CLASS(io, rb_obj_class(nfile));
06595 return io;
06596 }
06597
06598
06599
06600
06601
06602
06603
06604
06605
06606
06607
06608
06609
06610
06611
06612
06613
06614 static VALUE
06615 rb_io_reopen(int argc, VALUE *argv, VALUE file)
06616 {
06617 VALUE fname, nmode, opt;
06618 int oflags;
06619 rb_io_t *fptr;
06620
06621 if (rb_scan_args(argc, argv, "11:", &fname, &nmode, &opt) == 1) {
06622 VALUE tmp = rb_io_check_io(fname);
06623 if (!NIL_P(tmp)) {
06624 return io_reopen(file, tmp);
06625 }
06626 }
06627
06628 FilePathValue(fname);
06629 rb_io_taint_check(file);
06630 fptr = RFILE(file)->fptr;
06631 if (!fptr) {
06632 fptr = RFILE(file)->fptr = ALLOC(rb_io_t);
06633 MEMZERO(fptr, rb_io_t, 1);
06634 }
06635
06636 if (!NIL_P(nmode) || !NIL_P(opt)) {
06637 int fmode;
06638 convconfig_t convconfig;
06639
06640 rb_io_extract_modeenc(&nmode, 0, opt, &oflags, &fmode, &convconfig);
06641 if (IS_PREP_STDIO(fptr) &&
06642 ((fptr->mode & FMODE_READWRITE) & (fmode & FMODE_READWRITE)) !=
06643 (fptr->mode & FMODE_READWRITE)) {
06644 rb_raise(rb_eArgError,
06645 "%s can't change access mode from \"%s\" to \"%s\"",
06646 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
06647 rb_io_fmode_modestr(fmode));
06648 }
06649 fptr->mode = fmode;
06650 fptr->encs = convconfig;
06651 }
06652 else {
06653 oflags = rb_io_fmode_oflags(fptr->mode);
06654 }
06655
06656 fptr->pathv = rb_str_new_frozen(fname);
06657 if (fptr->fd < 0) {
06658 fptr->fd = rb_sysopen(fptr->pathv, oflags, 0666);
06659 fptr->stdio_file = 0;
06660 return file;
06661 }
06662
06663 if (fptr->mode & FMODE_WRITABLE) {
06664 if (io_fflush(fptr) < 0)
06665 rb_sys_fail(0);
06666 }
06667 fptr->rbuf.off = fptr->rbuf.len = 0;
06668
06669 if (fptr->stdio_file) {
06670 if (freopen(RSTRING_PTR(fptr->pathv), rb_io_oflags_modestr(oflags), fptr->stdio_file) == 0) {
06671 rb_sys_fail_path(fptr->pathv);
06672 }
06673 fptr->fd = fileno(fptr->stdio_file);
06674 rb_fd_fix_cloexec(fptr->fd);
06675 #ifdef USE_SETVBUF
06676 if (setvbuf(fptr->stdio_file, NULL, _IOFBF, 0) != 0)
06677 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
06678 #endif
06679 if (fptr->stdio_file == stderr) {
06680 if (setvbuf(fptr->stdio_file, NULL, _IONBF, BUFSIZ) != 0)
06681 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
06682 }
06683 else if (fptr->stdio_file == stdout && isatty(fptr->fd)) {
06684 if (setvbuf(fptr->stdio_file, NULL, _IOLBF, BUFSIZ) != 0)
06685 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
06686 }
06687 }
06688 else {
06689 int tmpfd = rb_sysopen(fptr->pathv, oflags, 0666);
06690 int err = 0;
06691 if (rb_cloexec_dup2(tmpfd, fptr->fd) < 0)
06692 err = errno;
06693 (void)close(tmpfd);
06694 if (err) {
06695 rb_syserr_fail_path(err, fptr->pathv);
06696 }
06697 }
06698
06699 return file;
06700 }
06701
06702
06703 static VALUE
06704 rb_io_init_copy(VALUE dest, VALUE io)
06705 {
06706 rb_io_t *fptr, *orig;
06707 int fd;
06708 VALUE write_io;
06709 off_t pos;
06710
06711 io = rb_io_get_io(io);
06712 if (!OBJ_INIT_COPY(dest, io)) return dest;
06713 GetOpenFile(io, orig);
06714 MakeOpenFile(dest, fptr);
06715
06716 rb_io_flush(io);
06717
06718
06719 fptr->mode = orig->mode & ~FMODE_PREP;
06720 fptr->encs = orig->encs;
06721 fptr->pid = orig->pid;
06722 fptr->lineno = orig->lineno;
06723 if (!NIL_P(orig->pathv)) fptr->pathv = orig->pathv;
06724 fptr->finalize = orig->finalize;
06725 #if defined (__CYGWIN__) || !defined(HAVE_FORK)
06726 if (fptr->finalize == pipe_finalize)
06727 pipe_add_fptr(fptr);
06728 #endif
06729
06730 fd = ruby_dup(orig->fd);
06731 fptr->fd = fd;
06732 pos = io_tell(orig);
06733 if (0 <= pos)
06734 io_seek(fptr, pos, SEEK_SET);
06735 if (fptr->mode & FMODE_BINMODE) {
06736 rb_io_binmode(dest);
06737 }
06738
06739 write_io = GetWriteIO(io);
06740 if (io != write_io) {
06741 write_io = rb_obj_dup(write_io);
06742 fptr->tied_io_for_writing = write_io;
06743 rb_ivar_set(dest, rb_intern("@tied_io_for_writing"), write_io);
06744 }
06745
06746 return dest;
06747 }
06748
06749
06750
06751
06752
06753
06754
06755
06756
06757
06758 VALUE
06759 rb_io_printf(int argc, VALUE *argv, VALUE out)
06760 {
06761 rb_io_write(out, rb_f_sprintf(argc, argv));
06762 return Qnil;
06763 }
06764
06765
06766
06767
06768
06769
06770
06771
06772
06773
06774
06775
06776 static VALUE
06777 rb_f_printf(int argc, VALUE *argv)
06778 {
06779 VALUE out;
06780
06781 if (argc == 0) return Qnil;
06782 if (RB_TYPE_P(argv[0], T_STRING)) {
06783 out = rb_stdout;
06784 }
06785 else {
06786 out = argv[0];
06787 argv++;
06788 argc--;
06789 }
06790 rb_io_write(out, rb_f_sprintf(argc, argv));
06791
06792 return Qnil;
06793 }
06794
06795
06796
06797
06798
06799
06800
06801
06802
06803
06804
06805
06806
06807
06808
06809
06810
06811
06812
06813
06814
06815
06816
06817 VALUE
06818 rb_io_print(int argc, VALUE *argv, VALUE out)
06819 {
06820 int i;
06821 VALUE line;
06822
06823
06824 if (argc == 0) {
06825 argc = 1;
06826 line = rb_lastline_get();
06827 argv = &line;
06828 }
06829 for (i=0; i<argc; i++) {
06830 if (!NIL_P(rb_output_fs) && i>0) {
06831 rb_io_write(out, rb_output_fs);
06832 }
06833 rb_io_write(out, argv[i]);
06834 }
06835 if (argc > 0 && !NIL_P(rb_output_rs)) {
06836 rb_io_write(out, rb_output_rs);
06837 }
06838
06839 return Qnil;
06840 }
06841
06842
06843
06844
06845
06846
06847
06848
06849
06850
06851
06852
06853
06854
06855
06856
06857
06858
06859
06860
06861
06862
06863
06864
06865 static VALUE
06866 rb_f_print(int argc, VALUE *argv)
06867 {
06868 rb_io_print(argc, argv, rb_stdout);
06869 return Qnil;
06870 }
06871
06872
06873
06874
06875
06876
06877
06878
06879
06880
06881
06882
06883
06884
06885
06886
06887
06888
06889
06890 static VALUE
06891 rb_io_putc(VALUE io, VALUE ch)
06892 {
06893 VALUE str;
06894 if (RB_TYPE_P(ch, T_STRING)) {
06895 str = rb_str_substr(ch, 0, 1);
06896 }
06897 else {
06898 char c = NUM2CHR(ch);
06899 str = rb_str_new(&c, 1);
06900 }
06901 rb_io_write(io, str);
06902 return ch;
06903 }
06904
06905
06906
06907
06908
06909
06910
06911
06912
06913
06914
06915
06916
06917 static VALUE
06918 rb_f_putc(VALUE recv, VALUE ch)
06919 {
06920 if (recv == rb_stdout) {
06921 return rb_io_putc(recv, ch);
06922 }
06923 return rb_funcall2(rb_stdout, rb_intern("putc"), 1, &ch);
06924 }
06925
06926
06927 static int
06928 str_end_with_asciichar(VALUE str, int c)
06929 {
06930 long len = RSTRING_LEN(str);
06931 const char *ptr = RSTRING_PTR(str);
06932 rb_encoding *enc = rb_enc_from_index(ENCODING_GET(str));
06933 int n;
06934
06935 if (len == 0) return 0;
06936 if ((n = rb_enc_mbminlen(enc)) == 1) {
06937 return ptr[len - 1] == c;
06938 }
06939 return rb_enc_ascget(ptr + ((len - 1) / n) * n, ptr + len, &n, enc) == c;
06940 }
06941
06942 static VALUE
06943 io_puts_ary(VALUE ary, VALUE out, int recur)
06944 {
06945 VALUE tmp;
06946 long i;
06947
06948 if (recur) {
06949 tmp = rb_str_new2("[...]");
06950 rb_io_puts(1, &tmp, out);
06951 return Qtrue;
06952 }
06953 ary = rb_check_array_type(ary);
06954 if (NIL_P(ary)) return Qfalse;
06955 for (i=0; i<RARRAY_LEN(ary); i++) {
06956 tmp = RARRAY_AREF(ary, i);
06957 rb_io_puts(1, &tmp, out);
06958 }
06959 return Qtrue;
06960 }
06961
06962
06963
06964
06965
06966
06967
06968
06969
06970
06971
06972
06973
06974
06975
06976
06977
06978
06979
06980
06981
06982 VALUE
06983 rb_io_puts(int argc, VALUE *argv, VALUE out)
06984 {
06985 int i;
06986 VALUE line;
06987
06988
06989 if (argc == 0) {
06990 rb_io_write(out, rb_default_rs);
06991 return Qnil;
06992 }
06993 for (i=0; i<argc; i++) {
06994 if (RB_TYPE_P(argv[i], T_STRING)) {
06995 line = argv[i];
06996 goto string;
06997 }
06998 if (rb_exec_recursive(io_puts_ary, argv[i], out)) {
06999 continue;
07000 }
07001 line = rb_obj_as_string(argv[i]);
07002 string:
07003 rb_io_write(out, line);
07004 if (RSTRING_LEN(line) == 0 ||
07005 !str_end_with_asciichar(line, '\n')) {
07006 rb_io_write(out, rb_default_rs);
07007 }
07008 }
07009
07010 return Qnil;
07011 }
07012
07013
07014
07015
07016
07017
07018
07019
07020
07021
07022 static VALUE
07023 rb_f_puts(int argc, VALUE *argv, VALUE recv)
07024 {
07025 if (recv == rb_stdout) {
07026 return rb_io_puts(argc, argv, recv);
07027 }
07028 return rb_funcall2(rb_stdout, rb_intern("puts"), argc, argv);
07029 }
07030
07031 void
07032 rb_p(VALUE obj)
07033 {
07034 VALUE str = rb_obj_as_string(rb_inspect(obj));
07035 if (RB_TYPE_P(rb_stdout, T_FILE) &&
07036 rb_method_basic_definition_p(CLASS_OF(rb_stdout), id_write)) {
07037 io_write(rb_stdout, str, 1);
07038 io_write(rb_stdout, rb_default_rs, 0);
07039 }
07040 else {
07041 rb_io_write(rb_stdout, str);
07042 rb_io_write(rb_stdout, rb_default_rs);
07043 }
07044 }
07045
07046 struct rb_f_p_arg {
07047 int argc;
07048 VALUE *argv;
07049 };
07050
07051 static VALUE
07052 rb_f_p_internal(VALUE arg)
07053 {
07054 struct rb_f_p_arg *arg1 = (struct rb_f_p_arg*)arg;
07055 int argc = arg1->argc;
07056 VALUE *argv = arg1->argv;
07057 int i;
07058 VALUE ret = Qnil;
07059
07060 for (i=0; i<argc; i++) {
07061 rb_p(argv[i]);
07062 }
07063 if (argc == 1) {
07064 ret = argv[0];
07065 }
07066 else if (argc > 1) {
07067 ret = rb_ary_new4(argc, argv);
07068 }
07069 if (RB_TYPE_P(rb_stdout, T_FILE)) {
07070 rb_io_flush(rb_stdout);
07071 }
07072 return ret;
07073 }
07074
07075
07076
07077
07078
07079
07080
07081
07082
07083
07084
07085
07086
07087
07088
07089
07090
07091
07092
07093 static VALUE
07094 rb_f_p(int argc, VALUE *argv, VALUE self)
07095 {
07096 struct rb_f_p_arg arg;
07097 arg.argc = argc;
07098 arg.argv = argv;
07099
07100 return rb_uninterruptible(rb_f_p_internal, (VALUE)&arg);
07101 }
07102
07103
07104
07105
07106
07107
07108
07109
07110
07111
07112
07113
07114
07115
07116
07117
07118
07119
07120
07121
07122
07123
07124
07125
07126 static VALUE
07127 rb_obj_display(int argc, VALUE *argv, VALUE self)
07128 {
07129 VALUE out;
07130
07131 if (argc == 0) {
07132 out = rb_stdout;
07133 }
07134 else {
07135 rb_scan_args(argc, argv, "01", &out);
07136 }
07137 rb_io_write(out, self);
07138
07139 return Qnil;
07140 }
07141
07142 void
07143 rb_write_error2(const char *mesg, long len)
07144 {
07145 if (rb_stderr == orig_stderr || RFILE(orig_stderr)->fptr->fd < 0) {
07146 if (fwrite(mesg, sizeof(char), (size_t)len, stderr) < (size_t)len) {
07147
07148 return;
07149 }
07150 }
07151 else {
07152 rb_io_write(rb_stderr, rb_str_new(mesg, len));
07153 }
07154 }
07155
07156 void
07157 rb_write_error(const char *mesg)
07158 {
07159 rb_write_error2(mesg, strlen(mesg));
07160 }
07161
07162 void
07163 rb_write_error_str(VALUE mesg)
07164 {
07165
07166 if (rb_stderr == orig_stderr || RFILE(orig_stderr)->fptr->fd < 0) {
07167 size_t len = (size_t)RSTRING_LEN(mesg);
07168 if (fwrite(RSTRING_PTR(mesg), sizeof(char), len, stderr) < len) {
07169 RB_GC_GUARD(mesg);
07170 return;
07171 }
07172 }
07173 else {
07174
07175 rb_io_write(rb_stderr, mesg);
07176 }
07177 }
07178
07179 static void
07180 must_respond_to(ID mid, VALUE val, ID id)
07181 {
07182 if (!rb_respond_to(val, mid)) {
07183 rb_raise(rb_eTypeError, "%s must have %s method, %s given",
07184 rb_id2name(id), rb_id2name(mid),
07185 rb_obj_classname(val));
07186 }
07187 }
07188
07189 static void
07190 stdout_setter(VALUE val, ID id, VALUE *variable)
07191 {
07192 must_respond_to(id_write, val, id);
07193 *variable = val;
07194 }
07195
07196 static VALUE
07197 prep_io(int fd, int fmode, VALUE klass, const char *path)
07198 {
07199 rb_io_t *fp;
07200 VALUE io = io_alloc(klass);
07201
07202 MakeOpenFile(io, fp);
07203 fp->fd = fd;
07204 #ifdef __CYGWIN__
07205 if (!isatty(fd)) {
07206 fmode |= FMODE_BINMODE;
07207 setmode(fd, O_BINARY);
07208 }
07209 #endif
07210 fp->mode = fmode;
07211 io_check_tty(fp);
07212 if (path) fp->pathv = rb_obj_freeze(rb_str_new_cstr(path));
07213 rb_update_max_fd(fd);
07214
07215 return io;
07216 }
07217
07218 VALUE
07219 rb_io_fdopen(int fd, int oflags, const char *path)
07220 {
07221 VALUE klass = rb_cIO;
07222
07223 if (path && strcmp(path, "-")) klass = rb_cFile;
07224 return prep_io(fd, rb_io_oflags_fmode(oflags), klass, path);
07225 }
07226
07227 static VALUE
07228 prep_stdio(FILE *f, int fmode, VALUE klass, const char *path)
07229 {
07230 rb_io_t *fptr;
07231 VALUE io = prep_io(fileno(f), fmode|FMODE_PREP|DEFAULT_TEXTMODE, klass, path);
07232
07233 GetOpenFile(io, fptr);
07234 fptr->encs.ecflags |= ECONV_DEFAULT_NEWLINE_DECORATOR;
07235 #ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
07236 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
07237 if (fmode & FMODE_READABLE) {
07238 fptr->encs.ecflags |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;
07239 }
07240 #endif
07241 fptr->stdio_file = f;
07242
07243 return io;
07244 }
07245
07246 FILE *
07247 rb_io_stdio_file(rb_io_t *fptr)
07248 {
07249 if (!fptr->stdio_file) {
07250 int oflags = rb_io_fmode_oflags(fptr->mode);
07251 fptr->stdio_file = rb_fdopen(fptr->fd, rb_io_oflags_modestr(oflags));
07252 }
07253 return fptr->stdio_file;
07254 }
07255
07256
07257
07258
07259
07260
07261
07262
07263
07264
07265
07266
07267
07268
07269
07270
07271
07272
07273
07274
07275
07276
07277
07278
07279
07280
07281
07282
07283
07284
07285
07286
07287
07288
07289
07290
07291
07292
07293
07294
07295
07296
07297
07298
07299
07300
07301
07302
07303
07304
07305
07306
07307
07308
07309
07310
07311
07312
07313
07314
07315
07316
07317
07318
07319
07320
07321
07322
07323
07324
07325
07326
07327
07328
07329
07330
07331
07332
07333
07334
07335
07336
07337
07338
07339
07340
07341
07342
07343
07344
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 static VALUE
07403 rb_io_initialize(int argc, VALUE *argv, VALUE io)
07404 {
07405 VALUE fnum, vmode;
07406 rb_io_t *fp;
07407 int fd, fmode, oflags = O_RDONLY;
07408 convconfig_t convconfig;
07409 VALUE opt;
07410 #if defined(HAVE_FCNTL) && defined(F_GETFL)
07411 int ofmode;
07412 #else
07413 struct stat st;
07414 #endif
07415
07416
07417 argc = rb_scan_args(argc, argv, "11:", &fnum, &vmode, &opt);
07418 rb_io_extract_modeenc(&vmode, 0, opt, &oflags, &fmode, &convconfig);
07419
07420 fd = NUM2INT(fnum);
07421 if (rb_reserved_fd_p(fd)) {
07422 rb_raise(rb_eArgError, "The given fd is not accessible because RubyVM reserves it");
07423 }
07424 #if defined(HAVE_FCNTL) && defined(F_GETFL)
07425 oflags = fcntl(fd, F_GETFL);
07426 if (oflags == -1) rb_sys_fail(0);
07427 #else
07428 if (fstat(fd, &st) == -1) rb_sys_fail(0);
07429 #endif
07430 rb_update_max_fd(fd);
07431 #if defined(HAVE_FCNTL) && defined(F_GETFL)
07432 ofmode = rb_io_oflags_fmode(oflags);
07433 if (NIL_P(vmode)) {
07434 fmode = ofmode;
07435 }
07436 else if ((~ofmode & fmode) & FMODE_READWRITE) {
07437 VALUE error = INT2FIX(EINVAL);
07438 rb_exc_raise(rb_class_new_instance(1, &error, rb_eSystemCallError));
07439 }
07440 #endif
07441 if (!NIL_P(opt) && rb_hash_aref(opt, sym_autoclose) == Qfalse) {
07442 fmode |= FMODE_PREP;
07443 }
07444 MakeOpenFile(io, fp);
07445 fp->fd = fd;
07446 fp->mode = fmode;
07447 fp->encs = convconfig;
07448 clear_codeconv(fp);
07449 io_check_tty(fp);
07450 if (fileno(stdin) == fd)
07451 fp->stdio_file = stdin;
07452 else if (fileno(stdout) == fd)
07453 fp->stdio_file = stdout;
07454 else if (fileno(stderr) == fd)
07455 fp->stdio_file = stderr;
07456
07457 if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
07458 return io;
07459 }
07460
07461
07462
07463
07464
07465
07466
07467
07468
07469
07470
07471
07472
07473
07474
07475
07476
07477
07478
07479
07480
07481
07482 static VALUE
07483 rb_file_initialize(int argc, VALUE *argv, VALUE io)
07484 {
07485 if (RFILE(io)->fptr) {
07486 rb_raise(rb_eRuntimeError, "reinitializing File");
07487 }
07488 if (0 < argc && argc < 3) {
07489 VALUE fd = rb_check_convert_type(argv[0], T_FIXNUM, "Fixnum", "to_int");
07490
07491 if (!NIL_P(fd)) {
07492 argv[0] = fd;
07493 return rb_io_initialize(argc, argv, io);
07494 }
07495 }
07496 rb_open_file(argc, argv, io);
07497
07498 return io;
07499 }
07500
07501
07502 static VALUE
07503 rb_io_s_new(int argc, VALUE *argv, VALUE klass)
07504 {
07505 if (rb_block_given_p()) {
07506 const char *cname = rb_class2name(klass);
07507
07508 rb_warn("%s::new() does not take block; use %s::open() instead",
07509 cname, cname);
07510 }
07511 return rb_class_new_instance(argc, argv, klass);
07512 }
07513
07514
07515
07516
07517
07518
07519
07520
07521
07522
07523 static VALUE
07524 rb_io_s_for_fd(int argc, VALUE *argv, VALUE klass)
07525 {
07526 VALUE io = rb_obj_alloc(klass);
07527 rb_io_initialize(argc, argv, io);
07528 return io;
07529 }
07530
07531
07532
07533
07534
07535
07536
07537
07538
07539 static VALUE
07540 rb_io_autoclose_p(VALUE io)
07541 {
07542 rb_io_t *fptr = RFILE(io)->fptr;
07543 rb_io_check_closed(fptr);
07544 return (fptr->mode & FMODE_PREP) ? Qfalse : Qtrue;
07545 }
07546
07547
07548
07549
07550
07551
07552
07553
07554
07555
07556
07557
07558
07559
07560
07561
07562
07563
07564 static VALUE
07565 rb_io_set_autoclose(VALUE io, VALUE autoclose)
07566 {
07567 rb_io_t *fptr;
07568 GetOpenFile(io, fptr);
07569 if (!RTEST(autoclose))
07570 fptr->mode |= FMODE_PREP;
07571 else
07572 fptr->mode &= ~FMODE_PREP;
07573 return io;
07574 }
07575
07576 static void
07577 argf_mark(void *ptr)
07578 {
07579 struct argf *p = ptr;
07580 rb_gc_mark(p->filename);
07581 rb_gc_mark(p->current_file);
07582 rb_gc_mark(p->argv);
07583 rb_gc_mark(p->encs.ecopts);
07584 }
07585
07586 static void
07587 argf_free(void *ptr)
07588 {
07589 struct argf *p = ptr;
07590 xfree(p->inplace);
07591 xfree(p);
07592 }
07593
07594 static size_t
07595 argf_memsize(const void *ptr)
07596 {
07597 const struct argf *p = ptr;
07598 size_t size = sizeof(*p);
07599 if (!ptr) return 0;
07600 if (p->inplace) size += strlen(p->inplace) + 1;
07601 return size;
07602 }
07603
07604 static const rb_data_type_t argf_type = {
07605 "ARGF",
07606 {argf_mark, argf_free, argf_memsize},
07607 NULL, NULL, RUBY_TYPED_FREE_IMMEDIATELY
07608 };
07609
07610 static inline void
07611 argf_init(struct argf *p, VALUE v)
07612 {
07613 p->filename = Qnil;
07614 p->current_file = Qnil;
07615 p->lineno = 0;
07616 p->argv = v;
07617 }
07618
07619 static VALUE
07620 argf_alloc(VALUE klass)
07621 {
07622 struct argf *p;
07623 VALUE argf = TypedData_Make_Struct(klass, struct argf, &argf_type, p);
07624
07625 argf_init(p, Qnil);
07626 return argf;
07627 }
07628
07629 #undef rb_argv
07630
07631
07632 static VALUE
07633 argf_initialize(VALUE argf, VALUE argv)
07634 {
07635 memset(&ARGF, 0, sizeof(ARGF));
07636 argf_init(&ARGF, argv);
07637
07638 return argf;
07639 }
07640
07641
07642 static VALUE
07643 argf_initialize_copy(VALUE argf, VALUE orig)
07644 {
07645 if (!OBJ_INIT_COPY(argf, orig)) return argf;
07646 ARGF = argf_of(orig);
07647 ARGF.argv = rb_obj_dup(ARGF.argv);
07648 if (ARGF.inplace) {
07649 const char *inplace = ARGF.inplace;
07650 ARGF.inplace = 0;
07651 ARGF.inplace = ruby_strdup(inplace);
07652 }
07653 return argf;
07654 }
07655
07656
07657
07658
07659
07660
07661
07662
07663
07664
07665
07666
07667
07668
07669
07670
07671
07672
07673
07674 static VALUE
07675 argf_set_lineno(VALUE argf, VALUE val)
07676 {
07677 ARGF.lineno = NUM2INT(val);
07678 ARGF.last_lineno = ARGF.lineno;
07679 return Qnil;
07680 }
07681
07682
07683
07684
07685
07686
07687
07688
07689
07690
07691
07692
07693
07694
07695 static VALUE
07696 argf_lineno(VALUE argf)
07697 {
07698 return INT2FIX(ARGF.lineno);
07699 }
07700
07701 static VALUE
07702 argf_forward(int argc, VALUE *argv, VALUE argf)
07703 {
07704 return rb_funcall3(ARGF.current_file, rb_frame_this_func(), argc, argv);
07705 }
07706
07707 #define next_argv() argf_next_argv(argf)
07708 #define ARGF_GENERIC_INPUT_P() \
07709 (ARGF.current_file == rb_stdin && !RB_TYPE_P(ARGF.current_file, T_FILE))
07710 #define ARGF_FORWARD(argc, argv) do {\
07711 if (ARGF_GENERIC_INPUT_P())\
07712 return argf_forward((argc), (argv), argf);\
07713 } while (0)
07714 #define NEXT_ARGF_FORWARD(argc, argv) do {\
07715 if (!next_argv()) return Qnil;\
07716 ARGF_FORWARD((argc), (argv));\
07717 } while (0)
07718
07719 static void
07720 argf_close(VALUE argf)
07721 {
07722 VALUE file = ARGF.current_file;
07723 if (file == rb_stdin) return;
07724 if (RB_TYPE_P(file, T_FILE)) {
07725 rb_io_set_write_io(file, Qnil);
07726 }
07727 rb_funcall3(file, rb_intern("close"), 0, 0);
07728 ARGF.init_p = -1;
07729 }
07730
07731 static int
07732 argf_next_argv(VALUE argf)
07733 {
07734 char *fn;
07735 rb_io_t *fptr;
07736 int stdout_binmode = 0;
07737 int fmode;
07738
07739 if (RB_TYPE_P(rb_stdout, T_FILE)) {
07740 GetOpenFile(rb_stdout, fptr);
07741 if (fptr->mode & FMODE_BINMODE)
07742 stdout_binmode = 1;
07743 }
07744
07745 if (ARGF.init_p == 0) {
07746 if (!NIL_P(ARGF.argv) && RARRAY_LEN(ARGF.argv) > 0) {
07747 ARGF.next_p = 1;
07748 }
07749 else {
07750 ARGF.next_p = -1;
07751 }
07752 ARGF.init_p = 1;
07753 }
07754 else {
07755 if (NIL_P(ARGF.argv)) {
07756 ARGF.next_p = -1;
07757 }
07758 else if (ARGF.next_p == -1 && RARRAY_LEN(ARGF.argv) > 0) {
07759 ARGF.next_p = 1;
07760 }
07761 }
07762
07763 if (ARGF.next_p == 1) {
07764 retry:
07765 if (RARRAY_LEN(ARGF.argv) > 0) {
07766 ARGF.filename = rb_ary_shift(ARGF.argv);
07767 fn = StringValueCStr(ARGF.filename);
07768 if (strlen(fn) == 1 && fn[0] == '-') {
07769 ARGF.current_file = rb_stdin;
07770 if (ARGF.inplace) {
07771 rb_warn("Can't do inplace edit for stdio; skipping");
07772 goto retry;
07773 }
07774 }
07775 else {
07776 VALUE write_io = Qnil;
07777 int fr = rb_sysopen(ARGF.filename, O_RDONLY, 0);
07778
07779 if (ARGF.inplace) {
07780 struct stat st;
07781 #ifndef NO_SAFE_RENAME
07782 struct stat st2;
07783 #endif
07784 VALUE str;
07785 int fw;
07786
07787 if (RB_TYPE_P(rb_stdout, T_FILE) && rb_stdout != orig_stdout) {
07788 rb_io_close(rb_stdout);
07789 }
07790 fstat(fr, &st);
07791 if (*ARGF.inplace) {
07792 str = rb_str_new2(fn);
07793 rb_str_cat2(str, ARGF.inplace);
07794 #ifdef NO_SAFE_RENAME
07795 (void)close(fr);
07796 (void)unlink(RSTRING_PTR(str));
07797 if (rename(fn, RSTRING_PTR(str)) < 0) {
07798 rb_warn("Can't rename %s to %s: %s, skipping file",
07799 fn, RSTRING_PTR(str), strerror(errno));
07800 goto retry;
07801 }
07802 fr = rb_sysopen(str, O_RDONLY, 0);
07803 #else
07804 if (rename(fn, RSTRING_PTR(str)) < 0) {
07805 rb_warn("Can't rename %s to %s: %s, skipping file",
07806 fn, RSTRING_PTR(str), strerror(errno));
07807 close(fr);
07808 goto retry;
07809 }
07810 #endif
07811 }
07812 else {
07813 #ifdef NO_SAFE_RENAME
07814 rb_fatal("Can't do inplace edit without backup");
07815 #else
07816 if (unlink(fn) < 0) {
07817 rb_warn("Can't remove %s: %s, skipping file",
07818 fn, strerror(errno));
07819 close(fr);
07820 goto retry;
07821 }
07822 #endif
07823 }
07824 fw = rb_sysopen(ARGF.filename, O_WRONLY|O_CREAT|O_TRUNC, 0666);
07825 #ifndef NO_SAFE_RENAME
07826 fstat(fw, &st2);
07827 #ifdef HAVE_FCHMOD
07828 fchmod(fw, st.st_mode);
07829 #else
07830 chmod(fn, st.st_mode);
07831 #endif
07832 if (st.st_uid!=st2.st_uid || st.st_gid!=st2.st_gid) {
07833 int err;
07834 #ifdef HAVE_FCHOWN
07835 err = fchown(fw, st.st_uid, st.st_gid);
07836 #else
07837 err = chown(fn, st.st_uid, st.st_gid);
07838 #endif
07839 if (err && getuid() == 0 && st2.st_uid == 0) {
07840 const char *wkfn = RSTRING_PTR(ARGF.filename);
07841 rb_warn("Can't set owner/group of %s to same as %s: %s, skipping file",
07842 wkfn, fn, strerror(errno));
07843 (void)close(fr);
07844 (void)close(fw);
07845 (void)unlink(wkfn);
07846 goto retry;
07847 }
07848 }
07849 #endif
07850 write_io = prep_io(fw, FMODE_WRITABLE, rb_cFile, fn);
07851 rb_stdout = write_io;
07852 if (stdout_binmode) rb_io_binmode(rb_stdout);
07853 }
07854 fmode = FMODE_READABLE;
07855 if (!ARGF.binmode) {
07856 fmode |= DEFAULT_TEXTMODE;
07857 }
07858 ARGF.current_file = prep_io(fr, fmode, rb_cFile, fn);
07859 if (!NIL_P(write_io)) {
07860 rb_io_set_write_io(ARGF.current_file, write_io);
07861 }
07862 }
07863 if (ARGF.binmode) rb_io_ascii8bit_binmode(ARGF.current_file);
07864 GetOpenFile(ARGF.current_file, fptr);
07865 if (ARGF.encs.enc) {
07866 fptr->encs = ARGF.encs;
07867 clear_codeconv(fptr);
07868 }
07869 else {
07870 fptr->encs.ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
07871 if (!ARGF.binmode) {
07872 fptr->encs.ecflags |= ECONV_DEFAULT_NEWLINE_DECORATOR;
07873 #ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
07874 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
07875 #endif
07876 }
07877 }
07878 ARGF.next_p = 0;
07879 }
07880 else {
07881 ARGF.next_p = 1;
07882 return FALSE;
07883 }
07884 }
07885 else if (ARGF.next_p == -1) {
07886 ARGF.current_file = rb_stdin;
07887 ARGF.filename = rb_str_new2("-");
07888 if (ARGF.inplace) {
07889 rb_warn("Can't do inplace edit for stdio");
07890 rb_stdout = orig_stdout;
07891 }
07892 }
07893 if (ARGF.init_p == -1) ARGF.init_p = 1;
07894 return TRUE;
07895 }
07896
07897 static VALUE
07898 argf_getline(int argc, VALUE *argv, VALUE argf)
07899 {
07900 VALUE line;
07901 long lineno = ARGF.lineno;
07902
07903 retry:
07904 if (!next_argv()) return Qnil;
07905 if (ARGF_GENERIC_INPUT_P()) {
07906 line = rb_funcall3(ARGF.current_file, idGets, argc, argv);
07907 }
07908 else {
07909 if (argc == 0 && rb_rs == rb_default_rs) {
07910 line = rb_io_gets(ARGF.current_file);
07911 }
07912 else {
07913 line = rb_io_getline(argc, argv, ARGF.current_file);
07914 }
07915 if (NIL_P(line) && ARGF.next_p != -1) {
07916 argf_close(argf);
07917 ARGF.next_p = 1;
07918 goto retry;
07919 }
07920 }
07921 if (!NIL_P(line)) {
07922 ARGF.lineno = ++lineno;
07923 ARGF.last_lineno = ARGF.lineno;
07924 }
07925 return line;
07926 }
07927
07928 static VALUE
07929 argf_lineno_getter(ID id, VALUE *var)
07930 {
07931 VALUE argf = *var;
07932 return INT2FIX(ARGF.last_lineno);
07933 }
07934
07935 static void
07936 argf_lineno_setter(VALUE val, ID id, VALUE *var)
07937 {
07938 VALUE argf = *var;
07939 int n = NUM2INT(val);
07940 ARGF.last_lineno = ARGF.lineno = n;
07941 }
07942
07943 static VALUE argf_gets(int, VALUE *, VALUE);
07944
07945
07946
07947
07948
07949
07950
07951
07952
07953
07954
07955
07956
07957
07958
07959
07960
07961
07962
07963
07964
07965
07966
07967
07968
07969
07970
07971
07972
07973
07974
07975
07976
07977
07978 static VALUE
07979 rb_f_gets(int argc, VALUE *argv, VALUE recv)
07980 {
07981 if (recv == argf) {
07982 return argf_gets(argc, argv, argf);
07983 }
07984 return rb_funcall2(argf, idGets, argc, argv);
07985 }
07986
07987
07988
07989
07990
07991
07992
07993
07994
07995
07996
07997
07998
07999
08000
08001
08002 static VALUE
08003 argf_gets(int argc, VALUE *argv, VALUE argf)
08004 {
08005 VALUE line;
08006
08007 line = argf_getline(argc, argv, argf);
08008 rb_lastline_set(line);
08009
08010 return line;
08011 }
08012
08013 VALUE
08014 rb_gets(void)
08015 {
08016 VALUE line;
08017
08018 if (rb_rs != rb_default_rs) {
08019 return rb_f_gets(0, 0, argf);
08020 }
08021
08022 retry:
08023 if (!next_argv()) return Qnil;
08024 line = rb_io_gets(ARGF.current_file);
08025 if (NIL_P(line) && ARGF.next_p != -1) {
08026 rb_io_close(ARGF.current_file);
08027 ARGF.next_p = 1;
08028 goto retry;
08029 }
08030 rb_lastline_set(line);
08031 if (!NIL_P(line)) {
08032 ARGF.lineno++;
08033 ARGF.last_lineno = ARGF.lineno;
08034 }
08035
08036 return line;
08037 }
08038
08039 static VALUE argf_readline(int, VALUE *, VALUE);
08040
08041
08042
08043
08044
08045
08046
08047
08048
08049
08050
08051 static VALUE
08052 rb_f_readline(int argc, VALUE *argv, VALUE recv)
08053 {
08054 if (recv == argf) {
08055 return argf_readline(argc, argv, argf);
08056 }
08057 return rb_funcall2(argf, rb_intern("readline"), argc, argv);
08058 }
08059
08060
08061
08062
08063
08064
08065
08066
08067
08068
08069
08070
08071
08072
08073
08074
08075
08076
08077 static VALUE
08078 argf_readline(int argc, VALUE *argv, VALUE argf)
08079 {
08080 VALUE line;
08081
08082 if (!next_argv()) rb_eof_error();
08083 ARGF_FORWARD(argc, argv);
08084 line = argf_gets(argc, argv, argf);
08085 if (NIL_P(line)) {
08086 rb_eof_error();
08087 }
08088
08089 return line;
08090 }
08091
08092 static VALUE argf_readlines(int, VALUE *, VALUE);
08093
08094
08095
08096
08097
08098
08099
08100
08101
08102
08103
08104 static VALUE
08105 rb_f_readlines(int argc, VALUE *argv, VALUE recv)
08106 {
08107 if (recv == argf) {
08108 return argf_readlines(argc, argv, argf);
08109 }
08110 return rb_funcall2(argf, rb_intern("readlines"), argc, argv);
08111 }
08112
08113
08114
08115
08116
08117
08118
08119
08120
08121
08122
08123
08124
08125
08126
08127
08128
08129 static VALUE
08130 argf_readlines(int argc, VALUE *argv, VALUE argf)
08131 {
08132 long lineno = ARGF.lineno;
08133 VALUE lines, ary;
08134
08135 ary = rb_ary_new();
08136 while (next_argv()) {
08137 if (ARGF_GENERIC_INPUT_P()) {
08138 lines = rb_funcall3(ARGF.current_file, rb_intern("readlines"), argc, argv);
08139 }
08140 else {
08141 lines = rb_io_readlines(argc, argv, ARGF.current_file);
08142 argf_close(argf);
08143 }
08144 ARGF.next_p = 1;
08145 rb_ary_concat(ary, lines);
08146 ARGF.lineno = lineno + RARRAY_LEN(ary);
08147 ARGF.last_lineno = ARGF.lineno;
08148 }
08149 ARGF.init_p = 0;
08150 return ary;
08151 }
08152
08153
08154
08155
08156
08157
08158
08159
08160
08161
08162
08163
08164
08165
08166
08167 static VALUE
08168 rb_f_backquote(VALUE obj, VALUE str)
08169 {
08170 volatile VALUE port;
08171 VALUE result;
08172 rb_io_t *fptr;
08173
08174 SafeStringValue(str);
08175 rb_last_status_clear();
08176 port = pipe_open_s(str, "r", FMODE_READABLE|DEFAULT_TEXTMODE, NULL);
08177 if (NIL_P(port)) return rb_str_new(0,0);
08178
08179 GetOpenFile(port, fptr);
08180 result = read_all(fptr, remain_size(fptr), Qnil);
08181 rb_io_close(port);
08182
08183 return result;
08184 }
08185
08186 #ifdef HAVE_SYS_SELECT_H
08187 #include <sys/select.h>
08188 #endif
08189
08190 static VALUE
08191 select_internal(VALUE read, VALUE write, VALUE except, struct timeval *tp, rb_fdset_t *fds)
08192 {
08193 VALUE res, list;
08194 rb_fdset_t *rp, *wp, *ep;
08195 rb_io_t *fptr;
08196 long i;
08197 int max = 0, n;
08198 int pending = 0;
08199 struct timeval timerec;
08200
08201 if (!NIL_P(read)) {
08202 Check_Type(read, T_ARRAY);
08203 for (i=0; i<RARRAY_LEN(read); i++) {
08204 GetOpenFile(rb_io_get_io(RARRAY_AREF(read, i)), fptr);
08205 rb_fd_set(fptr->fd, &fds[0]);
08206 if (READ_DATA_PENDING(fptr) || READ_CHAR_PENDING(fptr)) {
08207 pending++;
08208 rb_fd_set(fptr->fd, &fds[3]);
08209 }
08210 if (max < fptr->fd) max = fptr->fd;
08211 }
08212 if (pending) {
08213 timerec.tv_sec = timerec.tv_usec = 0;
08214 tp = &timerec;
08215 }
08216 rp = &fds[0];
08217 }
08218 else
08219 rp = 0;
08220
08221 if (!NIL_P(write)) {
08222 Check_Type(write, T_ARRAY);
08223 for (i=0; i<RARRAY_LEN(write); i++) {
08224 VALUE write_io = GetWriteIO(rb_io_get_io(RARRAY_AREF(write, i)));
08225 GetOpenFile(write_io, fptr);
08226 rb_fd_set(fptr->fd, &fds[1]);
08227 if (max < fptr->fd) max = fptr->fd;
08228 }
08229 wp = &fds[1];
08230 }
08231 else
08232 wp = 0;
08233
08234 if (!NIL_P(except)) {
08235 Check_Type(except, T_ARRAY);
08236 for (i=0; i<RARRAY_LEN(except); i++) {
08237 VALUE io = rb_io_get_io(RARRAY_AREF(except, i));
08238 VALUE write_io = GetWriteIO(io);
08239 GetOpenFile(io, fptr);
08240 rb_fd_set(fptr->fd, &fds[2]);
08241 if (max < fptr->fd) max = fptr->fd;
08242 if (io != write_io) {
08243 GetOpenFile(write_io, fptr);
08244 rb_fd_set(fptr->fd, &fds[2]);
08245 if (max < fptr->fd) max = fptr->fd;
08246 }
08247 }
08248 ep = &fds[2];
08249 }
08250 else {
08251 ep = 0;
08252 }
08253
08254 max++;
08255
08256 n = rb_thread_fd_select(max, rp, wp, ep, tp);
08257 if (n < 0) {
08258 rb_sys_fail(0);
08259 }
08260 if (!pending && n == 0) return Qnil;
08261
08262 res = rb_ary_new2(3);
08263 rb_ary_push(res, rp?rb_ary_new():rb_ary_new2(0));
08264 rb_ary_push(res, wp?rb_ary_new():rb_ary_new2(0));
08265 rb_ary_push(res, ep?rb_ary_new():rb_ary_new2(0));
08266
08267 if (rp) {
08268 list = RARRAY_AREF(res, 0);
08269 for (i=0; i< RARRAY_LEN(read); i++) {
08270 VALUE obj = rb_ary_entry(read, i);
08271 VALUE io = rb_io_get_io(obj);
08272 GetOpenFile(io, fptr);
08273 if (rb_fd_isset(fptr->fd, &fds[0]) ||
08274 rb_fd_isset(fptr->fd, &fds[3])) {
08275 rb_ary_push(list, obj);
08276 }
08277 }
08278 }
08279
08280 if (wp) {
08281 list = RARRAY_AREF(res, 1);
08282 for (i=0; i< RARRAY_LEN(write); i++) {
08283 VALUE obj = rb_ary_entry(write, i);
08284 VALUE io = rb_io_get_io(obj);
08285 VALUE write_io = GetWriteIO(io);
08286 GetOpenFile(write_io, fptr);
08287 if (rb_fd_isset(fptr->fd, &fds[1])) {
08288 rb_ary_push(list, obj);
08289 }
08290 }
08291 }
08292
08293 if (ep) {
08294 list = RARRAY_AREF(res, 2);
08295 for (i=0; i< RARRAY_LEN(except); i++) {
08296 VALUE obj = rb_ary_entry(except, i);
08297 VALUE io = rb_io_get_io(obj);
08298 VALUE write_io = GetWriteIO(io);
08299 GetOpenFile(io, fptr);
08300 if (rb_fd_isset(fptr->fd, &fds[2])) {
08301 rb_ary_push(list, obj);
08302 }
08303 else if (io != write_io) {
08304 GetOpenFile(write_io, fptr);
08305 if (rb_fd_isset(fptr->fd, &fds[2])) {
08306 rb_ary_push(list, obj);
08307 }
08308 }
08309 }
08310 }
08311
08312 return res;
08313 }
08314
08315 struct select_args {
08316 VALUE read, write, except;
08317 struct timeval *timeout;
08318 rb_fdset_t fdsets[4];
08319 };
08320
08321 static VALUE
08322 select_call(VALUE arg)
08323 {
08324 struct select_args *p = (struct select_args *)arg;
08325
08326 return select_internal(p->read, p->write, p->except, p->timeout, p->fdsets);
08327 }
08328
08329 static VALUE
08330 select_end(VALUE arg)
08331 {
08332 struct select_args *p = (struct select_args *)arg;
08333 int i;
08334
08335 for (i = 0; i < numberof(p->fdsets); ++i)
08336 rb_fd_term(&p->fdsets[i]);
08337 return Qnil;
08338 }
08339
08340 static VALUE sym_normal, sym_sequential, sym_random,
08341 sym_willneed, sym_dontneed, sym_noreuse;
08342
08343 #ifdef HAVE_POSIX_FADVISE
08344 struct io_advise_struct {
08345 int fd;
08346 off_t offset;
08347 off_t len;
08348 int advice;
08349 };
08350
08351 static VALUE
08352 io_advise_internal(void *arg)
08353 {
08354 struct io_advise_struct *ptr = arg;
08355 return posix_fadvise(ptr->fd, ptr->offset, ptr->len, ptr->advice);
08356 }
08357
08358 static VALUE
08359 io_advise_sym_to_const(VALUE sym)
08360 {
08361 #ifdef POSIX_FADV_NORMAL
08362 if (sym == sym_normal)
08363 return INT2NUM(POSIX_FADV_NORMAL);
08364 #endif
08365
08366 #ifdef POSIX_FADV_RANDOM
08367 if (sym == sym_random)
08368 return INT2NUM(POSIX_FADV_RANDOM);
08369 #endif
08370
08371 #ifdef POSIX_FADV_SEQUENTIAL
08372 if (sym == sym_sequential)
08373 return INT2NUM(POSIX_FADV_SEQUENTIAL);
08374 #endif
08375
08376 #ifdef POSIX_FADV_WILLNEED
08377 if (sym == sym_willneed)
08378 return INT2NUM(POSIX_FADV_WILLNEED);
08379 #endif
08380
08381 #ifdef POSIX_FADV_DONTNEED
08382 if (sym == sym_dontneed)
08383 return INT2NUM(POSIX_FADV_DONTNEED);
08384 #endif
08385
08386 #ifdef POSIX_FADV_NOREUSE
08387 if (sym == sym_noreuse)
08388 return INT2NUM(POSIX_FADV_NOREUSE);
08389 #endif
08390
08391 return Qnil;
08392 }
08393
08394 static VALUE
08395 do_io_advise(rb_io_t *fptr, VALUE advice, off_t offset, off_t len)
08396 {
08397 int rv;
08398 struct io_advise_struct ias;
08399 VALUE num_adv;
08400
08401 num_adv = io_advise_sym_to_const(advice);
08402
08403
08404
08405
08406
08407 if (NIL_P(num_adv))
08408 return Qnil;
08409
08410 ias.fd = fptr->fd;
08411 ias.advice = NUM2INT(num_adv);
08412 ias.offset = offset;
08413 ias.len = len;
08414
08415 rv = (int)rb_thread_io_blocking_region(io_advise_internal, &ias, fptr->fd);
08416 if (rv) {
08417
08418
08419 rb_syserr_fail_str(rv, fptr->pathv);
08420 }
08421
08422 return Qnil;
08423 }
08424
08425 #endif
08426
08427 static void
08428 advice_arg_check(VALUE advice)
08429 {
08430 if (!SYMBOL_P(advice))
08431 rb_raise(rb_eTypeError, "advice must be a Symbol");
08432
08433 if (advice != sym_normal &&
08434 advice != sym_sequential &&
08435 advice != sym_random &&
08436 advice != sym_willneed &&
08437 advice != sym_dontneed &&
08438 advice != sym_noreuse) {
08439 VALUE symname = rb_inspect(advice);
08440 rb_raise(rb_eNotImpError, "Unsupported advice: %s",
08441 StringValuePtr(symname));
08442 }
08443 }
08444
08445
08446
08447
08448
08449
08450
08451
08452
08453
08454
08455
08456
08457
08458
08459
08460
08461
08462
08463
08464
08465
08466
08467
08468
08469
08470
08471
08472
08473
08474
08475
08476
08477
08478
08479
08480
08481
08482
08483
08484
08485
08486
08487 static VALUE
08488 rb_io_advise(int argc, VALUE *argv, VALUE io)
08489 {
08490 VALUE advice, offset, len;
08491 off_t off, l;
08492 rb_io_t *fptr;
08493
08494 rb_scan_args(argc, argv, "12", &advice, &offset, &len);
08495 advice_arg_check(advice);
08496
08497 io = GetWriteIO(io);
08498 GetOpenFile(io, fptr);
08499
08500 off = NIL_P(offset) ? 0 : NUM2OFFT(offset);
08501 l = NIL_P(len) ? 0 : NUM2OFFT(len);
08502
08503 #ifdef HAVE_POSIX_FADVISE
08504 return do_io_advise(fptr, advice, off, l);
08505 #else
08506 ((void)off, (void)l);
08507 return Qnil;
08508 #endif
08509 }
08510
08511
08512
08513
08514
08515
08516
08517
08518
08519
08520
08521
08522
08523
08524
08525
08526
08527
08528
08529
08530
08531
08532
08533
08534
08535
08536
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 static VALUE
08656 rb_f_select(int argc, VALUE *argv, VALUE obj)
08657 {
08658 VALUE timeout;
08659 struct select_args args;
08660 struct timeval timerec;
08661 int i;
08662
08663 rb_scan_args(argc, argv, "13", &args.read, &args.write, &args.except, &timeout);
08664 if (NIL_P(timeout)) {
08665 args.timeout = 0;
08666 }
08667 else {
08668 timerec = rb_time_interval(timeout);
08669 args.timeout = &timerec;
08670 }
08671
08672 for (i = 0; i < numberof(args.fdsets); ++i)
08673 rb_fd_init(&args.fdsets[i]);
08674
08675 return rb_ensure(select_call, (VALUE)&args, select_end, (VALUE)&args);
08676 }
08677
08678 #if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
08679 typedef unsigned long ioctl_req_t;
08680 # define NUM2IOCTLREQ(num) NUM2ULONG(num)
08681 #else
08682 typedef int ioctl_req_t;
08683 # define NUM2IOCTLREQ(num) NUM2INT(num)
08684 #endif
08685
08686 struct ioctl_arg {
08687 int fd;
08688 ioctl_req_t cmd;
08689 long narg;
08690 };
08691
08692 static VALUE
08693 nogvl_ioctl(void *ptr)
08694 {
08695 struct ioctl_arg *arg = ptr;
08696
08697 return (VALUE)ioctl(arg->fd, arg->cmd, arg->narg);
08698 }
08699
08700 static int
08701 do_ioctl(int fd, ioctl_req_t cmd, long narg)
08702 {
08703 int retval;
08704 struct ioctl_arg arg;
08705
08706 arg.fd = fd;
08707 arg.cmd = cmd;
08708 arg.narg = narg;
08709
08710 retval = (int)rb_thread_io_blocking_region(nogvl_ioctl, &arg, fd);
08711
08712 return retval;
08713 }
08714
08715 #define DEFULT_IOCTL_NARG_LEN (256)
08716
08717 #if defined(__linux__) && defined(_IOC_SIZE)
08718 static long
08719 linux_iocparm_len(ioctl_req_t cmd)
08720 {
08721 long len;
08722
08723 if ((cmd & 0xFFFF0000) == 0) {
08724
08725 return DEFULT_IOCTL_NARG_LEN;
08726 }
08727
08728 len = _IOC_SIZE(cmd);
08729
08730
08731 if (len < DEFULT_IOCTL_NARG_LEN)
08732 len = DEFULT_IOCTL_NARG_LEN;
08733
08734 return len;
08735 }
08736 #endif
08737
08738 static long
08739 ioctl_narg_len(ioctl_req_t cmd)
08740 {
08741 long len;
08742
08743 #ifdef IOCPARM_MASK
08744 #ifndef IOCPARM_LEN
08745 #define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK)
08746 #endif
08747 #endif
08748 #ifdef IOCPARM_LEN
08749 len = IOCPARM_LEN(cmd);
08750 #elif defined(__linux__) && defined(_IOC_SIZE)
08751 len = linux_iocparm_len(cmd);
08752 #else
08753
08754 len = DEFULT_IOCTL_NARG_LEN;
08755 #endif
08756
08757 return len;
08758 }
08759
08760 #ifdef HAVE_FCNTL
08761 #ifdef __linux__
08762 typedef long fcntl_arg_t;
08763 #else
08764
08765 typedef int fcntl_arg_t;
08766 #endif
08767
08768 static long
08769 fcntl_narg_len(int cmd)
08770 {
08771 long len;
08772
08773 switch (cmd) {
08774 #ifdef F_DUPFD
08775 case F_DUPFD:
08776 len = sizeof(fcntl_arg_t);
08777 break;
08778 #endif
08779 #ifdef F_DUP2FD
08780 case F_DUP2FD:
08781 len = sizeof(int);
08782 break;
08783 #endif
08784 #ifdef F_DUPFD_CLOEXEC
08785 case F_DUPFD_CLOEXEC:
08786 len = sizeof(fcntl_arg_t);
08787 break;
08788 #endif
08789 #ifdef F_GETFD
08790 case F_GETFD:
08791 len = 1;
08792 break;
08793 #endif
08794 #ifdef F_SETFD
08795 case F_SETFD:
08796 len = sizeof(fcntl_arg_t);
08797 break;
08798 #endif
08799 #ifdef F_GETFL
08800 case F_GETFL:
08801 len = 1;
08802 break;
08803 #endif
08804 #ifdef F_SETFL
08805 case F_SETFL:
08806 len = sizeof(fcntl_arg_t);
08807 break;
08808 #endif
08809 #ifdef F_GETOWN
08810 case F_GETOWN:
08811 len = 1;
08812 break;
08813 #endif
08814 #ifdef F_SETOWN
08815 case F_SETOWN:
08816 len = sizeof(fcntl_arg_t);
08817 break;
08818 #endif
08819 #ifdef F_GETOWN_EX
08820 case F_GETOWN_EX:
08821 len = sizeof(struct f_owner_ex);
08822 break;
08823 #endif
08824 #ifdef F_SETOWN_EX
08825 case F_SETOWN_EX:
08826 len = sizeof(struct f_owner_ex);
08827 break;
08828 #endif
08829 #ifdef F_GETLK
08830 case F_GETLK:
08831 len = sizeof(struct flock);
08832 break;
08833 #endif
08834 #ifdef F_SETLK
08835 case F_SETLK:
08836 len = sizeof(struct flock);
08837 break;
08838 #endif
08839 #ifdef F_SETLKW
08840 case F_SETLKW:
08841 len = sizeof(struct flock);
08842 break;
08843 #endif
08844 #ifdef F_READAHEAD
08845 case F_READAHEAD:
08846 len = sizeof(int);
08847 break;
08848 #endif
08849 #ifdef F_RDAHEAD
08850 case F_RDAHEAD:
08851 len = sizeof(int);
08852 break;
08853 #endif
08854 #ifdef F_GETSIG
08855 case F_GETSIG:
08856 len = 1;
08857 break;
08858 #endif
08859 #ifdef F_SETSIG
08860 case F_SETSIG:
08861 len = sizeof(fcntl_arg_t);
08862 break;
08863 #endif
08864 #ifdef F_GETLEASE
08865 case F_GETLEASE:
08866 len = 1;
08867 break;
08868 #endif
08869 #ifdef F_SETLEASE
08870 case F_SETLEASE:
08871 len = sizeof(fcntl_arg_t);
08872 break;
08873 #endif
08874 #ifdef F_NOTIFY
08875 case F_NOTIFY:
08876 len = sizeof(fcntl_arg_t);
08877 break;
08878 #endif
08879
08880 default:
08881 len = 256;
08882 break;
08883 }
08884
08885 return len;
08886 }
08887 #else
08888 static long
08889 fcntl_narg_len(int cmd)
08890 {
08891 return 0;
08892 }
08893 #endif
08894
08895 static long
08896 setup_narg(ioctl_req_t cmd, VALUE *argp, int io_p)
08897 {
08898 long narg = 0;
08899 VALUE arg = *argp;
08900
08901 if (NIL_P(arg) || arg == Qfalse) {
08902 narg = 0;
08903 }
08904 else if (FIXNUM_P(arg)) {
08905 narg = FIX2LONG(arg);
08906 }
08907 else if (arg == Qtrue) {
08908 narg = 1;
08909 }
08910 else {
08911 VALUE tmp = rb_check_string_type(arg);
08912
08913 if (NIL_P(tmp)) {
08914 narg = NUM2LONG(arg);
08915 }
08916 else {
08917 long len;
08918
08919 *argp = arg = tmp;
08920 if (io_p)
08921 len = ioctl_narg_len(cmd);
08922 else
08923 len = fcntl_narg_len((int)cmd);
08924 rb_str_modify(arg);
08925
08926
08927 if (RSTRING_LEN(arg) < len+1) {
08928 rb_str_resize(arg, len+1);
08929 }
08930
08931 RSTRING_PTR(arg)[RSTRING_LEN(arg) - 1] = 17;
08932 narg = (long)(SIGNED_VALUE)RSTRING_PTR(arg);
08933 }
08934 }
08935
08936 return narg;
08937 }
08938
08939 static VALUE
08940 rb_ioctl(VALUE io, VALUE req, VALUE arg)
08941 {
08942 ioctl_req_t cmd = NUM2IOCTLREQ(req);
08943 rb_io_t *fptr;
08944 long narg;
08945 int retval;
08946
08947 rb_secure(2);
08948
08949 narg = setup_narg(cmd, &arg, 1);
08950 GetOpenFile(io, fptr);
08951 retval = do_ioctl(fptr->fd, cmd, narg);
08952 if (retval < 0) rb_sys_fail_path(fptr->pathv);
08953 if (RB_TYPE_P(arg, T_STRING)) {
08954 if (RSTRING_PTR(arg)[RSTRING_LEN(arg)-1] != 17)
08955 rb_raise(rb_eArgError, "return value overflowed string");
08956 RSTRING_PTR(arg)[RSTRING_LEN(arg)-1] = '\0';
08957 }
08958
08959 return INT2NUM(retval);
08960 }
08961
08962
08963
08964
08965
08966
08967
08968
08969
08970
08971
08972
08973
08974 static VALUE
08975 rb_io_ioctl(int argc, VALUE *argv, VALUE io)
08976 {
08977 VALUE req, arg;
08978
08979 rb_scan_args(argc, argv, "11", &req, &arg);
08980 return rb_ioctl(io, req, arg);
08981 }
08982
08983 #ifdef HAVE_FCNTL
08984 struct fcntl_arg {
08985 int fd;
08986 int cmd;
08987 long narg;
08988 };
08989
08990 static VALUE
08991 nogvl_fcntl(void *ptr)
08992 {
08993 struct fcntl_arg *arg = ptr;
08994
08995 #if defined(F_DUPFD)
08996 if (arg->cmd == F_DUPFD)
08997 return (VALUE)rb_cloexec_fcntl_dupfd(arg->fd, (int)arg->narg);
08998 #endif
08999 return (VALUE)fcntl(arg->fd, arg->cmd, arg->narg);
09000 }
09001
09002 static int
09003 do_fcntl(int fd, int cmd, long narg)
09004 {
09005 int retval;
09006 struct fcntl_arg arg;
09007
09008 arg.fd = fd;
09009 arg.cmd = cmd;
09010 arg.narg = narg;
09011
09012 retval = (int)rb_thread_io_blocking_region(nogvl_fcntl, &arg, fd);
09013 #if defined(F_DUPFD)
09014 if (retval != -1 && cmd == F_DUPFD) {
09015 rb_update_max_fd(retval);
09016 }
09017 #endif
09018
09019 return retval;
09020 }
09021
09022 static VALUE
09023 rb_fcntl(VALUE io, VALUE req, VALUE arg)
09024 {
09025 int cmd = NUM2INT(req);
09026 rb_io_t *fptr;
09027 long narg;
09028 int retval;
09029
09030 rb_secure(2);
09031
09032 narg = setup_narg(cmd, &arg, 0);
09033 GetOpenFile(io, fptr);
09034 retval = do_fcntl(fptr->fd, cmd, narg);
09035 if (retval < 0) rb_sys_fail_path(fptr->pathv);
09036 if (RB_TYPE_P(arg, T_STRING)) {
09037 if (RSTRING_PTR(arg)[RSTRING_LEN(arg)-1] != 17)
09038 rb_raise(rb_eArgError, "return value overflowed string");
09039 RSTRING_PTR(arg)[RSTRING_LEN(arg)-1] = '\0';
09040 }
09041
09042 if (cmd == F_SETFL) {
09043 if (narg & O_NONBLOCK) {
09044 fptr->mode |= FMODE_WSPLIT_INITIALIZED;
09045 fptr->mode &= ~FMODE_WSPLIT;
09046 }
09047 else {
09048 fptr->mode &= ~(FMODE_WSPLIT_INITIALIZED|FMODE_WSPLIT);
09049 }
09050 }
09051
09052 return INT2NUM(retval);
09053 }
09054
09055
09056
09057
09058
09059
09060
09061
09062
09063
09064
09065
09066
09067
09068 static VALUE
09069 rb_io_fcntl(int argc, VALUE *argv, VALUE io)
09070 {
09071 VALUE req, arg;
09072
09073 rb_scan_args(argc, argv, "11", &req, &arg);
09074 return rb_fcntl(io, req, arg);
09075 }
09076 #else
09077 #define rb_io_fcntl rb_f_notimplement
09078 #endif
09079
09080 #if defined(HAVE_SYSCALL) || defined(HAVE___SYSCALL)
09081
09082
09083
09084
09085
09086
09087
09088
09089
09090
09091
09092
09093
09094
09095
09096
09097
09098
09099
09100
09101
09102
09103
09104
09105
09106
09107
09108
09109
09110
09111
09112
09113
09114 static VALUE
09115 rb_f_syscall(int argc, VALUE *argv)
09116 {
09117 #ifdef atarist
09118 VALUE arg[13];
09119 #else
09120 VALUE arg[8];
09121 #endif
09122 #if SIZEOF_VOIDP == 8 && defined(HAVE___SYSCALL) && SIZEOF_INT != 8
09123 # define SYSCALL __syscall
09124 # define NUM2SYSCALLID(x) NUM2LONG(x)
09125 # define RETVAL2NUM(x) LONG2NUM(x)
09126 # if SIZEOF_LONG == 8
09127 long num, retval = -1;
09128 # elif SIZEOF_LONG_LONG == 8
09129 long long num, retval = -1;
09130 # else
09131 # error ---->> it is asserted that __syscall takes the first argument and returns retval in 64bit signed integer. <<----
09132 # endif
09133 #elif defined(__linux__)
09134 # define SYSCALL syscall
09135 # define NUM2SYSCALLID(x) NUM2LONG(x)
09136 # define RETVAL2NUM(x) LONG2NUM(x)
09137
09138
09139
09140
09141
09142
09143
09144 long num, retval = -1;
09145 #else
09146 # define SYSCALL syscall
09147 # define NUM2SYSCALLID(x) NUM2INT(x)
09148 # define RETVAL2NUM(x) INT2NUM(x)
09149 int num, retval = -1;
09150 #endif
09151 int i;
09152
09153 if (RTEST(ruby_verbose)) {
09154 rb_warning("We plan to remove a syscall function at future release. DL(Fiddle) provides safer alternative.");
09155 }
09156
09157 rb_secure(2);
09158 if (argc == 0)
09159 rb_raise(rb_eArgError, "too few arguments for syscall");
09160 if (argc > numberof(arg))
09161 rb_raise(rb_eArgError, "too many arguments for syscall");
09162 num = NUM2SYSCALLID(argv[0]); ++argv;
09163 for (i = argc - 1; i--; ) {
09164 VALUE v = rb_check_string_type(argv[i]);
09165
09166 if (!NIL_P(v)) {
09167 SafeStringValue(v);
09168 rb_str_modify(v);
09169 arg[i] = (VALUE)StringValueCStr(v);
09170 }
09171 else {
09172 arg[i] = (VALUE)NUM2LONG(argv[i]);
09173 }
09174 }
09175
09176 switch (argc) {
09177 case 1:
09178 retval = SYSCALL(num);
09179 break;
09180 case 2:
09181 retval = SYSCALL(num, arg[0]);
09182 break;
09183 case 3:
09184 retval = SYSCALL(num, arg[0],arg[1]);
09185 break;
09186 case 4:
09187 retval = SYSCALL(num, arg[0],arg[1],arg[2]);
09188 break;
09189 case 5:
09190 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3]);
09191 break;
09192 case 6:
09193 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4]);
09194 break;
09195 case 7:
09196 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5]);
09197 break;
09198 case 8:
09199 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6]);
09200 break;
09201 #ifdef atarist
09202 case 9:
09203 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6],
09204 arg[7]);
09205 break;
09206 case 10:
09207 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6],
09208 arg[7], arg[8]);
09209 break;
09210 case 11:
09211 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6],
09212 arg[7], arg[8], arg[9]);
09213 break;
09214 case 12:
09215 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6],
09216 arg[7], arg[8], arg[9], arg[10]);
09217 break;
09218 case 13:
09219 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6],
09220 arg[7], arg[8], arg[9], arg[10], arg[11]);
09221 break;
09222 case 14:
09223 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6],
09224 arg[7], arg[8], arg[9], arg[10], arg[11], arg[12]);
09225 break;
09226 #endif
09227 }
09228
09229 if (retval == -1)
09230 rb_sys_fail(0);
09231 return RETVAL2NUM(retval);
09232 #undef SYSCALL
09233 #undef NUM2SYSCALLID
09234 #undef RETVAL2NUM
09235 }
09236 #else
09237 #define rb_f_syscall rb_f_notimplement
09238 #endif
09239
09240 static VALUE
09241 io_new_instance(VALUE args)
09242 {
09243 return rb_class_new_instance(2, (VALUE*)args+1, *(VALUE*)args);
09244 }
09245
09246 static rb_encoding *
09247 find_encoding(VALUE v)
09248 {
09249 rb_encoding *enc = rb_find_encoding(v);
09250 if (!enc) unsupported_encoding(StringValueCStr(v));
09251 return enc;
09252 }
09253
09254 static void
09255 io_encoding_set(rb_io_t *fptr, VALUE v1, VALUE v2, VALUE opt)
09256 {
09257 rb_encoding *enc, *enc2;
09258 int ecflags = fptr->encs.ecflags;
09259 VALUE ecopts, tmp;
09260
09261 if (!NIL_P(v2)) {
09262 enc2 = find_encoding(v1);
09263 tmp = rb_check_string_type(v2);
09264 if (!NIL_P(tmp)) {
09265 if (RSTRING_LEN(tmp) == 1 && RSTRING_PTR(tmp)[0] == '-') {
09266
09267 enc = enc2;
09268 enc2 = NULL;
09269 }
09270 else
09271 enc = find_encoding(v2);
09272 if (enc == enc2) {
09273
09274 enc2 = NULL;
09275 }
09276 }
09277 else {
09278 enc = find_encoding(v2);
09279 if (enc == enc2) {
09280
09281 enc2 = NULL;
09282 }
09283 }
09284 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
09285 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
09286 }
09287 else {
09288 if (NIL_P(v1)) {
09289
09290 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
09291 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
09292 ecopts = Qnil;
09293 }
09294 else {
09295 tmp = rb_check_string_type(v1);
09296 if (!NIL_P(tmp) && rb_enc_asciicompat(rb_enc_get(tmp))) {
09297 parse_mode_enc(RSTRING_PTR(tmp), &enc, &enc2, NULL);
09298 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
09299 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
09300 }
09301 else {
09302 rb_io_ext_int_to_encs(find_encoding(v1), NULL, &enc, &enc2, 0);
09303 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
09304 ecopts = Qnil;
09305 }
09306 }
09307 }
09308 validate_enc_binmode(&fptr->mode, ecflags, enc, enc2);
09309 fptr->encs.enc = enc;
09310 fptr->encs.enc2 = enc2;
09311 fptr->encs.ecflags = ecflags;
09312 fptr->encs.ecopts = ecopts;
09313 clear_codeconv(fptr);
09314
09315 }
09316
09317 static VALUE
09318 pipe_pair_close(VALUE rw)
09319 {
09320 VALUE *rwp = (VALUE *)rw;
09321 return rb_ensure(io_close, rwp[0], io_close, rwp[1]);
09322 }
09323
09324
09325
09326
09327
09328
09329
09330
09331
09332
09333
09334
09335
09336
09337
09338
09339
09340
09341
09342
09343
09344
09345
09346
09347
09348
09349
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 static VALUE
09385 rb_io_s_pipe(int argc, VALUE *argv, VALUE klass)
09386 {
09387 int pipes[2], state;
09388 VALUE r, w, args[3], v1, v2;
09389 VALUE opt;
09390 rb_io_t *fptr, *fptr2;
09391 int fmode = 0;
09392 VALUE ret;
09393
09394 argc = rb_scan_args(argc, argv, "02:", &v1, &v2, &opt);
09395 if (rb_pipe(pipes) == -1)
09396 rb_sys_fail(0);
09397
09398 args[0] = klass;
09399 args[1] = INT2NUM(pipes[0]);
09400 args[2] = INT2FIX(O_RDONLY);
09401 r = rb_protect(io_new_instance, (VALUE)args, &state);
09402 if (state) {
09403 close(pipes[0]);
09404 close(pipes[1]);
09405 rb_jump_tag(state);
09406 }
09407 GetOpenFile(r, fptr);
09408 io_encoding_set(fptr, v1, v2, opt);
09409 args[1] = INT2NUM(pipes[1]);
09410 args[2] = INT2FIX(O_WRONLY);
09411 w = rb_protect(io_new_instance, (VALUE)args, &state);
09412 if (state) {
09413 close(pipes[1]);
09414 if (!NIL_P(r)) rb_io_close(r);
09415 rb_jump_tag(state);
09416 }
09417 GetOpenFile(w, fptr2);
09418 rb_io_synchronized(fptr2);
09419
09420 extract_binmode(opt, &fmode);
09421 #if DEFAULT_TEXTMODE
09422 if ((fptr->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
09423 fptr->mode &= ~FMODE_TEXTMODE;
09424 setmode(fptr->fd, O_BINARY);
09425 }
09426 #if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)
09427 if (fptr->encs.ecflags & ECONV_DEFAULT_NEWLINE_DECORATOR) {
09428 fptr->encs.ecflags |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;
09429 }
09430 #endif
09431 #endif
09432 fptr->mode |= fmode;
09433 #if DEFAULT_TEXTMODE
09434 if ((fptr2->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
09435 fptr2->mode &= ~FMODE_TEXTMODE;
09436 setmode(fptr2->fd, O_BINARY);
09437 }
09438 #endif
09439 fptr2->mode |= fmode;
09440
09441 ret = rb_assoc_new(r, w);
09442 if (rb_block_given_p()) {
09443 VALUE rw[2];
09444 rw[0] = r;
09445 rw[1] = w;
09446 return rb_ensure(rb_yield, ret, pipe_pair_close, (VALUE)rw);
09447 }
09448 return ret;
09449 }
09450
09451 struct foreach_arg {
09452 int argc;
09453 VALUE *argv;
09454 VALUE io;
09455 };
09456
09457 static void
09458 open_key_args(int argc, VALUE *argv, VALUE opt, struct foreach_arg *arg)
09459 {
09460 VALUE path, v;
09461
09462 path = *argv++;
09463 argc--;
09464 FilePathValue(path);
09465 arg->io = 0;
09466 arg->argc = argc;
09467 arg->argv = argv;
09468 if (NIL_P(opt)) {
09469 arg->io = rb_io_open(path, INT2NUM(O_RDONLY), INT2FIX(0666), Qnil);
09470 return;
09471 }
09472 v = rb_hash_aref(opt, sym_open_args);
09473 if (!NIL_P(v)) {
09474 VALUE args;
09475 long n;
09476
09477 v = rb_convert_type(v, T_ARRAY, "Array", "to_ary");
09478 n = RARRAY_LEN(v) + 1;
09479 #if SIZEOF_LONG > SIZEOF_INT
09480 if (n > INT_MAX) {
09481 rb_raise(rb_eArgError, "too many arguments");
09482 }
09483 #endif
09484 args = rb_ary_tmp_new(n);
09485 rb_ary_push(args, path);
09486 rb_ary_concat(args, v);
09487 arg->io = rb_io_open_with_args((int)n, RARRAY_CONST_PTR(args));
09488 rb_ary_clear(args);
09489 return;
09490 }
09491 arg->io = rb_io_open(path, Qnil, Qnil, opt);
09492 }
09493
09494 static VALUE
09495 io_s_foreach(struct foreach_arg *arg)
09496 {
09497 VALUE str;
09498
09499 while (!NIL_P(str = rb_io_gets_m(arg->argc, arg->argv, arg->io))) {
09500 rb_yield(str);
09501 }
09502 return Qnil;
09503 }
09504
09505
09506
09507
09508
09509
09510
09511
09512
09513
09514
09515
09516
09517
09518
09519
09520
09521
09522
09523
09524
09525
09526
09527
09528
09529
09530
09531 static VALUE
09532 rb_io_s_foreach(int argc, VALUE *argv, VALUE self)
09533 {
09534 VALUE opt;
09535 int orig_argc = argc;
09536 struct foreach_arg arg;
09537
09538 argc = rb_scan_args(argc, argv, "13:", NULL, NULL, NULL, NULL, &opt);
09539 RETURN_ENUMERATOR(self, orig_argc, argv);
09540 open_key_args(argc, argv, opt, &arg);
09541 if (NIL_P(arg.io)) return Qnil;
09542 return rb_ensure(io_s_foreach, (VALUE)&arg, rb_io_close, arg.io);
09543 }
09544
09545 static VALUE
09546 io_s_readlines(struct foreach_arg *arg)
09547 {
09548 return rb_io_readlines(arg->argc, arg->argv, arg->io);
09549 }
09550
09551
09552
09553
09554
09555
09556
09557
09558
09559
09560
09561
09562
09563
09564
09565
09566
09567
09568
09569 static VALUE
09570 rb_io_s_readlines(int argc, VALUE *argv, VALUE io)
09571 {
09572 VALUE opt;
09573 struct foreach_arg arg;
09574
09575 argc = rb_scan_args(argc, argv, "13:", NULL, NULL, NULL, NULL, &opt);
09576 open_key_args(argc, argv, opt, &arg);
09577 if (NIL_P(arg.io)) return Qnil;
09578 return rb_ensure(io_s_readlines, (VALUE)&arg, rb_io_close, arg.io);
09579 }
09580
09581 static VALUE
09582 io_s_read(struct foreach_arg *arg)
09583 {
09584 return io_read(arg->argc, arg->argv, arg->io);
09585 }
09586
09587 struct seek_arg {
09588 VALUE io;
09589 VALUE offset;
09590 int mode;
09591 };
09592
09593 static VALUE
09594 seek_before_access(VALUE argp)
09595 {
09596 struct seek_arg *arg = (struct seek_arg *)argp;
09597 rb_io_binmode(arg->io);
09598 return rb_io_seek(arg->io, arg->offset, arg->mode);
09599 }
09600
09601
09602
09603
09604
09605
09606
09607
09608
09609
09610
09611
09612
09613
09614
09615
09616
09617
09618
09619
09620
09621
09622
09623
09624
09625
09626
09627
09628
09629
09630
09631
09632
09633
09634
09635
09636
09637 static VALUE
09638 rb_io_s_read(int argc, VALUE *argv, VALUE io)
09639 {
09640 VALUE opt, offset;
09641 struct foreach_arg arg;
09642
09643 argc = rb_scan_args(argc, argv, "13:", NULL, NULL, &offset, NULL, &opt);
09644 open_key_args(argc, argv, opt, &arg);
09645 if (NIL_P(arg.io)) return Qnil;
09646 if (!NIL_P(offset)) {
09647 struct seek_arg sarg;
09648 int state = 0;
09649 sarg.io = arg.io;
09650 sarg.offset = offset;
09651 sarg.mode = SEEK_SET;
09652 rb_protect(seek_before_access, (VALUE)&sarg, &state);
09653 if (state) {
09654 rb_io_close(arg.io);
09655 rb_jump_tag(state);
09656 }
09657 if (arg.argc == 2) arg.argc = 1;
09658 }
09659 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
09660 }
09661
09662
09663
09664
09665
09666
09667
09668
09669
09670
09671
09672
09673
09674
09675
09676 static VALUE
09677 rb_io_s_binread(int argc, VALUE *argv, VALUE io)
09678 {
09679 VALUE offset;
09680 struct foreach_arg arg;
09681
09682 rb_scan_args(argc, argv, "12", NULL, NULL, &offset);
09683 FilePathValue(argv[0]);
09684 arg.io = rb_io_open(argv[0], rb_str_new_cstr("rb:ASCII-8BIT"), Qnil, Qnil);
09685 if (NIL_P(arg.io)) return Qnil;
09686 arg.argv = argv+1;
09687 arg.argc = (argc > 1) ? 1 : 0;
09688 if (!NIL_P(offset)) {
09689 rb_io_seek(arg.io, offset, SEEK_SET);
09690 }
09691 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
09692 }
09693
09694 static VALUE
09695 io_s_write0(struct write_arg *arg)
09696 {
09697 return io_write(arg->io,arg->str,arg->nosync);
09698 }
09699
09700 static VALUE
09701 io_s_write(int argc, VALUE *argv, int binary)
09702 {
09703 VALUE string, offset, opt;
09704 struct foreach_arg arg;
09705 struct write_arg warg;
09706
09707 rb_scan_args(argc, argv, "21:", NULL, &string, &offset, &opt);
09708
09709 if (NIL_P(opt)) opt = rb_hash_new();
09710 else opt = rb_hash_dup(opt);
09711
09712
09713 if (NIL_P(rb_hash_aref(opt,sym_mode))) {
09714 int mode = O_WRONLY|O_CREAT;
09715 #ifdef O_BINARY
09716 if (binary) mode |= O_BINARY;
09717 #endif
09718 if (NIL_P(offset)) mode |= O_TRUNC;
09719 rb_hash_aset(opt,sym_mode,INT2NUM(mode));
09720 }
09721 open_key_args(argc,argv,opt,&arg);
09722
09723 #ifndef O_BINARY
09724 if (binary) rb_io_binmode_m(arg.io);
09725 #endif
09726
09727 if (NIL_P(arg.io)) return Qnil;
09728 if (!NIL_P(offset)) {
09729 struct seek_arg sarg;
09730 int state = 0;
09731 sarg.io = arg.io;
09732 sarg.offset = offset;
09733 sarg.mode = SEEK_SET;
09734 rb_protect(seek_before_access, (VALUE)&sarg, &state);
09735 if (state) {
09736 rb_io_close(arg.io);
09737 rb_jump_tag(state);
09738 }
09739 }
09740
09741 warg.io = arg.io;
09742 warg.str = string;
09743 warg.nosync = 0;
09744
09745 return rb_ensure(io_s_write0, (VALUE)&warg, rb_io_close, arg.io);
09746 }
09747
09748
09749
09750
09751
09752
09753
09754
09755
09756
09757
09758
09759
09760
09761
09762
09763
09764
09765
09766
09767
09768
09769
09770
09771
09772
09773
09774
09775
09776
09777
09778
09779
09780
09781
09782
09783
09784
09785
09786
09787 static VALUE
09788 rb_io_s_write(int argc, VALUE *argv, VALUE io)
09789 {
09790 return io_s_write(argc, argv, 0);
09791 }
09792
09793
09794
09795
09796
09797
09798
09799
09800
09801
09802
09803 static VALUE
09804 rb_io_s_binwrite(int argc, VALUE *argv, VALUE io)
09805 {
09806 return io_s_write(argc, argv, 1);
09807 }
09808
09809 struct copy_stream_struct {
09810 VALUE src;
09811 VALUE dst;
09812 off_t copy_length;
09813 off_t src_offset;
09814
09815 int src_fd;
09816 int dst_fd;
09817 int close_src;
09818 int close_dst;
09819 off_t total;
09820 const char *syserr;
09821 int error_no;
09822 const char *notimp;
09823 rb_fdset_t fds;
09824 VALUE th;
09825 };
09826
09827 static void *
09828 exec_interrupts(void *arg)
09829 {
09830 VALUE th = (VALUE)arg;
09831 rb_thread_execute_interrupts(th);
09832 return NULL;
09833 }
09834
09835
09836
09837
09838
09839
09840 static int
09841 maygvl_copy_stream_continue_p(int has_gvl, struct copy_stream_struct *stp)
09842 {
09843 switch (errno) {
09844 case EINTR:
09845 #if defined(ERESTART)
09846 case ERESTART:
09847 #endif
09848 if (rb_thread_interrupted(stp->th)) {
09849 if (has_gvl)
09850 rb_thread_execute_interrupts(stp->th);
09851 else
09852 rb_thread_call_with_gvl(exec_interrupts, (void *)stp->th);
09853 }
09854 return TRUE;
09855 }
09856 return FALSE;
09857 }
09858
09859 static int
09860 maygvl_select(int has_gvl, int n, rb_fdset_t *rfds, rb_fdset_t *wfds, rb_fdset_t *efds, struct timeval *timeout)
09861 {
09862 if (has_gvl)
09863 return rb_thread_fd_select(n, rfds, wfds, efds, timeout);
09864 else
09865 return rb_fd_select(n, rfds, wfds, efds, timeout);
09866 }
09867
09868 static int
09869 maygvl_copy_stream_wait_read(int has_gvl, struct copy_stream_struct *stp)
09870 {
09871 int ret;
09872
09873 do {
09874 rb_fd_zero(&stp->fds);
09875 rb_fd_set(stp->src_fd, &stp->fds);
09876 ret = maygvl_select(has_gvl, rb_fd_max(&stp->fds), &stp->fds, NULL, NULL, NULL);
09877 } while (ret == -1 && maygvl_copy_stream_continue_p(has_gvl, stp));
09878
09879 if (ret == -1) {
09880 stp->syserr = "select";
09881 stp->error_no = errno;
09882 return -1;
09883 }
09884 return 0;
09885 }
09886
09887 static int
09888 nogvl_copy_stream_wait_write(struct copy_stream_struct *stp)
09889 {
09890 int ret;
09891
09892 do {
09893 rb_fd_zero(&stp->fds);
09894 rb_fd_set(stp->dst_fd, &stp->fds);
09895 ret = rb_fd_select(rb_fd_max(&stp->fds), NULL, &stp->fds, NULL, NULL);
09896 } while (ret == -1 && maygvl_copy_stream_continue_p(0, stp));
09897
09898 if (ret == -1) {
09899 stp->syserr = "select";
09900 stp->error_no = errno;
09901 return -1;
09902 }
09903 return 0;
09904 }
09905
09906 #ifdef HAVE_SENDFILE
09907
09908 # ifdef __linux__
09909 # define USE_SENDFILE
09910
09911 # ifdef HAVE_SYS_SENDFILE_H
09912 # include <sys/sendfile.h>
09913 # endif
09914
09915 static ssize_t
09916 simple_sendfile(int out_fd, int in_fd, off_t *offset, off_t count)
09917 {
09918 return sendfile(out_fd, in_fd, offset, (size_t)count);
09919 }
09920
09921 # elif 0 || defined(__APPLE__)
09922
09923
09924
09925 # define USE_SENDFILE
09926
09927 # ifdef HAVE_SYS_UIO_H
09928 # include <sys/uio.h>
09929 # endif
09930
09931 static ssize_t
09932 simple_sendfile(int out_fd, int in_fd, off_t *offset, off_t count)
09933 {
09934 int r;
09935 off_t pos = offset ? *offset : lseek(in_fd, 0, SEEK_CUR);
09936 off_t sbytes;
09937 # ifdef __APPLE__
09938 r = sendfile(in_fd, out_fd, pos, &count, NULL, 0);
09939 sbytes = count;
09940 # else
09941 r = sendfile(in_fd, out_fd, pos, (size_t)count, NULL, &sbytes, 0);
09942 # endif
09943 if (r != 0 && sbytes == 0) return -1;
09944 if (offset) {
09945 *offset += sbytes;
09946 }
09947 else {
09948 lseek(in_fd, sbytes, SEEK_CUR);
09949 }
09950 return (ssize_t)sbytes;
09951 }
09952
09953 # endif
09954
09955 #endif
09956
09957 #ifdef USE_SENDFILE
09958 static int
09959 nogvl_copy_stream_sendfile(struct copy_stream_struct *stp)
09960 {
09961 struct stat src_stat, dst_stat;
09962 ssize_t ss;
09963 int ret;
09964
09965 off_t copy_length;
09966 off_t src_offset;
09967 int use_pread;
09968
09969 ret = fstat(stp->src_fd, &src_stat);
09970 if (ret == -1) {
09971 stp->syserr = "fstat";
09972 stp->error_no = errno;
09973 return -1;
09974 }
09975 if (!S_ISREG(src_stat.st_mode))
09976 return 0;
09977
09978 ret = fstat(stp->dst_fd, &dst_stat);
09979 if (ret == -1) {
09980 stp->syserr = "fstat";
09981 stp->error_no = errno;
09982 return -1;
09983 }
09984 if ((dst_stat.st_mode & S_IFMT) != S_IFSOCK)
09985 return 0;
09986
09987 src_offset = stp->src_offset;
09988 use_pread = src_offset != (off_t)-1;
09989
09990 copy_length = stp->copy_length;
09991 if (copy_length == (off_t)-1) {
09992 if (use_pread)
09993 copy_length = src_stat.st_size - src_offset;
09994 else {
09995 off_t cur;
09996 errno = 0;
09997 cur = lseek(stp->src_fd, 0, SEEK_CUR);
09998 if (cur == (off_t)-1 && errno) {
09999 stp->syserr = "lseek";
10000 stp->error_no = errno;
10001 return -1;
10002 }
10003 copy_length = src_stat.st_size - cur;
10004 }
10005 }
10006
10007 retry_sendfile:
10008 # if SIZEOF_OFF_T > SIZEOF_SIZE_T
10009
10010 ss = (copy_length > (off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
10011 # else
10012 ss = (ssize_t)copy_length;
10013 # endif
10014 if (use_pread) {
10015 ss = simple_sendfile(stp->dst_fd, stp->src_fd, &src_offset, ss);
10016 }
10017 else {
10018 ss = simple_sendfile(stp->dst_fd, stp->src_fd, NULL, ss);
10019 }
10020 if (0 < ss) {
10021 stp->total += ss;
10022 copy_length -= ss;
10023 if (0 < copy_length) {
10024 goto retry_sendfile;
10025 }
10026 }
10027 if (ss == -1) {
10028 if (maygvl_copy_stream_continue_p(0, stp))
10029 goto retry_sendfile;
10030 switch (errno) {
10031 case EINVAL:
10032 #ifdef ENOSYS
10033 case ENOSYS:
10034 #endif
10035 return 0;
10036 case EAGAIN:
10037 #if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
10038 case EWOULDBLOCK:
10039 #endif
10040 #ifndef __linux__
10041
10042
10043
10044
10045
10046
10047
10048 if (maygvl_copy_stream_wait_read(0, stp) == -1)
10049 return -1;
10050 #endif
10051 if (nogvl_copy_stream_wait_write(stp) == -1)
10052 return -1;
10053 goto retry_sendfile;
10054 }
10055 stp->syserr = "sendfile";
10056 stp->error_no = errno;
10057 return -1;
10058 }
10059 return 1;
10060 }
10061 #endif
10062
10063 static ssize_t
10064 maygvl_read(int has_gvl, int fd, void *buf, size_t count)
10065 {
10066 if (has_gvl)
10067 return rb_read_internal(fd, buf, count);
10068 else
10069 return read(fd, buf, count);
10070 }
10071
10072 static ssize_t
10073 maygvl_copy_stream_read(int has_gvl, struct copy_stream_struct *stp, char *buf, size_t len, off_t offset)
10074 {
10075 ssize_t ss;
10076 retry_read:
10077 if (offset == (off_t)-1) {
10078 ss = maygvl_read(has_gvl, stp->src_fd, buf, len);
10079 }
10080 else {
10081 #ifdef HAVE_PREAD
10082 ss = pread(stp->src_fd, buf, len, offset);
10083 #else
10084 stp->notimp = "pread";
10085 return -1;
10086 #endif
10087 }
10088 if (ss == 0) {
10089 return 0;
10090 }
10091 if (ss == -1) {
10092 if (maygvl_copy_stream_continue_p(has_gvl, stp))
10093 goto retry_read;
10094 switch (errno) {
10095 case EAGAIN:
10096 #if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
10097 case EWOULDBLOCK:
10098 #endif
10099 if (maygvl_copy_stream_wait_read(has_gvl, stp) == -1)
10100 return -1;
10101 goto retry_read;
10102 #ifdef ENOSYS
10103 case ENOSYS:
10104 #endif
10105 stp->notimp = "pread";
10106 return -1;
10107 }
10108 stp->syserr = offset == (off_t)-1 ? "read" : "pread";
10109 stp->error_no = errno;
10110 return -1;
10111 }
10112 return ss;
10113 }
10114
10115 static int
10116 nogvl_copy_stream_write(struct copy_stream_struct *stp, char *buf, size_t len)
10117 {
10118 ssize_t ss;
10119 int off = 0;
10120 while (len) {
10121 ss = write(stp->dst_fd, buf+off, len);
10122 if (ss == -1) {
10123 if (maygvl_copy_stream_continue_p(0, stp))
10124 continue;
10125 if (errno == EAGAIN || errno == EWOULDBLOCK) {
10126 if (nogvl_copy_stream_wait_write(stp) == -1)
10127 return -1;
10128 continue;
10129 }
10130 stp->syserr = "write";
10131 stp->error_no = errno;
10132 return -1;
10133 }
10134 off += (int)ss;
10135 len -= (int)ss;
10136 stp->total += ss;
10137 }
10138 return 0;
10139 }
10140
10141 static void
10142 nogvl_copy_stream_read_write(struct copy_stream_struct *stp)
10143 {
10144 char buf[1024*16];
10145 size_t len;
10146 ssize_t ss;
10147 int ret;
10148 off_t copy_length;
10149 int use_eof;
10150 off_t src_offset;
10151 int use_pread;
10152
10153 copy_length = stp->copy_length;
10154 use_eof = copy_length == (off_t)-1;
10155 src_offset = stp->src_offset;
10156 use_pread = src_offset != (off_t)-1;
10157
10158 if (use_pread && stp->close_src) {
10159 off_t r;
10160 errno = 0;
10161 r = lseek(stp->src_fd, src_offset, SEEK_SET);
10162 if (r == (off_t)-1 && errno) {
10163 stp->syserr = "lseek";
10164 stp->error_no = errno;
10165 return;
10166 }
10167 src_offset = (off_t)-1;
10168 use_pread = 0;
10169 }
10170
10171 while (use_eof || 0 < copy_length) {
10172 if (!use_eof && copy_length < (off_t)sizeof(buf)) {
10173 len = (size_t)copy_length;
10174 }
10175 else {
10176 len = sizeof(buf);
10177 }
10178 if (use_pread) {
10179 ss = maygvl_copy_stream_read(0, stp, buf, len, src_offset);
10180 if (0 < ss)
10181 src_offset += ss;
10182 }
10183 else {
10184 ss = maygvl_copy_stream_read(0, stp, buf, len, (off_t)-1);
10185 }
10186 if (ss <= 0)
10187 return;
10188
10189 ret = nogvl_copy_stream_write(stp, buf, ss);
10190 if (ret < 0)
10191 return;
10192
10193 if (!use_eof)
10194 copy_length -= ss;
10195 }
10196 }
10197
10198 static void *
10199 nogvl_copy_stream_func(void *arg)
10200 {
10201 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
10202 #ifdef USE_SENDFILE
10203 int ret;
10204 #endif
10205
10206 #ifdef USE_SENDFILE
10207 ret = nogvl_copy_stream_sendfile(stp);
10208 if (ret != 0)
10209 goto finish;
10210 #endif
10211
10212 nogvl_copy_stream_read_write(stp);
10213
10214 #ifdef USE_SENDFILE
10215 finish:
10216 #endif
10217 return 0;
10218 }
10219
10220 static VALUE
10221 copy_stream_fallback_body(VALUE arg)
10222 {
10223 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
10224 const int buflen = 16*1024;
10225 VALUE n;
10226 VALUE buf = rb_str_buf_new(buflen);
10227 off_t rest = stp->copy_length;
10228 off_t off = stp->src_offset;
10229 ID read_method = id_readpartial;
10230
10231 if (stp->src_fd == -1) {
10232 if (!rb_respond_to(stp->src, read_method)) {
10233 read_method = id_read;
10234 }
10235 }
10236
10237 while (1) {
10238 long numwrote;
10239 long l;
10240 if (stp->copy_length == (off_t)-1) {
10241 l = buflen;
10242 }
10243 else {
10244 if (rest == 0)
10245 break;
10246 l = buflen < rest ? buflen : (long)rest;
10247 }
10248 if (stp->src_fd == -1) {
10249 VALUE rc = rb_funcall(stp->src, read_method, 2, INT2FIX(l), buf);
10250
10251 if (read_method == id_read && NIL_P(rc))
10252 break;
10253 }
10254 else {
10255 ssize_t ss;
10256 rb_str_resize(buf, buflen);
10257 ss = maygvl_copy_stream_read(1, stp, RSTRING_PTR(buf), l, off);
10258 if (ss == -1)
10259 return Qnil;
10260 if (ss == 0)
10261 rb_eof_error();
10262 rb_str_resize(buf, ss);
10263 if (off != (off_t)-1)
10264 off += ss;
10265 }
10266 n = rb_io_write(stp->dst, buf);
10267 numwrote = NUM2LONG(n);
10268 stp->total += numwrote;
10269 rest -= numwrote;
10270 if (read_method == id_read && RSTRING_LEN(buf) == 0) {
10271 break;
10272 }
10273 }
10274
10275 return Qnil;
10276 }
10277
10278 static VALUE
10279 copy_stream_fallback(struct copy_stream_struct *stp)
10280 {
10281 if (stp->src_fd == -1 && stp->src_offset != (off_t)-1) {
10282 rb_raise(rb_eArgError, "cannot specify src_offset for non-IO");
10283 }
10284 rb_rescue2(copy_stream_fallback_body, (VALUE)stp,
10285 (VALUE (*) (ANYARGS))0, (VALUE)0,
10286 rb_eEOFError, (VALUE)0);
10287 return Qnil;
10288 }
10289
10290 static VALUE
10291 copy_stream_body(VALUE arg)
10292 {
10293 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
10294 VALUE src_io = stp->src, dst_io = stp->dst;
10295 rb_io_t *src_fptr = 0, *dst_fptr = 0;
10296 int src_fd, dst_fd;
10297 const int common_oflags = 0
10298 #ifdef O_NOCTTY
10299 | O_NOCTTY
10300 #endif
10301 ;
10302
10303 stp->th = rb_thread_current();
10304
10305 stp->total = 0;
10306
10307 if (src_io == argf ||
10308 !(RB_TYPE_P(src_io, T_FILE) ||
10309 RB_TYPE_P(src_io, T_STRING) ||
10310 rb_respond_to(src_io, rb_intern("to_path")))) {
10311 src_fd = -1;
10312 }
10313 else {
10314 if (!RB_TYPE_P(src_io, T_FILE)) {
10315 VALUE args[2];
10316 FilePathValue(src_io);
10317 args[0] = src_io;
10318 args[1] = INT2NUM(O_RDONLY|common_oflags);
10319 src_io = rb_class_new_instance(2, args, rb_cFile);
10320 stp->src = src_io;
10321 stp->close_src = 1;
10322 }
10323 GetOpenFile(src_io, src_fptr);
10324 rb_io_check_byte_readable(src_fptr);
10325 src_fd = src_fptr->fd;
10326 }
10327 stp->src_fd = src_fd;
10328
10329 if (dst_io == argf ||
10330 !(RB_TYPE_P(dst_io, T_FILE) ||
10331 RB_TYPE_P(dst_io, T_STRING) ||
10332 rb_respond_to(dst_io, rb_intern("to_path")))) {
10333 dst_fd = -1;
10334 }
10335 else {
10336 if (!RB_TYPE_P(dst_io, T_FILE)) {
10337 VALUE args[3];
10338 FilePathValue(dst_io);
10339 args[0] = dst_io;
10340 args[1] = INT2NUM(O_WRONLY|O_CREAT|O_TRUNC|common_oflags);
10341 args[2] = INT2FIX(0666);
10342 dst_io = rb_class_new_instance(3, args, rb_cFile);
10343 stp->dst = dst_io;
10344 stp->close_dst = 1;
10345 }
10346 else {
10347 dst_io = GetWriteIO(dst_io);
10348 stp->dst = dst_io;
10349 }
10350 GetOpenFile(dst_io, dst_fptr);
10351 rb_io_check_writable(dst_fptr);
10352 dst_fd = dst_fptr->fd;
10353 }
10354 stp->dst_fd = dst_fd;
10355
10356 #ifdef O_BINARY
10357 if (src_fptr)
10358 SET_BINARY_MODE_WITH_SEEK_CUR(src_fptr);
10359 #endif
10360 if (dst_fptr)
10361 io_ascii8bit_binmode(dst_fptr);
10362
10363 if (stp->src_offset == (off_t)-1 && src_fptr && src_fptr->rbuf.len) {
10364 size_t len = src_fptr->rbuf.len;
10365 VALUE str;
10366 if (stp->copy_length != (off_t)-1 && stp->copy_length < (off_t)len) {
10367 len = (size_t)stp->copy_length;
10368 }
10369 str = rb_str_buf_new(len);
10370 rb_str_resize(str,len);
10371 read_buffered_data(RSTRING_PTR(str), len, src_fptr);
10372 if (dst_fptr) {
10373 if (io_binwrite(str, RSTRING_PTR(str), RSTRING_LEN(str), dst_fptr, 0) < 0)
10374 rb_sys_fail(0);
10375 }
10376 else
10377 rb_io_write(dst_io, str);
10378 stp->total += len;
10379 if (stp->copy_length != (off_t)-1)
10380 stp->copy_length -= len;
10381 }
10382
10383 if (dst_fptr && io_fflush(dst_fptr) < 0) {
10384 rb_raise(rb_eIOError, "flush failed");
10385 }
10386
10387 if (stp->copy_length == 0)
10388 return Qnil;
10389
10390 if (src_fd == -1 || dst_fd == -1) {
10391 return copy_stream_fallback(stp);
10392 }
10393
10394 rb_fd_set(src_fd, &stp->fds);
10395 rb_fd_set(dst_fd, &stp->fds);
10396
10397 rb_thread_call_without_gvl(nogvl_copy_stream_func, (void*)stp, RUBY_UBF_IO, 0);
10398 return Qnil;
10399 }
10400
10401 static VALUE
10402 copy_stream_finalize(VALUE arg)
10403 {
10404 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
10405 if (stp->close_src) {
10406 rb_io_close_m(stp->src);
10407 }
10408 if (stp->close_dst) {
10409 rb_io_close_m(stp->dst);
10410 }
10411 rb_fd_term(&stp->fds);
10412 if (stp->syserr) {
10413 errno = stp->error_no;
10414 rb_sys_fail(stp->syserr);
10415 }
10416 if (stp->notimp) {
10417 rb_raise(rb_eNotImpError, "%s() not implemented", stp->notimp);
10418 }
10419 return Qnil;
10420 }
10421
10422
10423
10424
10425
10426
10427
10428
10429
10430
10431
10432
10433
10434
10435
10436
10437
10438
10439
10440
10441
10442
10443
10444
10445
10446
10447
10448
10449
10450 static VALUE
10451 rb_io_s_copy_stream(int argc, VALUE *argv, VALUE io)
10452 {
10453 VALUE src, dst, length, src_offset;
10454 struct copy_stream_struct st;
10455
10456 MEMZERO(&st, struct copy_stream_struct, 1);
10457
10458 rb_scan_args(argc, argv, "22", &src, &dst, &length, &src_offset);
10459
10460 st.src = src;
10461 st.dst = dst;
10462
10463 if (NIL_P(length))
10464 st.copy_length = (off_t)-1;
10465 else
10466 st.copy_length = NUM2OFFT(length);
10467
10468 if (NIL_P(src_offset))
10469 st.src_offset = (off_t)-1;
10470 else
10471 st.src_offset = NUM2OFFT(src_offset);
10472
10473 rb_fd_init(&st.fds);
10474 rb_ensure(copy_stream_body, (VALUE)&st, copy_stream_finalize, (VALUE)&st);
10475
10476 return OFFT2NUM(st.total);
10477 }
10478
10479
10480
10481
10482
10483
10484
10485
10486
10487 static VALUE
10488 rb_io_external_encoding(VALUE io)
10489 {
10490 rb_io_t *fptr;
10491
10492 GetOpenFile(io, fptr);
10493 if (fptr->encs.enc2) {
10494 return rb_enc_from_encoding(fptr->encs.enc2);
10495 }
10496 if (fptr->mode & FMODE_WRITABLE) {
10497 if (fptr->encs.enc)
10498 return rb_enc_from_encoding(fptr->encs.enc);
10499 return Qnil;
10500 }
10501 return rb_enc_from_encoding(io_read_encoding(fptr));
10502 }
10503
10504
10505
10506
10507
10508
10509
10510
10511
10512 static VALUE
10513 rb_io_internal_encoding(VALUE io)
10514 {
10515 rb_io_t *fptr;
10516
10517 GetOpenFile(io, fptr);
10518 if (!fptr->encs.enc2) return Qnil;
10519 return rb_enc_from_encoding(io_read_encoding(fptr));
10520 }
10521
10522
10523
10524
10525
10526
10527
10528
10529
10530
10531
10532
10533
10534
10535
10536
10537
10538
10539
10540
10541 static VALUE
10542 rb_io_set_encoding(int argc, VALUE *argv, VALUE io)
10543 {
10544 rb_io_t *fptr;
10545 VALUE v1, v2, opt;
10546
10547 if (!RB_TYPE_P(io, T_FILE)) {
10548 return rb_funcall2(io, id_set_encoding, argc, argv);
10549 }
10550
10551 argc = rb_scan_args(argc, argv, "11:", &v1, &v2, &opt);
10552 GetOpenFile(io, fptr);
10553 io_encoding_set(fptr, v1, v2, opt);
10554 return io;
10555 }
10556
10557 void
10558 rb_stdio_set_default_encoding(void)
10559 {
10560 extern VALUE rb_stdin, rb_stdout, rb_stderr;
10561 VALUE val = Qnil;
10562
10563 rb_io_set_encoding(1, &val, rb_stdin);
10564 rb_io_set_encoding(1, &val, rb_stdout);
10565 rb_io_set_encoding(1, &val, rb_stderr);
10566 }
10567
10568
10569
10570
10571
10572
10573
10574
10575
10576
10577
10578
10579
10580
10581
10582
10583
10584 static VALUE
10585 argf_external_encoding(VALUE argf)
10586 {
10587 if (!RTEST(ARGF.current_file)) {
10588 return rb_enc_from_encoding(rb_default_external_encoding());
10589 }
10590 return rb_io_external_encoding(rb_io_check_io(ARGF.current_file));
10591 }
10592
10593
10594
10595
10596
10597
10598
10599
10600
10601
10602
10603
10604
10605
10606 static VALUE
10607 argf_internal_encoding(VALUE argf)
10608 {
10609 if (!RTEST(ARGF.current_file)) {
10610 return rb_enc_from_encoding(rb_default_external_encoding());
10611 }
10612 return rb_io_internal_encoding(rb_io_check_io(ARGF.current_file));
10613 }
10614
10615
10616
10617
10618
10619
10620
10621
10622
10623
10624
10625
10626
10627
10628
10629
10630
10631
10632
10633
10634
10635
10636
10637
10638
10639
10640
10641
10642
10643
10644
10645
10646 static VALUE
10647 argf_set_encoding(int argc, VALUE *argv, VALUE argf)
10648 {
10649 rb_io_t *fptr;
10650
10651 if (!next_argv()) {
10652 rb_raise(rb_eArgError, "no stream to set encoding");
10653 }
10654 rb_io_set_encoding(argc, argv, ARGF.current_file);
10655 GetOpenFile(ARGF.current_file, fptr);
10656 ARGF.encs = fptr->encs;
10657 return argf;
10658 }
10659
10660
10661
10662
10663
10664
10665
10666
10667
10668
10669
10670
10671
10672 static VALUE
10673 argf_tell(VALUE argf)
10674 {
10675 if (!next_argv()) {
10676 rb_raise(rb_eArgError, "no stream to tell");
10677 }
10678 ARGF_FORWARD(0, 0);
10679 return rb_io_tell(ARGF.current_file);
10680 }
10681
10682
10683
10684
10685
10686
10687
10688
10689 static VALUE
10690 argf_seek_m(int argc, VALUE *argv, VALUE argf)
10691 {
10692 if (!next_argv()) {
10693 rb_raise(rb_eArgError, "no stream to seek");
10694 }
10695 ARGF_FORWARD(argc, argv);
10696 return rb_io_seek_m(argc, argv, ARGF.current_file);
10697 }
10698
10699
10700
10701
10702
10703
10704
10705
10706
10707
10708
10709
10710 static VALUE
10711 argf_set_pos(VALUE argf, VALUE offset)
10712 {
10713 if (!next_argv()) {
10714 rb_raise(rb_eArgError, "no stream to set position");
10715 }
10716 ARGF_FORWARD(1, &offset);
10717 return rb_io_set_pos(ARGF.current_file, offset);
10718 }
10719
10720
10721
10722
10723
10724
10725
10726
10727
10728
10729
10730
10731
10732 static VALUE
10733 argf_rewind(VALUE argf)
10734 {
10735 if (!next_argv()) {
10736 rb_raise(rb_eArgError, "no stream to rewind");
10737 }
10738 ARGF_FORWARD(0, 0);
10739 return rb_io_rewind(ARGF.current_file);
10740 }
10741
10742
10743
10744
10745
10746
10747
10748
10749
10750
10751
10752 static VALUE
10753 argf_fileno(VALUE argf)
10754 {
10755 if (!next_argv()) {
10756 rb_raise(rb_eArgError, "no stream");
10757 }
10758 ARGF_FORWARD(0, 0);
10759 return rb_io_fileno(ARGF.current_file);
10760 }
10761
10762
10763
10764
10765
10766
10767
10768
10769
10770
10771
10772
10773
10774 static VALUE
10775 argf_to_io(VALUE argf)
10776 {
10777 next_argv();
10778 ARGF_FORWARD(0, 0);
10779 return ARGF.current_file;
10780 }
10781
10782
10783
10784
10785
10786
10787
10788
10789
10790
10791
10792
10793
10794
10795
10796
10797
10798
10799
10800 static VALUE
10801 argf_eof(VALUE argf)
10802 {
10803 next_argv();
10804 if (RTEST(ARGF.current_file)) {
10805 if (ARGF.init_p == 0) return Qtrue;
10806 next_argv();
10807 ARGF_FORWARD(0, 0);
10808 if (rb_io_eof(ARGF.current_file)) {
10809 return Qtrue;
10810 }
10811 }
10812 return Qfalse;
10813 }
10814
10815
10816
10817
10818
10819
10820
10821
10822
10823
10824
10825
10826
10827
10828
10829
10830
10831
10832
10833
10834
10835
10836
10837
10838
10839
10840
10841
10842
10843
10844
10845
10846
10847
10848
10849
10850
10851
10852
10853
10854 static VALUE
10855 argf_read(int argc, VALUE *argv, VALUE argf)
10856 {
10857 VALUE tmp, str, length;
10858 long len = 0;
10859
10860 rb_scan_args(argc, argv, "02", &length, &str);
10861 if (!NIL_P(length)) {
10862 len = NUM2LONG(argv[0]);
10863 }
10864 if (!NIL_P(str)) {
10865 StringValue(str);
10866 rb_str_resize(str,0);
10867 argv[1] = Qnil;
10868 }
10869
10870 retry:
10871 if (!next_argv()) {
10872 return str;
10873 }
10874 if (ARGF_GENERIC_INPUT_P()) {
10875 tmp = argf_forward(argc, argv, argf);
10876 }
10877 else {
10878 tmp = io_read(argc, argv, ARGF.current_file);
10879 }
10880 if (NIL_P(str)) str = tmp;
10881 else if (!NIL_P(tmp)) rb_str_append(str, tmp);
10882 if (NIL_P(tmp) || NIL_P(length)) {
10883 if (ARGF.next_p != -1) {
10884 argf_close(argf);
10885 ARGF.next_p = 1;
10886 goto retry;
10887 }
10888 }
10889 else if (argc >= 1) {
10890 if (RSTRING_LEN(str) < len) {
10891 len -= RSTRING_LEN(str);
10892 argv[0] = INT2NUM(len);
10893 goto retry;
10894 }
10895 }
10896 return str;
10897 }
10898
10899 struct argf_call_arg {
10900 int argc;
10901 VALUE *argv;
10902 VALUE argf;
10903 };
10904
10905 static VALUE
10906 argf_forward_call(VALUE arg)
10907 {
10908 struct argf_call_arg *p = (struct argf_call_arg *)arg;
10909 argf_forward(p->argc, p->argv, p->argf);
10910 return Qnil;
10911 }
10912
10913 static VALUE argf_getpartial(int argc, VALUE *argv, VALUE argf, int nonblock);
10914
10915
10916
10917
10918
10919
10920
10921
10922
10923
10924
10925
10926
10927
10928
10929
10930
10931
10932
10933
10934
10935 static VALUE
10936 argf_readpartial(int argc, VALUE *argv, VALUE argf)
10937 {
10938 return argf_getpartial(argc, argv, argf, 0);
10939 }
10940
10941
10942
10943
10944
10945
10946
10947
10948
10949 static VALUE
10950 argf_read_nonblock(int argc, VALUE *argv, VALUE argf)
10951 {
10952 return argf_getpartial(argc, argv, argf, 1);
10953 }
10954
10955 static VALUE
10956 argf_getpartial(int argc, VALUE *argv, VALUE argf, int nonblock)
10957 {
10958 VALUE tmp, str, length;
10959
10960 rb_scan_args(argc, argv, "11", &length, &str);
10961 if (!NIL_P(str)) {
10962 StringValue(str);
10963 argv[1] = str;
10964 }
10965
10966 if (!next_argv()) {
10967 rb_str_resize(str, 0);
10968 rb_eof_error();
10969 }
10970 if (ARGF_GENERIC_INPUT_P()) {
10971 struct argf_call_arg arg;
10972 arg.argc = argc;
10973 arg.argv = argv;
10974 arg.argf = argf;
10975 tmp = rb_rescue2(argf_forward_call, (VALUE)&arg,
10976 RUBY_METHOD_FUNC(0), Qnil, rb_eEOFError, (VALUE)0);
10977 }
10978 else {
10979 tmp = io_getpartial(argc, argv, ARGF.current_file, nonblock, 0);
10980 }
10981 if (NIL_P(tmp)) {
10982 if (ARGF.next_p == -1) {
10983 rb_eof_error();
10984 }
10985 argf_close(argf);
10986 ARGF.next_p = 1;
10987 if (RARRAY_LEN(ARGF.argv) == 0)
10988 rb_eof_error();
10989 if (NIL_P(str))
10990 str = rb_str_new(NULL, 0);
10991 return str;
10992 }
10993 return tmp;
10994 }
10995
10996
10997
10998
10999
11000
11001
11002
11003
11004
11005
11006
11007
11008
11009
11010
11011
11012
11013
11014
11015
11016
11017
11018
11019 static VALUE
11020 argf_getc(VALUE argf)
11021 {
11022 VALUE ch;
11023
11024 retry:
11025 if (!next_argv()) return Qnil;
11026 if (ARGF_GENERIC_INPUT_P()) {
11027 ch = rb_funcall3(ARGF.current_file, rb_intern("getc"), 0, 0);
11028 }
11029 else {
11030 ch = rb_io_getc(ARGF.current_file);
11031 }
11032 if (NIL_P(ch) && ARGF.next_p != -1) {
11033 argf_close(argf);
11034 ARGF.next_p = 1;
11035 goto retry;
11036 }
11037
11038 return ch;
11039 }
11040
11041
11042
11043
11044
11045
11046
11047
11048
11049
11050
11051
11052
11053
11054
11055
11056
11057
11058
11059 static VALUE
11060 argf_getbyte(VALUE argf)
11061 {
11062 VALUE ch;
11063
11064 retry:
11065 if (!next_argv()) return Qnil;
11066 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
11067 ch = rb_funcall3(ARGF.current_file, rb_intern("getbyte"), 0, 0);
11068 }
11069 else {
11070 ch = rb_io_getbyte(ARGF.current_file);
11071 }
11072 if (NIL_P(ch) && ARGF.next_p != -1) {
11073 argf_close(argf);
11074 ARGF.next_p = 1;
11075 goto retry;
11076 }
11077
11078 return ch;
11079 }
11080
11081
11082
11083
11084
11085
11086
11087
11088
11089
11090
11091
11092
11093
11094
11095
11096
11097
11098
11099 static VALUE
11100 argf_readchar(VALUE argf)
11101 {
11102 VALUE ch;
11103
11104 retry:
11105 if (!next_argv()) rb_eof_error();
11106 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
11107 ch = rb_funcall3(ARGF.current_file, rb_intern("getc"), 0, 0);
11108 }
11109 else {
11110 ch = rb_io_getc(ARGF.current_file);
11111 }
11112 if (NIL_P(ch) && ARGF.next_p != -1) {
11113 argf_close(argf);
11114 ARGF.next_p = 1;
11115 goto retry;
11116 }
11117
11118 return ch;
11119 }
11120
11121
11122
11123
11124
11125
11126
11127
11128
11129
11130
11131
11132
11133
11134
11135
11136
11137
11138
11139 static VALUE
11140 argf_readbyte(VALUE argf)
11141 {
11142 VALUE c;
11143
11144 NEXT_ARGF_FORWARD(0, 0);
11145 c = argf_getbyte(argf);
11146 if (NIL_P(c)) {
11147 rb_eof_error();
11148 }
11149 return c;
11150 }
11151
11152 #define FOREACH_ARGF() while (next_argv())
11153
11154 static VALUE
11155 argf_block_call_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
11156 {
11157 const VALUE current = ARGF.current_file;
11158 rb_yield_values2(argc, argv);
11159 if (ARGF.init_p == -1 || current != ARGF.current_file) {
11160 rb_iter_break_value(Qundef);
11161 }
11162 return Qnil;
11163 }
11164
11165 static void
11166 argf_block_call(ID mid, int argc, VALUE *argv, VALUE argf)
11167 {
11168 VALUE ret = rb_block_call(ARGF.current_file, mid, argc, argv, argf_block_call_i, argf);
11169 if (ret != Qundef) ARGF.next_p = 1;
11170 }
11171
11172
11173
11174
11175
11176
11177
11178
11179
11180
11181
11182
11183
11184
11185
11186
11187
11188
11189
11190
11191
11192
11193
11194
11195
11196
11197
11198
11199
11200
11201
11202
11203
11204 static VALUE
11205 argf_each_line(int argc, VALUE *argv, VALUE argf)
11206 {
11207 RETURN_ENUMERATOR(argf, argc, argv);
11208 FOREACH_ARGF() {
11209 argf_block_call(rb_intern("each_line"), argc, argv, argf);
11210 }
11211 return argf;
11212 }
11213
11214
11215
11216
11217
11218 static VALUE
11219 argf_lines(int argc, VALUE *argv, VALUE argf)
11220 {
11221 rb_warn("ARGF#lines is deprecated; use #each_line instead");
11222 if (!rb_block_given_p())
11223 return rb_enumeratorize(argf, ID2SYM(rb_intern("each_line")), argc, argv);
11224 return argf_each_line(argc, argv, argf);
11225 }
11226
11227
11228
11229
11230
11231
11232
11233
11234
11235
11236
11237
11238
11239
11240
11241
11242
11243
11244
11245
11246
11247
11248
11249
11250
11251 static VALUE
11252 argf_each_byte(VALUE argf)
11253 {
11254 RETURN_ENUMERATOR(argf, 0, 0);
11255 FOREACH_ARGF() {
11256 argf_block_call(rb_intern("each_byte"), 0, 0, argf);
11257 }
11258 return argf;
11259 }
11260
11261
11262
11263
11264
11265 static VALUE
11266 argf_bytes(VALUE argf)
11267 {
11268 rb_warn("ARGF#bytes is deprecated; use #each_byte instead");
11269 if (!rb_block_given_p())
11270 return rb_enumeratorize(argf, ID2SYM(rb_intern("each_byte")), 0, 0);
11271 return argf_each_byte(argf);
11272 }
11273
11274
11275
11276
11277
11278
11279
11280
11281
11282
11283
11284
11285
11286
11287
11288
11289
11290 static VALUE
11291 argf_each_char(VALUE argf)
11292 {
11293 RETURN_ENUMERATOR(argf, 0, 0);
11294 FOREACH_ARGF() {
11295 argf_block_call(rb_intern("each_char"), 0, 0, argf);
11296 }
11297 return argf;
11298 }
11299
11300
11301
11302
11303
11304 static VALUE
11305 argf_chars(VALUE argf)
11306 {
11307 rb_warn("ARGF#chars is deprecated; use #each_char instead");
11308 if (!rb_block_given_p())
11309 return rb_enumeratorize(argf, ID2SYM(rb_intern("each_char")), 0, 0);
11310 return argf_each_char(argf);
11311 }
11312
11313
11314
11315
11316
11317
11318
11319
11320
11321
11322
11323
11324
11325
11326
11327
11328
11329 static VALUE
11330 argf_each_codepoint(VALUE argf)
11331 {
11332 RETURN_ENUMERATOR(argf, 0, 0);
11333 FOREACH_ARGF() {
11334 argf_block_call(rb_intern("each_codepoint"), 0, 0, argf);
11335 }
11336 return argf;
11337 }
11338
11339
11340
11341
11342
11343 static VALUE
11344 argf_codepoints(VALUE argf)
11345 {
11346 rb_warn("ARGF#codepoints is deprecated; use #each_codepoint instead");
11347 if (!rb_block_given_p())
11348 return rb_enumeratorize(argf, ID2SYM(rb_intern("each_codepoint")), 0, 0);
11349 return argf_each_codepoint(argf);
11350 }
11351
11352
11353
11354
11355
11356
11357
11358
11359
11360
11361
11362
11363
11364
11365
11366
11367
11368
11369
11370
11371
11372
11373
11374 static VALUE
11375 argf_filename(VALUE argf)
11376 {
11377 next_argv();
11378 return ARGF.filename;
11379 }
11380
11381 static VALUE
11382 argf_filename_getter(ID id, VALUE *var)
11383 {
11384 return argf_filename(*var);
11385 }
11386
11387
11388
11389
11390
11391
11392
11393
11394
11395
11396
11397
11398
11399
11400
11401
11402
11403
11404
11405 static VALUE
11406 argf_file(VALUE argf)
11407 {
11408 next_argv();
11409 return ARGF.current_file;
11410 }
11411
11412
11413
11414
11415
11416
11417
11418
11419
11420
11421
11422
11423 static VALUE
11424 argf_binmode_m(VALUE argf)
11425 {
11426 ARGF.binmode = 1;
11427 next_argv();
11428 ARGF_FORWARD(0, 0);
11429 rb_io_ascii8bit_binmode(ARGF.current_file);
11430 return argf;
11431 }
11432
11433
11434
11435
11436
11437
11438
11439
11440
11441
11442
11443
11444
11445
11446 static VALUE
11447 argf_binmode_p(VALUE argf)
11448 {
11449 return ARGF.binmode ? Qtrue : Qfalse;
11450 }
11451
11452
11453
11454
11455
11456
11457
11458
11459
11460
11461
11462
11463
11464
11465
11466 static VALUE
11467 argf_skip(VALUE argf)
11468 {
11469 if (ARGF.init_p && ARGF.next_p == 0) {
11470 argf_close(argf);
11471 ARGF.next_p = 1;
11472 }
11473 return argf;
11474 }
11475
11476
11477
11478
11479
11480
11481
11482
11483
11484
11485
11486
11487
11488
11489
11490
11491
11492
11493
11494 static VALUE
11495 argf_close_m(VALUE argf)
11496 {
11497 next_argv();
11498 argf_close(argf);
11499 if (ARGF.next_p != -1) {
11500 ARGF.next_p = 1;
11501 }
11502 ARGF.lineno = 0;
11503 return argf;
11504 }
11505
11506
11507
11508
11509
11510
11511
11512
11513 static VALUE
11514 argf_closed(VALUE argf)
11515 {
11516 next_argv();
11517 ARGF_FORWARD(0, 0);
11518 return rb_io_closed(ARGF.current_file);
11519 }
11520
11521
11522
11523
11524
11525
11526
11527 static VALUE
11528 argf_to_s(VALUE argf)
11529 {
11530 return rb_str_new2("ARGF");
11531 }
11532
11533
11534
11535
11536
11537
11538
11539
11540
11541 static VALUE
11542 argf_inplace_mode_get(VALUE argf)
11543 {
11544 if (!ARGF.inplace) return Qnil;
11545 return rb_str_new2(ARGF.inplace);
11546 }
11547
11548 static VALUE
11549 opt_i_get(ID id, VALUE *var)
11550 {
11551 return argf_inplace_mode_get(*var);
11552 }
11553
11554
11555
11556
11557
11558
11559
11560
11561
11562
11563
11564
11565
11566
11567
11568
11569
11570
11571
11572
11573
11574 static VALUE
11575 argf_inplace_mode_set(VALUE argf, VALUE val)
11576 {
11577 if (rb_safe_level() >= 1 && OBJ_TAINTED(val))
11578 rb_insecure_operation();
11579
11580 if (!RTEST(val)) {
11581 if (ARGF.inplace) free(ARGF.inplace);
11582 ARGF.inplace = 0;
11583 }
11584 else {
11585 StringValue(val);
11586 if (ARGF.inplace) free(ARGF.inplace);
11587 ARGF.inplace = 0;
11588 ARGF.inplace = strdup(RSTRING_PTR(val));
11589 }
11590 return argf;
11591 }
11592
11593 static void
11594 opt_i_set(VALUE val, ID id, VALUE *var)
11595 {
11596 argf_inplace_mode_set(*var, val);
11597 }
11598
11599 const char *
11600 ruby_get_inplace_mode(void)
11601 {
11602 return ARGF.inplace;
11603 }
11604
11605 void
11606 ruby_set_inplace_mode(const char *suffix)
11607 {
11608 if (ARGF.inplace) free(ARGF.inplace);
11609 ARGF.inplace = 0;
11610 if (suffix) ARGF.inplace = strdup(suffix);
11611 }
11612
11613
11614
11615
11616
11617
11618
11619
11620
11621
11622
11623
11624
11625
11626
11627 static VALUE
11628 argf_argv(VALUE argf)
11629 {
11630 return ARGF.argv;
11631 }
11632
11633 static VALUE
11634 argf_argv_getter(ID id, VALUE *var)
11635 {
11636 return argf_argv(*var);
11637 }
11638
11639 VALUE
11640 rb_get_argv(void)
11641 {
11642 return ARGF.argv;
11643 }
11644
11645
11646
11647
11648
11649
11650
11651
11652 static VALUE
11653 argf_write_io(VALUE argf)
11654 {
11655 if (!RTEST(ARGF.current_file)) {
11656 rb_raise(rb_eIOError, "not opened for writing");
11657 }
11658 return GetWriteIO(ARGF.current_file);
11659 }
11660
11661
11662
11663
11664
11665
11666
11667 static VALUE
11668 argf_write(VALUE argf, VALUE str)
11669 {
11670 return rb_io_write(argf_write_io(argf), str);
11671 }
11672
11673 void
11674 rb_readwrite_sys_fail(int writable, const char *mesg)
11675 {
11676 VALUE arg;
11677 int n = errno;
11678 arg = mesg ? rb_str_new2(mesg) : Qnil;
11679 if (writable == RB_IO_WAIT_WRITABLE) {
11680 switch (n) {
11681 case EAGAIN:
11682 rb_exc_raise(rb_class_new_instance(1, &arg, rb_eEAGAINWaitWritable));
11683 break;
11684 #if EAGAIN != EWOULDBLOCK
11685 case EWOULDBLOCK:
11686 rb_exc_raise(rb_class_new_instance(1, &arg, rb_eEWOULDBLOCKWaitWritable));
11687 break;
11688 #endif
11689 case EINPROGRESS:
11690 rb_exc_raise(rb_class_new_instance(1, &arg, rb_eEINPROGRESSWaitWritable));
11691 break;
11692 default:
11693 rb_mod_sys_fail_str(rb_mWaitWritable, arg);
11694 }
11695 }
11696 else if (writable == RB_IO_WAIT_READABLE) {
11697 switch (n) {
11698 case EAGAIN:
11699 rb_exc_raise(rb_class_new_instance(1, &arg, rb_eEAGAINWaitReadable));
11700 break;
11701 #if EAGAIN != EWOULDBLOCK
11702 case EWOULDBLOCK:
11703 rb_exc_raise(rb_class_new_instance(1, &arg, rb_eEWOULDBLOCKWaitReadable));
11704 break;
11705 #endif
11706 case EINPROGRESS:
11707 rb_exc_raise(rb_class_new_instance(1, &arg, rb_eEINPROGRESSWaitReadable));
11708 break;
11709 default:
11710 rb_mod_sys_fail_str(rb_mWaitReadable, arg);
11711 }
11712 }
11713 else {
11714 rb_bug("invalid read/write type passed to rb_readwrite_sys_fail: %d", writable);
11715 }
11716 }
11717
11718
11719
11720
11721
11722
11723
11724
11725
11726
11727
11728
11729
11730
11731
11732
11733
11734
11735
11736
11737
11738
11739
11740
11741
11742
11743
11744
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 void
11874 Init_IO(void)
11875 {
11876 #undef rb_intern
11877 #define rb_intern(str) rb_intern_const(str)
11878
11879 VALUE rb_cARGF;
11880 #ifdef __CYGWIN__
11881 #include <sys/cygwin.h>
11882 static struct __cygwin_perfile pf[] =
11883 {
11884 {"", O_RDONLY | O_BINARY},
11885 {"", O_WRONLY | O_BINARY},
11886 {"", O_RDWR | O_BINARY},
11887 {"", O_APPEND | O_BINARY},
11888 {NULL, 0}
11889 };
11890 cygwin_internal(CW_PERFILE, pf);
11891 #endif
11892
11893 rb_eIOError = rb_define_class("IOError", rb_eStandardError);
11894 rb_eEOFError = rb_define_class("EOFError", rb_eIOError);
11895
11896 id_write = rb_intern("write");
11897 id_read = rb_intern("read");
11898 id_getc = rb_intern("getc");
11899 id_flush = rb_intern("flush");
11900 id_readpartial = rb_intern("readpartial");
11901 id_set_encoding = rb_intern("set_encoding");
11902
11903 rb_define_global_function("syscall", rb_f_syscall, -1);
11904
11905 rb_define_global_function("open", rb_f_open, -1);
11906 rb_define_global_function("printf", rb_f_printf, -1);
11907 rb_define_global_function("print", rb_f_print, -1);
11908 rb_define_global_function("putc", rb_f_putc, 1);
11909 rb_define_global_function("puts", rb_f_puts, -1);
11910 rb_define_global_function("gets", rb_f_gets, -1);
11911 rb_define_global_function("readline", rb_f_readline, -1);
11912 rb_define_global_function("select", rb_f_select, -1);
11913
11914 rb_define_global_function("readlines", rb_f_readlines, -1);
11915
11916 rb_define_global_function("`", rb_f_backquote, 1);
11917
11918 rb_define_global_function("p", rb_f_p, -1);
11919 rb_define_method(rb_mKernel, "display", rb_obj_display, -1);
11920
11921 rb_cIO = rb_define_class("IO", rb_cObject);
11922 rb_include_module(rb_cIO, rb_mEnumerable);
11923
11924 rb_mWaitReadable = rb_define_module_under(rb_cIO, "WaitReadable");
11925 rb_mWaitWritable = rb_define_module_under(rb_cIO, "WaitWritable");
11926 rb_eEAGAINWaitReadable = rb_define_class_under(rb_cIO, "EAGAINWaitReadable", rb_eEAGAIN);
11927 rb_include_module(rb_eEAGAINWaitReadable, rb_mWaitReadable);
11928 rb_eEAGAINWaitWritable = rb_define_class_under(rb_cIO, "EAGAINWaitWritable", rb_eEAGAIN);
11929 rb_include_module(rb_eEAGAINWaitWritable, rb_mWaitWritable);
11930 #if EAGAIN == EWOULDBLOCK
11931 rb_eEWOULDBLOCKWaitReadable = rb_eEAGAINWaitReadable;
11932
11933 rb_define_const(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEAGAINWaitReadable);
11934 rb_eEWOULDBLOCKWaitWritable = rb_eEAGAINWaitWritable;
11935
11936 rb_define_const(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEAGAINWaitWritable);
11937 #else
11938 rb_eEWOULDBLOCKWaitReadable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEWOULDBLOCK);
11939 rb_include_module(rb_eEWOULDBLOCKWaitReadable, rb_mWaitReadable);
11940 rb_eEWOULDBLOCKWaitWritable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEWOULDBLOCK);
11941 rb_include_module(rb_eEWOULDBLOCKWaitWritable, rb_mWaitWritable);
11942 #endif
11943 rb_eEINPROGRESSWaitReadable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitReadable", rb_eEINPROGRESS);
11944 rb_include_module(rb_eEINPROGRESSWaitReadable, rb_mWaitReadable);
11945 rb_eEINPROGRESSWaitWritable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitWritable", rb_eEINPROGRESS);
11946 rb_include_module(rb_eEINPROGRESSWaitWritable, rb_mWaitWritable);
11947
11948 #if 0
11949
11950 rb_define_singleton_method(rb_cFile, "open", rb_io_s_open, -1);
11951 #endif
11952
11953 rb_define_alloc_func(rb_cIO, io_alloc);
11954 rb_define_singleton_method(rb_cIO, "new", rb_io_s_new, -1);
11955 rb_define_singleton_method(rb_cIO, "open", rb_io_s_open, -1);
11956 rb_define_singleton_method(rb_cIO, "sysopen", rb_io_s_sysopen, -1);
11957 rb_define_singleton_method(rb_cIO, "for_fd", rb_io_s_for_fd, -1);
11958 rb_define_singleton_method(rb_cIO, "popen", rb_io_s_popen, -1);
11959 rb_define_singleton_method(rb_cIO, "foreach", rb_io_s_foreach, -1);
11960 rb_define_singleton_method(rb_cIO, "readlines", rb_io_s_readlines, -1);
11961 rb_define_singleton_method(rb_cIO, "read", rb_io_s_read, -1);
11962 rb_define_singleton_method(rb_cIO, "binread", rb_io_s_binread, -1);
11963 rb_define_singleton_method(rb_cIO, "write", rb_io_s_write, -1);
11964 rb_define_singleton_method(rb_cIO, "binwrite", rb_io_s_binwrite, -1);
11965 rb_define_singleton_method(rb_cIO, "select", rb_f_select, -1);
11966 rb_define_singleton_method(rb_cIO, "pipe", rb_io_s_pipe, -1);
11967 rb_define_singleton_method(rb_cIO, "try_convert", rb_io_s_try_convert, 1);
11968 rb_define_singleton_method(rb_cIO, "copy_stream", rb_io_s_copy_stream, -1);
11969
11970 rb_define_method(rb_cIO, "initialize", rb_io_initialize, -1);
11971
11972 rb_output_fs = Qnil;
11973 rb_define_hooked_variable("$,", &rb_output_fs, 0, rb_str_setter);
11974
11975 rb_rs = rb_default_rs = rb_usascii_str_new2("\n");
11976 rb_gc_register_mark_object(rb_default_rs);
11977 rb_output_rs = Qnil;
11978 OBJ_FREEZE(rb_default_rs);
11979 rb_define_hooked_variable("$/", &rb_rs, 0, rb_str_setter);
11980 rb_define_hooked_variable("$-0", &rb_rs, 0, rb_str_setter);
11981 rb_define_hooked_variable("$\\", &rb_output_rs, 0, rb_str_setter);
11982
11983 rb_define_virtual_variable("$_", rb_lastline_get, rb_lastline_set);
11984
11985 rb_define_method(rb_cIO, "initialize_copy", rb_io_init_copy, 1);
11986 rb_define_method(rb_cIO, "reopen", rb_io_reopen, -1);
11987
11988 rb_define_method(rb_cIO, "print", rb_io_print, -1);
11989 rb_define_method(rb_cIO, "putc", rb_io_putc, 1);
11990 rb_define_method(rb_cIO, "puts", rb_io_puts, -1);
11991 rb_define_method(rb_cIO, "printf", rb_io_printf, -1);
11992
11993 rb_define_method(rb_cIO, "each", rb_io_each_line, -1);
11994 rb_define_method(rb_cIO, "each_line", rb_io_each_line, -1);
11995 rb_define_method(rb_cIO, "each_byte", rb_io_each_byte, 0);
11996 rb_define_method(rb_cIO, "each_char", rb_io_each_char, 0);
11997 rb_define_method(rb_cIO, "each_codepoint", rb_io_each_codepoint, 0);
11998 rb_define_method(rb_cIO, "lines", rb_io_lines, -1);
11999 rb_define_method(rb_cIO, "bytes", rb_io_bytes, 0);
12000 rb_define_method(rb_cIO, "chars", rb_io_chars, 0);
12001 rb_define_method(rb_cIO, "codepoints", rb_io_codepoints, 0);
12002
12003 rb_define_method(rb_cIO, "syswrite", rb_io_syswrite, 1);
12004 rb_define_method(rb_cIO, "sysread", rb_io_sysread, -1);
12005
12006 rb_define_method(rb_cIO, "fileno", rb_io_fileno, 0);
12007 rb_define_alias(rb_cIO, "to_i", "fileno");
12008 rb_define_method(rb_cIO, "to_io", rb_io_to_io, 0);
12009
12010 rb_define_method(rb_cIO, "fsync", rb_io_fsync, 0);
12011 rb_define_method(rb_cIO, "fdatasync", rb_io_fdatasync, 0);
12012 rb_define_method(rb_cIO, "sync", rb_io_sync, 0);
12013 rb_define_method(rb_cIO, "sync=", rb_io_set_sync, 1);
12014
12015 rb_define_method(rb_cIO, "lineno", rb_io_lineno, 0);
12016 rb_define_method(rb_cIO, "lineno=", rb_io_set_lineno, 1);
12017
12018 rb_define_method(rb_cIO, "readlines", rb_io_readlines, -1);
12019
12020 rb_define_method(rb_cIO, "read_nonblock", io_read_nonblock, -1);
12021 rb_define_method(rb_cIO, "write_nonblock", rb_io_write_nonblock, -1);
12022 rb_define_method(rb_cIO, "readpartial", io_readpartial, -1);
12023 rb_define_method(rb_cIO, "read", io_read, -1);
12024 rb_define_method(rb_cIO, "write", io_write_m, 1);
12025 rb_define_method(rb_cIO, "gets", rb_io_gets_m, -1);
12026 rb_define_method(rb_cIO, "readline", rb_io_readline, -1);
12027 rb_define_method(rb_cIO, "getc", rb_io_getc, 0);
12028 rb_define_method(rb_cIO, "getbyte", rb_io_getbyte, 0);
12029 rb_define_method(rb_cIO, "readchar", rb_io_readchar, 0);
12030 rb_define_method(rb_cIO, "readbyte", rb_io_readbyte, 0);
12031 rb_define_method(rb_cIO, "ungetbyte",rb_io_ungetbyte, 1);
12032 rb_define_method(rb_cIO, "ungetc",rb_io_ungetc, 1);
12033 rb_define_method(rb_cIO, "<<", rb_io_addstr, 1);
12034 rb_define_method(rb_cIO, "flush", rb_io_flush, 0);
12035 rb_define_method(rb_cIO, "tell", rb_io_tell, 0);
12036 rb_define_method(rb_cIO, "seek", rb_io_seek_m, -1);
12037
12038 rb_define_const(rb_cIO, "SEEK_SET", INT2FIX(SEEK_SET));
12039
12040 rb_define_const(rb_cIO, "SEEK_CUR", INT2FIX(SEEK_CUR));
12041
12042 rb_define_const(rb_cIO, "SEEK_END", INT2FIX(SEEK_END));
12043 #ifdef SEEK_DATA
12044
12045 rb_define_const(rb_cIO, "SEEK_DATA", INT2FIX(SEEK_DATA));
12046 #endif
12047 #ifdef SEEK_HOLE
12048
12049 rb_define_const(rb_cIO, "SEEK_HOLE", INT2FIX(SEEK_HOLE));
12050 #endif
12051 rb_define_method(rb_cIO, "rewind", rb_io_rewind, 0);
12052 rb_define_method(rb_cIO, "pos", rb_io_tell, 0);
12053 rb_define_method(rb_cIO, "pos=", rb_io_set_pos, 1);
12054 rb_define_method(rb_cIO, "eof", rb_io_eof, 0);
12055 rb_define_method(rb_cIO, "eof?", rb_io_eof, 0);
12056
12057 rb_define_method(rb_cIO, "close_on_exec?", rb_io_close_on_exec_p, 0);
12058 rb_define_method(rb_cIO, "close_on_exec=", rb_io_set_close_on_exec, 1);
12059
12060 rb_define_method(rb_cIO, "close", rb_io_close_m, 0);
12061 rb_define_method(rb_cIO, "closed?", rb_io_closed, 0);
12062 rb_define_method(rb_cIO, "close_read", rb_io_close_read, 0);
12063 rb_define_method(rb_cIO, "close_write", rb_io_close_write, 0);
12064
12065 rb_define_method(rb_cIO, "isatty", rb_io_isatty, 0);
12066 rb_define_method(rb_cIO, "tty?", rb_io_isatty, 0);
12067 rb_define_method(rb_cIO, "binmode", rb_io_binmode_m, 0);
12068 rb_define_method(rb_cIO, "binmode?", rb_io_binmode_p, 0);
12069 rb_define_method(rb_cIO, "sysseek", rb_io_sysseek, -1);
12070 rb_define_method(rb_cIO, "advise", rb_io_advise, -1);
12071
12072 rb_define_method(rb_cIO, "ioctl", rb_io_ioctl, -1);
12073 rb_define_method(rb_cIO, "fcntl", rb_io_fcntl, -1);
12074 rb_define_method(rb_cIO, "pid", rb_io_pid, 0);
12075 rb_define_method(rb_cIO, "inspect", rb_io_inspect, 0);
12076
12077 rb_define_method(rb_cIO, "external_encoding", rb_io_external_encoding, 0);
12078 rb_define_method(rb_cIO, "internal_encoding", rb_io_internal_encoding, 0);
12079 rb_define_method(rb_cIO, "set_encoding", rb_io_set_encoding, -1);
12080
12081 rb_define_method(rb_cIO, "autoclose?", rb_io_autoclose_p, 0);
12082 rb_define_method(rb_cIO, "autoclose=", rb_io_set_autoclose, 1);
12083
12084 rb_define_variable("$stdin", &rb_stdin);
12085 rb_stdin = prep_stdio(stdin, FMODE_READABLE, rb_cIO, "<STDIN>");
12086 rb_define_hooked_variable("$stdout", &rb_stdout, 0, stdout_setter);
12087 rb_stdout = prep_stdio(stdout, FMODE_WRITABLE, rb_cIO, "<STDOUT>");
12088 rb_define_hooked_variable("$stderr", &rb_stderr, 0, stdout_setter);
12089 rb_stderr = prep_stdio(stderr, FMODE_WRITABLE|FMODE_SYNC, rb_cIO, "<STDERR>");
12090 rb_define_hooked_variable("$>", &rb_stdout, 0, stdout_setter);
12091 orig_stdout = rb_stdout;
12092 rb_deferr = orig_stderr = rb_stderr;
12093
12094
12095 rb_define_global_const("STDIN", rb_stdin);
12096
12097 rb_define_global_const("STDOUT", rb_stdout);
12098
12099 rb_define_global_const("STDERR", rb_stderr);
12100
12101 #if 0
12102
12103 rb_cARGF = rb_define_class("ARGF", rb_cObject);
12104 #endif
12105
12106 rb_cARGF = rb_class_new(rb_cObject);
12107 rb_set_class_path(rb_cARGF, rb_cObject, "ARGF.class");
12108 rb_define_alloc_func(rb_cARGF, argf_alloc);
12109
12110 rb_include_module(rb_cARGF, rb_mEnumerable);
12111
12112 rb_define_method(rb_cARGF, "initialize", argf_initialize, -2);
12113 rb_define_method(rb_cARGF, "initialize_copy", argf_initialize_copy, 1);
12114 rb_define_method(rb_cARGF, "to_s", argf_to_s, 0);
12115 rb_define_alias(rb_cARGF, "inspect", "to_s");
12116 rb_define_method(rb_cARGF, "argv", argf_argv, 0);
12117
12118 rb_define_method(rb_cARGF, "fileno", argf_fileno, 0);
12119 rb_define_method(rb_cARGF, "to_i", argf_fileno, 0);
12120 rb_define_method(rb_cARGF, "to_io", argf_to_io, 0);
12121 rb_define_method(rb_cARGF, "to_write_io", argf_write_io, 0);
12122 rb_define_method(rb_cARGF, "each", argf_each_line, -1);
12123 rb_define_method(rb_cARGF, "each_line", argf_each_line, -1);
12124 rb_define_method(rb_cARGF, "each_byte", argf_each_byte, 0);
12125 rb_define_method(rb_cARGF, "each_char", argf_each_char, 0);
12126 rb_define_method(rb_cARGF, "each_codepoint", argf_each_codepoint, 0);
12127 rb_define_method(rb_cARGF, "lines", argf_lines, -1);
12128 rb_define_method(rb_cARGF, "bytes", argf_bytes, 0);
12129 rb_define_method(rb_cARGF, "chars", argf_chars, 0);
12130 rb_define_method(rb_cARGF, "codepoints", argf_codepoints, 0);
12131
12132 rb_define_method(rb_cARGF, "read", argf_read, -1);
12133 rb_define_method(rb_cARGF, "readpartial", argf_readpartial, -1);
12134 rb_define_method(rb_cARGF, "read_nonblock", argf_read_nonblock, -1);
12135 rb_define_method(rb_cARGF, "readlines", argf_readlines, -1);
12136 rb_define_method(rb_cARGF, "to_a", argf_readlines, -1);
12137 rb_define_method(rb_cARGF, "gets", argf_gets, -1);
12138 rb_define_method(rb_cARGF, "readline", argf_readline, -1);
12139 rb_define_method(rb_cARGF, "getc", argf_getc, 0);
12140 rb_define_method(rb_cARGF, "getbyte", argf_getbyte, 0);
12141 rb_define_method(rb_cARGF, "readchar", argf_readchar, 0);
12142 rb_define_method(rb_cARGF, "readbyte", argf_readbyte, 0);
12143 rb_define_method(rb_cARGF, "tell", argf_tell, 0);
12144 rb_define_method(rb_cARGF, "seek", argf_seek_m, -1);
12145 rb_define_method(rb_cARGF, "rewind", argf_rewind, 0);
12146 rb_define_method(rb_cARGF, "pos", argf_tell, 0);
12147 rb_define_method(rb_cARGF, "pos=", argf_set_pos, 1);
12148 rb_define_method(rb_cARGF, "eof", argf_eof, 0);
12149 rb_define_method(rb_cARGF, "eof?", argf_eof, 0);
12150 rb_define_method(rb_cARGF, "binmode", argf_binmode_m, 0);
12151 rb_define_method(rb_cARGF, "binmode?", argf_binmode_p, 0);
12152
12153 rb_define_method(rb_cARGF, "write", argf_write, 1);
12154 rb_define_method(rb_cARGF, "print", rb_io_print, -1);
12155 rb_define_method(rb_cARGF, "putc", rb_io_putc, 1);
12156 rb_define_method(rb_cARGF, "puts", rb_io_puts, -1);
12157 rb_define_method(rb_cARGF, "printf", rb_io_printf, -1);
12158
12159 rb_define_method(rb_cARGF, "filename", argf_filename, 0);
12160 rb_define_method(rb_cARGF, "path", argf_filename, 0);
12161 rb_define_method(rb_cARGF, "file", argf_file, 0);
12162 rb_define_method(rb_cARGF, "skip", argf_skip, 0);
12163 rb_define_method(rb_cARGF, "close", argf_close_m, 0);
12164 rb_define_method(rb_cARGF, "closed?", argf_closed, 0);
12165
12166 rb_define_method(rb_cARGF, "lineno", argf_lineno, 0);
12167 rb_define_method(rb_cARGF, "lineno=", argf_set_lineno, 1);
12168
12169 rb_define_method(rb_cARGF, "inplace_mode", argf_inplace_mode_get, 0);
12170 rb_define_method(rb_cARGF, "inplace_mode=", argf_inplace_mode_set, 1);
12171
12172 rb_define_method(rb_cARGF, "external_encoding", argf_external_encoding, 0);
12173 rb_define_method(rb_cARGF, "internal_encoding", argf_internal_encoding, 0);
12174 rb_define_method(rb_cARGF, "set_encoding", argf_set_encoding, -1);
12175
12176 argf = rb_class_new_instance(0, 0, rb_cARGF);
12177
12178 rb_define_readonly_variable("$<", &argf);
12179
12180
12181
12182
12183
12184
12185 rb_define_global_const("ARGF", argf);
12186
12187 rb_define_hooked_variable("$.", &argf, argf_lineno_getter, argf_lineno_setter);
12188 rb_define_hooked_variable("$FILENAME", &argf, argf_filename_getter, rb_gvar_readonly_setter);
12189 ARGF.filename = rb_str_new2("-");
12190
12191 rb_define_hooked_variable("$-i", &argf, opt_i_get, opt_i_set);
12192 rb_define_hooked_variable("$*", &argf, argf_argv_getter, rb_gvar_readonly_setter);
12193
12194 #if defined (_WIN32) || defined(__CYGWIN__)
12195 atexit(pipe_atexit);
12196 #endif
12197
12198 Init_File();
12199
12200 rb_define_method(rb_cFile, "initialize", rb_file_initialize, -1);
12201
12202 sym_mode = ID2SYM(rb_intern("mode"));
12203 sym_perm = ID2SYM(rb_intern("perm"));
12204 sym_extenc = ID2SYM(rb_intern("external_encoding"));
12205 sym_intenc = ID2SYM(rb_intern("internal_encoding"));
12206 sym_encoding = ID2SYM(rb_intern("encoding"));
12207 sym_open_args = ID2SYM(rb_intern("open_args"));
12208 sym_textmode = ID2SYM(rb_intern("textmode"));
12209 sym_binmode = ID2SYM(rb_intern("binmode"));
12210 sym_autoclose = ID2SYM(rb_intern("autoclose"));
12211 sym_normal = ID2SYM(rb_intern("normal"));
12212 sym_sequential = ID2SYM(rb_intern("sequential"));
12213 sym_random = ID2SYM(rb_intern("random"));
12214 sym_willneed = ID2SYM(rb_intern("willneed"));
12215 sym_dontneed = ID2SYM(rb_intern("dontneed"));
12216 sym_noreuse = ID2SYM(rb_intern("noreuse"));
12217 sym_SET = ID2SYM(rb_intern("SET"));
12218 sym_CUR = ID2SYM(rb_intern("CUR"));
12219 sym_END = ID2SYM(rb_intern("END"));
12220 #ifdef SEEK_DATA
12221 sym_DATA = ID2SYM(rb_intern("DATA"));
12222 #endif
12223 #ifdef SEEK_HOLE
12224 sym_HOLE = ID2SYM(rb_intern("HOLE"));
12225 #endif
12226 sym_exception = ID2SYM(rb_intern("exception"));
12227 }
12228