xmlRelaxNGComputeInterleaves(xmlRelaxNGDefinePtr def,
                             xmlRelaxNGParserCtxtPtr ctxt,
                             xmlChar * name ATTRIBUTE_UNUSED)
{
    xmlRelaxNGDefinePtr cur, *tmp;

    xmlRelaxNGPartitionPtr partitions = NULL;
    xmlRelaxNGInterleaveGroupPtr *groups = NULL;
    xmlRelaxNGInterleaveGroupPtr group;
    int i, j, ret, res;
    int nbgroups = 0;
    int nbchild = 0;
    int is_mixed = 0;
    int is_determinist = 1;

    /*
     * Don't run that check in case of error. Infinite recursion
     * becomes possible.
     */
    if (ctxt->nbErrors != 0)
        return;

#ifdef DEBUG_INTERLEAVE
    xmlGenericError(xmlGenericErrorContext,
                    "xmlRelaxNGComputeInterleaves(%s)\n", name);
#endif
    cur = def->content;
    while (cur != NULL) {
        nbchild++;
        cur = cur->next;
    }

#ifdef DEBUG_INTERLEAVE
    xmlGenericError(xmlGenericErrorContext, "  %d child\n", nbchild);
#endif
    groups = (xmlRelaxNGInterleaveGroupPtr *)
        xmlMalloc(nbchild * sizeof(xmlRelaxNGInterleaveGroupPtr));
    if (groups == NULL)
        goto error;
    cur = def->content;
    while (cur != NULL) {
        groups[nbgroups] = (xmlRelaxNGInterleaveGroupPtr)
            xmlMalloc(sizeof(xmlRelaxNGInterleaveGroup));
        if (groups[nbgroups] == NULL)
            goto error;
        if (cur->type == XML_RELAXNG_TEXT)
            is_mixed++;
        groups[nbgroups]->rule = cur;
        groups[nbgroups]->defs = xmlRelaxNGGetElements(ctxt, cur, 0);
        groups[nbgroups]->attrs = xmlRelaxNGGetElements(ctxt, cur, 1);
        nbgroups++;
        cur = cur->next;
    }
#ifdef DEBUG_INTERLEAVE
    xmlGenericError(xmlGenericErrorContext, "  %d groups\n", nbgroups);
#endif

    /*
     * Let's check that all rules makes a partitions according to 7.4
     */
    partitions = (xmlRelaxNGPartitionPtr)
        xmlMalloc(sizeof(xmlRelaxNGPartition));
    if (partitions == NULL)
        goto error;
    memset(partitions, 0, sizeof(xmlRelaxNGPartition));
    partitions->nbgroups = nbgroups;
    partitions->triage = xmlHashCreate(nbgroups);
    for (i = 0; i < nbgroups; i++) {
        group = groups[i];
        for (j = i + 1; j < nbgroups; j++) {
            if (groups[j] == NULL)
                continue;

            ret = xmlRelaxNGCompareElemDefLists(ctxt, group->defs,
                                                groups[j]->defs);
            if (ret == 0) {
                xmlRngPErr(ctxt, def->node, XML_RNGP_ELEM_TEXT_CONFLICT,
                           "Element or text conflicts in interleave\n",
                           NULL, NULL);
            }
            ret = xmlRelaxNGCompareElemDefLists(ctxt, group->attrs,
                                                groups[j]->attrs);
            if (ret == 0) {
                xmlRngPErr(ctxt, def->node, XML_RNGP_ATTR_CONFLICT,
                           "Attributes conflicts in interleave\n", NULL,
                           NULL);
            }
        }
        tmp = group->defs;
        if ((tmp != NULL) && (*tmp != NULL)) {
            while (*tmp != NULL) {
                if ((*tmp)->type == XML_RELAXNG_TEXT) {
                    res = xmlHashAddEntry2(partitions->triage,
                                           BAD_CAST "#text", NULL,
                                           (void *) (long) (i + 1));
                    if (res != 0)
                        is_determinist = -1;
                } else if (((*tmp)->type == XML_RELAXNG_ELEMENT) &&
                           ((*tmp)->name != NULL)) {
                    if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
                        res = xmlHashAddEntry2(partitions->triage,
                                               (*tmp)->name, NULL,
                                               (void *) (long) (i + 1));
                    else
                        res = xmlHashAddEntry2(partitions->triage,
                                               (*tmp)->name, (*tmp)->ns,
                                               (void *) (long) (i + 1));
                    if (res != 0)
                        is_determinist = -1;
                } else if ((*tmp)->type == XML_RELAXNG_ELEMENT) {
                    if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
                        res = xmlHashAddEntry2(partitions->triage,
                                               BAD_CAST "#any", NULL,
                                               (void *) (long) (i + 1));
                    else
                        res = xmlHashAddEntry2(partitions->triage,
                                               BAD_CAST "#any", (*tmp)->ns,
                                               (void *) (long) (i + 1));
                    if ((*tmp)->nameClass != NULL)
                        is_determinist = 2;
                    if (res != 0)
                        is_determinist = -1;
                } else {
                    is_determinist = -1;
                }
                tmp++;
            }
        } else {
            is_determinist = 0;
        }
    }
    partitions->groups = groups;

    /*
     * and save the partition list back in the def
     */
    def->data = partitions;
    if (is_mixed != 0)
        def->dflags |= IS_MIXED;
    if (is_determinist == 1)
        partitions->flags = IS_DETERMINIST;
    if (is_determinist == 2)
        partitions->flags = IS_DETERMINIST | IS_NEEDCHECK;
    return;

  error:
    xmlRngPErrMemory(ctxt, "in interleave computation\n");
    if (groups != NULL) {
        for (i = 0; i < nbgroups; i++)
            if (groups[i] != NULL) {
                if (groups[i]->defs != NULL)
                    xmlFree(groups[i]->defs);
                xmlFree(groups[i]);
            }
        xmlFree(groups);
    }
    xmlRelaxNGFreePartition(partitions);
}