summaryrefslogtreecommitdiff
path: root/io.c
diff options
context:
space:
mode:
Diffstat (limited to 'io.c')
-rw-r--r--io.c492
1 files changed, 377 insertions, 115 deletions
diff --git a/io.c b/io.c
index 5573e76a64..9eba04ad7e 100644
--- a/io.c
+++ b/io.c
@@ -6,7 +6,7 @@
$Date$
created at: Fri Oct 15 18:08:59 JST 1993
- Copyright (C) 1993-1998 Yukihiro Matsumoto
+ Copyright (C) 1993-1999 Yukihiro Matsumoto
************************************************/
@@ -20,7 +20,7 @@
#if !defined(DJGPP) && !defined(NT) && !defined(__human68k__)
#include <sys/ioctl.h>
#endif
-#if defined(HAVE_FCNTL)
+#if defined(HAVE_FCNTL) || defined(NT)
#include <fcntl.h>
#endif
@@ -54,10 +54,14 @@ struct timeval {
#include <sys/errno.h>
#include <unix.mac.h>
#include <compat.h>
+ extern char* strdup(const char*);
#endif
extern void Init_File _((void));
#ifdef __BEOS__
+# ifdef _X86_
+# define NOFILE (OPEN_MAX)
+# endif
#include <net/socket.h>
#endif
@@ -99,7 +103,7 @@ static VALUE lineno;
#elif defined(__BEOS__)
# define ReadDataPending(fp) (fp->_state._eof == 0)
#elif defined(USE_CWGUSI)
-# define ReadDataPending(fp) (fp->state.eof == 0)
+# define READ_DATA_PENDING(fp) (fp->state.eof == 0)
#else
/* requires systems own version of the ReadDataPending() */
extern int ReadDataPending();
@@ -110,7 +114,10 @@ extern int ReadDataPending();
# define READ_CHECK(fp) 0
#else
# define READ_CHECK(fp) do {\
- if (!READ_DATA_PENDING(fp)) rb_thread_wait_fd(fileno(fp));\
+ if (!READ_DATA_PENDING(fp)) {\
+ rb_thread_wait_fd(fileno(fp));\
+ rb_io_check_closed(fptr);\
+ }\
} while(0)
#endif
@@ -840,8 +847,14 @@ static void
rb_io_fptr_close(fptr)
OpenFile *fptr;
{
+ int fd;
+
if (fptr->f == NULL && fptr->f2 == NULL) return;
+#ifdef USE_THREAD
+ rb_thread_fd_close(fileno(fptr->f));
+#endif
+
if (fptr->finalize) {
(*fptr->finalize)(fptr);
}
@@ -953,7 +966,9 @@ rb_io_syswrite(io, str)
f = GetWriteFile(fptr);
#ifdef USE_THREAD
- rb_thread_fd_writable(fileno(f));
+ if (!rb_thread_fd_writable(fileno(f))) {
+ rb_io_check_closed(fptr);
+ }
#endif
n = write(fileno(f), RSTRING(str)->ptr, RSTRING(str)->len);
@@ -1014,9 +1029,9 @@ rb_io_binmode(io)
rb_sys_fail(fptr->path);
# else /* USE_CWGUSI */
if (fptr->f)
- fptr->f->mode.binrb_ary_io = 1;
+ fptr->f->mode.binary_io = 1;
if (fptr->f2)
- fptr->f2->mode.binrb_ary_io = 1;
+ fptr->f2->mode.binary_io = 1;
# endif /* USE_CWGUSI */
#endif
@@ -1025,7 +1040,7 @@ rb_io_binmode(io)
return io;
}
-int
+static int
rb_io_mode_flags(mode)
char *mode;
{
@@ -1042,7 +1057,8 @@ rb_io_mode_flags(mode)
flags |= FMODE_WRITABLE;
break;
default:
- rb_raise(rb_eArgError, "illegal access mode");
+ error:
+ rb_raise(rb_eArgError, "illegal access mode %s", mode);
}
if (mode[1] == 'b') {
@@ -1052,29 +1068,112 @@ rb_io_mode_flags(mode)
if (mode[1] == '+') {
flags |= FMODE_READWRITE;
+ if (mode[2] != 0) goto error;
+ }
+ else if (mode[1] != 0) goto error;
+
+ return flags;
+}
+
+static int
+rb_io_mode_flags2(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 char*
+rb_io_flags_mode(flags)
+ int flags;
+{
+ static char mode[4];
+ 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_open(fname, flag, mode)
+ char *fname;
+ int flag;
+ unsigned int mode;
+{
+ int fd;
+
+ fd = open(fname, flag, mode);
+ if (fd < 0) {
+ if (errno == EMFILE || errno == ENFILE) {
+ rb_gc();
+ fd = open(fname, flag, mode);
+ }
+ if (fd < 0) {
+ rb_sys_fail(fname);
+ }
+ }
+ return fd;
+}
+
FILE *
rb_fopen(fname, mode)
char *fname;
char *mode;
{
- FILE *f;
+ FILE *file;
- f = fopen(fname, mode);
- if (f == NULL) {
+ file = fopen(fname, mode);
+ if (file == NULL) {
if (errno == EMFILE || errno == ENFILE) {
rb_gc();
- f = fopen(fname, mode);
+ file = fopen(fname, mode);
}
- if (f == NULL) {
+ if (file == NULL) {
rb_sys_fail(fname);
}
}
- return f;
+ return file;
}
FILE *
@@ -1082,18 +1181,65 @@ rb_fdopen(fd, mode)
int fd;
char *mode;
{
- FILE *f;
+ FILE *file;
- f = fdopen(fd, mode);
- if (f == NULL) {
- if (errno == EMFILE) {
- f = fdopen(fd, mode);
+ file = fdopen(fd, mode);
+ if (file == NULL) {
+ if (errno == EMFILE || errno == ENFILE) {
+ rb_gc();
+ file = fdopen(fd, mode);
}
- if (f == NULL) {
+ if (file == NULL) {
rb_sys_fail(0);
}
}
- return f;
+ return file;
+}
+
+VALUE
+rb_file_open(fname, mode)
+ char *fname, *mode;
+{
+ OpenFile *fptr;
+ NEWOBJ(port, struct RFile);
+ OBJSETUP(port, rb_cFile, T_FILE);
+ MakeOpenFile(port, fptr);
+
+ fptr->mode = rb_io_mode_flags(mode);
+ fptr->f = rb_fopen(fname, mode);
+ fptr->path = strdup(fname);
+ rb_obj_call_init((VALUE)port);
+
+ return (VALUE)port;
+}
+
+VALUE
+rb_file_sysopen(fname, flags, mode)
+ char *fname;
+ int flags, mode;
+{
+#ifdef USE_CWGUSI
+ if (mode != 0666) {
+ rb_warn("can't specify file mode on this platform");
+ }
+ return rb_file_open(fname, rb_io_flags_mode(flags));
+#else
+ OpenFile *fptr;
+ int fd;
+ char *m;
+ NEWOBJ(port, struct RFile);
+ OBJSETUP(port, rb_cFile, T_FILE);
+ MakeOpenFile(port, fptr);
+
+ fd = rb_open(fname, flags, mode);
+ m = rb_io_flags_mode(flags);
+ fptr->mode = rb_io_mode_flags2(flags);
+ fptr->f = rb_fdopen(fd, m);
+ fptr->path = strdup(fname);
+ rb_obj_call_init((VALUE)port);
+
+ return (VALUE)port;
+#endif
}
#if defined (NT) || defined(DJGPP) || defined(__CYGWIN32__) || defined(__human68k__)
@@ -1329,15 +1475,41 @@ rb_io_s_popen(argc, argv, self)
}
static VALUE
-rb_io_open(fname, mode)
- char *fname, *mode;
+rb_file_s_open(argc, argv, klass)
+ int argc;
+ VALUE *argv;
+ VALUE klass;
{
- if (fname[0] == '|') {
- return pipe_open(fname+1, mode);
+ VALUE fname, vmode, file, perm;
+ char *path, *mode;
+
+ rb_scan_args(argc, argv, "12", &fname, &vmode, &perm);
+ Check_SafeStr(fname);
+ path = RSTRING(fname)->ptr;
+
+ if (FIXNUM_P(vmode)) {
+ int flags = FIX2INT(vmode);
+ int fmode = NIL_P(perm) ? 0666 : FIX2INT(perm);
+
+ file = rb_file_sysopen(path, flags, fmode);
}
else {
- return rb_file_open(fname, mode);
+ if (!NIL_P(vmode)) {
+ mode = STR2CSTR(vmode);
+ }
+ else {
+ mode = "r";
+ }
+ file = rb_file_open(RSTRING(fname)->ptr, mode);
+ }
+
+ RBASIC(file)->klass = klass;
+ rb_obj_call_init(file);
+ if (rb_iterator_p()) {
+ return rb_ensure(rb_yield, file, rb_io_close, file);
}
+
+ return file;
}
static VALUE
@@ -1346,24 +1518,31 @@ rb_f_open(argc, argv)
VALUE *argv;
{
char *mode;
- VALUE pname, pmode;
+ VALUE pname, pmode, perm;
VALUE port;
- rb_scan_args(argc, argv, "11", &pname, &pmode);
+ rb_scan_args(argc, argv, "12", &pname, &pmode, &perm);
Check_SafeStr(pname);
+ if (RSTRING(pname)->ptr[0] != '|') /* open file */
+ return rb_file_s_open(argc, argv, rb_cFile);
+
+ /* open pipe */
if (NIL_P(pmode)) {
mode = "r";
}
+ else if (FIXNUM_P(pmode)) {
+ mode = rb_io_flags_mode(FIX2INT(pmode));
+ }
else {
int len;
mode = STR2CSTR(pmode);
len = strlen(mode);
if (len == 0 || len > 3)
- rb_raise(rb_eArgError, "illegal access mode");
+ rb_raise(rb_eArgError, "illegal access mode %s", mode);
}
- port = rb_io_open(RSTRING(pname)->ptr, mode);
+ port = pipe_open(RSTRING(pname)->ptr+1, mode);
if (rb_iterator_p()) {
return rb_ensure(rb_yield, port, rb_io_close, port);
}
@@ -1372,6 +1551,18 @@ rb_f_open(argc, argv)
}
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;
{
@@ -1393,7 +1584,7 @@ rb_io_mode_string(fptr)
}
}
-VALUE
+static VALUE
rb_io_reopen(io, nfile)
VALUE io, nfile;
{
@@ -1412,6 +1603,9 @@ rb_io_reopen(io, nfile)
else if (orig->mode & FMODE_WRITABLE) {
fflush(orig->f);
}
+#ifdef USE_THREAD
+ rb_thread_fd_close(fileno(fptr->f));
+#endif
/* copy OpenFile structure */
fptr->mode = orig->mode;
@@ -1458,6 +1652,56 @@ rb_io_reopen(io, nfile)
}
static VALUE
+rb_file_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_FILE) { /* fname must be IO */
+ return rb_io_reopen(file, fname);
+ }
+ }
+
+ Check_SafeStr(fname);
+ if (!NIL_P(nmode)) {
+ mode = STR2CSTR(nmode);
+ }
+ else {
+ mode = "r";
+ }
+
+ GetOpenFile(file, fptr);
+ if (fptr->path) free(fptr->path);
+ 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 = NULL;
+ }
+ return file;
+ }
+
+ if (freopen(RSTRING(fname)->ptr, mode, fptr->f) == NULL) {
+ rb_sys_fail(fptr->path);
+ }
+ if (fptr->f2) {
+ if (freopen(RSTRING(fname)->ptr, "w", fptr->f2) == NULL) {
+ rb_sys_fail(fptr->path);
+ }
+ }
+
+ return file;
+}
+
+static VALUE
rb_io_clone(io)
VALUE io;
{
@@ -1870,8 +2114,7 @@ next_argv()
#endif
}
fw = rb_fopen(fn, "w");
-#if !defined(MSDOS) && !defined(__CYGWIN32__) && !(NT) && !defined(__human68k__)\
- && !defined(USE_CWGUSI) && !defined(__BEOS__)
+#if !defined(MSDOS) && !defined(__CYGWIN32__) && !(NT) && !defined(__human68k__) && !defined(USE_CWGUSI) && !defined(__BEOS__)
fstat(fileno(fw), &st2);
fchmod(fileno(fw), st.st_mode);
if (st.st_uid!=st2.st_uid || st.st_gid!=st2.st_gid) {
@@ -1900,7 +2143,12 @@ rb_f_gets_internal(argc, argv)
retry:
if (!next_argv()) return Qnil;
- line = rb_io_gets_internal(argc, argv, file);
+ if (rb_rs == rb_default_rs) {
+ line = rb_io_gets(file);
+ }
+ else {
+ line = rb_io_gets_internal(argc, argv, file);
+ }
if (NIL_P(line) && next_p != -1) {
rb_io_close(file);
next_p = 1;
@@ -1928,6 +2176,10 @@ 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(file);
@@ -1960,76 +2212,13 @@ rb_f_readline(argc, argv)
}
static VALUE
-rb_f_tell()
-{
- return rb_io_tell(file);
-}
-
-static VALUE
-rb_f_seek(self, offset, ptrname)
- VALUE self, offset, ptrname;
-{
- if (!next_argv()) {
- rb_raise(rb_eArgError, "no stream to seek");
- }
-
- return rb_io_seek(file, offset, ptrname);
-}
-
-static VALUE
-rb_f_set_pos(self, offset)
- VALUE self, offset;
-{
- if (!next_argv()) {
- rb_raise(rb_eArgError, "no stream to pos");
- }
-
- return rb_io_set_pos(file, offset);
-}
-
-static VALUE
-rb_f_rewind()
-{
- return rb_io_rewind(file);
-}
-
-static VALUE
-rb_f_eof()
-{
- if (init_p == 0 && !next_argv())
- return Qtrue;
- if (rb_io_eof(file)) {
- next_p = 1;
- return Qtrue;
- }
- return Qfalse;
-}
-
-static VALUE
rb_f_getc()
{
+ rb_warn("getc is obsolete; use STDIN.getc instead");
return rb_io_getc(rb_stdin);
}
static VALUE
-rb_f_ungetc(self, c)
- VALUE self, c;
-{
- return rb_io_ungetc(rb_stdin, c);
-}
-
-static VALUE
-rb_f_readchar()
-{
- VALUE c = rb_f_getc();
-
- if (NIL_P(c)) {
- rb_eof_error();
- }
- return c;
-}
-
-static VALUE
rb_f_readlines(argc, argv)
int argc;
VALUE *argv;
@@ -2452,8 +2641,8 @@ rb_io_s_pipe()
#endif
rb_sys_fail(0);
- r = prep_stdio(fdopen(pipes[0], "r"), FMODE_READABLE, rb_cIO);
- w = prep_stdio(fdopen(pipes[1], "w"), FMODE_WRITABLE, rb_cIO);
+ r = prep_stdio(rb_fdopen(pipes[0], "r"), FMODE_READABLE, rb_cIO);
+ w = prep_stdio(rb_fdopen(pipes[1], "w"), FMODE_WRITABLE, rb_cIO);
ary = rb_ary_new2(2);
rb_ary_push(ary, r);
@@ -2533,6 +2722,40 @@ rb_io_s_readlines(argc, argv, io)
}
static VALUE
+arg_tell()
+{
+ return rb_io_tell(file);
+}
+
+static VALUE
+arg_seek(self, offset, ptrname)
+ VALUE self, offset, ptrname;
+{
+ if (!next_argv()) {
+ rb_raise(rb_eArgError, "no stream to seek");
+ }
+
+ return rb_io_seek(file, offset, ptrname);
+}
+
+static VALUE
+arg_set_pos(self, offset)
+ VALUE self, offset;
+{
+ if (!next_argv()) {
+ rb_raise(rb_eArgError, "no stream to pos");
+ }
+
+ return rb_io_set_pos(file, offset);
+}
+
+static VALUE
+arg_rewind()
+{
+ return rb_io_rewind(file);
+}
+
+static VALUE
arg_fileno()
{
return rb_io_fileno(file);
@@ -2550,7 +2773,7 @@ arg_read(argc, argv)
VALUE *argv;
{
VALUE tmp, str;
- size_t len;
+ int len;
if (argc == 1) len = NUM2INT(argv[0]);
str = Qnil;
@@ -2607,6 +2830,25 @@ arg_readchar()
}
static VALUE
+arg_eof()
+{
+ if (init_p == 0 && !next_argv())
+ return Qtrue;
+ if (rb_io_eof(file)) {
+ next_p = 1;
+ return Qtrue;
+ }
+ return Qfalse;
+}
+
+static VALUE
+rb_f_eof()
+{
+ rb_warn("eof? is obsolete; use ARGF.eof? instead");
+ return arg_eof();
+}
+
+static VALUE
arg_each_line(argc, argv)
int argc;
VALUE *argv;
@@ -2704,15 +2946,10 @@ Init_IO()
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("tell", rb_f_tell, 0);
- rb_define_global_function("seek", rb_f_seek, 2);
- rb_define_global_function("rewind", rb_f_rewind, 0);
rb_define_global_function("eof", rb_f_eof, 0);
rb_define_global_function("eof?", rb_f_eof, 0);
rb_define_global_function("getc", rb_f_getc, 0);
- rb_define_global_function("readchar", rb_f_readchar, 0);
rb_define_global_function("select", rb_f_select, -1);
- rb_define_global_function("ungetc", rb_f_ungetc, 1);
rb_define_global_function("readlines", rb_f_readlines, -1);
@@ -2838,14 +3075,13 @@ Init_IO()
rb_define_singleton_method(argf, "readline", rb_f_readline, -1);
rb_define_singleton_method(argf, "getc", arg_getc, 0);
rb_define_singleton_method(argf, "readchar", arg_readchar, 0);
- rb_define_singleton_method(argf, "tell", rb_f_tell, 0);
- rb_define_singleton_method(argf, "seek", rb_f_seek, 2);
- rb_define_singleton_method(argf, "rewind", rb_f_rewind, 0);
- rb_define_singleton_method(argf, "pos", rb_f_tell, 0);
- rb_define_singleton_method(argf, "pos=", rb_f_set_pos, 1);
- rb_define_singleton_method(argf, "eof", rb_f_eof, 0);
- rb_define_singleton_method(argf, "eof?", rb_f_eof, 0);
- rb_define_singleton_method(argf, "ungetc", rb_f_ungetc, 1);
+ rb_define_singleton_method(argf, "tell", arg_tell, 0);
+ rb_define_singleton_method(argf, "seek", arg_seek, 2);
+ rb_define_singleton_method(argf, "rewind", arg_rewind, 0);
+ rb_define_singleton_method(argf, "pos", arg_tell, 0);
+ rb_define_singleton_method(argf, "pos=", arg_set_pos, 1);
+ rb_define_singleton_method(argf, "eof", arg_eof, 0);
+ rb_define_singleton_method(argf, "eof?", arg_eof, 0);
rb_define_singleton_method(argf, "to_s", arg_filename, 0);
rb_define_singleton_method(argf, "filename", arg_filename, 0);
@@ -2866,4 +3102,30 @@ Init_IO()
#endif
Init_File();
+
+ rb_define_method(rb_cFile, "reopen", rb_file_reopen, -1);
+
+ rb_define_singleton_method(rb_cFile, "new", rb_file_s_open, -1);
+ rb_define_singleton_method(rb_cFile, "open", rb_file_s_open, -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
}