read_io (Nokogiri::HTML::Document)

    /*
     * call-seq:
     *  read_io(io, url, encoding, options)
     *
     * Read the HTML document from +io+ with given +url+, +encoding+,
     * and +options+.  See Nokogiri::HTML.parse
     */
    static VALUE read_io( VALUE klass,
                          VALUE io,
                          VALUE url,
                          VALUE encoding,
                          VALUE options )
    {
      const char * c_url    = (url == Qnil) ? NULL : StringValuePtr(url);
      const char * c_enc    = (encoding == Qnil) ? NULL : StringValuePtr(encoding);
      VALUE error_list      = rb_ary_new();

      xmlInitParser();
      xmlResetLastError();
      xmlSetStructuredErrorFunc((void *)error_list, Nokogiri_error_array_pusher);

      htmlDocPtr doc = htmlReadIO(
          io_read_callback,
          io_close_callback,
          (void *)io,
          c_url,
          c_enc,
          NUM2INT(options)
      );
      xmlSetStructuredErrorFunc(NULL, NULL);

      if(doc == NULL) {
        xmlFreeDoc(doc);

        xmlErrorPtr error = xmlGetLastError();
        if(error)
          rb_funcall(rb_mKernel, rb_intern("raise"), 1,
              Nokogiri_wrap_xml_syntax_error((VALUE)NULL, error)
          );
        else
          rb_raise(rb_eRuntimeError, "Could not parse document");

        return Qnil;
      }

      VALUE document = Nokogiri_wrap_xml_document(klass, doc);
      rb_funcall(document, rb_intern("errors="), 1, error_list);
      return document;
    }