xmlSchemaXPathProcessHistory(xmlSchemaValidCtxtPtr vctxt,
			     int depth)
{
    xmlSchemaIDCStateObjPtr sto, nextsto;
    int res, matchDepth;
    xmlSchemaPSVIIDCKeyPtr key = NULL;
    xmlSchemaTypePtr type = vctxt->inode->typeDef, simpleType = NULL;

    if (vctxt->xpathStates == NULL)
	return (0);
    sto = vctxt->xpathStates;

#ifdef DEBUG_IDC
    {
	xmlChar *str = NULL;
	xmlGenericError(xmlGenericErrorContext,
	    "IDC: BACK on %s, depth %d\n",
	    xmlSchemaFormatQName(&str, vctxt->inode->nsName,
		vctxt->inode->localName), vctxt->depth);
	FREE_AND_NULL(str)
    }
#endif
    /*
    * Evaluate the state objects.
    */
    while (sto != NULL) {
	res = xmlStreamPop((xmlStreamCtxtPtr) sto->xpathCtxt);
	if (res == -1) {
	    VERROR_INT("xmlSchemaXPathProcessHistory",
		"calling xmlStreamPop()");
	    return (-1);
	}
#ifdef DEBUG_IDC
	xmlGenericError(xmlGenericErrorContext, "IDC:   stream pop '%s'\n",
	    sto->sel->xpath);
#endif
	if (sto->nbHistory == 0)
	    goto deregister_check;

	matchDepth = sto->history[sto->nbHistory -1];

	/*
	* Only matches at the current depth are of interest.
	*/
	if (matchDepth != depth) {
	    sto = sto->next;
	    continue;
	}
	if (sto->type == XPATH_STATE_OBJ_TYPE_IDC_FIELD) {
	    /*
	    * NOTE: According to
	    *   http://www.w3.org/Bugs/Public/show_bug.cgi?id=2198
	    *   ... the simple-content of complex types is also allowed.
	    */

	    if (WXS_IS_COMPLEX(type)) {
		if (WXS_HAS_SIMPLE_CONTENT(type)) {
		    /*
		    * Sanity check for complex types with simple content.
		    */
		    simpleType = type->contentTypeDef;
		    if (simpleType == NULL) {
			VERROR_INT("xmlSchemaXPathProcessHistory",
			    "field resolves to a CT with simple content "
			    "but the CT is missing the ST definition");
			return (-1);
		    }
		} else
		    simpleType = NULL;
	    } else
		simpleType = type;
	    if (simpleType == NULL) {
		xmlChar *str = NULL;

		/*
		* Not qualified if the field resolves to a node of non
		* simple type.
		*/
		xmlSchemaCustomErr(ACTXT_CAST vctxt,
		    XML_SCHEMAV_CVC_IDC, NULL,
		    WXS_BASIC_CAST sto->matcher->aidc->def,
		    "The XPath '%s' of a field of %s does evaluate to a node of "
		    "non-simple type",
		    sto->sel->xpath,
		    xmlSchemaGetIDCDesignation(&str, sto->matcher->aidc->def));
		FREE_AND_NULL(str);
		sto->nbHistory--;
		goto deregister_check;
	    }

	    if ((key == NULL) && (vctxt->inode->val == NULL)) {
		/*
		* Failed to provide the normalized value; maybe
		* the value was invalid.
		*/
		VERROR(XML_SCHEMAV_CVC_IDC,
		    WXS_BASIC_CAST sto->matcher->aidc->def,
		    "Warning: No precomputed value available, the value "
		    "was either invalid or something strange happend");
		sto->nbHistory--;
		goto deregister_check;
	    } else {
		xmlSchemaIDCMatcherPtr matcher = sto->matcher;
		xmlSchemaPSVIIDCKeyPtr *keySeq;
		int pos, idx;

		/*
		* The key will be anchored on the matcher's list of
		* key-sequences. The position in this list is determined
		* by the target node's depth relative to the matcher's
		* depth of creation (i.e. the depth of the scope element).
		*
		* Element        Depth    Pos   List-entries
		* <scope>          0              NULL
		*   <bar>          1              NULL
		*     <target/>    2       2      target
		*   <bar>
                * </scope>
		*
		* The size of the list is only dependant on the depth of
		* the tree.
		* An entry will be NULLed in selector_leave, i.e. when
		* we hit the target's
		*/
		pos = sto->depth - matcher->depth;
		idx = sto->sel->index;

		/*
		* Create/grow the array of key-sequences.
		*/
		if (matcher->keySeqs == NULL) {
		    if (pos > 9)
			matcher->sizeKeySeqs = pos * 2;
		    else
			matcher->sizeKeySeqs = 10;
		    matcher->keySeqs = (xmlSchemaPSVIIDCKeyPtr **)
			xmlMalloc(matcher->sizeKeySeqs *
			sizeof(xmlSchemaPSVIIDCKeyPtr *));
		    if (matcher->keySeqs == NULL) {
			xmlSchemaVErrMemory(NULL,
			    "allocating an array of key-sequences",
			    NULL);
			return(-1);
		    }
		    memset(matcher->keySeqs, 0,
			matcher->sizeKeySeqs *
			sizeof(xmlSchemaPSVIIDCKeyPtr *));
		} else if (pos >= matcher->sizeKeySeqs) {
		    int i = matcher->sizeKeySeqs;

		    matcher->sizeKeySeqs *= 2;
		    matcher->keySeqs = (xmlSchemaPSVIIDCKeyPtr **)
			xmlRealloc(matcher->keySeqs,
			matcher->sizeKeySeqs *
			sizeof(xmlSchemaPSVIIDCKeyPtr *));
		    if (matcher->keySeqs == NULL) {
			xmlSchemaVErrMemory(NULL,
			    "reallocating an array of key-sequences",
			    NULL);
			return (-1);
		    }
		    /*
		    * The array needs to be NULLed.
		    * TODO: Use memset?
		    */
		    for (; i < matcher->sizeKeySeqs; i++)
			matcher->keySeqs[i] = NULL;
		}

		/*
		* Get/create the key-sequence.
		*/
		keySeq = matcher->keySeqs[pos];
		if (keySeq == NULL) {
		    goto create_sequence;
		} else if (keySeq[idx] != NULL) {
		    xmlChar *str = NULL;
		    /*
		    * cvc-identity-constraint:
		    * 3 For each node in the `target node set` all
		    * of the {fields}, with that node as the context
		    * node, evaluate to either an empty node-set or
		    * a node-set with exactly one member, which must
		    * have a simple type.
		    *
		    * The key was already set; report an error.
		    */
		    xmlSchemaCustomErr(ACTXT_CAST vctxt,
			XML_SCHEMAV_CVC_IDC, NULL,
			WXS_BASIC_CAST matcher->aidc->def,
			"The XPath '%s' of a field of %s evaluates to a "
			"node-set with more than one member",
			sto->sel->xpath,
			xmlSchemaGetIDCDesignation(&str, matcher->aidc->def));
		    FREE_AND_NULL(str);
		    sto->nbHistory--;
		    goto deregister_check;
		} else
		    goto create_key;

create_sequence:
		/*
		* Create a key-sequence.
		*/
		keySeq = (xmlSchemaPSVIIDCKeyPtr *) xmlMalloc(
		    matcher->aidc->def->nbFields *
		    sizeof(xmlSchemaPSVIIDCKeyPtr));
		if (keySeq == NULL) {
		    xmlSchemaVErrMemory(NULL,
			"allocating an IDC key-sequence", NULL);
		    return(-1);
		}
		memset(keySeq, 0, matcher->aidc->def->nbFields *
		    sizeof(xmlSchemaPSVIIDCKeyPtr));
		matcher->keySeqs[pos] = keySeq;
create_key:
		/*
		* Create a key once per node only.
		*/
		if (key == NULL) {
		    key = (xmlSchemaPSVIIDCKeyPtr) xmlMalloc(
			sizeof(xmlSchemaPSVIIDCKey));
		    if (key == NULL) {
			xmlSchemaVErrMemory(NULL,
			    "allocating a IDC key", NULL);
			xmlFree(keySeq);
			matcher->keySeqs[pos] = NULL;
			return(-1);
		    }
		    /*
		    * Consume the compiled value.
		    */
		    key->type = simpleType;
		    key->val = vctxt->inode->val;
		    vctxt->inode->val = NULL;
		    /*
		    * Store the key in a global list.
		    */
		    if (xmlSchemaIDCStoreKey(vctxt, key) == -1) {
			xmlSchemaIDCFreeKey(key);
			return (-1);
		    }
		}
		keySeq[idx] = key;
	    }
	} else if (sto->type == XPATH_STATE_OBJ_TYPE_IDC_SELECTOR) {

	    xmlSchemaPSVIIDCKeyPtr **keySeq = NULL;
	    /* xmlSchemaPSVIIDCBindingPtr bind; */
	    xmlSchemaPSVIIDCNodePtr ntItem;
	    xmlSchemaIDCMatcherPtr matcher;
	    xmlSchemaIDCPtr idc;
	    xmlSchemaItemListPtr targets;
	    int pos, i, j, nbKeys;
	    /*
	    * Here we have the following scenario:
	    * An IDC 'selector' state object resolved to a target node,
	    * during the time this target node was in the
	    * ancestor-or-self axis, the 'field' state object(s) looked
	    * out for matching nodes to create a key-sequence for this
	    * target node. Now we are back to this target node and need
	    * to put the key-sequence, together with the target node
	    * itself, into the node-table of the corresponding IDC
	    * binding.
	    */
	    matcher = sto->matcher;
	    idc = matcher->aidc->def;
	    nbKeys = idc->nbFields;
	    pos = depth - matcher->depth;
	    /*
	    * Check if the matcher has any key-sequences at all, plus
	    * if it has a key-sequence for the current target node.
	    */
	    if ((matcher->keySeqs == NULL) ||
		(matcher->sizeKeySeqs <= pos)) {
		if (idc->type == XML_SCHEMA_TYPE_IDC_KEY)
		    goto selector_key_error;
		else
		    goto selector_leave;
	    }

	    keySeq = &(matcher->keySeqs[pos]);
	    if (*keySeq == NULL) {
		if (idc->type == XML_SCHEMA_TYPE_IDC_KEY)
		    goto selector_key_error;
		else
		    goto selector_leave;
	    }

	    for (i = 0; i < nbKeys; i++) {
		if ((*keySeq)[i] == NULL) {
		    /*
		    * Not qualified, if not all fields did resolve.
		    */
		    if (idc->type == XML_SCHEMA_TYPE_IDC_KEY) {
			/*
			* All fields of a "key" IDC must resolve.
			*/
			goto selector_key_error;
		    }
		    goto selector_leave;
		}
	    }
	    /*
	    * All fields did resolve.
	    */

	    /*
	    * 4.1 If the {identity-constraint category} is unique(/key),
	    * then no two members of the `qualified node set` have
	    * `key-sequences` whose members are pairwise equal, as
	    * defined by Equal in [XML Schemas: Datatypes].
	    *
	    * Get the IDC binding from the matcher and check for
	    * duplicate key-sequences.
	    */
#if 0
	    bind = xmlSchemaIDCAcquireBinding(vctxt, matcher);
#endif
	    targets = xmlSchemaIDCAcquireTargetList(vctxt, matcher);
	    if ((idc->type != XML_SCHEMA_TYPE_IDC_KEYREF) &&
		(targets->nbItems != 0)) {
		xmlSchemaPSVIIDCKeyPtr ckey, bkey, *bkeySeq;

		i = 0;
		res = 0;
		/*
		* Compare the key-sequences, key by key.
		*/
		do {
		    bkeySeq =
			((xmlSchemaPSVIIDCNodePtr) targets->items[i])->keys;
		    for (j = 0; j < nbKeys; j++) {
			ckey = (*keySeq)[j];
			bkey = bkeySeq[j];
			res = xmlSchemaAreValuesEqual(ckey->val, bkey->val);
			if (res == -1) {
			    return (-1);
			} else if (res == 0) {
			    /*
			    * One of the keys differs, so the key-sequence
			    * won't be equal; get out.
			    */
			    break;
			}
		    }
		    if (res == 1) {
			/*
			* Duplicate key-sequence found.
			*/
			break;
		    }
		    i++;
		} while (i < targets->nbItems);
		if (i != targets->nbItems) {
		    xmlChar *str = NULL, *strB = NULL;
		    /*
		    * TODO: Try to report the key-sequence.
		    */
		    xmlSchemaCustomErr(ACTXT_CAST vctxt,
			XML_SCHEMAV_CVC_IDC, NULL,
			WXS_BASIC_CAST idc,
			"Duplicate key-sequence %s in %s",
			xmlSchemaFormatIDCKeySequence(vctxt, &str,
			    (*keySeq), nbKeys),
			xmlSchemaGetIDCDesignation(&strB, idc));
		    FREE_AND_NULL(str);
		    FREE_AND_NULL(strB);
		    goto selector_leave;
		}
	    }
	    /*
	    * Add a node-table item to the IDC binding.
	    */
	    ntItem = (xmlSchemaPSVIIDCNodePtr) xmlMalloc(
		sizeof(xmlSchemaPSVIIDCNode));
	    if (ntItem == NULL) {
		xmlSchemaVErrMemory(NULL,
		    "allocating an IDC node-table item", NULL);
		xmlFree(*keySeq);
		*keySeq = NULL;
		return(-1);
	    }
	    memset(ntItem, 0, sizeof(xmlSchemaPSVIIDCNode));

	    /*
	    * Store the node-table item in a global list.
	    */
	    if (idc->type != XML_SCHEMA_TYPE_IDC_KEYREF) {
		if (xmlSchemaIDCStoreNodeTableItem(vctxt, ntItem) == -1) {
		    xmlFree(ntItem);
		    xmlFree(*keySeq);
		    *keySeq = NULL;
		    return (-1);
		}
		ntItem->nodeQNameID = -1;
	    } else {
		/*
		* Save a cached QName for this node on the IDC node, to be
		* able to report it, even if the node is not saved.
		*/
		ntItem->nodeQNameID = xmlSchemaVAddNodeQName(vctxt,
		    vctxt->inode->localName, vctxt->inode->nsName);
		if (ntItem->nodeQNameID == -1) {
		    xmlFree(ntItem);
		    xmlFree(*keySeq);
		    *keySeq = NULL;
		    return (-1);
		}
	    }
	    /*
	    * Init the node-table item: Save the node, position and
	    * consume the key-sequence.
	    */
	    ntItem->node = vctxt->node;
	    ntItem->nodeLine = vctxt->inode->nodeLine;
	    ntItem->keys = *keySeq;
	    *keySeq = NULL;
#if 0
	    if (xmlSchemaIDCAppendNodeTableItem(bind, ntItem) == -1)
#endif
	    if (xmlSchemaItemListAdd(targets, ntItem) == -1) {
		if (idc->type == XML_SCHEMA_TYPE_IDC_KEYREF) {
		    /*
		    * Free the item, since keyref items won't be
		    * put on a global list.
		    */
		    xmlFree(ntItem->keys);
		    xmlFree(ntItem);
		}
		return (-1);
	    }

	    goto selector_leave;
selector_key_error:
	    {
		xmlChar *str = NULL;
		/*
		* 4.2.1 (KEY) The `target node set` and the
		* `qualified node set` are equal, that is, every
		* member of the `target node set` is also a member
		* of the `qualified node set` and vice versa.
		*/
		xmlSchemaCustomErr(ACTXT_CAST vctxt,
		    XML_SCHEMAV_CVC_IDC, NULL,
		    WXS_BASIC_CAST idc,
		    "Not all fields of %s evaluate to a node",
		    xmlSchemaGetIDCDesignation(&str, idc), NULL);
		FREE_AND_NULL(str);
	    }
selector_leave:
	    /*
	    * Free the key-sequence if not added to the IDC table.
	    */
	    if ((keySeq != NULL) && (*keySeq != NULL)) {
		xmlFree(*keySeq);
		*keySeq = NULL;
	    }
	} /* if selector */

	sto->nbHistory--;

deregister_check:
	/*
	* Deregister state objects if they reach the depth of creation.
	*/
	if ((sto->nbHistory == 0) && (sto->depth == depth)) {
#ifdef DEBUG_IDC
	    xmlGenericError(xmlGenericErrorContext, "IDC:   STO pop '%s'\n",
		sto->sel->xpath);
#endif
	    if (vctxt->xpathStates != sto) {
		VERROR_INT("xmlSchemaXPathProcessHistory",
		    "The state object to be removed is not the first "
		    "in the list");
	    }
	    nextsto = sto->next;
	    /*
	    * Unlink from the list of active XPath state objects.
	    */
	    vctxt->xpathStates = sto->next;
	    sto->next = vctxt->xpathStatePool;
	    /*
	    * Link it to the pool of reusable state objects.
	    */
	    vctxt->xpathStatePool = sto;
	    sto = nextsto;
	} else
	    sto = sto->next;
    } /* while (sto != NULL) */
    return (0);
}