/* 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);
}