Edit

kc3-lang/libxml2/xmlregexp.c

Branch :

  • Show log

    Commit

  • Author : Daniel Veillard
    Date : 2002-12-20 00:16:24
    Hash : ea7751d5
    Message : working on DTD validation on top of xml reader interfaces. Allows to * testReader.c xmlreader.c valid.c include/libxml/tree.h include/libxml/valid.h include/libxml/xmlreader.h: working on DTD validation on top of xml reader interfaces. Allows to validate arbitrary large instances. This required some extensions to the valid module interface and augmenting the size of xmlID and xmlRef structs a bit. * uri.c xmlregexp.c: simple cleanup. Daniel

  • xmlregexp.c
  • /*
     * regexp.c: generic and extensible Regular Expression engine
     *
     * Basically designed with the purpose of compiling regexps for 
     * the variety of validation/shemas mechanisms now available in
     * XML related specifications thise includes:
     *    - XML-1.0 DTD validation
     *    - XML Schemas structure part 1
     *    - XML Schemas Datatypes part 2 especially Appendix F
     *    - RELAX-NG/TREX i.e. the counter proposal
     *
     * See Copyright for the status of this software.
     *
     * Daniel Veillard <veillard@redhat.com>
     */
    
    #define IN_LIBXML
    #include "libxml.h"
    
    #ifdef LIBXML_REGEXP_ENABLED
    
    #include <stdio.h>
    #include <string.h>
    #include <libxml/tree.h>
    #include <libxml/parserInternals.h>
    #include <libxml/xmlregexp.h>
    #include <libxml/xmlautomata.h>
    #include <libxml/xmlunicode.h>
    
    /* #define DEBUG_REGEXP_GRAPH  */
    /* #define DEBUG_REGEXP_EXEC */
    /* #define DEBUG_PUSH */
    /* #define DEBUG_COMPACTION */
    
    #define ERROR(str) ctxt->error = 1;					\
        xmlGenericError(xmlGenericErrorContext, "Regexp: %s: %s\n", str, ctxt->cur)
    #define NEXT ctxt->cur++
    #define CUR (*(ctxt->cur))
    #define NXT(index) (ctxt->cur[index])
    
    #define CUR_SCHAR(s, l) xmlStringCurrentChar(NULL, s, &l)
    #define NEXTL(l) ctxt->cur += l;
    
    /**
     * TODO:
     *
     * macro to flag unimplemented blocks
     */
    #define TODO 								\
        xmlGenericError(xmlGenericErrorContext,				\
    	    "Unimplemented block at %s:%d\n",				\
                __FILE__, __LINE__);
    
    
    /************************************************************************
     * 									*
     * 			Datatypes and structures			*
     * 									*
     ************************************************************************/
    
    typedef enum {
        XML_REGEXP_EPSILON = 1,
        XML_REGEXP_CHARVAL,
        XML_REGEXP_RANGES,
        XML_REGEXP_SUBREG,
        XML_REGEXP_STRING,
        XML_REGEXP_ANYCHAR, /* . */
        XML_REGEXP_ANYSPACE, /* \s */
        XML_REGEXP_NOTSPACE, /* \S */
        XML_REGEXP_INITNAME, /* \l */
        XML_REGEXP_NOTINITNAME, /* \l */
        XML_REGEXP_NAMECHAR, /* \c */
        XML_REGEXP_NOTNAMECHAR, /* \C */
        XML_REGEXP_DECIMAL, /* \d */
        XML_REGEXP_NOTDECIMAL, /* \d */
        XML_REGEXP_REALCHAR, /* \w */
        XML_REGEXP_NOTREALCHAR, /* \w */
        XML_REGEXP_LETTER,
        XML_REGEXP_LETTER_UPPERCASE,
        XML_REGEXP_LETTER_LOWERCASE,
        XML_REGEXP_LETTER_TITLECASE,
        XML_REGEXP_LETTER_MODIFIER,
        XML_REGEXP_LETTER_OTHERS,
        XML_REGEXP_MARK,
        XML_REGEXP_MARK_NONSPACING,
        XML_REGEXP_MARK_SPACECOMBINING,
        XML_REGEXP_MARK_ENCLOSING,
        XML_REGEXP_NUMBER,
        XML_REGEXP_NUMBER_DECIMAL,
        XML_REGEXP_NUMBER_LETTER,
        XML_REGEXP_NUMBER_OTHERS,
        XML_REGEXP_PUNCT,
        XML_REGEXP_PUNCT_CONNECTOR,
        XML_REGEXP_PUNCT_DASH,
        XML_REGEXP_PUNCT_OPEN,
        XML_REGEXP_PUNCT_CLOSE,
        XML_REGEXP_PUNCT_INITQUOTE,
        XML_REGEXP_PUNCT_FINQUOTE,
        XML_REGEXP_PUNCT_OTHERS,
        XML_REGEXP_SEPAR,
        XML_REGEXP_SEPAR_SPACE,
        XML_REGEXP_SEPAR_LINE,
        XML_REGEXP_SEPAR_PARA,
        XML_REGEXP_SYMBOL,
        XML_REGEXP_SYMBOL_MATH,
        XML_REGEXP_SYMBOL_CURRENCY,
        XML_REGEXP_SYMBOL_MODIFIER,
        XML_REGEXP_SYMBOL_OTHERS,
        XML_REGEXP_OTHER,
        XML_REGEXP_OTHER_CONTROL,
        XML_REGEXP_OTHER_FORMAT,
        XML_REGEXP_OTHER_PRIVATE,
        XML_REGEXP_OTHER_NA,
        XML_REGEXP_BLOCK_NAME
    } xmlRegAtomType;
    
    typedef enum {
        XML_REGEXP_QUANT_EPSILON = 1,
        XML_REGEXP_QUANT_ONCE,
        XML_REGEXP_QUANT_OPT,
        XML_REGEXP_QUANT_MULT,
        XML_REGEXP_QUANT_PLUS,
        XML_REGEXP_QUANT_ONCEONLY,
        XML_REGEXP_QUANT_ALL,
        XML_REGEXP_QUANT_RANGE
    } xmlRegQuantType;
    
    typedef enum {
        XML_REGEXP_START_STATE = 1,
        XML_REGEXP_FINAL_STATE,
        XML_REGEXP_TRANS_STATE
    } xmlRegStateType;
    
    typedef enum {
        XML_REGEXP_MARK_NORMAL = 0,
        XML_REGEXP_MARK_START,
        XML_REGEXP_MARK_VISITED
    } xmlRegMarkedType;
    
    typedef struct _xmlRegRange xmlRegRange;
    typedef xmlRegRange *xmlRegRangePtr;
    
    struct _xmlRegRange {
        int neg;
        xmlRegAtomType type;
        int start;
        int end;
        xmlChar *blockName;
    };
    
    typedef struct _xmlRegAtom xmlRegAtom;
    typedef xmlRegAtom *xmlRegAtomPtr;
    
    typedef struct _xmlAutomataState xmlRegState;
    typedef xmlRegState *xmlRegStatePtr;
    
    struct _xmlRegAtom {
        int no;
        xmlRegAtomType type;
        xmlRegQuantType quant;
        int min;
        int max;
    
        void *valuep;
        void *valuep2;
        int neg;
        int codepoint;
        xmlRegStatePtr start;
        xmlRegStatePtr stop;
        int maxRanges;
        int nbRanges;
        xmlRegRangePtr *ranges;
        void *data;
    };
    
    typedef struct _xmlRegCounter xmlRegCounter;
    typedef xmlRegCounter *xmlRegCounterPtr;
    
    struct _xmlRegCounter {
        int min;
        int max;
    };
    
    typedef struct _xmlRegTrans xmlRegTrans;
    typedef xmlRegTrans *xmlRegTransPtr;
    
    struct _xmlRegTrans {
        xmlRegAtomPtr atom;
        int to;
        int counter;
        int count;
    };
    
    struct _xmlAutomataState {
        xmlRegStateType type;
        xmlRegMarkedType mark;
        xmlRegMarkedType reached;
        int no;
    
        int maxTrans;
        int nbTrans;
        xmlRegTrans *trans;
    };
    
    typedef struct _xmlAutomata xmlRegParserCtxt;
    typedef xmlRegParserCtxt *xmlRegParserCtxtPtr;
    
    struct _xmlAutomata {
        xmlChar *string;
        xmlChar *cur;
    
        int error;
        int neg;
    
        xmlRegStatePtr start;
        xmlRegStatePtr end;
        xmlRegStatePtr state;
    
        xmlRegAtomPtr atom;
    
        int maxAtoms;
        int nbAtoms;
        xmlRegAtomPtr *atoms;
    
        int maxStates;
        int nbStates;
        xmlRegStatePtr *states;
    
        int maxCounters;
        int nbCounters;
        xmlRegCounter *counters;
    
        int determinist;
    };
    
    struct _xmlRegexp {
        xmlChar *string;
        int nbStates;
        xmlRegStatePtr *states;
        int nbAtoms;
        xmlRegAtomPtr *atoms;
        int nbCounters;
        xmlRegCounter *counters;
        int determinist;
        /*
         * That's the compact form for determinists automatas
         */
        int nbstates;
        int *compact;
        void **transdata;
        int nbstrings;
        xmlChar **stringMap;
    };
    
    typedef struct _xmlRegExecRollback xmlRegExecRollback;
    typedef xmlRegExecRollback *xmlRegExecRollbackPtr;
    
    struct _xmlRegExecRollback {
        xmlRegStatePtr state;/* the current state */
        int index;		/* the index in the input stack */
        int nextbranch;	/* the next transition to explore in that state */
        int *counts;	/* save the automate state if it has some */
    };
    
    typedef struct _xmlRegInputToken xmlRegInputToken;
    typedef xmlRegInputToken *xmlRegInputTokenPtr;
    
    struct _xmlRegInputToken {
        xmlChar *value;
        void *data;
    };
    
    struct _xmlRegExecCtxt {
        int status;		/* execution status != 0 indicate an error */
        int determinist;	/* did we found an inderterministic behaviour */
        xmlRegexpPtr comp;	/* the compiled regexp */
        xmlRegExecCallbacks callback;
        void *data;
    
        xmlRegStatePtr state;/* the current state */
        int transno;	/* the current transition on that state */
        int transcount;	/* the number of char in char counted transitions */
    
        /*
         * A stack of rollback states
         */
        int maxRollbacks;
        int nbRollbacks;
        xmlRegExecRollback *rollbacks;
    
        /*
         * The state of the automata if any
         */
        int *counts;
    
        /*
         * The input stack
         */
        int inputStackMax;
        int inputStackNr;
        int index;
        int *charStack;
        const xmlChar *inputString; /* when operating on characters */
        xmlRegInputTokenPtr inputStack;/* when operating on strings */
    
    };
    
    #define REGEXP_ALL_COUNTER	0x123456
    #define REGEXP_ALL_LAX_COUNTER	0x123457
    
    static void xmlFAParseRegExp(xmlRegParserCtxtPtr ctxt, int top);
    static void xmlRegFreeState(xmlRegStatePtr state);
    static void xmlRegFreeAtom(xmlRegAtomPtr atom);
    
    /************************************************************************
     * 									*
     * 			Allocation/Deallocation				*
     * 									*
     ************************************************************************/
    
    static int xmlFAComputesDeterminism(xmlRegParserCtxtPtr ctxt);
    /**
     * xmlRegEpxFromParse:
     * @ctxt:  the parser context used to build it
     *
     * Allocate a new regexp and fill it with the reult from the parser
     *
     * Returns the new regexp or NULL in case of error
     */
    static xmlRegexpPtr
    xmlRegEpxFromParse(xmlRegParserCtxtPtr ctxt) {
        xmlRegexpPtr ret;
    
        ret = (xmlRegexpPtr) xmlMalloc(sizeof(xmlRegexp));
        if (ret == NULL)
    	return(NULL);
        memset(ret, 0, sizeof(xmlRegexp));
        ret->string = ctxt->string;
        ctxt->string = NULL;
        ret->nbStates = ctxt->nbStates;
        ctxt->nbStates = 0;
        ret->states = ctxt->states;
        ctxt->states = NULL;
        ret->nbAtoms = ctxt->nbAtoms;
        ctxt->nbAtoms = 0;
        ret->atoms = ctxt->atoms;
        ctxt->atoms = NULL;
        ret->nbCounters = ctxt->nbCounters;
        ctxt->nbCounters = 0;
        ret->counters = ctxt->counters;
        ctxt->counters = NULL;
        ret->determinist = ctxt->determinist;
    
        if ((ret->determinist != 0) &&
    	(ret->nbCounters == 0) &&
    	(ret->atoms != NULL) &&
    	(ret->atoms[0] != NULL) &&
    	(ret->atoms[0]->type == XML_REGEXP_STRING)) {
    	int i, j, nbstates = 0, nbatoms = 0;
    	int *stateRemap;
    	int *stringRemap;
    	int *transitions;
    	void **transdata;
    	xmlChar **stringMap;
            xmlChar *value;
    
    	/*
    	 * Switch to a compact representation
    	 * 1/ counting the effective number of states left
    	 * 2/ conting the unique number of atoms, and check that
    	 *    they are all of the string type
    	 * 3/ build a table state x atom for the transitions
    	 */
    
    	stateRemap = xmlMalloc(ret->nbStates * sizeof(int));
    	for (i = 0;i < ret->nbStates;i++) {
    	    if (ret->states[i] != NULL) {
    		stateRemap[i] = nbstates;
    		nbstates++;
    	    } else {
    		stateRemap[i] = -1;
    	    }
    	}
    #ifdef DEBUG_COMPACTION
    	printf("Final: %d states\n", nbstates);
    #endif
    	stringMap = xmlMalloc(ret->nbAtoms * sizeof(char *));
    	stringRemap = xmlMalloc(ret->nbAtoms * sizeof(int));
    	for (i = 0;i < ret->nbAtoms;i++) {
    	    if ((ret->atoms[i]->type == XML_REGEXP_STRING) &&
    		(ret->atoms[i]->quant == XML_REGEXP_QUANT_ONCE)) {
    		value = ret->atoms[i]->valuep;
                    for (j = 0;j < nbatoms;j++) {
    		    if (xmlStrEqual(stringMap[j], value)) {
    			stringRemap[i] = j;
    			break;
    		    }
    		}
    		if (j >= nbatoms) {
    		    stringRemap[i] = nbatoms;
    		    stringMap[nbatoms] = xmlStrdup(value);
    		    nbatoms++;
    		}
    	    } else {
    		xmlFree(stateRemap);
    		xmlFree(stringRemap);
    		for (i = 0;i < nbatoms;i++)
    		    xmlFree(stringMap[i]);
    		xmlFree(stringMap);
    		goto fail_compact;
    	    }
    	}
    #ifdef DEBUG_COMPACTION
    	printf("Final: %d atoms\n", nbatoms);
    #endif
    
    	/*
    	 * Allocate the transition table. The first entry for each
    	 * state correspond to the state type.
    	 */
    	transitions = (int *) xmlMalloc(nbstates * (nbatoms + 1) * sizeof(int));
    	transdata = NULL;
    	memset(transitions, 0, nbstates * (nbatoms + 1) * sizeof(int));
    
    	for (i = 0;i < ret->nbStates;i++) {
    	    int stateno, atomno, targetno, prev;
    	    xmlRegStatePtr state;
    	    xmlRegTransPtr trans;
    
    	    stateno = stateRemap[i];
    	    if (stateno == -1)
    		continue;
    	    state = ret->states[i];
    
    	    transitions[stateno * (nbatoms + 1)] = state->type;
    
    	    for (j = 0;j < state->nbTrans;j++) {
    		trans = &(state->trans[j]);
    		if ((trans->to == -1) || (trans->atom == NULL))
    		    continue;
                    atomno = stringRemap[trans->atom->no];
    		if ((trans->atom->data != NULL) && (transdata == NULL)) {
    		    transdata = (void **) xmlMalloc(nbstates * nbatoms *
    			                            sizeof(void *));
    		    if (transdata != NULL)
    			memset(transdata, 0,
    			       nbstates * nbatoms * sizeof(void *));
    		}
    		targetno = stateRemap[trans->to];
    		/*
    		 * if the same atome can generate transition to 2 different
    		 * states then it means the automata is not determinist and
    		 * the compact form can't be used !
    		 */
    		prev = transitions[stateno * (nbatoms + 1) + atomno + 1];
    		if (prev != 0) {
    		    if (prev != targetno + 1) {
    			printf("not determinist\n");
    			ret->determinist = 0;
    #ifdef DEBUG_COMPACTION
    			printf("Indet: state %d trans %d, atom %d to %d : %d to %d\n",
    			       i, j, trans->atom->no, trans->to, atomno, targetno);
    			printf("       previous to is %d\n", prev);
    #endif
    			ret->determinist = 0;
    			if (transdata != NULL)
    			    xmlFree(transdata);
    			xmlFree(transitions);
    			xmlFree(stateRemap);
    			xmlFree(stringRemap);
    			for (i = 0;i < nbatoms;i++)
    			    xmlFree(stringMap[i]);
    			xmlFree(stringMap);
    			goto fail_compact;
    		    }
    		} else {
    #if 0
    		    printf("State %d trans %d: atom %d to %d : %d to %d\n",
    			   i, j, trans->atom->no, trans->to, atomno, targetno);
    #endif
    		    transitions[stateno * (nbatoms + 1) + atomno + 1] =
    			targetno + 1; /* to avoid 0 */
    		    if (transdata != NULL)
    			transdata[stateno * nbatoms + atomno] =
    			    trans->atom->data;
    		}
    	    }
    	}
    	ret->determinist = 1;
    #ifdef DEBUG_COMPACTION
    	/*
    	 * Debug
    	 */
    	for (i = 0;i < nbstates;i++) {
    	    for (j = 0;j < nbatoms + 1;j++) {
                    printf("%02d ", transitions[i * (nbatoms + 1) + j]);
    	    }
    	    printf("\n");
    	}
    	printf("\n");
    #endif
    	/*
    	 * Cleanup of the old data
    	 */
    	if (ret->states != NULL) {
    	    for (i = 0;i < ret->nbStates;i++)
    		xmlRegFreeState(ret->states[i]);
    	    xmlFree(ret->states);
    	}
    	ret->states = NULL;
    	ret->nbStates = 0;
    	if (ret->atoms != NULL) {
    	    for (i = 0;i < ret->nbAtoms;i++)
    		xmlRegFreeAtom(ret->atoms[i]);
    	    xmlFree(ret->atoms);
    	}
    	ret->atoms = NULL;
    	ret->nbAtoms = 0;
    
    	ret->compact = transitions;
    	ret->transdata = transdata;
    	ret->stringMap = stringMap;
    	ret->nbstrings = nbatoms;
    	ret->nbstates = nbstates;
    	xmlFree(stateRemap);
    	xmlFree(stringRemap);
        }
    fail_compact:
        return(ret);
    }
    
    /**
     * xmlRegNewParserCtxt:
     * @string:  the string to parse
     *
     * Allocate a new regexp parser context
     *
     * Returns the new context or NULL in case of error
     */
    static xmlRegParserCtxtPtr
    xmlRegNewParserCtxt(const xmlChar *string) {
        xmlRegParserCtxtPtr ret;
    
        ret = (xmlRegParserCtxtPtr) xmlMalloc(sizeof(xmlRegParserCtxt));
        if (ret == NULL)
    	return(NULL);
        memset(ret, 0, sizeof(xmlRegParserCtxt));
        if (string != NULL)
    	ret->string = xmlStrdup(string);
        ret->cur = ret->string;
        ret->neg = 0;
        ret->error = 0;
        ret->determinist = -1;
        return(ret);
    }
    
    /**
     * xmlRegNewRange:
     * @ctxt:  the regexp parser context
     * @neg:  is that negative
     * @type:  the type of range
     * @start:  the start codepoint
     * @end:  the end codepoint
     *
     * Allocate a new regexp range
     *
     * Returns the new range or NULL in case of error
     */
    static xmlRegRangePtr
    xmlRegNewRange(xmlRegParserCtxtPtr ctxt,
    	       int neg, xmlRegAtomType type, int start, int end) {
        xmlRegRangePtr ret;
    
        ret = (xmlRegRangePtr) xmlMalloc(sizeof(xmlRegRange));
        if (ret == NULL) {
    	ERROR("failed to allocate regexp range");
    	return(NULL);
        }
        ret->neg = neg;
        ret->type = type;
        ret->start = start;
        ret->end = end;
        return(ret);
    }
    
    /**
     * xmlRegFreeRange:
     * @range:  the regexp range
     *
     * Free a regexp range
     */
    static void
    xmlRegFreeRange(xmlRegRangePtr range) {
        if (range == NULL)
    	return;
    
        if (range->blockName != NULL)
    	xmlFree(range->blockName);
        xmlFree(range);
    }
    
    /**
     * xmlRegNewAtom:
     * @ctxt:  the regexp parser context
     * @type:  the type of atom
     *
     * Allocate a new regexp range
     *
     * Returns the new atom or NULL in case of error
     */
    static xmlRegAtomPtr
    xmlRegNewAtom(xmlRegParserCtxtPtr ctxt, xmlRegAtomType type) {
        xmlRegAtomPtr ret;
    
        ret = (xmlRegAtomPtr) xmlMalloc(sizeof(xmlRegAtom));
        if (ret == NULL) {
    	ERROR("failed to allocate regexp atom");
    	return(NULL);
        }
        memset(ret, 0, sizeof(xmlRegAtom));
        ret->type = type;
        ret->quant = XML_REGEXP_QUANT_ONCE;
        ret->min = 0;
        ret->max = 0;
        return(ret);
    }
    
    /**
     * xmlRegFreeAtom:
     * @atom:  the regexp atom
     *
     * Free a regexp atom
     */
    static void
    xmlRegFreeAtom(xmlRegAtomPtr atom) {
        int i;
    
        if (atom == NULL)
    	return;
    
        for (i = 0;i < atom->nbRanges;i++)
    	xmlRegFreeRange(atom->ranges[i]);
        if (atom->ranges != NULL)
    	xmlFree(atom->ranges);
        if (atom->type == XML_REGEXP_STRING)
    	xmlFree(atom->valuep);
        xmlFree(atom);
    }
    
    static xmlRegStatePtr
    xmlRegNewState(xmlRegParserCtxtPtr ctxt) {
        xmlRegStatePtr ret;
    
        ret = (xmlRegStatePtr) xmlMalloc(sizeof(xmlRegState));
        if (ret == NULL) {
    	ERROR("failed to allocate regexp state");
    	return(NULL);
        }
        memset(ret, 0, sizeof(xmlRegState));
        ret->type = XML_REGEXP_TRANS_STATE;
        ret->mark = XML_REGEXP_MARK_NORMAL;
        return(ret);
    }
    
    /**
     * xmlRegFreeState:
     * @state:  the regexp state
     *
     * Free a regexp state
     */
    static void
    xmlRegFreeState(xmlRegStatePtr state) {
        if (state == NULL)
    	return;
    
        if (state->trans != NULL)
    	xmlFree(state->trans);
        xmlFree(state);
    }
    
    /**
     * xmlRegFreeParserCtxt:
     * @ctxt:  the regexp parser context
     *
     * Free a regexp parser context
     */
    static void
    xmlRegFreeParserCtxt(xmlRegParserCtxtPtr ctxt) {
        int i;
        if (ctxt == NULL)
    	return;
    
        if (ctxt->string != NULL)
    	xmlFree(ctxt->string);
        if (ctxt->states != NULL) {
    	for (i = 0;i < ctxt->nbStates;i++)
    	    xmlRegFreeState(ctxt->states[i]);
    	xmlFree(ctxt->states);
        }
        if (ctxt->atoms != NULL) {
    	for (i = 0;i < ctxt->nbAtoms;i++)
    	    xmlRegFreeAtom(ctxt->atoms[i]);
    	xmlFree(ctxt->atoms);
        }
        if (ctxt->counters != NULL)
    	xmlFree(ctxt->counters);
        xmlFree(ctxt);
    }
    
    /************************************************************************
     * 									*
     * 			Display of Data structures			*
     * 									*
     ************************************************************************/
    
    static void
    xmlRegPrintAtomType(FILE *output, xmlRegAtomType type) {
        switch (type) {
            case XML_REGEXP_EPSILON:
    	    fprintf(output, "epsilon "); break;
            case XML_REGEXP_CHARVAL:
    	    fprintf(output, "charval "); break;
            case XML_REGEXP_RANGES:
    	    fprintf(output, "ranges "); break;
            case XML_REGEXP_SUBREG:
    	    fprintf(output, "subexpr "); break;
            case XML_REGEXP_STRING:
    	    fprintf(output, "string "); break;
            case XML_REGEXP_ANYCHAR:
    	    fprintf(output, "anychar "); break;
            case XML_REGEXP_ANYSPACE:
    	    fprintf(output, "anyspace "); break;
            case XML_REGEXP_NOTSPACE:
    	    fprintf(output, "notspace "); break;
            case XML_REGEXP_INITNAME:
    	    fprintf(output, "initname "); break;
            case XML_REGEXP_NOTINITNAME:
    	    fprintf(output, "notinitname "); break;
            case XML_REGEXP_NAMECHAR:
    	    fprintf(output, "namechar "); break;
            case XML_REGEXP_NOTNAMECHAR:
    	    fprintf(output, "notnamechar "); break;
            case XML_REGEXP_DECIMAL:
    	    fprintf(output, "decimal "); break;
            case XML_REGEXP_NOTDECIMAL:
    	    fprintf(output, "notdecimal "); break;
            case XML_REGEXP_REALCHAR:
    	    fprintf(output, "realchar "); break;
            case XML_REGEXP_NOTREALCHAR:
    	    fprintf(output, "notrealchar "); break;
            case XML_REGEXP_LETTER:
                fprintf(output, "LETTER "); break;
            case XML_REGEXP_LETTER_UPPERCASE:
                fprintf(output, "LETTER_UPPERCASE "); break;
            case XML_REGEXP_LETTER_LOWERCASE:
                fprintf(output, "LETTER_LOWERCASE "); break;
            case XML_REGEXP_LETTER_TITLECASE:
                fprintf(output, "LETTER_TITLECASE "); break;
            case XML_REGEXP_LETTER_MODIFIER:
                fprintf(output, "LETTER_MODIFIER "); break;
            case XML_REGEXP_LETTER_OTHERS:
                fprintf(output, "LETTER_OTHERS "); break;
            case XML_REGEXP_MARK:
                fprintf(output, "MARK "); break;
            case XML_REGEXP_MARK_NONSPACING:
                fprintf(output, "MARK_NONSPACING "); break;
            case XML_REGEXP_MARK_SPACECOMBINING:
                fprintf(output, "MARK_SPACECOMBINING "); break;
            case XML_REGEXP_MARK_ENCLOSING:
                fprintf(output, "MARK_ENCLOSING "); break;
            case XML_REGEXP_NUMBER:
                fprintf(output, "NUMBER "); break;
            case XML_REGEXP_NUMBER_DECIMAL:
                fprintf(output, "NUMBER_DECIMAL "); break;
            case XML_REGEXP_NUMBER_LETTER:
                fprintf(output, "NUMBER_LETTER "); break;
            case XML_REGEXP_NUMBER_OTHERS:
                fprintf(output, "NUMBER_OTHERS "); break;
            case XML_REGEXP_PUNCT:
                fprintf(output, "PUNCT "); break;
            case XML_REGEXP_PUNCT_CONNECTOR:
                fprintf(output, "PUNCT_CONNECTOR "); break;
            case XML_REGEXP_PUNCT_DASH:
                fprintf(output, "PUNCT_DASH "); break;
            case XML_REGEXP_PUNCT_OPEN:
                fprintf(output, "PUNCT_OPEN "); break;
            case XML_REGEXP_PUNCT_CLOSE:
                fprintf(output, "PUNCT_CLOSE "); break;
            case XML_REGEXP_PUNCT_INITQUOTE:
                fprintf(output, "PUNCT_INITQUOTE "); break;
            case XML_REGEXP_PUNCT_FINQUOTE:
                fprintf(output, "PUNCT_FINQUOTE "); break;
            case XML_REGEXP_PUNCT_OTHERS:
                fprintf(output, "PUNCT_OTHERS "); break;
            case XML_REGEXP_SEPAR:
                fprintf(output, "SEPAR "); break;
            case XML_REGEXP_SEPAR_SPACE:
                fprintf(output, "SEPAR_SPACE "); break;
            case XML_REGEXP_SEPAR_LINE:
                fprintf(output, "SEPAR_LINE "); break;
            case XML_REGEXP_SEPAR_PARA:
                fprintf(output, "SEPAR_PARA "); break;
            case XML_REGEXP_SYMBOL:
                fprintf(output, "SYMBOL "); break;
            case XML_REGEXP_SYMBOL_MATH:
                fprintf(output, "SYMBOL_MATH "); break;
            case XML_REGEXP_SYMBOL_CURRENCY:
                fprintf(output, "SYMBOL_CURRENCY "); break;
            case XML_REGEXP_SYMBOL_MODIFIER:
                fprintf(output, "SYMBOL_MODIFIER "); break;
            case XML_REGEXP_SYMBOL_OTHERS:
                fprintf(output, "SYMBOL_OTHERS "); break;
            case XML_REGEXP_OTHER:
                fprintf(output, "OTHER "); break;
            case XML_REGEXP_OTHER_CONTROL:
                fprintf(output, "OTHER_CONTROL "); break;
            case XML_REGEXP_OTHER_FORMAT:
                fprintf(output, "OTHER_FORMAT "); break;
            case XML_REGEXP_OTHER_PRIVATE:
                fprintf(output, "OTHER_PRIVATE "); break;
            case XML_REGEXP_OTHER_NA:
                fprintf(output, "OTHER_NA "); break;
            case XML_REGEXP_BLOCK_NAME:
    	    fprintf(output, "BLOCK "); break;
        }
    }
    
    static void
    xmlRegPrintQuantType(FILE *output, xmlRegQuantType type) {
        switch (type) {
            case XML_REGEXP_QUANT_EPSILON:
    	    fprintf(output, "epsilon "); break;
            case XML_REGEXP_QUANT_ONCE:
    	    fprintf(output, "once "); break;
            case XML_REGEXP_QUANT_OPT:
    	    fprintf(output, "? "); break;
            case XML_REGEXP_QUANT_MULT:
    	    fprintf(output, "* "); break;
            case XML_REGEXP_QUANT_PLUS:
    	    fprintf(output, "+ "); break;
    	case XML_REGEXP_QUANT_RANGE:
    	    fprintf(output, "range "); break;
    	case XML_REGEXP_QUANT_ONCEONLY:
    	    fprintf(output, "onceonly "); break;
    	case XML_REGEXP_QUANT_ALL:
    	    fprintf(output, "all "); break;
        }
    }
    static void
    xmlRegPrintRange(FILE *output, xmlRegRangePtr range) {
        fprintf(output, "  range: ");
        if (range->neg)
    	fprintf(output, "negative ");
        xmlRegPrintAtomType(output, range->type);
        fprintf(output, "%c - %c\n", range->start, range->end);
    }
    
    static void
    xmlRegPrintAtom(FILE *output, xmlRegAtomPtr atom) {
        fprintf(output, " atom: ");
        if (atom == NULL) {
    	fprintf(output, "NULL\n");
    	return;
        }
        xmlRegPrintAtomType(output, atom->type);
        xmlRegPrintQuantType(output, atom->quant);
        if (atom->quant == XML_REGEXP_QUANT_RANGE)
    	fprintf(output, "%d-%d ", atom->min, atom->max);
        if (atom->type == XML_REGEXP_STRING)
    	fprintf(output, "'%s' ", (char *) atom->valuep);
        if (atom->type == XML_REGEXP_CHARVAL)
    	fprintf(output, "char %c\n", atom->codepoint);
        else if (atom->type == XML_REGEXP_RANGES) {
    	int i;
    	fprintf(output, "%d entries\n", atom->nbRanges);
    	for (i = 0; i < atom->nbRanges;i++)
    	    xmlRegPrintRange(output, atom->ranges[i]);
        } else if (atom->type == XML_REGEXP_SUBREG) {
    	fprintf(output, "start %d end %d\n", atom->start->no, atom->stop->no);
        } else {
    	fprintf(output, "\n");
        }
    }
    
    static void
    xmlRegPrintTrans(FILE *output, xmlRegTransPtr trans) {
        fprintf(output, "  trans: ");
        if (trans == NULL) {
    	fprintf(output, "NULL\n");
    	return;
        }
        if (trans->to < 0) {
    	fprintf(output, "removed\n");
    	return;
        }
        if (trans->counter >= 0) {
    	fprintf(output, "counted %d, ", trans->counter);
        }
        if (trans->count == REGEXP_ALL_COUNTER) {
    	fprintf(output, "all transition, ");
        } else if (trans->count >= 0) {
    	fprintf(output, "count based %d, ", trans->count);
        }
        if (trans->atom == NULL) {
    	fprintf(output, "epsilon to %d\n", trans->to);
    	return;
        }
        if (trans->atom->type == XML_REGEXP_CHARVAL)
    	fprintf(output, "char %c ", trans->atom->codepoint);
        fprintf(output, "atom %d, to %d\n", trans->atom->no, trans->to);
    }
        
    static void
    xmlRegPrintState(FILE *output, xmlRegStatePtr state) {
        int i;
    
        fprintf(output, " state: ");
        if (state == NULL) {
    	fprintf(output, "NULL\n");
    	return;
        }
        if (state->type == XML_REGEXP_START_STATE)
    	fprintf(output, "START ");
        if (state->type == XML_REGEXP_FINAL_STATE)
    	fprintf(output, "FINAL ");
        
        fprintf(output, "%d, %d transitions:\n", state->no, state->nbTrans);
        for (i = 0;i < state->nbTrans; i++) {
    	xmlRegPrintTrans(output, &(state->trans[i]));
        }
    }
    
    #ifdef DEBUG_REGEXP_GRAPH
    static void
    xmlRegPrintCtxt(FILE *output, xmlRegParserCtxtPtr ctxt) {
        int i;
    
        fprintf(output, " ctxt: ");
        if (ctxt == NULL) {
    	fprintf(output, "NULL\n");
    	return;
        }
        fprintf(output, "'%s' ", ctxt->string);
        if (ctxt->error)
    	fprintf(output, "error ");
        if (ctxt->neg)
    	fprintf(output, "neg ");
        fprintf(output, "\n");
        fprintf(output, "%d atoms:\n", ctxt->nbAtoms);
        for (i = 0;i < ctxt->nbAtoms; i++) {
    	fprintf(output, " %02d ", i);
    	xmlRegPrintAtom(output, ctxt->atoms[i]);
        }
        if (ctxt->atom != NULL) {
    	fprintf(output, "current atom:\n");
    	xmlRegPrintAtom(output, ctxt->atom);
        }
        fprintf(output, "%d states:", ctxt->nbStates);
        if (ctxt->start != NULL)
    	fprintf(output, " start: %d", ctxt->start->no);
        if (ctxt->end != NULL)
    	fprintf(output, " end: %d", ctxt->end->no);
        fprintf(output, "\n");
        for (i = 0;i < ctxt->nbStates; i++) {
    	xmlRegPrintState(output, ctxt->states[i]);
        }
        fprintf(output, "%d counters:\n", ctxt->nbCounters);
        for (i = 0;i < ctxt->nbCounters; i++) {
    	fprintf(output, " %d: min %d max %d\n", i, ctxt->counters[i].min,
    		                                ctxt->counters[i].max);
        }
    }
    #endif
    
    /************************************************************************
     * 									*
     *		 Finite Automata structures manipulations		*
     * 									*
     ************************************************************************/
    
    static void 
    xmlRegAtomAddRange(xmlRegParserCtxtPtr ctxt, xmlRegAtomPtr atom,
    	           int neg, xmlRegAtomType type, int start, int end,
    		   xmlChar *blockName) {
        xmlRegRangePtr range;
    
        if (atom == NULL) {
    	ERROR("add range: atom is NULL");
    	return;
        }
        if (atom->type != XML_REGEXP_RANGES) {
    	ERROR("add range: atom is not ranges");
    	return;
        }
        if (atom->maxRanges == 0) {
    	atom->maxRanges = 4;
    	atom->ranges = (xmlRegRangePtr *) xmlMalloc(atom->maxRanges *
    		                             sizeof(xmlRegRangePtr));
    	if (atom->ranges == NULL) {
    	    ERROR("add range: allocation failed");
    	    atom->maxRanges = 0;
    	    return;
    	}
        } else if (atom->nbRanges >= atom->maxRanges) {
    	xmlRegRangePtr *tmp;
    	atom->maxRanges *= 2;
    	tmp = (xmlRegRangePtr *) xmlRealloc(atom->ranges, atom->maxRanges *
    		                             sizeof(xmlRegRangePtr));
    	if (tmp == NULL) {
    	    ERROR("add range: allocation failed");
    	    atom->maxRanges /= 2;
    	    return;
    	}
    	atom->ranges = tmp;
        }
        range = xmlRegNewRange(ctxt, neg, type, start, end);
        if (range == NULL)
    	return;
        range->blockName = blockName;
        atom->ranges[atom->nbRanges++] = range;
        
    }
    
    static int
    xmlRegGetCounter(xmlRegParserCtxtPtr ctxt) {
        if (ctxt->maxCounters == 0) {
    	ctxt->maxCounters = 4;
    	ctxt->counters = (xmlRegCounter *) xmlMalloc(ctxt->maxCounters *
    		                             sizeof(xmlRegCounter));
    	if (ctxt->counters == NULL) {
    	    ERROR("reg counter: allocation failed");
    	    ctxt->maxCounters = 0;
    	    return(-1);
    	}
        } else if (ctxt->nbCounters >= ctxt->maxCounters) {
    	xmlRegCounter *tmp;
    	ctxt->maxCounters *= 2;
    	tmp = (xmlRegCounter *) xmlRealloc(ctxt->counters, ctxt->maxCounters *
    		                           sizeof(xmlRegCounter));
    	if (tmp == NULL) {
    	    ERROR("reg counter: allocation failed");
    	    ctxt->maxCounters /= 2;
    	    return(-1);
    	}
    	ctxt->counters = tmp;
        }
        ctxt->counters[ctxt->nbCounters].min = -1;
        ctxt->counters[ctxt->nbCounters].max = -1;
        return(ctxt->nbCounters++);
    }
    
    static void 
    xmlRegAtomPush(xmlRegParserCtxtPtr ctxt, xmlRegAtomPtr atom) {
        if (atom == NULL) {
    	ERROR("atom push: atom is NULL");
    	return;
        }
        if (ctxt->maxAtoms == 0) {
    	ctxt->maxAtoms = 4;
    	ctxt->atoms = (xmlRegAtomPtr *) xmlMalloc(ctxt->maxAtoms *
    		                             sizeof(xmlRegAtomPtr));
    	if (ctxt->atoms == NULL) {
    	    ERROR("atom push: allocation failed");
    	    ctxt->maxAtoms = 0;
    	    return;
    	}
        } else if (ctxt->nbAtoms >= ctxt->maxAtoms) {
    	xmlRegAtomPtr *tmp;
    	ctxt->maxAtoms *= 2;
    	tmp = (xmlRegAtomPtr *) xmlRealloc(ctxt->atoms, ctxt->maxAtoms *
    		                             sizeof(xmlRegAtomPtr));
    	if (tmp == NULL) {
    	    ERROR("atom push: allocation failed");
    	    ctxt->maxAtoms /= 2;
    	    return;
    	}
    	ctxt->atoms = tmp;
        }
        atom->no = ctxt->nbAtoms;
        ctxt->atoms[ctxt->nbAtoms++] = atom;
    }
    
    static void 
    xmlRegStateAddTrans(xmlRegParserCtxtPtr ctxt, xmlRegStatePtr state,
    	            xmlRegAtomPtr atom, xmlRegStatePtr target,
    		    int counter, int count) {
        if (state == NULL) {
    	ERROR("add state: state is NULL");
    	return;
        }
        if (target == NULL) {
    	ERROR("add state: target is NULL");
    	return;
        }
        if (state->maxTrans == 0) {
    	state->maxTrans = 4;
    	state->trans = (xmlRegTrans *) xmlMalloc(state->maxTrans *
    		                             sizeof(xmlRegTrans));
    	if (state->trans == NULL) {
    	    ERROR("add range: allocation failed");
    	    state->maxTrans = 0;
    	    return;
    	}
        } else if (state->nbTrans >= state->maxTrans) {
    	xmlRegTrans *tmp;
    	state->maxTrans *= 2;
    	tmp = (xmlRegTrans *) xmlRealloc(state->trans, state->maxTrans *
    		                             sizeof(xmlRegTrans));
    	if (tmp == NULL) {
    	    ERROR("add range: allocation failed");
    	    state->maxTrans /= 2;
    	    return;
    	}
    	state->trans = tmp;
        }
    #ifdef DEBUG_REGEXP_GRAPH
        printf("Add trans from %d to %d ", state->no, target->no);
        if (count == REGEXP_ALL_COUNTER)
    	printf("all transition");
        else if (count >= 0)
    	printf("count based %d", count);
        else if (counter >= 0)
    	printf("counted %d", counter);
        else if (atom == NULL)
    	printf("epsilon transition");
        printf("\n");
    #endif
    
        state->trans[state->nbTrans].atom = atom;
        state->trans[state->nbTrans].to = target->no;
        state->trans[state->nbTrans].counter = counter;
        state->trans[state->nbTrans].count = count;
        state->nbTrans++;
    }
    
    static void 
    xmlRegStatePush(xmlRegParserCtxtPtr ctxt, xmlRegStatePtr state) {
        if (ctxt->maxStates == 0) {
    	ctxt->maxStates = 4;
    	ctxt->states = (xmlRegStatePtr *) xmlMalloc(ctxt->maxStates *
    		                             sizeof(xmlRegStatePtr));
    	if (ctxt->states == NULL) {
    	    ERROR("add range: allocation failed");
    	    ctxt->maxStates = 0;
    	    return;
    	}
        } else if (ctxt->nbStates >= ctxt->maxStates) {
    	xmlRegStatePtr *tmp;
    	ctxt->maxStates *= 2;
    	tmp = (xmlRegStatePtr *) xmlRealloc(ctxt->states, ctxt->maxStates *
    		                             sizeof(xmlRegStatePtr));
    	if (tmp == NULL) {
    	    ERROR("add range: allocation failed");
    	    ctxt->maxStates /= 2;
    	    return;
    	}
    	ctxt->states = tmp;
        }
        state->no = ctxt->nbStates;
        ctxt->states[ctxt->nbStates++] = state;
    }
    
    /**
     * xmlFAGenerateAllTransition:
     * @ctxt:  a regexp parser context
     * @from:  the from state
     * @to:  the target state or NULL for building a new one
     * @lax:
     *
     */
    static void
    xmlFAGenerateAllTransition(xmlRegParserCtxtPtr ctxt,
    			   xmlRegStatePtr from, xmlRegStatePtr to,
    			   int lax) {
        if (to == NULL) {
    	to = xmlRegNewState(ctxt);
    	xmlRegStatePush(ctxt, to);
    	ctxt->state = to;
        }
        if (lax)
    	xmlRegStateAddTrans(ctxt, from, NULL, to, -1, REGEXP_ALL_LAX_COUNTER);
        else
    	xmlRegStateAddTrans(ctxt, from, NULL, to, -1, REGEXP_ALL_COUNTER);
    }
    
    /**
     * xmlFAGenerateEpsilonTransition:
     * @ctxt:  a regexp parser context
     * @from:  the from state
     * @to:  the target state or NULL for building a new one
     *
     */
    static void
    xmlFAGenerateEpsilonTransition(xmlRegParserCtxtPtr ctxt,
    			       xmlRegStatePtr from, xmlRegStatePtr to) {
        if (to == NULL) {
    	to = xmlRegNewState(ctxt);
    	xmlRegStatePush(ctxt, to);
    	ctxt->state = to;
        }
        xmlRegStateAddTrans(ctxt, from, NULL, to, -1, -1);
    }
    
    /**
     * xmlFAGenerateCountedEpsilonTransition:
     * @ctxt:  a regexp parser context
     * @from:  the from state
     * @to:  the target state or NULL for building a new one
     * counter:  the counter for that transition
     *
     */
    static void
    xmlFAGenerateCountedEpsilonTransition(xmlRegParserCtxtPtr ctxt,
    	    xmlRegStatePtr from, xmlRegStatePtr to, int counter) {
        if (to == NULL) {
    	to = xmlRegNewState(ctxt);
    	xmlRegStatePush(ctxt, to);
    	ctxt->state = to;
        }
        xmlRegStateAddTrans(ctxt, from, NULL, to, counter, -1);
    }
    
    /**
     * xmlFAGenerateCountedTransition:
     * @ctxt:  a regexp parser context
     * @from:  the from state
     * @to:  the target state or NULL for building a new one
     * counter:  the counter for that transition
     *
     */
    static void
    xmlFAGenerateCountedTransition(xmlRegParserCtxtPtr ctxt,
    	    xmlRegStatePtr from, xmlRegStatePtr to, int counter) {
        if (to == NULL) {
    	to = xmlRegNewState(ctxt);
    	xmlRegStatePush(ctxt, to);
    	ctxt->state = to;
        }
        xmlRegStateAddTrans(ctxt, from, NULL, to, -1, counter);
    }
    
    /**
     * xmlFAGenerateTransitions:
     * @ctxt:  a regexp parser context
     * @from:  the from state
     * @to:  the target state or NULL for building a new one
     * @atom:  the atom generating the transition
     *
     */
    static void
    xmlFAGenerateTransitions(xmlRegParserCtxtPtr ctxt, xmlRegStatePtr from,
    	                 xmlRegStatePtr to, xmlRegAtomPtr atom) {
        if (atom == NULL) {
    	ERROR("genrate transition: atom == NULL");
    	return;
        }
        if (atom->type == XML_REGEXP_SUBREG) {
    	/*
    	 * this is a subexpression handling one should not need to
    	 * create a new node excep for XML_REGEXP_QUANT_RANGE.
    	 */
    	xmlRegAtomPush(ctxt, atom);
    	if ((to != NULL) && (atom->stop != to) &&
    	    (atom->quant != XML_REGEXP_QUANT_RANGE)) {
    	    /*
    	     * Generate an epsilon transition to link to the target
    	     */
    	    xmlFAGenerateEpsilonTransition(ctxt, atom->stop, to);
    	}
    	switch (atom->quant) {
    	    case XML_REGEXP_QUANT_OPT:
    		atom->quant = XML_REGEXP_QUANT_ONCE;
    		xmlFAGenerateEpsilonTransition(ctxt, atom->start, atom->stop);
    		break;
    	    case XML_REGEXP_QUANT_MULT:
    		atom->quant = XML_REGEXP_QUANT_ONCE;
    		xmlFAGenerateEpsilonTransition(ctxt, atom->start, atom->stop);
    		xmlFAGenerateEpsilonTransition(ctxt, atom->stop, atom->start);
    		break;
    	    case XML_REGEXP_QUANT_PLUS:
    		atom->quant = XML_REGEXP_QUANT_ONCE;
    		xmlFAGenerateEpsilonTransition(ctxt, atom->stop, atom->start);
    		break;
    	    case XML_REGEXP_QUANT_RANGE: {
    		int counter;
    		xmlRegStatePtr newstate;
    
    		/*
    		 * This one is nasty:
    		 *   1/ register a new counter
    		 *   2/ register an epsilon transition associated to
    		 *      this counter going from atom->stop to atom->start
    		 *   3/ create a new state
    		 *   4/ generate a counted transition from atom->stop to
    		 *      that state
    		 */
    		counter = xmlRegGetCounter(ctxt);
    		ctxt->counters[counter].min = atom->min - 1;
    		ctxt->counters[counter].max = atom->max - 1;
    		atom->min = 0;
    		atom->max = 0;
    		atom->quant = XML_REGEXP_QUANT_ONCE;
    		xmlFAGenerateCountedEpsilonTransition(ctxt, atom->stop,
    			                              atom->start, counter);
    		if (to != NULL) {
    		    newstate = to;
    		} else {
    		    newstate = xmlRegNewState(ctxt);
    		    xmlRegStatePush(ctxt, newstate);
    		    ctxt->state = newstate;
    		}
    		xmlFAGenerateCountedTransition(ctxt, atom->stop,
    			                       newstate, counter);
    	    }
    	    default:
    		break;
    	}
    	return;
        } else {
    	if (to == NULL) {
    	    to = xmlRegNewState(ctxt);
    	    xmlRegStatePush(ctxt, to);
    	}
    	xmlRegStateAddTrans(ctxt, from, atom, to, -1, -1);
    	xmlRegAtomPush(ctxt, atom);
    	ctxt->state = to;
        }
        switch (atom->quant) {
    	case XML_REGEXP_QUANT_OPT:
    	    atom->quant = XML_REGEXP_QUANT_ONCE;
    	    xmlFAGenerateEpsilonTransition(ctxt, from, to);
    	    break;
    	case XML_REGEXP_QUANT_MULT:
    	    atom->quant = XML_REGEXP_QUANT_ONCE;
    	    xmlFAGenerateEpsilonTransition(ctxt, from, to);
    	    xmlRegStateAddTrans(ctxt, to, atom, to, -1, -1);
    	    break;
    	case XML_REGEXP_QUANT_PLUS:
    	    atom->quant = XML_REGEXP_QUANT_ONCE;
    	    xmlRegStateAddTrans(ctxt, to, atom, to, -1, -1);
    	    break;
    	default:
    	    break;
        }
    }
    
    /**
     * xmlFAReduceEpsilonTransitions:
     * @ctxt:  a regexp parser context
     * @fromnr:  the from state
     * @tonr:  the to state 
     * @cpunter:  should that transition be associted to a counted
     *
     */
    static void
    xmlFAReduceEpsilonTransitions(xmlRegParserCtxtPtr ctxt, int fromnr,
    	                      int tonr, int counter) {
        int transnr;
        xmlRegStatePtr from;
        xmlRegStatePtr to;
    
    #ifdef DEBUG_REGEXP_GRAPH
        printf("xmlFAReduceEpsilonTransitions(%d, %d)\n", fromnr, tonr);
    #endif
        from = ctxt->states[fromnr];
        if (from == NULL)
    	return;
        to = ctxt->states[tonr];
        if (to == NULL)
    	return;
        if ((to->mark == XML_REGEXP_MARK_START) ||
    	(to->mark == XML_REGEXP_MARK_VISITED))
    	return;
    
        to->mark = XML_REGEXP_MARK_VISITED;
        if (to->type == XML_REGEXP_FINAL_STATE) {
    #ifdef DEBUG_REGEXP_GRAPH
    	printf("State %d is final, so %d becomes final\n", tonr, fromnr);
    #endif
    	from->type = XML_REGEXP_FINAL_STATE;
        }
        for (transnr = 0;transnr < to->nbTrans;transnr++) {
    	if (to->trans[transnr].atom == NULL) {
    	    /*
    	     * Don't remove counted transitions
    	     * Don't loop either
    	     */
    	    if (to->trans[transnr].to != fromnr) {
    		if (to->trans[transnr].count >= 0) {
    		    int newto = to->trans[transnr].to;
    
    		    xmlRegStateAddTrans(ctxt, from, NULL,
    					ctxt->states[newto], 
    					-1, to->trans[transnr].count);
    		} else {
    #ifdef DEBUG_REGEXP_GRAPH
    		    printf("Found epsilon trans %d from %d to %d\n",
    			   transnr, tonr, to->trans[transnr].to);
    #endif
    		    if (to->trans[transnr].counter >= 0) {
    			xmlFAReduceEpsilonTransitions(ctxt, fromnr,
    					      to->trans[transnr].to,
    					      to->trans[transnr].counter);
    		    } else {
    			xmlFAReduceEpsilonTransitions(ctxt, fromnr,
    					      to->trans[transnr].to,
    					      counter);
    		    }
    		}
    	    }
    	} else {
    	    int newto = to->trans[transnr].to;
    
    	    if (to->trans[transnr].counter >= 0) {
    		xmlRegStateAddTrans(ctxt, from, to->trans[transnr].atom, 
    				    ctxt->states[newto], 
    				    to->trans[transnr].counter, -1);
    	    } else {
    		xmlRegStateAddTrans(ctxt, from, to->trans[transnr].atom, 
    				    ctxt->states[newto], counter, -1);
    	    }
    	}
        }
        to->mark = XML_REGEXP_MARK_NORMAL;
    }
    
    /**
     * xmlFAEliminateEpsilonTransitions:
     * @ctxt:  a regexp parser context
     *
     */
    static void
    xmlFAEliminateEpsilonTransitions(xmlRegParserCtxtPtr ctxt) {
        int statenr, transnr;
        xmlRegStatePtr state;
    
        /*
         * build the completed transitions bypassing the epsilons
         * Use a marking algorithm to avoid loops
         */
        for (statenr = 0;statenr < ctxt->nbStates;statenr++) {
    	state = ctxt->states[statenr];
    	if (state == NULL)
    	    continue;
    	for (transnr = 0;transnr < state->nbTrans;transnr++) {
    	    if ((state->trans[transnr].atom == NULL) &&
    		(state->trans[transnr].to >= 0)) {
    		if (state->trans[transnr].to == statenr) {
    		    state->trans[transnr].to = -1;
    #ifdef DEBUG_REGEXP_GRAPH
    		    printf("Removed loopback epsilon trans %d on %d\n",
    			   transnr, statenr);
    #endif
    		} else if (state->trans[transnr].count < 0) {
    		    int newto = state->trans[transnr].to;
    
    #ifdef DEBUG_REGEXP_GRAPH
    		    printf("Found epsilon trans %d from %d to %d\n",
    			   transnr, statenr, newto);
    #endif
    		    state->mark = XML_REGEXP_MARK_START;
    		    xmlFAReduceEpsilonTransitions(ctxt, statenr,
    				      newto, state->trans[transnr].counter);
    		    state->mark = XML_REGEXP_MARK_NORMAL;
    #ifdef DEBUG_REGEXP_GRAPH
    		} else {
    		    printf("Found counted transition %d on %d\n",
    			   transnr, statenr);
    #endif
    	        }
    	    }
    	}
        }
        /*
         * Eliminate the epsilon transitions
         */
        for (statenr = 0;statenr < ctxt->nbStates;statenr++) {
    	state = ctxt->states[statenr];
    	if (state == NULL)
    	    continue;
    	for (transnr = 0;transnr < state->nbTrans;transnr++) {
    	    if ((state->trans[transnr].atom == NULL) &&
    		(state->trans[transnr].count < 0) &&
    		(state->trans[transnr].to >= 0)) {
    		state->trans[transnr].to = -1;
    	    }
    	}
        }
    
        /*
         * Use this pass to detect unreachable states too
         */
        for (statenr = 0;statenr < ctxt->nbStates;statenr++) {
    	state = ctxt->states[statenr];
    	if (state != NULL)
    	    state->reached = 0;
        }
        state = ctxt->states[0];
        if (state != NULL)
    	state->reached = 1;
        while (state != NULL) {
    	xmlRegStatePtr target = NULL;
    	state->reached = 2;
    	/*
    	 * Mark all state reachable from the current reachable state
    	 */
    	for (transnr = 0;transnr < state->nbTrans;transnr++) {
    	    if ((state->trans[transnr].to >= 0) &&
    		((state->trans[transnr].atom != NULL) ||
    		 (state->trans[transnr].count >= 0))) {
    		int newto = state->trans[transnr].to;
    
    		if (ctxt->states[newto] == NULL)
    		    continue;
    		if (ctxt->states[newto]->reached == 0) {
    		    ctxt->states[newto]->reached = 1;
    		    target = ctxt->states[newto];
    		}
    	    }
    	}
    	/*
    	 * find the next accessible state not explored
    	 */
    	if (target == NULL) {
    	    for (statenr = 1;statenr < ctxt->nbStates;statenr++) {
    		state = ctxt->states[statenr];
    		if ((state != NULL) && (state->reached == 1)) {
    		    target = state;
    		    break;
    		}
    	    }
    	}
    	state = target;
        }
        for (statenr = 0;statenr < ctxt->nbStates;statenr++) {
    	state = ctxt->states[statenr];
    	if ((state != NULL) && (state->reached == 0)) {
    #ifdef DEBUG_REGEXP_GRAPH
    	    printf("Removed unreachable state %d\n", statenr);
    #endif
    	    xmlRegFreeState(state);
    	    ctxt->states[statenr] = NULL;
    	}
        }
    
    }
    
    /**
     * xmlFACompareAtoms:
     * @atom1:  an atom
     * @atom2:  an atom
     *
     * Compares two atoms to check whether they are equivatents
     *
     * Returns 1 if yes and 0 otherwise
     */
    static int
    xmlFACompareAtoms(xmlRegAtomPtr atom1, xmlRegAtomPtr atom2) {
        if (atom1 == atom2)
    	return(1);
        if ((atom1 == NULL) || (atom2 == NULL))
    	return(0);
    
        if (atom1->type != atom2->type)
    	return(0);
        switch (atom1->type) {
            case XML_REGEXP_STRING:
    	    return(xmlStrEqual((xmlChar *)atom1->valuep,
    			       (xmlChar *)atom2->valuep));
            case XML_REGEXP_EPSILON:
    	    return(1);
            case XML_REGEXP_CHARVAL:
    	    return(atom1->codepoint == atom2->codepoint);
            case XML_REGEXP_RANGES:
    	    TODO;
    	    return(0);
    	default:
    	    break;
        }
        return(1);
    }
    
    /**
     * xmlFARecurseDeterminism:
     * @ctxt:  a regexp parser context
     *
     * Check whether the associated regexp is determinist,
     * should be called after xmlFAEliminateEpsilonTransitions()
     *
     */
    static int
    xmlFARecurseDeterminism(xmlRegParserCtxtPtr ctxt, xmlRegStatePtr state,
    	                 int to, xmlRegAtomPtr atom) {
        int ret = 1;
        int transnr;
        xmlRegTransPtr t1;
    
        if (state == NULL)
    	return(ret);
        for (transnr = 0;transnr < state->nbTrans;transnr++) {
    	t1 = &(state->trans[transnr]);
    	/*
    	 * check transitions conflicting with the one looked at
    	 */
    	if (t1->atom == NULL) {
    	    if (t1->to == -1)
    		continue;
    	    ret = xmlFARecurseDeterminism(ctxt, ctxt->states[t1->to],
    		                           to, atom);
    	    if (ret == 0)
    		return(0);
    	    continue;
    	}
    	if (t1->to != to)
    	    continue;
    	if (xmlFACompareAtoms(t1->atom, atom))
    	    return(0);
        }
        return(ret);
    }
    
    /**
     * xmlFAComputesDeterminism:
     * @ctxt:  a regexp parser context
     *
     * Check whether the associated regexp is determinist,
     * should be called after xmlFAEliminateEpsilonTransitions()
     *
     */
    static int
    xmlFAComputesDeterminism(xmlRegParserCtxtPtr ctxt) {
        int statenr, transnr;
        xmlRegStatePtr state;
        xmlRegTransPtr t1, t2;
        int i;
        int ret = 1;
    
    #ifdef DEBUG_REGEXP_GRAPH
        printf("xmlFAComputesDeterminism\n");
        xmlRegPrintCtxt(stdout, ctxt);
    #endif
        if (ctxt->determinist != -1)
    	return(ctxt->determinist);
    
        /*
         * Check for all states that there isn't 2 transitions
         * with the same atom and a different target.
         */
        for (statenr = 0;statenr < ctxt->nbStates;statenr++) {
    	state = ctxt->states[statenr];
    	if (state == NULL)
    	    continue;
    	for (transnr = 0;transnr < state->nbTrans;transnr++) {
    	    t1 = &(state->trans[transnr]);
    	    /*
    	     * Determinism checks in case of counted or all transitions
    	     * will have to be handled separately
    	     */
    	    if (t1->atom == NULL)
    		continue;
    	    if (t1->to == -1) /* eliminated */
    		continue;
    	    for (i = 0;i < transnr;i++) {
    		t2 = &(state->trans[i]);
    		if (t2->to == -1) /* eliminated */
    		    continue;
    		if (t2->atom != NULL) {
    		    if (t1->to == t2->to) {
    			if (xmlFACompareAtoms(t1->atom, t2->atom))
    			    t2->to = -1; /* eliminate */
    		    } else {
    			/* not determinist ! */
    			if (xmlFACompareAtoms(t1->atom, t2->atom))
    			    ret = 0;
    		    }
    		} else if (t1->to != -1) {
    		    /*
    		     * do the closure in case of remaining specific
    		     * epsilon transitions like choices or all
    		     */
    		    ret = xmlFARecurseDeterminism(ctxt, ctxt->states[t1->to],
    						   t2->to, t2->atom);
    		    if (ret == 0)
    			return(0);
    		}
    	    }
    	    if (ret == 0)
    		break;
    	}
    	if (ret == 0)
    	    break;
        }
        ctxt->determinist = ret;
        return(ret);
    }
    
    /************************************************************************
     * 									*
     *	Routines to check input against transition atoms		*
     * 									*
     ************************************************************************/
    
    static int
    xmlRegCheckCharacterRange(xmlRegAtomType type, int codepoint, int neg,
    	                  int start, int end, const xmlChar *blockName) {
        int ret = 0;
    
        switch (type) {
            case XML_REGEXP_STRING:
            case XML_REGEXP_SUBREG:
            case XML_REGEXP_RANGES:
            case XML_REGEXP_EPSILON:
    	    return(-1);
            case XML_REGEXP_ANYCHAR:
    	    ret = ((codepoint != '\n') && (codepoint != '\r'));
    	    break;
            case XML_REGEXP_CHARVAL:
    	    ret = ((codepoint >= start) && (codepoint <= end));
    	    break;
            case XML_REGEXP_NOTSPACE:
    	    neg = !neg;
            case XML_REGEXP_ANYSPACE:
    	    ret = ((codepoint == '\n') || (codepoint == '\r') ||
    		   (codepoint == '\t') || (codepoint == ' '));
    	    break;
            case XML_REGEXP_NOTINITNAME:
    	    neg = !neg;
            case XML_REGEXP_INITNAME:
    	    ret = (xmlIsLetter(codepoint) || 
    		   (codepoint == '_') || (codepoint == ':'));
    	    break;
            case XML_REGEXP_NOTNAMECHAR:
    	    neg = !neg;
            case XML_REGEXP_NAMECHAR:
    	    ret = (xmlIsLetter(codepoint) || xmlIsDigit(codepoint) ||
    		   (codepoint == '.') || (codepoint == '-') ||
    		   (codepoint == '_') || (codepoint == ':') ||
    		   xmlIsCombining(codepoint) || xmlIsExtender(codepoint));
    	    break;
            case XML_REGEXP_NOTDECIMAL:
    	    neg = !neg;
            case XML_REGEXP_DECIMAL:
    	    ret = xmlUCSIsCatNd(codepoint);
    	    break;
            case XML_REGEXP_REALCHAR:
    	    neg = !neg;
            case XML_REGEXP_NOTREALCHAR:
    	    ret = xmlUCSIsCatP(codepoint);
    	    if (ret == 0)
    		ret = xmlUCSIsCatZ(codepoint);
    	    if (ret == 0)
    		ret = xmlUCSIsCatC(codepoint);
    	    break;
            case XML_REGEXP_LETTER:
    	    ret = xmlUCSIsCatL(codepoint);
    	    break;
            case XML_REGEXP_LETTER_UPPERCASE:
    	    ret = xmlUCSIsCatLu(codepoint);
    	    break;
            case XML_REGEXP_LETTER_LOWERCASE:
    	    ret = xmlUCSIsCatLl(codepoint);
    	    break;
            case XML_REGEXP_LETTER_TITLECASE:
    	    ret = xmlUCSIsCatLt(codepoint);
    	    break;
            case XML_REGEXP_LETTER_MODIFIER:
    	    ret = xmlUCSIsCatLm(codepoint);
    	    break;
            case XML_REGEXP_LETTER_OTHERS:
    	    ret = xmlUCSIsCatLo(codepoint);
    	    break;
            case XML_REGEXP_MARK:
    	    ret = xmlUCSIsCatM(codepoint);
    	    break;
            case XML_REGEXP_MARK_NONSPACING:
    	    ret = xmlUCSIsCatMn(codepoint);
    	    break;
            case XML_REGEXP_MARK_SPACECOMBINING:
    	    ret = xmlUCSIsCatMc(codepoint);
    	    break;
            case XML_REGEXP_MARK_ENCLOSING:
    	    ret = xmlUCSIsCatMe(codepoint);
    	    break;
            case XML_REGEXP_NUMBER:
    	    ret = xmlUCSIsCatN(codepoint);
    	    break;
            case XML_REGEXP_NUMBER_DECIMAL:
    	    ret = xmlUCSIsCatNd(codepoint);
    	    break;
            case XML_REGEXP_NUMBER_LETTER:
    	    ret = xmlUCSIsCatNl(codepoint);
    	    break;
            case XML_REGEXP_NUMBER_OTHERS:
    	    ret = xmlUCSIsCatNo(codepoint);
    	    break;
            case XML_REGEXP_PUNCT:
    	    ret = xmlUCSIsCatP(codepoint);
    	    break;
            case XML_REGEXP_PUNCT_CONNECTOR:
    	    ret = xmlUCSIsCatPc(codepoint);
    	    break;
            case XML_REGEXP_PUNCT_DASH:
    	    ret = xmlUCSIsCatPd(codepoint);
    	    break;
            case XML_REGEXP_PUNCT_OPEN:
    	    ret = xmlUCSIsCatPs(codepoint);
    	    break;
            case XML_REGEXP_PUNCT_CLOSE:
    	    ret = xmlUCSIsCatPe(codepoint);
    	    break;
            case XML_REGEXP_PUNCT_INITQUOTE:
    	    ret = xmlUCSIsCatPi(codepoint);
    	    break;
            case XML_REGEXP_PUNCT_FINQUOTE:
    	    ret = xmlUCSIsCatPf(codepoint);
    	    break;
            case XML_REGEXP_PUNCT_OTHERS:
    	    ret = xmlUCSIsCatPo(codepoint);
    	    break;
            case XML_REGEXP_SEPAR:
    	    ret = xmlUCSIsCatZ(codepoint);
    	    break;
            case XML_REGEXP_SEPAR_SPACE:
    	    ret = xmlUCSIsCatZs(codepoint);
    	    break;
            case XML_REGEXP_SEPAR_LINE:
    	    ret = xmlUCSIsCatZl(codepoint);
    	    break;
            case XML_REGEXP_SEPAR_PARA:
    	    ret = xmlUCSIsCatZp(codepoint);
    	    break;
            case XML_REGEXP_SYMBOL:
    	    ret = xmlUCSIsCatS(codepoint);
    	    break;
            case XML_REGEXP_SYMBOL_MATH:
    	    ret = xmlUCSIsCatSm(codepoint);
    	    break;
            case XML_REGEXP_SYMBOL_CURRENCY:
    	    ret = xmlUCSIsCatSc(codepoint);
    	    break;
            case XML_REGEXP_SYMBOL_MODIFIER:
    	    ret = xmlUCSIsCatSk(codepoint);
    	    break;
            case XML_REGEXP_SYMBOL_OTHERS:
    	    ret = xmlUCSIsCatSo(codepoint);
    	    break;
            case XML_REGEXP_OTHER:
    	    ret = xmlUCSIsCatC(codepoint);
    	    break;
            case XML_REGEXP_OTHER_CONTROL:
    	    ret = xmlUCSIsCatCc(codepoint);
    	    break;
            case XML_REGEXP_OTHER_FORMAT:
    	    ret = xmlUCSIsCatCf(codepoint);
    	    break;
            case XML_REGEXP_OTHER_PRIVATE:
    	    ret = xmlUCSIsCatCo(codepoint);
    	    break;
            case XML_REGEXP_OTHER_NA:
    	    /* ret = xmlUCSIsCatCn(codepoint); */
    	    /* Seems it doesn't exist anymore in recent Unicode releases */
    	    ret = 0;
    	    break;
            case XML_REGEXP_BLOCK_NAME:
    	    ret = xmlUCSIsBlock(codepoint, (const char *) blockName);
    	    break;
        }
        if (neg)
    	return(!ret);
        return(ret);
    }
    
    static int
    xmlRegCheckCharacter(xmlRegAtomPtr atom, int codepoint) {
        int i, ret = 0;
        xmlRegRangePtr range;
    
        if ((atom == NULL) || (!xmlIsChar(codepoint)))
    	return(-1);
    
        switch (atom->type) {
            case XML_REGEXP_SUBREG:
            case XML_REGEXP_EPSILON:
    	    return(-1);
            case XML_REGEXP_CHARVAL:
                return(codepoint == atom->codepoint);
            case XML_REGEXP_RANGES: {
    	    int accept = 0;
    	    for (i = 0;i < atom->nbRanges;i++) {
    		range = atom->ranges[i];
    		if (range->neg) {
    		    ret = xmlRegCheckCharacterRange(range->type, codepoint,
    						0, range->start, range->end,
    						range->blockName);
    		    if (ret != 0)
    			return(0); /* excluded char */
    		} else {
    		    ret = xmlRegCheckCharacterRange(range->type, codepoint,
    						0, range->start, range->end,
    						range->blockName);
    		    if (ret != 0)
    			accept = 1; /* might still be excluded */
    		}
    	    }
    	    return(accept);
    	}
            case XML_REGEXP_STRING:
    	    printf("TODO: XML_REGEXP_STRING\n");
    	    return(-1);
            case XML_REGEXP_ANYCHAR:
            case XML_REGEXP_ANYSPACE:
            case XML_REGEXP_NOTSPACE:
            case XML_REGEXP_INITNAME:
            case XML_REGEXP_NOTINITNAME:
            case XML_REGEXP_NAMECHAR:
            case XML_REGEXP_NOTNAMECHAR:
            case XML_REGEXP_DECIMAL:
            case XML_REGEXP_NOTDECIMAL:
            case XML_REGEXP_REALCHAR:
            case XML_REGEXP_NOTREALCHAR:
            case XML_REGEXP_LETTER:
            case XML_REGEXP_LETTER_UPPERCASE:
            case XML_REGEXP_LETTER_LOWERCASE:
            case XML_REGEXP_LETTER_TITLECASE:
            case XML_REGEXP_LETTER_MODIFIER:
            case XML_REGEXP_LETTER_OTHERS:
            case XML_REGEXP_MARK:
            case XML_REGEXP_MARK_NONSPACING:
            case XML_REGEXP_MARK_SPACECOMBINING:
            case XML_REGEXP_MARK_ENCLOSING:
            case XML_REGEXP_NUMBER:
            case XML_REGEXP_NUMBER_DECIMAL:
            case XML_REGEXP_NUMBER_LETTER:
            case XML_REGEXP_NUMBER_OTHERS:
            case XML_REGEXP_PUNCT:
            case XML_REGEXP_PUNCT_CONNECTOR:
            case XML_REGEXP_PUNCT_DASH:
            case XML_REGEXP_PUNCT_OPEN:
            case XML_REGEXP_PUNCT_CLOSE:
            case XML_REGEXP_PUNCT_INITQUOTE:
            case XML_REGEXP_PUNCT_FINQUOTE:
            case XML_REGEXP_PUNCT_OTHERS:
            case XML_REGEXP_SEPAR:
            case XML_REGEXP_SEPAR_SPACE:
            case XML_REGEXP_SEPAR_LINE:
            case XML_REGEXP_SEPAR_PARA:
            case XML_REGEXP_SYMBOL:
            case XML_REGEXP_SYMBOL_MATH:
            case XML_REGEXP_SYMBOL_CURRENCY:
            case XML_REGEXP_SYMBOL_MODIFIER:
            case XML_REGEXP_SYMBOL_OTHERS:
            case XML_REGEXP_OTHER:
            case XML_REGEXP_OTHER_CONTROL:
            case XML_REGEXP_OTHER_FORMAT:
            case XML_REGEXP_OTHER_PRIVATE:
            case XML_REGEXP_OTHER_NA:
    	case XML_REGEXP_BLOCK_NAME:
    	    ret = xmlRegCheckCharacterRange(atom->type, codepoint, 0, 0, 0,
    		                            (const xmlChar *)atom->valuep);
    	    if (atom->neg)
    		ret = !ret;
    	    break;
        }
        return(ret);
    }
    
    /************************************************************************
     * 									*
     *	Saving an restoring state of an execution context		*
     * 									*
     ************************************************************************/
    
    #ifdef DEBUG_REGEXP_EXEC
    static void
    xmlFARegDebugExec(xmlRegExecCtxtPtr exec) {
        printf("state: %d:%d:idx %d", exec->state->no, exec->transno, exec->index);
        if (exec->inputStack != NULL) {
    	int i;
    	printf(": ");
    	for (i = 0;(i < 3) && (i < exec->inputStackNr);i++)
    	    printf("%s ", exec->inputStack[exec->inputStackNr - (i + 1)]);
        } else {
    	printf(": %s", &(exec->inputString[exec->index]));
        }
        printf("\n");
    }
    #endif
    
    static void
    xmlFARegExecSave(xmlRegExecCtxtPtr exec) {
    #ifdef DEBUG_REGEXP_EXEC
        printf("saving ");
        exec->transno++;
        xmlFARegDebugExec(exec);
        exec->transno--;
    #endif
    
        if (exec->maxRollbacks == 0) {
    	exec->maxRollbacks = 4;
    	exec->rollbacks = (xmlRegExecRollback *) xmlMalloc(exec->maxRollbacks *
    		                             sizeof(xmlRegExecRollback));
    	if (exec->rollbacks == NULL) {
    	    fprintf(stderr, "exec save: allocation failed");
    	    exec->maxRollbacks = 0;
    	    return;
    	}
    	memset(exec->rollbacks, 0,
    	       exec->maxRollbacks * sizeof(xmlRegExecRollback));
        } else if (exec->nbRollbacks >= exec->maxRollbacks) {
    	xmlRegExecRollback *tmp;
    	int len = exec->maxRollbacks;
    
    	exec->maxRollbacks *= 2;
    	tmp = (xmlRegExecRollback *) xmlRealloc(exec->rollbacks,
    			exec->maxRollbacks * sizeof(xmlRegExecRollback));
    	if (tmp == NULL) {
    	    fprintf(stderr, "exec save: allocation failed");
    	    exec->maxRollbacks /= 2;
    	    return;
    	}
    	exec->rollbacks = tmp;
    	tmp = &exec->rollbacks[len];
    	memset(tmp, 0, (exec->maxRollbacks - len) * sizeof(xmlRegExecRollback));
        }
        exec->rollbacks[exec->nbRollbacks].state = exec->state;
        exec->rollbacks[exec->nbRollbacks].index = exec->index;
        exec->rollbacks[exec->nbRollbacks].nextbranch = exec->transno + 1;
        if (exec->comp->nbCounters > 0) {
    	if (exec->rollbacks[exec->nbRollbacks].counts == NULL) {
    	    exec->rollbacks[exec->nbRollbacks].counts = (int *)
    		xmlMalloc(exec->comp->nbCounters * sizeof(int));
    	    if (exec->rollbacks[exec->nbRollbacks].counts == NULL) {
    		fprintf(stderr, "exec save: allocation failed");
    		exec->status = -5;
    		return;
    	    }
    	}
    	memcpy(exec->rollbacks[exec->nbRollbacks].counts, exec->counts,
    	       exec->comp->nbCounters * sizeof(int));
        }
        exec->nbRollbacks++;
    }
    
    static void
    xmlFARegExecRollBack(xmlRegExecCtxtPtr exec) {
        if (exec->nbRollbacks <= 0) {
    	exec->status = -1;
    #ifdef DEBUG_REGEXP_EXEC
    	printf("rollback failed on empty stack\n");
    #endif
    	return;
        }
        exec->nbRollbacks--;
        exec->state = exec->rollbacks[exec->nbRollbacks].state;
        exec->index = exec->rollbacks[exec->nbRollbacks].index;
        exec->transno = exec->rollbacks[exec->nbRollbacks].nextbranch;
        if (exec->comp->nbCounters > 0) {
    	if (exec->rollbacks[exec->nbRollbacks].counts == NULL) {
    	    fprintf(stderr, "exec save: allocation failed");
    	    exec->status = -6;
    	    return;
    	}
    	memcpy(exec->counts, exec->rollbacks[exec->nbRollbacks].counts,
    	       exec->comp->nbCounters * sizeof(int));
        }
    
    #ifdef DEBUG_REGEXP_EXEC
        printf("restored ");
        xmlFARegDebugExec(exec);
    #endif
    }
    
    /************************************************************************
     * 									*
     *	Verifyer, running an input against a compiled regexp		*
     * 									*
     ************************************************************************/
    
    static int
    xmlFARegExec(xmlRegexpPtr comp, const xmlChar *content) {
        xmlRegExecCtxt execval;
        xmlRegExecCtxtPtr exec = &execval;
        int ret, codepoint, len;
    
        exec->inputString = content;
        exec->index = 0;
        exec->determinist = 1;
        exec->maxRollbacks = 0;
        exec->nbRollbacks = 0;
        exec->rollbacks = NULL;
        exec->status = 0;
        exec->comp = comp;
        exec->state = comp->states[0];
        exec->transno = 0;
        exec->transcount = 0;
        if (comp->nbCounters > 0) {
    	exec->counts = (int *) xmlMalloc(comp->nbCounters * sizeof(int));
    	if (exec->counts == NULL)
    	    return(-1);
            memset(exec->counts, 0, comp->nbCounters * sizeof(int));
        } else
    	exec->counts = NULL;
        while ((exec->status == 0) &&
    	   ((exec->inputString[exec->index] != 0) ||
    	    (exec->state->type != XML_REGEXP_FINAL_STATE))) {
    	xmlRegTransPtr trans;
    	xmlRegAtomPtr atom;
    
    	/*
    	 * End of input on non-terminal state, rollback, however we may
    	 * still have epsilon like transition for counted transitions
    	 * on counters, in that case don't break too early.
    	 */
    	if ((exec->inputString[exec->index] == 0) && (exec->counts == NULL))
    	    goto rollback;
    
    	exec->transcount = 0;
    	for (;exec->transno < exec->state->nbTrans;exec->transno++) {
    	    trans = &exec->state->trans[exec->transno];
    	    if (trans->to < 0)
    		continue;
    	    atom = trans->atom;
    	    ret = 0;
    	    if (trans->count >= 0) {
    		int count;
    		xmlRegCounterPtr counter;
    
    		/*
    		 * A counted transition.
    		 */
    
    		count = exec->counts[trans->count];
    		counter = &exec->comp->counters[trans->count];
    #ifdef DEBUG_REGEXP_EXEC
    		printf("testing count %d: val %d, min %d, max %d\n",
    		       trans->count, count, counter->min,  counter->max);
    #endif
    		ret = ((count >= counter->min) && (count <= counter->max));
    	    } else if (atom == NULL) {
    		fprintf(stderr, "epsilon transition left at runtime\n");
    		exec->status = -2;
    		break;
    	    } else if (exec->inputString[exec->index] != 0) {
                    codepoint = CUR_SCHAR(&(exec->inputString[exec->index]), len);
    		ret = xmlRegCheckCharacter(atom, codepoint);
    		if ((ret == 1) && (atom->min > 0) && (atom->max > 0)) {
    		    xmlRegStatePtr to = comp->states[trans->to];
    
    		    /*
    		     * this is a multiple input sequence
    		     */
    		    if (exec->state->nbTrans > exec->transno + 1) {
    			xmlFARegExecSave(exec);
    		    }
    		    exec->transcount = 1;
    		    do {
    			/*
    			 * Try to progress as much as possible on the input
    			 */
    			if (exec->transcount == atom->max) {
    			    break;
    			}
    			exec->index += len;
    			/*
    			 * End of input: stop here
    			 */
    			if (exec->inputString[exec->index] == 0) {
    			    exec->index -= len;
    			    break;
    			}
    			if (exec->transcount >= atom->min) {
    			    int transno = exec->transno;
    			    xmlRegStatePtr state = exec->state;
    
    			    /*
    			     * The transition is acceptable save it
    			     */
    			    exec->transno = -1; /* trick */
    			    exec->state = to;
    			    xmlFARegExecSave(exec);
    			    exec->transno = transno;
    			    exec->state = state;
    			}
    			codepoint = CUR_SCHAR(&(exec->inputString[exec->index]),
    				              len);
    			ret = xmlRegCheckCharacter(atom, codepoint);
    			exec->transcount++;
    		    } while (ret == 1);
    		    if (exec->transcount < atom->min)
    			ret = 0;
    
    		    /*
    		     * If the last check failed but one transition was found
    		     * possible, rollback
    		     */
    		    if (ret < 0)
    			ret = 0;
    		    if (ret == 0) {
    			goto rollback;
    		    }
    		}
    	    }
    	    if (ret == 1) {
    		if (exec->state->nbTrans > exec->transno + 1) {
    		    xmlFARegExecSave(exec);
    		}
    		if (trans->counter >= 0) {
    #ifdef DEBUG_REGEXP_EXEC
    		    printf("Increasing count %d\n", trans->counter);
    #endif
    		    exec->counts[trans->counter]++;
    		}
    #ifdef DEBUG_REGEXP_EXEC
    		printf("entering state %d\n", trans->to);
    #endif
    		exec->state = comp->states[trans->to];
    		exec->transno = 0;
    		if (trans->atom != NULL) {
    		    exec->index += len;
    		}
    		goto progress;
    	    } else if (ret < 0) {
    		exec->status = -4;
    		break;
    	    }
    	}
    	if ((exec->transno != 0) || (exec->state->nbTrans == 0)) {
    rollback:
    	    /*
    	     * Failed to find a way out
    	     */
    	    exec->determinist = 0;
    	    xmlFARegExecRollBack(exec);
    	}
    progress:
    	continue;
        }
        if (exec->rollbacks != NULL) {
    	if (exec->counts != NULL) {
    	    int i;
    
    	    for (i = 0;i < exec->maxRollbacks;i++)
    		if (exec->rollbacks[i].counts != NULL)
    		    xmlFree(exec->rollbacks[i].counts);
    	}
    	xmlFree(exec->rollbacks);
        }
        if (exec->counts != NULL)
    	xmlFree(exec->counts);
        if (exec->status == 0)
    	return(1);
        if (exec->status == -1)
    	return(0);
        return(exec->status);
    }
    
    /************************************************************************
     * 									*
     *	Progressive interface to the verifyer one atom at a time	*
     * 									*
     ************************************************************************/
    
    /**
     * xmlRegNewExecCtxt:
     * @comp: a precompiled regular expression
     * @callback: a callback function used for handling progresses in the
     *            automata matching phase
     * @data: the context data associated to the callback in this context
     *
     * Build a context used for progressive evaluation of a regexp.
     *
     * Returns the new context
     */
    xmlRegExecCtxtPtr
    xmlRegNewExecCtxt(xmlRegexpPtr comp, xmlRegExecCallbacks callback, void *data) {
        xmlRegExecCtxtPtr exec;
    
        if (comp == NULL)
    	return(NULL);
        exec = (xmlRegExecCtxtPtr) xmlMalloc(sizeof(xmlRegExecCtxt));
        if (exec == NULL) {
    	return(NULL);
        }
        memset(exec, 0, sizeof(xmlRegExecCtxt));
        exec->inputString = NULL;
        exec->index = 0;
        exec->determinist = 1;
        exec->maxRollbacks = 0;
        exec->nbRollbacks = 0;
        exec->rollbacks = NULL;
        exec->status = 0;
        exec->comp = comp;
        if (comp->compact == NULL)
    	exec->state = comp->states[0];
        exec->transno = 0;
        exec->transcount = 0;
        exec->callback = callback;
        exec->data = data;
        if (comp->nbCounters > 0) {
    	exec->counts = (int *) xmlMalloc(comp->nbCounters * sizeof(int));
    	if (exec->counts == NULL) {
    	    xmlFree(exec);
    	    return(NULL);
    	}
            memset(exec->counts, 0, comp->nbCounters * sizeof(int));
        } else
    	exec->counts = NULL;
        exec->inputStackMax = 0;
        exec->inputStackNr = 0;
        exec->inputStack = NULL;
        return(exec);
    }
    
    /**
     * xmlRegFreeExecCtxt:
     * @exec: a regular expression evaulation context
     *
     * Free the structures associated to a regular expression evaulation context.
     */
    void
    xmlRegFreeExecCtxt(xmlRegExecCtxtPtr exec) {
        if (exec == NULL)
    	return;
    
        if (exec->rollbacks != NULL) {
    	if (exec->counts != NULL) {
    	    int i;
    
    	    for (i = 0;i < exec->maxRollbacks;i++)
    		if (exec->rollbacks[i].counts != NULL)
    		    xmlFree(exec->rollbacks[i].counts);
    	}
    	xmlFree(exec->rollbacks);
        }
        if (exec->counts != NULL)
    	xmlFree(exec->counts);
        if (exec->inputStack != NULL) {
    	int i;
    
    	for (i = 0;i < exec->inputStackNr;i++) {
    	    if (exec->inputStack[i].value != NULL)
    		xmlFree(exec->inputStack[i].value);
    	}
    	xmlFree(exec->inputStack);
        }
        xmlFree(exec);
    }
    
    static void
    xmlFARegExecSaveInputString(xmlRegExecCtxtPtr exec, const xmlChar *value,
    	                    void *data) {
    #ifdef DEBUG_PUSH
        printf("saving value: %d:%s\n", exec->inputStackNr, value);
    #endif
        if (exec->inputStackMax == 0) {
    	exec->inputStackMax = 4;
    	exec->inputStack = (xmlRegInputTokenPtr) 
    	    xmlMalloc(exec->inputStackMax * sizeof(xmlRegInputToken));
    	if (exec->inputStack == NULL) {
    	    fprintf(stderr, "push input: allocation failed");
    	    exec->inputStackMax = 0;
    	    return;
    	}
        } else if (exec->inputStackNr + 1 >= exec->inputStackMax) {
    	xmlRegInputTokenPtr tmp;
    
    	exec->inputStackMax *= 2;
    	tmp = (xmlRegInputTokenPtr) xmlRealloc(exec->inputStack,
    			exec->inputStackMax * sizeof(xmlRegInputToken));
    	if (tmp == NULL) {
    	    fprintf(stderr, "push input: allocation failed");
    	    exec->inputStackMax /= 2;
    	    return;
    	}
    	exec->inputStack = tmp;
        }
        exec->inputStack[exec->inputStackNr].value = xmlStrdup(value);
        exec->inputStack[exec->inputStackNr].data = data;
        exec->inputStackNr++;
        exec->inputStack[exec->inputStackNr].value = NULL;
        exec->inputStack[exec->inputStackNr].data = NULL;
    }
    
    
    /**
     * xmlRegCompactPushString:
     * @exec: a regexp execution context
     * @comp:  the precompiled exec with a compact table
     * @value: a string token input
     * @data: data associated to the token to reuse in callbacks
     *
     * Push one input token in the execution context
     *
     * Returns: 1 if the regexp reached a final state, 0 if non-final, and
     *     a negative value in case of error.
     */
    static int
    xmlRegCompactPushString(xmlRegExecCtxtPtr exec,
    	                xmlRegexpPtr comp,
    	                const xmlChar *value,
    	                void *data) {
        int state = exec->index;
        int i, target;
    
        if ((comp == NULL) || (comp->compact == NULL) || (comp->stringMap == NULL))
    	return(-1);
        
        if (value == NULL) {
    	/*
    	 * are we at a final state ?
    	 */
    	if (comp->compact[state * (comp->nbstrings + 1)] ==
                XML_REGEXP_FINAL_STATE)
    	    return(1);
    	return(0);
        }
    
    #ifdef DEBUG_PUSH
        printf("value pushed: %s\n", value);
    #endif
    
        /*
         * Examine all outside transition from current state
         */
        for (i = 0;i < comp->nbstrings;i++) {
    	target = comp->compact[state * (comp->nbstrings + 1) + i + 1];
    	if ((target > 0) && (target <= comp->nbstates)) {
    	    target--; /* to avoid 0 */
    	    if (xmlStrEqual(comp->stringMap[i], value)) {
    		exec->index = target;
    		if ((exec->callback != NULL) && (comp->transdata != NULL)) {
    		    exec->callback(exec->data, value,
    			  comp->transdata[state * comp->nbstrings + i], data);
    		}
    #ifdef DEBUG_PUSH
    		printf("entering state %d\n", target);
    #endif
    		if (comp->compact[target * (comp->nbstrings + 1)] ==
    		    XML_REGEXP_FINAL_STATE)
    		    return(1);
    		return(0);
    	    }
    	}
        }
        /*
         * Failed to find an exit transition out from current state for the
         * current token
         */
    #ifdef DEBUG_PUSH
        printf("failed to find a transition for %s on state %d\n", value, state);
    #endif
        exec->status = -1;
        return(-1);
    }
    
    /**
     * xmlRegExecPushString:
     * @exec: a regexp execution context or NULL to indicate the end
     * @value: a string token input
     * @data: data associated to the token to reuse in callbacks
     *
     * Push one input token in the execution context
     *
     * Returns: 1 if the regexp reached a final state, 0 if non-final, and
     *     a negative value in case of error.
     */
    int
    xmlRegExecPushString(xmlRegExecCtxtPtr exec, const xmlChar *value,
    	             void *data) {
        xmlRegTransPtr trans;
        xmlRegAtomPtr atom;
        int ret;
        int final = 0;
    
        if (exec == NULL)
    	return(-1);
        if (exec->comp == NULL)
    	return(-1);
        if (exec->status != 0)
    	return(exec->status);
    
        if (exec->comp->compact != NULL)
    	return(xmlRegCompactPushString(exec, exec->comp, value, data));
    
        if (value == NULL) {
            if (exec->state->type == XML_REGEXP_FINAL_STATE)
    	    return(1);
    	final = 1;
        }
    
    #ifdef DEBUG_PUSH
        printf("value pushed: %s\n", value);
    #endif
        /*
         * If we have an active rollback stack push the new value there
         * and get back to where we were left
         */
        if ((value != NULL) && (exec->inputStackNr > 0)) {
    	xmlFARegExecSaveInputString(exec, value, data);
    	value = exec->inputStack[exec->index].value;
    	data = exec->inputStack[exec->index].data;
    #ifdef DEBUG_PUSH
    	printf("value loaded: %s\n", value);
    #endif
        }
    
        while ((exec->status == 0) &&
    	   ((value != NULL) ||
    	    ((final == 1) &&
    	     (exec->state->type != XML_REGEXP_FINAL_STATE)))) {
    
    	/*
    	 * End of input on non-terminal state, rollback, however we may
    	 * still have epsilon like transition for counted transitions
    	 * on counters, in that case don't break too early.
    	 */
    	if ((value == NULL) && (exec->counts == NULL))
    	    goto rollback;
    
    	exec->transcount = 0;
    	for (;exec->transno < exec->state->nbTrans;exec->transno++) {
    	    trans = &exec->state->trans[exec->transno];
    	    if (trans->to < 0)
    		continue;
    	    atom = trans->atom;
    	    ret = 0;
    	    if (trans->count == REGEXP_ALL_LAX_COUNTER) {
    		int i;
    		int count;
    		xmlRegTransPtr t;
    		xmlRegCounterPtr counter;
    
    		ret = 0;
    
    #ifdef DEBUG_PUSH
    		printf("testing all lax %d\n", trans->count);
    #endif
    		/*
    		 * Check all counted transitions from the current state
    		 */
    		if ((value == NULL) && (final)) {
    		    ret = 1;
    		} else if (value != NULL) {
    		    for (i = 0;i < exec->state->nbTrans;i++) {
    			t = &exec->state->trans[i];
    			if ((t->counter < 0) || (t == trans))
    			    continue;
    			counter = &exec->comp->counters[t->counter];
    			count = exec->counts[t->counter];
    			if ((count < counter->max) && 
    		            (t->atom != NULL) &&
    			    (xmlStrEqual(value, t->atom->valuep))) {
    			    ret = 0;
    			    break;
    			}
    			if ((count >= counter->min) &&
    			    (count < counter->max) &&
    			    (xmlStrEqual(value, t->atom->valuep))) {
    			    ret = 1;
    			    break;
    			}
    		    }
    		}
    	    } else if (trans->count == REGEXP_ALL_COUNTER) {
    		int i;
    		int count;
    		xmlRegTransPtr t;
    		xmlRegCounterPtr counter;
    
    		ret = 1;
    
    #ifdef DEBUG_PUSH
    		printf("testing all %d\n", trans->count);
    #endif
    		/*
    		 * Check all counted transitions from the current state
    		 */
    		for (i = 0;i < exec->state->nbTrans;i++) {
                        t = &exec->state->trans[i];
    		    if ((t->counter < 0) || (t == trans))
    			continue;
                        counter = &exec->comp->counters[t->counter];
    		    count = exec->counts[t->counter];
    		    if ((count < counter->min) || (count > counter->max)) {
    			ret = 0;
    			break;
    		    }
    		}
    	    } else if (trans->count >= 0) {
    		int count;
    		xmlRegCounterPtr counter;
    
    		/*
    		 * A counted transition.
    		 */
    
    		count = exec->counts[trans->count];
    		counter = &exec->comp->counters[trans->count];
    #ifdef DEBUG_PUSH
    		printf("testing count %d: val %d, min %d, max %d\n",
    		       trans->count, count, counter->min,  counter->max);
    #endif
    		ret = ((count >= counter->min) && (count <= counter->max));
    	    } else if (atom == NULL) {
    		fprintf(stderr, "epsilon transition left at runtime\n");
    		exec->status = -2;
    		break;
    	    } else if (value != NULL) {
    		ret = xmlStrEqual(value, atom->valuep);
    		if ((ret == 1) && (trans->counter >= 0)) {
    		    xmlRegCounterPtr counter;
    		    int count;
    
    		    count = exec->counts[trans->counter];
    		    counter = &exec->comp->counters[trans->counter];
    		    if (count >= counter->max)
    			ret = 0;
    		}
    
    		if ((ret == 1) && (atom->min > 0) && (atom->max > 0)) {
    		    xmlRegStatePtr to = exec->comp->states[trans->to];
    
    		    /*
    		     * this is a multiple input sequence
    		     */
    		    if (exec->state->nbTrans > exec->transno + 1) {
    			if (exec->inputStackNr <= 0) {
    			    xmlFARegExecSaveInputString(exec, value, data);
    			}
    			xmlFARegExecSave(exec);
    		    }
    		    exec->transcount = 1;
    		    do {
    			/*
    			 * Try to progress as much as possible on the input
    			 */
    			if (exec->transcount == atom->max) {
    			    break;
    			}
    			exec->index++;
    			value = exec->inputStack[exec->index].value;
    			data = exec->inputStack[exec->index].data;
    #ifdef DEBUG_PUSH
    			printf("value loaded: %s\n", value);
    #endif
    
    			/*
    			 * End of input: stop here
    			 */
    			if (value == NULL) {
    			    exec->index --;
    			    break;
    			}
    			if (exec->transcount >= atom->min) {
    			    int transno = exec->transno;
    			    xmlRegStatePtr state = exec->state;
    
    			    /*
    			     * The transition is acceptable save it
    			     */
    			    exec->transno = -1; /* trick */
    			    exec->state = to;
    			    if (exec->inputStackNr <= 0) {
    				xmlFARegExecSaveInputString(exec, value, data);
    			    }
    			    xmlFARegExecSave(exec);
    			    exec->transno = transno;
    			    exec->state = state;
    			}
    			ret = xmlStrEqual(value, atom->valuep);
    			exec->transcount++;
    		    } while (ret == 1);
    		    if (exec->transcount < atom->min)
    			ret = 0;
    
    		    /*
    		     * If the last check failed but one transition was found
    		     * possible, rollback
    		     */
    		    if (ret < 0)
    			ret = 0;
    		    if (ret == 0) {
    			goto rollback;
    		    }
    		}
    	    }
    	    if (ret == 1) {
    		if ((exec->callback != NULL) && (atom != NULL)) {
    		    exec->callback(exec->data, atom->valuep,
    			           atom->data, data);
    		}
    		if (exec->state->nbTrans > exec->transno + 1) {
    		    if (exec->inputStackNr <= 0) {
    			xmlFARegExecSaveInputString(exec, value, data);
    		    }
    		    xmlFARegExecSave(exec);
    		}
    		if (trans->counter >= 0) {
    #ifdef DEBUG_PUSH
    		    printf("Increasing count %d\n", trans->counter);
    #endif
    		    exec->counts[trans->counter]++;
    		}
    #ifdef DEBUG_PUSH
    		printf("entering state %d\n", trans->to);
    #endif
    		exec->state = exec->comp->states[trans->to];
    		exec->transno = 0;
    		if (trans->atom != NULL) {
    		    if (exec->inputStack != NULL) {
    			exec->index++;
    			if (exec->index < exec->inputStackNr) {
    			    value = exec->inputStack[exec->index].value;
    			    data = exec->inputStack[exec->index].data;
    #ifdef DEBUG_PUSH
    			    printf("value loaded: %s\n", value);
    #endif
    			} else {
    			    value = NULL;
    			    data = NULL;
    #ifdef DEBUG_PUSH
    			    printf("end of input\n");
    #endif
    			}
    		    } else {
    			value = NULL;
    			data = NULL;
    #ifdef DEBUG_PUSH
    			printf("end of input\n");
    #endif
    		    }
    		}
    		goto progress;
    	    } else if (ret < 0) {
    		exec->status = -4;
    		break;
    	    }
    	}
    	if ((exec->transno != 0) || (exec->state->nbTrans == 0)) {
    rollback:
    	    /*
    	     * Failed to find a way out
    	     */
    	    exec->determinist = 0;
    	    xmlFARegExecRollBack(exec);
    	    if (exec->status == 0) {
    		value = exec->inputStack[exec->index].value;
    		data = exec->inputStack[exec->index].data;
    #ifdef DEBUG_PUSH
    		printf("value loaded: %s\n", value);
    #endif
    	    }
    	}
    progress:
    	continue;
        }
        if (exec->status == 0) {
            return(exec->state->type == XML_REGEXP_FINAL_STATE);
        }
        return(exec->status);
    }
    
    #if 0
    static int
    xmlRegExecPushChar(xmlRegExecCtxtPtr exec, int UCS) {
        xmlRegTransPtr trans;
        xmlRegAtomPtr atom;
        int ret;
        int codepoint, len;
    
        if (exec == NULL)
    	return(-1);
        if (exec->status != 0)
    	return(exec->status);
    
        while ((exec->status == 0) &&
    	   ((exec->inputString[exec->index] != 0) ||
    	    (exec->state->type != XML_REGEXP_FINAL_STATE))) {
    
    	/*
    	 * End of input on non-terminal state, rollback, however we may
    	 * still have epsilon like transition for counted transitions
    	 * on counters, in that case don't break too early.
    	 */
    	if ((exec->inputString[exec->index] == 0) && (exec->counts == NULL))
    	    goto rollback;
    
    	exec->transcount = 0;
    	for (;exec->transno < exec->state->nbTrans;exec->transno++) {
    	    trans = &exec->state->trans[exec->transno];
    	    if (trans->to < 0)
    		continue;
    	    atom = trans->atom;
    	    ret = 0;
    	    if (trans->count >= 0) {
    		int count;
    		xmlRegCounterPtr counter;
    
    		/*
    		 * A counted transition.
    		 */
    
    		count = exec->counts[trans->count];
    		counter = &exec->comp->counters[trans->count];
    #ifdef DEBUG_REGEXP_EXEC
    		printf("testing count %d: val %d, min %d, max %d\n",
    		       trans->count, count, counter->min,  counter->max);
    #endif
    		ret = ((count >= counter->min) && (count <= counter->max));
    	    } else if (atom == NULL) {
    		fprintf(stderr, "epsilon transition left at runtime\n");
    		exec->status = -2;
    		break;
    	    } else if (exec->inputString[exec->index] != 0) {
                    codepoint = CUR_SCHAR(&(exec->inputString[exec->index]), len);
    		ret = xmlRegCheckCharacter(atom, codepoint);
    		if ((ret == 1) && (atom->min > 0) && (atom->max > 0)) {
    		    xmlRegStatePtr to = exec->comp->states[trans->to];
    
    		    /*
    		     * this is a multiple input sequence
    		     */
    		    if (exec->state->nbTrans > exec->transno + 1) {
    			xmlFARegExecSave(exec);
    		    }
    		    exec->transcount = 1;
    		    do {
    			/*
    			 * Try to progress as much as possible on the input
    			 */
    			if (exec->transcount == atom->max) {
    			    break;
    			}
    			exec->index += len;
    			/*
    			 * End of input: stop here
    			 */
    			if (exec->inputString[exec->index] == 0) {
    			    exec->index -= len;
    			    break;
    			}
    			if (exec->transcount >= atom->min) {
    			    int transno = exec->transno;
    			    xmlRegStatePtr state = exec->state;
    
    			    /*
    			     * The transition is acceptable save it
    			     */
    			    exec->transno = -1; /* trick */
    			    exec->state = to;
    			    xmlFARegExecSave(exec);
    			    exec->transno = transno;
    			    exec->state = state;
    			}
    			codepoint = CUR_SCHAR(&(exec->inputString[exec->index]),
    				              len);
    			ret = xmlRegCheckCharacter(atom, codepoint);
    			exec->transcount++;
    		    } while (ret == 1);
    		    if (exec->transcount < atom->min)
    			ret = 0;
    
    		    /*
    		     * If the last check failed but one transition was found
    		     * possible, rollback
    		     */
    		    if (ret < 0)
    			ret = 0;
    		    if (ret == 0) {
    			goto rollback;
    		    }
    		}
    	    }
    	    if (ret == 1) {
    		if (exec->state->nbTrans > exec->transno + 1) {
    		    xmlFARegExecSave(exec);
    		}
    		if (trans->counter >= 0) {
    #ifdef DEBUG_REGEXP_EXEC
    		    printf("Increasing count %d\n", trans->counter);
    #endif
    		    exec->counts[trans->counter]++;
    		}
    #ifdef DEBUG_REGEXP_EXEC
    		printf("entering state %d\n", trans->to);
    #endif
    		exec->state = exec->comp->states[trans->to];
    		exec->transno = 0;
    		if (trans->atom != NULL) {
    		    exec->index += len;
    		}
    		goto progress;
    	    } else if (ret < 0) {
    		exec->status = -4;
    		break;
    	    }
    	}
    	if ((exec->transno != 0) || (exec->state->nbTrans == 0)) {
    rollback:
    	    /*
    	     * Failed to find a way out
    	     */
    	    exec->determinist = 0;
    	    xmlFARegExecRollBack(exec);
    	}
    progress:
    	continue;
        }
    }
    #endif
    /************************************************************************
     * 									*
     *	Parser for the Shemas Datatype Regular Expressions		*
     *	http://www.w3.org/TR/2001/REC-xmlschema-2-20010502/#regexs	*
     * 									*
     ************************************************************************/
    
    /**
     * xmlFAIsChar:
     * @ctxt:  a regexp parser context
     *
     * [10]   Char   ::=   [^.\?*+()|#x5B#x5D]
     */
    static int
    xmlFAIsChar(xmlRegParserCtxtPtr ctxt) {
        int cur;
        int len;
    
        cur = CUR_SCHAR(ctxt->cur, len);
        if ((cur == '.') || (cur == '\\') || (cur == '?') ||
    	(cur == '*') || (cur == '+') || (cur == '(') ||
    	(cur == ')') || (cur == '|') || (cur == 0x5B) ||
    	(cur == 0x5D) || (cur == 0))
    	return(-1);
        return(cur);
    }
    
    /**
     * xmlFAParseCharProp:
     * @ctxt:  a regexp parser context
     *
     * [27]   charProp   ::=   IsCategory | IsBlock
     * [28]   IsCategory ::= Letters | Marks | Numbers | Punctuation |
     *                       Separators | Symbols | Others 
     * [29]   Letters   ::=   'L' [ultmo]?
     * [30]   Marks   ::=   'M' [nce]?
     * [31]   Numbers   ::=   'N' [dlo]?
     * [32]   Punctuation   ::=   'P' [cdseifo]?
     * [33]   Separators   ::=   'Z' [slp]?
     * [34]   Symbols   ::=   'S' [mcko]?
     * [35]   Others   ::=   'C' [cfon]?
     * [36]   IsBlock   ::=   'Is' [a-zA-Z0-9#x2D]+
     */
    static void
    xmlFAParseCharProp(xmlRegParserCtxtPtr ctxt) {
        int cur;
        xmlRegAtomType type = 0;
        xmlChar *blockName = NULL;
        
        cur = CUR;
        if (cur == 'L') {
    	NEXT;
    	cur = CUR;
    	if (cur == 'u') {
    	    NEXT;
    	    type = XML_REGEXP_LETTER_UPPERCASE;
    	} else if (cur == 'l') {
    	    NEXT;
    	    type = XML_REGEXP_LETTER_LOWERCASE;
    	} else if (cur == 't') {
    	    NEXT;
    	    type = XML_REGEXP_LETTER_TITLECASE;
    	} else if (cur == 'm') {
    	    NEXT;
    	    type = XML_REGEXP_LETTER_MODIFIER;
    	} else if (cur == 'o') {
    	    NEXT;
    	    type = XML_REGEXP_LETTER_OTHERS;
    	} else {
    	    type = XML_REGEXP_LETTER;
    	}
        } else if (cur == 'M') {
    	NEXT;
    	cur = CUR;
    	if (cur == 'n') {
    	    NEXT;
    	    /* nonspacing */
    	    type = XML_REGEXP_MARK_NONSPACING;
    	} else if (cur == 'c') {
    	    NEXT;
    	    /* spacing combining */
    	    type = XML_REGEXP_MARK_SPACECOMBINING;
    	} else if (cur == 'e') {
    	    NEXT;
    	    /* enclosing */
    	    type = XML_REGEXP_MARK_ENCLOSING;
    	} else {
    	    /* all marks */
    	    type = XML_REGEXP_MARK;
    	}
        } else if (cur == 'N') {
    	NEXT;
    	cur = CUR;
    	if (cur == 'd') {
    	    NEXT;
    	    /* digital */
    	    type = XML_REGEXP_NUMBER_DECIMAL;
    	} else if (cur == 'l') {
    	    NEXT;
    	    /* letter */
    	    type = XML_REGEXP_NUMBER_LETTER;
    	} else if (cur == 'o') {
    	    NEXT;
    	    /* other */
    	    type = XML_REGEXP_NUMBER_OTHERS;
    	} else {
    	    /* all numbers */
    	    type = XML_REGEXP_NUMBER;
    	}
        } else if (cur == 'P') {
    	NEXT;
    	cur = CUR;
    	if (cur == 'c') {
    	    NEXT;
    	    /* connector */
    	    type = XML_REGEXP_PUNCT_CONNECTOR;
    	} else if (cur == 'd') {
    	    NEXT;
    	    /* dash */
    	    type = XML_REGEXP_PUNCT_DASH;
    	} else if (cur == 's') {
    	    NEXT;
    	    /* open */
    	    type = XML_REGEXP_PUNCT_OPEN;
    	} else if (cur == 'e') {
    	    NEXT;
    	    /* close */
    	    type = XML_REGEXP_PUNCT_CLOSE;
    	} else if (cur == 'i') {
    	    NEXT;
    	    /* initial quote */
    	    type = XML_REGEXP_PUNCT_INITQUOTE;
    	} else if (cur == 'f') {
    	    NEXT;
    	    /* final quote */
    	    type = XML_REGEXP_PUNCT_FINQUOTE;
    	} else if (cur == 'o') {
    	    NEXT;
    	    /* other */
    	    type = XML_REGEXP_PUNCT_OTHERS;
    	} else {
    	    /* all punctuation */
    	    type = XML_REGEXP_PUNCT;
    	}
        } else if (cur == 'Z') {
    	NEXT;
    	cur = CUR;
    	if (cur == 's') {
    	    NEXT;
    	    /* space */
    	    type = XML_REGEXP_SEPAR_SPACE;
    	} else if (cur == 'l') {
    	    NEXT;
    	    /* line */
    	    type = XML_REGEXP_SEPAR_LINE;
    	} else if (cur == 'p') {
    	    NEXT;
    	    /* paragraph */
    	    type = XML_REGEXP_SEPAR_PARA;
    	} else {
    	    /* all separators */
    	    type = XML_REGEXP_SEPAR;
    	}
        } else if (cur == 'S') {
    	NEXT;
    	cur = CUR;
    	if (cur == 'm') {
    	    NEXT;
    	    type = XML_REGEXP_SYMBOL_MATH;
    	    /* math */
    	} else if (cur == 'c') {
    	    NEXT;
    	    type = XML_REGEXP_SYMBOL_CURRENCY;
    	    /* currency */
    	} else if (cur == 'k') {
    	    NEXT;
    	    type = XML_REGEXP_SYMBOL_MODIFIER;
    	    /* modifiers */
    	} else if (cur == 'o') {
    	    NEXT;
    	    type = XML_REGEXP_SYMBOL_OTHERS;
    	    /* other */
    	} else {
    	    /* all symbols */
    	    type = XML_REGEXP_SYMBOL;
    	}
        } else if (cur == 'C') {
    	NEXT;
    	cur = CUR;
    	if (cur == 'c') {
    	    NEXT;
    	    /* control */
    	    type = XML_REGEXP_OTHER_CONTROL;
    	} else if (cur == 'f') {
    	    NEXT;
    	    /* format */
    	    type = XML_REGEXP_OTHER_FORMAT;
    	} else if (cur == 'o') {
    	    NEXT;
    	    /* private use */
    	    type = XML_REGEXP_OTHER_PRIVATE;
    	} else if (cur == 'n') {
    	    NEXT;
    	    /* not assigned */
    	    type = XML_REGEXP_OTHER_NA;
    	} else {
    	    /* all others */
    	    type = XML_REGEXP_OTHER;
    	}
        } else if (cur == 'I') {
    	const xmlChar *start;
    	NEXT;
    	cur = CUR;
    	if (cur != 's') {
    	    ERROR("IsXXXX expected");
    	    return;
    	}
    	NEXT;
    	start = ctxt->cur;
    	cur = CUR;
    	if (((cur >= 'a') && (cur <= 'z')) || 
    	    ((cur >= 'A') && (cur <= 'Z')) || 
    	    ((cur >= '0') && (cur <= '9')) || 
    	    (cur == 0x2D)) {
    	    NEXT;
    	    cur = CUR;
    	    while (((cur >= 'a') && (cur <= 'z')) || 
    		((cur >= 'A') && (cur <= 'Z')) || 
    		((cur >= '0') && (cur <= '9')) || 
    		(cur == 0x2D)) {
    		NEXT;
    		cur = CUR;
    	    }
    	}
    	type = XML_REGEXP_BLOCK_NAME;
    	blockName = xmlStrndup(start, ctxt->cur - start);
        } else {
    	ERROR("Unknown char property");
    	return;
        }
        if (ctxt->atom == NULL) {
    	ctxt->atom = xmlRegNewAtom(ctxt, type);
    	if (ctxt->atom != NULL)
    	    ctxt->atom->valuep = blockName;
        } else if (ctxt->atom->type == XML_REGEXP_RANGES) {
            xmlRegAtomAddRange(ctxt, ctxt->atom, ctxt->neg,
    		           type, 0, 0, blockName);
        }
    }
    
    /**
     * xmlFAParseCharClassEsc:
     * @ctxt:  a regexp parser context
     *
     * [23] charClassEsc ::= ( SingleCharEsc | MultiCharEsc | catEsc | complEsc ) 
     * [24] SingleCharEsc ::= '\' [nrt\|.?*+(){}#x2D#x5B#x5D#x5E]
     * [25] catEsc   ::=   '\p{' charProp '}'
     * [26] complEsc ::=   '\P{' charProp '}'
     * [37] MultiCharEsc ::= '.' | ('\' [sSiIcCdDwW])
     */
    static void
    xmlFAParseCharClassEsc(xmlRegParserCtxtPtr ctxt) {
        int cur;
    
        if (CUR == '.') {
    	if (ctxt->atom == NULL) {
    	    ctxt->atom = xmlRegNewAtom(ctxt, XML_REGEXP_ANYCHAR);
    	} else if (ctxt->atom->type == XML_REGEXP_RANGES) {
    	    xmlRegAtomAddRange(ctxt, ctxt->atom, ctxt->neg,
    			       XML_REGEXP_ANYCHAR, 0, 0, NULL);
    	}
    	NEXT;
    	return;
        }
        if (CUR != '\\') {
    	ERROR("Escaped sequence: expecting \\");
    	return;
        }
        NEXT;
        cur = CUR;
        if (cur == 'p') {
    	NEXT;
    	if (CUR != '{') {
    	    ERROR("Expecting '{'");
    	    return;
    	}
    	NEXT;
    	xmlFAParseCharProp(ctxt);
    	if (CUR != '}') {
    	    ERROR("Expecting '}'");
    	    return;
    	}
    	NEXT;
        } else if (cur == 'P') {
    	NEXT;
    	if (CUR != '{') {
    	    ERROR("Expecting '{'");
    	    return;
    	}
    	NEXT;
    	xmlFAParseCharProp(ctxt);
    	ctxt->atom->neg = 1;
    	if (CUR != '}') {
    	    ERROR("Expecting '}'");
    	    return;
    	}
    	NEXT;
        } else if ((cur == 'n') || (cur == 'r') || (cur == 't') || (cur == '\\') ||
    	(cur == '|') || (cur == '.') || (cur == '?') || (cur == '*') ||
    	(cur == '+') || (cur == '(') || (cur == ')') || (cur == '{') ||
    	(cur == '}') || (cur == 0x2D) || (cur == 0x5B) || (cur == 0x5D) ||
    	(cur == 0x5E)) {
    	if (ctxt->atom == NULL) {
    	    ctxt->atom = xmlRegNewAtom(ctxt, XML_REGEXP_CHARVAL);
    	    if (ctxt->atom != NULL)
    		ctxt->atom->codepoint = cur;
    	} else if (ctxt->atom->type == XML_REGEXP_RANGES) {
    	    xmlRegAtomAddRange(ctxt, ctxt->atom, ctxt->neg,
    			       XML_REGEXP_CHARVAL, cur, cur, NULL);
    	}
    	NEXT;
        } else if ((cur == 's') || (cur == 'S') || (cur == 'i') || (cur == 'I') ||
    	(cur == 'c') || (cur == 'C') || (cur == 'd') || (cur == 'D') ||
    	(cur == 'w') || (cur == 'W')) {
    	xmlRegAtomType type = XML_REGEXP_ANYSPACE;
    
    	switch (cur) {
    	    case 's': 
    		type = XML_REGEXP_ANYSPACE;
    		break;
    	    case 'S': 
    		type = XML_REGEXP_NOTSPACE;
    		break;
    	    case 'i': 
    		type = XML_REGEXP_INITNAME;
    		break;
    	    case 'I': 
    		type = XML_REGEXP_NOTINITNAME;
    		break;
    	    case 'c': 
    		type = XML_REGEXP_NAMECHAR;
    		break;
    	    case 'C': 
    		type = XML_REGEXP_NOTNAMECHAR;
    		break;
    	    case 'd': 
    		type = XML_REGEXP_DECIMAL;
    		break;
    	    case 'D': 
    		type = XML_REGEXP_NOTDECIMAL;
    		break;
    	    case 'w': 
    		type = XML_REGEXP_REALCHAR;
    		break;
    	    case 'W': 
    		type = XML_REGEXP_NOTREALCHAR;
    		break;
    	}
    	NEXT;
    	if (ctxt->atom == NULL) {
    	    ctxt->atom = xmlRegNewAtom(ctxt, type);
    	} else if (ctxt->atom->type == XML_REGEXP_RANGES) {
    	    xmlRegAtomAddRange(ctxt, ctxt->atom, ctxt->neg,
    			       type, 0, 0, NULL);
    	}
        }
    }
    
    /**
     * xmlFAParseCharRef:
     * @ctxt:  a regexp parser context
     *
     * [19]   XmlCharRef   ::=   ( '&#' [0-9]+ ';' ) | (' &#x' [0-9a-fA-F]+ ';' )
     */
    static int
    xmlFAParseCharRef(xmlRegParserCtxtPtr ctxt) {
        int ret = 0, cur;
    
        if ((CUR != '&') || (NXT(1) != '#'))
    	return(-1);
        NEXT;
        NEXT;
        cur = CUR;
        if (cur == 'x') {
    	NEXT;
    	cur = CUR;
    	if (((cur >= '0') && (cur <= '9')) ||
    	    ((cur >= 'a') && (cur <= 'f')) ||
    	    ((cur >= 'A') && (cur <= 'F'))) {
    	    while (((cur >= '0') && (cur <= '9')) ||
    		   ((cur >= 'A') && (cur <= 'F'))) {
    		if ((cur >= '0') && (cur <= '9'))
    		    ret = ret * 16 + cur - '0';
    		else if ((cur >= 'a') && (cur <= 'f'))
    		    ret = ret * 16 + 10 + (cur - 'a');
    		else
    		    ret = ret * 16 + 10 + (cur - 'A');
    		NEXT;
    		cur = CUR;
    	    }
    	} else {
    	    ERROR("Char ref: expecting [0-9A-F]");
    	    return(-1);
    	}
        } else {
    	if ((cur >= '0') && (cur <= '9')) {
    	    while ((cur >= '0') && (cur <= '9')) {
    		ret = ret * 10 + cur - '0';
    		NEXT;
    		cur = CUR;
    	    }
    	} else {
    	    ERROR("Char ref: expecting [0-9]");
    	    return(-1);
    	}
        }
        if (cur != ';') {
    	ERROR("Char ref: expecting ';'");
    	return(-1);
        } else {
    	NEXT;
        }
        return(ret);
    }
    
    /**
     * xmlFAParseCharRange:
     * @ctxt:  a regexp parser context
     *
     * [17]   charRange   ::=     seRange | XmlCharRef | XmlCharIncDash 
     * [18]   seRange   ::=   charOrEsc '-' charOrEsc
     * [20]   charOrEsc   ::=   XmlChar | SingleCharEsc
     * [21]   XmlChar   ::=   [^\#x2D#x5B#x5D]
     * [22]   XmlCharIncDash   ::=   [^\#x5B#x5D]
     */
    static void
    xmlFAParseCharRange(xmlRegParserCtxtPtr ctxt) {
        int cur;
        int start = -1;
        int end = -1;
    
        if ((CUR == '&') && (NXT(1) == '#')) {
    	end = start = xmlFAParseCharRef(ctxt);
            xmlRegAtomAddRange(ctxt, ctxt->atom, ctxt->neg,
    	                   XML_REGEXP_CHARVAL, start, end, NULL);
    	return;
        }
        cur = CUR;
        if (cur == '\\') {
    	NEXT;
    	cur = CUR;
    	switch (cur) {
    	    case 'n': start = 0xA; break;
    	    case 'r': start = 0xD; break;
    	    case 't': start = 0x9; break;
    	    case '\\': case '|': case '.': case '-': case '^': case '?':
    	    case '*': case '+': case '{': case '}': case '(': case ')':
    	    case '[': case ']':
    		start = cur; break;
    	    default:
    		ERROR("Invalid escape value");
    		return;
    	}
    	end = start;
        } else if ((cur != 0x5B) && (cur != 0x5D)) {
    	end = start = cur;
        } else {
    	ERROR("Expecting a char range");
    	return;
        }
        NEXT;
        if (start == '-') {
    	return;
        }
        cur = CUR;
        if (cur != '-') {
            xmlRegAtomAddRange(ctxt, ctxt->atom, ctxt->neg,
    		              XML_REGEXP_CHARVAL, start, end, NULL);
    	return;
        }
        NEXT;
        cur = CUR;
        if (cur == '\\') {
    	NEXT;
    	cur = CUR;
    	switch (cur) {
    	    case 'n': end = 0xA; break;
    	    case 'r': end = 0xD; break;
    	    case 't': end = 0x9; break;
    	    case '\\': case '|': case '.': case '-': case '^': case '?':
    	    case '*': case '+': case '{': case '}': case '(': case ')':
    	    case '[': case ']':
    		end = cur; break;
    	    default:
    		ERROR("Invalid escape value");
    		return;
    	}
        } else if ((cur != 0x5B) && (cur != 0x5D)) {
    	end = cur;
        } else {
    	ERROR("Expecting the end of a char range");
    	return;
        }
        NEXT;
        /* TODO check that the values are acceptable character ranges for XML */
        if (end < start) {
    	ERROR("End of range is before start of range");
        } else {
            xmlRegAtomAddRange(ctxt, ctxt->atom, ctxt->neg,
    		           XML_REGEXP_CHARVAL, start, end, NULL);
        }
        return;
    }
    
    /**
     * xmlFAParsePosCharGroup:
     * @ctxt:  a regexp parser context
     *
     * [14]   posCharGroup ::= ( charRange | charClassEsc  )+
     */
    static void
    xmlFAParsePosCharGroup(xmlRegParserCtxtPtr ctxt) {
        do {
    	if ((CUR == '\\') || (CUR == '.')) {
    	    xmlFAParseCharClassEsc(ctxt);
    	} else {
    	    xmlFAParseCharRange(ctxt);
    	}
        } while ((CUR != ']') && (CUR != '^') && (CUR != '-') &&
    	     (ctxt->error == 0));
    }
    
    /**
     * xmlFAParseCharGroup:
     * @ctxt:  a regexp parser context
     *
     * [13]   charGroup    ::= posCharGroup | negCharGroup | charClassSub
     * [15]   negCharGroup ::= '^' posCharGroup
     * [16]   charClassSub ::= ( posCharGroup | negCharGroup ) '-' charClassExpr  
     * [12]   charClassExpr ::= '[' charGroup ']'
     */
    static void
    xmlFAParseCharGroup(xmlRegParserCtxtPtr ctxt) {
        int n = ctxt->neg;
        while ((CUR != ']') && (ctxt->error == 0)) {
    	if (CUR == '^') {
    	    int neg = ctxt->neg;
    
    	    NEXT;
    	    ctxt->neg = !ctxt->neg;
    	    xmlFAParsePosCharGroup(ctxt);
    	    ctxt->neg = neg;
    	} else if (CUR == '-') {
    	    NEXT;
    	    ctxt->neg = !ctxt->neg;
    	    if (CUR != '[') {
    		ERROR("charClassExpr: '[' expected");
    		break;
    	    }
    	    NEXT;
    	    xmlFAParseCharGroup(ctxt);
    	    if (CUR == ']') {
    		NEXT;
    	    } else {
    		ERROR("charClassExpr: ']' expected");
    		break;
    	    }
    	    break;
    	} else if (CUR != ']') {
    	    xmlFAParsePosCharGroup(ctxt);
    	}
        }
        ctxt->neg = n;
    }
    
    /**
     * xmlFAParseCharClass:
     * @ctxt:  a regexp parser context
     *
     * [11]   charClass   ::=     charClassEsc | charClassExpr
     * [12]   charClassExpr   ::=   '[' charGroup ']'
     */
    static void
    xmlFAParseCharClass(xmlRegParserCtxtPtr ctxt) {
        if (CUR == '[') {
    	NEXT;
    	ctxt->atom = xmlRegNewAtom(ctxt, XML_REGEXP_RANGES);
    	if (ctxt->atom == NULL)
    	    return;
    	xmlFAParseCharGroup(ctxt);
    	if (CUR == ']') {
    	    NEXT;
    	} else {
    	    ERROR("xmlFAParseCharClass: ']' expected");
    	}
        } else {
    	xmlFAParseCharClassEsc(ctxt);
        }
    }
    
    /**
     * xmlFAParseQuantExact:
     * @ctxt:  a regexp parser context
     *
     * [8]   QuantExact   ::=   [0-9]+
     */
    static int
    xmlFAParseQuantExact(xmlRegParserCtxtPtr ctxt) {
        int ret = 0;
        int ok = 0;
    
        while ((CUR >= '0') && (CUR <= '9')) {
    	ret = ret * 10 + (CUR - '0');
    	ok = 1;
    	NEXT;
        }
        if (ok != 1) {
    	return(-1);
        }
        return(ret);
    }
    
    /**
     * xmlFAParseQuantifier:
     * @ctxt:  a regexp parser context
     *
     * [4]   quantifier   ::=   [?*+] | ( '{' quantity '}' )
     * [5]   quantity   ::=   quantRange | quantMin | QuantExact
     * [6]   quantRange   ::=   QuantExact ',' QuantExact
     * [7]   quantMin   ::=   QuantExact ','
     * [8]   QuantExact   ::=   [0-9]+
     */
    static int
    xmlFAParseQuantifier(xmlRegParserCtxtPtr ctxt) {
        int cur;
    
        cur = CUR;
        if ((cur == '?') || (cur == '*') || (cur == '+')) {
    	if (ctxt->atom != NULL) {
    	    if (cur == '?')
    		ctxt->atom->quant = XML_REGEXP_QUANT_OPT;
    	    else if (cur == '*')
    		ctxt->atom->quant = XML_REGEXP_QUANT_MULT;
    	    else if (cur == '+')
    		ctxt->atom->quant = XML_REGEXP_QUANT_PLUS;
    	}
    	NEXT;
    	return(1);
        }
        if (cur == '{') {
    	int min = 0, max = 0;
    
    	NEXT;
    	cur = xmlFAParseQuantExact(ctxt);
    	if (cur >= 0)
    	    min = cur;
    	if (CUR == ',') {
    	    NEXT;
    	    cur = xmlFAParseQuantExact(ctxt);
    	    if (cur >= 0)
    		max = cur;
    	}
    	if (CUR == '}') {
    	    NEXT;
    	} else {
    	    ERROR("Unterminated quantifier");
    	}
    	if (max == 0)
    	    max = min;
    	if (ctxt->atom != NULL) {
    	    ctxt->atom->quant = XML_REGEXP_QUANT_RANGE;
    	    ctxt->atom->min = min;
    	    ctxt->atom->max = max;
    	}
    	return(1);
        }
        return(0);
    }
    
    /**
     * xmlFAParseAtom:
     * @ctxt:  a regexp parser context
     *
     * [9]   atom   ::=   Char | charClass | ( '(' regExp ')' )
     */
    static int
    xmlFAParseAtom(xmlRegParserCtxtPtr ctxt) {
        int codepoint, len;
    
        codepoint = xmlFAIsChar(ctxt);
        if (codepoint > 0) {
    	ctxt->atom = xmlRegNewAtom(ctxt, XML_REGEXP_CHARVAL);
    	if (ctxt->atom == NULL)
    	    return(-1);
    	codepoint = CUR_SCHAR(ctxt->cur, len);
    	ctxt->atom->codepoint = codepoint;
    	NEXTL(len);
    	return(1);
        } else if (CUR == '|') {
    	return(0);
        } else if (CUR == 0) {
    	return(0);
        } else if (CUR == ')') {
    	return(0);
        } else if (CUR == '(') {
    	xmlRegStatePtr start, oldend;
    
    	NEXT;
    	xmlFAGenerateEpsilonTransition(ctxt, ctxt->state, NULL);
    	start = ctxt->state;
    	oldend = ctxt->end;
    	ctxt->end = NULL;
    	ctxt->atom = NULL;
    	xmlFAParseRegExp(ctxt, 0);
    	if (CUR == ')') {
    	    NEXT;
    	} else {
    	    ERROR("xmlFAParseAtom: expecting ')'");
    	}
    	ctxt->atom = xmlRegNewAtom(ctxt, XML_REGEXP_SUBREG);
    	if (ctxt->atom == NULL)
    	    return(-1);
    	ctxt->atom->start = start;
    	ctxt->atom->stop = ctxt->state;
    	ctxt->end = oldend;
    	return(1);
        } else if ((CUR == '[') || (CUR == '\\') || (CUR == '.')) {
    	xmlFAParseCharClass(ctxt);
    	return(1);
        }
        return(0);
    }
    
    /**
     * xmlFAParsePiece:
     * @ctxt:  a regexp parser context
     *
     * [3]   piece   ::=   atom quantifier?
     */
    static int
    xmlFAParsePiece(xmlRegParserCtxtPtr ctxt) {
        int ret;
    
        ctxt->atom = NULL;
        ret = xmlFAParseAtom(ctxt);
        if (ret == 0)
    	return(0);
        if (ctxt->atom == NULL) {
    	ERROR("internal: no atom generated");
        }
        xmlFAParseQuantifier(ctxt);
        return(1);
    }
    
    /**
     * xmlFAParseBranch:
     * @ctxt:  a regexp parser context
     * @first:  is taht the first
     *
     * [2]   branch   ::=   piece*
     */
    static void
    xmlFAParseBranch(xmlRegParserCtxtPtr ctxt, int first) {
        xmlRegStatePtr previous;
        xmlRegAtomPtr prevatom = NULL;
        int ret;
    
        previous = ctxt->state;
        ret = xmlFAParsePiece(ctxt);
        if (ret != 0) {
    	if (first) {
    	    xmlFAGenerateTransitions(ctxt, previous, NULL, ctxt->atom);
    	    previous = ctxt->state;
    	} else {
    	    prevatom = ctxt->atom;
    	}
    	ctxt->atom = NULL;
        }
        while ((ret != 0) && (ctxt->error == 0)) {
    	ret = xmlFAParsePiece(ctxt);
    	if (ret != 0) {
    	    if (first) {
    		xmlFAGenerateTransitions(ctxt, previous, NULL, ctxt->atom);
    	    } else {
    		xmlFAGenerateTransitions(ctxt, previous, NULL, prevatom);
    		prevatom = ctxt->atom;
    	    }
    	    previous = ctxt->state;
    	    ctxt->atom = NULL;
    	}
        }
        if (!first) {
    	xmlFAGenerateTransitions(ctxt, previous, ctxt->end, prevatom);
        }
    }
    
    /**
     * xmlFAParseRegExp:
     * @ctxt:  a regexp parser context
     * @top:  is that the top-level expressions ?
     *
     * [1]   regExp   ::=     branch  ( '|' branch )*
     */
    static void
    xmlFAParseRegExp(xmlRegParserCtxtPtr ctxt, int top) {
        xmlRegStatePtr start, end, oldend;
    
        oldend = ctxt->end;
    
        start = ctxt->state;
        xmlFAParseBranch(ctxt, (ctxt->end == NULL));
        if (CUR != '|') {
    	ctxt->end = ctxt->state;
    	return;
        }
        end = ctxt->state;
        while ((CUR == '|') && (ctxt->error == 0)) {
    	NEXT;
    	ctxt->state = start;
    	ctxt->end = end;
    	xmlFAParseBranch(ctxt, 0);
        }
        if (!top)
    	ctxt->end = oldend;
    }
    
    /************************************************************************
     * 									*
     * 			The basic API					*
     * 									*
     ************************************************************************/
    
    /**
     * xmlRegexpPrint:
     * @output: the file for the output debug
     * @regexp: the compiled regexp
     *
     * Print the content of the compiled regular expression
     */
    void
    xmlRegexpPrint(FILE *output, xmlRegexpPtr regexp) {
        int i;
    
        fprintf(output, " regexp: ");
        if (regexp == NULL) {
    	fprintf(output, "NULL\n");
    	return;
        }
        fprintf(output, "'%s' ", regexp->string);
        fprintf(output, "\n");
        fprintf(output, "%d atoms:\n", regexp->nbAtoms);
        for (i = 0;i < regexp->nbAtoms; i++) {
    	fprintf(output, " %02d ", i);
    	xmlRegPrintAtom(output, regexp->atoms[i]);
        }
        fprintf(output, "%d states:", regexp->nbStates);
        fprintf(output, "\n");
        for (i = 0;i < regexp->nbStates; i++) {
    	xmlRegPrintState(output, regexp->states[i]);
        }
        fprintf(output, "%d counters:\n", regexp->nbCounters);
        for (i = 0;i < regexp->nbCounters; i++) {
    	fprintf(output, " %d: min %d max %d\n", i, regexp->counters[i].min,
    		                                regexp->counters[i].max);
        }
    }
    
    /**
     * xmlRegexpCompile:
     * @regexp:  a regular expression string
     *
     * Parses a regular expression conforming to XML Schemas Part 2 Datatype
     * Appendix F and build an automata suitable for testing strings against
     * that regular expression
     *
     * Returns the compiled expression or NULL in case of error
     */
    xmlRegexpPtr
    xmlRegexpCompile(const xmlChar *regexp) {
        xmlRegexpPtr ret;
        xmlRegParserCtxtPtr ctxt;
    
        ctxt = xmlRegNewParserCtxt(regexp);
        if (ctxt == NULL)
    	return(NULL);
    
        /* initialize the parser */
        ctxt->end = NULL;
        ctxt->start = ctxt->state = xmlRegNewState(ctxt);
        xmlRegStatePush(ctxt, ctxt->start);
    
        /* parse the expression building an automata */
        xmlFAParseRegExp(ctxt, 1);
        if (CUR != 0) {
    	ERROR("xmlFAParseRegExp: extra characters");
        }
        ctxt->end = ctxt->state;
        ctxt->start->type = XML_REGEXP_START_STATE;
        ctxt->end->type = XML_REGEXP_FINAL_STATE;
    
        /* remove the Epsilon except for counted transitions */
        xmlFAEliminateEpsilonTransitions(ctxt);
    
    
        if (ctxt->error != 0) {
    	xmlRegFreeParserCtxt(ctxt);
    	return(NULL);
        }
        ret = xmlRegEpxFromParse(ctxt);
        xmlRegFreeParserCtxt(ctxt);
        return(ret);
    }
    
    /**
     * xmlRegexpExec:
     * @comp:  the compiled regular expression
     * @content:  the value to check against the regular expression
     *
     * Check if the regular expression generate the value
     *
     * Returns 1 if it matches, 0 if not and a negativa value in case of error
     */
    int
    xmlRegexpExec(xmlRegexpPtr comp, const xmlChar *content) {
        if ((comp == NULL) || (content == NULL))
    	return(-1);
        return(xmlFARegExec(comp, content));
    }
    
    /**
     * xmlRegexpIsDeterminist:
     * @comp:  the compiled regular expression
     *
     * Check if the regular expression is determinist
     *
     * Returns 1 if it yes, 0 if not and a negativa value in case of error
     */
    int
    xmlRegexpIsDeterminist(xmlRegexpPtr comp) {
        xmlAutomataPtr am;
        int ret;
    
        if (comp == NULL)
    	return(-1);
        if (comp->determinist != -1)
    	return(comp->determinist);
    
        am = xmlNewAutomata();
        if (am->states != NULL) {
    	int i;
    
    	for (i = 0;i < am->nbStates;i++)
    	    xmlRegFreeState(am->states[i]);
    	xmlFree(am->states);
        }
        am->nbAtoms = comp->nbAtoms;
        am->atoms = comp->atoms;
        am->nbStates = comp->nbStates;
        am->states = comp->states;
        am->determinist = -1;
        ret = xmlFAComputesDeterminism(am);
        am->atoms = NULL;
        am->states = NULL;
        xmlFreeAutomata(am);
        return(ret);
    }
    
    /**
     * xmlRegFreeRegexp:
     * @regexp:  the regexp
     *
     * Free a regexp
     */
    void
    xmlRegFreeRegexp(xmlRegexpPtr regexp) {
        int i;
        if (regexp == NULL)
    	return;
    
        if (regexp->string != NULL)
    	xmlFree(regexp->string);
        if (regexp->states != NULL) {
    	for (i = 0;i < regexp->nbStates;i++)
    	    xmlRegFreeState(regexp->states[i]);
    	xmlFree(regexp->states);
        }
        if (regexp->atoms != NULL) {
    	for (i = 0;i < regexp->nbAtoms;i++)
    	    xmlRegFreeAtom(regexp->atoms[i]);
    	xmlFree(regexp->atoms);
        }
        if (regexp->counters != NULL)
    	xmlFree(regexp->counters);
        if (regexp->compact != NULL)
    	xmlFree(regexp->compact);
        if (regexp->transdata != NULL)
    	xmlFree(regexp->transdata);
        if (regexp->stringMap != NULL) {
    	for (i = 0; i < regexp->nbstrings;i++)
    	    xmlFree(regexp->stringMap[i]);
    	xmlFree(regexp->stringMap);
        }
    
        xmlFree(regexp);
    }
    
    #ifdef LIBXML_AUTOMATA_ENABLED
    /************************************************************************
     * 									*
     * 			The Automata interface				*
     * 									*
     ************************************************************************/
    
    /**
     * xmlNewAutomata:
     *
     * Create a new automata
     *
     * Returns the new object or NULL in case of failure
     */
    xmlAutomataPtr
    xmlNewAutomata(void) {
        xmlAutomataPtr ctxt;
    
        ctxt = xmlRegNewParserCtxt(NULL);
        if (ctxt == NULL)
    	return(NULL);
    
        /* initialize the parser */
        ctxt->end = NULL;
        ctxt->start = ctxt->state = xmlRegNewState(ctxt);
        xmlRegStatePush(ctxt, ctxt->start);
    
        return(ctxt);
    }
    
    /**
     * xmlFreeAutomata:
     * @am: an automata
     *
     * Free an automata
     */
    void
    xmlFreeAutomata(xmlAutomataPtr am) {
        if (am == NULL)
    	return;
        xmlRegFreeParserCtxt(am);
    }
    
    /**
     * xmlAutomataGetInitState:
     * @am: an automata
     *
     * Initial state lookup
     *
     * Returns the initial state of the automata
     */
    xmlAutomataStatePtr
    xmlAutomataGetInitState(xmlAutomataPtr am) {
        if (am == NULL)
    	return(NULL);
        return(am->start);
    }
    
    /**
     * xmlAutomataSetFinalState:
     * @am: an automata
     * @state: a state in this automata
     *
     * Makes that state a final state
     *
     * Returns 0 or -1 in case of error
     */
    int
    xmlAutomataSetFinalState(xmlAutomataPtr am, xmlAutomataStatePtr state) {
        if ((am == NULL) || (state == NULL))
    	return(-1);
        state->type = XML_REGEXP_FINAL_STATE;
        return(0);
    }
    
    /**
     * xmlAutomataNewTransition:
     * @am: an automata
     * @from: the starting point of the transition
     * @to: the target point of the transition or NULL
     * @token: the input string associated to that transition
     * @data: data passed to the callback function if the transition is activated
     *
     * If @to is NULL, this create first a new target state in the automata
     * and then adds a transition from the @from state to the target state
     * activated by the value of @token
     *
     * Returns the target state or NULL in case of error
     */
    xmlAutomataStatePtr
    xmlAutomataNewTransition(xmlAutomataPtr am, xmlAutomataStatePtr from,
    			 xmlAutomataStatePtr to, const xmlChar *token,
    			 void *data) {
        xmlRegAtomPtr atom;
    
        if ((am == NULL) || (from == NULL) || (token == NULL))
    	return(NULL);
        atom = xmlRegNewAtom(am, XML_REGEXP_STRING);
        atom->data = data;
        if (atom == NULL)
    	return(NULL);
        atom->valuep = xmlStrdup(token);
    
        xmlFAGenerateTransitions(am, from, to, atom);
        if (to == NULL)
    	return(am->state);
        return(to);
    }
    
    /**
     * xmlAutomataNewCountTrans:
     * @am: an automata
     * @from: the starting point of the transition
     * @to: the target point of the transition or NULL
     * @token: the input string associated to that transition
     * @min:  the minimum successive occurences of token
     * @max:  the maximum successive occurences of token
     * @data:  data associated to the transition
     *
     * If @to is NULL, this create first a new target state in the automata
     * and then adds a transition from the @from state to the target state
     * activated by a succession of input of value @token and whose number
     * is between @min and @max
     *
     * Returns the target state or NULL in case of error
     */
    xmlAutomataStatePtr
    xmlAutomataNewCountTrans(xmlAutomataPtr am, xmlAutomataStatePtr from,
    			 xmlAutomataStatePtr to, const xmlChar *token,
    			 int min, int max, void *data) {
        xmlRegAtomPtr atom;
    
        if ((am == NULL) || (from == NULL) || (token == NULL))
    	return(NULL);
        if (min < 0)
    	return(NULL);
        if ((max < min) || (max < 1))
    	return(NULL);
        atom = xmlRegNewAtom(am, XML_REGEXP_STRING);
        if (atom == NULL)
    	return(NULL);
        atom->valuep = xmlStrdup(token);
        atom->data = data;
        if (min == 0)
    	atom->min = 1;
        else
    	atom->min = min;
        atom->max = max;
    
        xmlFAGenerateTransitions(am, from, to, atom);
        if (to == NULL)
    	to = am->state;
        if (to == NULL)
    	return(NULL);
        if (min == 0)
    	xmlFAGenerateEpsilonTransition(am, from, to);
        return(to);
    }
    
    /**
     * xmlAutomataNewOnceTrans:
     * @am: an automata
     * @from: the starting point of the transition
     * @to: the target point of the transition or NULL
     * @token: the input string associated to that transition
     * @min:  the minimum successive occurences of token
     * @max:  the maximum successive occurences of token
     * @data:  data associated to the transition
     *
     * If @to is NULL, this create first a new target state in the automata
     * and then adds a transition from the @from state to the target state
     * activated by a succession of input of value @token and whose number
     * is between @min and @max, moreover that transistion can only be crossed
     * once.
     *
     * Returns the target state or NULL in case of error
     */
    xmlAutomataStatePtr
    xmlAutomataNewOnceTrans(xmlAutomataPtr am, xmlAutomataStatePtr from,
    			 xmlAutomataStatePtr to, const xmlChar *token,
    			 int min, int max, void *data) {
        xmlRegAtomPtr atom;
        int counter;
    
        if ((am == NULL) || (from == NULL) || (token == NULL))
    	return(NULL);
        if (min < 1)
    	return(NULL);
        if ((max < min) || (max < 1))
    	return(NULL);
        atom = xmlRegNewAtom(am, XML_REGEXP_STRING);
        if (atom == NULL)
    	return(NULL);
        atom->valuep = xmlStrdup(token);
        atom->data = data;
        atom->quant = XML_REGEXP_QUANT_ONCEONLY;
        if (min == 0)
    	atom->min = 1;
        else
    	atom->min = min;
        atom->max = max;
        /*
         * associate a counter to the transition.
         */
        counter = xmlRegGetCounter(am);
        am->counters[counter].min = 1;
        am->counters[counter].max = 1;
    
        /* xmlFAGenerateTransitions(am, from, to, atom); */
        if (to == NULL) {
    	to = xmlRegNewState(am);
    	xmlRegStatePush(am, to);
        }
        xmlRegStateAddTrans(am, from, atom, to, counter, -1);
        xmlRegAtomPush(am, atom);
        am->state = to;
        if (to == NULL)
    	to = am->state;
        if (to == NULL)
    	return(NULL);
        return(to);
    }
    
    /**
     * xmlAutomataNewState:
     * @am: an automata
     *
     * Create a new disconnected state in the automata
     *
     * Returns the new state or NULL in case of error
     */
    xmlAutomataStatePtr
    xmlAutomataNewState(xmlAutomataPtr am) {
        xmlAutomataStatePtr to; 
    
        if (am == NULL)
    	return(NULL);
        to = xmlRegNewState(am);
        xmlRegStatePush(am, to);
        return(to);
    }
    
    /**
     * xmlAutomataNewEpsilon:
     * @am: an automata
     * @from: the starting point of the transition
     * @to: the target point of the transition or NULL
     *
     * If @to is NULL, this create first a new target state in the automata
     * and then adds a an epsilon transition from the @from state to the
     * target state
     *
     * Returns the target state or NULL in case of error
     */
    xmlAutomataStatePtr
    xmlAutomataNewEpsilon(xmlAutomataPtr am, xmlAutomataStatePtr from,
    		      xmlAutomataStatePtr to) {
        if ((am == NULL) || (from == NULL))
    	return(NULL);
        xmlFAGenerateEpsilonTransition(am, from, to);
        if (to == NULL)
    	return(am->state);
        return(to);
    }
    
    /**
     * xmlAutomataNewAllTrans:
     * @am: an automata
     * @from: the starting point of the transition
     * @to: the target point of the transition or NULL
     * @lax: allow to transition if not all all transitions have been activated
     *
     * If @to is NULL, this create first a new target state in the automata
     * and then adds a an ALL transition from the @from state to the
     * target state. That transition is an epsilon transition allowed only when
     * all transitions from the @from node have been activated.
     *
     * Returns the target state or NULL in case of error
     */
    xmlAutomataStatePtr
    xmlAutomataNewAllTrans(xmlAutomataPtr am, xmlAutomataStatePtr from,
    		       xmlAutomataStatePtr to, int lax) {
        if ((am == NULL) || (from == NULL))
    	return(NULL);
        xmlFAGenerateAllTransition(am, from, to, lax);
        if (to == NULL)
    	return(am->state);
        return(to);
    }
    
    /**
     * xmlAutomataNewCounter:
     * @am: an automata
     * @min:  the minimal value on the counter
     * @max:  the maximal value on the counter
     *
     * Create a new counter
     *
     * Returns the counter number or -1 in case of error
     */
    int		
    xmlAutomataNewCounter(xmlAutomataPtr am, int min, int max) {
        int ret;
    
        if (am == NULL)
    	return(-1);
    
        ret = xmlRegGetCounter(am);
        if (ret < 0)
    	return(-1);
        am->counters[ret].min = min;
        am->counters[ret].max = max;
        return(ret);
    }
    
    /**
     * xmlAutomataNewCountedTrans:
     * @am: an automata
     * @from: the starting point of the transition
     * @to: the target point of the transition or NULL
     * @counter: the counter associated to that transition
     *
     * If @to is NULL, this create first a new target state in the automata
     * and then adds an epsilon transition from the @from state to the target state
     * which will increment the counter provided
     *
     * Returns the target state or NULL in case of error
     */
    xmlAutomataStatePtr
    xmlAutomataNewCountedTrans(xmlAutomataPtr am, xmlAutomataStatePtr from,
    		xmlAutomataStatePtr to, int counter) {
        if ((am == NULL) || (from == NULL) || (counter < 0))
    	return(NULL);
        xmlFAGenerateCountedEpsilonTransition(am, from, to, counter);
        if (to == NULL)
    	return(am->state);
        return(to);
    }
    
    /**
     * xmlAutomataNewCounterTrans:
     * @am: an automata
     * @from: the starting point of the transition
     * @to: the target point of the transition or NULL
     * @counter: the counter associated to that transition
     *
     * If @to is NULL, this create first a new target state in the automata
     * and then adds an epsilon transition from the @from state to the target state
     * which will be allowed only if the counter is within the right range.
     *
     * Returns the target state or NULL in case of error
     */
    xmlAutomataStatePtr
    xmlAutomataNewCounterTrans(xmlAutomataPtr am, xmlAutomataStatePtr from,
    		xmlAutomataStatePtr to, int counter) {
        if ((am == NULL) || (from == NULL) || (counter < 0))
    	return(NULL);
        xmlFAGenerateCountedTransition(am, from, to, counter);
        if (to == NULL)
    	return(am->state);
        return(to);
    }
    
    /**
     * xmlAutomataCompile:
     * @am: an automata
     *
     * Compile the automata into a Reg Exp ready for being executed.
     * The automata should be free after this point.
     *
     * Returns the compiled regexp or NULL in case of error
     */
    xmlRegexpPtr          
    xmlAutomataCompile(xmlAutomataPtr am) {
        xmlRegexpPtr ret;
    
        xmlFAEliminateEpsilonTransitions(am);
        /* xmlFAComputesDeterminism(am); */
        ret = xmlRegEpxFromParse(am);
    
        return(ret);
    }
    
    /**
     * xmlAutomataIsDeterminist:
     * @am: an automata
     *
     * Checks if an automata is determinist.
     *
     * Returns 1 if true, 0 if not, and -1 in case of error
     */
    int          
    xmlAutomataIsDeterminist(xmlAutomataPtr am) {
        int ret;
    
        if (am == NULL)
    	return(-1);
    
        ret = xmlFAComputesDeterminism(am);
        return(ret);
    }
    #endif /* LIBXML_AUTOMATA_ENABLED */
    #endif /* LIBXML_REGEXP_ENABLED */