From b0e0f45571d509a3d76732b76aa63a96ad6b371f Mon Sep 17 00:00:00 2001 From: nobu Date: Wed, 25 Feb 2004 12:17:39 +0000 Subject: * 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 --- ChangeLog | 7 +++++++ gc.c | 1 - io.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++----------- rubyio.h | 2 ++ 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 + + * 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 * 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 IO object (a stream) for the given - * integer file descriptor and mode string. See also - * IO#fileno and IO::for_fd. - * + * IO object or integer file descriptor and mode + * string. See also IO#fileno and + * IO::for_fd. + * + * 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) -- cgit v1.2.3