/*
 * call-seq:
 *  evaluate(search_path)
 *
 * Evaluate the +search_path+ returning an XML::XPath object.
 */
static VALUE evaluate(int argc, VALUE *argv, VALUE self)
{
  VALUE search_path, xpath_handler;
  xmlXPathContextPtr ctx;
  Data_Get_Struct(self, xmlXPathContext, ctx);
  VALUE error_list      = rb_ary_new();

  if(rb_scan_args(argc, argv, "11", &search_path, &xpath_handler) == 1)
    xpath_handler = Qnil;

  xmlChar* query = (xmlChar *)StringValuePtr(search_path);

  if(Qnil != xpath_handler) {
    // FIXME: not sure if this is the correct place to shove private data.
    ctx->userData = (void *)xpath_handler;
    xmlXPathRegisterFuncLookup(ctx, lookup, (void *)xpath_handler);
  }

  xmlResetLastError();
  xmlSetStructuredErrorFunc((void *)error_list, Nokogiri_error_array_pusher);
  xmlXPathObjectPtr xpath = xmlXPathEvalExpression(query, ctx);
  xmlSetStructuredErrorFunc(NULL, NULL);

  if(xpath == NULL) {
    VALUE xpath = rb_const_get(mNokogiriXml, rb_intern("XPath"));
    VALUE klass = rb_const_get(xpath, rb_intern("SyntaxError"));

    xmlErrorPtr error = xmlGetLastError();
    rb_funcall(rb_mKernel, rb_intern("raise"), 1,
        Nokogiri_wrap_xml_syntax_error(klass, error)
    );
  }

  VALUE xpath_object = Nokogiri_wrap_xml_xpath(xpath);

  assert(ctx->doc);
  assert(ctx->doc->_private);

  rb_funcall( xpath_object,
              rb_intern("document="),
              1,
              (VALUE)ctx->doc->_private
    );
  return xpath_object;
}