/* TODO: DOCUMENT ME */
static VALUE in_context(VALUE self, VALUE _str, VALUE _options)
{
xmlNodePtr node, list = 0, child_iter, node_children, doc_children;
xmlNodeSetPtr set;
xmlParserErrors error;
VALUE doc, err;
int doc_is_empty;
Data_Get_Struct(self, xmlNode, node);
doc = DOC_RUBY_OBJECT(node->doc);
err = rb_iv_get(doc, "@errors");
doc_is_empty = (node->doc->children == NULL) ? 1 : 0;
node_children = node->children;
doc_children = node->doc->children;
xmlSetStructuredErrorFunc((void *)err, Nokogiri_error_array_pusher);
/* Twiddle global variable because of a bug in libxml2.
* http://git.gnome.org/browse/libxml2/commit/?id=e20fb5a72c83cbfc8e4a8aa3943c6be8febadab7
*/
#ifndef HTML_PARSE_NOIMPLIED
htmlHandleOmittedElem(0);
#endif
/* This function adds a fake node to the child of +node+. If the parser
* does not exit cleanly with XML_ERR_OK, the list is freed. This can
* leave the child pointers in a bad state if they were originally empty.
*
* http://git.gnome.org/browse/libxml2/tree/parser.c#n13177
* */
error = xmlParseInNodeContext(node, StringValuePtr(_str),
(int)RSTRING_LEN(_str),
(int)NUM2INT(_options), &list);
/* xmlParseInNodeContext should not mutate the original document or node,
* so reassigning these pointers should be OK. The reason we're reassigning
* is because if there were errors, it's possible for the child pointers
* to be manipulated. */
if (error != XML_ERR_OK) {
node->doc->children = doc_children;
node->children = node_children;
}
/* make sure parent/child pointers are coherent so an unlink will work
* properly (#331)
*/
child_iter = node->doc->children ;
while (child_iter) {
if (child_iter->parent != (xmlNodePtr)node->doc)
child_iter->parent = (xmlNodePtr)node->doc;
child_iter = child_iter->next;
}
#ifndef HTML_PARSE_NOIMPLIED
htmlHandleOmittedElem(1);
#endif
xmlSetStructuredErrorFunc(NULL, NULL);
/* Workaround for a libxml2 bug where a parsing error may leave a broken
* node reference in node->doc->children.
* This workaround is limited to when a parse error occurs, the document
* went from having no children to having children, and the context node is
* part of a document fragment.
* https://bugzilla.gnome.org/show_bug.cgi?id=668155
*/
if (error != XML_ERR_OK && doc_is_empty && node->doc->children != NULL) {
child_iter = node;
while (child_iter->parent)
child_iter = child_iter->parent;
if (child_iter->type == XML_DOCUMENT_FRAG_NODE)
node->doc->children = NULL;
}
/* FIXME: This probably needs to handle more constants... */
switch (error) {
case XML_ERR_INTERNAL_ERROR:
case XML_ERR_NO_MEMORY:
rb_raise(rb_eRuntimeError, "error parsing fragment (%d)", error);
break;
default:
break;
}
set = xmlXPathNodeSetCreate(NULL);
while (list) {
xmlXPathNodeSetAddUnique(set, list);
list = list->next;
}
return Nokogiri_wrap_xml_node_set(set, doc);
}