mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
2f8d3bdc21
modifying buffer is shared. * array.c (ary_make_shared): make an internal buffer of an array to be shared. * array.c (rb_ary_shift): avoid sliding an internal buffer by using shared buffer. * array.c (rb_ary_subseq): avoid copying the buffer. * parse.y (gettable): should freeze __LINE__ string. * io.c (rb_io_puts): old behavoir restored. rationale: a) if you want to call to_s for arrays, you can just call print a, "\n". b) to_s wastes memory if array (and sum of its contents) is huge. c) now any object that has to_ary is treated as an array, using rb_check_convert_type(). * hash.c (rb_hash_initialize): now accepts a block to calculate the default value. [new] * hash.c (rb_hash_aref): call "default" method to get the value corrensponding to the non existing key. * hash.c (rb_hash_default): get the default value based on the block given to 'new'. Now it takes an optinal "key" argument. "default" became the method to get the value for non existing key. Users may override "default" method to change the hash behavior. * hash.c (rb_hash_set_default): clear the flag if a block is given to 'new' * object.c (Init_Object): undef Data.allocate, left Data.new. * ext/curses/curses.c (window_scrollok): use RTEST(). * ext/curses/curses.c (window_idlok): ditto. * ext/curses/curses.c (window_keypad): ditto. * ext/curses/curses.c (window_idlok): idlok() may return void on some platforms; so don't use return value. * ext/curses/curses.c (window_scrollok): ditto for consistency. * ext/curses/curses.c: replace FIX2INT() by typechecking NUM2INT(). * parse.y (str_extend): should not process immature #$x and #@x interpolation, e.g #@#@ etc. * enum.c (enum_sort_by): sort_by does not have to be stable always. * enum.c (enum_sort_by): call qsort directly to gain performance. * util.c (ruby_qsort): ruby_qsort(qs6) is now native thread safe. * error.c (rb_sys_fail): it must be a bug if it's called when errno == 0. * regex.c (WC2MBC1ST): should not pass through > 0x80 number in UTF-8. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@1896 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
3700 lines
71 KiB
C
3700 lines
71 KiB
C
/**********************************************************************
|
|
|
|
io.c -
|
|
|
|
$Author$
|
|
$Date$
|
|
created at: Fri Oct 15 18:08:59 JST 1993
|
|
|
|
Copyright (C) 1993-2001 Yukihiro Matsumoto
|
|
Copyright (C) 2000 Network Applied Communication Laboratory, Inc.
|
|
Copyright (C) 2000 Information-technology Promotion Agency, Japan
|
|
|
|
**********************************************************************/
|
|
|
|
#include "ruby.h"
|
|
#include "rubyio.h"
|
|
#include "rubysig.h"
|
|
#include "env.h"
|
|
#include <ctype.h>
|
|
#include <errno.h>
|
|
|
|
#if defined(MSDOS) || defined(__BOW__) || defined(__CYGWIN__) || defined(NT) || defined(__human68k__) || defined(__EMX__) || defined(__BEOS__)
|
|
# define NO_SAFE_RENAME
|
|
#endif
|
|
|
|
#if defined(MSDOS) || defined(__CYGWIN__) || defined(NT)
|
|
# define NO_LONG_FNAME
|
|
#endif
|
|
|
|
#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(sun) || defined(_nec_ews)
|
|
# define USE_SETVBUF
|
|
#endif
|
|
|
|
#ifdef __QNXNTO__
|
|
#include "unix.h"
|
|
#endif
|
|
|
|
#include <sys/types.h>
|
|
#if !defined(DJGPP) && !defined(NT) && !defined(__human68k__)
|
|
#include <sys/ioctl.h>
|
|
#endif
|
|
#if defined(HAVE_FCNTL_H) || defined(NT)
|
|
#include <fcntl.h>
|
|
#elif defined(HAVE_SYS_FCNTL_H)
|
|
#include <sys/fcntl.h>
|
|
#endif
|
|
|
|
#ifdef HAVE_SYS_TIME_H
|
|
# include <sys/time.h>
|
|
#else
|
|
#ifndef NT
|
|
struct timeval {
|
|
long tv_sec; /* seconds */
|
|
long tv_usec; /* and microseconds */
|
|
};
|
|
#endif
|
|
#endif
|
|
#ifdef HAVE_VFORK_H
|
|
#include <vfork.h>
|
|
#endif
|
|
|
|
#include <sys/stat.h>
|
|
|
|
/* EMX has sys/parm.h, but.. */
|
|
#if defined(HAVE_SYS_PARAM_H) && !defined(__EMX__)
|
|
# include <sys/param.h>
|
|
#else
|
|
# define NOFILE 64
|
|
#endif
|
|
|
|
#ifdef HAVE_UNISTD_H
|
|
#include <unistd.h>
|
|
#endif
|
|
|
|
extern void Init_File _((void));
|
|
|
|
#ifdef __BEOS__
|
|
# ifndef NOFILE
|
|
# define NOFILE (OPEN_MAX)
|
|
# endif
|
|
#include <net/socket.h>
|
|
#endif
|
|
|
|
#include "util.h"
|
|
|
|
VALUE rb_cIO;
|
|
VALUE rb_eEOFError;
|
|
VALUE rb_eIOError;
|
|
|
|
VALUE rb_stdin, rb_stdout, rb_stderr, rb_defout;
|
|
static VALUE orig_stdin, orig_stdout, orig_stderr;
|
|
static int saved_fd[3] = {0, 1, 2};
|
|
|
|
VALUE rb_output_fs;
|
|
VALUE rb_rs;
|
|
VALUE rb_output_rs;
|
|
VALUE rb_default_rs;
|
|
|
|
static VALUE argf;
|
|
|
|
static ID id_write;
|
|
|
|
extern char *ruby_inplace_mode;
|
|
|
|
struct timeval rb_time_interval _((VALUE));
|
|
|
|
static VALUE filename, current_file;
|
|
static int gets_lineno;
|
|
static int init_p = 0, next_p = 0, first_p = 1;
|
|
static VALUE lineno;
|
|
|
|
#ifdef _STDIO_USES_IOSTREAM /* GNU libc */
|
|
# ifdef _IO_fpos_t
|
|
# define READ_DATA_PENDING(fp) ((fp)->_IO_read_ptr != (fp)->_IO_read_end)
|
|
# define READ_DATA_PENDING_COUNT(fp) ((fp)->_IO_read_end - (fp)->_IO_read_ptr)
|
|
# else
|
|
# define READ_DATA_PENDING(fp) ((fp)->_gptr < (fp)->_egptr)
|
|
# define READ_DATA_PENDING_COUNT(fp) ((fp)->_egptr - (fp)->_gptr)
|
|
# endif
|
|
#elif defined(FILE_COUNT)
|
|
# define READ_DATA_PENDING(fp) ((fp)->FILE_COUNT > 0)
|
|
# define READ_DATA_PENDING_COUNT(fp) ((fp)->FILE_COUNT)
|
|
#elif defined(__BEOS__)
|
|
# define READ_DATA_PENDING(fp) (fp->_state._eof == 0)
|
|
#else
|
|
/* requires systems own version of the ReadDataPending() */
|
|
extern int ReadDataPending();
|
|
# define READ_DATA_PENDING(fp) ReadDataPending(fp)
|
|
#endif
|
|
|
|
#define READ_CHECK(fp) do {\
|
|
if (!READ_DATA_PENDING(fp)) {\
|
|
rb_thread_wait_fd(fileno(fp));\
|
|
rb_io_check_closed(fptr);\
|
|
}\
|
|
} while(0)
|
|
|
|
void
|
|
rb_eof_error()
|
|
{
|
|
rb_raise(rb_eEOFError, "End of file reached");
|
|
}
|
|
|
|
VALUE
|
|
rb_io_taint_check(io)
|
|
VALUE io;
|
|
{
|
|
if (!OBJ_TAINTED(io) && rb_safe_level() >= 4)
|
|
rb_raise(rb_eSecurityError, "Insecure: operation on untainted IO");
|
|
return io;
|
|
}
|
|
|
|
void
|
|
rb_io_check_closed(fptr)
|
|
OpenFile *fptr;
|
|
{
|
|
if (!fptr) {
|
|
rb_raise(rb_eIOError, "uninitialized stream");
|
|
}
|
|
if (!fptr->f && !fptr->f2) {
|
|
rb_raise(rb_eIOError, "closed stream");
|
|
}
|
|
}
|
|
|
|
void
|
|
rb_io_check_readable(fptr)
|
|
OpenFile *fptr;
|
|
{
|
|
if (!(fptr->mode & FMODE_READABLE)) {
|
|
rb_raise(rb_eIOError, "not opened for reading");
|
|
}
|
|
}
|
|
|
|
void
|
|
rb_io_check_writable(fptr)
|
|
OpenFile *fptr;
|
|
{
|
|
if (!(fptr->mode & FMODE_WRITABLE)) {
|
|
rb_raise(rb_eIOError, "not opened for writing");
|
|
}
|
|
}
|
|
|
|
int
|
|
rb_read_pending(fp)
|
|
FILE *fp;
|
|
{
|
|
return READ_DATA_PENDING(fp);
|
|
}
|
|
|
|
void
|
|
rb_read_check(fp)
|
|
FILE *fp;
|
|
{
|
|
if (!READ_DATA_PENDING(fp)) {
|
|
rb_thread_wait_fd(fileno(fp));
|
|
}
|
|
}
|
|
|
|
static int
|
|
ruby_dup(orig)
|
|
int orig;
|
|
{
|
|
int fd;
|
|
|
|
fd = dup(orig);
|
|
if (fd < 0) {
|
|
if (errno == EMFILE || errno == ENFILE) {
|
|
rb_gc();
|
|
fd = dup(orig);
|
|
}
|
|
if (fd < 0) {
|
|
rb_sys_fail(0);
|
|
}
|
|
}
|
|
return fd;
|
|
}
|
|
|
|
static void
|
|
io_fflush(f, path)
|
|
FILE *f;
|
|
const char *path;
|
|
{
|
|
int n;
|
|
|
|
rb_thread_fd_writable(fileno(f));
|
|
TRAP_BEG;
|
|
n = fflush(f);
|
|
TRAP_END;
|
|
if (n == EOF) rb_sys_fail(path);
|
|
}
|
|
|
|
/* writing functions */
|
|
static VALUE
|
|
io_write(io, str)
|
|
VALUE io, str;
|
|
{
|
|
OpenFile *fptr;
|
|
FILE *f;
|
|
int n;
|
|
|
|
rb_secure(4);
|
|
if (TYPE(str) != T_STRING)
|
|
str = rb_obj_as_string(str);
|
|
if (RSTRING(str)->len == 0) return INT2FIX(0);
|
|
|
|
if (TYPE(io) != T_FILE) {
|
|
/* port is not IO, call write method for it. */
|
|
return rb_funcall(io, id_write, 1, str);
|
|
}
|
|
|
|
GetOpenFile(io, fptr);
|
|
rb_io_check_writable(fptr);
|
|
f = GetWriteFile(fptr);
|
|
|
|
#ifdef __human68k__
|
|
{
|
|
register char *ptr = RSTRING(str)->ptr;
|
|
n = (int)RSTRING(str)->len;
|
|
while (--n >= 0)
|
|
if (fputc(*ptr++, f) == EOF)
|
|
rb_sys_fail(fptr->path);
|
|
n = ptr - RSTRING(str)->ptr;
|
|
}
|
|
if (ferror(f))
|
|
rb_sys_fail(fptr->path);
|
|
#else
|
|
n = fwrite(RSTRING(str)->ptr, 1, RSTRING(str)->len, f);
|
|
if (ferror(f)) {
|
|
rb_sys_fail(fptr->path);
|
|
}
|
|
#endif
|
|
if (fptr->mode & FMODE_SYNC) {
|
|
io_fflush(f, fptr->path);
|
|
}
|
|
|
|
return INT2FIX(n);
|
|
}
|
|
|
|
VALUE
|
|
rb_io_write(io, str)
|
|
VALUE io, str;
|
|
{
|
|
return rb_funcall(io, id_write, 1, str);
|
|
}
|
|
|
|
static VALUE
|
|
rb_io_addstr(io, str)
|
|
VALUE io, str;
|
|
{
|
|
rb_io_write(io, str);
|
|
return io;
|
|
}
|
|
|
|
static VALUE
|
|
rb_io_flush(io)
|
|
VALUE io;
|
|
{
|
|
OpenFile *fptr;
|
|
FILE *f;
|
|
|
|
GetOpenFile(io, fptr);
|
|
rb_io_check_writable(fptr);
|
|
f = GetWriteFile(fptr);
|
|
|
|
io_fflush(f, fptr->path);
|
|
|
|
return io;
|
|
}
|
|
|
|
static VALUE
|
|
rb_io_tell(io)
|
|
VALUE io;
|
|
{
|
|
OpenFile *fptr;
|
|
long pos;
|
|
|
|
GetOpenFile(io, fptr);
|
|
pos = ftell(fptr->f);
|
|
if (ferror(fptr->f)) rb_sys_fail(fptr->path);
|
|
|
|
return rb_int2inum(pos);
|
|
}
|
|
|
|
#ifndef SEEK_CUR
|
|
# define SEEK_SET 0
|
|
# define SEEK_CUR 1
|
|
# define SEEK_END 2
|
|
#endif
|
|
|
|
static VALUE
|
|
rb_io_seek(io, offset, whence)
|
|
VALUE io, offset;
|
|
int whence;
|
|
{
|
|
OpenFile *fptr;
|
|
long pos;
|
|
|
|
GetOpenFile(io, fptr);
|
|
pos = fseek(fptr->f, NUM2LONG(offset), whence);
|
|
if (pos != 0) rb_sys_fail(fptr->path);
|
|
clearerr(fptr->f);
|
|
|
|
return INT2FIX(0);
|
|
}
|
|
|
|
static VALUE
|
|
rb_io_seek_m(argc, argv, io)
|
|
int argc;
|
|
VALUE *argv;
|
|
VALUE io;
|
|
{
|
|
VALUE offset, ptrname;
|
|
int whence;
|
|
|
|
rb_scan_args(argc, argv, "11", &offset, &ptrname);
|
|
if (argc == 1) whence = SEEK_SET;
|
|
else whence = NUM2INT(ptrname);
|
|
|
|
return rb_io_seek(io, offset, whence);
|
|
}
|
|
|
|
static VALUE
|
|
rb_io_set_pos(io, offset)
|
|
VALUE io, offset;
|
|
{
|
|
OpenFile *fptr;
|
|
long pos;
|
|
|
|
GetOpenFile(io, fptr);
|
|
pos = fseek(fptr->f, NUM2LONG(offset), SEEK_SET);
|
|
if (pos != 0) rb_sys_fail(fptr->path);
|
|
clearerr(fptr->f);
|
|
|
|
return INT2NUM(pos);
|
|
}
|
|
|
|
static VALUE
|
|
rb_io_rewind(io)
|
|
VALUE io;
|
|
{
|
|
OpenFile *fptr;
|
|
|
|
GetOpenFile(io, fptr);
|
|
if (fseek(fptr->f, 0L, 0) != 0) rb_sys_fail(fptr->path);
|
|
clearerr(fptr->f);
|
|
if (io == current_file) {
|
|
gets_lineno -= fptr->lineno;
|
|
}
|
|
fptr->lineno = 0;
|
|
|
|
return INT2FIX(0);
|
|
}
|
|
|
|
VALUE
|
|
rb_io_eof(io)
|
|
VALUE io;
|
|
{
|
|
OpenFile *fptr;
|
|
int ch;
|
|
|
|
GetOpenFile(io, fptr);
|
|
rb_io_check_readable(fptr);
|
|
|
|
if (feof(fptr->f)) return Qtrue;
|
|
if (READ_DATA_PENDING(fptr->f)) return Qfalse;
|
|
READ_CHECK(fptr->f);
|
|
TRAP_BEG;
|
|
ch = getc(fptr->f);
|
|
TRAP_END;
|
|
|
|
if (ch != EOF) {
|
|
ungetc(ch, fptr->f);
|
|
return Qfalse;
|
|
}
|
|
return Qtrue;
|
|
}
|
|
|
|
static VALUE
|
|
rb_io_sync(io)
|
|
VALUE io;
|
|
{
|
|
OpenFile *fptr;
|
|
|
|
GetOpenFile(io, fptr);
|
|
return (fptr->mode & FMODE_SYNC) ? Qtrue : Qfalse;
|
|
}
|
|
|
|
static VALUE
|
|
rb_io_set_sync(io, mode)
|
|
VALUE io, mode;
|
|
{
|
|
OpenFile *fptr;
|
|
|
|
GetOpenFile(io, fptr);
|
|
if (RTEST(mode)) {
|
|
fptr->mode |= FMODE_SYNC;
|
|
}
|
|
else {
|
|
fptr->mode &= ~FMODE_SYNC;
|
|
}
|
|
return mode;
|
|
}
|
|
|
|
static VALUE
|
|
rb_io_fileno(io)
|
|
VALUE io;
|
|
{
|
|
OpenFile *fptr;
|
|
int fd;
|
|
|
|
GetOpenFile(io, fptr);
|
|
fd = fileno(fptr->f);
|
|
return INT2FIX(fd);
|
|
}
|
|
|
|
static VALUE
|
|
rb_io_pid(io)
|
|
VALUE io;
|
|
{
|
|
OpenFile *fptr;
|
|
|
|
GetOpenFile(io, fptr);
|
|
if (!fptr->pid)
|
|
return Qnil;
|
|
return INT2FIX(fptr->pid);
|
|
}
|
|
|
|
static VALUE
|
|
rb_io_to_io(io)
|
|
VALUE io;
|
|
{
|
|
return io;
|
|
}
|
|
|
|
/* reading functions */
|
|
|
|
static long
|
|
io_fread(ptr, len, f)
|
|
char *ptr;
|
|
long len;
|
|
FILE *f;
|
|
{
|
|
long n = len;
|
|
int c;
|
|
|
|
while (n > 0) {
|
|
#ifdef READ_DATA_PENDING_COUNT
|
|
int i = READ_DATA_PENDING_COUNT(f);
|
|
if (i <= 0) {
|
|
rb_thread_wait_fd(fileno(f));
|
|
i = READ_DATA_PENDING_COUNT(f);
|
|
}
|
|
if (i > 0) {
|
|
if (i > n) i = n;
|
|
TRAP_BEG;
|
|
c = fread(ptr, 1, i, f);
|
|
TRAP_END;
|
|
if (c < 0) goto eof;
|
|
ptr += c;
|
|
n -= c;
|
|
if (c < i) goto eof;
|
|
continue;
|
|
}
|
|
#else
|
|
if (!READ_DATA_PENDING(f)) {
|
|
rb_thread_wait_fd(fileno(f));
|
|
}
|
|
#endif
|
|
TRAP_BEG;
|
|
c = getc(f);
|
|
TRAP_END;
|
|
if (c == EOF) {
|
|
eof:
|
|
if (ferror(f)) {
|
|
if (errno == EINTR) continue;
|
|
if (errno == EAGAIN) return len - n;
|
|
#if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
|
|
if (errno == EWOULDBLOCK) return len - n;
|
|
#endif
|
|
rb_sys_fail(0);
|
|
}
|
|
*ptr = '\0';
|
|
break;
|
|
}
|
|
*ptr++ = c;
|
|
n--;
|
|
}
|
|
|
|
return len - n;
|
|
}
|
|
|
|
#ifndef S_ISREG
|
|
# define S_ISREG(m) ((m & S_IFMT) == S_IFREG)
|
|
#endif
|
|
|
|
#define SMALLBUF 100
|
|
|
|
static VALUE
|
|
read_all(port)
|
|
VALUE port;
|
|
{
|
|
OpenFile *fptr;
|
|
VALUE str = Qnil;
|
|
struct stat st;
|
|
long siz = BUFSIZ;
|
|
long bytes = 0;
|
|
int n;
|
|
|
|
GetOpenFile(port, fptr);
|
|
rb_io_check_readable(fptr);
|
|
|
|
if (feof(fptr->f)) return Qnil;
|
|
if (fstat(fileno(fptr->f), &st) == 0 && S_ISREG(st.st_mode)
|
|
#ifdef __BEOS__
|
|
&& (st.st_dev > 3)
|
|
#endif
|
|
)
|
|
{
|
|
if (st.st_size == 0) {
|
|
getc(fptr->f); /* force EOF */
|
|
return rb_str_new(0, 0);
|
|
}
|
|
else {
|
|
long pos = ftell(fptr->f);
|
|
if (st.st_size > pos && pos >= 0) {
|
|
siz = st.st_size - pos + 1;
|
|
}
|
|
}
|
|
}
|
|
str = rb_tainted_str_new(0, siz);
|
|
READ_CHECK(fptr->f);
|
|
for (;;) {
|
|
n = io_fread(RSTRING(str)->ptr+bytes, siz-bytes, fptr->f);
|
|
if (n == 0 && bytes == 0) {
|
|
if (feof(fptr->f)) return Qnil;
|
|
rb_sys_fail(fptr->path);
|
|
}
|
|
bytes += n;
|
|
if (bytes < siz) break;
|
|
siz += BUFSIZ;
|
|
rb_str_resize(str, siz);
|
|
}
|
|
if (bytes == 0) return rb_str_new(0,0);
|
|
if (bytes != siz) rb_str_resize(str, bytes);
|
|
|
|
return str;
|
|
}
|
|
|
|
static VALUE
|
|
io_read(argc, argv, io)
|
|
int argc;
|
|
VALUE *argv;
|
|
VALUE io;
|
|
{
|
|
OpenFile *fptr;
|
|
int n, len;
|
|
VALUE length, str;
|
|
|
|
rb_scan_args(argc, argv, "01", &length);
|
|
if (NIL_P(length)) {
|
|
return read_all(io);
|
|
}
|
|
|
|
len = NUM2INT(length);
|
|
if (len < 0) {
|
|
rb_raise(rb_eArgError, "negative length %d given", len);
|
|
}
|
|
GetOpenFile(io, fptr);
|
|
rb_io_check_readable(fptr);
|
|
|
|
if (feof(fptr->f)) return Qnil;
|
|
str = rb_str_new(0, len);
|
|
if (len == 0) return str;
|
|
|
|
READ_CHECK(fptr->f);
|
|
n = io_fread(RSTRING(str)->ptr, len, fptr->f);
|
|
if (n == 0) {
|
|
if (feof(fptr->f)) return Qnil;
|
|
rb_sys_fail(fptr->path);
|
|
}
|
|
RSTRING(str)->len = n;
|
|
RSTRING(str)->ptr[n] = '\0';
|
|
OBJ_TAINT(str);
|
|
|
|
return str;
|
|
}
|
|
|
|
static VALUE
|
|
rb_io_gets_internal(argc, argv, io)
|
|
int argc;
|
|
VALUE *argv;
|
|
VALUE io;
|
|
{
|
|
OpenFile *fptr;
|
|
FILE *f;
|
|
VALUE str = Qnil;
|
|
int c, newline;
|
|
char *rsptr;
|
|
int rslen, rspara = 0;
|
|
VALUE rs;
|
|
|
|
if (argc == 0) {
|
|
rs = rb_rs;
|
|
}
|
|
else {
|
|
rb_scan_args(argc, argv, "1", &rs);
|
|
}
|
|
|
|
if (NIL_P(rs)) {
|
|
rsptr = 0;
|
|
rslen = 0;
|
|
}
|
|
else if (rs == rb_default_rs) {
|
|
return rb_io_gets(io);
|
|
}
|
|
else {
|
|
StringValue(rs);
|
|
rslen = RSTRING(rs)->len;
|
|
if (rslen == 0) {
|
|
rsptr = "\n\n";
|
|
rslen = 2;
|
|
rspara = 1;
|
|
}
|
|
else if (rslen == 1 && RSTRING(rs)->ptr[0] == '\n') {
|
|
return rb_io_gets(io);
|
|
}
|
|
else {
|
|
rsptr = RSTRING(rs)->ptr;
|
|
}
|
|
}
|
|
|
|
GetOpenFile(io, fptr);
|
|
rb_io_check_readable(fptr);
|
|
f = fptr->f;
|
|
|
|
if (rspara) {
|
|
do {
|
|
READ_CHECK(f);
|
|
TRAP_BEG;
|
|
c = getc(f);
|
|
TRAP_END;
|
|
if (c != '\n') {
|
|
ungetc(c,f);
|
|
break;
|
|
}
|
|
} while (c != EOF);
|
|
}
|
|
|
|
newline = rslen ? rsptr[rslen - 1] : 0777;
|
|
{
|
|
char buf[8192];
|
|
char *bp, *bpe = buf + sizeof buf - 3;
|
|
int cnt;
|
|
int append = 0;
|
|
|
|
again:
|
|
bp = buf;
|
|
|
|
if (rslen) {
|
|
for (;;) {
|
|
READ_CHECK(f);
|
|
TRAP_BEG;
|
|
c = getc(f);
|
|
TRAP_END;
|
|
if (c == EOF) {
|
|
if (ferror(f)) {
|
|
if (errno == EINTR) continue;
|
|
rb_sys_fail(fptr->path);
|
|
}
|
|
break;
|
|
}
|
|
if ((*bp++ = c) == newline) break;
|
|
if (bp == bpe) break;
|
|
}
|
|
cnt = bp - buf;
|
|
}
|
|
else {
|
|
READ_CHECK(f);
|
|
cnt = io_fread(buf, sizeof(buf), f);
|
|
if (cnt == 0) {
|
|
if (ferror(f)) rb_sys_fail(fptr->path);
|
|
c = EOF;
|
|
}
|
|
else {
|
|
c = 0;
|
|
}
|
|
}
|
|
|
|
if (c == EOF && !append && cnt == 0) {
|
|
str = Qnil;
|
|
goto return_gets;
|
|
}
|
|
|
|
if (append)
|
|
rb_str_cat(str, buf, cnt);
|
|
else
|
|
str = rb_str_new(buf, cnt);
|
|
|
|
if (c != EOF &&
|
|
(!rslen ||
|
|
RSTRING(str)->len < rslen ||
|
|
memcmp(RSTRING(str)->ptr+RSTRING(str)->len-rslen,rsptr,rslen))) {
|
|
append = 1;
|
|
goto again;
|
|
}
|
|
}
|
|
|
|
return_gets:
|
|
if (rspara) {
|
|
while (c != EOF) {
|
|
READ_CHECK(f);
|
|
TRAP_BEG;
|
|
c = getc(f);
|
|
TRAP_END;
|
|
if (c != '\n') {
|
|
ungetc(c, f);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!NIL_P(str)) {
|
|
fptr->lineno++;
|
|
lineno = INT2FIX(fptr->lineno);
|
|
OBJ_TAINT(str);
|
|
}
|
|
|
|
return str;
|
|
}
|
|
|
|
VALUE
|
|
rb_io_gets(io)
|
|
VALUE io;
|
|
{
|
|
OpenFile *fptr;
|
|
FILE *f;
|
|
VALUE str = Qnil;
|
|
int c;
|
|
char buf[8192];
|
|
char *bp, *bpe = buf + sizeof buf - 3;
|
|
int cnt;
|
|
int append = 0;
|
|
|
|
GetOpenFile(io, fptr);
|
|
rb_io_check_readable(fptr);
|
|
f = fptr->f;
|
|
|
|
again:
|
|
bp = buf;
|
|
for (;;) {
|
|
READ_CHECK(f);
|
|
TRAP_BEG;
|
|
c = getc(f);
|
|
TRAP_END;
|
|
if (c == EOF) {
|
|
if (ferror(f)) {
|
|
if (errno == EINTR) continue;
|
|
rb_sys_fail(fptr->path);
|
|
}
|
|
break;
|
|
}
|
|
if ((*bp++ = c) == '\n') break;
|
|
if (bp == bpe) break;
|
|
}
|
|
cnt = bp - buf;
|
|
|
|
if (c == EOF && !append && cnt == 0) {
|
|
str = Qnil;
|
|
goto return_gets;
|
|
}
|
|
|
|
if (append)
|
|
rb_str_cat(str, buf, cnt);
|
|
else
|
|
str = rb_str_new(buf, cnt);
|
|
|
|
if (c != EOF && RSTRING(str)->ptr[RSTRING(str)->len-1] != '\n') {
|
|
append = 1;
|
|
goto again;
|
|
}
|
|
|
|
return_gets:
|
|
if (!NIL_P(str)) {
|
|
fptr->lineno++;
|
|
lineno = INT2FIX(fptr->lineno);
|
|
OBJ_TAINT(str);
|
|
}
|
|
|
|
return str;
|
|
}
|
|
|
|
static VALUE
|
|
rb_io_gets_m(argc, argv, io)
|
|
int argc;
|
|
VALUE *argv;
|
|
VALUE io;
|
|
{
|
|
VALUE str = rb_io_gets_internal(argc, argv, io);
|
|
|
|
if (!NIL_P(str)) {
|
|
rb_lastline_set(str);
|
|
}
|
|
return str;
|
|
}
|
|
|
|
static VALUE
|
|
rb_io_lineno(io)
|
|
VALUE io;
|
|
{
|
|
OpenFile *fptr;
|
|
|
|
GetOpenFile(io, fptr);
|
|
rb_io_check_readable(fptr);
|
|
return INT2NUM(fptr->lineno);
|
|
}
|
|
|
|
static VALUE
|
|
rb_io_set_lineno(io, lineno)
|
|
VALUE io, lineno;
|
|
{
|
|
OpenFile *fptr;
|
|
|
|
GetOpenFile(io, fptr);
|
|
rb_io_check_readable(fptr);
|
|
fptr->lineno = NUM2INT(lineno);
|
|
return lineno;
|
|
}
|
|
|
|
static void
|
|
lineno_setter(val, id, var)
|
|
VALUE val;
|
|
ID id;
|
|
VALUE *var;
|
|
{
|
|
gets_lineno = NUM2INT(val);
|
|
*var = INT2FIX(gets_lineno);
|
|
}
|
|
|
|
static VALUE
|
|
argf_set_lineno(argf, val)
|
|
VALUE argf, val;
|
|
{
|
|
gets_lineno = NUM2INT(val);
|
|
lineno = INT2FIX(gets_lineno);
|
|
return Qnil;
|
|
}
|
|
|
|
static VALUE
|
|
argf_lineno()
|
|
{
|
|
return lineno;
|
|
}
|
|
|
|
static VALUE
|
|
rb_io_readline(argc, argv, io)
|
|
int argc;
|
|
VALUE *argv;
|
|
VALUE io;
|
|
{
|
|
VALUE line = rb_io_gets_m(argc, argv, io);
|
|
|
|
if (NIL_P(line)) {
|
|
rb_eof_error();
|
|
}
|
|
return line;
|
|
}
|
|
|
|
static VALUE
|
|
rb_io_readlines(argc, argv, io)
|
|
int argc;
|
|
VALUE *argv;
|
|
VALUE io;
|
|
{
|
|
VALUE line, ary;
|
|
|
|
ary = rb_ary_new();
|
|
while (!NIL_P(line = rb_io_gets_internal(argc, argv, io))) {
|
|
rb_ary_push(ary, line);
|
|
}
|
|
return ary;
|
|
}
|
|
|
|
static VALUE
|
|
rb_io_each_line(argc, argv, io)
|
|
int argc;
|
|
VALUE *argv;
|
|
VALUE io;
|
|
{
|
|
VALUE str;
|
|
|
|
while (!NIL_P(str = rb_io_gets_internal(argc, argv, io))) {
|
|
rb_yield(str);
|
|
}
|
|
return io;
|
|
}
|
|
|
|
static VALUE
|
|
rb_io_each_byte(io)
|
|
VALUE io;
|
|
{
|
|
OpenFile *fptr;
|
|
FILE *f;
|
|
int c;
|
|
|
|
GetOpenFile(io, fptr);
|
|
rb_io_check_readable(fptr);
|
|
f = fptr->f;
|
|
|
|
for (;;) {
|
|
READ_CHECK(f);
|
|
TRAP_BEG;
|
|
c = getc(f);
|
|
TRAP_END;
|
|
if (c == EOF) {
|
|
if (ferror(f)) {
|
|
if (errno == EINTR) continue;
|
|
rb_sys_fail(fptr->path);
|
|
}
|
|
break;
|
|
}
|
|
rb_yield(INT2FIX(c & 0xff));
|
|
}
|
|
if (ferror(f)) rb_sys_fail(fptr->path);
|
|
return Qnil;
|
|
}
|
|
|
|
VALUE
|
|
rb_io_getc(io)
|
|
VALUE io;
|
|
{
|
|
OpenFile *fptr;
|
|
FILE *f;
|
|
int c;
|
|
|
|
GetOpenFile(io, fptr);
|
|
rb_io_check_readable(fptr);
|
|
f = fptr->f;
|
|
|
|
retry:
|
|
READ_CHECK(f);
|
|
TRAP_BEG;
|
|
c = getc(f);
|
|
TRAP_END;
|
|
|
|
if (c == EOF) {
|
|
if (ferror(f)) {
|
|
if (errno == EINTR) goto retry;
|
|
rb_sys_fail(fptr->path);
|
|
}
|
|
return Qnil;
|
|
}
|
|
return INT2FIX(c & 0xff);
|
|
}
|
|
|
|
int
|
|
rb_getc(f)
|
|
FILE *f;
|
|
{
|
|
int c;
|
|
|
|
if (!READ_DATA_PENDING(f)) {
|
|
rb_thread_wait_fd(fileno(f));
|
|
}
|
|
TRAP_BEG;
|
|
c = getc(f);
|
|
TRAP_END;
|
|
|
|
return c;
|
|
}
|
|
|
|
static VALUE
|
|
rb_io_readchar(io)
|
|
VALUE io;
|
|
{
|
|
VALUE c = rb_io_getc(io);
|
|
|
|
if (NIL_P(c)) {
|
|
rb_eof_error();
|
|
}
|
|
return c;
|
|
}
|
|
|
|
VALUE
|
|
rb_io_ungetc(io, c)
|
|
VALUE io, c;
|
|
{
|
|
OpenFile *fptr;
|
|
int cc = NUM2INT(c);
|
|
|
|
GetOpenFile(io, fptr);
|
|
rb_io_check_readable(fptr);
|
|
|
|
if (ungetc(cc, fptr->f) == EOF)
|
|
rb_sys_fail(fptr->path);
|
|
return Qnil;
|
|
}
|
|
|
|
static VALUE
|
|
rb_io_isatty(io)
|
|
VALUE io;
|
|
{
|
|
OpenFile *fptr;
|
|
|
|
GetOpenFile(io, fptr);
|
|
if (isatty(fileno(fptr->f)) == 0)
|
|
return Qfalse;
|
|
return Qtrue;
|
|
}
|
|
|
|
static void
|
|
fptr_finalize(fptr)
|
|
OpenFile *fptr;
|
|
{
|
|
if (fptr->f) {
|
|
fclose(fptr->f);
|
|
}
|
|
if (fptr->f2) {
|
|
fclose(fptr->f2);
|
|
}
|
|
}
|
|
|
|
static void
|
|
rb_io_fptr_cleanup(fptr)
|
|
OpenFile *fptr;
|
|
{
|
|
if (fptr->finalize) {
|
|
(*fptr->finalize)(fptr);
|
|
}
|
|
else {
|
|
fptr_finalize(fptr);
|
|
}
|
|
fptr->f = fptr->f2 = 0;
|
|
|
|
if (fptr->path) {
|
|
free(fptr->path);
|
|
fptr->path = 0;
|
|
}
|
|
}
|
|
|
|
void
|
|
rb_io_fptr_finalize(fptr)
|
|
OpenFile *fptr;
|
|
{
|
|
if (!fptr) return;
|
|
if (!fptr->f && !fptr->f2) return;
|
|
if (fileno(fptr->f) < 3) return;
|
|
|
|
rb_io_fptr_cleanup(fptr);
|
|
}
|
|
|
|
static void
|
|
rb_io_fptr_close(fptr)
|
|
OpenFile *fptr;
|
|
{
|
|
int fd;
|
|
|
|
if (!fptr) return;
|
|
if (!fptr->f && !fptr->f2) return;
|
|
|
|
fd = fileno(fptr->f);
|
|
rb_io_fptr_cleanup(fptr);
|
|
rb_thread_fd_close(fd);
|
|
}
|
|
|
|
VALUE
|
|
rb_io_close(io)
|
|
VALUE io;
|
|
{
|
|
OpenFile *fptr;
|
|
|
|
fptr = RFILE(io)->fptr;
|
|
rb_io_fptr_close(fptr);
|
|
if (fptr->pid) {
|
|
rb_syswait(fptr->pid);
|
|
fptr->pid = 0;
|
|
}
|
|
|
|
return Qnil;
|
|
}
|
|
|
|
static VALUE
|
|
rb_io_close_m(io)
|
|
VALUE io;
|
|
{
|
|
if (rb_safe_level() >= 4 && !OBJ_TAINTED(io)) {
|
|
rb_raise(rb_eSecurityError, "Insecure: can't close");
|
|
}
|
|
rb_io_close(io);
|
|
return Qnil;
|
|
}
|
|
|
|
static VALUE
|
|
rb_io_closed(io)
|
|
VALUE io;
|
|
{
|
|
OpenFile *fptr;
|
|
|
|
fptr = RFILE(io)->fptr;
|
|
return (fptr->f || fptr->f2)?Qfalse:Qtrue;
|
|
}
|
|
|
|
VALUE
|
|
rb_io_close_read(io)
|
|
VALUE io;
|
|
{
|
|
OpenFile *fptr;
|
|
int n;
|
|
|
|
if (rb_safe_level() >= 4 && !OBJ_TAINTED(io)) {
|
|
rb_raise(rb_eSecurityError, "Insecure: can't close");
|
|
}
|
|
GetOpenFile(io, fptr);
|
|
if (fptr->f2 == 0 && (fptr->mode & FMODE_WRITABLE)) {
|
|
rb_raise(rb_eIOError, "closing non-duplex IO for reading");
|
|
}
|
|
if (fptr->f2 == 0) {
|
|
return rb_io_close(io);
|
|
}
|
|
n = fclose(fptr->f);
|
|
fptr->mode &= ~FMODE_READABLE;
|
|
fptr->f = fptr->f2;
|
|
fptr->f2 = 0;
|
|
if (n != 0) rb_sys_fail(fptr->path);
|
|
|
|
return Qnil;
|
|
}
|
|
|
|
static VALUE
|
|
rb_io_close_write(io)
|
|
VALUE io;
|
|
{
|
|
OpenFile *fptr;
|
|
int n;
|
|
|
|
if (rb_safe_level() >= 4 && !OBJ_TAINTED(io)) {
|
|
rb_raise(rb_eSecurityError, "Insecure: can't close");
|
|
}
|
|
GetOpenFile(io, fptr);
|
|
if (fptr->f2 == 0 && (fptr->mode & FMODE_READABLE)) {
|
|
rb_raise(rb_eIOError, "closing non-duplex IO for writing");
|
|
}
|
|
if (fptr->f2 == 0) {
|
|
return rb_io_close(io);
|
|
}
|
|
n = fclose(fptr->f2);
|
|
fptr->f2 = 0;
|
|
fptr->mode &= ~FMODE_WRITABLE;
|
|
if (n != 0) rb_sys_fail(fptr->path);
|
|
|
|
return Qnil;
|
|
}
|
|
|
|
static VALUE
|
|
rb_io_syswrite(io, str)
|
|
VALUE io, str;
|
|
{
|
|
OpenFile *fptr;
|
|
FILE *f;
|
|
int n;
|
|
|
|
rb_secure(4);
|
|
if (TYPE(str) != T_STRING)
|
|
str = rb_obj_as_string(str);
|
|
|
|
GetOpenFile(io, fptr);
|
|
rb_io_check_writable(fptr);
|
|
f = GetWriteFile(fptr);
|
|
|
|
if (!rb_thread_fd_writable(fileno(f))) {
|
|
rb_io_check_closed(fptr);
|
|
}
|
|
n = write(fileno(f), RSTRING(str)->ptr, RSTRING(str)->len);
|
|
|
|
if (n == -1) rb_sys_fail(fptr->path);
|
|
|
|
return INT2FIX(n);
|
|
}
|
|
|
|
static VALUE
|
|
rb_io_sysread(io, len)
|
|
VALUE io, len;
|
|
{
|
|
OpenFile *fptr;
|
|
int n, ilen;
|
|
VALUE str;
|
|
|
|
ilen = NUM2INT(len);
|
|
GetOpenFile(io, fptr);
|
|
rb_io_check_readable(fptr);
|
|
|
|
if (READ_DATA_PENDING(fptr->f)) {
|
|
rb_raise(rb_eIOError, "sysread for buffered IO");
|
|
}
|
|
str = rb_str_new(0, ilen);
|
|
|
|
n = fileno(fptr->f);
|
|
rb_thread_wait_fd(fileno(fptr->f));
|
|
TRAP_BEG;
|
|
n = read(fileno(fptr->f), RSTRING(str)->ptr, RSTRING(str)->len);
|
|
TRAP_END;
|
|
|
|
if (n == -1) rb_sys_fail(fptr->path);
|
|
if (n == 0 && ilen > 0) {
|
|
rb_eof_error();
|
|
}
|
|
|
|
RSTRING(str)->len = n;
|
|
RSTRING(str)->ptr[n] = '\0';
|
|
OBJ_TAINT(str);
|
|
|
|
return str;
|
|
}
|
|
|
|
VALUE
|
|
rb_io_binmode(io)
|
|
VALUE io;
|
|
{
|
|
#if defined(NT) || defined(DJGPP) || defined(__CYGWIN__) || defined(__human68k__) || defined(__EMX__)
|
|
OpenFile *fptr;
|
|
|
|
GetOpenFile(io, fptr);
|
|
#ifdef __human68k__
|
|
if (fptr->f)
|
|
fmode(fptr->f, _IOBIN);
|
|
if (fptr->f2)
|
|
fmode(fptr->f2, _IOBIN);
|
|
#else
|
|
if (fptr->f && setmode(fileno(fptr->f), O_BINARY) == -1)
|
|
rb_sys_fail(fptr->path);
|
|
if (fptr->f2 && setmode(fileno(fptr->f2), O_BINARY) == -1)
|
|
rb_sys_fail(fptr->path);
|
|
#endif
|
|
|
|
fptr->mode |= FMODE_BINMODE;
|
|
#endif
|
|
return io;
|
|
}
|
|
|
|
int
|
|
rb_io_mode_flags(mode)
|
|
const char *mode;
|
|
{
|
|
int flags = 0;
|
|
const char *m = mode;
|
|
|
|
switch (*m++) {
|
|
case 'r':
|
|
flags |= FMODE_READABLE;
|
|
break;
|
|
case 'w':
|
|
flags |= FMODE_WRITABLE;
|
|
break;
|
|
case 'a':
|
|
flags |= FMODE_WRITABLE;
|
|
break;
|
|
default:
|
|
error:
|
|
rb_raise(rb_eArgError, "illegal access mode %s", mode);
|
|
}
|
|
|
|
if (*m == 'b') {
|
|
flags |= FMODE_BINMODE;
|
|
m++;
|
|
}
|
|
|
|
if (*m == '+') {
|
|
flags |= FMODE_READWRITE;
|
|
if (m[1] != 0) goto error;
|
|
}
|
|
else if (*m != 0) goto error;
|
|
|
|
return flags;
|
|
}
|
|
|
|
static int
|
|
rb_io_binmode_flags(mode)
|
|
int mode;
|
|
{
|
|
int flags;
|
|
|
|
switch (mode & (O_RDONLY|O_WRONLY|O_RDWR)) {
|
|
case O_RDONLY:
|
|
flags = FMODE_READABLE;
|
|
break;
|
|
case O_WRONLY:
|
|
flags = FMODE_WRITABLE;
|
|
break;
|
|
case O_RDWR:
|
|
flags = FMODE_WRITABLE|FMODE_READABLE;
|
|
break;
|
|
}
|
|
|
|
#ifdef O_BINARY
|
|
if (mode & O_BINARY) {
|
|
flags |= FMODE_BINMODE;
|
|
}
|
|
#endif
|
|
|
|
return flags;
|
|
}
|
|
|
|
static int
|
|
rb_io_mode_binmode(mode)
|
|
const char *mode;
|
|
{
|
|
int flags = 0;
|
|
const char *m = mode;
|
|
|
|
switch (*m++) {
|
|
case 'r':
|
|
flags |= O_RDONLY;
|
|
break;
|
|
case 'w':
|
|
flags |= O_WRONLY | O_CREAT | O_TRUNC;
|
|
break;
|
|
case 'a':
|
|
flags |= O_WRONLY | O_CREAT | O_APPEND;
|
|
break;
|
|
default:
|
|
error:
|
|
rb_raise(rb_eArgError, "illegal access mode %s", mode);
|
|
}
|
|
|
|
if (*m == 'b') {
|
|
#ifdef O_BINARY
|
|
flags |= O_BINARY;
|
|
#endif
|
|
m++;
|
|
}
|
|
|
|
if (*m == '+') {
|
|
flags |= O_RDWR;
|
|
if (m[1] != 0) goto error;
|
|
}
|
|
else if (*m != 0) goto error;
|
|
|
|
return flags;
|
|
}
|
|
|
|
static char*
|
|
rb_io_binmode_mode(flags, mode)
|
|
int flags;
|
|
char *mode;
|
|
{
|
|
char *p = mode;
|
|
|
|
switch (flags & (O_RDONLY|O_WRONLY|O_RDWR)) {
|
|
case O_RDONLY:
|
|
*p++ = 'r';
|
|
break;
|
|
case O_WRONLY:
|
|
*p++ = 'w';
|
|
break;
|
|
case O_RDWR:
|
|
*p++ = 'w';
|
|
*p++ = '+';
|
|
break;
|
|
}
|
|
*p++ = '\0';
|
|
#ifdef O_BINARY
|
|
if (flags & O_BINARY) {
|
|
if (mode[1] == '+') {
|
|
mode[1] = 'b'; mode[2] = '+'; mode[3] = '\0';
|
|
}
|
|
else {
|
|
mode[1] = 'b'; mode[2] = '\0';
|
|
}
|
|
}
|
|
#endif
|
|
return mode;
|
|
}
|
|
|
|
static int
|
|
rb_sysopen(fname, flags, mode)
|
|
char *fname;
|
|
int flags;
|
|
unsigned int mode;
|
|
{
|
|
int fd;
|
|
|
|
fd = open(fname, flags, mode);
|
|
if (fd < 0) {
|
|
if (errno == EMFILE || errno == ENFILE) {
|
|
rb_gc();
|
|
fd = open(fname, flags, mode);
|
|
}
|
|
if (fd < 0) {
|
|
rb_sys_fail(fname);
|
|
}
|
|
}
|
|
return fd;
|
|
}
|
|
|
|
FILE *
|
|
rb_fopen(fname, mode)
|
|
const char *fname;
|
|
const char *mode;
|
|
{
|
|
FILE *file;
|
|
|
|
file = fopen(fname, mode);
|
|
if (!file) {
|
|
if (errno == EMFILE || errno == ENFILE) {
|
|
rb_gc();
|
|
file = fopen(fname, mode);
|
|
}
|
|
if (!file) {
|
|
rb_sys_fail(fname);
|
|
}
|
|
}
|
|
#ifdef USE_SETVBUF
|
|
if (setvbuf(file, NULL, _IOFBF, 0) != 0)
|
|
rb_warn("setvbuf() can't be honered for %s", fname);
|
|
#endif
|
|
#ifdef __human68k__
|
|
fmode(file, _IOTEXT);
|
|
#endif
|
|
return file;
|
|
}
|
|
|
|
FILE *
|
|
rb_fdopen(fd, mode)
|
|
int fd;
|
|
const char *mode;
|
|
{
|
|
FILE *file;
|
|
|
|
file = fdopen(fd, mode);
|
|
if (!file) {
|
|
if (errno == EMFILE || errno == ENFILE) {
|
|
rb_gc();
|
|
file = fdopen(fd, mode);
|
|
}
|
|
if (!file) {
|
|
rb_sys_fail(0);
|
|
}
|
|
}
|
|
|
|
#ifdef USE_SETVBUF
|
|
if (setvbuf(file, NULL, _IOFBF, 0) != 0)
|
|
rb_warn("setvbuf() can't be honered (fd=%d)", fd);
|
|
#endif
|
|
return file;
|
|
}
|
|
|
|
static VALUE
|
|
rb_file_open_internal(io, fname, mode)
|
|
VALUE io;
|
|
const char *fname, *mode;
|
|
{
|
|
OpenFile *fptr;
|
|
|
|
MakeOpenFile(io, fptr);
|
|
|
|
fptr->mode = rb_io_mode_flags(mode);
|
|
fptr->f = rb_fopen(fname, mode);
|
|
fptr->path = strdup(fname);
|
|
|
|
return io;
|
|
}
|
|
|
|
VALUE
|
|
rb_file_open(fname, mode)
|
|
const char *fname, *mode;
|
|
{
|
|
VALUE io = rb_obj_alloc(rb_cFile);
|
|
|
|
return rb_file_open_internal(io, fname, mode);
|
|
}
|
|
|
|
static VALUE
|
|
rb_file_sysopen_internal(io, fname, flags, mode)
|
|
VALUE io;
|
|
char *fname;
|
|
int flags, mode;
|
|
{
|
|
OpenFile *fptr;
|
|
int fd;
|
|
char *m;
|
|
char mbuf[4];
|
|
|
|
MakeOpenFile(io, fptr);
|
|
|
|
fd = rb_sysopen(fname, flags, mode);
|
|
m = rb_io_binmode_mode(flags, mbuf);
|
|
fptr->mode = rb_io_binmode_flags(flags);
|
|
fptr->f = rb_fdopen(fd, m);
|
|
fptr->path = strdup(fname);
|
|
|
|
return io;
|
|
}
|
|
|
|
VALUE
|
|
rb_file_sysopen(fname, flags, mode)
|
|
const char *fname;
|
|
int flags, mode;
|
|
{
|
|
VALUE io = rb_obj_alloc(rb_cFile);
|
|
|
|
return rb_file_sysopen_internal(io, fname, flags, mode);
|
|
}
|
|
|
|
#if defined (NT) || defined(DJGPP) || defined(__CYGWIN__) || defined(__human68k__)
|
|
static struct pipe_list {
|
|
OpenFile *fptr;
|
|
struct pipe_list *next;
|
|
} *pipe_list;
|
|
|
|
static void
|
|
pipe_add_fptr(fptr)
|
|
OpenFile *fptr;
|
|
{
|
|
struct pipe_list *list;
|
|
|
|
list = ALLOC(struct pipe_list);
|
|
list->fptr = fptr;
|
|
list->next = pipe_list;
|
|
pipe_list = list;
|
|
}
|
|
|
|
static void
|
|
pipe_del_fptr(fptr)
|
|
OpenFile *fptr;
|
|
{
|
|
struct pipe_list *list = pipe_list;
|
|
struct pipe_list *tmp;
|
|
|
|
if (list->fptr == fptr) {
|
|
pipe_list = list->next;
|
|
free(list);
|
|
return;
|
|
}
|
|
|
|
while (list->next) {
|
|
if (list->next->fptr == fptr) {
|
|
tmp = list->next;
|
|
list->next = list->next->next;
|
|
free(tmp);
|
|
return;
|
|
}
|
|
list = list->next;
|
|
}
|
|
}
|
|
|
|
#if defined (NT) || defined(DJGPP) || defined(__CYGWIN__) || defined(__human68k__)
|
|
static void
|
|
pipe_atexit _((void))
|
|
{
|
|
struct pipe_list *list = pipe_list;
|
|
struct pipe_list *tmp;
|
|
|
|
while (list) {
|
|
tmp = list->next;
|
|
rb_io_fptr_finalize(list->fptr);
|
|
list = tmp;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
static void pipe_finalize _((OpenFile *fptr));
|
|
|
|
static void
|
|
pipe_finalize(fptr)
|
|
OpenFile *fptr;
|
|
{
|
|
#if !defined (__CYGWIN__)
|
|
extern VALUE rb_last_status;
|
|
int status;
|
|
if (fptr->f) {
|
|
status = pclose(fptr->f);
|
|
}
|
|
if (fptr->f2) {
|
|
status = pclose(fptr->f2);
|
|
}
|
|
fptr->f = fptr->f2 = 0;
|
|
#if defined DJGPP
|
|
status <<= 8;
|
|
#endif
|
|
rb_last_status = INT2FIX(status);
|
|
#else
|
|
fptr_finalize(fptr);
|
|
#endif
|
|
pipe_del_fptr(fptr);
|
|
}
|
|
#endif
|
|
|
|
void
|
|
rb_io_synchronized(fptr)
|
|
OpenFile *fptr;
|
|
{
|
|
fptr->mode |= FMODE_SYNC;
|
|
}
|
|
|
|
void
|
|
rb_io_unbuffered(fptr)
|
|
OpenFile *fptr;
|
|
{
|
|
rb_io_synchronized(fptr);
|
|
}
|
|
|
|
static VALUE
|
|
pipe_open(pname, mode)
|
|
char *pname, *mode;
|
|
{
|
|
int modef = rb_io_mode_flags(mode);
|
|
OpenFile *fptr;
|
|
|
|
#if defined(NT) || defined(DJGPP) || defined(__human68k__)
|
|
FILE *f = popen(pname, mode);
|
|
|
|
if (!f) rb_sys_fail(pname);
|
|
else {
|
|
VALUE port = rb_obj_alloc(rb_cIO);
|
|
|
|
MakeOpenFile(port, fptr);
|
|
fptr->finalize = pipe_finalize;
|
|
fptr->mode = modef;
|
|
|
|
pipe_add_fptr(fptr);
|
|
if (modef & FMODE_READABLE) fptr->f = f;
|
|
if (modef & FMODE_WRITABLE) {
|
|
if (fptr->f) fptr->f2 = f;
|
|
else fptr->f = f;
|
|
rb_io_synchronized(fptr);
|
|
}
|
|
return (VALUE)port;
|
|
}
|
|
#else
|
|
int pid, pr[2], pw[2];
|
|
volatile int doexec;
|
|
|
|
if (((modef & FMODE_READABLE) && pipe(pr) == -1) ||
|
|
((modef & FMODE_WRITABLE) && pipe(pw) == -1))
|
|
rb_sys_fail(pname);
|
|
|
|
doexec = (strcmp("-", pname) != 0);
|
|
if (!doexec) {
|
|
fflush(stdin); /* is it really needed? */
|
|
fflush(stdout);
|
|
fflush(stderr);
|
|
}
|
|
|
|
retry:
|
|
switch (pid = (doexec?vfork():fork())) {
|
|
case 0: /* child */
|
|
if (modef & FMODE_READABLE) {
|
|
close(pr[0]);
|
|
if (pr[1] != 1) {
|
|
dup2(pr[1], 1);
|
|
close(pr[1]);
|
|
}
|
|
}
|
|
if (modef & FMODE_WRITABLE) {
|
|
close(pw[1]);
|
|
if (pw[0] != 0) {
|
|
dup2(pw[0], 0);
|
|
close(pw[0]);
|
|
}
|
|
}
|
|
|
|
if (doexec) {
|
|
int fd;
|
|
|
|
for (fd = 3; fd < NOFILE; fd++)
|
|
close(fd);
|
|
rb_proc_exec(pname);
|
|
fprintf(stderr, "%s:%d: command not found: %s\n",
|
|
ruby_sourcefile, ruby_sourceline, pname);
|
|
_exit(127);
|
|
}
|
|
rb_io_synchronized(RFILE(orig_stdout)->fptr);
|
|
rb_io_synchronized(RFILE(orig_stderr)->fptr);
|
|
return Qnil;
|
|
|
|
case -1: /* fork failed */
|
|
if (errno == EAGAIN) {
|
|
rb_thread_sleep(1);
|
|
goto retry;
|
|
}
|
|
close(pr[0]); close(pw[1]);
|
|
rb_sys_fail(pname);
|
|
break;
|
|
|
|
default: /* parent */
|
|
if (pid < 0) rb_sys_fail(pname);
|
|
else {
|
|
VALUE port = rb_obj_alloc(rb_cIO);
|
|
|
|
MakeOpenFile(port, fptr);
|
|
fptr->mode = modef;
|
|
fptr->mode |= FMODE_SYNC;
|
|
fptr->pid = pid;
|
|
|
|
if (modef & FMODE_READABLE) {
|
|
close(pr[1]);
|
|
fptr->f = rb_fdopen(pr[0], "r");
|
|
}
|
|
if (modef & FMODE_WRITABLE) {
|
|
FILE *f = rb_fdopen(pw[1], "w");
|
|
|
|
close(pw[0]);
|
|
if (fptr->f) fptr->f2 = f;
|
|
else fptr->f = f;
|
|
}
|
|
#if defined (__CYGWIN__)
|
|
fptr->finalize = pipe_finalize;
|
|
pipe_add_fptr(fptr);
|
|
#endif
|
|
return (VALUE)port;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
static VALUE
|
|
rb_io_popen(str, argc, argv, klass)
|
|
char *str;
|
|
int argc;
|
|
VALUE *argv;
|
|
VALUE klass;
|
|
{
|
|
char *mode;
|
|
VALUE pname, pmode, port;
|
|
char mbuf[4];
|
|
|
|
if (rb_scan_args(argc, argv, "11", &pname, &pmode) == 1) {
|
|
mode = "r";
|
|
}
|
|
else if (FIXNUM_P(pmode)) {
|
|
mode = rb_io_binmode_mode(FIX2INT(pmode), mbuf);
|
|
}
|
|
else {
|
|
mode = StringValuePtr(pmode);
|
|
}
|
|
SafeStringValue(pname);
|
|
port = pipe_open(str, mode);
|
|
if (NIL_P(port)) {
|
|
/* child */
|
|
if (rb_block_given_p()) {
|
|
rb_yield(Qnil);
|
|
fflush(stdout);
|
|
fflush(stderr);
|
|
_exit(0);
|
|
}
|
|
return Qnil;
|
|
}
|
|
RBASIC(port)->klass = klass;
|
|
if (rb_block_given_p()) {
|
|
return rb_ensure(rb_yield, port, rb_io_close, port);
|
|
}
|
|
return port;
|
|
}
|
|
|
|
static VALUE
|
|
rb_io_s_popen(argc, argv, klass)
|
|
int argc;
|
|
VALUE *argv;
|
|
VALUE klass;
|
|
{
|
|
char *str = 0;
|
|
|
|
if (argc >= 1) {
|
|
str = StringValuePtr(argv[0]);
|
|
}
|
|
return rb_io_popen(str, argc, argv, klass);
|
|
}
|
|
|
|
static VALUE
|
|
rb_open_file(argc, argv, io)
|
|
int argc;
|
|
VALUE *argv;
|
|
VALUE io;
|
|
{
|
|
VALUE fname, vmode, file, perm;
|
|
char *path, *mode;
|
|
int flags, fmode;
|
|
|
|
rb_scan_args(argc, argv, "12", &fname, &vmode, &perm);
|
|
SafeStringValue(fname);
|
|
path = RSTRING(fname)->ptr;
|
|
|
|
if (FIXNUM_P(vmode) || !NIL_P(perm)) {
|
|
flags = FIXNUM_P(vmode) ? NUM2INT(vmode) : rb_io_mode_binmode(StringValuePtr(vmode));
|
|
fmode = NIL_P(perm) ? 0666 : NUM2INT(perm);
|
|
|
|
file = rb_file_sysopen_internal(io, path, flags, fmode);
|
|
}
|
|
else {
|
|
mode = NIL_P(vmode) ? "r" : StringValuePtr(vmode);
|
|
file = rb_file_open_internal(io, RSTRING(fname)->ptr, mode);
|
|
}
|
|
return io;
|
|
}
|
|
|
|
static VALUE
|
|
rb_file_s_open(argc, argv, klass)
|
|
int argc;
|
|
VALUE *argv;
|
|
VALUE klass;
|
|
{
|
|
VALUE io = rb_obj_alloc(klass);
|
|
|
|
RFILE(io)->fptr = 0;
|
|
rb_open_file(argc, argv, (VALUE)io);
|
|
if (rb_block_given_p()) {
|
|
return rb_ensure(rb_yield, (VALUE)io, rb_io_close, (VALUE)io);
|
|
}
|
|
|
|
return (VALUE)io;
|
|
}
|
|
|
|
static VALUE
|
|
rb_f_open(argc, argv)
|
|
int argc;
|
|
VALUE *argv;
|
|
{
|
|
if (argc >= 1) {
|
|
char *str = StringValuePtr(argv[0]);
|
|
|
|
if (str[0] == '|') {
|
|
return rb_io_popen(str+1, argc, argv, rb_cIO);
|
|
}
|
|
}
|
|
return rb_file_s_open(argc, argv, rb_cFile);
|
|
}
|
|
|
|
static VALUE
|
|
rb_io_open(fname, mode)
|
|
char *fname, *mode;
|
|
{
|
|
if (fname[0] == '|') {
|
|
return pipe_open(fname+1, mode);
|
|
}
|
|
else {
|
|
return rb_file_open(fname, mode);
|
|
}
|
|
}
|
|
|
|
static VALUE
|
|
rb_io_get_io(io)
|
|
VALUE io;
|
|
{
|
|
return rb_convert_type(io, T_FILE, "IO", "to_io");
|
|
}
|
|
|
|
static char*
|
|
rb_io_mode_string(fptr)
|
|
OpenFile *fptr;
|
|
{
|
|
switch (fptr->mode & FMODE_READWRITE) {
|
|
case FMODE_READABLE:
|
|
default:
|
|
return "r";
|
|
case FMODE_WRITABLE:
|
|
return "w";
|
|
case FMODE_READWRITE:
|
|
return "r+";
|
|
}
|
|
}
|
|
|
|
static VALUE
|
|
io_reopen(io, nfile)
|
|
VALUE io, nfile;
|
|
{
|
|
OpenFile *fptr, *orig;
|
|
char *mode;
|
|
int fd;
|
|
long pos;
|
|
|
|
nfile = rb_io_get_io(nfile);
|
|
if (rb_safe_level() >= 4 && (!OBJ_TAINTED(io) || !OBJ_TAINTED(nfile))) {
|
|
rb_raise(rb_eSecurityError, "Insecure: can't reopen");
|
|
}
|
|
GetOpenFile(io, fptr);
|
|
GetOpenFile(nfile, orig);
|
|
|
|
if (fptr == orig) return io;
|
|
if (orig->mode & FMODE_READABLE) {
|
|
pos = ftell(orig->f);
|
|
}
|
|
if (orig->f2) {
|
|
io_fflush(orig->f2, orig->path);
|
|
}
|
|
else if (orig->mode & FMODE_WRITABLE) {
|
|
io_fflush(orig->f, orig->path);
|
|
}
|
|
rb_thread_fd_close(fileno(fptr->f));
|
|
|
|
/* copy OpenFile structure */
|
|
fptr->mode = orig->mode;
|
|
fptr->pid = orig->pid;
|
|
fptr->lineno = orig->lineno;
|
|
if (fptr->path) free(fptr->path);
|
|
if (orig->path) fptr->path = strdup(orig->path);
|
|
else fptr->path = 0;
|
|
fptr->finalize = orig->finalize;
|
|
|
|
mode = rb_io_mode_string(fptr);
|
|
fd = fileno(fptr->f);
|
|
if (fd < 3) {
|
|
clearerr(fptr->f);
|
|
/* need to keep stdio objects */
|
|
if (dup2(fileno(orig->f), fd) < 0)
|
|
rb_sys_fail(orig->path);
|
|
}
|
|
else {
|
|
fclose(fptr->f);
|
|
if (dup2(fileno(orig->f), fd) < 0)
|
|
rb_sys_fail(orig->path);
|
|
fptr->f = rb_fdopen(fd, mode);
|
|
}
|
|
if ((orig->mode & FMODE_READABLE) && pos >= 0) {
|
|
fseek(fptr->f, pos, SEEK_SET);
|
|
fseek(orig->f, pos, SEEK_SET);
|
|
}
|
|
|
|
if (fptr->f2) {
|
|
fd = fileno(fptr->f2);
|
|
fclose(fptr->f2);
|
|
if (orig->f2) {
|
|
if (dup2(fileno(orig->f2), fd) < 0)
|
|
rb_sys_fail(orig->path);
|
|
fptr->f2 = rb_fdopen(fd, "w");
|
|
}
|
|
else {
|
|
fptr->f2 = 0;
|
|
}
|
|
}
|
|
|
|
if (fptr->mode & FMODE_BINMODE) {
|
|
rb_io_binmode(io);
|
|
}
|
|
|
|
RBASIC(io)->klass = RBASIC(nfile)->klass;
|
|
return io;
|
|
}
|
|
|
|
static VALUE
|
|
rb_io_reopen(argc, argv, file)
|
|
int argc;
|
|
VALUE *argv;
|
|
VALUE file;
|
|
{
|
|
VALUE fname, nmode;
|
|
char *mode;
|
|
OpenFile *fptr;
|
|
|
|
rb_secure(4);
|
|
if (rb_scan_args(argc, argv, "11", &fname, &nmode) == 1) {
|
|
if (TYPE(fname) != T_STRING) { /* fname must be IO */
|
|
return io_reopen(file, fname);
|
|
}
|
|
}
|
|
|
|
SafeStringValue(fname);
|
|
if (!NIL_P(nmode)) {
|
|
mode = StringValuePtr(nmode);
|
|
}
|
|
else {
|
|
mode = "r";
|
|
}
|
|
|
|
GetOpenFile(file, fptr);
|
|
if (fptr->path) {
|
|
free(fptr->path);
|
|
fptr->path = 0;
|
|
}
|
|
|
|
fptr->path = strdup(RSTRING(fname)->ptr);
|
|
fptr->mode = rb_io_mode_flags(mode);
|
|
if (!fptr->f) {
|
|
fptr->f = rb_fopen(RSTRING(fname)->ptr, mode);
|
|
if (fptr->f2) {
|
|
fclose(fptr->f2);
|
|
fptr->f2 = 0;
|
|
}
|
|
|
|
return file;
|
|
}
|
|
|
|
if (freopen(RSTRING(fname)->ptr, mode, fptr->f) == 0) {
|
|
rb_sys_fail(fptr->path);
|
|
}
|
|
#ifdef USE_SETVBUF
|
|
if (setvbuf(fptr->f, NULL, _IOFBF, 0) != 0)
|
|
rb_warn("setvbuf() can't be honered for %s", RSTRING(fname)->ptr);
|
|
#endif
|
|
|
|
if (fptr->f2) {
|
|
if (freopen(RSTRING(fname)->ptr, "w", fptr->f2) == 0) {
|
|
rb_sys_fail(fptr->path);
|
|
}
|
|
}
|
|
|
|
return file;
|
|
}
|
|
|
|
static VALUE
|
|
rb_io_clone(io)
|
|
VALUE io;
|
|
{
|
|
OpenFile *fptr, *orig;
|
|
int fd;
|
|
char *mode;
|
|
VALUE clone = rb_obj_clone(io);
|
|
|
|
GetOpenFile(io, orig);
|
|
MakeOpenFile(clone, fptr);
|
|
|
|
if (orig->f2) {
|
|
io_fflush(orig->f2, orig->path);
|
|
}
|
|
else if (orig->mode & FMODE_WRITABLE) {
|
|
io_fflush(orig->f, orig->path);
|
|
}
|
|
|
|
/* copy OpenFile structure */
|
|
fptr->mode = orig->mode;
|
|
fptr->pid = orig->pid;
|
|
fptr->lineno = orig->lineno;
|
|
if (orig->path) fptr->path = strdup(orig->path);
|
|
fptr->finalize = orig->finalize;
|
|
|
|
switch (fptr->mode & FMODE_READWRITE) {
|
|
case FMODE_READABLE:
|
|
default:
|
|
mode = "r"; break;
|
|
case FMODE_WRITABLE:
|
|
mode = "w"; break;
|
|
case FMODE_READWRITE:
|
|
if (orig->f2) mode = "r";
|
|
else mode = "r+";
|
|
break;
|
|
}
|
|
fd = ruby_dup(fileno(orig->f));
|
|
fptr->f = rb_fdopen(fd, mode);
|
|
if (fptr->f2) {
|
|
if (fileno(orig->f) != fileno(orig->f2)) {
|
|
fd = ruby_dup(fileno(orig->f2));
|
|
}
|
|
fptr->f = rb_fdopen(fd, "w");
|
|
}
|
|
if (fptr->mode & FMODE_BINMODE) {
|
|
rb_io_binmode((VALUE)clone);
|
|
}
|
|
|
|
return (VALUE)clone;
|
|
}
|
|
|
|
static VALUE
|
|
rb_io_printf(argc, argv, out)
|
|
int argc;
|
|
VALUE argv[];
|
|
VALUE out;
|
|
{
|
|
rb_io_write(out, rb_f_sprintf(argc, argv));
|
|
return Qnil;
|
|
}
|
|
|
|
static VALUE
|
|
rb_f_printf(argc, argv)
|
|
int argc;
|
|
VALUE argv[];
|
|
{
|
|
VALUE out;
|
|
|
|
if (argc == 0) return Qnil;
|
|
if (TYPE(argv[0]) == T_STRING) {
|
|
out = rb_defout;
|
|
}
|
|
else {
|
|
out = argv[0];
|
|
argv++;
|
|
argc--;
|
|
}
|
|
rb_io_write(out, rb_f_sprintf(argc, argv));
|
|
|
|
return Qnil;
|
|
}
|
|
|
|
static VALUE
|
|
rb_io_print(argc, argv, out)
|
|
int argc;
|
|
VALUE *argv;
|
|
VALUE out;
|
|
{
|
|
int i;
|
|
VALUE line;
|
|
|
|
/* if no argument given, print `$_' */
|
|
if (argc == 0) {
|
|
argc = 1;
|
|
line = rb_lastline_get();
|
|
argv = &line;
|
|
}
|
|
for (i=0; i<argc; i++) {
|
|
if (!NIL_P(rb_output_fs) && i>0) {
|
|
rb_io_write(out, rb_output_fs);
|
|
}
|
|
switch (TYPE(argv[i])) {
|
|
case T_NIL:
|
|
rb_io_write(out, rb_str_new2("nil"));
|
|
break;
|
|
default:
|
|
rb_io_write(out, argv[i]);
|
|
break;
|
|
}
|
|
}
|
|
if (!NIL_P(rb_output_rs)) {
|
|
rb_io_write(out, rb_output_rs);
|
|
}
|
|
|
|
return Qnil;
|
|
}
|
|
|
|
static VALUE
|
|
rb_f_print(argc, argv)
|
|
int argc;
|
|
VALUE *argv;
|
|
{
|
|
rb_io_print(argc, argv, rb_defout);
|
|
return Qnil;
|
|
}
|
|
|
|
static VALUE
|
|
rb_io_putc(io, ch)
|
|
VALUE io, ch;
|
|
{
|
|
OpenFile *fptr;
|
|
FILE *f;
|
|
int c = NUM2CHR(ch);
|
|
|
|
rb_secure(4);
|
|
GetOpenFile(io, fptr);
|
|
rb_io_check_writable(fptr);
|
|
f = GetWriteFile(fptr);
|
|
|
|
if (fputc(c, f) == EOF)
|
|
rb_sys_fail(fptr->path);
|
|
if (fptr->mode & FMODE_SYNC) {
|
|
io_fflush(f, fptr->path);
|
|
}
|
|
|
|
return ch;
|
|
}
|
|
|
|
static VALUE
|
|
rb_f_putc(recv, ch)
|
|
VALUE recv, ch;
|
|
{
|
|
return rb_io_putc(rb_defout, ch);
|
|
}
|
|
|
|
static VALUE rb_io_puts _((int, VALUE*, VALUE));
|
|
|
|
static VALUE
|
|
io_puts_ary(ary, out)
|
|
VALUE ary, out;
|
|
{
|
|
VALUE tmp;
|
|
int i;
|
|
|
|
for (i=0; i<RARRAY(ary)->len; i++) {
|
|
tmp = RARRAY(ary)->ptr[i];
|
|
if (rb_inspecting_p(tmp)) {
|
|
tmp = rb_str_new2("[...]");
|
|
}
|
|
rb_io_puts(1, &tmp, out);
|
|
}
|
|
return Qnil;
|
|
}
|
|
|
|
static VALUE
|
|
rb_io_puts(argc, argv, out)
|
|
int argc;
|
|
VALUE *argv;
|
|
VALUE out;
|
|
{
|
|
int i;
|
|
VALUE line;
|
|
|
|
/* if no argument given, print newline. */
|
|
if (argc == 0) {
|
|
rb_io_write(out, rb_default_rs);
|
|
return Qnil;
|
|
}
|
|
for (i=0; i<argc; i++) {
|
|
if (NIL_P(argv[i])) {
|
|
line = rb_str_new2("nil");
|
|
}
|
|
else {
|
|
line = rb_check_convert_type(argv[i], T_ARRAY, "Array", "to_ary");
|
|
if (!NIL_P(line)) {
|
|
rb_protect_inspect(io_puts_ary, line, out);
|
|
continue;
|
|
}
|
|
line = rb_obj_as_string(argv[i]);
|
|
}
|
|
rb_io_write(out, line);
|
|
if (RSTRING(line)->ptr[RSTRING(line)->len-1] != '\n') {
|
|
rb_io_write(out, rb_default_rs);
|
|
}
|
|
}
|
|
|
|
return Qnil;
|
|
}
|
|
|
|
static VALUE
|
|
rb_f_puts(argc, argv)
|
|
int argc;
|
|
VALUE *argv;
|
|
{
|
|
rb_io_puts(argc, argv, rb_defout);
|
|
return Qnil;
|
|
}
|
|
|
|
void
|
|
rb_p(obj) /* for debug print within C code */
|
|
VALUE obj;
|
|
{
|
|
rb_io_write(rb_defout, rb_obj_as_string(rb_inspect(obj)));
|
|
rb_io_write(rb_defout, rb_default_rs);
|
|
}
|
|
|
|
static VALUE
|
|
rb_f_p(argc, argv)
|
|
int argc;
|
|
VALUE *argv;
|
|
{
|
|
int i;
|
|
|
|
for (i=0; i<argc; i++) {
|
|
rb_p(argv[i]);
|
|
}
|
|
if (TYPE(rb_defout) == T_FILE) {
|
|
rb_io_flush(rb_defout);
|
|
}
|
|
return Qnil;
|
|
}
|
|
|
|
static VALUE
|
|
rb_obj_display(argc, argv, self)
|
|
int argc;
|
|
VALUE *argv;
|
|
VALUE self;
|
|
{
|
|
VALUE out;
|
|
|
|
if (rb_scan_args(argc, argv, "01", &out) == 0) {
|
|
out = rb_defout;
|
|
}
|
|
|
|
rb_io_write(out, self);
|
|
|
|
return Qnil;
|
|
}
|
|
|
|
static void
|
|
rb_io_defset(val, id)
|
|
VALUE val;
|
|
ID id;
|
|
{
|
|
if (!rb_respond_to(val, id_write)) {
|
|
rb_raise(rb_eTypeError, "$> must have write method, %s given",
|
|
rb_class2name(CLASS_OF(val)));
|
|
}
|
|
rb_defout = val;
|
|
}
|
|
|
|
static void
|
|
set_stdin(val, id, var)
|
|
VALUE val;
|
|
ID id;
|
|
VALUE *var;
|
|
{
|
|
OpenFile *fptr;
|
|
|
|
if (val == *var) return;
|
|
if (TYPE(val) != T_FILE) {
|
|
*var = val;
|
|
return;
|
|
}
|
|
if (TYPE(*var) != T_FILE) {
|
|
*var = orig_stdin;
|
|
}
|
|
|
|
GetOpenFile(val, fptr);
|
|
rb_io_check_readable(fptr);
|
|
if (fileno(fptr->f) == 0 && saved_fd[0] != 0) {
|
|
dup2(saved_fd[0], 0);
|
|
close(saved_fd[0]);
|
|
saved_fd[0] = 0;
|
|
}
|
|
else {
|
|
saved_fd[0] = dup(0);
|
|
dup2(fileno(fptr->f), 0);
|
|
}
|
|
|
|
*var = val;
|
|
}
|
|
|
|
static void
|
|
set_outfile(val, var, orig, stdf)
|
|
VALUE val;
|
|
VALUE *var;
|
|
VALUE orig;
|
|
FILE *stdf;
|
|
{
|
|
OpenFile *fptr;
|
|
FILE *f;
|
|
int fd;
|
|
|
|
if (val == *var) return;
|
|
|
|
if (TYPE(*var) == T_FILE && !rb_io_closed(*var)) {
|
|
rb_io_flush(*var);
|
|
}
|
|
if (TYPE(val) != T_FILE) {
|
|
*var = val;
|
|
return;
|
|
}
|
|
if (TYPE(*var) != T_FILE) {
|
|
*var = orig;
|
|
}
|
|
|
|
GetOpenFile(val, fptr);
|
|
rb_io_check_writable(fptr);
|
|
f = GetWriteFile(fptr);
|
|
fd = fileno(stdf);
|
|
if (fileno(fptr->f) == fd && saved_fd[fd] != fd) {
|
|
dup2(saved_fd[fd], fd);
|
|
close(saved_fd[fd]);
|
|
saved_fd[fd] = fd;
|
|
}
|
|
else {
|
|
saved_fd[fd] = dup(fd);
|
|
dup2(fileno(fptr->f), fd);
|
|
}
|
|
|
|
*var = val;
|
|
}
|
|
|
|
static void
|
|
set_stdout(val, id, var)
|
|
VALUE val;
|
|
ID id;
|
|
VALUE *var;
|
|
{
|
|
set_outfile(val, var, orig_stdout, stdout);
|
|
}
|
|
|
|
static void
|
|
set_stderr(val, id, var)
|
|
VALUE val;
|
|
ID id;
|
|
VALUE *var;
|
|
{
|
|
set_outfile(val, var, orig_stderr, stderr);
|
|
}
|
|
|
|
static VALUE
|
|
prep_stdio(f, mode, klass)
|
|
FILE *f;
|
|
int mode;
|
|
VALUE klass;
|
|
{
|
|
OpenFile *fp;
|
|
VALUE io = rb_obj_alloc(klass);
|
|
|
|
MakeOpenFile(io, fp);
|
|
fp->f = f;
|
|
fp->mode = mode;
|
|
|
|
return (VALUE)io;
|
|
}
|
|
|
|
static void
|
|
prep_path(io, path)
|
|
VALUE io;
|
|
char *path;
|
|
{
|
|
OpenFile *fptr;
|
|
|
|
GetOpenFile(io, fptr);
|
|
if (fptr->path) rb_bug("illegal prep_path() call");
|
|
fptr->path = strdup(path);
|
|
}
|
|
|
|
static VALUE
|
|
rb_io_s_alloc(klass)
|
|
VALUE klass;
|
|
{
|
|
NEWOBJ(io, struct RFile);
|
|
OBJSETUP(io, klass, T_FILE);
|
|
|
|
io->fptr = 0;
|
|
|
|
return (VALUE)io;
|
|
}
|
|
|
|
static VALUE
|
|
rb_io_initialize(argc, argv, io)
|
|
int argc;
|
|
VALUE *argv;
|
|
VALUE io;
|
|
{
|
|
VALUE fnum, mode;
|
|
OpenFile *fp;
|
|
char *m = "r";
|
|
|
|
if (rb_scan_args(argc, argv, "11", &fnum, &mode) == 2) {
|
|
SafeStringValue(mode);
|
|
m = RSTRING(mode)->ptr;
|
|
}
|
|
MakeOpenFile(io, fp);
|
|
fp->f = rb_fdopen(NUM2INT(fnum), m);
|
|
fp->mode = rb_io_mode_flags(m);
|
|
|
|
return io;
|
|
}
|
|
|
|
static VALUE
|
|
rb_file_initialize(argc, argv, io)
|
|
int argc;
|
|
VALUE *argv;
|
|
VALUE io;
|
|
{
|
|
if (RFILE(io)->fptr) {
|
|
rb_io_close_m(io);
|
|
free(RFILE(io)->fptr);
|
|
RFILE(io)->fptr = 0;
|
|
}
|
|
rb_open_file(argc, argv, io);
|
|
if (rb_block_given_p()) {
|
|
rb_warn("File::new() does not take block; use File::open() instead");
|
|
}
|
|
|
|
return io;
|
|
}
|
|
|
|
static VALUE
|
|
rb_io_s_for_fd(argc, argv, klass)
|
|
int argc;
|
|
VALUE *argv;
|
|
VALUE klass;
|
|
{
|
|
VALUE fnum, mode;
|
|
OpenFile *fp;
|
|
char *m = "r";
|
|
VALUE io = rb_obj_alloc(klass);
|
|
|
|
if (rb_scan_args(argc, argv, "11", &fnum, &mode) == 2) {
|
|
SafeStringValue(mode);
|
|
m = RSTRING(mode)->ptr;
|
|
}
|
|
MakeOpenFile(io, fp);
|
|
|
|
fp->f = rb_fdopen(NUM2INT(fnum), m);
|
|
fp->mode = rb_io_mode_flags(m);
|
|
|
|
return io;
|
|
}
|
|
|
|
static int binmode = 0;
|
|
|
|
static VALUE
|
|
argf_forward()
|
|
{
|
|
return rb_funcall3(current_file, ruby_frame->last_func,
|
|
ruby_frame->argc, ruby_frame->argv);
|
|
}
|
|
|
|
static VALUE
|
|
argf_binmode()
|
|
{
|
|
if (TYPE(current_file) != T_FILE) {
|
|
argf_forward();
|
|
}
|
|
else {
|
|
rb_io_binmode(current_file);
|
|
}
|
|
binmode = 1;
|
|
return argf;
|
|
}
|
|
|
|
static int
|
|
next_argv()
|
|
{
|
|
extern VALUE rb_argv;
|
|
char *fn;
|
|
|
|
if (init_p == 0) {
|
|
if (RARRAY(rb_argv)->len > 0) {
|
|
next_p = 1;
|
|
}
|
|
else {
|
|
next_p = -1;
|
|
current_file = rb_stdin;
|
|
filename = rb_str_new2("-");
|
|
}
|
|
init_p = 1;
|
|
first_p = 0;
|
|
gets_lineno = 0;
|
|
}
|
|
|
|
retry:
|
|
if (next_p == 1) {
|
|
next_p = 0;
|
|
if (RARRAY(rb_argv)->len > 0) {
|
|
filename = rb_ary_shift(rb_argv);
|
|
fn = StringValuePtr(filename);
|
|
if (strlen(fn) == 1 && fn[0] == '-') {
|
|
current_file = rb_stdin;
|
|
if (ruby_inplace_mode) {
|
|
rb_warn("Can't do inplace edit for stdio");
|
|
rb_defout = rb_stdout;
|
|
}
|
|
}
|
|
else {
|
|
FILE *fr = rb_fopen(fn, "r");
|
|
|
|
if (ruby_inplace_mode) {
|
|
struct stat st, st2;
|
|
VALUE str;
|
|
FILE *fw;
|
|
|
|
if (TYPE(rb_defout) == T_FILE && rb_defout != rb_stdout) {
|
|
rb_io_close(rb_defout);
|
|
}
|
|
fstat(fileno(fr), &st);
|
|
if (*ruby_inplace_mode) {
|
|
str = rb_str_new2(fn);
|
|
#ifdef NO_LONG_FNAME
|
|
ruby_add_suffix(str, ruby_inplace_mode);
|
|
#else
|
|
rb_str_cat2(str, ruby_inplace_mode);
|
|
#endif
|
|
#ifdef NO_SAFE_RENAME
|
|
(void)fclose(fr);
|
|
(void)unlink(RSTRING(str)->ptr);
|
|
(void)rename(fn, RSTRING(str)->ptr);
|
|
fr = rb_fopen(RSTRING(str)->ptr, "r");
|
|
#else
|
|
if (rename(fn, RSTRING(str)->ptr) < 0) {
|
|
rb_warn("Can't rename %s to %s: %s, skipping file",
|
|
fn, RSTRING(str)->ptr, strerror(errno));
|
|
fclose(fr);
|
|
goto retry;
|
|
}
|
|
#endif
|
|
}
|
|
else {
|
|
#ifdef NO_SAFE_RENAME
|
|
rb_fatal("Can't do inplace edit without backup");
|
|
#else
|
|
if (unlink(fn) < 0) {
|
|
rb_warn("Can't remove %s: %s, skipping file",
|
|
fn, strerror(errno));
|
|
fclose(fr);
|
|
goto retry;
|
|
}
|
|
#endif
|
|
}
|
|
fw = rb_fopen(fn, "w");
|
|
#ifndef NO_SAFE_RENAME
|
|
fstat(fileno(fw), &st2);
|
|
#ifdef HAVE_FCHMOD
|
|
fchmod(fileno(fw), st.st_mode);
|
|
#else
|
|
chmod(fn, st.st_mode);
|
|
#endif
|
|
if (st.st_uid!=st2.st_uid || st.st_gid!=st2.st_gid) {
|
|
fchown(fileno(fw), st.st_uid, st.st_gid);
|
|
}
|
|
#endif
|
|
rb_defout = prep_stdio(fw, FMODE_WRITABLE, rb_cFile);
|
|
prep_path(rb_defout, fn);
|
|
}
|
|
current_file = prep_stdio(fr, FMODE_READABLE, rb_cFile);
|
|
prep_path(current_file, fn);
|
|
}
|
|
if (binmode) rb_io_binmode(current_file);
|
|
}
|
|
else {
|
|
init_p = 0;
|
|
return Qfalse;
|
|
}
|
|
}
|
|
return Qtrue;
|
|
}
|
|
|
|
static void
|
|
any_close(file)
|
|
VALUE file;
|
|
{
|
|
if (TYPE(file) == T_FILE)
|
|
rb_io_close(file);
|
|
else
|
|
rb_funcall3(file, rb_intern("close"), 0, 0);
|
|
}
|
|
|
|
static VALUE
|
|
rb_f_gets_internal(argc, argv)
|
|
int argc;
|
|
VALUE *argv;
|
|
{
|
|
VALUE line;
|
|
|
|
retry:
|
|
if (!next_argv()) return Qnil;
|
|
if (TYPE(current_file) != T_FILE) {
|
|
line = rb_funcall3(current_file, rb_intern("gets"), argc, argv);
|
|
}
|
|
else if (argc == 0 && rb_rs == rb_default_rs) {
|
|
line = rb_io_gets(current_file);
|
|
}
|
|
else {
|
|
line = rb_io_gets_internal(argc, argv, current_file);
|
|
}
|
|
if (NIL_P(line) && next_p != -1) {
|
|
any_close(current_file);
|
|
next_p = 1;
|
|
goto retry;
|
|
}
|
|
gets_lineno++;
|
|
lineno = INT2FIX(gets_lineno);
|
|
|
|
return line;
|
|
}
|
|
|
|
static VALUE
|
|
rb_f_gets(argc, argv)
|
|
int argc;
|
|
VALUE *argv;
|
|
{
|
|
VALUE line = rb_f_gets_internal(argc, argv);
|
|
|
|
rb_lastline_set(line);
|
|
return line;
|
|
}
|
|
|
|
VALUE
|
|
rb_gets()
|
|
{
|
|
VALUE line;
|
|
|
|
if (rb_rs != rb_default_rs) {
|
|
return rb_f_gets(0, 0);
|
|
}
|
|
|
|
retry:
|
|
if (!next_argv()) return Qnil;
|
|
line = rb_io_gets(current_file);
|
|
if (NIL_P(line) && next_p != -1) {
|
|
any_close(current_file);
|
|
next_p = 1;
|
|
goto retry;
|
|
}
|
|
rb_lastline_set(line);
|
|
if (!NIL_P(line)) {
|
|
gets_lineno++;
|
|
lineno = INT2FIX(gets_lineno);
|
|
}
|
|
|
|
return line;
|
|
}
|
|
|
|
static VALUE
|
|
rb_f_readline(argc, argv)
|
|
int argc;
|
|
VALUE *argv;
|
|
{
|
|
VALUE line = rb_f_gets(argc, argv);
|
|
|
|
if (NIL_P(line)) {
|
|
rb_eof_error();
|
|
}
|
|
|
|
return line;
|
|
}
|
|
|
|
static VALUE
|
|
rb_f_getc()
|
|
{
|
|
rb_warn("getc is obsolete; use STDIN.getc instead");
|
|
return rb_io_getc(rb_stdin);
|
|
}
|
|
|
|
static VALUE
|
|
rb_f_readlines(argc, argv)
|
|
int argc;
|
|
VALUE *argv;
|
|
{
|
|
VALUE line, ary;
|
|
|
|
ary = rb_ary_new();
|
|
while (!NIL_P(line = rb_f_gets_internal(argc, argv))) {
|
|
rb_ary_push(ary, line);
|
|
}
|
|
|
|
return ary;
|
|
}
|
|
|
|
static VALUE
|
|
rb_f_backquote(obj, str)
|
|
VALUE obj, str;
|
|
{
|
|
VALUE port, result;
|
|
|
|
SafeStringValue(str);
|
|
port = pipe_open(RSTRING(str)->ptr, "r");
|
|
if (NIL_P(port)) return rb_str_new(0,0);
|
|
result = read_all(port);
|
|
|
|
rb_io_close(port);
|
|
|
|
if (NIL_P(result)) return rb_str_new(0,0);
|
|
return result;
|
|
}
|
|
|
|
#ifdef HAVE_SYS_SELECT_H
|
|
#include <sys/select.h>
|
|
#endif
|
|
|
|
static VALUE
|
|
rb_f_select(argc, argv, obj)
|
|
int argc;
|
|
VALUE *argv;
|
|
VALUE obj;
|
|
{
|
|
VALUE read, write, except, timeout, res, list;
|
|
fd_set rset, wset, eset, pset;
|
|
fd_set *rp, *wp, *ep;
|
|
struct timeval *tp, timerec;
|
|
OpenFile *fptr;
|
|
int i, max = 0, n;
|
|
int interrupt_flag = 0;
|
|
int pending = 0;
|
|
|
|
rb_scan_args(argc, argv, "13", &read, &write, &except, &timeout);
|
|
if (NIL_P(timeout)) {
|
|
tp = 0;
|
|
}
|
|
else {
|
|
timerec = rb_time_interval(timeout);
|
|
tp = &timerec;
|
|
}
|
|
|
|
FD_ZERO(&pset);
|
|
if (!NIL_P(read)) {
|
|
Check_Type(read, T_ARRAY);
|
|
rp = &rset;
|
|
FD_ZERO(rp);
|
|
for (i=0; i<RARRAY(read)->len; i++) {
|
|
GetOpenFile(rb_io_get_io(RARRAY(read)->ptr[i]), fptr);
|
|
FD_SET(fileno(fptr->f), rp);
|
|
if (READ_DATA_PENDING(fptr->f)) { /* check for buffered data */
|
|
pending++;
|
|
FD_SET(fileno(fptr->f), &pset);
|
|
}
|
|
if (max < fileno(fptr->f)) max = fileno(fptr->f);
|
|
}
|
|
if (pending) { /* no blocking if there's buffered data */
|
|
timerec.tv_sec = timerec.tv_usec = 0;
|
|
tp = &timerec;
|
|
}
|
|
}
|
|
else
|
|
rp = 0;
|
|
|
|
if (!NIL_P(write)) {
|
|
Check_Type(write, T_ARRAY);
|
|
wp = &wset;
|
|
FD_ZERO(wp);
|
|
for (i=0; i<RARRAY(write)->len; i++) {
|
|
GetOpenFile(rb_io_get_io(RARRAY(write)->ptr[i]), fptr);
|
|
FD_SET(fileno(fptr->f), wp);
|
|
if (max < fileno(fptr->f)) max = fileno(fptr->f);
|
|
if (fptr->f2) {
|
|
FD_SET(fileno(fptr->f2), wp);
|
|
if (max < fileno(fptr->f2)) max = fileno(fptr->f2);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
wp = 0;
|
|
|
|
if (!NIL_P(except)) {
|
|
Check_Type(except, T_ARRAY);
|
|
ep = &eset;
|
|
FD_ZERO(ep);
|
|
for (i=0; i<RARRAY(except)->len; i++) {
|
|
GetOpenFile(rb_io_get_io(RARRAY(except)->ptr[i]), fptr);
|
|
FD_SET(fileno(fptr->f), ep);
|
|
if (max < fileno(fptr->f)) max = fileno(fptr->f);
|
|
if (fptr->f2) {
|
|
FD_SET(fileno(fptr->f2), ep);
|
|
if (max < fileno(fptr->f2)) max = fileno(fptr->f2);
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
ep = 0;
|
|
}
|
|
|
|
max++;
|
|
|
|
n = rb_thread_select(max, rp, wp, ep, tp);
|
|
if (n < 0) {
|
|
rb_sys_fail(0);
|
|
}
|
|
if (!pending && n == 0) return Qnil; /* returns nil on timeout */
|
|
|
|
res = rb_ary_new2(3);
|
|
rb_ary_push(res, rp?rb_ary_new():rb_ary_new2(0));
|
|
rb_ary_push(res, wp?rb_ary_new():rb_ary_new2(0));
|
|
rb_ary_push(res, ep?rb_ary_new():rb_ary_new2(0));
|
|
|
|
if (interrupt_flag == 0) {
|
|
if (rp) {
|
|
list = RARRAY(res)->ptr[0];
|
|
for (i=0; i< RARRAY(read)->len; i++) {
|
|
GetOpenFile(rb_io_get_io(RARRAY(read)->ptr[i]), fptr);
|
|
if (FD_ISSET(fileno(fptr->f), rp)
|
|
|| FD_ISSET(fileno(fptr->f), &pset)) {
|
|
rb_ary_push(list, RARRAY(read)->ptr[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (wp) {
|
|
list = RARRAY(res)->ptr[1];
|
|
for (i=0; i< RARRAY(write)->len; i++) {
|
|
GetOpenFile(rb_io_get_io(RARRAY(write)->ptr[i]), fptr);
|
|
if (FD_ISSET(fileno(fptr->f), wp)) {
|
|
rb_ary_push(list, RARRAY(write)->ptr[i]);
|
|
}
|
|
else if (fptr->f2 && FD_ISSET(fileno(fptr->f2), wp)) {
|
|
rb_ary_push(list, RARRAY(write)->ptr[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (ep) {
|
|
list = RARRAY(res)->ptr[2];
|
|
for (i=0; i< RARRAY(except)->len; i++) {
|
|
GetOpenFile(rb_io_get_io(RARRAY(except)->ptr[i]), fptr);
|
|
if (FD_ISSET(fileno(fptr->f), ep)) {
|
|
rb_ary_push(list, RARRAY(except)->ptr[i]);
|
|
}
|
|
else if (fptr->f2 && FD_ISSET(fileno(fptr->f2), ep)) {
|
|
rb_ary_push(list, RARRAY(except)->ptr[i]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return res; /* returns an empty array on interrupt */
|
|
}
|
|
|
|
#if !defined(MSDOS) && !defined(__human68k__)
|
|
static int
|
|
io_cntl(fd, cmd, narg, io_p)
|
|
int fd, cmd, io_p;
|
|
long narg;
|
|
{
|
|
int retval;
|
|
|
|
#ifdef HAVE_FCNTL
|
|
TRAP_BEG;
|
|
# if defined(__CYGWIN__)
|
|
retval = io_p?ioctl(fd, cmd, (void*)narg):fcntl(fd, cmd, narg);
|
|
# else
|
|
retval = io_p?ioctl(fd, cmd, narg):fcntl(fd, cmd, narg);
|
|
# endif
|
|
TRAP_END;
|
|
#else
|
|
if (!io_p) {
|
|
rb_notimplement();
|
|
}
|
|
TRAP_BEG;
|
|
retval = ioctl(fd, cmd, narg);
|
|
TRAP_END;
|
|
#endif
|
|
return retval;
|
|
}
|
|
#endif
|
|
|
|
static VALUE
|
|
rb_io_ctl(io, req, arg, io_p)
|
|
VALUE io, req, arg;
|
|
int io_p;
|
|
{
|
|
#if !defined(MSDOS) && !defined(__human68k__)
|
|
int cmd = NUM2ULONG(req);
|
|
OpenFile *fptr;
|
|
int len = 0;
|
|
long narg = 0;
|
|
int retval;
|
|
|
|
rb_secure(2);
|
|
GetOpenFile(io, fptr);
|
|
|
|
if (NIL_P(arg) || arg == Qfalse) {
|
|
narg = 0;
|
|
}
|
|
else if (FIXNUM_P(arg)) {
|
|
narg = FIX2INT(arg);
|
|
}
|
|
else if (arg == Qtrue) {
|
|
narg = 1;
|
|
}
|
|
else if (rb_obj_is_kind_of(arg, rb_cInteger)) {
|
|
narg = NUM2LONG(arg);
|
|
}
|
|
else {
|
|
StringValue(arg);
|
|
|
|
#ifdef IOCPARM_MASK
|
|
#ifndef IOCPARM_LEN
|
|
#define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK)
|
|
#endif
|
|
#endif
|
|
#ifdef IOCPARM_LEN
|
|
len = IOCPARM_LEN(cmd); /* on BSDish systems we're safe */
|
|
#else
|
|
len = 256; /* otherwise guess at what's safe */
|
|
#endif
|
|
rb_str_modify(arg);
|
|
|
|
if (len <= RSTRING(arg)->len) {
|
|
len = RSTRING(arg)->len;
|
|
}
|
|
if (RSTRING(arg)->len < len) {
|
|
rb_str_resize(arg, len+1);
|
|
}
|
|
RSTRING(arg)->ptr[len] = 17; /* a little sanity check here */
|
|
narg = (long)RSTRING(arg)->ptr;
|
|
}
|
|
retval = io_cntl(fileno(fptr->f), cmd, narg, io_p);
|
|
if (retval < 0) rb_sys_fail(fptr->path);
|
|
if (TYPE(arg) == T_STRING && RSTRING(arg)->ptr[len] != 17) {
|
|
rb_raise(rb_eArgError, "return value overflowed string");
|
|
}
|
|
|
|
if (fptr->f2 && fileno(fptr->f) != fileno(fptr->f2)) {
|
|
/* call on f2 too; ignore result */
|
|
io_cntl(fileno(fptr->f2), cmd, narg, io_p);
|
|
}
|
|
|
|
return INT2NUM(retval);
|
|
#else
|
|
rb_notimplement();
|
|
return Qnil; /* not reached */
|
|
#endif
|
|
}
|
|
|
|
static VALUE
|
|
rb_io_ioctl(argc, argv, io)
|
|
int argc;
|
|
VALUE *argv;
|
|
VALUE io;
|
|
{
|
|
VALUE req, arg;
|
|
|
|
rb_scan_args(argc, argv, "11", &req, &arg);
|
|
return rb_io_ctl(io, req, arg, 1);
|
|
}
|
|
|
|
static VALUE
|
|
rb_io_fcntl(argc, argv, io)
|
|
int argc;
|
|
VALUE *argv;
|
|
VALUE io;
|
|
{
|
|
#ifdef HAVE_FCNTL
|
|
VALUE req, arg;
|
|
|
|
rb_scan_args(argc, argv, "11", &req, &arg);
|
|
return rb_io_ctl(io, req, arg, 0);
|
|
#else
|
|
rb_notimplement();
|
|
return Qnil; /* not reached */
|
|
#endif
|
|
}
|
|
|
|
static VALUE
|
|
rb_f_syscall(argc, argv)
|
|
int argc;
|
|
VALUE *argv;
|
|
{
|
|
#if defined(HAVE_SYSCALL) && !defined(__CHECKER__)
|
|
#ifdef atarist
|
|
unsigned long arg[14]; /* yes, we really need that many ! */
|
|
#else
|
|
unsigned long arg[8];
|
|
#endif
|
|
int retval = -1;
|
|
int i = 1;
|
|
int items = argc - 1;
|
|
|
|
/* This probably won't work on machines where sizeof(long) != sizeof(int)
|
|
* or where sizeof(long) != sizeof(char*). But such machines will
|
|
* not likely have syscall implemented either, so who cares?
|
|
*/
|
|
|
|
rb_secure(2);
|
|
if (argc == 0)
|
|
rb_raise(rb_eArgError, "too few arguments for syscall");
|
|
arg[0] = NUM2INT(argv[0]); argv++;
|
|
while (items--) {
|
|
if (FIXNUM_P(*argv)) {
|
|
arg[i] = (unsigned long)NUM2INT(*argv);
|
|
}
|
|
else {
|
|
VALUE v = *argv;
|
|
|
|
StringValue(v);
|
|
rb_str_modify(v);
|
|
arg[i] = (unsigned long)RSTRING(v)->ptr;
|
|
}
|
|
argv++;
|
|
i++;
|
|
}
|
|
TRAP_BEG;
|
|
switch (argc) {
|
|
case 1:
|
|
retval = syscall(arg[0]);
|
|
break;
|
|
case 2:
|
|
retval = syscall(arg[0],arg[1]);
|
|
break;
|
|
case 3:
|
|
retval = syscall(arg[0],arg[1],arg[2]);
|
|
break;
|
|
case 4:
|
|
retval = syscall(arg[0],arg[1],arg[2],arg[3]);
|
|
break;
|
|
case 5:
|
|
retval = syscall(arg[0],arg[1],arg[2],arg[3],arg[4]);
|
|
break;
|
|
case 6:
|
|
retval = syscall(arg[0],arg[1],arg[2],arg[3],arg[4],arg[5]);
|
|
break;
|
|
case 7:
|
|
retval = syscall(arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6]);
|
|
break;
|
|
case 8:
|
|
retval = syscall(arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6],
|
|
arg[7]);
|
|
break;
|
|
#ifdef atarist
|
|
case 9:
|
|
retval = syscall(arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6],
|
|
arg[7], arg[8]);
|
|
break;
|
|
case 10:
|
|
retval = syscall(arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6],
|
|
arg[7], arg[8], arg[9]);
|
|
break;
|
|
case 11:
|
|
retval = syscall(arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6],
|
|
arg[7], arg[8], arg[9], arg[10]);
|
|
break;
|
|
case 12:
|
|
retval = syscall(arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6],
|
|
arg[7], arg[8], arg[9], arg[10], arg[11]);
|
|
break;
|
|
case 13:
|
|
retval = syscall(arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6],
|
|
arg[7], arg[8], arg[9], arg[10], arg[11], arg[12]);
|
|
break;
|
|
case 14:
|
|
retval = syscall(arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6],
|
|
arg[7], arg[8], arg[9], arg[10], arg[11], arg[12], arg[13]);
|
|
break;
|
|
#endif /* atarist */
|
|
}
|
|
TRAP_END;
|
|
if (retval < 0) rb_sys_fail(0);
|
|
return INT2NUM(retval);
|
|
#else
|
|
rb_notimplement();
|
|
return Qnil; /* not reached */
|
|
#endif
|
|
}
|
|
|
|
static VALUE
|
|
rb_io_s_pipe()
|
|
{
|
|
#ifndef __human68k__
|
|
int pipes[2];
|
|
VALUE r, w;
|
|
|
|
#ifdef NT
|
|
if (_pipe(pipes, 1024, O_BINARY) == -1)
|
|
#else
|
|
if (pipe(pipes) == -1)
|
|
#endif
|
|
rb_sys_fail(0);
|
|
|
|
r = prep_stdio(rb_fdopen(pipes[0], "r"), FMODE_READABLE, rb_cIO);
|
|
w = prep_stdio(rb_fdopen(pipes[1], "w"), FMODE_WRITABLE|FMODE_SYNC, rb_cIO);
|
|
|
|
return rb_assoc_new(r, w);
|
|
#else
|
|
rb_notimplement();
|
|
return Qnil; /* not reached */
|
|
#endif
|
|
}
|
|
|
|
struct foreach_arg {
|
|
int argc;
|
|
VALUE sep;
|
|
VALUE io;
|
|
};
|
|
|
|
static VALUE
|
|
io_s_foreach(arg)
|
|
struct foreach_arg *arg;
|
|
{
|
|
VALUE str;
|
|
|
|
while (!NIL_P(str = rb_io_gets_internal(arg->argc, &arg->sep, arg->io))) {
|
|
rb_yield(str);
|
|
}
|
|
return Qnil;
|
|
}
|
|
|
|
static VALUE
|
|
rb_io_s_foreach(argc, argv, io)
|
|
int argc;
|
|
VALUE *argv;
|
|
VALUE io;
|
|
{
|
|
VALUE fname;
|
|
struct foreach_arg arg;
|
|
|
|
rb_scan_args(argc, argv, "11", &fname, &arg.sep);
|
|
SafeStringValue(fname);
|
|
|
|
arg.argc = argc - 1;
|
|
arg.io = rb_io_open(RSTRING(fname)->ptr, "r");
|
|
if (NIL_P(arg.io)) return Qnil;
|
|
return rb_ensure(io_s_foreach, (VALUE)&arg, rb_io_close, arg.io);
|
|
}
|
|
|
|
static VALUE
|
|
io_s_readlines(arg)
|
|
struct foreach_arg *arg;
|
|
{
|
|
return rb_io_readlines(arg->argc, &arg->sep, arg->io);
|
|
}
|
|
|
|
static VALUE
|
|
rb_io_s_readlines(argc, argv, io)
|
|
int argc;
|
|
VALUE *argv;
|
|
VALUE io;
|
|
{
|
|
VALUE fname;
|
|
struct foreach_arg arg;
|
|
|
|
rb_scan_args(argc, argv, "11", &fname, &arg.sep);
|
|
SafeStringValue(fname);
|
|
|
|
arg.argc = argc - 1;
|
|
arg.io = rb_io_open(RSTRING(fname)->ptr, "r");
|
|
if (NIL_P(arg.io)) return Qnil;
|
|
return rb_ensure(io_s_readlines, (VALUE)&arg, rb_io_close, arg.io);
|
|
}
|
|
|
|
static VALUE
|
|
io_s_read(arg)
|
|
struct foreach_arg *arg;
|
|
{
|
|
return io_read(arg->argc, &arg->sep, arg->io);
|
|
}
|
|
|
|
static VALUE
|
|
rb_io_s_read(argc, argv, io)
|
|
int argc;
|
|
VALUE *argv;
|
|
VALUE io;
|
|
{
|
|
VALUE fname, offset;
|
|
struct foreach_arg arg;
|
|
|
|
rb_scan_args(argc, argv, "12", &fname, &arg.sep, &offset);
|
|
SafeStringValue(fname);
|
|
|
|
arg.argc = argc ? 1 : 0;
|
|
arg.io = rb_io_open(RSTRING(fname)->ptr, "r");
|
|
if (NIL_P(arg.io)) return Qnil;
|
|
if (!NIL_P(offset)) {
|
|
rb_io_seek(arg.io, offset, SEEK_SET);
|
|
}
|
|
return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
|
|
}
|
|
|
|
static VALUE
|
|
argf_tell()
|
|
{
|
|
if (!next_argv()) {
|
|
rb_raise(rb_eArgError, "no stream to tell");
|
|
}
|
|
|
|
if (TYPE(current_file) != T_FILE) {
|
|
return argf_forward();
|
|
}
|
|
return rb_io_tell(current_file);
|
|
}
|
|
|
|
static VALUE
|
|
argf_seek_m(argc, argv, self)
|
|
int argc;
|
|
VALUE *argv;
|
|
VALUE self;
|
|
{
|
|
if (!next_argv()) {
|
|
rb_raise(rb_eArgError, "no stream to seek");
|
|
}
|
|
|
|
if (TYPE(current_file) != T_FILE) {
|
|
return argf_forward();
|
|
}
|
|
return rb_io_seek_m(argc, argv, current_file);
|
|
}
|
|
|
|
static VALUE
|
|
argf_set_pos(self, offset)
|
|
VALUE self, offset;
|
|
{
|
|
if (!next_argv()) {
|
|
rb_raise(rb_eArgError, "no stream to set position");
|
|
}
|
|
|
|
if (TYPE(current_file) != T_FILE) {
|
|
return argf_forward();
|
|
}
|
|
return rb_io_set_pos(current_file, offset);
|
|
}
|
|
|
|
static VALUE
|
|
argf_rewind()
|
|
{
|
|
if (!next_argv()) {
|
|
rb_raise(rb_eArgError, "no stream to rewind");
|
|
}
|
|
if (TYPE(current_file) != T_FILE) {
|
|
return argf_forward();
|
|
}
|
|
return rb_io_rewind(current_file);
|
|
}
|
|
|
|
static VALUE
|
|
argf_fileno()
|
|
{
|
|
if (!next_argv()) {
|
|
rb_raise(rb_eArgError, "no stream");
|
|
}
|
|
if (TYPE(current_file) != T_FILE) {
|
|
return argf_forward();
|
|
}
|
|
return rb_io_fileno(current_file);
|
|
}
|
|
|
|
static VALUE
|
|
argf_to_io()
|
|
{
|
|
return current_file;
|
|
}
|
|
|
|
static VALUE
|
|
argf_read(argc, argv)
|
|
int argc;
|
|
VALUE *argv;
|
|
{
|
|
VALUE tmp, str;
|
|
int len;
|
|
|
|
if (argc == 1) len = NUM2INT(argv[0]);
|
|
str = Qnil;
|
|
|
|
retry:
|
|
if (!next_argv()) return str;
|
|
if (TYPE(current_file) != T_FILE) {
|
|
tmp = argf_forward();
|
|
StringValue(tmp);
|
|
}
|
|
else {
|
|
tmp = io_read(argc, argv, current_file);
|
|
}
|
|
if (NIL_P(tmp) && next_p != -1) {
|
|
any_close(current_file);
|
|
next_p = 1;
|
|
goto retry;
|
|
}
|
|
if (NIL_P(tmp) || RSTRING(tmp)->len == 0) return str;
|
|
else if (NIL_P(str)) str = tmp;
|
|
else rb_str_append(str, tmp);
|
|
if (argc == 0) {
|
|
goto retry;
|
|
}
|
|
if (RSTRING(tmp)->len < len) {
|
|
len -= RSTRING(tmp)->len;
|
|
argv[0] = INT2FIX(len);
|
|
goto retry;
|
|
}
|
|
|
|
return str;
|
|
}
|
|
|
|
static VALUE
|
|
argf_getc()
|
|
{
|
|
VALUE byte;
|
|
|
|
retry:
|
|
if (!next_argv()) return Qnil;
|
|
if (TYPE(current_file) != T_FILE) {
|
|
byte = rb_funcall3(current_file, rb_intern("getc"), 0, 0);
|
|
}
|
|
else {
|
|
byte = rb_io_getc(current_file);
|
|
}
|
|
if (NIL_P(byte) && next_p != -1) {
|
|
any_close(current_file);
|
|
next_p = 1;
|
|
goto retry;
|
|
}
|
|
|
|
return byte;
|
|
}
|
|
|
|
static VALUE
|
|
argf_readchar()
|
|
{
|
|
VALUE c = argf_getc();
|
|
|
|
if (NIL_P(c)) {
|
|
rb_eof_error();
|
|
}
|
|
return c;
|
|
}
|
|
|
|
static VALUE
|
|
argf_eof()
|
|
{
|
|
int first = first_p;
|
|
|
|
if (!next_argv()) return Qtrue;
|
|
if (next_p == 1) {
|
|
return Qtrue;
|
|
}
|
|
if (TYPE(current_file) != T_FILE) {
|
|
return argf_forward();
|
|
}
|
|
if (rb_io_eof(current_file)) {
|
|
next_p = 1;
|
|
return Qtrue;
|
|
}
|
|
return Qfalse;
|
|
}
|
|
|
|
static VALUE
|
|
argf_each_line(argc, argv)
|
|
int argc;
|
|
VALUE *argv;
|
|
{
|
|
VALUE str;
|
|
|
|
while (RTEST(str = rb_f_gets_internal(argc, argv))) {
|
|
rb_yield(str);
|
|
}
|
|
return argf;
|
|
}
|
|
|
|
static VALUE
|
|
argf_each_byte()
|
|
{
|
|
VALUE byte;
|
|
|
|
while (!NIL_P(byte = argf_getc())) {
|
|
rb_yield(byte);
|
|
}
|
|
return Qnil;
|
|
}
|
|
|
|
static VALUE
|
|
argf_filename()
|
|
{
|
|
return filename;
|
|
}
|
|
|
|
static VALUE
|
|
argf_file()
|
|
{
|
|
return current_file;
|
|
}
|
|
|
|
static VALUE
|
|
argf_skip()
|
|
{
|
|
if (next_p != -1) {
|
|
any_close(current_file);
|
|
next_p = 1;
|
|
}
|
|
return argf;
|
|
}
|
|
|
|
static VALUE
|
|
argf_close()
|
|
{
|
|
any_close(current_file);
|
|
if (next_p != -1) {
|
|
next_p = 1;
|
|
}
|
|
gets_lineno = 0;
|
|
return argf;
|
|
}
|
|
|
|
static VALUE
|
|
argf_closed()
|
|
{
|
|
if (TYPE(current_file) != T_FILE) {
|
|
return argf_forward();
|
|
}
|
|
return rb_io_closed(current_file);
|
|
}
|
|
|
|
static VALUE
|
|
opt_i_get()
|
|
{
|
|
if (!ruby_inplace_mode) return Qnil;
|
|
return rb_str_new2(ruby_inplace_mode);
|
|
}
|
|
|
|
static void
|
|
opt_i_set(val)
|
|
VALUE val;
|
|
{
|
|
if (!RTEST(val)) {
|
|
if (ruby_inplace_mode) free(ruby_inplace_mode);
|
|
ruby_inplace_mode = 0;
|
|
return;
|
|
}
|
|
StringValue(val);
|
|
if (ruby_inplace_mode) free(ruby_inplace_mode);
|
|
ruby_inplace_mode = 0;
|
|
ruby_inplace_mode = strdup(RSTRING(val)->ptr);
|
|
}
|
|
|
|
void
|
|
Init_IO()
|
|
{
|
|
rb_eIOError = rb_define_class("IOError", rb_eStandardError);
|
|
rb_eEOFError = rb_define_class("EOFError", rb_eIOError);
|
|
|
|
id_write = rb_intern("write");
|
|
|
|
rb_define_global_function("syscall", rb_f_syscall, -1);
|
|
|
|
rb_define_global_function("open", rb_f_open, -1);
|
|
rb_define_global_function("printf", rb_f_printf, -1);
|
|
rb_define_global_function("print", rb_f_print, -1);
|
|
rb_define_global_function("putc", rb_f_putc, 1);
|
|
rb_define_global_function("puts", rb_f_puts, -1);
|
|
rb_define_global_function("gets", rb_f_gets, -1);
|
|
rb_define_global_function("readline", rb_f_readline, -1);
|
|
rb_define_global_function("getc", rb_f_getc, 0);
|
|
rb_define_global_function("select", rb_f_select, -1);
|
|
|
|
rb_define_global_function("readlines", rb_f_readlines, -1);
|
|
|
|
rb_define_global_function("`", rb_f_backquote, 1);
|
|
|
|
rb_define_global_function("p", rb_f_p, -1);
|
|
rb_define_method(rb_mKernel, "display", rb_obj_display, -1);
|
|
|
|
rb_cIO = rb_define_class("IO", rb_cObject);
|
|
rb_include_module(rb_cIO, rb_mEnumerable);
|
|
|
|
rb_define_singleton_method(rb_cIO, "allocate", rb_io_s_alloc, 0);
|
|
rb_define_singleton_method(rb_cIO, "for_fd", rb_io_s_for_fd, -1);
|
|
rb_define_method(rb_cIO, "initialize", rb_io_initialize, -1);
|
|
rb_define_singleton_method(rb_cIO, "popen", rb_io_s_popen, -1);
|
|
rb_define_singleton_method(rb_cIO, "foreach", rb_io_s_foreach, -1);
|
|
rb_define_singleton_method(rb_cIO, "readlines", rb_io_s_readlines, -1);
|
|
rb_define_singleton_method(rb_cIO, "read", rb_io_s_read, -1);
|
|
rb_define_singleton_method(rb_cIO, "select", rb_f_select, -1);
|
|
rb_define_singleton_method(rb_cIO, "pipe", rb_io_s_pipe, 0);
|
|
|
|
rb_output_fs = Qnil;
|
|
rb_define_hooked_variable("$,", &rb_output_fs, 0, rb_str_setter);
|
|
|
|
rb_rs = rb_default_rs = rb_str_new2("\n");
|
|
rb_output_rs = Qnil;
|
|
rb_global_variable(&rb_default_rs);
|
|
OBJ_FREEZE(rb_default_rs); /* avoid modifying RS_default */
|
|
rb_define_variable("$/", &rb_rs);
|
|
rb_define_variable("$-0", &rb_rs);
|
|
rb_define_variable("$\\", &rb_output_rs);
|
|
|
|
rb_define_hooked_variable("$.", &lineno, 0, lineno_setter);
|
|
rb_define_virtual_variable("$_", rb_lastline_get, rb_lastline_set);
|
|
|
|
rb_define_method(rb_cIO, "clone", rb_io_clone, 0);
|
|
rb_define_method(rb_cIO, "reopen", rb_io_reopen, -1);
|
|
|
|
rb_define_method(rb_cIO, "print", rb_io_print, -1);
|
|
rb_define_method(rb_cIO, "putc", rb_io_putc, 1);
|
|
rb_define_method(rb_cIO, "puts", rb_io_puts, -1);
|
|
rb_define_method(rb_cIO, "printf", rb_io_printf, -1);
|
|
|
|
rb_define_method(rb_cIO, "each", rb_io_each_line, -1);
|
|
rb_define_method(rb_cIO, "each_line", rb_io_each_line, -1);
|
|
rb_define_method(rb_cIO, "each_byte", rb_io_each_byte, 0);
|
|
|
|
rb_define_method(rb_cIO, "syswrite", rb_io_syswrite, 1);
|
|
rb_define_method(rb_cIO, "sysread", rb_io_sysread, 1);
|
|
|
|
rb_define_method(rb_cIO, "fileno", rb_io_fileno, 0);
|
|
rb_define_alias(rb_cIO, "to_i", "fileno");
|
|
rb_define_method(rb_cIO, "to_io", rb_io_to_io, 0);
|
|
|
|
rb_define_method(rb_cIO, "sync", rb_io_sync, 0);
|
|
rb_define_method(rb_cIO, "sync=", rb_io_set_sync, 1);
|
|
|
|
rb_define_method(rb_cIO, "lineno", rb_io_lineno, 0);
|
|
rb_define_method(rb_cIO, "lineno=", rb_io_set_lineno, 1);
|
|
|
|
rb_define_method(rb_cIO, "readlines", rb_io_readlines, -1);
|
|
|
|
rb_define_method(rb_cIO, "read", io_read, -1);
|
|
rb_define_method(rb_cIO, "write", io_write, 1);
|
|
rb_define_method(rb_cIO, "gets", rb_io_gets_m, -1);
|
|
rb_define_method(rb_cIO, "readline", rb_io_readline, -1);
|
|
rb_define_method(rb_cIO, "getc", rb_io_getc, 0);
|
|
rb_define_method(rb_cIO, "readchar", rb_io_readchar, 0);
|
|
rb_define_method(rb_cIO, "ungetc",rb_io_ungetc, 1);
|
|
rb_define_method(rb_cIO, "<<", rb_io_addstr, 1);
|
|
rb_define_method(rb_cIO, "flush", rb_io_flush, 0);
|
|
rb_define_method(rb_cIO, "tell", rb_io_tell, 0);
|
|
rb_define_method(rb_cIO, "seek", rb_io_seek_m, -1);
|
|
rb_define_const(rb_cIO, "SEEK_SET", INT2FIX(SEEK_SET));
|
|
rb_define_const(rb_cIO, "SEEK_CUR", INT2FIX(SEEK_CUR));
|
|
rb_define_const(rb_cIO, "SEEK_END", INT2FIX(SEEK_END));
|
|
rb_define_method(rb_cIO, "rewind", rb_io_rewind, 0);
|
|
rb_define_method(rb_cIO, "pos", rb_io_tell, 0);
|
|
rb_define_method(rb_cIO, "pos=", rb_io_set_pos, 1);
|
|
rb_define_method(rb_cIO, "eof", rb_io_eof, 0);
|
|
rb_define_method(rb_cIO, "eof?", rb_io_eof, 0);
|
|
|
|
rb_define_method(rb_cIO, "close", rb_io_close_m, 0);
|
|
rb_define_method(rb_cIO, "closed?", rb_io_closed, 0);
|
|
rb_define_method(rb_cIO, "close_read", rb_io_close_read, 0);
|
|
rb_define_method(rb_cIO, "close_write", rb_io_close_write, 0);
|
|
|
|
rb_define_method(rb_cIO, "isatty", rb_io_isatty, 0);
|
|
rb_define_method(rb_cIO, "tty?", rb_io_isatty, 0);
|
|
rb_define_method(rb_cIO, "binmode", rb_io_binmode, 0);
|
|
|
|
rb_define_method(rb_cIO, "ioctl", rb_io_ioctl, -1);
|
|
rb_define_method(rb_cIO, "fcntl", rb_io_fcntl, -1);
|
|
rb_define_method(rb_cIO, "pid", rb_io_pid, 0);
|
|
|
|
rb_stdin = orig_stdin = prep_stdio(stdin, FMODE_READABLE, rb_cIO);
|
|
rb_define_hooked_variable("$stdin", &rb_stdin, 0, set_stdin);
|
|
rb_stdout = orig_stdout = prep_stdio(stdout, FMODE_WRITABLE, rb_cIO);
|
|
rb_define_hooked_variable("$stdout", &rb_stdout, 0, set_stdout);
|
|
rb_stderr = orig_stderr = prep_stdio(stderr, FMODE_WRITABLE, rb_cIO);
|
|
rb_define_hooked_variable("$stderr", &rb_stderr, 0, set_stderr);
|
|
rb_defout = rb_stdout;
|
|
rb_define_hooked_variable("$>", &rb_defout, 0, rb_io_defset);
|
|
rb_define_hooked_variable("$defout", &rb_defout, 0, rb_io_defset);
|
|
|
|
rb_define_global_const("STDIN", rb_stdin);
|
|
rb_define_global_const("STDOUT", rb_stdout);
|
|
rb_define_global_const("STDERR", rb_stderr);
|
|
|
|
argf = rb_obj_alloc(rb_cObject);
|
|
rb_extend_object(argf, rb_mEnumerable);
|
|
|
|
rb_define_readonly_variable("$<", &argf);
|
|
rb_define_global_const("ARGF", argf);
|
|
|
|
rb_define_singleton_method(argf, "fileno", argf_fileno, 0);
|
|
rb_define_singleton_method(argf, "to_i", argf_fileno, 0);
|
|
rb_define_singleton_method(argf, "to_io", argf_to_io, 0);
|
|
rb_define_singleton_method(argf, "each", argf_each_line, -1);
|
|
rb_define_singleton_method(argf, "each_line", argf_each_line, -1);
|
|
rb_define_singleton_method(argf, "each_byte", argf_each_byte, 0);
|
|
|
|
rb_define_singleton_method(argf, "read", argf_read, -1);
|
|
rb_define_singleton_method(argf, "readlines", rb_f_readlines, -1);
|
|
rb_define_singleton_method(argf, "to_a", rb_f_readlines, -1);
|
|
rb_define_singleton_method(argf, "gets", rb_f_gets, -1);
|
|
rb_define_singleton_method(argf, "readline", rb_f_readline, -1);
|
|
rb_define_singleton_method(argf, "getc", argf_getc, 0);
|
|
rb_define_singleton_method(argf, "readchar", argf_readchar, 0);
|
|
rb_define_singleton_method(argf, "tell", argf_tell, 0);
|
|
rb_define_singleton_method(argf, "seek", argf_seek_m, -1);
|
|
rb_define_singleton_method(argf, "rewind", argf_rewind, 0);
|
|
rb_define_singleton_method(argf, "pos", argf_tell, 0);
|
|
rb_define_singleton_method(argf, "pos=", argf_set_pos, 1);
|
|
rb_define_singleton_method(argf, "eof", argf_eof, 0);
|
|
rb_define_singleton_method(argf, "eof?", argf_eof, 0);
|
|
rb_define_singleton_method(argf, "binmode", argf_binmode, 0);
|
|
|
|
rb_define_singleton_method(argf, "to_s", argf_filename, 0);
|
|
rb_define_singleton_method(argf, "filename", argf_filename, 0);
|
|
rb_define_singleton_method(argf, "file", argf_file, 0);
|
|
rb_define_singleton_method(argf, "skip", argf_skip, 0);
|
|
rb_define_singleton_method(argf, "close", argf_close, 0);
|
|
rb_define_singleton_method(argf, "closed?", argf_closed, 0);
|
|
|
|
rb_define_singleton_method(argf, "lineno", argf_lineno, 0);
|
|
rb_define_singleton_method(argf, "lineno=", argf_set_lineno, 1);
|
|
|
|
current_file = rb_stdin;
|
|
rb_global_variable(¤t_file);
|
|
filename = rb_str_new2("-");
|
|
rb_define_readonly_variable("$FILENAME", &filename);
|
|
|
|
rb_define_virtual_variable("$-i", opt_i_get, opt_i_set);
|
|
|
|
#if defined (NT) || defined(DJGPP) || defined(__CYGWIN__) || defined(__human68k__)
|
|
atexit(pipe_atexit);
|
|
#endif
|
|
|
|
Init_File();
|
|
|
|
rb_define_singleton_method(rb_cFile, "open", rb_file_s_open, -1);
|
|
rb_define_method(rb_cFile, "initialize", rb_file_initialize, -1);
|
|
|
|
rb_file_const("RDONLY", INT2FIX(O_RDONLY));
|
|
rb_file_const("WRONLY", INT2FIX(O_WRONLY));
|
|
rb_file_const("RDWR", INT2FIX(O_RDWR));
|
|
rb_file_const("APPEND", INT2FIX(O_APPEND));
|
|
rb_file_const("CREAT", INT2FIX(O_CREAT));
|
|
rb_file_const("EXCL", INT2FIX(O_EXCL));
|
|
#if defined(O_NDELAY) || defined(O_NONBLOCK)
|
|
# ifdef O_NONBLOCK
|
|
rb_file_const("NONBLOCK", INT2FIX(O_NONBLOCK));
|
|
# else
|
|
rb_file_const("NONBLOCK", INT2FIX(O_NDELAY));
|
|
# endif
|
|
#endif
|
|
rb_file_const("TRUNC", INT2FIX(O_TRUNC));
|
|
#ifdef O_NOCTTY
|
|
rb_file_const("NOCTTY", INT2FIX(O_NOCTTY));
|
|
#endif
|
|
#ifdef O_BINARY
|
|
rb_file_const("BINARY", INT2FIX(O_BINARY));
|
|
#endif
|
|
#ifdef O_SYNC
|
|
rb_file_const("SYNC", INT2FIX(O_SYNC));
|
|
#endif
|
|
}
|