summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2004-02-25 12:17:39 +0000
committernobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2004-02-25 12:17:39 +0000
commitb0e0f45571d509a3d76732b76aa63a96ad6b371f (patch)
tree11a9c00880ee065d5a03b1306e4d82f7872ab973
parent61deeb37417b040e93cb258e58d1a5777055842b (diff)
* gc.c (obj_free), io.c (rb_io_fptr_finalize), rubyio.h (OpenFile):
sharing OpenFile. * io.c (rb_io_initialize): accept IO instance. [ruby-dev:22195] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@5831 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r--ChangeLog7
-rw-r--r--gc.c1
-rw-r--r--io.c67
-rw-r--r--rubyio.h2
4 files changed, 65 insertions, 12 deletions
diff --git a/ChangeLog b/ChangeLog
index 9228c748cd..a5f15c1a6d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+Wed Feb 25 21:17:33 2004 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * gc.c (obj_free), io.c (rb_io_fptr_finalize), rubyio.h (OpenFile):
+ sharing OpenFile.
+
+ * io.c (rb_io_initialize): accept IO instance. [ruby-dev:22195]
+
Wed Feb 25 21:16:10 2004 Nobuyoshi Nakada <nobu@ruby-lang.org>
* instruby.rb (with_destdir): should return the given argument if no
diff --git a/gc.c b/gc.c
index a93900a5e2..9138d235ef 100644
--- a/gc.c
+++ b/gc.c
@@ -1178,7 +1178,6 @@ obj_free(obj)
case T_FILE:
if (RANY(obj)->as.file.fptr) {
rb_io_fptr_finalize(RANY(obj)->as.file.fptr);
- RUBY_CRITICAL(free(RANY(obj)->as.file.fptr));
}
break;
case T_ICLASS:
diff --git a/io.c b/io.c
index 3568228a82..46145fec25 100644
--- a/io.c
+++ b/io.c
@@ -1780,6 +1780,7 @@ rb_io_fptr_finalize(fptr)
OpenFile *fptr;
{
if (!fptr) return;
+ if (fptr->refcnt <= 0 || --fptr->refcnt) return;
if (fptr->path) {
free(fptr->path);
}
@@ -1787,6 +1788,7 @@ rb_io_fptr_finalize(fptr)
if (fileno(fptr->f) < 3) return;
rb_io_fptr_cleanup(fptr, Qtrue);
+ free(fptr);
}
VALUE
@@ -3059,6 +3061,13 @@ rb_io_get_io(io)
return rb_convert_type(io, T_FILE, "IO", "to_io");
}
+static VALUE
+rb_io_check_io(io)
+ VALUE io;
+{
+ return rb_check_convert_type(io, T_FILE, "IO", "to_io");
+}
+
static char*
rb_io_mode_string(fptr)
OpenFile *fptr;
@@ -3751,9 +3760,12 @@ prep_path(io, path)
* IO.new(fd, mode) => io
*
* Returns a new <code>IO</code> object (a stream) for the given
- * integer file descriptor and mode string. See also
- * <code>IO#fileno</code> and <code>IO::for_fd</code>.
- *
+ * <code>IO</code> object or integer file descriptor and mode
+ * string. See also <code>IO#fileno</code> and
+ * <code>IO::for_fd</code>.
+ *
+ * puts IO.new($stdout).fileno # => 1
+ *
* a = IO.new(2,"w") # '2' is standard error
* $stderr.puts "Hello"
* a.puts "World"
@@ -3770,14 +3782,24 @@ rb_io_initialize(argc, argv, io)
VALUE *argv;
VALUE io;
{
- VALUE fnum, mode;
- OpenFile *fp;
- int fd, flags;
+ VALUE fnum, mode, orig;
+ OpenFile *fp, *ofp = NULL;
+ int fd, flags, fmode;
char mbuf[4];
rb_secure(4);
rb_scan_args(argc, argv, "11", &fnum, &mode);
- fd = NUM2INT(fnum);
+ orig = rb_io_check_io(fnum);
+ if (NIL_P(orig)) {
+ fd = NUM2INT(fnum);
+ }
+ else {
+ GetOpenFile(orig, ofp);
+ if (ofp->refcnt == LONG_MAX) {
+ VALUE s = rb_inspect(orig);
+ rb_raise(rb_eIOError, "too many shared IO for %s", StringValuePtr(s));
+ }
+ }
if (argc == 2) {
if (FIXNUM_P(mode)) {
flags = FIX2LONG(mode);
@@ -3786,17 +3808,40 @@ rb_io_initialize(argc, argv, io)
SafeStringValue(mode);
flags = rb_io_mode_modenum(RSTRING(mode)->ptr);
}
+ fmode = rb_io_modenum_flags(flags);
}
- else {
+ else if (!ofp) {
#if defined(HAVE_FCNTL) && defined(F_GETFL)
flags = fcntl(fd, F_GETFL);
#else
flags = O_RDONLY;
#endif
+ fmode = rb_io_modenum_flags(flags);
+ }
+ if (!ofp) {
+ MakeOpenFile(io, fp);
+ fp->mode = fmode;
+ fp->f = rb_fdopen(fd, rb_io_modenum_mode(flags, mbuf));
+ }
+ else {
+ if (argc == 2) {
+ if ((ofp->mode ^ fmode) & (FMODE_READWRITE|FMODE_BINMODE)) {
+ if (FIXNUM_P(mode)) {
+ rb_raise(rb_eArgError, "incompatible mode 0%o", flags);
+ }
+ else {
+ rb_raise(rb_eArgError, "incompatible mode %s", RSTRING(mode)->ptr);
+ }
+ }
+ }
+ if (RFILE(io)->fptr) {
+ rb_io_close(io);
+ free(RFILE(io)->fptr);
+ RFILE(io)->fptr = 0;
+ }
+ ofp->refcnt++;
+ RFILE(io)->fptr = ofp;
}
- MakeOpenFile(io, fp);
- fp->mode = rb_io_modenum_flags(flags);
- fp->f = rb_fdopen(fd, rb_io_modenum_mode(flags, mbuf));
return io;
}
diff --git a/rubyio.h b/rubyio.h
index 26f86b0d07..d3b71fb767 100644
--- a/rubyio.h
+++ b/rubyio.h
@@ -24,6 +24,7 @@ typedef struct OpenFile {
int lineno; /* number of lines read */
char *path; /* pathname for file */
void (*finalize) _((struct OpenFile*,int)); /* finalize proc */
+ long refcnt;
} OpenFile;
#define FMODE_READABLE 1
@@ -50,6 +51,7 @@ typedef struct OpenFile {
fp->lineno = 0;\
fp->path = NULL;\
fp->finalize = 0;\
+ fp->refcnt = 1;\
} while (0)
#define GetReadFile(fptr) ((fptr)->f)