Beispiel #1
0
/**
 * exsltMathLowestFunction:
 * @ctxt:  an XPath parser context
 * @nargs:  the number of arguments
 *
 * Wraps #exsltMathLowest for use by the XPath processor
 */
static void
exsltMathLowestFunction (xmlXPathParserContextPtr ctxt, int nargs) {
    xmlNodeSetPtr ns, ret;
    void *user = NULL;
    

    if (nargs != 1) {
	xmlXPathSetArityError(ctxt);
	return;
    }

    /* We need to delay the freeing of value->user */
    if ((ctxt->value != NULL) && (ctxt->value->boolval != 0)) {
        user = ctxt->value->user;
	ctxt->value->boolval = 0;
	ctxt->value->user = NULL;
    }
    ns = xmlXPathPopNodeSet(ctxt);
    if (xmlXPathCheckError(ctxt))
	return;

    ret = exsltMathLowest(ns);

    xmlXPathFreeNodeSet(ns);
    if (user != NULL)
        xmlFreeNodeList((xmlNodePtr)user);

    xmlXPathReturnNodeSet(ctxt, ret);
}
static void ruby_funcall(xmlXPathParserContextPtr ctx, int nargs)
{
  VALUE xpath_handler = Qnil;
  VALUE result;
  VALUE *argv;
  VALUE doc;
  VALUE node_set = Qnil;
  xmlNodeSetPtr xml_node_set = NULL;
  xmlXPathObjectPtr obj;
  int i;
  nokogiriNodeSetTuple *node_set_tuple;

  assert(ctx);
  assert(ctx->context);
  assert(ctx->context->userData);
  assert(ctx->context->doc);
  assert(DOC_RUBY_OBJECT_TEST(ctx->context->doc));

  xpath_handler = (VALUE)(ctx->context->userData);

  argv = (VALUE *)calloc((size_t)nargs, sizeof(VALUE));
  for (i = 0 ; i < nargs ; ++i) {
    rb_gc_register_address(&argv[i]);
  }

  doc = DOC_RUBY_OBJECT(ctx->context->doc);

  if (nargs > 0) {
    i = nargs - 1;
    do {
      obj = valuePop(ctx);
      switch(obj->type) {
        case XPATH_STRING:
          argv[i] = NOKOGIRI_STR_NEW2(obj->stringval);
          break;
        case XPATH_BOOLEAN:
          argv[i] = obj->boolval == 1 ? Qtrue : Qfalse;
          break;
        case XPATH_NUMBER:
          argv[i] = rb_float_new(obj->floatval);
          break;
        case XPATH_NODESET:
          argv[i] = Nokogiri_wrap_xml_node_set(obj->nodesetval, doc);
          break;
        default:
          argv[i] = NOKOGIRI_STR_NEW2(xmlXPathCastToString(obj));
      }
      xmlXPathFreeNodeSetList(obj);
    } while(i-- > 0);
  }

  result = rb_funcall2(
      xpath_handler,
      rb_intern((const char *)ctx->context->function),
      nargs,
      argv
  );

  for (i = 0 ; i < nargs ; ++i) {
    rb_gc_unregister_address(&argv[i]);
  }
  free(argv);

  switch(TYPE(result)) {
    case T_FLOAT:
    case T_BIGNUM:
    case T_FIXNUM:
      xmlXPathReturnNumber(ctx, NUM2DBL(result));
      break;
    case T_STRING:
      xmlXPathReturnString(
          ctx,
          (xmlChar *)xmlXPathWrapCString(StringValuePtr(result))
      );
      break;
    case T_TRUE:
      xmlXPathReturnTrue(ctx);
      break;
    case T_FALSE:
      xmlXPathReturnFalse(ctx);
      break;
    case T_NIL:
      break;
    case T_ARRAY:
      {
        VALUE args[2];
	args[0] = doc;
	args[1] = result;
        node_set = rb_class_new_instance(2, args, cNokogiriXmlNodeSet);
        Data_Get_Struct(node_set, nokogiriNodeSetTuple, node_set_tuple);
	xml_node_set = node_set_tuple->node_set;
        xmlXPathReturnNodeSet(ctx, xmlXPathNodeSetMerge(NULL, xml_node_set));
      }
      break;
    case T_DATA:
      if(rb_obj_is_kind_of(result, cNokogiriXmlNodeSet)) {
        Data_Get_Struct(result, nokogiriNodeSetTuple, node_set_tuple);
	xml_node_set = node_set_tuple->node_set;
        /* Copy the node set, otherwise it will get GC'd. */
        xmlXPathReturnNodeSet(ctx, xmlXPathNodeSetMerge(NULL, xml_node_set));
        break;
      }
    default:
      rb_raise(rb_eRuntimeError, "Invalid return type");
  }
}