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