Made Ogg::Vorbis::Tagger#close return nil.
[ruby-vorbistagger.git] / ext / ext.c
index 0ee20d352d06b640c19734459684d3bf5f3a044f..46ce0d178d1090296f6a74b16e29b205e692c706 100644 (file)
--- a/ext/ext.c
+++ b/ext/ext.c
 #include <stdio.h>
 #include <stdbool.h>
 #include <errno.h>
+#include <assert.h>
 
 #include "vcedit.h"
 #include "comments.h"
 
+#define CHECK_CLOSED(o) \
+       if (!o->state) \
+               rb_raise (eClosed, "closed stream");
+
 typedef struct {
        vcedit_state *state;
        VALUE comments;
@@ -31,7 +36,8 @@ typedef struct {
 
 static VALUE c_close (VALUE self);
 
-static VALUE cComments, eVTError;
+static VALUE cComments, eVT, eClosed, eOpen, eInvalidData,
+             eInvalidComment, eTempFile, eReopen;
 static ID id_length;
 
 static void
@@ -100,13 +106,23 @@ c_init (VALUE self, VALUE filename)
 
        o->state = vcedit_state_new (StringValuePtr (filename));
        if (!o->state)
-               rb_raise (eVTError, "vcedit_new_state() failed - %s",
-                         vcedit_error (o->state));
+               rb_raise (rb_eNoMemError, "Out of Memory");
+
+       switch (vcedit_open (o->state)) {
+               case VCEDIT_ERR_OPEN:
+                       rb_raise (eOpen, "Cannot open file");
+               case VCEDIT_ERR_INVAL:
+                       rb_raise (eInvalidData, "Invalid data");
+               default:
+                       break;
+       }
 
        vc = vcedit_comments (o->state);
-       if (!vc)
-               rb_raise (eVTError, "vcedit_comments() failed - %s",
-                         vcedit_error (o->state));
+
+       /* vcedit_open() succeeded, so vcedit_comments() cannot
+        * return NULL.
+        */
+       assert (vc);
 
        /* check whether all comments are well-formed */
        for (i = 0; i < vc->comments; i++) {
@@ -114,7 +130,7 @@ c_init (VALUE self, VALUE filename)
 
                ptr = strchr (content, '=');
                if (!ptr || ptr == content)
-                       rb_raise (eVTError, "malformed comment - %s", content);
+                       rb_raise (eInvalidComment, "invalid comment - %s", content);
        }
 
        o->comments = rb_class_new_instance (0, NULL, cComments);
@@ -126,9 +142,11 @@ c_init (VALUE self, VALUE filename)
 
 /*
  * call-seq:
- *  object.close -> object
+ *  object.close -> nil
  *
- * Closes *object* and returns it.
+ * Closes *object*. Further method calls on *object* will raise an
+ * Ogg::Vorbis::Tagger::ClosedStreamError exception.
+ * Returns +nil+.
  */
 static VALUE
 c_close (VALUE self)
@@ -137,10 +155,12 @@ c_close (VALUE self)
 
        Data_Get_Struct (self, RbVorbisTagger, o);
 
+       CHECK_CLOSED (o);
+
        vcedit_state_unref (o->state);
        o->state = NULL;
 
-       return self;
+       return Qnil;
 }
 
 /*
@@ -157,11 +177,20 @@ c_write (VALUE self)
 
        Data_Get_Struct (self, RbVorbisTagger, o);
 
+       CHECK_CLOSED (o);
+
        comments_sync (o->comments, o->state);
 
-       if (vcedit_write (o->state) < 0)
-               rb_raise (rb_eIOError, "write failed - %s",
-                         vcedit_error (o->state));
+       switch (vcedit_write (o->state)) {
+               case VCEDIT_ERR_INVAL:
+                       rb_raise (eInvalidData, "Invalid data");
+               case VCEDIT_ERR_TMPFILE:
+                       rb_raise (eTempFile, "Cannot create temporary file");
+               case VCEDIT_ERR_REOPEN:
+                       rb_raise (eReopen, "Cannot reopen file");
+               default:
+                       break;
+       }
 
        return rb_funcall (o->comments, id_length, 0);
 }
@@ -180,6 +209,8 @@ c_comments (VALUE self)
 
        Data_Get_Struct (self, RbVorbisTagger, o);
 
+       CHECK_CLOSED (o);
+
        return o->comments;
 }
 
@@ -201,10 +232,18 @@ 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);
+       eVT = rb_define_class_under (cVT, "TaggerError", eVorbis);
+       eClosed = rb_define_class_under (cVT, "ClosedStreamError", eVT);
+       eOpen = rb_define_class_under (cVT, "OpenError", eVT);
+       eInvalidData = rb_define_class_under (cVT, "InvalidDataError", eVT);
+       eInvalidComment = rb_define_class_under (cVT, "InvalidCommentError",
+                                                eInvalidData);
+       eTempFile = rb_define_class_under (cVT, "TempFileError", eVT);
+       eReopen = rb_define_class_under (cVT, "ReopenError", eVT);
 
        id_length = rb_intern ("length");