Reworked output file writing.
[ruby-vorbistagger.git] / ext / ext.c
index da2798f579495d9bdf81f0f2a8f84876335b3607..0ee20d352d06b640c19734459684d3bf5f3a044f 100644 (file)
--- a/ext/ext.c
+++ b/ext/ext.c
  */
 
 #include <ruby.h>
+#include <stdio.h>
 #include <stdbool.h>
+#include <errno.h>
 
 #include "vcedit.h"
 #include "comments.h"
 
 typedef struct {
-       VALUE io;
-       bool need_close;
-
        vcedit_state *state;
-
        VALUE comments;
 } RbVorbisTagger;
 
 static VALUE c_close (VALUE self);
 
-static VALUE cComments, eVTError, io_buf;
-static ID id_read, id_write, id_seek, id_length;
-
-static size_t
-on_read (void *ptr, size_t size, size_t nmemb, RbVorbisTagger *o)
-{
-       struct RString *buf;
-       size_t total = size * nmemb;
-       VALUE tmp;
-
-       rb_str_resize (io_buf, size * nmemb);
-
-       tmp = rb_funcall (o->io, id_read, 2, LONG2NUM (total), io_buf);
-       if (NIL_P (tmp))
-               return 0;
-
-       buf = RSTRING (tmp);
-       memcpy (ptr, buf->ptr, buf->len);
-
-       return buf->len;
-}
-
-static size_t
-on_write (const void *ptr, size_t size, size_t nmemb, RbVorbisTagger *o)
-{
-       size_t total = size * nmemb;
-
-       rb_str_resize (io_buf, total);
-       memcpy (RSTRING (io_buf)->ptr, ptr, total);
-
-       return NUM2LONG (rb_io_write (o->io, io_buf));
-}
-
-static void
-c_mark (RbVorbisTagger *o)
-{
-       rb_gc_mark (o->io);
-       rb_gc_mark (o->comments);
-}
+static VALUE cComments, eVTError;
+static ID id_length;
 
 static void
 c_free (RbVorbisTagger *o)
@@ -83,6 +44,12 @@ c_free (RbVorbisTagger *o)
        ruby_xfree (o);
 }
 
+static void
+c_mark (RbVorbisTagger *o)
+{
+       rb_gc_mark (o->comments);
+}
+
 static VALUE
 c_alloc (VALUE klass)
 {
@@ -94,14 +61,12 @@ c_alloc (VALUE klass)
 /*
  * call-seq:
  *  Ogg::Vorbis::Tagger.open(arg)                    -> object
- *  Ogg::Vorbis::Tagger.open(arg) { |object| block } -> nil
+ *  Ogg::Vorbis::Tagger.open(arg) { |object| block } -> object
  *
  * If a block isn't specified, Ogg::Vorbis::Tagger.open is a synonym
  * for Ogg::Vorbis::Tagger.new.
- * If a block is given, it will be invoked with the
- * Ogg::Vorbis::Tagger object as a parameter, and the file or IO object
- * will be automatically closed when the block terminates.
- * The method always returns +nil+ in this case.
+ * If a block is given, it will be invoked with the * Ogg::Vorbis::Tagger
+ * object as a parameter.
  */
 static VALUE
 c_open (VALUE klass, VALUE arg)
@@ -116,47 +81,28 @@ c_open (VALUE klass, VALUE arg)
 
 /*
  * call-seq:
- *  Ogg::Vorbis::Tagger.new(arg) -> object
+ *  Ogg::Vorbis::Tagger.new(filename) -> object
  *
- * Returns a new Ogg::Vorbis::Tagger object for the specified argument.
- * *arg* can either be an IO object or a filename.
+ * Returns a new Ogg::Vorbis::Tagger object for the specified file.
  *
  * FIXME: add optional mode argument (read-only or read-write)
  */
 static VALUE
-c_init (VALUE self, VALUE io)
+c_init (VALUE self, VALUE filename)
 {
        RbVorbisTagger *o;
        vorbis_comment *vc;
-       int s, i;
+       int i;
 
        Data_Get_Struct (self, RbVorbisTagger, o);
 
-       /* is this actually an IO object or a filename? */
-       if (rb_respond_to (io, id_read) &&
-           rb_respond_to (io, id_write) &&
-           rb_respond_to (io, id_seek))
-               o->need_close = false;
-       else if (!NIL_P (rb_check_string_type (io))) {
-               io = rb_file_open (StringValuePtr (io), "rb+");
-               o->need_close = true;
-       } else
-               rb_raise (rb_eArgError, "invalid argument");
+       StringValue (filename);
 
-       o->io = io;
-
-       o->state = vcedit_state_new ();
+       o->state = vcedit_state_new (StringValuePtr (filename));
        if (!o->state)
                rb_raise (eVTError, "vcedit_new_state() failed - %s",
                          vcedit_error (o->state));
 
-       s = vcedit_open_callbacks (o->state, o,
-                                  (vcedit_read_func) on_read,
-                                  (vcedit_write_func) on_write);
-       if (s < 0)
-               rb_raise (eVTError, "vcedit_open_callbacks() failed - %s",
-                         vcedit_error (o->state));
-
        vc = vcedit_comments (o->state);
        if (!vc)
                rb_raise (eVTError, "vcedit_comments() failed - %s",
@@ -194,9 +140,6 @@ c_close (VALUE self)
        vcedit_state_unref (o->state);
        o->state = NULL;
 
-       if (o->need_close)
-               rb_io_close (o->io);
-
        return self;
 }
 
@@ -211,17 +154,12 @@ static VALUE
 c_write (VALUE self)
 {
        RbVorbisTagger *o;
-       int s;
 
        Data_Get_Struct (self, RbVorbisTagger, o);
 
        comments_sync (o->comments, o->state);
 
-       /* seek back to BOF */
-       rb_funcall (o->io, id_seek, 1, INT2FIX (0));
-
-       s = vcedit_write (o->state, o);
-       if (s < 0)
+       if (vcedit_write (o->state) < 0)
                rb_raise (rb_eIOError, "write failed - %s",
                          vcedit_error (o->state));
 
@@ -263,19 +201,12 @@ Init_vorbistagger_ext (void)
 
        rb_define_singleton_method (cVT, "open", c_open, 1);
        rb_define_method (cVT, "initialize", c_init, 1);
-       rb_define_method (cVT, "close", c_close, 0);
        rb_define_method (cVT, "write", c_write, 0);
        rb_define_method (cVT, "comments", c_comments, 0);
 
        eVTError = rb_define_class_under (cVT, "TaggerError", eVorbis);
 
-       id_read = rb_intern ("read");
-       id_write = rb_intern ("write");
-       id_seek = rb_intern ("seek");
        id_length = rb_intern ("length");
 
        cComments = Init_Comments (mVorbis);
-
-       io_buf = rb_str_buf_new (0);
-       rb_global_variable (&io_buf);
 }