xmlregexp.c revision 34b350048d1ee97c4f42dd6729a77b3f36753b3a
1/*
2 * regexp.c: generic and extensible Regular Expression engine
3 *
4 * Basically designed with the purpose of compiling regexps for
5 * the variety of validation/shemas mechanisms now available in
6 * XML related specifications these include:
7 *    - XML-1.0 DTD validation
8 *    - XML Schemas structure part 1
9 *    - XML Schemas Datatypes part 2 especially Appendix F
10 *    - RELAX-NG/TREX i.e. the counter proposal
11 *
12 * See Copyright for the status of this software.
13 *
14 * Daniel Veillard <veillard@redhat.com>
15 */
16
17#define IN_LIBXML
18#include "libxml.h"
19
20#ifdef LIBXML_REGEXP_ENABLED
21
22/* #define DEBUG_ERR */
23
24#include <stdio.h>
25#include <string.h>
26#ifdef HAVE_LIMITS_H
27#include <limits.h>
28#endif
29
30#include <libxml/tree.h>
31#include <libxml/parserInternals.h>
32#include <libxml/xmlregexp.h>
33#include <libxml/xmlautomata.h>
34#include <libxml/xmlunicode.h>
35
36#ifndef INT_MAX
37#define INT_MAX 123456789 /* easy to flag and big enough for our needs */
38#endif
39
40/* #define DEBUG_REGEXP_GRAPH */
41/* #define DEBUG_REGEXP_EXEC */
42/* #define DEBUG_PUSH */
43/* #define DEBUG_COMPACTION */
44
45#define MAX_PUSH 10000000
46
47#ifdef ERROR
48#undef ERROR
49#endif
50#define ERROR(str)							\
51    ctxt->error = XML_REGEXP_COMPILE_ERROR;				\
52    xmlRegexpErrCompile(ctxt, str);
53#define NEXT ctxt->cur++
54#define CUR (*(ctxt->cur))
55#define NXT(index) (ctxt->cur[index])
56
57#define CUR_SCHAR(s, l) xmlStringCurrentChar(NULL, s, &l)
58#define NEXTL(l) ctxt->cur += l;
59#define XML_REG_STRING_SEPARATOR '|'
60/*
61 * Need PREV to check on a '-' within a Character Group. May only be used
62 * when it's guaranteed that cur is not at the beginning of ctxt->string!
63 */
64#define PREV (ctxt->cur[-1])
65
66/**
67 * TODO:
68 *
69 * macro to flag unimplemented blocks
70 */
71#define TODO								\
72    xmlGenericError(xmlGenericErrorContext,				\
73	    "Unimplemented block at %s:%d\n",				\
74            __FILE__, __LINE__);
75
76/************************************************************************
77 *									*
78 *			Datatypes and structures			*
79 *									*
80 ************************************************************************/
81
82/*
83 * Note: the order of the enums below is significant, do not shuffle
84 */
85typedef enum {
86    XML_REGEXP_EPSILON = 1,
87    XML_REGEXP_CHARVAL,
88    XML_REGEXP_RANGES,
89    XML_REGEXP_SUBREG,  /* used for () sub regexps */
90    XML_REGEXP_STRING,
91    XML_REGEXP_ANYCHAR, /* . */
92    XML_REGEXP_ANYSPACE, /* \s */
93    XML_REGEXP_NOTSPACE, /* \S */
94    XML_REGEXP_INITNAME, /* \l */
95    XML_REGEXP_NOTINITNAME, /* \L */
96    XML_REGEXP_NAMECHAR, /* \c */
97    XML_REGEXP_NOTNAMECHAR, /* \C */
98    XML_REGEXP_DECIMAL, /* \d */
99    XML_REGEXP_NOTDECIMAL, /* \D */
100    XML_REGEXP_REALCHAR, /* \w */
101    XML_REGEXP_NOTREALCHAR, /* \W */
102    XML_REGEXP_LETTER = 100,
103    XML_REGEXP_LETTER_UPPERCASE,
104    XML_REGEXP_LETTER_LOWERCASE,
105    XML_REGEXP_LETTER_TITLECASE,
106    XML_REGEXP_LETTER_MODIFIER,
107    XML_REGEXP_LETTER_OTHERS,
108    XML_REGEXP_MARK,
109    XML_REGEXP_MARK_NONSPACING,
110    XML_REGEXP_MARK_SPACECOMBINING,
111    XML_REGEXP_MARK_ENCLOSING,
112    XML_REGEXP_NUMBER,
113    XML_REGEXP_NUMBER_DECIMAL,
114    XML_REGEXP_NUMBER_LETTER,
115    XML_REGEXP_NUMBER_OTHERS,
116    XML_REGEXP_PUNCT,
117    XML_REGEXP_PUNCT_CONNECTOR,
118    XML_REGEXP_PUNCT_DASH,
119    XML_REGEXP_PUNCT_OPEN,
120    XML_REGEXP_PUNCT_CLOSE,
121    XML_REGEXP_PUNCT_INITQUOTE,
122    XML_REGEXP_PUNCT_FINQUOTE,
123    XML_REGEXP_PUNCT_OTHERS,
124    XML_REGEXP_SEPAR,
125    XML_REGEXP_SEPAR_SPACE,
126    XML_REGEXP_SEPAR_LINE,
127    XML_REGEXP_SEPAR_PARA,
128    XML_REGEXP_SYMBOL,
129    XML_REGEXP_SYMBOL_MATH,
130    XML_REGEXP_SYMBOL_CURRENCY,
131    XML_REGEXP_SYMBOL_MODIFIER,
132    XML_REGEXP_SYMBOL_OTHERS,
133    XML_REGEXP_OTHER,
134    XML_REGEXP_OTHER_CONTROL,
135    XML_REGEXP_OTHER_FORMAT,
136    XML_REGEXP_OTHER_PRIVATE,
137    XML_REGEXP_OTHER_NA,
138    XML_REGEXP_BLOCK_NAME
139} xmlRegAtomType;
140
141typedef enum {
142    XML_REGEXP_QUANT_EPSILON = 1,
143    XML_REGEXP_QUANT_ONCE,
144    XML_REGEXP_QUANT_OPT,
145    XML_REGEXP_QUANT_MULT,
146    XML_REGEXP_QUANT_PLUS,
147    XML_REGEXP_QUANT_ONCEONLY,
148    XML_REGEXP_QUANT_ALL,
149    XML_REGEXP_QUANT_RANGE
150} xmlRegQuantType;
151
152typedef enum {
153    XML_REGEXP_START_STATE = 1,
154    XML_REGEXP_FINAL_STATE,
155    XML_REGEXP_TRANS_STATE,
156    XML_REGEXP_SINK_STATE,
157    XML_REGEXP_UNREACH_STATE
158} xmlRegStateType;
159
160typedef enum {
161    XML_REGEXP_MARK_NORMAL = 0,
162    XML_REGEXP_MARK_START,
163    XML_REGEXP_MARK_VISITED
164} xmlRegMarkedType;
165
166typedef struct _xmlRegRange xmlRegRange;
167typedef xmlRegRange *xmlRegRangePtr;
168
169struct _xmlRegRange {
170    int neg;		/* 0 normal, 1 not, 2 exclude */
171    xmlRegAtomType type;
172    int start;
173    int end;
174    xmlChar *blockName;
175};
176
177typedef struct _xmlRegAtom xmlRegAtom;
178typedef xmlRegAtom *xmlRegAtomPtr;
179
180typedef struct _xmlAutomataState xmlRegState;
181typedef xmlRegState *xmlRegStatePtr;
182
183struct _xmlRegAtom {
184    int no;
185    xmlRegAtomType type;
186    xmlRegQuantType quant;
187    int min;
188    int max;
189
190    void *valuep;
191    void *valuep2;
192    int neg;
193    int codepoint;
194    xmlRegStatePtr start;
195    xmlRegStatePtr start0;
196    xmlRegStatePtr stop;
197    int maxRanges;
198    int nbRanges;
199    xmlRegRangePtr *ranges;
200    void *data;
201};
202
203typedef struct _xmlRegCounter xmlRegCounter;
204typedef xmlRegCounter *xmlRegCounterPtr;
205
206struct _xmlRegCounter {
207    int min;
208    int max;
209};
210
211typedef struct _xmlRegTrans xmlRegTrans;
212typedef xmlRegTrans *xmlRegTransPtr;
213
214struct _xmlRegTrans {
215    xmlRegAtomPtr atom;
216    int to;
217    int counter;
218    int count;
219    int nd;
220};
221
222struct _xmlAutomataState {
223    xmlRegStateType type;
224    xmlRegMarkedType mark;
225    xmlRegMarkedType markd;
226    xmlRegMarkedType reached;
227    int no;
228    int maxTrans;
229    int nbTrans;
230    xmlRegTrans *trans;
231    /*  knowing states ponting to us can speed things up */
232    int maxTransTo;
233    int nbTransTo;
234    int *transTo;
235};
236
237typedef struct _xmlAutomata xmlRegParserCtxt;
238typedef xmlRegParserCtxt *xmlRegParserCtxtPtr;
239
240#define AM_AUTOMATA_RNG 1
241
242struct _xmlAutomata {
243    xmlChar *string;
244    xmlChar *cur;
245
246    int error;
247    int neg;
248
249    xmlRegStatePtr start;
250    xmlRegStatePtr end;
251    xmlRegStatePtr state;
252
253    xmlRegAtomPtr atom;
254
255    int maxAtoms;
256    int nbAtoms;
257    xmlRegAtomPtr *atoms;
258
259    int maxStates;
260    int nbStates;
261    xmlRegStatePtr *states;
262
263    int maxCounters;
264    int nbCounters;
265    xmlRegCounter *counters;
266
267    int determinist;
268    int negs;
269    int flags;
270};
271
272struct _xmlRegexp {
273    xmlChar *string;
274    int nbStates;
275    xmlRegStatePtr *states;
276    int nbAtoms;
277    xmlRegAtomPtr *atoms;
278    int nbCounters;
279    xmlRegCounter *counters;
280    int determinist;
281    int flags;
282    /*
283     * That's the compact form for determinists automatas
284     */
285    int nbstates;
286    int *compact;
287    void **transdata;
288    int nbstrings;
289    xmlChar **stringMap;
290};
291
292typedef struct _xmlRegExecRollback xmlRegExecRollback;
293typedef xmlRegExecRollback *xmlRegExecRollbackPtr;
294
295struct _xmlRegExecRollback {
296    xmlRegStatePtr state;/* the current state */
297    int index;		/* the index in the input stack */
298    int nextbranch;	/* the next transition to explore in that state */
299    int *counts;	/* save the automata state if it has some */
300};
301
302typedef struct _xmlRegInputToken xmlRegInputToken;
303typedef xmlRegInputToken *xmlRegInputTokenPtr;
304
305struct _xmlRegInputToken {
306    xmlChar *value;
307    void *data;
308};
309
310struct _xmlRegExecCtxt {
311    int status;		/* execution status != 0 indicate an error */
312    int determinist;	/* did we find an indeterministic behaviour */
313    xmlRegexpPtr comp;	/* the compiled regexp */
314    xmlRegExecCallbacks callback;
315    void *data;
316
317    xmlRegStatePtr state;/* the current state */
318    int transno;	/* the current transition on that state */
319    int transcount;	/* the number of chars in char counted transitions */
320
321    /*
322     * A stack of rollback states
323     */
324    int maxRollbacks;
325    int nbRollbacks;
326    xmlRegExecRollback *rollbacks;
327
328    /*
329     * The state of the automata if any
330     */
331    int *counts;
332
333    /*
334     * The input stack
335     */
336    int inputStackMax;
337    int inputStackNr;
338    int index;
339    int *charStack;
340    const xmlChar *inputString; /* when operating on characters */
341    xmlRegInputTokenPtr inputStack;/* when operating on strings */
342
343    /*
344     * error handling
345     */
346    int errStateNo;		/* the error state number */
347    xmlRegStatePtr errState;    /* the error state */
348    xmlChar *errString;		/* the string raising the error */
349    int *errCounts;		/* counters at the error state */
350    int nbPush;
351};
352
353#define REGEXP_ALL_COUNTER	0x123456
354#define REGEXP_ALL_LAX_COUNTER	0x123457
355
356static void xmlFAParseRegExp(xmlRegParserCtxtPtr ctxt, int top);
357static void xmlRegFreeState(xmlRegStatePtr state);
358static void xmlRegFreeAtom(xmlRegAtomPtr atom);
359static int xmlRegStrEqualWildcard(const xmlChar *expStr, const xmlChar *valStr);
360static int xmlRegCheckCharacter(xmlRegAtomPtr atom, int codepoint);
361static int xmlRegCheckCharacterRange(xmlRegAtomType type, int codepoint,
362                  int neg, int start, int end, const xmlChar *blockName);
363
364void xmlAutomataSetFlags(xmlAutomataPtr am, int flags);
365
366/************************************************************************
367 *									*
368 *		Regexp memory error handler				*
369 *									*
370 ************************************************************************/
371/**
372 * xmlRegexpErrMemory:
373 * @extra:  extra information
374 *
375 * Handle an out of memory condition
376 */
377static void
378xmlRegexpErrMemory(xmlRegParserCtxtPtr ctxt, const char *extra)
379{
380    const char *regexp = NULL;
381    if (ctxt != NULL) {
382        regexp = (const char *) ctxt->string;
383	ctxt->error = XML_ERR_NO_MEMORY;
384    }
385    __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_REGEXP,
386		    XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, extra,
387		    regexp, NULL, 0, 0,
388		    "Memory allocation failed : %s\n", extra);
389}
390
391/**
392 * xmlRegexpErrCompile:
393 * @extra:  extra information
394 *
395 * Handle a compilation failure
396 */
397static void
398xmlRegexpErrCompile(xmlRegParserCtxtPtr ctxt, const char *extra)
399{
400    const char *regexp = NULL;
401    int idx = 0;
402
403    if (ctxt != NULL) {
404        regexp = (const char *) ctxt->string;
405	idx = ctxt->cur - ctxt->string;
406	ctxt->error = XML_REGEXP_COMPILE_ERROR;
407    }
408    __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_REGEXP,
409		    XML_REGEXP_COMPILE_ERROR, XML_ERR_FATAL, NULL, 0, extra,
410		    regexp, NULL, idx, 0,
411		    "failed to compile: %s\n", extra);
412}
413
414/************************************************************************
415 *									*
416 *			Allocation/Deallocation				*
417 *									*
418 ************************************************************************/
419
420static int xmlFAComputesDeterminism(xmlRegParserCtxtPtr ctxt);
421/**
422 * xmlRegEpxFromParse:
423 * @ctxt:  the parser context used to build it
424 *
425 * Allocate a new regexp and fill it with the result from the parser
426 *
427 * Returns the new regexp or NULL in case of error
428 */
429static xmlRegexpPtr
430xmlRegEpxFromParse(xmlRegParserCtxtPtr ctxt) {
431    xmlRegexpPtr ret;
432
433    ret = (xmlRegexpPtr) xmlMalloc(sizeof(xmlRegexp));
434    if (ret == NULL) {
435	xmlRegexpErrMemory(ctxt, "compiling regexp");
436	return(NULL);
437    }
438    memset(ret, 0, sizeof(xmlRegexp));
439    ret->string = ctxt->string;
440    ret->nbStates = ctxt->nbStates;
441    ret->states = ctxt->states;
442    ret->nbAtoms = ctxt->nbAtoms;
443    ret->atoms = ctxt->atoms;
444    ret->nbCounters = ctxt->nbCounters;
445    ret->counters = ctxt->counters;
446    ret->determinist = ctxt->determinist;
447    ret->flags = ctxt->flags;
448    if (ret->determinist == -1) {
449        xmlRegexpIsDeterminist(ret);
450    }
451
452    if ((ret->determinist != 0) &&
453	(ret->nbCounters == 0) &&
454	(ctxt->negs == 0) &&
455	(ret->atoms != NULL) &&
456	(ret->atoms[0] != NULL) &&
457	(ret->atoms[0]->type == XML_REGEXP_STRING)) {
458	int i, j, nbstates = 0, nbatoms = 0;
459	int *stateRemap;
460	int *stringRemap;
461	int *transitions;
462	void **transdata;
463	xmlChar **stringMap;
464        xmlChar *value;
465
466	/*
467	 * Switch to a compact representation
468	 * 1/ counting the effective number of states left
469	 * 2/ counting the unique number of atoms, and check that
470	 *    they are all of the string type
471	 * 3/ build a table state x atom for the transitions
472	 */
473
474	stateRemap = xmlMalloc(ret->nbStates * sizeof(int));
475	if (stateRemap == NULL) {
476	    xmlRegexpErrMemory(ctxt, "compiling regexp");
477	    xmlFree(ret);
478	    return(NULL);
479	}
480	for (i = 0;i < ret->nbStates;i++) {
481	    if (ret->states[i] != NULL) {
482		stateRemap[i] = nbstates;
483		nbstates++;
484	    } else {
485		stateRemap[i] = -1;
486	    }
487	}
488#ifdef DEBUG_COMPACTION
489	printf("Final: %d states\n", nbstates);
490#endif
491	stringMap = xmlMalloc(ret->nbAtoms * sizeof(char *));
492	if (stringMap == NULL) {
493	    xmlRegexpErrMemory(ctxt, "compiling regexp");
494	    xmlFree(stateRemap);
495	    xmlFree(ret);
496	    return(NULL);
497	}
498	stringRemap = xmlMalloc(ret->nbAtoms * sizeof(int));
499	if (stringRemap == NULL) {
500	    xmlRegexpErrMemory(ctxt, "compiling regexp");
501	    xmlFree(stringMap);
502	    xmlFree(stateRemap);
503	    xmlFree(ret);
504	    return(NULL);
505	}
506	for (i = 0;i < ret->nbAtoms;i++) {
507	    if ((ret->atoms[i]->type == XML_REGEXP_STRING) &&
508		(ret->atoms[i]->quant == XML_REGEXP_QUANT_ONCE)) {
509		value = ret->atoms[i]->valuep;
510                for (j = 0;j < nbatoms;j++) {
511		    if (xmlStrEqual(stringMap[j], value)) {
512			stringRemap[i] = j;
513			break;
514		    }
515		}
516		if (j >= nbatoms) {
517		    stringRemap[i] = nbatoms;
518		    stringMap[nbatoms] = xmlStrdup(value);
519		    if (stringMap[nbatoms] == NULL) {
520			for (i = 0;i < nbatoms;i++)
521			    xmlFree(stringMap[i]);
522			xmlFree(stringRemap);
523			xmlFree(stringMap);
524			xmlFree(stateRemap);
525			xmlFree(ret);
526			return(NULL);
527		    }
528		    nbatoms++;
529		}
530	    } else {
531		xmlFree(stateRemap);
532		xmlFree(stringRemap);
533		for (i = 0;i < nbatoms;i++)
534		    xmlFree(stringMap[i]);
535		xmlFree(stringMap);
536		xmlFree(ret);
537		return(NULL);
538	    }
539	}
540#ifdef DEBUG_COMPACTION
541	printf("Final: %d atoms\n", nbatoms);
542#endif
543	transitions = (int *) xmlMalloc((nbstates + 1) *
544	                                (nbatoms + 1) * sizeof(int));
545	if (transitions == NULL) {
546	    xmlFree(stateRemap);
547	    xmlFree(stringRemap);
548	    xmlFree(stringMap);
549	    xmlFree(ret);
550	    return(NULL);
551	}
552	memset(transitions, 0, (nbstates + 1) * (nbatoms + 1) * sizeof(int));
553
554	/*
555	 * Allocate the transition table. The first entry for each
556	 * state corresponds to the state type.
557	 */
558	transdata = NULL;
559
560	for (i = 0;i < ret->nbStates;i++) {
561	    int stateno, atomno, targetno, prev;
562	    xmlRegStatePtr state;
563	    xmlRegTransPtr trans;
564
565	    stateno = stateRemap[i];
566	    if (stateno == -1)
567		continue;
568	    state = ret->states[i];
569
570	    transitions[stateno * (nbatoms + 1)] = state->type;
571
572	    for (j = 0;j < state->nbTrans;j++) {
573		trans = &(state->trans[j]);
574		if ((trans->to == -1) || (trans->atom == NULL))
575		    continue;
576                atomno = stringRemap[trans->atom->no];
577		if ((trans->atom->data != NULL) && (transdata == NULL)) {
578		    transdata = (void **) xmlMalloc(nbstates * nbatoms *
579			                            sizeof(void *));
580		    if (transdata != NULL)
581			memset(transdata, 0,
582			       nbstates * nbatoms * sizeof(void *));
583		    else {
584			xmlRegexpErrMemory(ctxt, "compiling regexp");
585			break;
586		    }
587		}
588		targetno = stateRemap[trans->to];
589		/*
590		 * if the same atom can generate transitions to 2 different
591		 * states then it means the automata is not determinist and
592		 * the compact form can't be used !
593		 */
594		prev = transitions[stateno * (nbatoms + 1) + atomno + 1];
595		if (prev != 0) {
596		    if (prev != targetno + 1) {
597			ret->determinist = 0;
598#ifdef DEBUG_COMPACTION
599			printf("Indet: state %d trans %d, atom %d to %d : %d to %d\n",
600			       i, j, trans->atom->no, trans->to, atomno, targetno);
601			printf("       previous to is %d\n", prev);
602#endif
603			if (transdata != NULL)
604			    xmlFree(transdata);
605			xmlFree(transitions);
606			xmlFree(stateRemap);
607			xmlFree(stringRemap);
608			for (i = 0;i < nbatoms;i++)
609			    xmlFree(stringMap[i]);
610			xmlFree(stringMap);
611			goto not_determ;
612		    }
613		} else {
614#if 0
615		    printf("State %d trans %d: atom %d to %d : %d to %d\n",
616			   i, j, trans->atom->no, trans->to, atomno, targetno);
617#endif
618		    transitions[stateno * (nbatoms + 1) + atomno + 1] =
619			targetno + 1; /* to avoid 0 */
620		    if (transdata != NULL)
621			transdata[stateno * nbatoms + atomno] =
622			    trans->atom->data;
623		}
624	    }
625	}
626	ret->determinist = 1;
627#ifdef DEBUG_COMPACTION
628	/*
629	 * Debug
630	 */
631	for (i = 0;i < nbstates;i++) {
632	    for (j = 0;j < nbatoms + 1;j++) {
633                printf("%02d ", transitions[i * (nbatoms + 1) + j]);
634	    }
635	    printf("\n");
636	}
637	printf("\n");
638#endif
639	/*
640	 * Cleanup of the old data
641	 */
642	if (ret->states != NULL) {
643	    for (i = 0;i < ret->nbStates;i++)
644		xmlRegFreeState(ret->states[i]);
645	    xmlFree(ret->states);
646	}
647	ret->states = NULL;
648	ret->nbStates = 0;
649	if (ret->atoms != NULL) {
650	    for (i = 0;i < ret->nbAtoms;i++)
651		xmlRegFreeAtom(ret->atoms[i]);
652	    xmlFree(ret->atoms);
653	}
654	ret->atoms = NULL;
655	ret->nbAtoms = 0;
656
657	ret->compact = transitions;
658	ret->transdata = transdata;
659	ret->stringMap = stringMap;
660	ret->nbstrings = nbatoms;
661	ret->nbstates = nbstates;
662	xmlFree(stateRemap);
663	xmlFree(stringRemap);
664    }
665not_determ:
666    ctxt->string = NULL;
667    ctxt->nbStates = 0;
668    ctxt->states = NULL;
669    ctxt->nbAtoms = 0;
670    ctxt->atoms = NULL;
671    ctxt->nbCounters = 0;
672    ctxt->counters = NULL;
673    return(ret);
674}
675
676/**
677 * xmlRegNewParserCtxt:
678 * @string:  the string to parse
679 *
680 * Allocate a new regexp parser context
681 *
682 * Returns the new context or NULL in case of error
683 */
684static xmlRegParserCtxtPtr
685xmlRegNewParserCtxt(const xmlChar *string) {
686    xmlRegParserCtxtPtr ret;
687
688    ret = (xmlRegParserCtxtPtr) xmlMalloc(sizeof(xmlRegParserCtxt));
689    if (ret == NULL)
690	return(NULL);
691    memset(ret, 0, sizeof(xmlRegParserCtxt));
692    if (string != NULL)
693	ret->string = xmlStrdup(string);
694    ret->cur = ret->string;
695    ret->neg = 0;
696    ret->negs = 0;
697    ret->error = 0;
698    ret->determinist = -1;
699    return(ret);
700}
701
702/**
703 * xmlRegNewRange:
704 * @ctxt:  the regexp parser context
705 * @neg:  is that negative
706 * @type:  the type of range
707 * @start:  the start codepoint
708 * @end:  the end codepoint
709 *
710 * Allocate a new regexp range
711 *
712 * Returns the new range or NULL in case of error
713 */
714static xmlRegRangePtr
715xmlRegNewRange(xmlRegParserCtxtPtr ctxt,
716	       int neg, xmlRegAtomType type, int start, int end) {
717    xmlRegRangePtr ret;
718
719    ret = (xmlRegRangePtr) xmlMalloc(sizeof(xmlRegRange));
720    if (ret == NULL) {
721	xmlRegexpErrMemory(ctxt, "allocating range");
722	return(NULL);
723    }
724    ret->neg = neg;
725    ret->type = type;
726    ret->start = start;
727    ret->end = end;
728    return(ret);
729}
730
731/**
732 * xmlRegFreeRange:
733 * @range:  the regexp range
734 *
735 * Free a regexp range
736 */
737static void
738xmlRegFreeRange(xmlRegRangePtr range) {
739    if (range == NULL)
740	return;
741
742    if (range->blockName != NULL)
743	xmlFree(range->blockName);
744    xmlFree(range);
745}
746
747/**
748 * xmlRegCopyRange:
749 * @range:  the regexp range
750 *
751 * Copy a regexp range
752 *
753 * Returns the new copy or NULL in case of error.
754 */
755static xmlRegRangePtr
756xmlRegCopyRange(xmlRegParserCtxtPtr ctxt, xmlRegRangePtr range) {
757    xmlRegRangePtr ret;
758
759    if (range == NULL)
760	return(NULL);
761
762    ret = xmlRegNewRange(ctxt, range->neg, range->type, range->start,
763                         range->end);
764    if (ret == NULL)
765        return(NULL);
766    if (range->blockName != NULL) {
767	ret->blockName = xmlStrdup(range->blockName);
768	if (ret->blockName == NULL) {
769	    xmlRegexpErrMemory(ctxt, "allocating range");
770	    xmlRegFreeRange(ret);
771	    return(NULL);
772	}
773    }
774    return(ret);
775}
776
777/**
778 * xmlRegNewAtom:
779 * @ctxt:  the regexp parser context
780 * @type:  the type of atom
781 *
782 * Allocate a new atom
783 *
784 * Returns the new atom or NULL in case of error
785 */
786static xmlRegAtomPtr
787xmlRegNewAtom(xmlRegParserCtxtPtr ctxt, xmlRegAtomType type) {
788    xmlRegAtomPtr ret;
789
790    ret = (xmlRegAtomPtr) xmlMalloc(sizeof(xmlRegAtom));
791    if (ret == NULL) {
792	xmlRegexpErrMemory(ctxt, "allocating atom");
793	return(NULL);
794    }
795    memset(ret, 0, sizeof(xmlRegAtom));
796    ret->type = type;
797    ret->quant = XML_REGEXP_QUANT_ONCE;
798    ret->min = 0;
799    ret->max = 0;
800    return(ret);
801}
802
803/**
804 * xmlRegFreeAtom:
805 * @atom:  the regexp atom
806 *
807 * Free a regexp atom
808 */
809static void
810xmlRegFreeAtom(xmlRegAtomPtr atom) {
811    int i;
812
813    if (atom == NULL)
814	return;
815
816    for (i = 0;i < atom->nbRanges;i++)
817	xmlRegFreeRange(atom->ranges[i]);
818    if (atom->ranges != NULL)
819	xmlFree(atom->ranges);
820    if ((atom->type == XML_REGEXP_STRING) && (atom->valuep != NULL))
821	xmlFree(atom->valuep);
822    if ((atom->type == XML_REGEXP_STRING) && (atom->valuep2 != NULL))
823	xmlFree(atom->valuep2);
824    if ((atom->type == XML_REGEXP_BLOCK_NAME) && (atom->valuep != NULL))
825	xmlFree(atom->valuep);
826    xmlFree(atom);
827}
828
829/**
830 * xmlRegCopyAtom:
831 * @ctxt:  the regexp parser context
832 * @atom:  the oiginal atom
833 *
834 * Allocate a new regexp range
835 *
836 * Returns the new atom or NULL in case of error
837 */
838static xmlRegAtomPtr
839xmlRegCopyAtom(xmlRegParserCtxtPtr ctxt, xmlRegAtomPtr atom) {
840    xmlRegAtomPtr ret;
841
842    ret = (xmlRegAtomPtr) xmlMalloc(sizeof(xmlRegAtom));
843    if (ret == NULL) {
844	xmlRegexpErrMemory(ctxt, "copying atom");
845	return(NULL);
846    }
847    memset(ret, 0, sizeof(xmlRegAtom));
848    ret->type = atom->type;
849    ret->quant = atom->quant;
850    ret->min = atom->min;
851    ret->max = atom->max;
852    if (atom->nbRanges > 0) {
853        int i;
854
855        ret->ranges = (xmlRegRangePtr *) xmlMalloc(sizeof(xmlRegRangePtr) *
856	                                           atom->nbRanges);
857	if (ret->ranges == NULL) {
858	    xmlRegexpErrMemory(ctxt, "copying atom");
859	    goto error;
860	}
861	for (i = 0;i < atom->nbRanges;i++) {
862	    ret->ranges[i] = xmlRegCopyRange(ctxt, atom->ranges[i]);
863	    if (ret->ranges[i] == NULL)
864	        goto error;
865	    ret->nbRanges = i + 1;
866	}
867    }
868    return(ret);
869
870error:
871    xmlRegFreeAtom(ret);
872    return(NULL);
873}
874
875static xmlRegStatePtr
876xmlRegNewState(xmlRegParserCtxtPtr ctxt) {
877    xmlRegStatePtr ret;
878
879    ret = (xmlRegStatePtr) xmlMalloc(sizeof(xmlRegState));
880    if (ret == NULL) {
881	xmlRegexpErrMemory(ctxt, "allocating state");
882	return(NULL);
883    }
884    memset(ret, 0, sizeof(xmlRegState));
885    ret->type = XML_REGEXP_TRANS_STATE;
886    ret->mark = XML_REGEXP_MARK_NORMAL;
887    return(ret);
888}
889
890/**
891 * xmlRegFreeState:
892 * @state:  the regexp state
893 *
894 * Free a regexp state
895 */
896static void
897xmlRegFreeState(xmlRegStatePtr state) {
898    if (state == NULL)
899	return;
900
901    if (state->trans != NULL)
902	xmlFree(state->trans);
903    if (state->transTo != NULL)
904	xmlFree(state->transTo);
905    xmlFree(state);
906}
907
908/**
909 * xmlRegFreeParserCtxt:
910 * @ctxt:  the regexp parser context
911 *
912 * Free a regexp parser context
913 */
914static void
915xmlRegFreeParserCtxt(xmlRegParserCtxtPtr ctxt) {
916    int i;
917    if (ctxt == NULL)
918	return;
919
920    if (ctxt->string != NULL)
921	xmlFree(ctxt->string);
922    if (ctxt->states != NULL) {
923	for (i = 0;i < ctxt->nbStates;i++)
924	    xmlRegFreeState(ctxt->states[i]);
925	xmlFree(ctxt->states);
926    }
927    if (ctxt->atoms != NULL) {
928	for (i = 0;i < ctxt->nbAtoms;i++)
929	    xmlRegFreeAtom(ctxt->atoms[i]);
930	xmlFree(ctxt->atoms);
931    }
932    if (ctxt->counters != NULL)
933	xmlFree(ctxt->counters);
934    xmlFree(ctxt);
935}
936
937/************************************************************************
938 *									*
939 *			Display of Data structures			*
940 *									*
941 ************************************************************************/
942
943static void
944xmlRegPrintAtomType(FILE *output, xmlRegAtomType type) {
945    switch (type) {
946        case XML_REGEXP_EPSILON:
947	    fprintf(output, "epsilon "); break;
948        case XML_REGEXP_CHARVAL:
949	    fprintf(output, "charval "); break;
950        case XML_REGEXP_RANGES:
951	    fprintf(output, "ranges "); break;
952        case XML_REGEXP_SUBREG:
953	    fprintf(output, "subexpr "); break;
954        case XML_REGEXP_STRING:
955	    fprintf(output, "string "); break;
956        case XML_REGEXP_ANYCHAR:
957	    fprintf(output, "anychar "); break;
958        case XML_REGEXP_ANYSPACE:
959	    fprintf(output, "anyspace "); break;
960        case XML_REGEXP_NOTSPACE:
961	    fprintf(output, "notspace "); break;
962        case XML_REGEXP_INITNAME:
963	    fprintf(output, "initname "); break;
964        case XML_REGEXP_NOTINITNAME:
965	    fprintf(output, "notinitname "); break;
966        case XML_REGEXP_NAMECHAR:
967	    fprintf(output, "namechar "); break;
968        case XML_REGEXP_NOTNAMECHAR:
969	    fprintf(output, "notnamechar "); break;
970        case XML_REGEXP_DECIMAL:
971	    fprintf(output, "decimal "); break;
972        case XML_REGEXP_NOTDECIMAL:
973	    fprintf(output, "notdecimal "); break;
974        case XML_REGEXP_REALCHAR:
975	    fprintf(output, "realchar "); break;
976        case XML_REGEXP_NOTREALCHAR:
977	    fprintf(output, "notrealchar "); break;
978        case XML_REGEXP_LETTER:
979            fprintf(output, "LETTER "); break;
980        case XML_REGEXP_LETTER_UPPERCASE:
981            fprintf(output, "LETTER_UPPERCASE "); break;
982        case XML_REGEXP_LETTER_LOWERCASE:
983            fprintf(output, "LETTER_LOWERCASE "); break;
984        case XML_REGEXP_LETTER_TITLECASE:
985            fprintf(output, "LETTER_TITLECASE "); break;
986        case XML_REGEXP_LETTER_MODIFIER:
987            fprintf(output, "LETTER_MODIFIER "); break;
988        case XML_REGEXP_LETTER_OTHERS:
989            fprintf(output, "LETTER_OTHERS "); break;
990        case XML_REGEXP_MARK:
991            fprintf(output, "MARK "); break;
992        case XML_REGEXP_MARK_NONSPACING:
993            fprintf(output, "MARK_NONSPACING "); break;
994        case XML_REGEXP_MARK_SPACECOMBINING:
995            fprintf(output, "MARK_SPACECOMBINING "); break;
996        case XML_REGEXP_MARK_ENCLOSING:
997            fprintf(output, "MARK_ENCLOSING "); break;
998        case XML_REGEXP_NUMBER:
999            fprintf(output, "NUMBER "); break;
1000        case XML_REGEXP_NUMBER_DECIMAL:
1001            fprintf(output, "NUMBER_DECIMAL "); break;
1002        case XML_REGEXP_NUMBER_LETTER:
1003            fprintf(output, "NUMBER_LETTER "); break;
1004        case XML_REGEXP_NUMBER_OTHERS:
1005            fprintf(output, "NUMBER_OTHERS "); break;
1006        case XML_REGEXP_PUNCT:
1007            fprintf(output, "PUNCT "); break;
1008        case XML_REGEXP_PUNCT_CONNECTOR:
1009            fprintf(output, "PUNCT_CONNECTOR "); break;
1010        case XML_REGEXP_PUNCT_DASH:
1011            fprintf(output, "PUNCT_DASH "); break;
1012        case XML_REGEXP_PUNCT_OPEN:
1013            fprintf(output, "PUNCT_OPEN "); break;
1014        case XML_REGEXP_PUNCT_CLOSE:
1015            fprintf(output, "PUNCT_CLOSE "); break;
1016        case XML_REGEXP_PUNCT_INITQUOTE:
1017            fprintf(output, "PUNCT_INITQUOTE "); break;
1018        case XML_REGEXP_PUNCT_FINQUOTE:
1019            fprintf(output, "PUNCT_FINQUOTE "); break;
1020        case XML_REGEXP_PUNCT_OTHERS:
1021            fprintf(output, "PUNCT_OTHERS "); break;
1022        case XML_REGEXP_SEPAR:
1023            fprintf(output, "SEPAR "); break;
1024        case XML_REGEXP_SEPAR_SPACE:
1025            fprintf(output, "SEPAR_SPACE "); break;
1026        case XML_REGEXP_SEPAR_LINE:
1027            fprintf(output, "SEPAR_LINE "); break;
1028        case XML_REGEXP_SEPAR_PARA:
1029            fprintf(output, "SEPAR_PARA "); break;
1030        case XML_REGEXP_SYMBOL:
1031            fprintf(output, "SYMBOL "); break;
1032        case XML_REGEXP_SYMBOL_MATH:
1033            fprintf(output, "SYMBOL_MATH "); break;
1034        case XML_REGEXP_SYMBOL_CURRENCY:
1035            fprintf(output, "SYMBOL_CURRENCY "); break;
1036        case XML_REGEXP_SYMBOL_MODIFIER:
1037            fprintf(output, "SYMBOL_MODIFIER "); break;
1038        case XML_REGEXP_SYMBOL_OTHERS:
1039            fprintf(output, "SYMBOL_OTHERS "); break;
1040        case XML_REGEXP_OTHER:
1041            fprintf(output, "OTHER "); break;
1042        case XML_REGEXP_OTHER_CONTROL:
1043            fprintf(output, "OTHER_CONTROL "); break;
1044        case XML_REGEXP_OTHER_FORMAT:
1045            fprintf(output, "OTHER_FORMAT "); break;
1046        case XML_REGEXP_OTHER_PRIVATE:
1047            fprintf(output, "OTHER_PRIVATE "); break;
1048        case XML_REGEXP_OTHER_NA:
1049            fprintf(output, "OTHER_NA "); break;
1050        case XML_REGEXP_BLOCK_NAME:
1051	    fprintf(output, "BLOCK "); break;
1052    }
1053}
1054
1055static void
1056xmlRegPrintQuantType(FILE *output, xmlRegQuantType type) {
1057    switch (type) {
1058        case XML_REGEXP_QUANT_EPSILON:
1059	    fprintf(output, "epsilon "); break;
1060        case XML_REGEXP_QUANT_ONCE:
1061	    fprintf(output, "once "); break;
1062        case XML_REGEXP_QUANT_OPT:
1063	    fprintf(output, "? "); break;
1064        case XML_REGEXP_QUANT_MULT:
1065	    fprintf(output, "* "); break;
1066        case XML_REGEXP_QUANT_PLUS:
1067	    fprintf(output, "+ "); break;
1068	case XML_REGEXP_QUANT_RANGE:
1069	    fprintf(output, "range "); break;
1070	case XML_REGEXP_QUANT_ONCEONLY:
1071	    fprintf(output, "onceonly "); break;
1072	case XML_REGEXP_QUANT_ALL:
1073	    fprintf(output, "all "); break;
1074    }
1075}
1076static void
1077xmlRegPrintRange(FILE *output, xmlRegRangePtr range) {
1078    fprintf(output, "  range: ");
1079    if (range->neg)
1080	fprintf(output, "negative ");
1081    xmlRegPrintAtomType(output, range->type);
1082    fprintf(output, "%c - %c\n", range->start, range->end);
1083}
1084
1085static void
1086xmlRegPrintAtom(FILE *output, xmlRegAtomPtr atom) {
1087    fprintf(output, " atom: ");
1088    if (atom == NULL) {
1089	fprintf(output, "NULL\n");
1090	return;
1091    }
1092    if (atom->neg)
1093        fprintf(output, "not ");
1094    xmlRegPrintAtomType(output, atom->type);
1095    xmlRegPrintQuantType(output, atom->quant);
1096    if (atom->quant == XML_REGEXP_QUANT_RANGE)
1097	fprintf(output, "%d-%d ", atom->min, atom->max);
1098    if (atom->type == XML_REGEXP_STRING)
1099	fprintf(output, "'%s' ", (char *) atom->valuep);
1100    if (atom->type == XML_REGEXP_CHARVAL)
1101	fprintf(output, "char %c\n", atom->codepoint);
1102    else if (atom->type == XML_REGEXP_RANGES) {
1103	int i;
1104	fprintf(output, "%d entries\n", atom->nbRanges);
1105	for (i = 0; i < atom->nbRanges;i++)
1106	    xmlRegPrintRange(output, atom->ranges[i]);
1107    } else if (atom->type == XML_REGEXP_SUBREG) {
1108	fprintf(output, "start %d end %d\n", atom->start->no, atom->stop->no);
1109    } else {
1110	fprintf(output, "\n");
1111    }
1112}
1113
1114static void
1115xmlRegPrintTrans(FILE *output, xmlRegTransPtr trans) {
1116    fprintf(output, "  trans: ");
1117    if (trans == NULL) {
1118	fprintf(output, "NULL\n");
1119	return;
1120    }
1121    if (trans->to < 0) {
1122	fprintf(output, "removed\n");
1123	return;
1124    }
1125    if (trans->nd != 0) {
1126	if (trans->nd == 2)
1127	    fprintf(output, "last not determinist, ");
1128	else
1129	    fprintf(output, "not determinist, ");
1130    }
1131    if (trans->counter >= 0) {
1132	fprintf(output, "counted %d, ", trans->counter);
1133    }
1134    if (trans->count == REGEXP_ALL_COUNTER) {
1135	fprintf(output, "all transition, ");
1136    } else if (trans->count >= 0) {
1137	fprintf(output, "count based %d, ", trans->count);
1138    }
1139    if (trans->atom == NULL) {
1140	fprintf(output, "epsilon to %d\n", trans->to);
1141	return;
1142    }
1143    if (trans->atom->type == XML_REGEXP_CHARVAL)
1144	fprintf(output, "char %c ", trans->atom->codepoint);
1145    fprintf(output, "atom %d, to %d\n", trans->atom->no, trans->to);
1146}
1147
1148static void
1149xmlRegPrintState(FILE *output, xmlRegStatePtr state) {
1150    int i;
1151
1152    fprintf(output, " state: ");
1153    if (state == NULL) {
1154	fprintf(output, "NULL\n");
1155	return;
1156    }
1157    if (state->type == XML_REGEXP_START_STATE)
1158	fprintf(output, "START ");
1159    if (state->type == XML_REGEXP_FINAL_STATE)
1160	fprintf(output, "FINAL ");
1161
1162    fprintf(output, "%d, %d transitions:\n", state->no, state->nbTrans);
1163    for (i = 0;i < state->nbTrans; i++) {
1164	xmlRegPrintTrans(output, &(state->trans[i]));
1165    }
1166}
1167
1168#ifdef DEBUG_REGEXP_GRAPH
1169static void
1170xmlRegPrintCtxt(FILE *output, xmlRegParserCtxtPtr ctxt) {
1171    int i;
1172
1173    fprintf(output, " ctxt: ");
1174    if (ctxt == NULL) {
1175	fprintf(output, "NULL\n");
1176	return;
1177    }
1178    fprintf(output, "'%s' ", ctxt->string);
1179    if (ctxt->error)
1180	fprintf(output, "error ");
1181    if (ctxt->neg)
1182	fprintf(output, "neg ");
1183    fprintf(output, "\n");
1184    fprintf(output, "%d atoms:\n", ctxt->nbAtoms);
1185    for (i = 0;i < ctxt->nbAtoms; i++) {
1186	fprintf(output, " %02d ", i);
1187	xmlRegPrintAtom(output, ctxt->atoms[i]);
1188    }
1189    if (ctxt->atom != NULL) {
1190	fprintf(output, "current atom:\n");
1191	xmlRegPrintAtom(output, ctxt->atom);
1192    }
1193    fprintf(output, "%d states:", ctxt->nbStates);
1194    if (ctxt->start != NULL)
1195	fprintf(output, " start: %d", ctxt->start->no);
1196    if (ctxt->end != NULL)
1197	fprintf(output, " end: %d", ctxt->end->no);
1198    fprintf(output, "\n");
1199    for (i = 0;i < ctxt->nbStates; i++) {
1200	xmlRegPrintState(output, ctxt->states[i]);
1201    }
1202    fprintf(output, "%d counters:\n", ctxt->nbCounters);
1203    for (i = 0;i < ctxt->nbCounters; i++) {
1204	fprintf(output, " %d: min %d max %d\n", i, ctxt->counters[i].min,
1205		                                ctxt->counters[i].max);
1206    }
1207}
1208#endif
1209
1210/************************************************************************
1211 *									*
1212 *		 Finite Automata structures manipulations		*
1213 *									*
1214 ************************************************************************/
1215
1216static void
1217xmlRegAtomAddRange(xmlRegParserCtxtPtr ctxt, xmlRegAtomPtr atom,
1218	           int neg, xmlRegAtomType type, int start, int end,
1219		   xmlChar *blockName) {
1220    xmlRegRangePtr range;
1221
1222    if (atom == NULL) {
1223	ERROR("add range: atom is NULL");
1224	return;
1225    }
1226    if (atom->type != XML_REGEXP_RANGES) {
1227	ERROR("add range: atom is not ranges");
1228	return;
1229    }
1230    if (atom->maxRanges == 0) {
1231	atom->maxRanges = 4;
1232	atom->ranges = (xmlRegRangePtr *) xmlMalloc(atom->maxRanges *
1233		                             sizeof(xmlRegRangePtr));
1234	if (atom->ranges == NULL) {
1235	    xmlRegexpErrMemory(ctxt, "adding ranges");
1236	    atom->maxRanges = 0;
1237	    return;
1238	}
1239    } else if (atom->nbRanges >= atom->maxRanges) {
1240	xmlRegRangePtr *tmp;
1241	atom->maxRanges *= 2;
1242	tmp = (xmlRegRangePtr *) xmlRealloc(atom->ranges, atom->maxRanges *
1243		                             sizeof(xmlRegRangePtr));
1244	if (tmp == NULL) {
1245	    xmlRegexpErrMemory(ctxt, "adding ranges");
1246	    atom->maxRanges /= 2;
1247	    return;
1248	}
1249	atom->ranges = tmp;
1250    }
1251    range = xmlRegNewRange(ctxt, neg, type, start, end);
1252    if (range == NULL)
1253	return;
1254    range->blockName = blockName;
1255    atom->ranges[atom->nbRanges++] = range;
1256
1257}
1258
1259static int
1260xmlRegGetCounter(xmlRegParserCtxtPtr ctxt) {
1261    if (ctxt->maxCounters == 0) {
1262	ctxt->maxCounters = 4;
1263	ctxt->counters = (xmlRegCounter *) xmlMalloc(ctxt->maxCounters *
1264		                             sizeof(xmlRegCounter));
1265	if (ctxt->counters == NULL) {
1266	    xmlRegexpErrMemory(ctxt, "allocating counter");
1267	    ctxt->maxCounters = 0;
1268	    return(-1);
1269	}
1270    } else if (ctxt->nbCounters >= ctxt->maxCounters) {
1271	xmlRegCounter *tmp;
1272	ctxt->maxCounters *= 2;
1273	tmp = (xmlRegCounter *) xmlRealloc(ctxt->counters, ctxt->maxCounters *
1274		                           sizeof(xmlRegCounter));
1275	if (tmp == NULL) {
1276	    xmlRegexpErrMemory(ctxt, "allocating counter");
1277	    ctxt->maxCounters /= 2;
1278	    return(-1);
1279	}
1280	ctxt->counters = tmp;
1281    }
1282    ctxt->counters[ctxt->nbCounters].min = -1;
1283    ctxt->counters[ctxt->nbCounters].max = -1;
1284    return(ctxt->nbCounters++);
1285}
1286
1287static int
1288xmlRegAtomPush(xmlRegParserCtxtPtr ctxt, xmlRegAtomPtr atom) {
1289    if (atom == NULL) {
1290	ERROR("atom push: atom is NULL");
1291	return(-1);
1292    }
1293    if (ctxt->maxAtoms == 0) {
1294	ctxt->maxAtoms = 4;
1295	ctxt->atoms = (xmlRegAtomPtr *) xmlMalloc(ctxt->maxAtoms *
1296		                             sizeof(xmlRegAtomPtr));
1297	if (ctxt->atoms == NULL) {
1298	    xmlRegexpErrMemory(ctxt, "pushing atom");
1299	    ctxt->maxAtoms = 0;
1300	    return(-1);
1301	}
1302    } else if (ctxt->nbAtoms >= ctxt->maxAtoms) {
1303	xmlRegAtomPtr *tmp;
1304	ctxt->maxAtoms *= 2;
1305	tmp = (xmlRegAtomPtr *) xmlRealloc(ctxt->atoms, ctxt->maxAtoms *
1306		                             sizeof(xmlRegAtomPtr));
1307	if (tmp == NULL) {
1308	    xmlRegexpErrMemory(ctxt, "allocating counter");
1309	    ctxt->maxAtoms /= 2;
1310	    return(-1);
1311	}
1312	ctxt->atoms = tmp;
1313    }
1314    atom->no = ctxt->nbAtoms;
1315    ctxt->atoms[ctxt->nbAtoms++] = atom;
1316    return(0);
1317}
1318
1319static void
1320xmlRegStateAddTransTo(xmlRegParserCtxtPtr ctxt, xmlRegStatePtr target,
1321                      int from) {
1322    if (target->maxTransTo == 0) {
1323	target->maxTransTo = 8;
1324	target->transTo = (int *) xmlMalloc(target->maxTransTo *
1325		                             sizeof(int));
1326	if (target->transTo == NULL) {
1327	    xmlRegexpErrMemory(ctxt, "adding transition");
1328	    target->maxTransTo = 0;
1329	    return;
1330	}
1331    } else if (target->nbTransTo >= target->maxTransTo) {
1332	int *tmp;
1333	target->maxTransTo *= 2;
1334	tmp = (int *) xmlRealloc(target->transTo, target->maxTransTo *
1335		                             sizeof(int));
1336	if (tmp == NULL) {
1337	    xmlRegexpErrMemory(ctxt, "adding transition");
1338	    target->maxTransTo /= 2;
1339	    return;
1340	}
1341	target->transTo = tmp;
1342    }
1343    target->transTo[target->nbTransTo] = from;
1344    target->nbTransTo++;
1345}
1346
1347static void
1348xmlRegStateAddTrans(xmlRegParserCtxtPtr ctxt, xmlRegStatePtr state,
1349	            xmlRegAtomPtr atom, xmlRegStatePtr target,
1350		    int counter, int count) {
1351
1352    int nrtrans;
1353
1354    if (state == NULL) {
1355	ERROR("add state: state is NULL");
1356	return;
1357    }
1358    if (target == NULL) {
1359	ERROR("add state: target is NULL");
1360	return;
1361    }
1362    /*
1363     * Other routines follow the philosophy 'When in doubt, add a transition'
1364     * so we check here whether such a transition is already present and, if
1365     * so, silently ignore this request.
1366     */
1367
1368    for (nrtrans = state->nbTrans - 1; nrtrans >= 0; nrtrans--) {
1369	xmlRegTransPtr trans = &(state->trans[nrtrans]);
1370	if ((trans->atom == atom) &&
1371	    (trans->to == target->no) &&
1372	    (trans->counter == counter) &&
1373	    (trans->count == count)) {
1374#ifdef DEBUG_REGEXP_GRAPH
1375	    printf("Ignoring duplicate transition from %d to %d\n",
1376		    state->no, target->no);
1377#endif
1378	    return;
1379	}
1380    }
1381
1382    if (state->maxTrans == 0) {
1383	state->maxTrans = 8;
1384	state->trans = (xmlRegTrans *) xmlMalloc(state->maxTrans *
1385		                             sizeof(xmlRegTrans));
1386	if (state->trans == NULL) {
1387	    xmlRegexpErrMemory(ctxt, "adding transition");
1388	    state->maxTrans = 0;
1389	    return;
1390	}
1391    } else if (state->nbTrans >= state->maxTrans) {
1392	xmlRegTrans *tmp;
1393	state->maxTrans *= 2;
1394	tmp = (xmlRegTrans *) xmlRealloc(state->trans, state->maxTrans *
1395		                             sizeof(xmlRegTrans));
1396	if (tmp == NULL) {
1397	    xmlRegexpErrMemory(ctxt, "adding transition");
1398	    state->maxTrans /= 2;
1399	    return;
1400	}
1401	state->trans = tmp;
1402    }
1403#ifdef DEBUG_REGEXP_GRAPH
1404    printf("Add trans from %d to %d ", state->no, target->no);
1405    if (count == REGEXP_ALL_COUNTER)
1406	printf("all transition\n");
1407    else if (count >= 0)
1408	printf("count based %d\n", count);
1409    else if (counter >= 0)
1410	printf("counted %d\n", counter);
1411    else if (atom == NULL)
1412	printf("epsilon transition\n");
1413    else if (atom != NULL)
1414        xmlRegPrintAtom(stdout, atom);
1415#endif
1416
1417    state->trans[state->nbTrans].atom = atom;
1418    state->trans[state->nbTrans].to = target->no;
1419    state->trans[state->nbTrans].counter = counter;
1420    state->trans[state->nbTrans].count = count;
1421    state->trans[state->nbTrans].nd = 0;
1422    state->nbTrans++;
1423    xmlRegStateAddTransTo(ctxt, target, state->no);
1424}
1425
1426static int
1427xmlRegStatePush(xmlRegParserCtxtPtr ctxt, xmlRegStatePtr state) {
1428    if (state == NULL) return(-1);
1429    if (ctxt->maxStates == 0) {
1430	ctxt->maxStates = 4;
1431	ctxt->states = (xmlRegStatePtr *) xmlMalloc(ctxt->maxStates *
1432		                             sizeof(xmlRegStatePtr));
1433	if (ctxt->states == NULL) {
1434	    xmlRegexpErrMemory(ctxt, "adding state");
1435	    ctxt->maxStates = 0;
1436	    return(-1);
1437	}
1438    } else if (ctxt->nbStates >= ctxt->maxStates) {
1439	xmlRegStatePtr *tmp;
1440	ctxt->maxStates *= 2;
1441	tmp = (xmlRegStatePtr *) xmlRealloc(ctxt->states, ctxt->maxStates *
1442		                             sizeof(xmlRegStatePtr));
1443	if (tmp == NULL) {
1444	    xmlRegexpErrMemory(ctxt, "adding state");
1445	    ctxt->maxStates /= 2;
1446	    return(-1);
1447	}
1448	ctxt->states = tmp;
1449    }
1450    state->no = ctxt->nbStates;
1451    ctxt->states[ctxt->nbStates++] = state;
1452    return(0);
1453}
1454
1455/**
1456 * xmlFAGenerateAllTransition:
1457 * @ctxt:  a regexp parser context
1458 * @from:  the from state
1459 * @to:  the target state or NULL for building a new one
1460 * @lax:
1461 *
1462 */
1463static void
1464xmlFAGenerateAllTransition(xmlRegParserCtxtPtr ctxt,
1465			   xmlRegStatePtr from, xmlRegStatePtr to,
1466			   int lax) {
1467    if (to == NULL) {
1468	to = xmlRegNewState(ctxt);
1469	xmlRegStatePush(ctxt, to);
1470	ctxt->state = to;
1471    }
1472    if (lax)
1473	xmlRegStateAddTrans(ctxt, from, NULL, to, -1, REGEXP_ALL_LAX_COUNTER);
1474    else
1475	xmlRegStateAddTrans(ctxt, from, NULL, to, -1, REGEXP_ALL_COUNTER);
1476}
1477
1478/**
1479 * xmlFAGenerateEpsilonTransition:
1480 * @ctxt:  a regexp parser context
1481 * @from:  the from state
1482 * @to:  the target state or NULL for building a new one
1483 *
1484 */
1485static void
1486xmlFAGenerateEpsilonTransition(xmlRegParserCtxtPtr ctxt,
1487			       xmlRegStatePtr from, xmlRegStatePtr to) {
1488    if (to == NULL) {
1489	to = xmlRegNewState(ctxt);
1490	xmlRegStatePush(ctxt, to);
1491	ctxt->state = to;
1492    }
1493    xmlRegStateAddTrans(ctxt, from, NULL, to, -1, -1);
1494}
1495
1496/**
1497 * xmlFAGenerateCountedEpsilonTransition:
1498 * @ctxt:  a regexp parser context
1499 * @from:  the from state
1500 * @to:  the target state or NULL for building a new one
1501 * counter:  the counter for that transition
1502 *
1503 */
1504static void
1505xmlFAGenerateCountedEpsilonTransition(xmlRegParserCtxtPtr ctxt,
1506	    xmlRegStatePtr from, xmlRegStatePtr to, int counter) {
1507    if (to == NULL) {
1508	to = xmlRegNewState(ctxt);
1509	xmlRegStatePush(ctxt, to);
1510	ctxt->state = to;
1511    }
1512    xmlRegStateAddTrans(ctxt, from, NULL, to, counter, -1);
1513}
1514
1515/**
1516 * xmlFAGenerateCountedTransition:
1517 * @ctxt:  a regexp parser context
1518 * @from:  the from state
1519 * @to:  the target state or NULL for building a new one
1520 * counter:  the counter for that transition
1521 *
1522 */
1523static void
1524xmlFAGenerateCountedTransition(xmlRegParserCtxtPtr ctxt,
1525	    xmlRegStatePtr from, xmlRegStatePtr to, int counter) {
1526    if (to == NULL) {
1527	to = xmlRegNewState(ctxt);
1528	xmlRegStatePush(ctxt, to);
1529	ctxt->state = to;
1530    }
1531    xmlRegStateAddTrans(ctxt, from, NULL, to, -1, counter);
1532}
1533
1534/**
1535 * xmlFAGenerateTransitions:
1536 * @ctxt:  a regexp parser context
1537 * @from:  the from state
1538 * @to:  the target state or NULL for building a new one
1539 * @atom:  the atom generating the transition
1540 *
1541 * Returns 0 if success and -1 in case of error.
1542 */
1543static int
1544xmlFAGenerateTransitions(xmlRegParserCtxtPtr ctxt, xmlRegStatePtr from,
1545	                 xmlRegStatePtr to, xmlRegAtomPtr atom) {
1546    xmlRegStatePtr end;
1547    int nullable = 0;
1548
1549    if (atom == NULL) {
1550	ERROR("genrate transition: atom == NULL");
1551	return(-1);
1552    }
1553    if (atom->type == XML_REGEXP_SUBREG) {
1554	/*
1555	 * this is a subexpression handling one should not need to
1556	 * create a new node except for XML_REGEXP_QUANT_RANGE.
1557	 */
1558	if (xmlRegAtomPush(ctxt, atom) < 0) {
1559	    return(-1);
1560	}
1561	if ((to != NULL) && (atom->stop != to) &&
1562	    (atom->quant != XML_REGEXP_QUANT_RANGE)) {
1563	    /*
1564	     * Generate an epsilon transition to link to the target
1565	     */
1566	    xmlFAGenerateEpsilonTransition(ctxt, atom->stop, to);
1567#ifdef DV
1568	} else if ((to == NULL) && (atom->quant != XML_REGEXP_QUANT_RANGE) &&
1569		   (atom->quant != XML_REGEXP_QUANT_ONCE)) {
1570	    to = xmlRegNewState(ctxt);
1571	    xmlRegStatePush(ctxt, to);
1572	    ctxt->state = to;
1573	    xmlFAGenerateEpsilonTransition(ctxt, atom->stop, to);
1574#endif
1575	}
1576	switch (atom->quant) {
1577	    case XML_REGEXP_QUANT_OPT:
1578		atom->quant = XML_REGEXP_QUANT_ONCE;
1579		/*
1580		 * transition done to the state after end of atom.
1581		 *      1. set transition from atom start to new state
1582		 *      2. set transition from atom end to this state.
1583		 */
1584                if (to == NULL) {
1585                    xmlFAGenerateEpsilonTransition(ctxt, atom->start, 0);
1586                    xmlFAGenerateEpsilonTransition(ctxt, atom->stop,
1587                                                   ctxt->state);
1588                } else {
1589                    xmlFAGenerateEpsilonTransition(ctxt, atom->start, to);
1590                }
1591		break;
1592	    case XML_REGEXP_QUANT_MULT:
1593		atom->quant = XML_REGEXP_QUANT_ONCE;
1594		xmlFAGenerateEpsilonTransition(ctxt, atom->start, atom->stop);
1595		xmlFAGenerateEpsilonTransition(ctxt, atom->stop, atom->start);
1596		break;
1597	    case XML_REGEXP_QUANT_PLUS:
1598		atom->quant = XML_REGEXP_QUANT_ONCE;
1599		xmlFAGenerateEpsilonTransition(ctxt, atom->stop, atom->start);
1600		break;
1601	    case XML_REGEXP_QUANT_RANGE: {
1602		int counter;
1603		xmlRegStatePtr inter, newstate;
1604
1605		/*
1606		 * create the final state now if needed
1607		 */
1608		if (to != NULL) {
1609		    newstate = to;
1610		} else {
1611		    newstate = xmlRegNewState(ctxt);
1612		    xmlRegStatePush(ctxt, newstate);
1613		}
1614
1615		/*
1616		 * The principle here is to use counted transition
1617		 * to avoid explosion in the number of states in the
1618		 * graph. This is clearly more complex but should not
1619		 * be exploitable at runtime.
1620		 */
1621		if ((atom->min == 0) && (atom->start0 == NULL)) {
1622		    xmlRegAtomPtr copy;
1623		    /*
1624		     * duplicate a transition based on atom to count next
1625		     * occurences after 1. We cannot loop to atom->start
1626		     * directly because we need an epsilon transition to
1627		     * newstate.
1628		     */
1629		     /* ???? For some reason it seems we never reach that
1630		        case, I suppose this got optimized out before when
1631			building the automata */
1632		    copy = xmlRegCopyAtom(ctxt, atom);
1633		    if (copy == NULL)
1634		        return(-1);
1635		    copy->quant = XML_REGEXP_QUANT_ONCE;
1636		    copy->min = 0;
1637		    copy->max = 0;
1638
1639		    if (xmlFAGenerateTransitions(ctxt, atom->start, NULL, copy)
1640		        < 0)
1641			return(-1);
1642		    inter = ctxt->state;
1643		    counter = xmlRegGetCounter(ctxt);
1644		    ctxt->counters[counter].min = atom->min - 1;
1645		    ctxt->counters[counter].max = atom->max - 1;
1646		    /* count the number of times we see it again */
1647		    xmlFAGenerateCountedEpsilonTransition(ctxt, inter,
1648						   atom->stop, counter);
1649		    /* allow a way out based on the count */
1650		    xmlFAGenerateCountedTransition(ctxt, inter,
1651			                           newstate, counter);
1652		    /* and also allow a direct exit for 0 */
1653		    xmlFAGenerateEpsilonTransition(ctxt, atom->start,
1654		                                   newstate);
1655		} else {
1656		    /*
1657		     * either we need the atom at least once or there
1658		     * is an atom->start0 allowing to easilly plug the
1659		     * epsilon transition.
1660		     */
1661		    counter = xmlRegGetCounter(ctxt);
1662		    ctxt->counters[counter].min = atom->min - 1;
1663		    ctxt->counters[counter].max = atom->max - 1;
1664		    /* count the number of times we see it again */
1665		    xmlFAGenerateCountedEpsilonTransition(ctxt, atom->stop,
1666						   atom->start, counter);
1667		    /* allow a way out based on the count */
1668		    xmlFAGenerateCountedTransition(ctxt, atom->stop,
1669			                           newstate, counter);
1670		    /* and if needed allow a direct exit for 0 */
1671		    if (atom->min == 0)
1672			xmlFAGenerateEpsilonTransition(ctxt, atom->start0,
1673						       newstate);
1674
1675		}
1676		atom->min = 0;
1677		atom->max = 0;
1678		atom->quant = XML_REGEXP_QUANT_ONCE;
1679		ctxt->state = newstate;
1680	    }
1681	    default:
1682		break;
1683	}
1684	return(0);
1685    }
1686    if ((atom->min == 0) && (atom->max == 0) &&
1687               (atom->quant == XML_REGEXP_QUANT_RANGE)) {
1688        /*
1689	 * we can discard the atom and generate an epsilon transition instead
1690	 */
1691	if (to == NULL) {
1692	    to = xmlRegNewState(ctxt);
1693	    if (to != NULL)
1694		xmlRegStatePush(ctxt, to);
1695	    else {
1696		return(-1);
1697	    }
1698	}
1699	xmlFAGenerateEpsilonTransition(ctxt, from, to);
1700	ctxt->state = to;
1701	xmlRegFreeAtom(atom);
1702	return(0);
1703    }
1704    if (to == NULL) {
1705	to = xmlRegNewState(ctxt);
1706	if (to != NULL)
1707	    xmlRegStatePush(ctxt, to);
1708	else {
1709	    return(-1);
1710	}
1711    }
1712    end = to;
1713    if ((atom->quant == XML_REGEXP_QUANT_MULT) ||
1714        (atom->quant == XML_REGEXP_QUANT_PLUS)) {
1715	/*
1716	 * Do not pollute the target state by adding transitions from
1717	 * it as it is likely to be the shared target of multiple branches.
1718	 * So isolate with an epsilon transition.
1719	 */
1720        xmlRegStatePtr tmp;
1721
1722	tmp = xmlRegNewState(ctxt);
1723	if (tmp != NULL)
1724	    xmlRegStatePush(ctxt, tmp);
1725	else {
1726	    return(-1);
1727	}
1728	xmlFAGenerateEpsilonTransition(ctxt, tmp, to);
1729	to = tmp;
1730    }
1731    if (xmlRegAtomPush(ctxt, atom) < 0) {
1732	return(-1);
1733    }
1734    if ((atom->quant == XML_REGEXP_QUANT_RANGE) &&
1735        (atom->min == 0) && (atom->max > 0)) {
1736	nullable = 1;
1737	atom->min = 1;
1738        if (atom->max == 1)
1739	    atom->quant = XML_REGEXP_QUANT_OPT;
1740    }
1741    xmlRegStateAddTrans(ctxt, from, atom, to, -1, -1);
1742    ctxt->state = end;
1743    switch (atom->quant) {
1744	case XML_REGEXP_QUANT_OPT:
1745	    atom->quant = XML_REGEXP_QUANT_ONCE;
1746	    xmlFAGenerateEpsilonTransition(ctxt, from, to);
1747	    break;
1748	case XML_REGEXP_QUANT_MULT:
1749	    atom->quant = XML_REGEXP_QUANT_ONCE;
1750	    xmlFAGenerateEpsilonTransition(ctxt, from, to);
1751	    xmlRegStateAddTrans(ctxt, to, atom, to, -1, -1);
1752	    break;
1753	case XML_REGEXP_QUANT_PLUS:
1754	    atom->quant = XML_REGEXP_QUANT_ONCE;
1755	    xmlRegStateAddTrans(ctxt, to, atom, to, -1, -1);
1756	    break;
1757	case XML_REGEXP_QUANT_RANGE:
1758	    if (nullable)
1759		xmlFAGenerateEpsilonTransition(ctxt, from, to);
1760	    break;
1761	default:
1762	    break;
1763    }
1764    return(0);
1765}
1766
1767/**
1768 * xmlFAReduceEpsilonTransitions:
1769 * @ctxt:  a regexp parser context
1770 * @fromnr:  the from state
1771 * @tonr:  the to state
1772 * @counter:  should that transition be associated to a counted
1773 *
1774 */
1775static void
1776xmlFAReduceEpsilonTransitions(xmlRegParserCtxtPtr ctxt, int fromnr,
1777	                      int tonr, int counter) {
1778    int transnr;
1779    xmlRegStatePtr from;
1780    xmlRegStatePtr to;
1781
1782#ifdef DEBUG_REGEXP_GRAPH
1783    printf("xmlFAReduceEpsilonTransitions(%d, %d)\n", fromnr, tonr);
1784#endif
1785    from = ctxt->states[fromnr];
1786    if (from == NULL)
1787	return;
1788    to = ctxt->states[tonr];
1789    if (to == NULL)
1790	return;
1791    if ((to->mark == XML_REGEXP_MARK_START) ||
1792	(to->mark == XML_REGEXP_MARK_VISITED))
1793	return;
1794
1795    to->mark = XML_REGEXP_MARK_VISITED;
1796    if (to->type == XML_REGEXP_FINAL_STATE) {
1797#ifdef DEBUG_REGEXP_GRAPH
1798	printf("State %d is final, so %d becomes final\n", tonr, fromnr);
1799#endif
1800	from->type = XML_REGEXP_FINAL_STATE;
1801    }
1802    for (transnr = 0;transnr < to->nbTrans;transnr++) {
1803        if (to->trans[transnr].to < 0)
1804	    continue;
1805	if (to->trans[transnr].atom == NULL) {
1806	    /*
1807	     * Don't remove counted transitions
1808	     * Don't loop either
1809	     */
1810	    if (to->trans[transnr].to != fromnr) {
1811		if (to->trans[transnr].count >= 0) {
1812		    int newto = to->trans[transnr].to;
1813
1814		    xmlRegStateAddTrans(ctxt, from, NULL,
1815					ctxt->states[newto],
1816					-1, to->trans[transnr].count);
1817		} else {
1818#ifdef DEBUG_REGEXP_GRAPH
1819		    printf("Found epsilon trans %d from %d to %d\n",
1820			   transnr, tonr, to->trans[transnr].to);
1821#endif
1822		    if (to->trans[transnr].counter >= 0) {
1823			xmlFAReduceEpsilonTransitions(ctxt, fromnr,
1824					      to->trans[transnr].to,
1825					      to->trans[transnr].counter);
1826		    } else {
1827			xmlFAReduceEpsilonTransitions(ctxt, fromnr,
1828					      to->trans[transnr].to,
1829					      counter);
1830		    }
1831		}
1832	    }
1833	} else {
1834	    int newto = to->trans[transnr].to;
1835
1836	    if (to->trans[transnr].counter >= 0) {
1837		xmlRegStateAddTrans(ctxt, from, to->trans[transnr].atom,
1838				    ctxt->states[newto],
1839				    to->trans[transnr].counter, -1);
1840	    } else {
1841		xmlRegStateAddTrans(ctxt, from, to->trans[transnr].atom,
1842				    ctxt->states[newto], counter, -1);
1843	    }
1844	}
1845    }
1846    to->mark = XML_REGEXP_MARK_NORMAL;
1847}
1848
1849/**
1850 * xmlFAEliminateSimpleEpsilonTransitions:
1851 * @ctxt:  a regexp parser context
1852 *
1853 * Eliminating general epsilon transitions can get costly in the general
1854 * algorithm due to the large amount of generated new transitions and
1855 * associated comparisons. However for simple epsilon transition used just
1856 * to separate building blocks when generating the automata this can be
1857 * reduced to state elimination:
1858 *    - if there exists an epsilon from X to Y
1859 *    - if there is no other transition from X
1860 * then X and Y are semantically equivalent and X can be eliminated
1861 * If X is the start state then make Y the start state, else replace the
1862 * target of all transitions to X by transitions to Y.
1863 */
1864static void
1865xmlFAEliminateSimpleEpsilonTransitions(xmlRegParserCtxtPtr ctxt) {
1866    int statenr, i, j, newto;
1867    xmlRegStatePtr state, tmp;
1868
1869    for (statenr = 0;statenr < ctxt->nbStates;statenr++) {
1870	state = ctxt->states[statenr];
1871	if (state == NULL)
1872	    continue;
1873	if (state->nbTrans != 1)
1874	    continue;
1875	if (state->type == XML_REGEXP_UNREACH_STATE)
1876	    continue;
1877	/* is the only transition out a basic transition */
1878	if ((state->trans[0].atom == NULL) &&
1879	    (state->trans[0].to >= 0) &&
1880	    (state->trans[0].to != statenr) &&
1881	    (state->trans[0].counter < 0) &&
1882	    (state->trans[0].count < 0)) {
1883	    newto = state->trans[0].to;
1884
1885            if (state->type == XML_REGEXP_START_STATE) {
1886#ifdef DEBUG_REGEXP_GRAPH
1887		printf("Found simple epsilon trans from start %d to %d\n",
1888		       statenr, newto);
1889#endif
1890            } else {
1891#ifdef DEBUG_REGEXP_GRAPH
1892		printf("Found simple epsilon trans from %d to %d\n",
1893		       statenr, newto);
1894#endif
1895	        for (i = 0;i < state->nbTransTo;i++) {
1896		    tmp = ctxt->states[state->transTo[i]];
1897		    for (j = 0;j < tmp->nbTrans;j++) {
1898			if (tmp->trans[j].to == statenr) {
1899#ifdef DEBUG_REGEXP_GRAPH
1900			    printf("Changed transition %d on %d to go to %d\n",
1901				   j, tmp->no, newto);
1902#endif
1903			    tmp->trans[j].to = -1;
1904			    xmlRegStateAddTrans(ctxt, tmp, tmp->trans[j].atom,
1905						ctxt->states[newto],
1906					        tmp->trans[j].counter,
1907						tmp->trans[j].count);
1908			}
1909		    }
1910		}
1911		if (state->type == XML_REGEXP_FINAL_STATE)
1912		    ctxt->states[newto]->type = XML_REGEXP_FINAL_STATE;
1913		/* eliminate the transition completely */
1914		state->nbTrans = 0;
1915
1916                state->type = XML_REGEXP_UNREACH_STATE;
1917
1918	    }
1919
1920	}
1921    }
1922}
1923/**
1924 * xmlFAEliminateEpsilonTransitions:
1925 * @ctxt:  a regexp parser context
1926 *
1927 */
1928static void
1929xmlFAEliminateEpsilonTransitions(xmlRegParserCtxtPtr ctxt) {
1930    int statenr, transnr;
1931    xmlRegStatePtr state;
1932    int has_epsilon;
1933
1934    if (ctxt->states == NULL) return;
1935
1936    /*
1937     * Eliminate simple epsilon transition and the associated unreachable
1938     * states.
1939     */
1940    xmlFAEliminateSimpleEpsilonTransitions(ctxt);
1941    for (statenr = 0;statenr < ctxt->nbStates;statenr++) {
1942	state = ctxt->states[statenr];
1943	if ((state != NULL) && (state->type == XML_REGEXP_UNREACH_STATE)) {
1944#ifdef DEBUG_REGEXP_GRAPH
1945	    printf("Removed unreachable state %d\n", statenr);
1946#endif
1947	    xmlRegFreeState(state);
1948	    ctxt->states[statenr] = NULL;
1949	}
1950    }
1951
1952    has_epsilon = 0;
1953
1954    /*
1955     * Build the completed transitions bypassing the epsilons
1956     * Use a marking algorithm to avoid loops
1957     * Mark sink states too.
1958     * Process from the latests states backward to the start when
1959     * there is long cascading epsilon chains this minimize the
1960     * recursions and transition compares when adding the new ones
1961     */
1962    for (statenr = ctxt->nbStates - 1;statenr >= 0;statenr--) {
1963	state = ctxt->states[statenr];
1964	if (state == NULL)
1965	    continue;
1966	if ((state->nbTrans == 0) &&
1967	    (state->type != XML_REGEXP_FINAL_STATE)) {
1968	    state->type = XML_REGEXP_SINK_STATE;
1969	}
1970	for (transnr = 0;transnr < state->nbTrans;transnr++) {
1971	    if ((state->trans[transnr].atom == NULL) &&
1972		(state->trans[transnr].to >= 0)) {
1973		if (state->trans[transnr].to == statenr) {
1974		    state->trans[transnr].to = -1;
1975#ifdef DEBUG_REGEXP_GRAPH
1976		    printf("Removed loopback epsilon trans %d on %d\n",
1977			   transnr, statenr);
1978#endif
1979		} else if (state->trans[transnr].count < 0) {
1980		    int newto = state->trans[transnr].to;
1981
1982#ifdef DEBUG_REGEXP_GRAPH
1983		    printf("Found epsilon trans %d from %d to %d\n",
1984			   transnr, statenr, newto);
1985#endif
1986		    has_epsilon = 1;
1987		    state->trans[transnr].to = -2;
1988		    state->mark = XML_REGEXP_MARK_START;
1989		    xmlFAReduceEpsilonTransitions(ctxt, statenr,
1990				      newto, state->trans[transnr].counter);
1991		    state->mark = XML_REGEXP_MARK_NORMAL;
1992#ifdef DEBUG_REGEXP_GRAPH
1993		} else {
1994		    printf("Found counted transition %d on %d\n",
1995			   transnr, statenr);
1996#endif
1997	        }
1998	    }
1999	}
2000    }
2001    /*
2002     * Eliminate the epsilon transitions
2003     */
2004    if (has_epsilon) {
2005	for (statenr = 0;statenr < ctxt->nbStates;statenr++) {
2006	    state = ctxt->states[statenr];
2007	    if (state == NULL)
2008		continue;
2009	    for (transnr = 0;transnr < state->nbTrans;transnr++) {
2010		xmlRegTransPtr trans = &(state->trans[transnr]);
2011		if ((trans->atom == NULL) &&
2012		    (trans->count < 0) &&
2013		    (trans->to >= 0)) {
2014		    trans->to = -1;
2015		}
2016	    }
2017	}
2018    }
2019
2020    /*
2021     * Use this pass to detect unreachable states too
2022     */
2023    for (statenr = 0;statenr < ctxt->nbStates;statenr++) {
2024	state = ctxt->states[statenr];
2025	if (state != NULL)
2026	    state->reached = XML_REGEXP_MARK_NORMAL;
2027    }
2028    state = ctxt->states[0];
2029    if (state != NULL)
2030	state->reached = XML_REGEXP_MARK_START;
2031    while (state != NULL) {
2032	xmlRegStatePtr target = NULL;
2033	state->reached = XML_REGEXP_MARK_VISITED;
2034	/*
2035	 * Mark all states reachable from the current reachable state
2036	 */
2037	for (transnr = 0;transnr < state->nbTrans;transnr++) {
2038	    if ((state->trans[transnr].to >= 0) &&
2039		((state->trans[transnr].atom != NULL) ||
2040		 (state->trans[transnr].count >= 0))) {
2041		int newto = state->trans[transnr].to;
2042
2043		if (ctxt->states[newto] == NULL)
2044		    continue;
2045		if (ctxt->states[newto]->reached == XML_REGEXP_MARK_NORMAL) {
2046		    ctxt->states[newto]->reached = XML_REGEXP_MARK_START;
2047		    target = ctxt->states[newto];
2048		}
2049	    }
2050	}
2051
2052	/*
2053	 * find the next accessible state not explored
2054	 */
2055	if (target == NULL) {
2056	    for (statenr = 1;statenr < ctxt->nbStates;statenr++) {
2057		state = ctxt->states[statenr];
2058		if ((state != NULL) && (state->reached ==
2059			XML_REGEXP_MARK_START)) {
2060		    target = state;
2061		    break;
2062		}
2063	    }
2064	}
2065	state = target;
2066    }
2067    for (statenr = 0;statenr < ctxt->nbStates;statenr++) {
2068	state = ctxt->states[statenr];
2069	if ((state != NULL) && (state->reached == XML_REGEXP_MARK_NORMAL)) {
2070#ifdef DEBUG_REGEXP_GRAPH
2071	    printf("Removed unreachable state %d\n", statenr);
2072#endif
2073	    xmlRegFreeState(state);
2074	    ctxt->states[statenr] = NULL;
2075	}
2076    }
2077
2078}
2079
2080static int
2081xmlFACompareRanges(xmlRegRangePtr range1, xmlRegRangePtr range2) {
2082    int ret = 0;
2083
2084    if ((range1->type == XML_REGEXP_RANGES) ||
2085        (range2->type == XML_REGEXP_RANGES) ||
2086        (range2->type == XML_REGEXP_SUBREG) ||
2087        (range1->type == XML_REGEXP_SUBREG) ||
2088        (range1->type == XML_REGEXP_STRING) ||
2089        (range2->type == XML_REGEXP_STRING))
2090	return(-1);
2091
2092    /* put them in order */
2093    if (range1->type > range2->type) {
2094        xmlRegRangePtr tmp;
2095
2096	tmp = range1;
2097	range1 = range2;
2098	range2 = tmp;
2099    }
2100    if ((range1->type == XML_REGEXP_ANYCHAR) ||
2101        (range2->type == XML_REGEXP_ANYCHAR)) {
2102	ret = 1;
2103    } else if ((range1->type == XML_REGEXP_EPSILON) ||
2104               (range2->type == XML_REGEXP_EPSILON)) {
2105	return(0);
2106    } else if (range1->type == range2->type) {
2107        if (range1->type != XML_REGEXP_CHARVAL)
2108            ret = 1;
2109        else if ((range1->end < range2->start) ||
2110	         (range2->end < range1->start))
2111	    ret = 0;
2112	else
2113	    ret = 1;
2114    } else if (range1->type == XML_REGEXP_CHARVAL) {
2115        int codepoint;
2116	int neg = 0;
2117
2118	/*
2119	 * just check all codepoints in the range for acceptance,
2120	 * this is usually way cheaper since done only once at
2121	 * compilation than testing over and over at runtime or
2122	 * pushing too many states when evaluating.
2123	 */
2124	if (((range1->neg == 0) && (range2->neg != 0)) ||
2125	    ((range1->neg != 0) && (range2->neg == 0)))
2126	    neg = 1;
2127
2128	for (codepoint = range1->start;codepoint <= range1->end ;codepoint++) {
2129	    ret = xmlRegCheckCharacterRange(range2->type, codepoint,
2130					    0, range2->start, range2->end,
2131					    range2->blockName);
2132	    if (ret < 0)
2133	        return(-1);
2134	    if (((neg == 1) && (ret == 0)) ||
2135	        ((neg == 0) && (ret == 1)))
2136		return(1);
2137	}
2138	return(0);
2139    } else if ((range1->type == XML_REGEXP_BLOCK_NAME) ||
2140               (range2->type == XML_REGEXP_BLOCK_NAME)) {
2141	if (range1->type == range2->type) {
2142	    ret = xmlStrEqual(range1->blockName, range2->blockName);
2143	} else {
2144	    /*
2145	     * comparing a block range with anything else is way
2146	     * too costly, and maintining the table is like too much
2147	     * memory too, so let's force the automata to save state
2148	     * here.
2149	     */
2150	    return(1);
2151	}
2152    } else if ((range1->type < XML_REGEXP_LETTER) ||
2153               (range2->type < XML_REGEXP_LETTER)) {
2154	if ((range1->type == XML_REGEXP_ANYSPACE) &&
2155	    (range2->type == XML_REGEXP_NOTSPACE))
2156	    ret = 0;
2157	else if ((range1->type == XML_REGEXP_INITNAME) &&
2158	         (range2->type == XML_REGEXP_NOTINITNAME))
2159	    ret = 0;
2160	else if ((range1->type == XML_REGEXP_NAMECHAR) &&
2161	         (range2->type == XML_REGEXP_NOTNAMECHAR))
2162	    ret = 0;
2163	else if ((range1->type == XML_REGEXP_DECIMAL) &&
2164	         (range2->type == XML_REGEXP_NOTDECIMAL))
2165	    ret = 0;
2166	else if ((range1->type == XML_REGEXP_REALCHAR) &&
2167	         (range2->type == XML_REGEXP_NOTREALCHAR))
2168	    ret = 0;
2169	else {
2170	    /* same thing to limit complexity */
2171	    return(1);
2172	}
2173    } else {
2174        ret = 0;
2175        /* range1->type < range2->type here */
2176        switch (range1->type) {
2177	    case XML_REGEXP_LETTER:
2178	         /* all disjoint except in the subgroups */
2179	         if ((range2->type == XML_REGEXP_LETTER_UPPERCASE) ||
2180		     (range2->type == XML_REGEXP_LETTER_LOWERCASE) ||
2181		     (range2->type == XML_REGEXP_LETTER_TITLECASE) ||
2182		     (range2->type == XML_REGEXP_LETTER_MODIFIER) ||
2183		     (range2->type == XML_REGEXP_LETTER_OTHERS))
2184		     ret = 1;
2185		 break;
2186	    case XML_REGEXP_MARK:
2187	         if ((range2->type == XML_REGEXP_MARK_NONSPACING) ||
2188		     (range2->type == XML_REGEXP_MARK_SPACECOMBINING) ||
2189		     (range2->type == XML_REGEXP_MARK_ENCLOSING))
2190		     ret = 1;
2191		 break;
2192	    case XML_REGEXP_NUMBER:
2193	         if ((range2->type == XML_REGEXP_NUMBER_DECIMAL) ||
2194		     (range2->type == XML_REGEXP_NUMBER_LETTER) ||
2195		     (range2->type == XML_REGEXP_NUMBER_OTHERS))
2196		     ret = 1;
2197		 break;
2198	    case XML_REGEXP_PUNCT:
2199	         if ((range2->type == XML_REGEXP_PUNCT_CONNECTOR) ||
2200		     (range2->type == XML_REGEXP_PUNCT_DASH) ||
2201		     (range2->type == XML_REGEXP_PUNCT_OPEN) ||
2202		     (range2->type == XML_REGEXP_PUNCT_CLOSE) ||
2203		     (range2->type == XML_REGEXP_PUNCT_INITQUOTE) ||
2204		     (range2->type == XML_REGEXP_PUNCT_FINQUOTE) ||
2205		     (range2->type == XML_REGEXP_PUNCT_OTHERS))
2206		     ret = 1;
2207		 break;
2208	    case XML_REGEXP_SEPAR:
2209	         if ((range2->type == XML_REGEXP_SEPAR_SPACE) ||
2210		     (range2->type == XML_REGEXP_SEPAR_LINE) ||
2211		     (range2->type == XML_REGEXP_SEPAR_PARA))
2212		     ret = 1;
2213		 break;
2214	    case XML_REGEXP_SYMBOL:
2215	         if ((range2->type == XML_REGEXP_SYMBOL_MATH) ||
2216		     (range2->type == XML_REGEXP_SYMBOL_CURRENCY) ||
2217		     (range2->type == XML_REGEXP_SYMBOL_MODIFIER) ||
2218		     (range2->type == XML_REGEXP_SYMBOL_OTHERS))
2219		     ret = 1;
2220		 break;
2221	    case XML_REGEXP_OTHER:
2222	         if ((range2->type == XML_REGEXP_OTHER_CONTROL) ||
2223		     (range2->type == XML_REGEXP_OTHER_FORMAT) ||
2224		     (range2->type == XML_REGEXP_OTHER_PRIVATE))
2225		     ret = 1;
2226		 break;
2227            default:
2228	         if ((range2->type >= XML_REGEXP_LETTER) &&
2229		     (range2->type < XML_REGEXP_BLOCK_NAME))
2230		     ret = 0;
2231		 else {
2232		     /* safety net ! */
2233		     return(1);
2234		 }
2235	}
2236    }
2237    if (((range1->neg == 0) && (range2->neg != 0)) ||
2238        ((range1->neg != 0) && (range2->neg == 0)))
2239	ret = !ret;
2240    return(ret);
2241}
2242
2243/**
2244 * xmlFACompareAtomTypes:
2245 * @type1:  an atom type
2246 * @type2:  an atom type
2247 *
2248 * Compares two atoms type to check whether they intersect in some ways,
2249 * this is used by xmlFACompareAtoms only
2250 *
2251 * Returns 1 if they may intersect and 0 otherwise
2252 */
2253static int
2254xmlFACompareAtomTypes(xmlRegAtomType type1, xmlRegAtomType type2) {
2255    if ((type1 == XML_REGEXP_EPSILON) ||
2256        (type1 == XML_REGEXP_CHARVAL) ||
2257	(type1 == XML_REGEXP_RANGES) ||
2258	(type1 == XML_REGEXP_SUBREG) ||
2259	(type1 == XML_REGEXP_STRING) ||
2260	(type1 == XML_REGEXP_ANYCHAR))
2261	return(1);
2262    if ((type2 == XML_REGEXP_EPSILON) ||
2263        (type2 == XML_REGEXP_CHARVAL) ||
2264	(type2 == XML_REGEXP_RANGES) ||
2265	(type2 == XML_REGEXP_SUBREG) ||
2266	(type2 == XML_REGEXP_STRING) ||
2267	(type2 == XML_REGEXP_ANYCHAR))
2268	return(1);
2269
2270    if (type1 == type2) return(1);
2271
2272    /* simplify subsequent compares by making sure type1 < type2 */
2273    if (type1 > type2) {
2274        xmlRegAtomType tmp = type1;
2275	type1 = type2;
2276	type2 = tmp;
2277    }
2278    switch (type1) {
2279        case XML_REGEXP_ANYSPACE: /* \s */
2280	    /* can't be a letter, number, mark, pontuation, symbol */
2281	    if ((type2 == XML_REGEXP_NOTSPACE) ||
2282		((type2 >= XML_REGEXP_LETTER) &&
2283		 (type2 <= XML_REGEXP_LETTER_OTHERS)) ||
2284	        ((type2 >= XML_REGEXP_NUMBER) &&
2285		 (type2 <= XML_REGEXP_NUMBER_OTHERS)) ||
2286	        ((type2 >= XML_REGEXP_MARK) &&
2287		 (type2 <= XML_REGEXP_MARK_ENCLOSING)) ||
2288	        ((type2 >= XML_REGEXP_PUNCT) &&
2289		 (type2 <= XML_REGEXP_PUNCT_OTHERS)) ||
2290	        ((type2 >= XML_REGEXP_SYMBOL) &&
2291		 (type2 <= XML_REGEXP_SYMBOL_OTHERS))
2292	        ) return(0);
2293	    break;
2294        case XML_REGEXP_NOTSPACE: /* \S */
2295	    break;
2296        case XML_REGEXP_INITNAME: /* \l */
2297	    /* can't be a number, mark, separator, pontuation, symbol or other */
2298	    if ((type2 == XML_REGEXP_NOTINITNAME) ||
2299	        ((type2 >= XML_REGEXP_NUMBER) &&
2300		 (type2 <= XML_REGEXP_NUMBER_OTHERS)) ||
2301	        ((type2 >= XML_REGEXP_MARK) &&
2302		 (type2 <= XML_REGEXP_MARK_ENCLOSING)) ||
2303	        ((type2 >= XML_REGEXP_SEPAR) &&
2304		 (type2 <= XML_REGEXP_SEPAR_PARA)) ||
2305	        ((type2 >= XML_REGEXP_PUNCT) &&
2306		 (type2 <= XML_REGEXP_PUNCT_OTHERS)) ||
2307	        ((type2 >= XML_REGEXP_SYMBOL) &&
2308		 (type2 <= XML_REGEXP_SYMBOL_OTHERS)) ||
2309	        ((type2 >= XML_REGEXP_OTHER) &&
2310		 (type2 <= XML_REGEXP_OTHER_NA))
2311		) return(0);
2312	    break;
2313        case XML_REGEXP_NOTINITNAME: /* \L */
2314	    break;
2315        case XML_REGEXP_NAMECHAR: /* \c */
2316	    /* can't be a mark, separator, pontuation, symbol or other */
2317	    if ((type2 == XML_REGEXP_NOTNAMECHAR) ||
2318	        ((type2 >= XML_REGEXP_MARK) &&
2319		 (type2 <= XML_REGEXP_MARK_ENCLOSING)) ||
2320	        ((type2 >= XML_REGEXP_PUNCT) &&
2321		 (type2 <= XML_REGEXP_PUNCT_OTHERS)) ||
2322	        ((type2 >= XML_REGEXP_SEPAR) &&
2323		 (type2 <= XML_REGEXP_SEPAR_PARA)) ||
2324	        ((type2 >= XML_REGEXP_SYMBOL) &&
2325		 (type2 <= XML_REGEXP_SYMBOL_OTHERS)) ||
2326	        ((type2 >= XML_REGEXP_OTHER) &&
2327		 (type2 <= XML_REGEXP_OTHER_NA))
2328		) return(0);
2329	    break;
2330        case XML_REGEXP_NOTNAMECHAR: /* \C */
2331	    break;
2332        case XML_REGEXP_DECIMAL: /* \d */
2333	    /* can't be a letter, mark, separator, pontuation, symbol or other */
2334	    if ((type2 == XML_REGEXP_NOTDECIMAL) ||
2335	        (type2 == XML_REGEXP_REALCHAR) ||
2336		((type2 >= XML_REGEXP_LETTER) &&
2337		 (type2 <= XML_REGEXP_LETTER_OTHERS)) ||
2338	        ((type2 >= XML_REGEXP_MARK) &&
2339		 (type2 <= XML_REGEXP_MARK_ENCLOSING)) ||
2340	        ((type2 >= XML_REGEXP_PUNCT) &&
2341		 (type2 <= XML_REGEXP_PUNCT_OTHERS)) ||
2342	        ((type2 >= XML_REGEXP_SEPAR) &&
2343		 (type2 <= XML_REGEXP_SEPAR_PARA)) ||
2344	        ((type2 >= XML_REGEXP_SYMBOL) &&
2345		 (type2 <= XML_REGEXP_SYMBOL_OTHERS)) ||
2346	        ((type2 >= XML_REGEXP_OTHER) &&
2347		 (type2 <= XML_REGEXP_OTHER_NA))
2348		)return(0);
2349	    break;
2350        case XML_REGEXP_NOTDECIMAL: /* \D */
2351	    break;
2352        case XML_REGEXP_REALCHAR: /* \w */
2353	    /* can't be a mark, separator, pontuation, symbol or other */
2354	    if ((type2 == XML_REGEXP_NOTDECIMAL) ||
2355	        ((type2 >= XML_REGEXP_MARK) &&
2356		 (type2 <= XML_REGEXP_MARK_ENCLOSING)) ||
2357	        ((type2 >= XML_REGEXP_PUNCT) &&
2358		 (type2 <= XML_REGEXP_PUNCT_OTHERS)) ||
2359	        ((type2 >= XML_REGEXP_SEPAR) &&
2360		 (type2 <= XML_REGEXP_SEPAR_PARA)) ||
2361	        ((type2 >= XML_REGEXP_SYMBOL) &&
2362		 (type2 <= XML_REGEXP_SYMBOL_OTHERS)) ||
2363	        ((type2 >= XML_REGEXP_OTHER) &&
2364		 (type2 <= XML_REGEXP_OTHER_NA))
2365		)return(0);
2366	    break;
2367        case XML_REGEXP_NOTREALCHAR: /* \W */
2368	    break;
2369	/*
2370	 * at that point we know both type 1 and type2 are from
2371	 * character categories are ordered and are different,
2372	 * it becomes simple because this is a partition
2373	 */
2374        case XML_REGEXP_LETTER:
2375	    if (type2 <= XML_REGEXP_LETTER_OTHERS)
2376	        return(1);
2377	    return(0);
2378        case XML_REGEXP_LETTER_UPPERCASE:
2379        case XML_REGEXP_LETTER_LOWERCASE:
2380        case XML_REGEXP_LETTER_TITLECASE:
2381        case XML_REGEXP_LETTER_MODIFIER:
2382        case XML_REGEXP_LETTER_OTHERS:
2383	    return(0);
2384        case XML_REGEXP_MARK:
2385	    if (type2 <= XML_REGEXP_MARK_ENCLOSING)
2386	        return(1);
2387	    return(0);
2388        case XML_REGEXP_MARK_NONSPACING:
2389        case XML_REGEXP_MARK_SPACECOMBINING:
2390        case XML_REGEXP_MARK_ENCLOSING:
2391	    return(0);
2392        case XML_REGEXP_NUMBER:
2393	    if (type2 <= XML_REGEXP_NUMBER_OTHERS)
2394	        return(1);
2395	    return(0);
2396        case XML_REGEXP_NUMBER_DECIMAL:
2397        case XML_REGEXP_NUMBER_LETTER:
2398        case XML_REGEXP_NUMBER_OTHERS:
2399	    return(0);
2400        case XML_REGEXP_PUNCT:
2401	    if (type2 <= XML_REGEXP_PUNCT_OTHERS)
2402	        return(1);
2403	    return(0);
2404        case XML_REGEXP_PUNCT_CONNECTOR:
2405        case XML_REGEXP_PUNCT_DASH:
2406        case XML_REGEXP_PUNCT_OPEN:
2407        case XML_REGEXP_PUNCT_CLOSE:
2408        case XML_REGEXP_PUNCT_INITQUOTE:
2409        case XML_REGEXP_PUNCT_FINQUOTE:
2410        case XML_REGEXP_PUNCT_OTHERS:
2411	    return(0);
2412        case XML_REGEXP_SEPAR:
2413	    if (type2 <= XML_REGEXP_SEPAR_PARA)
2414	        return(1);
2415	    return(0);
2416        case XML_REGEXP_SEPAR_SPACE:
2417        case XML_REGEXP_SEPAR_LINE:
2418        case XML_REGEXP_SEPAR_PARA:
2419	    return(0);
2420        case XML_REGEXP_SYMBOL:
2421	    if (type2 <= XML_REGEXP_SYMBOL_OTHERS)
2422	        return(1);
2423	    return(0);
2424        case XML_REGEXP_SYMBOL_MATH:
2425        case XML_REGEXP_SYMBOL_CURRENCY:
2426        case XML_REGEXP_SYMBOL_MODIFIER:
2427        case XML_REGEXP_SYMBOL_OTHERS:
2428	    return(0);
2429        case XML_REGEXP_OTHER:
2430	    if (type2 <= XML_REGEXP_OTHER_NA)
2431	        return(1);
2432	    return(0);
2433        case XML_REGEXP_OTHER_CONTROL:
2434        case XML_REGEXP_OTHER_FORMAT:
2435        case XML_REGEXP_OTHER_PRIVATE:
2436        case XML_REGEXP_OTHER_NA:
2437	    return(0);
2438	default:
2439	    break;
2440    }
2441    return(1);
2442}
2443
2444/**
2445 * xmlFAEqualAtoms:
2446 * @atom1:  an atom
2447 * @atom2:  an atom
2448 * @deep: if not set only compare string pointers
2449 *
2450 * Compares two atoms to check whether they are the same exactly
2451 * this is used to remove equivalent transitions
2452 *
2453 * Returns 1 if same and 0 otherwise
2454 */
2455static int
2456xmlFAEqualAtoms(xmlRegAtomPtr atom1, xmlRegAtomPtr atom2, int deep) {
2457    int ret = 0;
2458
2459    if (atom1 == atom2)
2460	return(1);
2461    if ((atom1 == NULL) || (atom2 == NULL))
2462	return(0);
2463
2464    if (atom1->type != atom2->type)
2465        return(0);
2466    switch (atom1->type) {
2467        case XML_REGEXP_EPSILON:
2468	    ret = 0;
2469	    break;
2470        case XML_REGEXP_STRING:
2471            if (!deep)
2472                ret = (atom1->valuep == atom2->valuep);
2473            else
2474                ret = xmlStrEqual((xmlChar *)atom1->valuep,
2475                                  (xmlChar *)atom2->valuep);
2476	    break;
2477        case XML_REGEXP_CHARVAL:
2478	    ret = (atom1->codepoint == atom2->codepoint);
2479	    break;
2480	case XML_REGEXP_RANGES:
2481	    /* too hard to do in the general case */
2482	    ret = 0;
2483	default:
2484	    break;
2485    }
2486    return(ret);
2487}
2488
2489/**
2490 * xmlFACompareAtoms:
2491 * @atom1:  an atom
2492 * @atom2:  an atom
2493 * @deep: if not set only compare string pointers
2494 *
2495 * Compares two atoms to check whether they intersect in some ways,
2496 * this is used by xmlFAComputesDeterminism and xmlFARecurseDeterminism only
2497 *
2498 * Returns 1 if yes and 0 otherwise
2499 */
2500static int
2501xmlFACompareAtoms(xmlRegAtomPtr atom1, xmlRegAtomPtr atom2, int deep) {
2502    int ret = 1;
2503
2504    if (atom1 == atom2)
2505	return(1);
2506    if ((atom1 == NULL) || (atom2 == NULL))
2507	return(0);
2508
2509    if ((atom1->type == XML_REGEXP_ANYCHAR) ||
2510        (atom2->type == XML_REGEXP_ANYCHAR))
2511	return(1);
2512
2513    if (atom1->type > atom2->type) {
2514	xmlRegAtomPtr tmp;
2515	tmp = atom1;
2516	atom1 = atom2;
2517	atom2 = tmp;
2518    }
2519    if (atom1->type != atom2->type) {
2520        ret = xmlFACompareAtomTypes(atom1->type, atom2->type);
2521	/* if they can't intersect at the type level break now */
2522	if (ret == 0)
2523	    return(0);
2524    }
2525    switch (atom1->type) {
2526        case XML_REGEXP_STRING:
2527            if (!deep)
2528                ret = (atom1->valuep != atom2->valuep);
2529            else
2530                ret = xmlRegStrEqualWildcard((xmlChar *)atom1->valuep,
2531                                             (xmlChar *)atom2->valuep);
2532	    break;
2533        case XML_REGEXP_EPSILON:
2534	    goto not_determinist;
2535        case XML_REGEXP_CHARVAL:
2536	    if (atom2->type == XML_REGEXP_CHARVAL) {
2537		ret = (atom1->codepoint == atom2->codepoint);
2538	    } else {
2539	        ret = xmlRegCheckCharacter(atom2, atom1->codepoint);
2540		if (ret < 0)
2541		    ret = 1;
2542	    }
2543	    break;
2544        case XML_REGEXP_RANGES:
2545	    if (atom2->type == XML_REGEXP_RANGES) {
2546	        int i, j, res;
2547		xmlRegRangePtr r1, r2;
2548
2549		/*
2550		 * need to check that none of the ranges eventually matches
2551		 */
2552		for (i = 0;i < atom1->nbRanges;i++) {
2553		    for (j = 0;j < atom2->nbRanges;j++) {
2554			r1 = atom1->ranges[i];
2555			r2 = atom2->ranges[j];
2556			res = xmlFACompareRanges(r1, r2);
2557			if (res == 1) {
2558			    ret = 1;
2559			    goto done;
2560			}
2561		    }
2562		}
2563		ret = 0;
2564	    }
2565	    break;
2566	default:
2567	    goto not_determinist;
2568    }
2569done:
2570    if (atom1->neg != atom2->neg) {
2571        ret = !ret;
2572    }
2573    if (ret == 0)
2574        return(0);
2575not_determinist:
2576    return(1);
2577}
2578
2579/**
2580 * xmlFARecurseDeterminism:
2581 * @ctxt:  a regexp parser context
2582 *
2583 * Check whether the associated regexp is determinist,
2584 * should be called after xmlFAEliminateEpsilonTransitions()
2585 *
2586 */
2587static int
2588xmlFARecurseDeterminism(xmlRegParserCtxtPtr ctxt, xmlRegStatePtr state,
2589	                 int to, xmlRegAtomPtr atom) {
2590    int ret = 1;
2591    int res;
2592    int transnr, nbTrans;
2593    xmlRegTransPtr t1;
2594    int deep = 1;
2595
2596    if (state == NULL)
2597	return(ret);
2598    if (state->markd == XML_REGEXP_MARK_VISITED)
2599	return(ret);
2600
2601    if (ctxt->flags & AM_AUTOMATA_RNG)
2602        deep = 0;
2603
2604    /*
2605     * don't recurse on transitions potentially added in the course of
2606     * the elimination.
2607     */
2608    nbTrans = state->nbTrans;
2609    for (transnr = 0;transnr < nbTrans;transnr++) {
2610	t1 = &(state->trans[transnr]);
2611	/*
2612	 * check transitions conflicting with the one looked at
2613	 */
2614	if (t1->atom == NULL) {
2615	    if (t1->to < 0)
2616		continue;
2617	    state->markd = XML_REGEXP_MARK_VISITED;
2618	    res = xmlFARecurseDeterminism(ctxt, ctxt->states[t1->to],
2619		                           to, atom);
2620	    state->markd = 0;
2621	    if (res == 0) {
2622	        ret = 0;
2623		/* t1->nd = 1; */
2624	    }
2625	    continue;
2626	}
2627	if (t1->to != to)
2628	    continue;
2629	if (xmlFACompareAtoms(t1->atom, atom, deep)) {
2630	    ret = 0;
2631	    /* mark the transition as non-deterministic */
2632	    t1->nd = 1;
2633	}
2634    }
2635    return(ret);
2636}
2637
2638/**
2639 * xmlFAComputesDeterminism:
2640 * @ctxt:  a regexp parser context
2641 *
2642 * Check whether the associated regexp is determinist,
2643 * should be called after xmlFAEliminateEpsilonTransitions()
2644 *
2645 */
2646static int
2647xmlFAComputesDeterminism(xmlRegParserCtxtPtr ctxt) {
2648    int statenr, transnr;
2649    xmlRegStatePtr state;
2650    xmlRegTransPtr t1, t2, last;
2651    int i;
2652    int ret = 1;
2653    int deep = 1;
2654
2655#ifdef DEBUG_REGEXP_GRAPH
2656    printf("xmlFAComputesDeterminism\n");
2657    xmlRegPrintCtxt(stdout, ctxt);
2658#endif
2659    if (ctxt->determinist != -1)
2660	return(ctxt->determinist);
2661
2662    if (ctxt->flags & AM_AUTOMATA_RNG)
2663        deep = 0;
2664
2665    /*
2666     * First cleanup the automata removing cancelled transitions
2667     */
2668    for (statenr = 0;statenr < ctxt->nbStates;statenr++) {
2669	state = ctxt->states[statenr];
2670	if (state == NULL)
2671	    continue;
2672	if (state->nbTrans < 2)
2673	    continue;
2674	for (transnr = 0;transnr < state->nbTrans;transnr++) {
2675	    t1 = &(state->trans[transnr]);
2676	    /*
2677	     * Determinism checks in case of counted or all transitions
2678	     * will have to be handled separately
2679	     */
2680	    if (t1->atom == NULL) {
2681		/* t1->nd = 1; */
2682		continue;
2683	    }
2684	    if (t1->to == -1) /* eliminated */
2685		continue;
2686	    for (i = 0;i < transnr;i++) {
2687		t2 = &(state->trans[i]);
2688		if (t2->to == -1) /* eliminated */
2689		    continue;
2690		if (t2->atom != NULL) {
2691		    if (t1->to == t2->to) {
2692                        /*
2693                         * Here we use deep because we want to keep the
2694                         * transitions which indicate a conflict
2695                         */
2696			if (xmlFAEqualAtoms(t1->atom, t2->atom, deep) &&
2697                            (t1->counter == t2->counter) &&
2698                            (t1->count == t2->count))
2699			    t2->to = -1; /* eliminated */
2700		    }
2701		}
2702	    }
2703	}
2704    }
2705
2706    /*
2707     * Check for all states that there aren't 2 transitions
2708     * with the same atom and a different target.
2709     */
2710    for (statenr = 0;statenr < ctxt->nbStates;statenr++) {
2711	state = ctxt->states[statenr];
2712	if (state == NULL)
2713	    continue;
2714	if (state->nbTrans < 2)
2715	    continue;
2716	last = NULL;
2717	for (transnr = 0;transnr < state->nbTrans;transnr++) {
2718	    t1 = &(state->trans[transnr]);
2719	    /*
2720	     * Determinism checks in case of counted or all transitions
2721	     * will have to be handled separately
2722	     */
2723	    if (t1->atom == NULL) {
2724		continue;
2725	    }
2726	    if (t1->to == -1) /* eliminated */
2727		continue;
2728	    for (i = 0;i < transnr;i++) {
2729		t2 = &(state->trans[i]);
2730		if (t2->to == -1) /* eliminated */
2731		    continue;
2732		if (t2->atom != NULL) {
2733                    /*
2734                     * But here we don't use deep because we want to
2735                     * find transitions which indicate a conflict
2736                     */
2737		    if (xmlFACompareAtoms(t1->atom, t2->atom, 1)) {
2738			ret = 0;
2739			/* mark the transitions as non-deterministic ones */
2740			t1->nd = 1;
2741			t2->nd = 1;
2742			last = t1;
2743		    }
2744		} else if (t1->to != -1) {
2745		    /*
2746		     * do the closure in case of remaining specific
2747		     * epsilon transitions like choices or all
2748		     */
2749		    ret = xmlFARecurseDeterminism(ctxt, ctxt->states[t1->to],
2750						   t2->to, t2->atom);
2751		    /* don't shortcut the computation so all non deterministic
2752		       transition get marked down
2753		    if (ret == 0)
2754			return(0);
2755		     */
2756		    if (ret == 0) {
2757			t1->nd = 1;
2758			/* t2->nd = 1; */
2759			last = t1;
2760		    }
2761		}
2762	    }
2763	    /* don't shortcut the computation so all non deterministic
2764	       transition get marked down
2765	    if (ret == 0)
2766		break; */
2767	}
2768
2769	/*
2770	 * mark specifically the last non-deterministic transition
2771	 * from a state since there is no need to set-up rollback
2772	 * from it
2773	 */
2774	if (last != NULL) {
2775	    last->nd = 2;
2776	}
2777
2778	/* don't shortcut the computation so all non deterministic
2779	   transition get marked down
2780	if (ret == 0)
2781	    break; */
2782    }
2783
2784    ctxt->determinist = ret;
2785    return(ret);
2786}
2787
2788/************************************************************************
2789 *									*
2790 *	Routines to check input against transition atoms		*
2791 *									*
2792 ************************************************************************/
2793
2794static int
2795xmlRegCheckCharacterRange(xmlRegAtomType type, int codepoint, int neg,
2796	                  int start, int end, const xmlChar *blockName) {
2797    int ret = 0;
2798
2799    switch (type) {
2800        case XML_REGEXP_STRING:
2801        case XML_REGEXP_SUBREG:
2802        case XML_REGEXP_RANGES:
2803        case XML_REGEXP_EPSILON:
2804	    return(-1);
2805        case XML_REGEXP_ANYCHAR:
2806	    ret = ((codepoint != '\n') && (codepoint != '\r'));
2807	    break;
2808        case XML_REGEXP_CHARVAL:
2809	    ret = ((codepoint >= start) && (codepoint <= end));
2810	    break;
2811        case XML_REGEXP_NOTSPACE:
2812	    neg = !neg;
2813        case XML_REGEXP_ANYSPACE:
2814	    ret = ((codepoint == '\n') || (codepoint == '\r') ||
2815		   (codepoint == '\t') || (codepoint == ' '));
2816	    break;
2817        case XML_REGEXP_NOTINITNAME:
2818	    neg = !neg;
2819        case XML_REGEXP_INITNAME:
2820	    ret = (IS_LETTER(codepoint) ||
2821		   (codepoint == '_') || (codepoint == ':'));
2822	    break;
2823        case XML_REGEXP_NOTNAMECHAR:
2824	    neg = !neg;
2825        case XML_REGEXP_NAMECHAR:
2826	    ret = (IS_LETTER(codepoint) || IS_DIGIT(codepoint) ||
2827		   (codepoint == '.') || (codepoint == '-') ||
2828		   (codepoint == '_') || (codepoint == ':') ||
2829		   IS_COMBINING(codepoint) || IS_EXTENDER(codepoint));
2830	    break;
2831        case XML_REGEXP_NOTDECIMAL:
2832	    neg = !neg;
2833        case XML_REGEXP_DECIMAL:
2834	    ret = xmlUCSIsCatNd(codepoint);
2835	    break;
2836        case XML_REGEXP_REALCHAR:
2837	    neg = !neg;
2838        case XML_REGEXP_NOTREALCHAR:
2839	    ret = xmlUCSIsCatP(codepoint);
2840	    if (ret == 0)
2841		ret = xmlUCSIsCatZ(codepoint);
2842	    if (ret == 0)
2843		ret = xmlUCSIsCatC(codepoint);
2844	    break;
2845        case XML_REGEXP_LETTER:
2846	    ret = xmlUCSIsCatL(codepoint);
2847	    break;
2848        case XML_REGEXP_LETTER_UPPERCASE:
2849	    ret = xmlUCSIsCatLu(codepoint);
2850	    break;
2851        case XML_REGEXP_LETTER_LOWERCASE:
2852	    ret = xmlUCSIsCatLl(codepoint);
2853	    break;
2854        case XML_REGEXP_LETTER_TITLECASE:
2855	    ret = xmlUCSIsCatLt(codepoint);
2856	    break;
2857        case XML_REGEXP_LETTER_MODIFIER:
2858	    ret = xmlUCSIsCatLm(codepoint);
2859	    break;
2860        case XML_REGEXP_LETTER_OTHERS:
2861	    ret = xmlUCSIsCatLo(codepoint);
2862	    break;
2863        case XML_REGEXP_MARK:
2864	    ret = xmlUCSIsCatM(codepoint);
2865	    break;
2866        case XML_REGEXP_MARK_NONSPACING:
2867	    ret = xmlUCSIsCatMn(codepoint);
2868	    break;
2869        case XML_REGEXP_MARK_SPACECOMBINING:
2870	    ret = xmlUCSIsCatMc(codepoint);
2871	    break;
2872        case XML_REGEXP_MARK_ENCLOSING:
2873	    ret = xmlUCSIsCatMe(codepoint);
2874	    break;
2875        case XML_REGEXP_NUMBER:
2876	    ret = xmlUCSIsCatN(codepoint);
2877	    break;
2878        case XML_REGEXP_NUMBER_DECIMAL:
2879	    ret = xmlUCSIsCatNd(codepoint);
2880	    break;
2881        case XML_REGEXP_NUMBER_LETTER:
2882	    ret = xmlUCSIsCatNl(codepoint);
2883	    break;
2884        case XML_REGEXP_NUMBER_OTHERS:
2885	    ret = xmlUCSIsCatNo(codepoint);
2886	    break;
2887        case XML_REGEXP_PUNCT:
2888	    ret = xmlUCSIsCatP(codepoint);
2889	    break;
2890        case XML_REGEXP_PUNCT_CONNECTOR:
2891	    ret = xmlUCSIsCatPc(codepoint);
2892	    break;
2893        case XML_REGEXP_PUNCT_DASH:
2894	    ret = xmlUCSIsCatPd(codepoint);
2895	    break;
2896        case XML_REGEXP_PUNCT_OPEN:
2897	    ret = xmlUCSIsCatPs(codepoint);
2898	    break;
2899        case XML_REGEXP_PUNCT_CLOSE:
2900	    ret = xmlUCSIsCatPe(codepoint);
2901	    break;
2902        case XML_REGEXP_PUNCT_INITQUOTE:
2903	    ret = xmlUCSIsCatPi(codepoint);
2904	    break;
2905        case XML_REGEXP_PUNCT_FINQUOTE:
2906	    ret = xmlUCSIsCatPf(codepoint);
2907	    break;
2908        case XML_REGEXP_PUNCT_OTHERS:
2909	    ret = xmlUCSIsCatPo(codepoint);
2910	    break;
2911        case XML_REGEXP_SEPAR:
2912	    ret = xmlUCSIsCatZ(codepoint);
2913	    break;
2914        case XML_REGEXP_SEPAR_SPACE:
2915	    ret = xmlUCSIsCatZs(codepoint);
2916	    break;
2917        case XML_REGEXP_SEPAR_LINE:
2918	    ret = xmlUCSIsCatZl(codepoint);
2919	    break;
2920        case XML_REGEXP_SEPAR_PARA:
2921	    ret = xmlUCSIsCatZp(codepoint);
2922	    break;
2923        case XML_REGEXP_SYMBOL:
2924	    ret = xmlUCSIsCatS(codepoint);
2925	    break;
2926        case XML_REGEXP_SYMBOL_MATH:
2927	    ret = xmlUCSIsCatSm(codepoint);
2928	    break;
2929        case XML_REGEXP_SYMBOL_CURRENCY:
2930	    ret = xmlUCSIsCatSc(codepoint);
2931	    break;
2932        case XML_REGEXP_SYMBOL_MODIFIER:
2933	    ret = xmlUCSIsCatSk(codepoint);
2934	    break;
2935        case XML_REGEXP_SYMBOL_OTHERS:
2936	    ret = xmlUCSIsCatSo(codepoint);
2937	    break;
2938        case XML_REGEXP_OTHER:
2939	    ret = xmlUCSIsCatC(codepoint);
2940	    break;
2941        case XML_REGEXP_OTHER_CONTROL:
2942	    ret = xmlUCSIsCatCc(codepoint);
2943	    break;
2944        case XML_REGEXP_OTHER_FORMAT:
2945	    ret = xmlUCSIsCatCf(codepoint);
2946	    break;
2947        case XML_REGEXP_OTHER_PRIVATE:
2948	    ret = xmlUCSIsCatCo(codepoint);
2949	    break;
2950        case XML_REGEXP_OTHER_NA:
2951	    /* ret = xmlUCSIsCatCn(codepoint); */
2952	    /* Seems it doesn't exist anymore in recent Unicode releases */
2953	    ret = 0;
2954	    break;
2955        case XML_REGEXP_BLOCK_NAME:
2956	    ret = xmlUCSIsBlock(codepoint, (const char *) blockName);
2957	    break;
2958    }
2959    if (neg)
2960	return(!ret);
2961    return(ret);
2962}
2963
2964static int
2965xmlRegCheckCharacter(xmlRegAtomPtr atom, int codepoint) {
2966    int i, ret = 0;
2967    xmlRegRangePtr range;
2968
2969    if ((atom == NULL) || (!IS_CHAR(codepoint)))
2970	return(-1);
2971
2972    switch (atom->type) {
2973        case XML_REGEXP_SUBREG:
2974        case XML_REGEXP_EPSILON:
2975	    return(-1);
2976        case XML_REGEXP_CHARVAL:
2977            return(codepoint == atom->codepoint);
2978        case XML_REGEXP_RANGES: {
2979	    int accept = 0;
2980
2981	    for (i = 0;i < atom->nbRanges;i++) {
2982		range = atom->ranges[i];
2983		if (range->neg == 2) {
2984		    ret = xmlRegCheckCharacterRange(range->type, codepoint,
2985						0, range->start, range->end,
2986						range->blockName);
2987		    if (ret != 0)
2988			return(0); /* excluded char */
2989		} else if (range->neg) {
2990		    ret = xmlRegCheckCharacterRange(range->type, codepoint,
2991						0, range->start, range->end,
2992						range->blockName);
2993		    if (ret == 0)
2994		        accept = 1;
2995		    else
2996		        return(0);
2997		} else {
2998		    ret = xmlRegCheckCharacterRange(range->type, codepoint,
2999						0, range->start, range->end,
3000						range->blockName);
3001		    if (ret != 0)
3002			accept = 1; /* might still be excluded */
3003		}
3004	    }
3005	    return(accept);
3006	}
3007        case XML_REGEXP_STRING:
3008	    printf("TODO: XML_REGEXP_STRING\n");
3009	    return(-1);
3010        case XML_REGEXP_ANYCHAR:
3011        case XML_REGEXP_ANYSPACE:
3012        case XML_REGEXP_NOTSPACE:
3013        case XML_REGEXP_INITNAME:
3014        case XML_REGEXP_NOTINITNAME:
3015        case XML_REGEXP_NAMECHAR:
3016        case XML_REGEXP_NOTNAMECHAR:
3017        case XML_REGEXP_DECIMAL:
3018        case XML_REGEXP_NOTDECIMAL:
3019        case XML_REGEXP_REALCHAR:
3020        case XML_REGEXP_NOTREALCHAR:
3021        case XML_REGEXP_LETTER:
3022        case XML_REGEXP_LETTER_UPPERCASE:
3023        case XML_REGEXP_LETTER_LOWERCASE:
3024        case XML_REGEXP_LETTER_TITLECASE:
3025        case XML_REGEXP_LETTER_MODIFIER:
3026        case XML_REGEXP_LETTER_OTHERS:
3027        case XML_REGEXP_MARK:
3028        case XML_REGEXP_MARK_NONSPACING:
3029        case XML_REGEXP_MARK_SPACECOMBINING:
3030        case XML_REGEXP_MARK_ENCLOSING:
3031        case XML_REGEXP_NUMBER:
3032        case XML_REGEXP_NUMBER_DECIMAL:
3033        case XML_REGEXP_NUMBER_LETTER:
3034        case XML_REGEXP_NUMBER_OTHERS:
3035        case XML_REGEXP_PUNCT:
3036        case XML_REGEXP_PUNCT_CONNECTOR:
3037        case XML_REGEXP_PUNCT_DASH:
3038        case XML_REGEXP_PUNCT_OPEN:
3039        case XML_REGEXP_PUNCT_CLOSE:
3040        case XML_REGEXP_PUNCT_INITQUOTE:
3041        case XML_REGEXP_PUNCT_FINQUOTE:
3042        case XML_REGEXP_PUNCT_OTHERS:
3043        case XML_REGEXP_SEPAR:
3044        case XML_REGEXP_SEPAR_SPACE:
3045        case XML_REGEXP_SEPAR_LINE:
3046        case XML_REGEXP_SEPAR_PARA:
3047        case XML_REGEXP_SYMBOL:
3048        case XML_REGEXP_SYMBOL_MATH:
3049        case XML_REGEXP_SYMBOL_CURRENCY:
3050        case XML_REGEXP_SYMBOL_MODIFIER:
3051        case XML_REGEXP_SYMBOL_OTHERS:
3052        case XML_REGEXP_OTHER:
3053        case XML_REGEXP_OTHER_CONTROL:
3054        case XML_REGEXP_OTHER_FORMAT:
3055        case XML_REGEXP_OTHER_PRIVATE:
3056        case XML_REGEXP_OTHER_NA:
3057	case XML_REGEXP_BLOCK_NAME:
3058	    ret = xmlRegCheckCharacterRange(atom->type, codepoint, 0, 0, 0,
3059		                            (const xmlChar *)atom->valuep);
3060	    if (atom->neg)
3061		ret = !ret;
3062	    break;
3063    }
3064    return(ret);
3065}
3066
3067/************************************************************************
3068 *									*
3069 *	Saving and restoring state of an execution context		*
3070 *									*
3071 ************************************************************************/
3072
3073#ifdef DEBUG_REGEXP_EXEC
3074static void
3075xmlFARegDebugExec(xmlRegExecCtxtPtr exec) {
3076    printf("state: %d:%d:idx %d", exec->state->no, exec->transno, exec->index);
3077    if (exec->inputStack != NULL) {
3078	int i;
3079	printf(": ");
3080	for (i = 0;(i < 3) && (i < exec->inputStackNr);i++)
3081	    printf("%s ", (const char *)
3082	           exec->inputStack[exec->inputStackNr - (i + 1)].value);
3083    } else {
3084	printf(": %s", &(exec->inputString[exec->index]));
3085    }
3086    printf("\n");
3087}
3088#endif
3089
3090static void
3091xmlFARegExecSave(xmlRegExecCtxtPtr exec) {
3092#ifdef DEBUG_REGEXP_EXEC
3093    printf("saving ");
3094    exec->transno++;
3095    xmlFARegDebugExec(exec);
3096    exec->transno--;
3097#endif
3098#ifdef MAX_PUSH
3099    if (exec->nbPush > MAX_PUSH) {
3100        return;
3101    }
3102    exec->nbPush++;
3103#endif
3104
3105    if (exec->maxRollbacks == 0) {
3106	exec->maxRollbacks = 4;
3107	exec->rollbacks = (xmlRegExecRollback *) xmlMalloc(exec->maxRollbacks *
3108		                             sizeof(xmlRegExecRollback));
3109	if (exec->rollbacks == NULL) {
3110	    xmlRegexpErrMemory(NULL, "saving regexp");
3111	    exec->maxRollbacks = 0;
3112	    return;
3113	}
3114	memset(exec->rollbacks, 0,
3115	       exec->maxRollbacks * sizeof(xmlRegExecRollback));
3116    } else if (exec->nbRollbacks >= exec->maxRollbacks) {
3117	xmlRegExecRollback *tmp;
3118	int len = exec->maxRollbacks;
3119
3120	exec->maxRollbacks *= 2;
3121	tmp = (xmlRegExecRollback *) xmlRealloc(exec->rollbacks,
3122			exec->maxRollbacks * sizeof(xmlRegExecRollback));
3123	if (tmp == NULL) {
3124	    xmlRegexpErrMemory(NULL, "saving regexp");
3125	    exec->maxRollbacks /= 2;
3126	    return;
3127	}
3128	exec->rollbacks = tmp;
3129	tmp = &exec->rollbacks[len];
3130	memset(tmp, 0, (exec->maxRollbacks - len) * sizeof(xmlRegExecRollback));
3131    }
3132    exec->rollbacks[exec->nbRollbacks].state = exec->state;
3133    exec->rollbacks[exec->nbRollbacks].index = exec->index;
3134    exec->rollbacks[exec->nbRollbacks].nextbranch = exec->transno + 1;
3135    if (exec->comp->nbCounters > 0) {
3136	if (exec->rollbacks[exec->nbRollbacks].counts == NULL) {
3137	    exec->rollbacks[exec->nbRollbacks].counts = (int *)
3138		xmlMalloc(exec->comp->nbCounters * sizeof(int));
3139	    if (exec->rollbacks[exec->nbRollbacks].counts == NULL) {
3140		xmlRegexpErrMemory(NULL, "saving regexp");
3141		exec->status = -5;
3142		return;
3143	    }
3144	}
3145	memcpy(exec->rollbacks[exec->nbRollbacks].counts, exec->counts,
3146	       exec->comp->nbCounters * sizeof(int));
3147    }
3148    exec->nbRollbacks++;
3149}
3150
3151static void
3152xmlFARegExecRollBack(xmlRegExecCtxtPtr exec) {
3153    if (exec->nbRollbacks <= 0) {
3154	exec->status = -1;
3155#ifdef DEBUG_REGEXP_EXEC
3156	printf("rollback failed on empty stack\n");
3157#endif
3158	return;
3159    }
3160    exec->nbRollbacks--;
3161    exec->state = exec->rollbacks[exec->nbRollbacks].state;
3162    exec->index = exec->rollbacks[exec->nbRollbacks].index;
3163    exec->transno = exec->rollbacks[exec->nbRollbacks].nextbranch;
3164    if (exec->comp->nbCounters > 0) {
3165	if (exec->rollbacks[exec->nbRollbacks].counts == NULL) {
3166	    fprintf(stderr, "exec save: allocation failed");
3167	    exec->status = -6;
3168	    return;
3169	}
3170	if (exec->counts) {
3171	    memcpy(exec->counts, exec->rollbacks[exec->nbRollbacks].counts,
3172	       exec->comp->nbCounters * sizeof(int));
3173	}
3174    }
3175
3176#ifdef DEBUG_REGEXP_EXEC
3177    printf("restored ");
3178    xmlFARegDebugExec(exec);
3179#endif
3180}
3181
3182/************************************************************************
3183 *									*
3184 *	Verifier, running an input against a compiled regexp		*
3185 *									*
3186 ************************************************************************/
3187
3188static int
3189xmlFARegExec(xmlRegexpPtr comp, const xmlChar *content) {
3190    xmlRegExecCtxt execval;
3191    xmlRegExecCtxtPtr exec = &execval;
3192    int ret, codepoint = 0, len, deter;
3193
3194    exec->inputString = content;
3195    exec->index = 0;
3196    exec->nbPush = 0;
3197    exec->determinist = 1;
3198    exec->maxRollbacks = 0;
3199    exec->nbRollbacks = 0;
3200    exec->rollbacks = NULL;
3201    exec->status = 0;
3202    exec->comp = comp;
3203    exec->state = comp->states[0];
3204    exec->transno = 0;
3205    exec->transcount = 0;
3206    exec->inputStack = NULL;
3207    exec->inputStackMax = 0;
3208    if (comp->nbCounters > 0) {
3209	exec->counts = (int *) xmlMalloc(comp->nbCounters * sizeof(int));
3210	if (exec->counts == NULL) {
3211	    xmlRegexpErrMemory(NULL, "running regexp");
3212	    return(-1);
3213	}
3214        memset(exec->counts, 0, comp->nbCounters * sizeof(int));
3215    } else
3216	exec->counts = NULL;
3217    while ((exec->status == 0) && (exec->state != NULL) &&
3218	   ((exec->inputString[exec->index] != 0) ||
3219	    ((exec->state != NULL) &&
3220	     (exec->state->type != XML_REGEXP_FINAL_STATE)))) {
3221	xmlRegTransPtr trans;
3222	xmlRegAtomPtr atom;
3223
3224	/*
3225	 * If end of input on non-terminal state, rollback, however we may
3226	 * still have epsilon like transition for counted transitions
3227	 * on counters, in that case don't break too early.  Additionally,
3228	 * if we are working on a range like "AB{0,2}", where B is not present,
3229	 * we don't want to break.
3230	 */
3231	len = 1;
3232	if ((exec->inputString[exec->index] == 0) && (exec->counts == NULL)) {
3233	    /*
3234	     * if there is a transition, we must check if
3235	     *  atom allows minOccurs of 0
3236	     */
3237	    if (exec->transno < exec->state->nbTrans) {
3238	        trans = &exec->state->trans[exec->transno];
3239		if (trans->to >=0) {
3240		    atom = trans->atom;
3241		    if (!((atom->min == 0) && (atom->max > 0)))
3242		        goto rollback;
3243		}
3244	    } else
3245	        goto rollback;
3246	}
3247
3248	exec->transcount = 0;
3249	for (;exec->transno < exec->state->nbTrans;exec->transno++) {
3250	    trans = &exec->state->trans[exec->transno];
3251	    if (trans->to < 0)
3252		continue;
3253	    atom = trans->atom;
3254	    ret = 0;
3255	    deter = 1;
3256	    if (trans->count >= 0) {
3257		int count;
3258		xmlRegCounterPtr counter;
3259
3260		if (exec->counts == NULL) {
3261		    exec->status = -1;
3262		    goto error;
3263		}
3264		/*
3265		 * A counted transition.
3266		 */
3267
3268		count = exec->counts[trans->count];
3269		counter = &exec->comp->counters[trans->count];
3270#ifdef DEBUG_REGEXP_EXEC
3271		printf("testing count %d: val %d, min %d, max %d\n",
3272		       trans->count, count, counter->min,  counter->max);
3273#endif
3274		ret = ((count >= counter->min) && (count <= counter->max));
3275		if ((ret) && (counter->min != counter->max))
3276		    deter = 0;
3277	    } else if (atom == NULL) {
3278		fprintf(stderr, "epsilon transition left at runtime\n");
3279		exec->status = -2;
3280		break;
3281	    } else if (exec->inputString[exec->index] != 0) {
3282                codepoint = CUR_SCHAR(&(exec->inputString[exec->index]), len);
3283		ret = xmlRegCheckCharacter(atom, codepoint);
3284		if ((ret == 1) && (atom->min >= 0) && (atom->max > 0)) {
3285		    xmlRegStatePtr to = comp->states[trans->to];
3286
3287		    /*
3288		     * this is a multiple input sequence
3289		     * If there is a counter associated increment it now.
3290		     * before potentially saving and rollback
3291		     * do not increment if the counter is already over the
3292		     * maximum limit in which case get to next transition
3293		     */
3294		    if (trans->counter >= 0) {
3295			xmlRegCounterPtr counter;
3296
3297			if ((exec->counts == NULL) ||
3298			    (exec->comp == NULL) ||
3299			    (exec->comp->counters == NULL)) {
3300			    exec->status = -1;
3301			    goto error;
3302			}
3303			counter = &exec->comp->counters[trans->counter];
3304			if (exec->counts[trans->counter] >= counter->max)
3305			    continue; /* for loop on transitions */
3306
3307#ifdef DEBUG_REGEXP_EXEC
3308			printf("Increasing count %d\n", trans->counter);
3309#endif
3310			exec->counts[trans->counter]++;
3311		    }
3312		    if (exec->state->nbTrans > exec->transno + 1) {
3313			xmlFARegExecSave(exec);
3314		    }
3315		    exec->transcount = 1;
3316		    do {
3317			/*
3318			 * Try to progress as much as possible on the input
3319			 */
3320			if (exec->transcount == atom->max) {
3321			    break;
3322			}
3323			exec->index += len;
3324			/*
3325			 * End of input: stop here
3326			 */
3327			if (exec->inputString[exec->index] == 0) {
3328			    exec->index -= len;
3329			    break;
3330			}
3331			if (exec->transcount >= atom->min) {
3332			    int transno = exec->transno;
3333			    xmlRegStatePtr state = exec->state;
3334
3335			    /*
3336			     * The transition is acceptable save it
3337			     */
3338			    exec->transno = -1; /* trick */
3339			    exec->state = to;
3340			    xmlFARegExecSave(exec);
3341			    exec->transno = transno;
3342			    exec->state = state;
3343			}
3344			codepoint = CUR_SCHAR(&(exec->inputString[exec->index]),
3345				              len);
3346			ret = xmlRegCheckCharacter(atom, codepoint);
3347			exec->transcount++;
3348		    } while (ret == 1);
3349		    if (exec->transcount < atom->min)
3350			ret = 0;
3351
3352		    /*
3353		     * If the last check failed but one transition was found
3354		     * possible, rollback
3355		     */
3356		    if (ret < 0)
3357			ret = 0;
3358		    if (ret == 0) {
3359			goto rollback;
3360		    }
3361		    if (trans->counter >= 0) {
3362			if (exec->counts == NULL) {
3363			    exec->status = -1;
3364			    goto error;
3365			}
3366#ifdef DEBUG_REGEXP_EXEC
3367			printf("Decreasing count %d\n", trans->counter);
3368#endif
3369			exec->counts[trans->counter]--;
3370		    }
3371		} else if ((ret == 0) && (atom->min == 0) && (atom->max > 0)) {
3372		    /*
3373		     * we don't match on the codepoint, but minOccurs of 0
3374		     * says that's ok.  Setting len to 0 inhibits stepping
3375		     * over the codepoint.
3376		     */
3377		    exec->transcount = 1;
3378		    len = 0;
3379		    ret = 1;
3380		}
3381	    } else if ((atom->min == 0) && (atom->max > 0)) {
3382	        /* another spot to match when minOccurs is 0 */
3383		exec->transcount = 1;
3384		len = 0;
3385		ret = 1;
3386	    }
3387	    if (ret == 1) {
3388		if ((trans->nd == 1) ||
3389		    ((trans->count >= 0) && (deter == 0) &&
3390		     (exec->state->nbTrans > exec->transno + 1))) {
3391#ifdef DEBUG_REGEXP_EXEC
3392		    if (trans->nd == 1)
3393		        printf("Saving on nd transition atom %d for %c at %d\n",
3394			       trans->atom->no, codepoint, exec->index);
3395		    else
3396		        printf("Saving on counted transition count %d for %c at %d\n",
3397			       trans->count, codepoint, exec->index);
3398#endif
3399		    xmlFARegExecSave(exec);
3400		}
3401		if (trans->counter >= 0) {
3402		    xmlRegCounterPtr counter;
3403
3404                    /* make sure we don't go over the counter maximum value */
3405		    if ((exec->counts == NULL) ||
3406			(exec->comp == NULL) ||
3407			(exec->comp->counters == NULL)) {
3408			exec->status = -1;
3409			goto error;
3410		    }
3411		    counter = &exec->comp->counters[trans->counter];
3412		    if (exec->counts[trans->counter] >= counter->max)
3413			continue; /* for loop on transitions */
3414#ifdef DEBUG_REGEXP_EXEC
3415		    printf("Increasing count %d\n", trans->counter);
3416#endif
3417		    exec->counts[trans->counter]++;
3418		}
3419		if ((trans->count >= 0) &&
3420		    (trans->count < REGEXP_ALL_COUNTER)) {
3421		    if (exec->counts == NULL) {
3422		        exec->status = -1;
3423			goto error;
3424		    }
3425#ifdef DEBUG_REGEXP_EXEC
3426		    printf("resetting count %d on transition\n",
3427		           trans->count);
3428#endif
3429		    exec->counts[trans->count] = 0;
3430		}
3431#ifdef DEBUG_REGEXP_EXEC
3432		printf("entering state %d\n", trans->to);
3433#endif
3434		exec->state = comp->states[trans->to];
3435		exec->transno = 0;
3436		if (trans->atom != NULL) {
3437		    exec->index += len;
3438		}
3439		goto progress;
3440	    } else if (ret < 0) {
3441		exec->status = -4;
3442		break;
3443	    }
3444	}
3445	if ((exec->transno != 0) || (exec->state->nbTrans == 0)) {
3446rollback:
3447	    /*
3448	     * Failed to find a way out
3449	     */
3450	    exec->determinist = 0;
3451#ifdef DEBUG_REGEXP_EXEC
3452	    printf("rollback from state %d on %d:%c\n", exec->state->no,
3453	           codepoint,codepoint);
3454#endif
3455	    xmlFARegExecRollBack(exec);
3456	}
3457progress:
3458	continue;
3459    }
3460error:
3461    if (exec->rollbacks != NULL) {
3462	if (exec->counts != NULL) {
3463	    int i;
3464
3465	    for (i = 0;i < exec->maxRollbacks;i++)
3466		if (exec->rollbacks[i].counts != NULL)
3467		    xmlFree(exec->rollbacks[i].counts);
3468	}
3469	xmlFree(exec->rollbacks);
3470    }
3471    if (exec->state == NULL)
3472        return(-1);
3473    if (exec->counts != NULL)
3474	xmlFree(exec->counts);
3475    if (exec->status == 0)
3476	return(1);
3477    if (exec->status == -1) {
3478	if (exec->nbPush > MAX_PUSH)
3479	    return(-1);
3480	return(0);
3481    }
3482    return(exec->status);
3483}
3484
3485/************************************************************************
3486 *									*
3487 *	Progressive interface to the verifier one atom at a time	*
3488 *									*
3489 ************************************************************************/
3490#ifdef DEBUG_ERR
3491static void testerr(xmlRegExecCtxtPtr exec);
3492#endif
3493
3494/**
3495 * xmlRegNewExecCtxt:
3496 * @comp: a precompiled regular expression
3497 * @callback: a callback function used for handling progresses in the
3498 *            automata matching phase
3499 * @data: the context data associated to the callback in this context
3500 *
3501 * Build a context used for progressive evaluation of a regexp.
3502 *
3503 * Returns the new context
3504 */
3505xmlRegExecCtxtPtr
3506xmlRegNewExecCtxt(xmlRegexpPtr comp, xmlRegExecCallbacks callback, void *data) {
3507    xmlRegExecCtxtPtr exec;
3508
3509    if (comp == NULL)
3510	return(NULL);
3511    if ((comp->compact == NULL) && (comp->states == NULL))
3512        return(NULL);
3513    exec = (xmlRegExecCtxtPtr) xmlMalloc(sizeof(xmlRegExecCtxt));
3514    if (exec == NULL) {
3515	xmlRegexpErrMemory(NULL, "creating execution context");
3516	return(NULL);
3517    }
3518    memset(exec, 0, sizeof(xmlRegExecCtxt));
3519    exec->inputString = NULL;
3520    exec->index = 0;
3521    exec->determinist = 1;
3522    exec->maxRollbacks = 0;
3523    exec->nbRollbacks = 0;
3524    exec->rollbacks = NULL;
3525    exec->status = 0;
3526    exec->comp = comp;
3527    if (comp->compact == NULL)
3528	exec->state = comp->states[0];
3529    exec->transno = 0;
3530    exec->transcount = 0;
3531    exec->callback = callback;
3532    exec->data = data;
3533    if (comp->nbCounters > 0) {
3534        /*
3535	 * For error handling, exec->counts is allocated twice the size
3536	 * the second half is used to store the data in case of rollback
3537	 */
3538	exec->counts = (int *) xmlMalloc(comp->nbCounters * sizeof(int)
3539	                                 * 2);
3540	if (exec->counts == NULL) {
3541	    xmlRegexpErrMemory(NULL, "creating execution context");
3542	    xmlFree(exec);
3543	    return(NULL);
3544	}
3545        memset(exec->counts, 0, comp->nbCounters * sizeof(int) * 2);
3546	exec->errCounts = &exec->counts[comp->nbCounters];
3547    } else {
3548	exec->counts = NULL;
3549	exec->errCounts = NULL;
3550    }
3551    exec->inputStackMax = 0;
3552    exec->inputStackNr = 0;
3553    exec->inputStack = NULL;
3554    exec->errStateNo = -1;
3555    exec->errString = NULL;
3556    exec->nbPush = 0;
3557    return(exec);
3558}
3559
3560/**
3561 * xmlRegFreeExecCtxt:
3562 * @exec: a regular expression evaulation context
3563 *
3564 * Free the structures associated to a regular expression evaulation context.
3565 */
3566void
3567xmlRegFreeExecCtxt(xmlRegExecCtxtPtr exec) {
3568    if (exec == NULL)
3569	return;
3570
3571    if (exec->rollbacks != NULL) {
3572	if (exec->counts != NULL) {
3573	    int i;
3574
3575	    for (i = 0;i < exec->maxRollbacks;i++)
3576		if (exec->rollbacks[i].counts != NULL)
3577		    xmlFree(exec->rollbacks[i].counts);
3578	}
3579	xmlFree(exec->rollbacks);
3580    }
3581    if (exec->counts != NULL)
3582	xmlFree(exec->counts);
3583    if (exec->inputStack != NULL) {
3584	int i;
3585
3586	for (i = 0;i < exec->inputStackNr;i++) {
3587	    if (exec->inputStack[i].value != NULL)
3588		xmlFree(exec->inputStack[i].value);
3589	}
3590	xmlFree(exec->inputStack);
3591    }
3592    if (exec->errString != NULL)
3593        xmlFree(exec->errString);
3594    xmlFree(exec);
3595}
3596
3597static void
3598xmlFARegExecSaveInputString(xmlRegExecCtxtPtr exec, const xmlChar *value,
3599	                    void *data) {
3600#ifdef DEBUG_PUSH
3601    printf("saving value: %d:%s\n", exec->inputStackNr, value);
3602#endif
3603    if (exec->inputStackMax == 0) {
3604	exec->inputStackMax = 4;
3605	exec->inputStack = (xmlRegInputTokenPtr)
3606	    xmlMalloc(exec->inputStackMax * sizeof(xmlRegInputToken));
3607	if (exec->inputStack == NULL) {
3608	    xmlRegexpErrMemory(NULL, "pushing input string");
3609	    exec->inputStackMax = 0;
3610	    return;
3611	}
3612    } else if (exec->inputStackNr + 1 >= exec->inputStackMax) {
3613	xmlRegInputTokenPtr tmp;
3614
3615	exec->inputStackMax *= 2;
3616	tmp = (xmlRegInputTokenPtr) xmlRealloc(exec->inputStack,
3617			exec->inputStackMax * sizeof(xmlRegInputToken));
3618	if (tmp == NULL) {
3619	    xmlRegexpErrMemory(NULL, "pushing input string");
3620	    exec->inputStackMax /= 2;
3621	    return;
3622	}
3623	exec->inputStack = tmp;
3624    }
3625    exec->inputStack[exec->inputStackNr].value = xmlStrdup(value);
3626    exec->inputStack[exec->inputStackNr].data = data;
3627    exec->inputStackNr++;
3628    exec->inputStack[exec->inputStackNr].value = NULL;
3629    exec->inputStack[exec->inputStackNr].data = NULL;
3630}
3631
3632/**
3633 * xmlRegStrEqualWildcard:
3634 * @expStr:  the string to be evaluated
3635 * @valStr:  the validation string
3636 *
3637 * Checks if both strings are equal or have the same content. "*"
3638 * can be used as a wildcard in @valStr; "|" is used as a seperator of
3639 * substrings in both @expStr and @valStr.
3640 *
3641 * Returns 1 if the comparison is satisfied and the number of substrings
3642 * is equal, 0 otherwise.
3643 */
3644
3645static int
3646xmlRegStrEqualWildcard(const xmlChar *expStr, const xmlChar *valStr) {
3647    if (expStr == valStr) return(1);
3648    if (expStr == NULL) return(0);
3649    if (valStr == NULL) return(0);
3650    do {
3651	/*
3652	* Eval if we have a wildcard for the current item.
3653	*/
3654        if (*expStr != *valStr) {
3655	    /* if one of them starts with a wildcard make valStr be it */
3656	    if (*valStr == '*') {
3657	        const xmlChar *tmp;
3658
3659		tmp = valStr;
3660		valStr = expStr;
3661		expStr = tmp;
3662	    }
3663	    if ((*valStr != 0) && (*expStr != 0) && (*expStr++ == '*')) {
3664		do {
3665		    if (*valStr == XML_REG_STRING_SEPARATOR)
3666			break;
3667		    valStr++;
3668		} while (*valStr != 0);
3669		continue;
3670	    } else
3671		return(0);
3672	}
3673	expStr++;
3674	valStr++;
3675    } while (*valStr != 0);
3676    if (*expStr != 0)
3677	return (0);
3678    else
3679	return (1);
3680}
3681
3682/**
3683 * xmlRegCompactPushString:
3684 * @exec: a regexp execution context
3685 * @comp:  the precompiled exec with a compact table
3686 * @value: a string token input
3687 * @data: data associated to the token to reuse in callbacks
3688 *
3689 * Push one input token in the execution context
3690 *
3691 * Returns: 1 if the regexp reached a final state, 0 if non-final, and
3692 *     a negative value in case of error.
3693 */
3694static int
3695xmlRegCompactPushString(xmlRegExecCtxtPtr exec,
3696	                xmlRegexpPtr comp,
3697	                const xmlChar *value,
3698	                void *data) {
3699    int state = exec->index;
3700    int i, target;
3701
3702    if ((comp == NULL) || (comp->compact == NULL) || (comp->stringMap == NULL))
3703	return(-1);
3704
3705    if (value == NULL) {
3706	/*
3707	 * are we at a final state ?
3708	 */
3709	if (comp->compact[state * (comp->nbstrings + 1)] ==
3710            XML_REGEXP_FINAL_STATE)
3711	    return(1);
3712	return(0);
3713    }
3714
3715#ifdef DEBUG_PUSH
3716    printf("value pushed: %s\n", value);
3717#endif
3718
3719    /*
3720     * Examine all outside transitions from current state
3721     */
3722    for (i = 0;i < comp->nbstrings;i++) {
3723	target = comp->compact[state * (comp->nbstrings + 1) + i + 1];
3724	if ((target > 0) && (target <= comp->nbstates)) {
3725	    target--; /* to avoid 0 */
3726	    if (xmlRegStrEqualWildcard(comp->stringMap[i], value)) {
3727		exec->index = target;
3728		if ((exec->callback != NULL) && (comp->transdata != NULL)) {
3729		    exec->callback(exec->data, value,
3730			  comp->transdata[state * comp->nbstrings + i], data);
3731		}
3732#ifdef DEBUG_PUSH
3733		printf("entering state %d\n", target);
3734#endif
3735		if (comp->compact[target * (comp->nbstrings + 1)] ==
3736		    XML_REGEXP_SINK_STATE)
3737		    goto error;
3738
3739		if (comp->compact[target * (comp->nbstrings + 1)] ==
3740		    XML_REGEXP_FINAL_STATE)
3741		    return(1);
3742		return(0);
3743	    }
3744	}
3745    }
3746    /*
3747     * Failed to find an exit transition out from current state for the
3748     * current token
3749     */
3750#ifdef DEBUG_PUSH
3751    printf("failed to find a transition for %s on state %d\n", value, state);
3752#endif
3753error:
3754    if (exec->errString != NULL)
3755        xmlFree(exec->errString);
3756    exec->errString = xmlStrdup(value);
3757    exec->errStateNo = state;
3758    exec->status = -1;
3759#ifdef DEBUG_ERR
3760    testerr(exec);
3761#endif
3762    return(-1);
3763}
3764
3765/**
3766 * xmlRegExecPushStringInternal:
3767 * @exec: a regexp execution context or NULL to indicate the end
3768 * @value: a string token input
3769 * @data: data associated to the token to reuse in callbacks
3770 * @compound: value was assembled from 2 strings
3771 *
3772 * Push one input token in the execution context
3773 *
3774 * Returns: 1 if the regexp reached a final state, 0 if non-final, and
3775 *     a negative value in case of error.
3776 */
3777static int
3778xmlRegExecPushStringInternal(xmlRegExecCtxtPtr exec, const xmlChar *value,
3779	                     void *data, int compound) {
3780    xmlRegTransPtr trans;
3781    xmlRegAtomPtr atom;
3782    int ret;
3783    int final = 0;
3784    int progress = 1;
3785
3786    if (exec == NULL)
3787	return(-1);
3788    if (exec->comp == NULL)
3789	return(-1);
3790    if (exec->status != 0)
3791	return(exec->status);
3792
3793    if (exec->comp->compact != NULL)
3794	return(xmlRegCompactPushString(exec, exec->comp, value, data));
3795
3796    if (value == NULL) {
3797        if (exec->state->type == XML_REGEXP_FINAL_STATE)
3798	    return(1);
3799	final = 1;
3800    }
3801
3802#ifdef DEBUG_PUSH
3803    printf("value pushed: %s\n", value);
3804#endif
3805    /*
3806     * If we have an active rollback stack push the new value there
3807     * and get back to where we were left
3808     */
3809    if ((value != NULL) && (exec->inputStackNr > 0)) {
3810	xmlFARegExecSaveInputString(exec, value, data);
3811	value = exec->inputStack[exec->index].value;
3812	data = exec->inputStack[exec->index].data;
3813#ifdef DEBUG_PUSH
3814	printf("value loaded: %s\n", value);
3815#endif
3816    }
3817
3818    while ((exec->status == 0) &&
3819	   ((value != NULL) ||
3820	    ((final == 1) &&
3821	     (exec->state->type != XML_REGEXP_FINAL_STATE)))) {
3822
3823	/*
3824	 * End of input on non-terminal state, rollback, however we may
3825	 * still have epsilon like transition for counted transitions
3826	 * on counters, in that case don't break too early.
3827	 */
3828	if ((value == NULL) && (exec->counts == NULL))
3829	    goto rollback;
3830
3831	exec->transcount = 0;
3832	for (;exec->transno < exec->state->nbTrans;exec->transno++) {
3833	    trans = &exec->state->trans[exec->transno];
3834	    if (trans->to < 0)
3835		continue;
3836	    atom = trans->atom;
3837	    ret = 0;
3838	    if (trans->count == REGEXP_ALL_LAX_COUNTER) {
3839		int i;
3840		int count;
3841		xmlRegTransPtr t;
3842		xmlRegCounterPtr counter;
3843
3844		ret = 0;
3845
3846#ifdef DEBUG_PUSH
3847		printf("testing all lax %d\n", trans->count);
3848#endif
3849		/*
3850		 * Check all counted transitions from the current state
3851		 */
3852		if ((value == NULL) && (final)) {
3853		    ret = 1;
3854		} else if (value != NULL) {
3855		    for (i = 0;i < exec->state->nbTrans;i++) {
3856			t = &exec->state->trans[i];
3857			if ((t->counter < 0) || (t == trans))
3858			    continue;
3859			counter = &exec->comp->counters[t->counter];
3860			count = exec->counts[t->counter];
3861			if ((count < counter->max) &&
3862		            (t->atom != NULL) &&
3863			    (xmlStrEqual(value, t->atom->valuep))) {
3864			    ret = 0;
3865			    break;
3866			}
3867			if ((count >= counter->min) &&
3868			    (count < counter->max) &&
3869			    (t->atom != NULL) &&
3870			    (xmlStrEqual(value, t->atom->valuep))) {
3871			    ret = 1;
3872			    break;
3873			}
3874		    }
3875		}
3876	    } else if (trans->count == REGEXP_ALL_COUNTER) {
3877		int i;
3878		int count;
3879		xmlRegTransPtr t;
3880		xmlRegCounterPtr counter;
3881
3882		ret = 1;
3883
3884#ifdef DEBUG_PUSH
3885		printf("testing all %d\n", trans->count);
3886#endif
3887		/*
3888		 * Check all counted transitions from the current state
3889		 */
3890		for (i = 0;i < exec->state->nbTrans;i++) {
3891                    t = &exec->state->trans[i];
3892		    if ((t->counter < 0) || (t == trans))
3893			continue;
3894                    counter = &exec->comp->counters[t->counter];
3895		    count = exec->counts[t->counter];
3896		    if ((count < counter->min) || (count > counter->max)) {
3897			ret = 0;
3898			break;
3899		    }
3900		}
3901	    } else if (trans->count >= 0) {
3902		int count;
3903		xmlRegCounterPtr counter;
3904
3905		/*
3906		 * A counted transition.
3907		 */
3908
3909		count = exec->counts[trans->count];
3910		counter = &exec->comp->counters[trans->count];
3911#ifdef DEBUG_PUSH
3912		printf("testing count %d: val %d, min %d, max %d\n",
3913		       trans->count, count, counter->min,  counter->max);
3914#endif
3915		ret = ((count >= counter->min) && (count <= counter->max));
3916	    } else if (atom == NULL) {
3917		fprintf(stderr, "epsilon transition left at runtime\n");
3918		exec->status = -2;
3919		break;
3920	    } else if (value != NULL) {
3921		ret = xmlRegStrEqualWildcard(atom->valuep, value);
3922		if (atom->neg) {
3923		    ret = !ret;
3924		    if (!compound)
3925		        ret = 0;
3926		}
3927		if ((ret == 1) && (trans->counter >= 0)) {
3928		    xmlRegCounterPtr counter;
3929		    int count;
3930
3931		    count = exec->counts[trans->counter];
3932		    counter = &exec->comp->counters[trans->counter];
3933		    if (count >= counter->max)
3934			ret = 0;
3935		}
3936
3937		if ((ret == 1) && (atom->min > 0) && (atom->max > 0)) {
3938		    xmlRegStatePtr to = exec->comp->states[trans->to];
3939
3940		    /*
3941		     * this is a multiple input sequence
3942		     */
3943		    if (exec->state->nbTrans > exec->transno + 1) {
3944			if (exec->inputStackNr <= 0) {
3945			    xmlFARegExecSaveInputString(exec, value, data);
3946			}
3947			xmlFARegExecSave(exec);
3948		    }
3949		    exec->transcount = 1;
3950		    do {
3951			/*
3952			 * Try to progress as much as possible on the input
3953			 */
3954			if (exec->transcount == atom->max) {
3955			    break;
3956			}
3957			exec->index++;
3958			value = exec->inputStack[exec->index].value;
3959			data = exec->inputStack[exec->index].data;
3960#ifdef DEBUG_PUSH
3961			printf("value loaded: %s\n", value);
3962#endif
3963
3964			/*
3965			 * End of input: stop here
3966			 */
3967			if (value == NULL) {
3968			    exec->index --;
3969			    break;
3970			}
3971			if (exec->transcount >= atom->min) {
3972			    int transno = exec->transno;
3973			    xmlRegStatePtr state = exec->state;
3974
3975			    /*
3976			     * The transition is acceptable save it
3977			     */
3978			    exec->transno = -1; /* trick */
3979			    exec->state = to;
3980			    if (exec->inputStackNr <= 0) {
3981				xmlFARegExecSaveInputString(exec, value, data);
3982			    }
3983			    xmlFARegExecSave(exec);
3984			    exec->transno = transno;
3985			    exec->state = state;
3986			}
3987			ret = xmlStrEqual(value, atom->valuep);
3988			exec->transcount++;
3989		    } while (ret == 1);
3990		    if (exec->transcount < atom->min)
3991			ret = 0;
3992
3993		    /*
3994		     * If the last check failed but one transition was found
3995		     * possible, rollback
3996		     */
3997		    if (ret < 0)
3998			ret = 0;
3999		    if (ret == 0) {
4000			goto rollback;
4001		    }
4002		}
4003	    }
4004	    if (ret == 1) {
4005		if ((exec->callback != NULL) && (atom != NULL) &&
4006			(data != NULL)) {
4007		    exec->callback(exec->data, atom->valuep,
4008			           atom->data, data);
4009		}
4010		if (exec->state->nbTrans > exec->transno + 1) {
4011		    if (exec->inputStackNr <= 0) {
4012			xmlFARegExecSaveInputString(exec, value, data);
4013		    }
4014		    xmlFARegExecSave(exec);
4015		}
4016		if (trans->counter >= 0) {
4017#ifdef DEBUG_PUSH
4018		    printf("Increasing count %d\n", trans->counter);
4019#endif
4020		    exec->counts[trans->counter]++;
4021		}
4022		if ((trans->count >= 0) &&
4023		    (trans->count < REGEXP_ALL_COUNTER)) {
4024#ifdef DEBUG_REGEXP_EXEC
4025		    printf("resetting count %d on transition\n",
4026		           trans->count);
4027#endif
4028		    exec->counts[trans->count] = 0;
4029		}
4030#ifdef DEBUG_PUSH
4031		printf("entering state %d\n", trans->to);
4032#endif
4033                if ((exec->comp->states[trans->to] != NULL) &&
4034		    (exec->comp->states[trans->to]->type ==
4035		     XML_REGEXP_SINK_STATE)) {
4036		    /*
4037		     * entering a sink state, save the current state as error
4038		     * state.
4039		     */
4040		    if (exec->errString != NULL)
4041			xmlFree(exec->errString);
4042		    exec->errString = xmlStrdup(value);
4043		    exec->errState = exec->state;
4044		    memcpy(exec->errCounts, exec->counts,
4045			   exec->comp->nbCounters * sizeof(int));
4046		}
4047		exec->state = exec->comp->states[trans->to];
4048		exec->transno = 0;
4049		if (trans->atom != NULL) {
4050		    if (exec->inputStack != NULL) {
4051			exec->index++;
4052			if (exec->index < exec->inputStackNr) {
4053			    value = exec->inputStack[exec->index].value;
4054			    data = exec->inputStack[exec->index].data;
4055#ifdef DEBUG_PUSH
4056			    printf("value loaded: %s\n", value);
4057#endif
4058			} else {
4059			    value = NULL;
4060			    data = NULL;
4061#ifdef DEBUG_PUSH
4062			    printf("end of input\n");
4063#endif
4064			}
4065		    } else {
4066			value = NULL;
4067			data = NULL;
4068#ifdef DEBUG_PUSH
4069			printf("end of input\n");
4070#endif
4071		    }
4072		}
4073		goto progress;
4074	    } else if (ret < 0) {
4075		exec->status = -4;
4076		break;
4077	    }
4078	}
4079	if ((exec->transno != 0) || (exec->state->nbTrans == 0)) {
4080rollback:
4081            /*
4082	     * if we didn't yet rollback on the current input
4083	     * store the current state as the error state.
4084	     */
4085	    if ((progress) && (exec->state != NULL) &&
4086	        (exec->state->type != XML_REGEXP_SINK_STATE)) {
4087	        progress = 0;
4088		if (exec->errString != NULL)
4089		    xmlFree(exec->errString);
4090		exec->errString = xmlStrdup(value);
4091		exec->errState = exec->state;
4092		memcpy(exec->errCounts, exec->counts,
4093		       exec->comp->nbCounters * sizeof(int));
4094	    }
4095
4096	    /*
4097	     * Failed to find a way out
4098	     */
4099	    exec->determinist = 0;
4100	    xmlFARegExecRollBack(exec);
4101	    if ((exec->inputStack != NULL ) && (exec->status == 0)) {
4102		value = exec->inputStack[exec->index].value;
4103		data = exec->inputStack[exec->index].data;
4104#ifdef DEBUG_PUSH
4105		printf("value loaded: %s\n", value);
4106#endif
4107	    }
4108	}
4109	continue;
4110progress:
4111        progress = 1;
4112	continue;
4113    }
4114    if (exec->status == 0) {
4115        return(exec->state->type == XML_REGEXP_FINAL_STATE);
4116    }
4117#ifdef DEBUG_ERR
4118    if (exec->status < 0) {
4119	testerr(exec);
4120    }
4121#endif
4122    return(exec->status);
4123}
4124
4125/**
4126 * xmlRegExecPushString:
4127 * @exec: a regexp execution context or NULL to indicate the end
4128 * @value: a string token input
4129 * @data: data associated to the token to reuse in callbacks
4130 *
4131 * Push one input token in the execution context
4132 *
4133 * Returns: 1 if the regexp reached a final state, 0 if non-final, and
4134 *     a negative value in case of error.
4135 */
4136int
4137xmlRegExecPushString(xmlRegExecCtxtPtr exec, const xmlChar *value,
4138	             void *data) {
4139    return(xmlRegExecPushStringInternal(exec, value, data, 0));
4140}
4141
4142/**
4143 * xmlRegExecPushString2:
4144 * @exec: a regexp execution context or NULL to indicate the end
4145 * @value: the first string token input
4146 * @value2: the second string token input
4147 * @data: data associated to the token to reuse in callbacks
4148 *
4149 * Push one input token in the execution context
4150 *
4151 * Returns: 1 if the regexp reached a final state, 0 if non-final, and
4152 *     a negative value in case of error.
4153 */
4154int
4155xmlRegExecPushString2(xmlRegExecCtxtPtr exec, const xmlChar *value,
4156                      const xmlChar *value2, void *data) {
4157    xmlChar buf[150];
4158    int lenn, lenp, ret;
4159    xmlChar *str;
4160
4161    if (exec == NULL)
4162	return(-1);
4163    if (exec->comp == NULL)
4164	return(-1);
4165    if (exec->status != 0)
4166	return(exec->status);
4167
4168    if (value2 == NULL)
4169        return(xmlRegExecPushString(exec, value, data));
4170
4171    lenn = strlen((char *) value2);
4172    lenp = strlen((char *) value);
4173
4174    if (150 < lenn + lenp + 2) {
4175	str = (xmlChar *) xmlMallocAtomic(lenn + lenp + 2);
4176	if (str == NULL) {
4177	    exec->status = -1;
4178	    return(-1);
4179	}
4180    } else {
4181	str = buf;
4182    }
4183    memcpy(&str[0], value, lenp);
4184    str[lenp] = XML_REG_STRING_SEPARATOR;
4185    memcpy(&str[lenp + 1], value2, lenn);
4186    str[lenn + lenp + 1] = 0;
4187
4188    if (exec->comp->compact != NULL)
4189	ret = xmlRegCompactPushString(exec, exec->comp, str, data);
4190    else
4191        ret = xmlRegExecPushStringInternal(exec, str, data, 1);
4192
4193    if (str != buf)
4194        xmlFree(str);
4195    return(ret);
4196}
4197
4198/**
4199 * xmlRegExecGetValues:
4200 * @exec: a regexp execution context
4201 * @err: error extraction or normal one
4202 * @nbval: pointer to the number of accepted values IN/OUT
4203 * @nbneg: return number of negative transitions
4204 * @values: pointer to the array of acceptable values
4205 * @terminal: return value if this was a terminal state
4206 *
4207 * Extract informations from the regexp execution, internal routine to
4208 * implement xmlRegExecNextValues() and xmlRegExecErrInfo()
4209 *
4210 * Returns: 0 in case of success or -1 in case of error.
4211 */
4212static int
4213xmlRegExecGetValues(xmlRegExecCtxtPtr exec, int err,
4214                    int *nbval, int *nbneg,
4215		    xmlChar **values, int *terminal) {
4216    int maxval;
4217    int nb = 0;
4218
4219    if ((exec == NULL) || (nbval == NULL) || (nbneg == NULL) ||
4220        (values == NULL) || (*nbval <= 0))
4221        return(-1);
4222
4223    maxval = *nbval;
4224    *nbval = 0;
4225    *nbneg = 0;
4226    if ((exec->comp != NULL) && (exec->comp->compact != NULL)) {
4227        xmlRegexpPtr comp;
4228	int target, i, state;
4229
4230        comp = exec->comp;
4231
4232	if (err) {
4233	    if (exec->errStateNo == -1) return(-1);
4234	    state = exec->errStateNo;
4235	} else {
4236	    state = exec->index;
4237	}
4238	if (terminal != NULL) {
4239	    if (comp->compact[state * (comp->nbstrings + 1)] ==
4240	        XML_REGEXP_FINAL_STATE)
4241		*terminal = 1;
4242	    else
4243		*terminal = 0;
4244	}
4245	for (i = 0;(i < comp->nbstrings) && (nb < maxval);i++) {
4246	    target = comp->compact[state * (comp->nbstrings + 1) + i + 1];
4247	    if ((target > 0) && (target <= comp->nbstates) &&
4248	        (comp->compact[(target - 1) * (comp->nbstrings + 1)] !=
4249		 XML_REGEXP_SINK_STATE)) {
4250	        values[nb++] = comp->stringMap[i];
4251		(*nbval)++;
4252	    }
4253	}
4254	for (i = 0;(i < comp->nbstrings) && (nb < maxval);i++) {
4255	    target = comp->compact[state * (comp->nbstrings + 1) + i + 1];
4256	    if ((target > 0) && (target <= comp->nbstates) &&
4257	        (comp->compact[(target - 1) * (comp->nbstrings + 1)] ==
4258		 XML_REGEXP_SINK_STATE)) {
4259	        values[nb++] = comp->stringMap[i];
4260		(*nbneg)++;
4261	    }
4262	}
4263    } else {
4264        int transno;
4265	xmlRegTransPtr trans;
4266	xmlRegAtomPtr atom;
4267	xmlRegStatePtr state;
4268
4269	if (terminal != NULL) {
4270	    if (exec->state->type == XML_REGEXP_FINAL_STATE)
4271		*terminal = 1;
4272	    else
4273		*terminal = 0;
4274	}
4275
4276	if (err) {
4277	    if (exec->errState == NULL) return(-1);
4278	    state = exec->errState;
4279	} else {
4280	    if (exec->state == NULL) return(-1);
4281	    state = exec->state;
4282	}
4283	for (transno = 0;
4284	     (transno < state->nbTrans) && (nb < maxval);
4285	     transno++) {
4286	    trans = &state->trans[transno];
4287	    if (trans->to < 0)
4288		continue;
4289	    atom = trans->atom;
4290	    if ((atom == NULL) || (atom->valuep == NULL))
4291		continue;
4292	    if (trans->count == REGEXP_ALL_LAX_COUNTER) {
4293	        /* this should not be reached but ... */
4294	        TODO;
4295	    } else if (trans->count == REGEXP_ALL_COUNTER) {
4296	        /* this should not be reached but ... */
4297	        TODO;
4298	    } else if (trans->counter >= 0) {
4299		xmlRegCounterPtr counter = NULL;
4300		int count;
4301
4302		if (err)
4303		    count = exec->errCounts[trans->counter];
4304		else
4305		    count = exec->counts[trans->counter];
4306		if (exec->comp != NULL)
4307		    counter = &exec->comp->counters[trans->counter];
4308		if ((counter == NULL) || (count < counter->max)) {
4309		    if (atom->neg)
4310			values[nb++] = (xmlChar *) atom->valuep2;
4311		    else
4312			values[nb++] = (xmlChar *) atom->valuep;
4313		    (*nbval)++;
4314		}
4315	    } else {
4316                if ((exec->comp != NULL) && (exec->comp->states[trans->to] != NULL) &&
4317		    (exec->comp->states[trans->to]->type !=
4318		     XML_REGEXP_SINK_STATE)) {
4319		    if (atom->neg)
4320			values[nb++] = (xmlChar *) atom->valuep2;
4321		    else
4322			values[nb++] = (xmlChar *) atom->valuep;
4323		    (*nbval)++;
4324		}
4325	    }
4326	}
4327	for (transno = 0;
4328	     (transno < state->nbTrans) && (nb < maxval);
4329	     transno++) {
4330	    trans = &state->trans[transno];
4331	    if (trans->to < 0)
4332		continue;
4333	    atom = trans->atom;
4334	    if ((atom == NULL) || (atom->valuep == NULL))
4335		continue;
4336	    if (trans->count == REGEXP_ALL_LAX_COUNTER) {
4337	        continue;
4338	    } else if (trans->count == REGEXP_ALL_COUNTER) {
4339	        continue;
4340	    } else if (trans->counter >= 0) {
4341	        continue;
4342	    } else {
4343                if ((exec->comp->states[trans->to] != NULL) &&
4344		    (exec->comp->states[trans->to]->type ==
4345		     XML_REGEXP_SINK_STATE)) {
4346		    if (atom->neg)
4347			values[nb++] = (xmlChar *) atom->valuep2;
4348		    else
4349			values[nb++] = (xmlChar *) atom->valuep;
4350		    (*nbneg)++;
4351		}
4352	    }
4353	}
4354    }
4355    return(0);
4356}
4357
4358/**
4359 * xmlRegExecNextValues:
4360 * @exec: a regexp execution context
4361 * @nbval: pointer to the number of accepted values IN/OUT
4362 * @nbneg: return number of negative transitions
4363 * @values: pointer to the array of acceptable values
4364 * @terminal: return value if this was a terminal state
4365 *
4366 * Extract informations from the regexp execution,
4367 * the parameter @values must point to an array of @nbval string pointers
4368 * on return nbval will contain the number of possible strings in that
4369 * state and the @values array will be updated with them. The string values
4370 * returned will be freed with the @exec context and don't need to be
4371 * deallocated.
4372 *
4373 * Returns: 0 in case of success or -1 in case of error.
4374 */
4375int
4376xmlRegExecNextValues(xmlRegExecCtxtPtr exec, int *nbval, int *nbneg,
4377                     xmlChar **values, int *terminal) {
4378    return(xmlRegExecGetValues(exec, 0, nbval, nbneg, values, terminal));
4379}
4380
4381/**
4382 * xmlRegExecErrInfo:
4383 * @exec: a regexp execution context generating an error
4384 * @string: return value for the error string
4385 * @nbval: pointer to the number of accepted values IN/OUT
4386 * @nbneg: return number of negative transitions
4387 * @values: pointer to the array of acceptable values
4388 * @terminal: return value if this was a terminal state
4389 *
4390 * Extract error informations from the regexp execution, the parameter
4391 * @string will be updated with the value pushed and not accepted,
4392 * the parameter @values must point to an array of @nbval string pointers
4393 * on return nbval will contain the number of possible strings in that
4394 * state and the @values array will be updated with them. The string values
4395 * returned will be freed with the @exec context and don't need to be
4396 * deallocated.
4397 *
4398 * Returns: 0 in case of success or -1 in case of error.
4399 */
4400int
4401xmlRegExecErrInfo(xmlRegExecCtxtPtr exec, const xmlChar **string,
4402                  int *nbval, int *nbneg, xmlChar **values, int *terminal) {
4403    if (exec == NULL)
4404        return(-1);
4405    if (string != NULL) {
4406        if (exec->status != 0)
4407	    *string = exec->errString;
4408	else
4409	    *string = NULL;
4410    }
4411    return(xmlRegExecGetValues(exec, 1, nbval, nbneg, values, terminal));
4412}
4413
4414#ifdef DEBUG_ERR
4415static void testerr(xmlRegExecCtxtPtr exec) {
4416    const xmlChar *string;
4417    xmlChar *values[5];
4418    int nb = 5;
4419    int nbneg;
4420    int terminal;
4421    xmlRegExecErrInfo(exec, &string, &nb, &nbneg, &values[0], &terminal);
4422}
4423#endif
4424
4425#if 0
4426static int
4427xmlRegExecPushChar(xmlRegExecCtxtPtr exec, int UCS) {
4428    xmlRegTransPtr trans;
4429    xmlRegAtomPtr atom;
4430    int ret;
4431    int codepoint, len;
4432
4433    if (exec == NULL)
4434	return(-1);
4435    if (exec->status != 0)
4436	return(exec->status);
4437
4438    while ((exec->status == 0) &&
4439	   ((exec->inputString[exec->index] != 0) ||
4440	    (exec->state->type != XML_REGEXP_FINAL_STATE))) {
4441
4442	/*
4443	 * End of input on non-terminal state, rollback, however we may
4444	 * still have epsilon like transition for counted transitions
4445	 * on counters, in that case don't break too early.
4446	 */
4447	if ((exec->inputString[exec->index] == 0) && (exec->counts == NULL))
4448	    goto rollback;
4449
4450	exec->transcount = 0;
4451	for (;exec->transno < exec->state->nbTrans;exec->transno++) {
4452	    trans = &exec->state->trans[exec->transno];
4453	    if (trans->to < 0)
4454		continue;
4455	    atom = trans->atom;
4456	    ret = 0;
4457	    if (trans->count >= 0) {
4458		int count;
4459		xmlRegCounterPtr counter;
4460
4461		/*
4462		 * A counted transition.
4463		 */
4464
4465		count = exec->counts[trans->count];
4466		counter = &exec->comp->counters[trans->count];
4467#ifdef DEBUG_REGEXP_EXEC
4468		printf("testing count %d: val %d, min %d, max %d\n",
4469		       trans->count, count, counter->min,  counter->max);
4470#endif
4471		ret = ((count >= counter->min) && (count <= counter->max));
4472	    } else if (atom == NULL) {
4473		fprintf(stderr, "epsilon transition left at runtime\n");
4474		exec->status = -2;
4475		break;
4476	    } else if (exec->inputString[exec->index] != 0) {
4477                codepoint = CUR_SCHAR(&(exec->inputString[exec->index]), len);
4478		ret = xmlRegCheckCharacter(atom, codepoint);
4479		if ((ret == 1) && (atom->min > 0) && (atom->max > 0)) {
4480		    xmlRegStatePtr to = exec->comp->states[trans->to];
4481
4482		    /*
4483		     * this is a multiple input sequence
4484		     */
4485		    if (exec->state->nbTrans > exec->transno + 1) {
4486			xmlFARegExecSave(exec);
4487		    }
4488		    exec->transcount = 1;
4489		    do {
4490			/*
4491			 * Try to progress as much as possible on the input
4492			 */
4493			if (exec->transcount == atom->max) {
4494			    break;
4495			}
4496			exec->index += len;
4497			/*
4498			 * End of input: stop here
4499			 */
4500			if (exec->inputString[exec->index] == 0) {
4501			    exec->index -= len;
4502			    break;
4503			}
4504			if (exec->transcount >= atom->min) {
4505			    int transno = exec->transno;
4506			    xmlRegStatePtr state = exec->state;
4507
4508			    /*
4509			     * The transition is acceptable save it
4510			     */
4511			    exec->transno = -1; /* trick */
4512			    exec->state = to;
4513			    xmlFARegExecSave(exec);
4514			    exec->transno = transno;
4515			    exec->state = state;
4516			}
4517			codepoint = CUR_SCHAR(&(exec->inputString[exec->index]),
4518				              len);
4519			ret = xmlRegCheckCharacter(atom, codepoint);
4520			exec->transcount++;
4521		    } while (ret == 1);
4522		    if (exec->transcount < atom->min)
4523			ret = 0;
4524
4525		    /*
4526		     * If the last check failed but one transition was found
4527		     * possible, rollback
4528		     */
4529		    if (ret < 0)
4530			ret = 0;
4531		    if (ret == 0) {
4532			goto rollback;
4533		    }
4534		}
4535	    }
4536	    if (ret == 1) {
4537		if (exec->state->nbTrans > exec->transno + 1) {
4538		    xmlFARegExecSave(exec);
4539		}
4540		/*
4541		 * restart count for expressions like this ((abc){2})*
4542		 */
4543		if (trans->count >= 0) {
4544#ifdef DEBUG_REGEXP_EXEC
4545		    printf("Reset count %d\n", trans->count);
4546#endif
4547		    exec->counts[trans->count] = 0;
4548		}
4549		if (trans->counter >= 0) {
4550#ifdef DEBUG_REGEXP_EXEC
4551		    printf("Increasing count %d\n", trans->counter);
4552#endif
4553		    exec->counts[trans->counter]++;
4554		}
4555#ifdef DEBUG_REGEXP_EXEC
4556		printf("entering state %d\n", trans->to);
4557#endif
4558		exec->state = exec->comp->states[trans->to];
4559		exec->transno = 0;
4560		if (trans->atom != NULL) {
4561		    exec->index += len;
4562		}
4563		goto progress;
4564	    } else if (ret < 0) {
4565		exec->status = -4;
4566		break;
4567	    }
4568	}
4569	if ((exec->transno != 0) || (exec->state->nbTrans == 0)) {
4570rollback:
4571	    /*
4572	     * Failed to find a way out
4573	     */
4574	    exec->determinist = 0;
4575	    xmlFARegExecRollBack(exec);
4576	}
4577progress:
4578	continue;
4579    }
4580}
4581#endif
4582/************************************************************************
4583 *									*
4584 *	Parser for the Schemas Datatype Regular Expressions		*
4585 *	http://www.w3.org/TR/2001/REC-xmlschema-2-20010502/#regexs	*
4586 *									*
4587 ************************************************************************/
4588
4589/**
4590 * xmlFAIsChar:
4591 * @ctxt:  a regexp parser context
4592 *
4593 * [10]   Char   ::=   [^.\?*+()|#x5B#x5D]
4594 */
4595static int
4596xmlFAIsChar(xmlRegParserCtxtPtr ctxt) {
4597    int cur;
4598    int len;
4599
4600    cur = CUR_SCHAR(ctxt->cur, len);
4601    if ((cur == '.') || (cur == '\\') || (cur == '?') ||
4602	(cur == '*') || (cur == '+') || (cur == '(') ||
4603	(cur == ')') || (cur == '|') || (cur == 0x5B) ||
4604	(cur == 0x5D) || (cur == 0))
4605	return(-1);
4606    return(cur);
4607}
4608
4609/**
4610 * xmlFAParseCharProp:
4611 * @ctxt:  a regexp parser context
4612 *
4613 * [27]   charProp   ::=   IsCategory | IsBlock
4614 * [28]   IsCategory ::= Letters | Marks | Numbers | Punctuation |
4615 *                       Separators | Symbols | Others
4616 * [29]   Letters   ::=   'L' [ultmo]?
4617 * [30]   Marks   ::=   'M' [nce]?
4618 * [31]   Numbers   ::=   'N' [dlo]?
4619 * [32]   Punctuation   ::=   'P' [cdseifo]?
4620 * [33]   Separators   ::=   'Z' [slp]?
4621 * [34]   Symbols   ::=   'S' [mcko]?
4622 * [35]   Others   ::=   'C' [cfon]?
4623 * [36]   IsBlock   ::=   'Is' [a-zA-Z0-9#x2D]+
4624 */
4625static void
4626xmlFAParseCharProp(xmlRegParserCtxtPtr ctxt) {
4627    int cur;
4628    xmlRegAtomType type = (xmlRegAtomType) 0;
4629    xmlChar *blockName = NULL;
4630
4631    cur = CUR;
4632    if (cur == 'L') {
4633	NEXT;
4634	cur = CUR;
4635	if (cur == 'u') {
4636	    NEXT;
4637	    type = XML_REGEXP_LETTER_UPPERCASE;
4638	} else if (cur == 'l') {
4639	    NEXT;
4640	    type = XML_REGEXP_LETTER_LOWERCASE;
4641	} else if (cur == 't') {
4642	    NEXT;
4643	    type = XML_REGEXP_LETTER_TITLECASE;
4644	} else if (cur == 'm') {
4645	    NEXT;
4646	    type = XML_REGEXP_LETTER_MODIFIER;
4647	} else if (cur == 'o') {
4648	    NEXT;
4649	    type = XML_REGEXP_LETTER_OTHERS;
4650	} else {
4651	    type = XML_REGEXP_LETTER;
4652	}
4653    } else if (cur == 'M') {
4654	NEXT;
4655	cur = CUR;
4656	if (cur == 'n') {
4657	    NEXT;
4658	    /* nonspacing */
4659	    type = XML_REGEXP_MARK_NONSPACING;
4660	} else if (cur == 'c') {
4661	    NEXT;
4662	    /* spacing combining */
4663	    type = XML_REGEXP_MARK_SPACECOMBINING;
4664	} else if (cur == 'e') {
4665	    NEXT;
4666	    /* enclosing */
4667	    type = XML_REGEXP_MARK_ENCLOSING;
4668	} else {
4669	    /* all marks */
4670	    type = XML_REGEXP_MARK;
4671	}
4672    } else if (cur == 'N') {
4673	NEXT;
4674	cur = CUR;
4675	if (cur == 'd') {
4676	    NEXT;
4677	    /* digital */
4678	    type = XML_REGEXP_NUMBER_DECIMAL;
4679	} else if (cur == 'l') {
4680	    NEXT;
4681	    /* letter */
4682	    type = XML_REGEXP_NUMBER_LETTER;
4683	} else if (cur == 'o') {
4684	    NEXT;
4685	    /* other */
4686	    type = XML_REGEXP_NUMBER_OTHERS;
4687	} else {
4688	    /* all numbers */
4689	    type = XML_REGEXP_NUMBER;
4690	}
4691    } else if (cur == 'P') {
4692	NEXT;
4693	cur = CUR;
4694	if (cur == 'c') {
4695	    NEXT;
4696	    /* connector */
4697	    type = XML_REGEXP_PUNCT_CONNECTOR;
4698	} else if (cur == 'd') {
4699	    NEXT;
4700	    /* dash */
4701	    type = XML_REGEXP_PUNCT_DASH;
4702	} else if (cur == 's') {
4703	    NEXT;
4704	    /* open */
4705	    type = XML_REGEXP_PUNCT_OPEN;
4706	} else if (cur == 'e') {
4707	    NEXT;
4708	    /* close */
4709	    type = XML_REGEXP_PUNCT_CLOSE;
4710	} else if (cur == 'i') {
4711	    NEXT;
4712	    /* initial quote */
4713	    type = XML_REGEXP_PUNCT_INITQUOTE;
4714	} else if (cur == 'f') {
4715	    NEXT;
4716	    /* final quote */
4717	    type = XML_REGEXP_PUNCT_FINQUOTE;
4718	} else if (cur == 'o') {
4719	    NEXT;
4720	    /* other */
4721	    type = XML_REGEXP_PUNCT_OTHERS;
4722	} else {
4723	    /* all punctuation */
4724	    type = XML_REGEXP_PUNCT;
4725	}
4726    } else if (cur == 'Z') {
4727	NEXT;
4728	cur = CUR;
4729	if (cur == 's') {
4730	    NEXT;
4731	    /* space */
4732	    type = XML_REGEXP_SEPAR_SPACE;
4733	} else if (cur == 'l') {
4734	    NEXT;
4735	    /* line */
4736	    type = XML_REGEXP_SEPAR_LINE;
4737	} else if (cur == 'p') {
4738	    NEXT;
4739	    /* paragraph */
4740	    type = XML_REGEXP_SEPAR_PARA;
4741	} else {
4742	    /* all separators */
4743	    type = XML_REGEXP_SEPAR;
4744	}
4745    } else if (cur == 'S') {
4746	NEXT;
4747	cur = CUR;
4748	if (cur == 'm') {
4749	    NEXT;
4750	    type = XML_REGEXP_SYMBOL_MATH;
4751	    /* math */
4752	} else if (cur == 'c') {
4753	    NEXT;
4754	    type = XML_REGEXP_SYMBOL_CURRENCY;
4755	    /* currency */
4756	} else if (cur == 'k') {
4757	    NEXT;
4758	    type = XML_REGEXP_SYMBOL_MODIFIER;
4759	    /* modifiers */
4760	} else if (cur == 'o') {
4761	    NEXT;
4762	    type = XML_REGEXP_SYMBOL_OTHERS;
4763	    /* other */
4764	} else {
4765	    /* all symbols */
4766	    type = XML_REGEXP_SYMBOL;
4767	}
4768    } else if (cur == 'C') {
4769	NEXT;
4770	cur = CUR;
4771	if (cur == 'c') {
4772	    NEXT;
4773	    /* control */
4774	    type = XML_REGEXP_OTHER_CONTROL;
4775	} else if (cur == 'f') {
4776	    NEXT;
4777	    /* format */
4778	    type = XML_REGEXP_OTHER_FORMAT;
4779	} else if (cur == 'o') {
4780	    NEXT;
4781	    /* private use */
4782	    type = XML_REGEXP_OTHER_PRIVATE;
4783	} else if (cur == 'n') {
4784	    NEXT;
4785	    /* not assigned */
4786	    type = XML_REGEXP_OTHER_NA;
4787	} else {
4788	    /* all others */
4789	    type = XML_REGEXP_OTHER;
4790	}
4791    } else if (cur == 'I') {
4792	const xmlChar *start;
4793	NEXT;
4794	cur = CUR;
4795	if (cur != 's') {
4796	    ERROR("IsXXXX expected");
4797	    return;
4798	}
4799	NEXT;
4800	start = ctxt->cur;
4801	cur = CUR;
4802	if (((cur >= 'a') && (cur <= 'z')) ||
4803	    ((cur >= 'A') && (cur <= 'Z')) ||
4804	    ((cur >= '0') && (cur <= '9')) ||
4805	    (cur == 0x2D)) {
4806	    NEXT;
4807	    cur = CUR;
4808	    while (((cur >= 'a') && (cur <= 'z')) ||
4809		((cur >= 'A') && (cur <= 'Z')) ||
4810		((cur >= '0') && (cur <= '9')) ||
4811		(cur == 0x2D)) {
4812		NEXT;
4813		cur = CUR;
4814	    }
4815	}
4816	type = XML_REGEXP_BLOCK_NAME;
4817	blockName = xmlStrndup(start, ctxt->cur - start);
4818    } else {
4819	ERROR("Unknown char property");
4820	return;
4821    }
4822    if (ctxt->atom == NULL) {
4823	ctxt->atom = xmlRegNewAtom(ctxt, type);
4824	if (ctxt->atom != NULL)
4825	    ctxt->atom->valuep = blockName;
4826    } else if (ctxt->atom->type == XML_REGEXP_RANGES) {
4827        xmlRegAtomAddRange(ctxt, ctxt->atom, ctxt->neg,
4828		           type, 0, 0, blockName);
4829    }
4830}
4831
4832/**
4833 * xmlFAParseCharClassEsc:
4834 * @ctxt:  a regexp parser context
4835 *
4836 * [23] charClassEsc ::= ( SingleCharEsc | MultiCharEsc | catEsc | complEsc )
4837 * [24] SingleCharEsc ::= '\' [nrt\|.?*+(){}#x2D#x5B#x5D#x5E]
4838 * [25] catEsc   ::=   '\p{' charProp '}'
4839 * [26] complEsc ::=   '\P{' charProp '}'
4840 * [37] MultiCharEsc ::= '.' | ('\' [sSiIcCdDwW])
4841 */
4842static void
4843xmlFAParseCharClassEsc(xmlRegParserCtxtPtr ctxt) {
4844    int cur;
4845
4846    if (CUR == '.') {
4847	if (ctxt->atom == NULL) {
4848	    ctxt->atom = xmlRegNewAtom(ctxt, XML_REGEXP_ANYCHAR);
4849	} else if (ctxt->atom->type == XML_REGEXP_RANGES) {
4850	    xmlRegAtomAddRange(ctxt, ctxt->atom, ctxt->neg,
4851			       XML_REGEXP_ANYCHAR, 0, 0, NULL);
4852	}
4853	NEXT;
4854	return;
4855    }
4856    if (CUR != '\\') {
4857	ERROR("Escaped sequence: expecting \\");
4858	return;
4859    }
4860    NEXT;
4861    cur = CUR;
4862    if (cur == 'p') {
4863	NEXT;
4864	if (CUR != '{') {
4865	    ERROR("Expecting '{'");
4866	    return;
4867	}
4868	NEXT;
4869	xmlFAParseCharProp(ctxt);
4870	if (CUR != '}') {
4871	    ERROR("Expecting '}'");
4872	    return;
4873	}
4874	NEXT;
4875    } else if (cur == 'P') {
4876	NEXT;
4877	if (CUR != '{') {
4878	    ERROR("Expecting '{'");
4879	    return;
4880	}
4881	NEXT;
4882	xmlFAParseCharProp(ctxt);
4883	ctxt->atom->neg = 1;
4884	if (CUR != '}') {
4885	    ERROR("Expecting '}'");
4886	    return;
4887	}
4888	NEXT;
4889    } else if ((cur == 'n') || (cur == 'r') || (cur == 't') || (cur == '\\') ||
4890	(cur == '|') || (cur == '.') || (cur == '?') || (cur == '*') ||
4891	(cur == '+') || (cur == '(') || (cur == ')') || (cur == '{') ||
4892	(cur == '}') || (cur == 0x2D) || (cur == 0x5B) || (cur == 0x5D) ||
4893	(cur == 0x5E)) {
4894	if (ctxt->atom == NULL) {
4895	    ctxt->atom = xmlRegNewAtom(ctxt, XML_REGEXP_CHARVAL);
4896	    if (ctxt->atom != NULL) {
4897	        switch (cur) {
4898		    case 'n':
4899		        ctxt->atom->codepoint = '\n';
4900			break;
4901		    case 'r':
4902		        ctxt->atom->codepoint = '\r';
4903			break;
4904		    case 't':
4905		        ctxt->atom->codepoint = '\t';
4906			break;
4907		    default:
4908			ctxt->atom->codepoint = cur;
4909		}
4910	    }
4911	} else if (ctxt->atom->type == XML_REGEXP_RANGES) {
4912            switch (cur) {
4913                case 'n':
4914                    cur = '\n';
4915                    break;
4916                case 'r':
4917                    cur = '\r';
4918                    break;
4919                case 't':
4920                    cur = '\t';
4921                    break;
4922            }
4923	    xmlRegAtomAddRange(ctxt, ctxt->atom, ctxt->neg,
4924			       XML_REGEXP_CHARVAL, cur, cur, NULL);
4925	}
4926	NEXT;
4927    } else if ((cur == 's') || (cur == 'S') || (cur == 'i') || (cur == 'I') ||
4928	(cur == 'c') || (cur == 'C') || (cur == 'd') || (cur == 'D') ||
4929	(cur == 'w') || (cur == 'W')) {
4930	xmlRegAtomType type = XML_REGEXP_ANYSPACE;
4931
4932	switch (cur) {
4933	    case 's':
4934		type = XML_REGEXP_ANYSPACE;
4935		break;
4936	    case 'S':
4937		type = XML_REGEXP_NOTSPACE;
4938		break;
4939	    case 'i':
4940		type = XML_REGEXP_INITNAME;
4941		break;
4942	    case 'I':
4943		type = XML_REGEXP_NOTINITNAME;
4944		break;
4945	    case 'c':
4946		type = XML_REGEXP_NAMECHAR;
4947		break;
4948	    case 'C':
4949		type = XML_REGEXP_NOTNAMECHAR;
4950		break;
4951	    case 'd':
4952		type = XML_REGEXP_DECIMAL;
4953		break;
4954	    case 'D':
4955		type = XML_REGEXP_NOTDECIMAL;
4956		break;
4957	    case 'w':
4958		type = XML_REGEXP_REALCHAR;
4959		break;
4960	    case 'W':
4961		type = XML_REGEXP_NOTREALCHAR;
4962		break;
4963	}
4964	NEXT;
4965	if (ctxt->atom == NULL) {
4966	    ctxt->atom = xmlRegNewAtom(ctxt, type);
4967	} else if (ctxt->atom->type == XML_REGEXP_RANGES) {
4968	    xmlRegAtomAddRange(ctxt, ctxt->atom, ctxt->neg,
4969			       type, 0, 0, NULL);
4970	}
4971    } else {
4972	ERROR("Wrong escape sequence, misuse of character '\\'");
4973    }
4974}
4975
4976/**
4977 * xmlFAParseCharRange:
4978 * @ctxt:  a regexp parser context
4979 *
4980 * [17]   charRange   ::=     seRange | XmlCharRef | XmlCharIncDash
4981 * [18]   seRange   ::=   charOrEsc '-' charOrEsc
4982 * [20]   charOrEsc   ::=   XmlChar | SingleCharEsc
4983 * [21]   XmlChar   ::=   [^\#x2D#x5B#x5D]
4984 * [22]   XmlCharIncDash   ::=   [^\#x5B#x5D]
4985 */
4986static void
4987xmlFAParseCharRange(xmlRegParserCtxtPtr ctxt) {
4988    int cur, len;
4989    int start = -1;
4990    int end = -1;
4991
4992    if (CUR == '\0') {
4993        ERROR("Expecting ']'");
4994	return;
4995    }
4996
4997    cur = CUR;
4998    if (cur == '\\') {
4999	NEXT;
5000	cur = CUR;
5001	switch (cur) {
5002	    case 'n': start = 0xA; break;
5003	    case 'r': start = 0xD; break;
5004	    case 't': start = 0x9; break;
5005	    case '\\': case '|': case '.': case '-': case '^': case '?':
5006	    case '*': case '+': case '{': case '}': case '(': case ')':
5007	    case '[': case ']':
5008		start = cur; break;
5009	    default:
5010		ERROR("Invalid escape value");
5011		return;
5012	}
5013	end = start;
5014        len = 1;
5015    } else if ((cur != 0x5B) && (cur != 0x5D)) {
5016        end = start = CUR_SCHAR(ctxt->cur, len);
5017    } else {
5018	ERROR("Expecting a char range");
5019	return;
5020    }
5021    /*
5022     * Since we are "inside" a range, we can assume ctxt->cur is past
5023     * the start of ctxt->string, and PREV should be safe
5024     */
5025    if ((start == '-') && (NXT(1) != ']') && (PREV != '[') && (PREV != '^')) {
5026	NEXTL(len);
5027	return;
5028    }
5029    NEXTL(len);
5030    cur = CUR;
5031    if ((cur != '-') || (NXT(1) == ']')) {
5032        xmlRegAtomAddRange(ctxt, ctxt->atom, ctxt->neg,
5033		              XML_REGEXP_CHARVAL, start, end, NULL);
5034	return;
5035    }
5036    NEXT;
5037    cur = CUR;
5038    if (cur == '\\') {
5039	NEXT;
5040	cur = CUR;
5041	switch (cur) {
5042	    case 'n': end = 0xA; break;
5043	    case 'r': end = 0xD; break;
5044	    case 't': end = 0x9; break;
5045	    case '\\': case '|': case '.': case '-': case '^': case '?':
5046	    case '*': case '+': case '{': case '}': case '(': case ')':
5047	    case '[': case ']':
5048		end = cur; break;
5049	    default:
5050		ERROR("Invalid escape value");
5051		return;
5052	}
5053        len = 1;
5054    } else if ((cur != 0x5B) && (cur != 0x5D)) {
5055        end = CUR_SCHAR(ctxt->cur, len);
5056    } else {
5057	ERROR("Expecting the end of a char range");
5058	return;
5059    }
5060    NEXTL(len);
5061    /* TODO check that the values are acceptable character ranges for XML */
5062    if (end < start) {
5063	ERROR("End of range is before start of range");
5064    } else {
5065        xmlRegAtomAddRange(ctxt, ctxt->atom, ctxt->neg,
5066		           XML_REGEXP_CHARVAL, start, end, NULL);
5067    }
5068    return;
5069}
5070
5071/**
5072 * xmlFAParsePosCharGroup:
5073 * @ctxt:  a regexp parser context
5074 *
5075 * [14]   posCharGroup ::= ( charRange | charClassEsc  )+
5076 */
5077static void
5078xmlFAParsePosCharGroup(xmlRegParserCtxtPtr ctxt) {
5079    do {
5080	if (CUR == '\\') {
5081	    xmlFAParseCharClassEsc(ctxt);
5082	} else {
5083	    xmlFAParseCharRange(ctxt);
5084	}
5085    } while ((CUR != ']') && (CUR != '^') && (CUR != '-') &&
5086             (CUR != 0) && (ctxt->error == 0));
5087}
5088
5089/**
5090 * xmlFAParseCharGroup:
5091 * @ctxt:  a regexp parser context
5092 *
5093 * [13]   charGroup    ::= posCharGroup | negCharGroup | charClassSub
5094 * [15]   negCharGroup ::= '^' posCharGroup
5095 * [16]   charClassSub ::= ( posCharGroup | negCharGroup ) '-' charClassExpr
5096 * [12]   charClassExpr ::= '[' charGroup ']'
5097 */
5098static void
5099xmlFAParseCharGroup(xmlRegParserCtxtPtr ctxt) {
5100    int n = ctxt->neg;
5101    while ((CUR != ']') && (ctxt->error == 0)) {
5102	if (CUR == '^') {
5103	    int neg = ctxt->neg;
5104
5105	    NEXT;
5106	    ctxt->neg = !ctxt->neg;
5107	    xmlFAParsePosCharGroup(ctxt);
5108	    ctxt->neg = neg;
5109	} else if ((CUR == '-') && (NXT(1) == '[')) {
5110	    int neg = ctxt->neg;
5111	    ctxt->neg = 2;
5112	    NEXT;	/* eat the '-' */
5113	    NEXT;	/* eat the '[' */
5114	    xmlFAParseCharGroup(ctxt);
5115	    if (CUR == ']') {
5116		NEXT;
5117	    } else {
5118		ERROR("charClassExpr: ']' expected");
5119		break;
5120	    }
5121	    ctxt->neg = neg;
5122	    break;
5123	} else if (CUR != ']') {
5124	    xmlFAParsePosCharGroup(ctxt);
5125	}
5126    }
5127    ctxt->neg = n;
5128}
5129
5130/**
5131 * xmlFAParseCharClass:
5132 * @ctxt:  a regexp parser context
5133 *
5134 * [11]   charClass   ::=     charClassEsc | charClassExpr
5135 * [12]   charClassExpr   ::=   '[' charGroup ']'
5136 */
5137static void
5138xmlFAParseCharClass(xmlRegParserCtxtPtr ctxt) {
5139    if (CUR == '[') {
5140	NEXT;
5141	ctxt->atom = xmlRegNewAtom(ctxt, XML_REGEXP_RANGES);
5142	if (ctxt->atom == NULL)
5143	    return;
5144	xmlFAParseCharGroup(ctxt);
5145	if (CUR == ']') {
5146	    NEXT;
5147	} else {
5148	    ERROR("xmlFAParseCharClass: ']' expected");
5149	}
5150    } else {
5151	xmlFAParseCharClassEsc(ctxt);
5152    }
5153}
5154
5155/**
5156 * xmlFAParseQuantExact:
5157 * @ctxt:  a regexp parser context
5158 *
5159 * [8]   QuantExact   ::=   [0-9]+
5160 *
5161 * Returns 0 if success or -1 in case of error
5162 */
5163static int
5164xmlFAParseQuantExact(xmlRegParserCtxtPtr ctxt) {
5165    int ret = 0;
5166    int ok = 0;
5167
5168    while ((CUR >= '0') && (CUR <= '9')) {
5169	ret = ret * 10 + (CUR - '0');
5170	ok = 1;
5171	NEXT;
5172    }
5173    if (ok != 1) {
5174	return(-1);
5175    }
5176    return(ret);
5177}
5178
5179/**
5180 * xmlFAParseQuantifier:
5181 * @ctxt:  a regexp parser context
5182 *
5183 * [4]   quantifier   ::=   [?*+] | ( '{' quantity '}' )
5184 * [5]   quantity   ::=   quantRange | quantMin | QuantExact
5185 * [6]   quantRange   ::=   QuantExact ',' QuantExact
5186 * [7]   quantMin   ::=   QuantExact ','
5187 * [8]   QuantExact   ::=   [0-9]+
5188 */
5189static int
5190xmlFAParseQuantifier(xmlRegParserCtxtPtr ctxt) {
5191    int cur;
5192
5193    cur = CUR;
5194    if ((cur == '?') || (cur == '*') || (cur == '+')) {
5195	if (ctxt->atom != NULL) {
5196	    if (cur == '?')
5197		ctxt->atom->quant = XML_REGEXP_QUANT_OPT;
5198	    else if (cur == '*')
5199		ctxt->atom->quant = XML_REGEXP_QUANT_MULT;
5200	    else if (cur == '+')
5201		ctxt->atom->quant = XML_REGEXP_QUANT_PLUS;
5202	}
5203	NEXT;
5204	return(1);
5205    }
5206    if (cur == '{') {
5207	int min = 0, max = 0;
5208
5209	NEXT;
5210	cur = xmlFAParseQuantExact(ctxt);
5211	if (cur >= 0)
5212	    min = cur;
5213	if (CUR == ',') {
5214	    NEXT;
5215	    if (CUR == '}')
5216	        max = INT_MAX;
5217	    else {
5218	        cur = xmlFAParseQuantExact(ctxt);
5219	        if (cur >= 0)
5220		    max = cur;
5221		else {
5222		    ERROR("Improper quantifier");
5223		}
5224	    }
5225	}
5226	if (CUR == '}') {
5227	    NEXT;
5228	} else {
5229	    ERROR("Unterminated quantifier");
5230	}
5231	if (max == 0)
5232	    max = min;
5233	if (ctxt->atom != NULL) {
5234	    ctxt->atom->quant = XML_REGEXP_QUANT_RANGE;
5235	    ctxt->atom->min = min;
5236	    ctxt->atom->max = max;
5237	}
5238	return(1);
5239    }
5240    return(0);
5241}
5242
5243/**
5244 * xmlFAParseAtom:
5245 * @ctxt:  a regexp parser context
5246 *
5247 * [9]   atom   ::=   Char | charClass | ( '(' regExp ')' )
5248 */
5249static int
5250xmlFAParseAtom(xmlRegParserCtxtPtr ctxt) {
5251    int codepoint, len;
5252
5253    codepoint = xmlFAIsChar(ctxt);
5254    if (codepoint > 0) {
5255	ctxt->atom = xmlRegNewAtom(ctxt, XML_REGEXP_CHARVAL);
5256	if (ctxt->atom == NULL)
5257	    return(-1);
5258	codepoint = CUR_SCHAR(ctxt->cur, len);
5259	ctxt->atom->codepoint = codepoint;
5260	NEXTL(len);
5261	return(1);
5262    } else if (CUR == '|') {
5263	return(0);
5264    } else if (CUR == 0) {
5265	return(0);
5266    } else if (CUR == ')') {
5267	return(0);
5268    } else if (CUR == '(') {
5269	xmlRegStatePtr start, oldend, start0;
5270
5271	NEXT;
5272	/*
5273	 * this extra Epsilon transition is needed if we count with 0 allowed
5274	 * unfortunately this can't be known at that point
5275	 */
5276	xmlFAGenerateEpsilonTransition(ctxt, ctxt->state, NULL);
5277	start0 = ctxt->state;
5278	xmlFAGenerateEpsilonTransition(ctxt, ctxt->state, NULL);
5279	start = ctxt->state;
5280	oldend = ctxt->end;
5281	ctxt->end = NULL;
5282	ctxt->atom = NULL;
5283	xmlFAParseRegExp(ctxt, 0);
5284	if (CUR == ')') {
5285	    NEXT;
5286	} else {
5287	    ERROR("xmlFAParseAtom: expecting ')'");
5288	}
5289	ctxt->atom = xmlRegNewAtom(ctxt, XML_REGEXP_SUBREG);
5290	if (ctxt->atom == NULL)
5291	    return(-1);
5292	ctxt->atom->start = start;
5293	ctxt->atom->start0 = start0;
5294	ctxt->atom->stop = ctxt->state;
5295	ctxt->end = oldend;
5296	return(1);
5297    } else if ((CUR == '[') || (CUR == '\\') || (CUR == '.')) {
5298	xmlFAParseCharClass(ctxt);
5299	return(1);
5300    }
5301    return(0);
5302}
5303
5304/**
5305 * xmlFAParsePiece:
5306 * @ctxt:  a regexp parser context
5307 *
5308 * [3]   piece   ::=   atom quantifier?
5309 */
5310static int
5311xmlFAParsePiece(xmlRegParserCtxtPtr ctxt) {
5312    int ret;
5313
5314    ctxt->atom = NULL;
5315    ret = xmlFAParseAtom(ctxt);
5316    if (ret == 0)
5317	return(0);
5318    if (ctxt->atom == NULL) {
5319	ERROR("internal: no atom generated");
5320    }
5321    xmlFAParseQuantifier(ctxt);
5322    return(1);
5323}
5324
5325/**
5326 * xmlFAParseBranch:
5327 * @ctxt:  a regexp parser context
5328 * @to: optional target to the end of the branch
5329 *
5330 * @to is used to optimize by removing duplicate path in automata
5331 * in expressions like (a|b)(c|d)
5332 *
5333 * [2]   branch   ::=   piece*
5334 */
5335static int
5336xmlFAParseBranch(xmlRegParserCtxtPtr ctxt, xmlRegStatePtr to) {
5337    xmlRegStatePtr previous;
5338    int ret;
5339
5340    previous = ctxt->state;
5341    ret = xmlFAParsePiece(ctxt);
5342    if (ret != 0) {
5343	if (xmlFAGenerateTransitions(ctxt, previous,
5344	        (CUR=='|' || CUR==')') ? to : NULL, ctxt->atom) < 0)
5345	    return(-1);
5346	previous = ctxt->state;
5347	ctxt->atom = NULL;
5348    }
5349    while ((ret != 0) && (ctxt->error == 0)) {
5350	ret = xmlFAParsePiece(ctxt);
5351	if (ret != 0) {
5352	    if (xmlFAGenerateTransitions(ctxt, previous,
5353	            (CUR=='|' || CUR==')') ? to : NULL, ctxt->atom) < 0)
5354		    return(-1);
5355	    previous = ctxt->state;
5356	    ctxt->atom = NULL;
5357	}
5358    }
5359    return(0);
5360}
5361
5362/**
5363 * xmlFAParseRegExp:
5364 * @ctxt:  a regexp parser context
5365 * @top:  is this the top-level expression ?
5366 *
5367 * [1]   regExp   ::=     branch  ( '|' branch )*
5368 */
5369static void
5370xmlFAParseRegExp(xmlRegParserCtxtPtr ctxt, int top) {
5371    xmlRegStatePtr start, end;
5372
5373    /* if not top start should have been generated by an epsilon trans */
5374    start = ctxt->state;
5375    ctxt->end = NULL;
5376    xmlFAParseBranch(ctxt, NULL);
5377    if (top) {
5378#ifdef DEBUG_REGEXP_GRAPH
5379	printf("State %d is final\n", ctxt->state->no);
5380#endif
5381	ctxt->state->type = XML_REGEXP_FINAL_STATE;
5382    }
5383    if (CUR != '|') {
5384	ctxt->end = ctxt->state;
5385	return;
5386    }
5387    end = ctxt->state;
5388    while ((CUR == '|') && (ctxt->error == 0)) {
5389	NEXT;
5390	if (CUR == 0) {
5391	    ERROR("expecting a branch after |")
5392	    return;
5393	}
5394	ctxt->state = start;
5395	ctxt->end = NULL;
5396	xmlFAParseBranch(ctxt, end);
5397    }
5398    if (!top) {
5399	ctxt->state = end;
5400	ctxt->end = end;
5401    }
5402}
5403
5404/************************************************************************
5405 *									*
5406 *			The basic API					*
5407 *									*
5408 ************************************************************************/
5409
5410/**
5411 * xmlRegexpPrint:
5412 * @output: the file for the output debug
5413 * @regexp: the compiled regexp
5414 *
5415 * Print the content of the compiled regular expression
5416 */
5417void
5418xmlRegexpPrint(FILE *output, xmlRegexpPtr regexp) {
5419    int i;
5420
5421    if (output == NULL)
5422        return;
5423    fprintf(output, " regexp: ");
5424    if (regexp == NULL) {
5425	fprintf(output, "NULL\n");
5426	return;
5427    }
5428    fprintf(output, "'%s' ", regexp->string);
5429    fprintf(output, "\n");
5430    fprintf(output, "%d atoms:\n", regexp->nbAtoms);
5431    for (i = 0;i < regexp->nbAtoms; i++) {
5432	fprintf(output, " %02d ", i);
5433	xmlRegPrintAtom(output, regexp->atoms[i]);
5434    }
5435    fprintf(output, "%d states:", regexp->nbStates);
5436    fprintf(output, "\n");
5437    for (i = 0;i < regexp->nbStates; i++) {
5438	xmlRegPrintState(output, regexp->states[i]);
5439    }
5440    fprintf(output, "%d counters:\n", regexp->nbCounters);
5441    for (i = 0;i < regexp->nbCounters; i++) {
5442	fprintf(output, " %d: min %d max %d\n", i, regexp->counters[i].min,
5443		                                regexp->counters[i].max);
5444    }
5445}
5446
5447/**
5448 * xmlRegexpCompile:
5449 * @regexp:  a regular expression string
5450 *
5451 * Parses a regular expression conforming to XML Schemas Part 2 Datatype
5452 * Appendix F and builds an automata suitable for testing strings against
5453 * that regular expression
5454 *
5455 * Returns the compiled expression or NULL in case of error
5456 */
5457xmlRegexpPtr
5458xmlRegexpCompile(const xmlChar *regexp) {
5459    xmlRegexpPtr ret;
5460    xmlRegParserCtxtPtr ctxt;
5461
5462    ctxt = xmlRegNewParserCtxt(regexp);
5463    if (ctxt == NULL)
5464	return(NULL);
5465
5466    /* initialize the parser */
5467    ctxt->end = NULL;
5468    ctxt->start = ctxt->state = xmlRegNewState(ctxt);
5469    xmlRegStatePush(ctxt, ctxt->start);
5470
5471    /* parse the expression building an automata */
5472    xmlFAParseRegExp(ctxt, 1);
5473    if (CUR != 0) {
5474	ERROR("xmlFAParseRegExp: extra characters");
5475    }
5476    if (ctxt->error != 0) {
5477	xmlRegFreeParserCtxt(ctxt);
5478	return(NULL);
5479    }
5480    ctxt->end = ctxt->state;
5481    ctxt->start->type = XML_REGEXP_START_STATE;
5482    ctxt->end->type = XML_REGEXP_FINAL_STATE;
5483
5484    /* remove the Epsilon except for counted transitions */
5485    xmlFAEliminateEpsilonTransitions(ctxt);
5486
5487
5488    if (ctxt->error != 0) {
5489	xmlRegFreeParserCtxt(ctxt);
5490	return(NULL);
5491    }
5492    ret = xmlRegEpxFromParse(ctxt);
5493    xmlRegFreeParserCtxt(ctxt);
5494    return(ret);
5495}
5496
5497/**
5498 * xmlRegexpExec:
5499 * @comp:  the compiled regular expression
5500 * @content:  the value to check against the regular expression
5501 *
5502 * Check if the regular expression generates the value
5503 *
5504 * Returns 1 if it matches, 0 if not and a negative value in case of error
5505 */
5506int
5507xmlRegexpExec(xmlRegexpPtr comp, const xmlChar *content) {
5508    if ((comp == NULL) || (content == NULL))
5509	return(-1);
5510    return(xmlFARegExec(comp, content));
5511}
5512
5513/**
5514 * xmlRegexpIsDeterminist:
5515 * @comp:  the compiled regular expression
5516 *
5517 * Check if the regular expression is determinist
5518 *
5519 * Returns 1 if it yes, 0 if not and a negative value in case of error
5520 */
5521int
5522xmlRegexpIsDeterminist(xmlRegexpPtr comp) {
5523    xmlAutomataPtr am;
5524    int ret;
5525
5526    if (comp == NULL)
5527	return(-1);
5528    if (comp->determinist != -1)
5529	return(comp->determinist);
5530
5531    am = xmlNewAutomata();
5532    if (am->states != NULL) {
5533	int i;
5534
5535	for (i = 0;i < am->nbStates;i++)
5536	    xmlRegFreeState(am->states[i]);
5537	xmlFree(am->states);
5538    }
5539    am->nbAtoms = comp->nbAtoms;
5540    am->atoms = comp->atoms;
5541    am->nbStates = comp->nbStates;
5542    am->states = comp->states;
5543    am->determinist = -1;
5544    am->flags = comp->flags;
5545    ret = xmlFAComputesDeterminism(am);
5546    am->atoms = NULL;
5547    am->states = NULL;
5548    xmlFreeAutomata(am);
5549    comp->determinist = ret;
5550    return(ret);
5551}
5552
5553/**
5554 * xmlRegFreeRegexp:
5555 * @regexp:  the regexp
5556 *
5557 * Free a regexp
5558 */
5559void
5560xmlRegFreeRegexp(xmlRegexpPtr regexp) {
5561    int i;
5562    if (regexp == NULL)
5563	return;
5564
5565    if (regexp->string != NULL)
5566	xmlFree(regexp->string);
5567    if (regexp->states != NULL) {
5568	for (i = 0;i < regexp->nbStates;i++)
5569	    xmlRegFreeState(regexp->states[i]);
5570	xmlFree(regexp->states);
5571    }
5572    if (regexp->atoms != NULL) {
5573	for (i = 0;i < regexp->nbAtoms;i++)
5574	    xmlRegFreeAtom(regexp->atoms[i]);
5575	xmlFree(regexp->atoms);
5576    }
5577    if (regexp->counters != NULL)
5578	xmlFree(regexp->counters);
5579    if (regexp->compact != NULL)
5580	xmlFree(regexp->compact);
5581    if (regexp->transdata != NULL)
5582	xmlFree(regexp->transdata);
5583    if (regexp->stringMap != NULL) {
5584	for (i = 0; i < regexp->nbstrings;i++)
5585	    xmlFree(regexp->stringMap[i]);
5586	xmlFree(regexp->stringMap);
5587    }
5588
5589    xmlFree(regexp);
5590}
5591
5592#ifdef LIBXML_AUTOMATA_ENABLED
5593/************************************************************************
5594 *									*
5595 *			The Automata interface				*
5596 *									*
5597 ************************************************************************/
5598
5599/**
5600 * xmlNewAutomata:
5601 *
5602 * Create a new automata
5603 *
5604 * Returns the new object or NULL in case of failure
5605 */
5606xmlAutomataPtr
5607xmlNewAutomata(void) {
5608    xmlAutomataPtr ctxt;
5609
5610    ctxt = xmlRegNewParserCtxt(NULL);
5611    if (ctxt == NULL)
5612	return(NULL);
5613
5614    /* initialize the parser */
5615    ctxt->end = NULL;
5616    ctxt->start = ctxt->state = xmlRegNewState(ctxt);
5617    if (ctxt->start == NULL) {
5618	xmlFreeAutomata(ctxt);
5619	return(NULL);
5620    }
5621    ctxt->start->type = XML_REGEXP_START_STATE;
5622    if (xmlRegStatePush(ctxt, ctxt->start) < 0) {
5623        xmlRegFreeState(ctxt->start);
5624	xmlFreeAutomata(ctxt);
5625	return(NULL);
5626    }
5627    ctxt->flags = 0;
5628
5629    return(ctxt);
5630}
5631
5632/**
5633 * xmlFreeAutomata:
5634 * @am: an automata
5635 *
5636 * Free an automata
5637 */
5638void
5639xmlFreeAutomata(xmlAutomataPtr am) {
5640    if (am == NULL)
5641	return;
5642    xmlRegFreeParserCtxt(am);
5643}
5644
5645/**
5646 * xmlAutomataSetFlags:
5647 * @am: an automata
5648 * @flags:  a set of internal flags
5649 *
5650 * Set some flags on the automata
5651 */
5652void
5653xmlAutomataSetFlags(xmlAutomataPtr am, int flags) {
5654    if (am == NULL)
5655	return;
5656    am->flags |= flags;
5657}
5658
5659/**
5660 * xmlAutomataGetInitState:
5661 * @am: an automata
5662 *
5663 * Initial state lookup
5664 *
5665 * Returns the initial state of the automata
5666 */
5667xmlAutomataStatePtr
5668xmlAutomataGetInitState(xmlAutomataPtr am) {
5669    if (am == NULL)
5670	return(NULL);
5671    return(am->start);
5672}
5673
5674/**
5675 * xmlAutomataSetFinalState:
5676 * @am: an automata
5677 * @state: a state in this automata
5678 *
5679 * Makes that state a final state
5680 *
5681 * Returns 0 or -1 in case of error
5682 */
5683int
5684xmlAutomataSetFinalState(xmlAutomataPtr am, xmlAutomataStatePtr state) {
5685    if ((am == NULL) || (state == NULL))
5686	return(-1);
5687    state->type = XML_REGEXP_FINAL_STATE;
5688    return(0);
5689}
5690
5691/**
5692 * xmlAutomataNewTransition:
5693 * @am: an automata
5694 * @from: the starting point of the transition
5695 * @to: the target point of the transition or NULL
5696 * @token: the input string associated to that transition
5697 * @data: data passed to the callback function if the transition is activated
5698 *
5699 * If @to is NULL, this creates first a new target state in the automata
5700 * and then adds a transition from the @from state to the target state
5701 * activated by the value of @token
5702 *
5703 * Returns the target state or NULL in case of error
5704 */
5705xmlAutomataStatePtr
5706xmlAutomataNewTransition(xmlAutomataPtr am, xmlAutomataStatePtr from,
5707			 xmlAutomataStatePtr to, const xmlChar *token,
5708			 void *data) {
5709    xmlRegAtomPtr atom;
5710
5711    if ((am == NULL) || (from == NULL) || (token == NULL))
5712	return(NULL);
5713    atom = xmlRegNewAtom(am, XML_REGEXP_STRING);
5714    if (atom == NULL)
5715        return(NULL);
5716    atom->data = data;
5717    atom->valuep = xmlStrdup(token);
5718
5719    if (xmlFAGenerateTransitions(am, from, to, atom) < 0) {
5720        xmlRegFreeAtom(atom);
5721	return(NULL);
5722    }
5723    if (to == NULL)
5724	return(am->state);
5725    return(to);
5726}
5727
5728/**
5729 * xmlAutomataNewTransition2:
5730 * @am: an automata
5731 * @from: the starting point of the transition
5732 * @to: the target point of the transition or NULL
5733 * @token: the first input string associated to that transition
5734 * @token2: the second input string associated to that transition
5735 * @data: data passed to the callback function if the transition is activated
5736 *
5737 * If @to is NULL, this creates first a new target state in the automata
5738 * and then adds a transition from the @from state to the target state
5739 * activated by the value of @token
5740 *
5741 * Returns the target state or NULL in case of error
5742 */
5743xmlAutomataStatePtr
5744xmlAutomataNewTransition2(xmlAutomataPtr am, xmlAutomataStatePtr from,
5745			  xmlAutomataStatePtr to, const xmlChar *token,
5746			  const xmlChar *token2, void *data) {
5747    xmlRegAtomPtr atom;
5748
5749    if ((am == NULL) || (from == NULL) || (token == NULL))
5750	return(NULL);
5751    atom = xmlRegNewAtom(am, XML_REGEXP_STRING);
5752    if (atom == NULL)
5753	return(NULL);
5754    atom->data = data;
5755    if ((token2 == NULL) || (*token2 == 0)) {
5756	atom->valuep = xmlStrdup(token);
5757    } else {
5758	int lenn, lenp;
5759	xmlChar *str;
5760
5761	lenn = strlen((char *) token2);
5762	lenp = strlen((char *) token);
5763
5764	str = (xmlChar *) xmlMallocAtomic(lenn + lenp + 2);
5765	if (str == NULL) {
5766	    xmlRegFreeAtom(atom);
5767	    return(NULL);
5768	}
5769	memcpy(&str[0], token, lenp);
5770	str[lenp] = '|';
5771	memcpy(&str[lenp + 1], token2, lenn);
5772	str[lenn + lenp + 1] = 0;
5773
5774	atom->valuep = str;
5775    }
5776
5777    if (xmlFAGenerateTransitions(am, from, to, atom) < 0) {
5778        xmlRegFreeAtom(atom);
5779	return(NULL);
5780    }
5781    if (to == NULL)
5782	return(am->state);
5783    return(to);
5784}
5785
5786/**
5787 * xmlAutomataNewNegTrans:
5788 * @am: an automata
5789 * @from: the starting point of the transition
5790 * @to: the target point of the transition or NULL
5791 * @token: the first input string associated to that transition
5792 * @token2: the second input string associated to that transition
5793 * @data: data passed to the callback function if the transition is activated
5794 *
5795 * If @to is NULL, this creates first a new target state in the automata
5796 * and then adds a transition from the @from state to the target state
5797 * activated by any value except (@token,@token2)
5798 * Note that if @token2 is not NULL, then (X, NULL) won't match to follow
5799 # the semantic of XSD ##other
5800 *
5801 * Returns the target state or NULL in case of error
5802 */
5803xmlAutomataStatePtr
5804xmlAutomataNewNegTrans(xmlAutomataPtr am, xmlAutomataStatePtr from,
5805		       xmlAutomataStatePtr to, const xmlChar *token,
5806		       const xmlChar *token2, void *data) {
5807    xmlRegAtomPtr atom;
5808    xmlChar err_msg[200];
5809
5810    if ((am == NULL) || (from == NULL) || (token == NULL))
5811	return(NULL);
5812    atom = xmlRegNewAtom(am, XML_REGEXP_STRING);
5813    if (atom == NULL)
5814	return(NULL);
5815    atom->data = data;
5816    atom->neg = 1;
5817    if ((token2 == NULL) || (*token2 == 0)) {
5818	atom->valuep = xmlStrdup(token);
5819    } else {
5820	int lenn, lenp;
5821	xmlChar *str;
5822
5823	lenn = strlen((char *) token2);
5824	lenp = strlen((char *) token);
5825
5826	str = (xmlChar *) xmlMallocAtomic(lenn + lenp + 2);
5827	if (str == NULL) {
5828	    xmlRegFreeAtom(atom);
5829	    return(NULL);
5830	}
5831	memcpy(&str[0], token, lenp);
5832	str[lenp] = '|';
5833	memcpy(&str[lenp + 1], token2, lenn);
5834	str[lenn + lenp + 1] = 0;
5835
5836	atom->valuep = str;
5837    }
5838    snprintf((char *) err_msg, 199, "not %s", (const char *) atom->valuep);
5839    err_msg[199] = 0;
5840    atom->valuep2 = xmlStrdup(err_msg);
5841
5842    if (xmlFAGenerateTransitions(am, from, to, atom) < 0) {
5843        xmlRegFreeAtom(atom);
5844	return(NULL);
5845    }
5846    am->negs++;
5847    if (to == NULL)
5848	return(am->state);
5849    return(to);
5850}
5851
5852/**
5853 * xmlAutomataNewCountTrans2:
5854 * @am: an automata
5855 * @from: the starting point of the transition
5856 * @to: the target point of the transition or NULL
5857 * @token: the input string associated to that transition
5858 * @token2: the second input string associated to that transition
5859 * @min:  the minimum successive occurences of token
5860 * @max:  the maximum successive occurences of token
5861 * @data:  data associated to the transition
5862 *
5863 * If @to is NULL, this creates first a new target state in the automata
5864 * and then adds a transition from the @from state to the target state
5865 * activated by a succession of input of value @token and @token2 and
5866 * whose number is between @min and @max
5867 *
5868 * Returns the target state or NULL in case of error
5869 */
5870xmlAutomataStatePtr
5871xmlAutomataNewCountTrans2(xmlAutomataPtr am, xmlAutomataStatePtr from,
5872			 xmlAutomataStatePtr to, const xmlChar *token,
5873			 const xmlChar *token2,
5874			 int min, int max, void *data) {
5875    xmlRegAtomPtr atom;
5876    int counter;
5877
5878    if ((am == NULL) || (from == NULL) || (token == NULL))
5879	return(NULL);
5880    if (min < 0)
5881	return(NULL);
5882    if ((max < min) || (max < 1))
5883	return(NULL);
5884    atom = xmlRegNewAtom(am, XML_REGEXP_STRING);
5885    if (atom == NULL)
5886	return(NULL);
5887    if ((token2 == NULL) || (*token2 == 0)) {
5888	atom->valuep = xmlStrdup(token);
5889    } else {
5890	int lenn, lenp;
5891	xmlChar *str;
5892
5893	lenn = strlen((char *) token2);
5894	lenp = strlen((char *) token);
5895
5896	str = (xmlChar *) xmlMallocAtomic(lenn + lenp + 2);
5897	if (str == NULL) {
5898	    xmlRegFreeAtom(atom);
5899	    return(NULL);
5900	}
5901	memcpy(&str[0], token, lenp);
5902	str[lenp] = '|';
5903	memcpy(&str[lenp + 1], token2, lenn);
5904	str[lenn + lenp + 1] = 0;
5905
5906	atom->valuep = str;
5907    }
5908    atom->data = data;
5909    if (min == 0)
5910	atom->min = 1;
5911    else
5912	atom->min = min;
5913    atom->max = max;
5914
5915    /*
5916     * associate a counter to the transition.
5917     */
5918    counter = xmlRegGetCounter(am);
5919    am->counters[counter].min = min;
5920    am->counters[counter].max = max;
5921
5922    /* xmlFAGenerateTransitions(am, from, to, atom); */
5923    if (to == NULL) {
5924        to = xmlRegNewState(am);
5925	xmlRegStatePush(am, to);
5926    }
5927    xmlRegStateAddTrans(am, from, atom, to, counter, -1);
5928    xmlRegAtomPush(am, atom);
5929    am->state = to;
5930
5931    if (to == NULL)
5932	to = am->state;
5933    if (to == NULL)
5934	return(NULL);
5935    if (min == 0)
5936	xmlFAGenerateEpsilonTransition(am, from, to);
5937    return(to);
5938}
5939
5940/**
5941 * xmlAutomataNewCountTrans:
5942 * @am: an automata
5943 * @from: the starting point of the transition
5944 * @to: the target point of the transition or NULL
5945 * @token: the input string associated to that transition
5946 * @min:  the minimum successive occurences of token
5947 * @max:  the maximum successive occurences of token
5948 * @data:  data associated to the transition
5949 *
5950 * If @to is NULL, this creates first a new target state in the automata
5951 * and then adds a transition from the @from state to the target state
5952 * activated by a succession of input of value @token and whose number
5953 * is between @min and @max
5954 *
5955 * Returns the target state or NULL in case of error
5956 */
5957xmlAutomataStatePtr
5958xmlAutomataNewCountTrans(xmlAutomataPtr am, xmlAutomataStatePtr from,
5959			 xmlAutomataStatePtr to, const xmlChar *token,
5960			 int min, int max, void *data) {
5961    xmlRegAtomPtr atom;
5962    int counter;
5963
5964    if ((am == NULL) || (from == NULL) || (token == NULL))
5965	return(NULL);
5966    if (min < 0)
5967	return(NULL);
5968    if ((max < min) || (max < 1))
5969	return(NULL);
5970    atom = xmlRegNewAtom(am, XML_REGEXP_STRING);
5971    if (atom == NULL)
5972	return(NULL);
5973    atom->valuep = xmlStrdup(token);
5974    atom->data = data;
5975    if (min == 0)
5976	atom->min = 1;
5977    else
5978	atom->min = min;
5979    atom->max = max;
5980
5981    /*
5982     * associate a counter to the transition.
5983     */
5984    counter = xmlRegGetCounter(am);
5985    am->counters[counter].min = min;
5986    am->counters[counter].max = max;
5987
5988    /* xmlFAGenerateTransitions(am, from, to, atom); */
5989    if (to == NULL) {
5990        to = xmlRegNewState(am);
5991	xmlRegStatePush(am, to);
5992    }
5993    xmlRegStateAddTrans(am, from, atom, to, counter, -1);
5994    xmlRegAtomPush(am, atom);
5995    am->state = to;
5996
5997    if (to == NULL)
5998	to = am->state;
5999    if (to == NULL)
6000	return(NULL);
6001    if (min == 0)
6002	xmlFAGenerateEpsilonTransition(am, from, to);
6003    return(to);
6004}
6005
6006/**
6007 * xmlAutomataNewOnceTrans2:
6008 * @am: an automata
6009 * @from: the starting point of the transition
6010 * @to: the target point of the transition or NULL
6011 * @token: the input string associated to that transition
6012 * @token2: the second input string associated to that transition
6013 * @min:  the minimum successive occurences of token
6014 * @max:  the maximum successive occurences of token
6015 * @data:  data associated to the transition
6016 *
6017 * If @to is NULL, this creates first a new target state in the automata
6018 * and then adds a transition from the @from state to the target state
6019 * activated by a succession of input of value @token and @token2 and whose
6020 * number is between @min and @max, moreover that transition can only be
6021 * crossed once.
6022 *
6023 * Returns the target state or NULL in case of error
6024 */
6025xmlAutomataStatePtr
6026xmlAutomataNewOnceTrans2(xmlAutomataPtr am, xmlAutomataStatePtr from,
6027			 xmlAutomataStatePtr to, const xmlChar *token,
6028			 const xmlChar *token2,
6029			 int min, int max, void *data) {
6030    xmlRegAtomPtr atom;
6031    int counter;
6032
6033    if ((am == NULL) || (from == NULL) || (token == NULL))
6034	return(NULL);
6035    if (min < 1)
6036	return(NULL);
6037    if ((max < min) || (max < 1))
6038	return(NULL);
6039    atom = xmlRegNewAtom(am, XML_REGEXP_STRING);
6040    if (atom == NULL)
6041	return(NULL);
6042    if ((token2 == NULL) || (*token2 == 0)) {
6043	atom->valuep = xmlStrdup(token);
6044    } else {
6045	int lenn, lenp;
6046	xmlChar *str;
6047
6048	lenn = strlen((char *) token2);
6049	lenp = strlen((char *) token);
6050
6051	str = (xmlChar *) xmlMallocAtomic(lenn + lenp + 2);
6052	if (str == NULL) {
6053	    xmlRegFreeAtom(atom);
6054	    return(NULL);
6055	}
6056	memcpy(&str[0], token, lenp);
6057	str[lenp] = '|';
6058	memcpy(&str[lenp + 1], token2, lenn);
6059	str[lenn + lenp + 1] = 0;
6060
6061	atom->valuep = str;
6062    }
6063    atom->data = data;
6064    atom->quant = XML_REGEXP_QUANT_ONCEONLY;
6065    atom->min = min;
6066    atom->max = max;
6067    /*
6068     * associate a counter to the transition.
6069     */
6070    counter = xmlRegGetCounter(am);
6071    am->counters[counter].min = 1;
6072    am->counters[counter].max = 1;
6073
6074    /* xmlFAGenerateTransitions(am, from, to, atom); */
6075    if (to == NULL) {
6076	to = xmlRegNewState(am);
6077	xmlRegStatePush(am, to);
6078    }
6079    xmlRegStateAddTrans(am, from, atom, to, counter, -1);
6080    xmlRegAtomPush(am, atom);
6081    am->state = to;
6082    return(to);
6083}
6084
6085
6086
6087/**
6088 * xmlAutomataNewOnceTrans:
6089 * @am: an automata
6090 * @from: the starting point of the transition
6091 * @to: the target point of the transition or NULL
6092 * @token: the input string associated to that transition
6093 * @min:  the minimum successive occurences of token
6094 * @max:  the maximum successive occurences of token
6095 * @data:  data associated to the transition
6096 *
6097 * If @to is NULL, this creates first a new target state in the automata
6098 * and then adds a transition from the @from state to the target state
6099 * activated by a succession of input of value @token and whose number
6100 * is between @min and @max, moreover that transition can only be crossed
6101 * once.
6102 *
6103 * Returns the target state or NULL in case of error
6104 */
6105xmlAutomataStatePtr
6106xmlAutomataNewOnceTrans(xmlAutomataPtr am, xmlAutomataStatePtr from,
6107			 xmlAutomataStatePtr to, const xmlChar *token,
6108			 int min, int max, void *data) {
6109    xmlRegAtomPtr atom;
6110    int counter;
6111
6112    if ((am == NULL) || (from == NULL) || (token == NULL))
6113	return(NULL);
6114    if (min < 1)
6115	return(NULL);
6116    if ((max < min) || (max < 1))
6117	return(NULL);
6118    atom = xmlRegNewAtom(am, XML_REGEXP_STRING);
6119    if (atom == NULL)
6120	return(NULL);
6121    atom->valuep = xmlStrdup(token);
6122    atom->data = data;
6123    atom->quant = XML_REGEXP_QUANT_ONCEONLY;
6124    atom->min = min;
6125    atom->max = max;
6126    /*
6127     * associate a counter to the transition.
6128     */
6129    counter = xmlRegGetCounter(am);
6130    am->counters[counter].min = 1;
6131    am->counters[counter].max = 1;
6132
6133    /* xmlFAGenerateTransitions(am, from, to, atom); */
6134    if (to == NULL) {
6135	to = xmlRegNewState(am);
6136	xmlRegStatePush(am, to);
6137    }
6138    xmlRegStateAddTrans(am, from, atom, to, counter, -1);
6139    xmlRegAtomPush(am, atom);
6140    am->state = to;
6141    return(to);
6142}
6143
6144/**
6145 * xmlAutomataNewState:
6146 * @am: an automata
6147 *
6148 * Create a new disconnected state in the automata
6149 *
6150 * Returns the new state or NULL in case of error
6151 */
6152xmlAutomataStatePtr
6153xmlAutomataNewState(xmlAutomataPtr am) {
6154    xmlAutomataStatePtr to;
6155
6156    if (am == NULL)
6157	return(NULL);
6158    to = xmlRegNewState(am);
6159    xmlRegStatePush(am, to);
6160    return(to);
6161}
6162
6163/**
6164 * xmlAutomataNewEpsilon:
6165 * @am: an automata
6166 * @from: the starting point of the transition
6167 * @to: the target point of the transition or NULL
6168 *
6169 * If @to is NULL, this creates first a new target state in the automata
6170 * and then adds an epsilon transition from the @from state to the
6171 * target state
6172 *
6173 * Returns the target state or NULL in case of error
6174 */
6175xmlAutomataStatePtr
6176xmlAutomataNewEpsilon(xmlAutomataPtr am, xmlAutomataStatePtr from,
6177		      xmlAutomataStatePtr to) {
6178    if ((am == NULL) || (from == NULL))
6179	return(NULL);
6180    xmlFAGenerateEpsilonTransition(am, from, to);
6181    if (to == NULL)
6182	return(am->state);
6183    return(to);
6184}
6185
6186/**
6187 * xmlAutomataNewAllTrans:
6188 * @am: an automata
6189 * @from: the starting point of the transition
6190 * @to: the target point of the transition or NULL
6191 * @lax: allow to transition if not all all transitions have been activated
6192 *
6193 * If @to is NULL, this creates first a new target state in the automata
6194 * and then adds a an ALL transition from the @from state to the
6195 * target state. That transition is an epsilon transition allowed only when
6196 * all transitions from the @from node have been activated.
6197 *
6198 * Returns the target state or NULL in case of error
6199 */
6200xmlAutomataStatePtr
6201xmlAutomataNewAllTrans(xmlAutomataPtr am, xmlAutomataStatePtr from,
6202		       xmlAutomataStatePtr to, int lax) {
6203    if ((am == NULL) || (from == NULL))
6204	return(NULL);
6205    xmlFAGenerateAllTransition(am, from, to, lax);
6206    if (to == NULL)
6207	return(am->state);
6208    return(to);
6209}
6210
6211/**
6212 * xmlAutomataNewCounter:
6213 * @am: an automata
6214 * @min:  the minimal value on the counter
6215 * @max:  the maximal value on the counter
6216 *
6217 * Create a new counter
6218 *
6219 * Returns the counter number or -1 in case of error
6220 */
6221int
6222xmlAutomataNewCounter(xmlAutomataPtr am, int min, int max) {
6223    int ret;
6224
6225    if (am == NULL)
6226	return(-1);
6227
6228    ret = xmlRegGetCounter(am);
6229    if (ret < 0)
6230	return(-1);
6231    am->counters[ret].min = min;
6232    am->counters[ret].max = max;
6233    return(ret);
6234}
6235
6236/**
6237 * xmlAutomataNewCountedTrans:
6238 * @am: an automata
6239 * @from: the starting point of the transition
6240 * @to: the target point of the transition or NULL
6241 * @counter: the counter associated to that transition
6242 *
6243 * If @to is NULL, this creates first a new target state in the automata
6244 * and then adds an epsilon transition from the @from state to the target state
6245 * which will increment the counter provided
6246 *
6247 * Returns the target state or NULL in case of error
6248 */
6249xmlAutomataStatePtr
6250xmlAutomataNewCountedTrans(xmlAutomataPtr am, xmlAutomataStatePtr from,
6251		xmlAutomataStatePtr to, int counter) {
6252    if ((am == NULL) || (from == NULL) || (counter < 0))
6253	return(NULL);
6254    xmlFAGenerateCountedEpsilonTransition(am, from, to, counter);
6255    if (to == NULL)
6256	return(am->state);
6257    return(to);
6258}
6259
6260/**
6261 * xmlAutomataNewCounterTrans:
6262 * @am: an automata
6263 * @from: the starting point of the transition
6264 * @to: the target point of the transition or NULL
6265 * @counter: the counter associated to that transition
6266 *
6267 * If @to is NULL, this creates first a new target state in the automata
6268 * and then adds an epsilon transition from the @from state to the target state
6269 * which will be allowed only if the counter is within the right range.
6270 *
6271 * Returns the target state or NULL in case of error
6272 */
6273xmlAutomataStatePtr
6274xmlAutomataNewCounterTrans(xmlAutomataPtr am, xmlAutomataStatePtr from,
6275		xmlAutomataStatePtr to, int counter) {
6276    if ((am == NULL) || (from == NULL) || (counter < 0))
6277	return(NULL);
6278    xmlFAGenerateCountedTransition(am, from, to, counter);
6279    if (to == NULL)
6280	return(am->state);
6281    return(to);
6282}
6283
6284/**
6285 * xmlAutomataCompile:
6286 * @am: an automata
6287 *
6288 * Compile the automata into a Reg Exp ready for being executed.
6289 * The automata should be free after this point.
6290 *
6291 * Returns the compiled regexp or NULL in case of error
6292 */
6293xmlRegexpPtr
6294xmlAutomataCompile(xmlAutomataPtr am) {
6295    xmlRegexpPtr ret;
6296
6297    if ((am == NULL) || (am->error != 0)) return(NULL);
6298    xmlFAEliminateEpsilonTransitions(am);
6299    /* xmlFAComputesDeterminism(am); */
6300    ret = xmlRegEpxFromParse(am);
6301
6302    return(ret);
6303}
6304
6305/**
6306 * xmlAutomataIsDeterminist:
6307 * @am: an automata
6308 *
6309 * Checks if an automata is determinist.
6310 *
6311 * Returns 1 if true, 0 if not, and -1 in case of error
6312 */
6313int
6314xmlAutomataIsDeterminist(xmlAutomataPtr am) {
6315    int ret;
6316
6317    if (am == NULL)
6318	return(-1);
6319
6320    ret = xmlFAComputesDeterminism(am);
6321    return(ret);
6322}
6323#endif /* LIBXML_AUTOMATA_ENABLED */
6324
6325#ifdef LIBXML_EXPR_ENABLED
6326/************************************************************************
6327 *									*
6328 *		Formal Expression handling code				*
6329 *									*
6330 ************************************************************************/
6331/************************************************************************
6332 *									*
6333 *		Expression handling context				*
6334 *									*
6335 ************************************************************************/
6336
6337struct _xmlExpCtxt {
6338    xmlDictPtr dict;
6339    xmlExpNodePtr *table;
6340    int size;
6341    int nbElems;
6342    int nb_nodes;
6343    int maxNodes;
6344    const char *expr;
6345    const char *cur;
6346    int nb_cons;
6347    int tabSize;
6348};
6349
6350/**
6351 * xmlExpNewCtxt:
6352 * @maxNodes:  the maximum number of nodes
6353 * @dict:  optional dictionary to use internally
6354 *
6355 * Creates a new context for manipulating expressions
6356 *
6357 * Returns the context or NULL in case of error
6358 */
6359xmlExpCtxtPtr
6360xmlExpNewCtxt(int maxNodes, xmlDictPtr dict) {
6361    xmlExpCtxtPtr ret;
6362    int size = 256;
6363
6364    if (maxNodes <= 4096)
6365        maxNodes = 4096;
6366
6367    ret = (xmlExpCtxtPtr) xmlMalloc(sizeof(xmlExpCtxt));
6368    if (ret == NULL)
6369        return(NULL);
6370    memset(ret, 0, sizeof(xmlExpCtxt));
6371    ret->size = size;
6372    ret->nbElems = 0;
6373    ret->maxNodes = maxNodes;
6374    ret->table = xmlMalloc(size * sizeof(xmlExpNodePtr));
6375    if (ret->table == NULL) {
6376        xmlFree(ret);
6377	return(NULL);
6378    }
6379    memset(ret->table, 0, size * sizeof(xmlExpNodePtr));
6380    if (dict == NULL) {
6381        ret->dict = xmlDictCreate();
6382	if (ret->dict == NULL) {
6383	    xmlFree(ret->table);
6384	    xmlFree(ret);
6385	    return(NULL);
6386	}
6387    } else {
6388        ret->dict = dict;
6389	xmlDictReference(ret->dict);
6390    }
6391    return(ret);
6392}
6393
6394/**
6395 * xmlExpFreeCtxt:
6396 * @ctxt:  an expression context
6397 *
6398 * Free an expression context
6399 */
6400void
6401xmlExpFreeCtxt(xmlExpCtxtPtr ctxt) {
6402    if (ctxt == NULL)
6403        return;
6404    xmlDictFree(ctxt->dict);
6405    if (ctxt->table != NULL)
6406	xmlFree(ctxt->table);
6407    xmlFree(ctxt);
6408}
6409
6410/************************************************************************
6411 *									*
6412 *		Structure associated to an expression node		*
6413 *									*
6414 ************************************************************************/
6415#define MAX_NODES 10000
6416
6417/* #define DEBUG_DERIV */
6418
6419/*
6420 * TODO:
6421 * - Wildcards
6422 * - public API for creation
6423 *
6424 * Started
6425 * - regression testing
6426 *
6427 * Done
6428 * - split into module and test tool
6429 * - memleaks
6430 */
6431
6432typedef enum {
6433    XML_EXP_NILABLE = (1 << 0)
6434} xmlExpNodeInfo;
6435
6436#define IS_NILLABLE(node) ((node)->info & XML_EXP_NILABLE)
6437
6438struct _xmlExpNode {
6439    unsigned char type;/* xmlExpNodeType */
6440    unsigned char info;/* OR of xmlExpNodeInfo */
6441    unsigned short key;	/* the hash key */
6442    unsigned int ref;	/* The number of references */
6443    int c_max;		/* the maximum length it can consume */
6444    xmlExpNodePtr exp_left;
6445    xmlExpNodePtr next;/* the next node in the hash table or free list */
6446    union {
6447	struct {
6448	    int f_min;
6449	    int f_max;
6450	} count;
6451	struct {
6452	    xmlExpNodePtr f_right;
6453	} children;
6454        const xmlChar *f_str;
6455    } field;
6456};
6457
6458#define exp_min field.count.f_min
6459#define exp_max field.count.f_max
6460/* #define exp_left field.children.f_left */
6461#define exp_right field.children.f_right
6462#define exp_str field.f_str
6463
6464static xmlExpNodePtr xmlExpNewNode(xmlExpCtxtPtr ctxt, xmlExpNodeType type);
6465static xmlExpNode forbiddenExpNode = {
6466    XML_EXP_FORBID, 0, 0, 0, 0, NULL, NULL, {{ 0, 0}}
6467};
6468xmlExpNodePtr forbiddenExp = &forbiddenExpNode;
6469static xmlExpNode emptyExpNode = {
6470    XML_EXP_EMPTY, 1, 0, 0, 0, NULL, NULL, {{ 0, 0}}
6471};
6472xmlExpNodePtr emptyExp = &emptyExpNode;
6473
6474/************************************************************************
6475 *									*
6476 *  The custom hash table for unicity and canonicalization		*
6477 *  of sub-expressions pointers						*
6478 *									*
6479 ************************************************************************/
6480/*
6481 * xmlExpHashNameComputeKey:
6482 * Calculate the hash key for a token
6483 */
6484static unsigned short
6485xmlExpHashNameComputeKey(const xmlChar *name) {
6486    unsigned short value = 0L;
6487    char ch;
6488
6489    if (name != NULL) {
6490	value += 30 * (*name);
6491	while ((ch = *name++) != 0) {
6492	    value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
6493	}
6494    }
6495    return (value);
6496}
6497
6498/*
6499 * xmlExpHashComputeKey:
6500 * Calculate the hash key for a compound expression
6501 */
6502static unsigned short
6503xmlExpHashComputeKey(xmlExpNodeType type, xmlExpNodePtr left,
6504                     xmlExpNodePtr right) {
6505    unsigned long value;
6506    unsigned short ret;
6507
6508    switch (type) {
6509        case XML_EXP_SEQ:
6510	    value = left->key;
6511	    value += right->key;
6512	    value *= 3;
6513	    ret = (unsigned short) value;
6514	    break;
6515        case XML_EXP_OR:
6516	    value = left->key;
6517	    value += right->key;
6518	    value *= 7;
6519	    ret = (unsigned short) value;
6520	    break;
6521        case XML_EXP_COUNT:
6522	    value = left->key;
6523	    value += right->key;
6524	    ret = (unsigned short) value;
6525	    break;
6526	default:
6527	    ret = 0;
6528    }
6529    return(ret);
6530}
6531
6532
6533static xmlExpNodePtr
6534xmlExpNewNode(xmlExpCtxtPtr ctxt, xmlExpNodeType type) {
6535    xmlExpNodePtr ret;
6536
6537    if (ctxt->nb_nodes >= MAX_NODES)
6538        return(NULL);
6539    ret = (xmlExpNodePtr) xmlMalloc(sizeof(xmlExpNode));
6540    if (ret == NULL)
6541        return(NULL);
6542    memset(ret, 0, sizeof(xmlExpNode));
6543    ret->type = type;
6544    ret->next = NULL;
6545    ctxt->nb_nodes++;
6546    ctxt->nb_cons++;
6547    return(ret);
6548}
6549
6550/**
6551 * xmlExpHashGetEntry:
6552 * @table: the hash table
6553 *
6554 * Get the unique entry from the hash table. The entry is created if
6555 * needed. @left and @right are consumed, i.e. their ref count will
6556 * be decremented by the operation.
6557 *
6558 * Returns the pointer or NULL in case of error
6559 */
6560static xmlExpNodePtr
6561xmlExpHashGetEntry(xmlExpCtxtPtr ctxt, xmlExpNodeType type,
6562                   xmlExpNodePtr left, xmlExpNodePtr right,
6563		   const xmlChar *name, int min, int max) {
6564    unsigned short kbase, key;
6565    xmlExpNodePtr entry;
6566    xmlExpNodePtr insert;
6567
6568    if (ctxt == NULL)
6569	return(NULL);
6570
6571    /*
6572     * Check for duplicate and insertion location.
6573     */
6574    if (type == XML_EXP_ATOM) {
6575	kbase = xmlExpHashNameComputeKey(name);
6576    } else if (type == XML_EXP_COUNT) {
6577        /* COUNT reduction rule 1 */
6578	/* a{1} -> a */
6579	if (min == max) {
6580	    if (min == 1) {
6581		return(left);
6582	    }
6583	    if (min == 0) {
6584		xmlExpFree(ctxt, left);
6585	        return(emptyExp);
6586	    }
6587	}
6588	if (min < 0) {
6589	    xmlExpFree(ctxt, left);
6590	    return(forbiddenExp);
6591	}
6592        if (max == -1)
6593	    kbase = min + 79;
6594	else
6595	    kbase = max - min;
6596	kbase += left->key;
6597    } else if (type == XML_EXP_OR) {
6598        /* Forbid reduction rules */
6599        if (left->type == XML_EXP_FORBID) {
6600	    xmlExpFree(ctxt, left);
6601	    return(right);
6602	}
6603        if (right->type == XML_EXP_FORBID) {
6604	    xmlExpFree(ctxt, right);
6605	    return(left);
6606	}
6607
6608        /* OR reduction rule 1 */
6609	/* a | a reduced to a */
6610        if (left == right) {
6611	    left->ref--;
6612	    return(left);
6613	}
6614        /* OR canonicalization rule 1 */
6615	/* linearize (a | b) | c into a | (b | c) */
6616        if ((left->type == XML_EXP_OR) && (right->type != XML_EXP_OR)) {
6617	    xmlExpNodePtr tmp = left;
6618            left = right;
6619	    right = tmp;
6620	}
6621        /* OR reduction rule 2 */
6622	/* a | (a | b) and b | (a | b) are reduced to a | b */
6623        if (right->type == XML_EXP_OR) {
6624	    if ((left == right->exp_left) ||
6625	        (left == right->exp_right)) {
6626		xmlExpFree(ctxt, left);
6627		return(right);
6628	    }
6629	}
6630        /* OR canonicalization rule 2 */
6631	/* linearize (a | b) | c into a | (b | c) */
6632        if (left->type == XML_EXP_OR) {
6633	    xmlExpNodePtr tmp;
6634
6635	    /* OR canonicalization rule 2 */
6636	    if ((left->exp_right->type != XML_EXP_OR) &&
6637	        (left->exp_right->key < left->exp_left->key)) {
6638	        tmp = left->exp_right;
6639		left->exp_right = left->exp_left;
6640		left->exp_left = tmp;
6641	    }
6642	    left->exp_right->ref++;
6643	    tmp = xmlExpHashGetEntry(ctxt, XML_EXP_OR, left->exp_right, right,
6644	                             NULL, 0, 0);
6645	    left->exp_left->ref++;
6646	    tmp = xmlExpHashGetEntry(ctxt, XML_EXP_OR, left->exp_left, tmp,
6647	                             NULL, 0, 0);
6648
6649	    xmlExpFree(ctxt, left);
6650	    return(tmp);
6651	}
6652	if (right->type == XML_EXP_OR) {
6653	    /* Ordering in the tree */
6654	    /* C | (A | B) -> A | (B | C) */
6655	    if (left->key > right->exp_right->key) {
6656		xmlExpNodePtr tmp;
6657		right->exp_right->ref++;
6658		tmp = xmlExpHashGetEntry(ctxt, XML_EXP_OR, right->exp_right,
6659		                         left, NULL, 0, 0);
6660		right->exp_left->ref++;
6661		tmp = xmlExpHashGetEntry(ctxt, XML_EXP_OR, right->exp_left,
6662		                         tmp, NULL, 0, 0);
6663		xmlExpFree(ctxt, right);
6664		return(tmp);
6665	    }
6666	    /* Ordering in the tree */
6667	    /* B | (A | C) -> A | (B | C) */
6668	    if (left->key > right->exp_left->key) {
6669		xmlExpNodePtr tmp;
6670		right->exp_right->ref++;
6671		tmp = xmlExpHashGetEntry(ctxt, XML_EXP_OR, left,
6672		                         right->exp_right, NULL, 0, 0);
6673		right->exp_left->ref++;
6674		tmp = xmlExpHashGetEntry(ctxt, XML_EXP_OR, right->exp_left,
6675		                         tmp, NULL, 0, 0);
6676		xmlExpFree(ctxt, right);
6677		return(tmp);
6678	    }
6679	}
6680	/* we know both types are != XML_EXP_OR here */
6681        else if (left->key > right->key) {
6682	    xmlExpNodePtr tmp = left;
6683            left = right;
6684	    right = tmp;
6685	}
6686	kbase = xmlExpHashComputeKey(type, left, right);
6687    } else if (type == XML_EXP_SEQ) {
6688        /* Forbid reduction rules */
6689        if (left->type == XML_EXP_FORBID) {
6690	    xmlExpFree(ctxt, right);
6691	    return(left);
6692	}
6693        if (right->type == XML_EXP_FORBID) {
6694	    xmlExpFree(ctxt, left);
6695	    return(right);
6696	}
6697        /* Empty reduction rules */
6698        if (right->type == XML_EXP_EMPTY) {
6699	    return(left);
6700	}
6701        if (left->type == XML_EXP_EMPTY) {
6702	    return(right);
6703	}
6704	kbase = xmlExpHashComputeKey(type, left, right);
6705    } else
6706        return(NULL);
6707
6708    key = kbase % ctxt->size;
6709    if (ctxt->table[key] != NULL) {
6710	for (insert = ctxt->table[key]; insert != NULL;
6711	     insert = insert->next) {
6712	    if ((insert->key == kbase) &&
6713	        (insert->type == type)) {
6714		if (type == XML_EXP_ATOM) {
6715		    if (name == insert->exp_str) {
6716			insert->ref++;
6717			return(insert);
6718		    }
6719		} else if (type == XML_EXP_COUNT) {
6720		    if ((insert->exp_min == min) && (insert->exp_max == max) &&
6721		        (insert->exp_left == left)) {
6722			insert->ref++;
6723			left->ref--;
6724			return(insert);
6725		    }
6726		} else if ((insert->exp_left == left) &&
6727			   (insert->exp_right == right)) {
6728		    insert->ref++;
6729		    left->ref--;
6730		    right->ref--;
6731		    return(insert);
6732		}
6733	    }
6734	}
6735    }
6736
6737    entry = xmlExpNewNode(ctxt, type);
6738    if (entry == NULL)
6739        return(NULL);
6740    entry->key = kbase;
6741    if (type == XML_EXP_ATOM) {
6742	entry->exp_str = name;
6743	entry->c_max = 1;
6744    } else if (type == XML_EXP_COUNT) {
6745        entry->exp_min = min;
6746        entry->exp_max = max;
6747	entry->exp_left = left;
6748	if ((min == 0) || (IS_NILLABLE(left)))
6749	    entry->info |= XML_EXP_NILABLE;
6750	if (max < 0)
6751	    entry->c_max = -1;
6752	else
6753	    entry->c_max = max * entry->exp_left->c_max;
6754    } else {
6755	entry->exp_left = left;
6756	entry->exp_right = right;
6757	if (type == XML_EXP_OR) {
6758	    if ((IS_NILLABLE(left)) || (IS_NILLABLE(right)))
6759		entry->info |= XML_EXP_NILABLE;
6760	    if ((entry->exp_left->c_max == -1) ||
6761	        (entry->exp_right->c_max == -1))
6762		entry->c_max = -1;
6763	    else if (entry->exp_left->c_max > entry->exp_right->c_max)
6764	        entry->c_max = entry->exp_left->c_max;
6765	    else
6766	        entry->c_max = entry->exp_right->c_max;
6767	} else {
6768	    if ((IS_NILLABLE(left)) && (IS_NILLABLE(right)))
6769		entry->info |= XML_EXP_NILABLE;
6770	    if ((entry->exp_left->c_max == -1) ||
6771	        (entry->exp_right->c_max == -1))
6772		entry->c_max = -1;
6773	    else
6774	        entry->c_max = entry->exp_left->c_max + entry->exp_right->c_max;
6775	}
6776    }
6777    entry->ref = 1;
6778    if (ctxt->table[key] != NULL)
6779        entry->next = ctxt->table[key];
6780
6781    ctxt->table[key] = entry;
6782    ctxt->nbElems++;
6783
6784    return(entry);
6785}
6786
6787/**
6788 * xmlExpFree:
6789 * @ctxt: the expression context
6790 * @exp: the expression
6791 *
6792 * Dereference the expression
6793 */
6794void
6795xmlExpFree(xmlExpCtxtPtr ctxt, xmlExpNodePtr exp) {
6796    if ((exp == NULL) || (exp == forbiddenExp) || (exp == emptyExp))
6797        return;
6798    exp->ref--;
6799    if (exp->ref == 0) {
6800        unsigned short key;
6801
6802        /* Unlink it first from the hash table */
6803	key = exp->key % ctxt->size;
6804	if (ctxt->table[key] == exp) {
6805	    ctxt->table[key] = exp->next;
6806	} else {
6807	    xmlExpNodePtr tmp;
6808
6809	    tmp = ctxt->table[key];
6810	    while (tmp != NULL) {
6811	        if (tmp->next == exp) {
6812		    tmp->next = exp->next;
6813		    break;
6814		}
6815	        tmp = tmp->next;
6816	    }
6817	}
6818
6819        if ((exp->type == XML_EXP_SEQ) || (exp->type == XML_EXP_OR)) {
6820	    xmlExpFree(ctxt, exp->exp_left);
6821	    xmlExpFree(ctxt, exp->exp_right);
6822	} else if (exp->type == XML_EXP_COUNT) {
6823	    xmlExpFree(ctxt, exp->exp_left);
6824	}
6825        xmlFree(exp);
6826	ctxt->nb_nodes--;
6827    }
6828}
6829
6830/**
6831 * xmlExpRef:
6832 * @exp: the expression
6833 *
6834 * Increase the reference count of the expression
6835 */
6836void
6837xmlExpRef(xmlExpNodePtr exp) {
6838    if (exp != NULL)
6839        exp->ref++;
6840}
6841
6842/**
6843 * xmlExpNewAtom:
6844 * @ctxt: the expression context
6845 * @name: the atom name
6846 * @len: the atom name length in byte (or -1);
6847 *
6848 * Get the atom associated to this name from that context
6849 *
6850 * Returns the node or NULL in case of error
6851 */
6852xmlExpNodePtr
6853xmlExpNewAtom(xmlExpCtxtPtr ctxt, const xmlChar *name, int len) {
6854    if ((ctxt == NULL) || (name == NULL))
6855        return(NULL);
6856    name = xmlDictLookup(ctxt->dict, name, len);
6857    if (name == NULL)
6858        return(NULL);
6859    return(xmlExpHashGetEntry(ctxt, XML_EXP_ATOM, NULL, NULL, name, 0, 0));
6860}
6861
6862/**
6863 * xmlExpNewOr:
6864 * @ctxt: the expression context
6865 * @left: left expression
6866 * @right: right expression
6867 *
6868 * Get the atom associated to the choice @left | @right
6869 * Note that @left and @right are consumed in the operation, to keep
6870 * an handle on them use xmlExpRef() and use xmlExpFree() to release them,
6871 * this is true even in case of failure (unless ctxt == NULL).
6872 *
6873 * Returns the node or NULL in case of error
6874 */
6875xmlExpNodePtr
6876xmlExpNewOr(xmlExpCtxtPtr ctxt, xmlExpNodePtr left, xmlExpNodePtr right) {
6877    if (ctxt == NULL)
6878        return(NULL);
6879    if ((left == NULL) || (right == NULL)) {
6880        xmlExpFree(ctxt, left);
6881        xmlExpFree(ctxt, right);
6882        return(NULL);
6883    }
6884    return(xmlExpHashGetEntry(ctxt, XML_EXP_OR, left, right, NULL, 0, 0));
6885}
6886
6887/**
6888 * xmlExpNewSeq:
6889 * @ctxt: the expression context
6890 * @left: left expression
6891 * @right: right expression
6892 *
6893 * Get the atom associated to the sequence @left , @right
6894 * Note that @left and @right are consumed in the operation, to keep
6895 * an handle on them use xmlExpRef() and use xmlExpFree() to release them,
6896 * this is true even in case of failure (unless ctxt == NULL).
6897 *
6898 * Returns the node or NULL in case of error
6899 */
6900xmlExpNodePtr
6901xmlExpNewSeq(xmlExpCtxtPtr ctxt, xmlExpNodePtr left, xmlExpNodePtr right) {
6902    if (ctxt == NULL)
6903        return(NULL);
6904    if ((left == NULL) || (right == NULL)) {
6905        xmlExpFree(ctxt, left);
6906        xmlExpFree(ctxt, right);
6907        return(NULL);
6908    }
6909    return(xmlExpHashGetEntry(ctxt, XML_EXP_SEQ, left, right, NULL, 0, 0));
6910}
6911
6912/**
6913 * xmlExpNewRange:
6914 * @ctxt: the expression context
6915 * @subset: the expression to be repeated
6916 * @min: the lower bound for the repetition
6917 * @max: the upper bound for the repetition, -1 means infinite
6918 *
6919 * Get the atom associated to the range (@subset){@min, @max}
6920 * Note that @subset is consumed in the operation, to keep
6921 * an handle on it use xmlExpRef() and use xmlExpFree() to release it,
6922 * this is true even in case of failure (unless ctxt == NULL).
6923 *
6924 * Returns the node or NULL in case of error
6925 */
6926xmlExpNodePtr
6927xmlExpNewRange(xmlExpCtxtPtr ctxt, xmlExpNodePtr subset, int min, int max) {
6928    if (ctxt == NULL)
6929        return(NULL);
6930    if ((subset == NULL) || (min < 0) || (max < -1) ||
6931        ((max >= 0) && (min > max))) {
6932	xmlExpFree(ctxt, subset);
6933        return(NULL);
6934    }
6935    return(xmlExpHashGetEntry(ctxt, XML_EXP_COUNT, subset,
6936                              NULL, NULL, min, max));
6937}
6938
6939/************************************************************************
6940 *									*
6941 *		Public API for operations on expressions		*
6942 *									*
6943 ************************************************************************/
6944
6945static int
6946xmlExpGetLanguageInt(xmlExpCtxtPtr ctxt, xmlExpNodePtr exp,
6947                     const xmlChar**list, int len, int nb) {
6948    int tmp, tmp2;
6949tail:
6950    switch (exp->type) {
6951        case XML_EXP_EMPTY:
6952	    return(0);
6953        case XML_EXP_ATOM:
6954	    for (tmp = 0;tmp < nb;tmp++)
6955	        if (list[tmp] == exp->exp_str)
6956		    return(0);
6957            if (nb >= len)
6958	        return(-2);
6959	    list[nb] = exp->exp_str;
6960	    return(1);
6961        case XML_EXP_COUNT:
6962	    exp = exp->exp_left;
6963	    goto tail;
6964        case XML_EXP_SEQ:
6965        case XML_EXP_OR:
6966	    tmp = xmlExpGetLanguageInt(ctxt, exp->exp_left, list, len, nb);
6967	    if (tmp < 0)
6968	        return(tmp);
6969	    tmp2 = xmlExpGetLanguageInt(ctxt, exp->exp_right, list, len,
6970	                                nb + tmp);
6971	    if (tmp2 < 0)
6972	        return(tmp2);
6973            return(tmp + tmp2);
6974    }
6975    return(-1);
6976}
6977
6978/**
6979 * xmlExpGetLanguage:
6980 * @ctxt: the expression context
6981 * @exp: the expression
6982 * @langList: where to store the tokens
6983 * @len: the allocated length of @list
6984 *
6985 * Find all the strings used in @exp and store them in @list
6986 *
6987 * Returns the number of unique strings found, -1 in case of errors and
6988 *         -2 if there is more than @len strings
6989 */
6990int
6991xmlExpGetLanguage(xmlExpCtxtPtr ctxt, xmlExpNodePtr exp,
6992                  const xmlChar**langList, int len) {
6993    if ((ctxt == NULL) || (exp == NULL) || (langList == NULL) || (len <= 0))
6994        return(-1);
6995    return(xmlExpGetLanguageInt(ctxt, exp, langList, len, 0));
6996}
6997
6998static int
6999xmlExpGetStartInt(xmlExpCtxtPtr ctxt, xmlExpNodePtr exp,
7000                  const xmlChar**list, int len, int nb) {
7001    int tmp, tmp2;
7002tail:
7003    switch (exp->type) {
7004        case XML_EXP_FORBID:
7005	    return(0);
7006        case XML_EXP_EMPTY:
7007	    return(0);
7008        case XML_EXP_ATOM:
7009	    for (tmp = 0;tmp < nb;tmp++)
7010	        if (list[tmp] == exp->exp_str)
7011		    return(0);
7012            if (nb >= len)
7013	        return(-2);
7014	    list[nb] = exp->exp_str;
7015	    return(1);
7016        case XML_EXP_COUNT:
7017	    exp = exp->exp_left;
7018	    goto tail;
7019        case XML_EXP_SEQ:
7020	    tmp = xmlExpGetStartInt(ctxt, exp->exp_left, list, len, nb);
7021	    if (tmp < 0)
7022	        return(tmp);
7023	    if (IS_NILLABLE(exp->exp_left)) {
7024		tmp2 = xmlExpGetStartInt(ctxt, exp->exp_right, list, len,
7025					    nb + tmp);
7026		if (tmp2 < 0)
7027		    return(tmp2);
7028		tmp += tmp2;
7029	    }
7030            return(tmp);
7031        case XML_EXP_OR:
7032	    tmp = xmlExpGetStartInt(ctxt, exp->exp_left, list, len, nb);
7033	    if (tmp < 0)
7034	        return(tmp);
7035	    tmp2 = xmlExpGetStartInt(ctxt, exp->exp_right, list, len,
7036	                                nb + tmp);
7037	    if (tmp2 < 0)
7038	        return(tmp2);
7039            return(tmp + tmp2);
7040    }
7041    return(-1);
7042}
7043
7044/**
7045 * xmlExpGetStart:
7046 * @ctxt: the expression context
7047 * @exp: the expression
7048 * @tokList: where to store the tokens
7049 * @len: the allocated length of @list
7050 *
7051 * Find all the strings that appears at the start of the languages
7052 * accepted by @exp and store them in @list. E.g. for (a, b) | c
7053 * it will return the list [a, c]
7054 *
7055 * Returns the number of unique strings found, -1 in case of errors and
7056 *         -2 if there is more than @len strings
7057 */
7058int
7059xmlExpGetStart(xmlExpCtxtPtr ctxt, xmlExpNodePtr exp,
7060               const xmlChar**tokList, int len) {
7061    if ((ctxt == NULL) || (exp == NULL) || (tokList == NULL) || (len <= 0))
7062        return(-1);
7063    return(xmlExpGetStartInt(ctxt, exp, tokList, len, 0));
7064}
7065
7066/**
7067 * xmlExpIsNillable:
7068 * @exp: the expression
7069 *
7070 * Finds if the expression is nillable, i.e. if it accepts the empty sequqnce
7071 *
7072 * Returns 1 if nillable, 0 if not and -1 in case of error
7073 */
7074int
7075xmlExpIsNillable(xmlExpNodePtr exp) {
7076    if (exp == NULL)
7077        return(-1);
7078    return(IS_NILLABLE(exp) != 0);
7079}
7080
7081static xmlExpNodePtr
7082xmlExpStringDeriveInt(xmlExpCtxtPtr ctxt, xmlExpNodePtr exp, const xmlChar *str)
7083{
7084    xmlExpNodePtr ret;
7085
7086    switch (exp->type) {
7087	case XML_EXP_EMPTY:
7088	    return(forbiddenExp);
7089	case XML_EXP_FORBID:
7090	    return(forbiddenExp);
7091	case XML_EXP_ATOM:
7092	    if (exp->exp_str == str) {
7093#ifdef DEBUG_DERIV
7094		printf("deriv atom: equal => Empty\n");
7095#endif
7096	        ret = emptyExp;
7097	    } else {
7098#ifdef DEBUG_DERIV
7099		printf("deriv atom: mismatch => forbid\n");
7100#endif
7101	        /* TODO wildcards here */
7102		ret = forbiddenExp;
7103	    }
7104	    return(ret);
7105	case XML_EXP_OR: {
7106	    xmlExpNodePtr tmp;
7107
7108#ifdef DEBUG_DERIV
7109	    printf("deriv or: => or(derivs)\n");
7110#endif
7111	    tmp = xmlExpStringDeriveInt(ctxt, exp->exp_left, str);
7112	    if (tmp == NULL) {
7113		return(NULL);
7114	    }
7115	    ret = xmlExpStringDeriveInt(ctxt, exp->exp_right, str);
7116	    if (ret == NULL) {
7117	        xmlExpFree(ctxt, tmp);
7118		return(NULL);
7119	    }
7120            ret = xmlExpHashGetEntry(ctxt, XML_EXP_OR, tmp, ret,
7121			     NULL, 0, 0);
7122	    return(ret);
7123	}
7124	case XML_EXP_SEQ:
7125#ifdef DEBUG_DERIV
7126	    printf("deriv seq: starting with left\n");
7127#endif
7128	    ret = xmlExpStringDeriveInt(ctxt, exp->exp_left, str);
7129	    if (ret == NULL) {
7130	        return(NULL);
7131	    } else if (ret == forbiddenExp) {
7132	        if (IS_NILLABLE(exp->exp_left)) {
7133#ifdef DEBUG_DERIV
7134		    printf("deriv seq: left failed but nillable\n");
7135#endif
7136		    ret = xmlExpStringDeriveInt(ctxt, exp->exp_right, str);
7137		}
7138	    } else {
7139#ifdef DEBUG_DERIV
7140		printf("deriv seq: left match => sequence\n");
7141#endif
7142	        exp->exp_right->ref++;
7143	        ret = xmlExpHashGetEntry(ctxt, XML_EXP_SEQ, ret, exp->exp_right,
7144		                         NULL, 0, 0);
7145	    }
7146	    return(ret);
7147	case XML_EXP_COUNT: {
7148	    int min, max;
7149	    xmlExpNodePtr tmp;
7150
7151	    if (exp->exp_max == 0)
7152		return(forbiddenExp);
7153	    ret = xmlExpStringDeriveInt(ctxt, exp->exp_left, str);
7154	    if (ret == NULL)
7155	        return(NULL);
7156	    if (ret == forbiddenExp) {
7157#ifdef DEBUG_DERIV
7158		printf("deriv count: pattern mismatch => forbid\n");
7159#endif
7160	        return(ret);
7161	    }
7162	    if (exp->exp_max == 1)
7163		return(ret);
7164	    if (exp->exp_max < 0) /* unbounded */
7165		max = -1;
7166	    else
7167		max = exp->exp_max - 1;
7168	    if (exp->exp_min > 0)
7169		min = exp->exp_min - 1;
7170	    else
7171		min = 0;
7172	    exp->exp_left->ref++;
7173	    tmp = xmlExpHashGetEntry(ctxt, XML_EXP_COUNT, exp->exp_left, NULL,
7174				     NULL, min, max);
7175	    if (ret == emptyExp) {
7176#ifdef DEBUG_DERIV
7177		printf("deriv count: match to empty => new count\n");
7178#endif
7179	        return(tmp);
7180	    }
7181#ifdef DEBUG_DERIV
7182	    printf("deriv count: match => sequence with new count\n");
7183#endif
7184	    return(xmlExpHashGetEntry(ctxt, XML_EXP_SEQ, ret, tmp,
7185	                              NULL, 0, 0));
7186	}
7187    }
7188    return(NULL);
7189}
7190
7191/**
7192 * xmlExpStringDerive:
7193 * @ctxt: the expression context
7194 * @exp: the expression
7195 * @str: the string
7196 * @len: the string len in bytes if available
7197 *
7198 * Do one step of Brzozowski derivation of the expression @exp with
7199 * respect to the input string
7200 *
7201 * Returns the resulting expression or NULL in case of internal error
7202 */
7203xmlExpNodePtr
7204xmlExpStringDerive(xmlExpCtxtPtr ctxt, xmlExpNodePtr exp,
7205                   const xmlChar *str, int len) {
7206    const xmlChar *input;
7207
7208    if ((exp == NULL) || (ctxt == NULL) || (str == NULL)) {
7209        return(NULL);
7210    }
7211    /*
7212     * check the string is in the dictionary, if yes use an interned
7213     * copy, otherwise we know it's not an acceptable input
7214     */
7215    input = xmlDictExists(ctxt->dict, str, len);
7216    if (input == NULL) {
7217        return(forbiddenExp);
7218    }
7219    return(xmlExpStringDeriveInt(ctxt, exp, input));
7220}
7221
7222static int
7223xmlExpCheckCard(xmlExpNodePtr exp, xmlExpNodePtr sub) {
7224    int ret = 1;
7225
7226    if (sub->c_max == -1) {
7227        if (exp->c_max != -1)
7228	    ret = 0;
7229    } else if ((exp->c_max >= 0) && (exp->c_max < sub->c_max)) {
7230        ret = 0;
7231    }
7232#if 0
7233    if ((IS_NILLABLE(sub)) && (!IS_NILLABLE(exp)))
7234        ret = 0;
7235#endif
7236    return(ret);
7237}
7238
7239static xmlExpNodePtr xmlExpExpDeriveInt(xmlExpCtxtPtr ctxt, xmlExpNodePtr exp,
7240                                        xmlExpNodePtr sub);
7241/**
7242 * xmlExpDivide:
7243 * @ctxt: the expressions context
7244 * @exp: the englobing expression
7245 * @sub: the subexpression
7246 * @mult: the multiple expression
7247 * @remain: the remain from the derivation of the multiple
7248 *
7249 * Check if exp is a multiple of sub, i.e. if there is a finite number n
7250 * so that sub{n} subsume exp
7251 *
7252 * Returns the multiple value if successful, 0 if it is not a multiple
7253 *         and -1 in case of internel error.
7254 */
7255
7256static int
7257xmlExpDivide(xmlExpCtxtPtr ctxt, xmlExpNodePtr exp, xmlExpNodePtr sub,
7258             xmlExpNodePtr *mult, xmlExpNodePtr *remain) {
7259    int i;
7260    xmlExpNodePtr tmp, tmp2;
7261
7262    if (mult != NULL) *mult = NULL;
7263    if (remain != NULL) *remain = NULL;
7264    if (exp->c_max == -1) return(0);
7265    if (IS_NILLABLE(exp) && (!IS_NILLABLE(sub))) return(0);
7266
7267    for (i = 1;i <= exp->c_max;i++) {
7268        sub->ref++;
7269        tmp = xmlExpHashGetEntry(ctxt, XML_EXP_COUNT,
7270				 sub, NULL, NULL, i, i);
7271	if (tmp == NULL) {
7272	    return(-1);
7273	}
7274	if (!xmlExpCheckCard(tmp, exp)) {
7275	    xmlExpFree(ctxt, tmp);
7276	    continue;
7277	}
7278	tmp2 = xmlExpExpDeriveInt(ctxt, tmp, exp);
7279	if (tmp2 == NULL) {
7280	    xmlExpFree(ctxt, tmp);
7281	    return(-1);
7282	}
7283	if ((tmp2 != forbiddenExp) && (IS_NILLABLE(tmp2))) {
7284	    if (remain != NULL)
7285	        *remain = tmp2;
7286	    else
7287	        xmlExpFree(ctxt, tmp2);
7288	    if (mult != NULL)
7289	        *mult = tmp;
7290	    else
7291	        xmlExpFree(ctxt, tmp);
7292#ifdef DEBUG_DERIV
7293	    printf("Divide succeeded %d\n", i);
7294#endif
7295	    return(i);
7296	}
7297	xmlExpFree(ctxt, tmp);
7298	xmlExpFree(ctxt, tmp2);
7299    }
7300#ifdef DEBUG_DERIV
7301    printf("Divide failed\n");
7302#endif
7303    return(0);
7304}
7305
7306/**
7307 * xmlExpExpDeriveInt:
7308 * @ctxt: the expressions context
7309 * @exp: the englobing expression
7310 * @sub: the subexpression
7311 *
7312 * Try to do a step of Brzozowski derivation but at a higher level
7313 * the input being a subexpression.
7314 *
7315 * Returns the resulting expression or NULL in case of internal error
7316 */
7317static xmlExpNodePtr
7318xmlExpExpDeriveInt(xmlExpCtxtPtr ctxt, xmlExpNodePtr exp, xmlExpNodePtr sub) {
7319    xmlExpNodePtr ret, tmp, tmp2, tmp3;
7320    const xmlChar **tab;
7321    int len, i;
7322
7323    /*
7324     * In case of equality and if the expression can only consume a finite
7325     * amount, then the derivation is empty
7326     */
7327    if ((exp == sub) && (exp->c_max >= 0)) {
7328#ifdef DEBUG_DERIV
7329        printf("Equal(exp, sub) and finite -> Empty\n");
7330#endif
7331        return(emptyExp);
7332    }
7333    /*
7334     * decompose sub sequence first
7335     */
7336    if (sub->type == XML_EXP_EMPTY) {
7337#ifdef DEBUG_DERIV
7338        printf("Empty(sub) -> Empty\n");
7339#endif
7340	exp->ref++;
7341        return(exp);
7342    }
7343    if (sub->type == XML_EXP_SEQ) {
7344#ifdef DEBUG_DERIV
7345        printf("Seq(sub) -> decompose\n");
7346#endif
7347        tmp = xmlExpExpDeriveInt(ctxt, exp, sub->exp_left);
7348	if (tmp == NULL)
7349	    return(NULL);
7350	if (tmp == forbiddenExp)
7351	    return(tmp);
7352	ret = xmlExpExpDeriveInt(ctxt, tmp, sub->exp_right);
7353	xmlExpFree(ctxt, tmp);
7354	return(ret);
7355    }
7356    if (sub->type == XML_EXP_OR) {
7357#ifdef DEBUG_DERIV
7358        printf("Or(sub) -> decompose\n");
7359#endif
7360        tmp = xmlExpExpDeriveInt(ctxt, exp, sub->exp_left);
7361	if (tmp == forbiddenExp)
7362	    return(tmp);
7363	if (tmp == NULL)
7364	    return(NULL);
7365	ret = xmlExpExpDeriveInt(ctxt, exp, sub->exp_right);
7366	if ((ret == NULL) || (ret == forbiddenExp)) {
7367	    xmlExpFree(ctxt, tmp);
7368	    return(ret);
7369	}
7370	return(xmlExpHashGetEntry(ctxt, XML_EXP_OR, tmp, ret, NULL, 0, 0));
7371    }
7372    if (!xmlExpCheckCard(exp, sub)) {
7373#ifdef DEBUG_DERIV
7374        printf("CheckCard(exp, sub) failed -> Forbid\n");
7375#endif
7376        return(forbiddenExp);
7377    }
7378    switch (exp->type) {
7379        case XML_EXP_EMPTY:
7380	    if (sub == emptyExp)
7381	        return(emptyExp);
7382#ifdef DEBUG_DERIV
7383	    printf("Empty(exp) -> Forbid\n");
7384#endif
7385	    return(forbiddenExp);
7386        case XML_EXP_FORBID:
7387#ifdef DEBUG_DERIV
7388	    printf("Forbid(exp) -> Forbid\n");
7389#endif
7390	    return(forbiddenExp);
7391        case XML_EXP_ATOM:
7392	    if (sub->type == XML_EXP_ATOM) {
7393	        /* TODO: handle wildcards */
7394	        if (exp->exp_str == sub->exp_str) {
7395#ifdef DEBUG_DERIV
7396		    printf("Atom match -> Empty\n");
7397#endif
7398		    return(emptyExp);
7399                }
7400#ifdef DEBUG_DERIV
7401		printf("Atom mismatch -> Forbid\n");
7402#endif
7403	        return(forbiddenExp);
7404	    }
7405	    if ((sub->type == XML_EXP_COUNT) &&
7406	        (sub->exp_max == 1) &&
7407	        (sub->exp_left->type == XML_EXP_ATOM)) {
7408	        /* TODO: handle wildcards */
7409	        if (exp->exp_str == sub->exp_left->exp_str) {
7410#ifdef DEBUG_DERIV
7411		    printf("Atom match -> Empty\n");
7412#endif
7413		    return(emptyExp);
7414		}
7415#ifdef DEBUG_DERIV
7416		printf("Atom mismatch -> Forbid\n");
7417#endif
7418	        return(forbiddenExp);
7419	    }
7420#ifdef DEBUG_DERIV
7421	    printf("Compex exp vs Atom -> Forbid\n");
7422#endif
7423	    return(forbiddenExp);
7424        case XML_EXP_SEQ:
7425	    /* try to get the sequence consumed only if possible */
7426	    if (xmlExpCheckCard(exp->exp_left, sub)) {
7427		/* See if the sequence can be consumed directly */
7428#ifdef DEBUG_DERIV
7429		printf("Seq trying left only\n");
7430#endif
7431		ret = xmlExpExpDeriveInt(ctxt, exp->exp_left, sub);
7432		if ((ret != forbiddenExp) && (ret != NULL)) {
7433#ifdef DEBUG_DERIV
7434		    printf("Seq trying left only worked\n");
7435#endif
7436		    /*
7437		     * TODO: assumption here that we are determinist
7438		     *       i.e. we won't get to a nillable exp left
7439		     *       subset which could be matched by the right
7440		     *       part too.
7441		     * e.g.: (a | b)+,(a | c) and 'a+,a'
7442		     */
7443		    exp->exp_right->ref++;
7444		    return(xmlExpHashGetEntry(ctxt, XML_EXP_SEQ, ret,
7445					      exp->exp_right, NULL, 0, 0));
7446		}
7447#ifdef DEBUG_DERIV
7448	    } else {
7449		printf("Seq: left too short\n");
7450#endif
7451	    }
7452	    /* Try instead to decompose */
7453	    if (sub->type == XML_EXP_COUNT) {
7454		int min, max;
7455
7456#ifdef DEBUG_DERIV
7457		printf("Seq: sub is a count\n");
7458#endif
7459	        ret = xmlExpExpDeriveInt(ctxt, exp->exp_left, sub->exp_left);
7460		if (ret == NULL)
7461		    return(NULL);
7462		if (ret != forbiddenExp) {
7463#ifdef DEBUG_DERIV
7464		    printf("Seq , Count match on left\n");
7465#endif
7466		    if (sub->exp_max < 0)
7467		        max = -1;
7468	            else
7469		        max = sub->exp_max -1;
7470		    if (sub->exp_min > 0)
7471		        min = sub->exp_min -1;
7472		    else
7473		        min = 0;
7474		    exp->exp_right->ref++;
7475		    tmp = xmlExpHashGetEntry(ctxt, XML_EXP_SEQ, ret,
7476		                             exp->exp_right, NULL, 0, 0);
7477		    if (tmp == NULL)
7478		        return(NULL);
7479
7480		    sub->exp_left->ref++;
7481		    tmp2 = xmlExpHashGetEntry(ctxt, XML_EXP_COUNT,
7482				      sub->exp_left, NULL, NULL, min, max);
7483		    if (tmp2 == NULL) {
7484		        xmlExpFree(ctxt, tmp);
7485			return(NULL);
7486		    }
7487		    ret = xmlExpExpDeriveInt(ctxt, tmp, tmp2);
7488		    xmlExpFree(ctxt, tmp);
7489		    xmlExpFree(ctxt, tmp2);
7490		    return(ret);
7491		}
7492	    }
7493	    /* we made no progress on structured operations */
7494	    break;
7495        case XML_EXP_OR:
7496#ifdef DEBUG_DERIV
7497	    printf("Or , trying both side\n");
7498#endif
7499	    ret = xmlExpExpDeriveInt(ctxt, exp->exp_left, sub);
7500	    if (ret == NULL)
7501	        return(NULL);
7502	    tmp = xmlExpExpDeriveInt(ctxt, exp->exp_right, sub);
7503	    if (tmp == NULL) {
7504		xmlExpFree(ctxt, ret);
7505	        return(NULL);
7506	    }
7507	    return(xmlExpHashGetEntry(ctxt, XML_EXP_OR, ret, tmp, NULL, 0, 0));
7508        case XML_EXP_COUNT: {
7509	    int min, max;
7510
7511	    if (sub->type == XML_EXP_COUNT) {
7512	        /*
7513		 * Try to see if the loop is completely subsumed
7514		 */
7515	        tmp = xmlExpExpDeriveInt(ctxt, exp->exp_left, sub->exp_left);
7516		if (tmp == NULL)
7517		    return(NULL);
7518		if (tmp == forbiddenExp) {
7519		    int mult;
7520
7521#ifdef DEBUG_DERIV
7522		    printf("Count, Count inner don't subsume\n");
7523#endif
7524		    mult = xmlExpDivide(ctxt, sub->exp_left, exp->exp_left,
7525		                        NULL, &tmp);
7526		    if (mult <= 0) {
7527#ifdef DEBUG_DERIV
7528			printf("Count, Count not multiple => forbidden\n");
7529#endif
7530                        return(forbiddenExp);
7531		    }
7532		    if (sub->exp_max == -1) {
7533		        max = -1;
7534			if (exp->exp_max == -1) {
7535			    if (exp->exp_min <= sub->exp_min * mult)
7536			        min = 0;
7537			    else
7538			        min = exp->exp_min - sub->exp_min * mult;
7539			} else {
7540#ifdef DEBUG_DERIV
7541			    printf("Count, Count finite can't subsume infinite\n");
7542#endif
7543                            xmlExpFree(ctxt, tmp);
7544			    return(forbiddenExp);
7545			}
7546		    } else {
7547			if (exp->exp_max == -1) {
7548#ifdef DEBUG_DERIV
7549			    printf("Infinite loop consume mult finite loop\n");
7550#endif
7551			    if (exp->exp_min > sub->exp_min * mult) {
7552				max = -1;
7553				min = exp->exp_min - sub->exp_min * mult;
7554			    } else {
7555				max = -1;
7556				min = 0;
7557			    }
7558			} else {
7559			    if (exp->exp_max < sub->exp_max * mult) {
7560#ifdef DEBUG_DERIV
7561				printf("loops max mult mismatch => forbidden\n");
7562#endif
7563				xmlExpFree(ctxt, tmp);
7564				return(forbiddenExp);
7565			    }
7566			    if (sub->exp_max * mult > exp->exp_min)
7567				min = 0;
7568			    else
7569				min = exp->exp_min - sub->exp_max * mult;
7570			    max = exp->exp_max - sub->exp_max * mult;
7571			}
7572		    }
7573		} else if (!IS_NILLABLE(tmp)) {
7574		    /*
7575		     * TODO: loop here to try to grow if working on finite
7576		     *       blocks.
7577		     */
7578#ifdef DEBUG_DERIV
7579		    printf("Count, Count remain not nillable => forbidden\n");
7580#endif
7581		    xmlExpFree(ctxt, tmp);
7582		    return(forbiddenExp);
7583		} else if (sub->exp_max == -1) {
7584		    if (exp->exp_max == -1) {
7585		        if (exp->exp_min <= sub->exp_min) {
7586#ifdef DEBUG_DERIV
7587			    printf("Infinite loops Okay => COUNT(0,Inf)\n");
7588#endif
7589                            max = -1;
7590			    min = 0;
7591			} else {
7592#ifdef DEBUG_DERIV
7593			    printf("Infinite loops min => Count(X,Inf)\n");
7594#endif
7595                            max = -1;
7596			    min = exp->exp_min - sub->exp_min;
7597			}
7598		    } else if (exp->exp_min > sub->exp_min) {
7599#ifdef DEBUG_DERIV
7600			printf("loops min mismatch 1 => forbidden ???\n");
7601#endif
7602		        xmlExpFree(ctxt, tmp);
7603		        return(forbiddenExp);
7604		    } else {
7605			max = -1;
7606			min = 0;
7607		    }
7608		} else {
7609		    if (exp->exp_max == -1) {
7610#ifdef DEBUG_DERIV
7611			printf("Infinite loop consume finite loop\n");
7612#endif
7613		        if (exp->exp_min > sub->exp_min) {
7614			    max = -1;
7615			    min = exp->exp_min - sub->exp_min;
7616			} else {
7617			    max = -1;
7618			    min = 0;
7619			}
7620		    } else {
7621		        if (exp->exp_max < sub->exp_max) {
7622#ifdef DEBUG_DERIV
7623			    printf("loops max mismatch => forbidden\n");
7624#endif
7625			    xmlExpFree(ctxt, tmp);
7626			    return(forbiddenExp);
7627			}
7628			if (sub->exp_max > exp->exp_min)
7629			    min = 0;
7630			else
7631			    min = exp->exp_min - sub->exp_max;
7632			max = exp->exp_max - sub->exp_max;
7633		    }
7634		}
7635#ifdef DEBUG_DERIV
7636		printf("loops match => SEQ(COUNT())\n");
7637#endif
7638		exp->exp_left->ref++;
7639		tmp2 = xmlExpHashGetEntry(ctxt, XML_EXP_COUNT, exp->exp_left,
7640		                          NULL, NULL, min, max);
7641		if (tmp2 == NULL) {
7642		    return(NULL);
7643		}
7644                ret = xmlExpHashGetEntry(ctxt, XML_EXP_SEQ, tmp, tmp2,
7645		                         NULL, 0, 0);
7646		return(ret);
7647	    }
7648	    tmp = xmlExpExpDeriveInt(ctxt, exp->exp_left, sub);
7649	    if (tmp == NULL)
7650		return(NULL);
7651	    if (tmp == forbiddenExp) {
7652#ifdef DEBUG_DERIV
7653		printf("loop mismatch => forbidden\n");
7654#endif
7655		return(forbiddenExp);
7656	    }
7657	    if (exp->exp_min > 0)
7658		min = exp->exp_min - 1;
7659	    else
7660		min = 0;
7661	    if (exp->exp_max < 0)
7662		max = -1;
7663	    else
7664		max = exp->exp_max - 1;
7665
7666#ifdef DEBUG_DERIV
7667	    printf("loop match => SEQ(COUNT())\n");
7668#endif
7669	    exp->exp_left->ref++;
7670	    tmp2 = xmlExpHashGetEntry(ctxt, XML_EXP_COUNT, exp->exp_left,
7671				      NULL, NULL, min, max);
7672	    if (tmp2 == NULL)
7673		return(NULL);
7674	    ret = xmlExpHashGetEntry(ctxt, XML_EXP_SEQ, tmp, tmp2,
7675				     NULL, 0, 0);
7676	    return(ret);
7677	}
7678    }
7679
7680#ifdef DEBUG_DERIV
7681    printf("Fallback to derivative\n");
7682#endif
7683    if (IS_NILLABLE(sub)) {
7684        if (!(IS_NILLABLE(exp)))
7685	    return(forbiddenExp);
7686	else
7687	    ret = emptyExp;
7688    } else
7689	ret = NULL;
7690    /*
7691     * here the structured derivation made no progress so
7692     * we use the default token based derivation to force one more step
7693     */
7694    if (ctxt->tabSize == 0)
7695        ctxt->tabSize = 40;
7696
7697    tab = (const xmlChar **) xmlMalloc(ctxt->tabSize *
7698	                               sizeof(const xmlChar *));
7699    if (tab == NULL) {
7700	return(NULL);
7701    }
7702
7703    /*
7704     * collect all the strings accepted by the subexpression on input
7705     */
7706    len = xmlExpGetStartInt(ctxt, sub, tab, ctxt->tabSize, 0);
7707    while (len < 0) {
7708        const xmlChar **temp;
7709	temp = (const xmlChar **) xmlRealloc((xmlChar **) tab, ctxt->tabSize * 2 *
7710	                                     sizeof(const xmlChar *));
7711	if (temp == NULL) {
7712	    xmlFree((xmlChar **) tab);
7713	    return(NULL);
7714	}
7715	tab = temp;
7716	ctxt->tabSize *= 2;
7717	len = xmlExpGetStartInt(ctxt, sub, tab, ctxt->tabSize, 0);
7718    }
7719    for (i = 0;i < len;i++) {
7720        tmp = xmlExpStringDeriveInt(ctxt, exp, tab[i]);
7721	if ((tmp == NULL) || (tmp == forbiddenExp)) {
7722	    xmlExpFree(ctxt, ret);
7723	    xmlFree((xmlChar **) tab);
7724	    return(tmp);
7725	}
7726	tmp2 = xmlExpStringDeriveInt(ctxt, sub, tab[i]);
7727	if ((tmp2 == NULL) || (tmp2 == forbiddenExp)) {
7728	    xmlExpFree(ctxt, tmp);
7729	    xmlExpFree(ctxt, ret);
7730	    xmlFree((xmlChar **) tab);
7731	    return(tmp);
7732	}
7733	tmp3 = xmlExpExpDeriveInt(ctxt, tmp, tmp2);
7734	xmlExpFree(ctxt, tmp);
7735	xmlExpFree(ctxt, tmp2);
7736
7737	if ((tmp3 == NULL) || (tmp3 == forbiddenExp)) {
7738	    xmlExpFree(ctxt, ret);
7739	    xmlFree((xmlChar **) tab);
7740	    return(tmp3);
7741	}
7742
7743	if (ret == NULL)
7744	    ret = tmp3;
7745	else {
7746	    ret = xmlExpHashGetEntry(ctxt, XML_EXP_OR, ret, tmp3, NULL, 0, 0);
7747	    if (ret == NULL) {
7748		xmlFree((xmlChar **) tab);
7749	        return(NULL);
7750	    }
7751	}
7752    }
7753    xmlFree((xmlChar **) tab);
7754    return(ret);
7755}
7756
7757/**
7758 * xmlExpExpDerive:
7759 * @ctxt: the expressions context
7760 * @exp: the englobing expression
7761 * @sub: the subexpression
7762 *
7763 * Evaluates the expression resulting from @exp consuming a sub expression @sub
7764 * Based on algebraic derivation and sometimes direct Brzozowski derivation
7765 * it usually tatkes less than linear time and can handle expressions generating
7766 * infinite languages.
7767 *
7768 * Returns the resulting expression or NULL in case of internal error, the
7769 *         result must be freed
7770 */
7771xmlExpNodePtr
7772xmlExpExpDerive(xmlExpCtxtPtr ctxt, xmlExpNodePtr exp, xmlExpNodePtr sub) {
7773    if ((exp == NULL) || (ctxt == NULL) || (sub == NULL))
7774        return(NULL);
7775
7776    /*
7777     * O(1) speedups
7778     */
7779    if (IS_NILLABLE(sub) && (!IS_NILLABLE(exp))) {
7780#ifdef DEBUG_DERIV
7781	printf("Sub nillable and not exp : can't subsume\n");
7782#endif
7783        return(forbiddenExp);
7784    }
7785    if (xmlExpCheckCard(exp, sub) == 0) {
7786#ifdef DEBUG_DERIV
7787	printf("sub generate longuer sequances than exp : can't subsume\n");
7788#endif
7789        return(forbiddenExp);
7790    }
7791    return(xmlExpExpDeriveInt(ctxt, exp, sub));
7792}
7793
7794/**
7795 * xmlExpSubsume:
7796 * @ctxt: the expressions context
7797 * @exp: the englobing expression
7798 * @sub: the subexpression
7799 *
7800 * Check whether @exp accepts all the languages accexpted by @sub
7801 * the input being a subexpression.
7802 *
7803 * Returns 1 if true 0 if false and -1 in case of failure.
7804 */
7805int
7806xmlExpSubsume(xmlExpCtxtPtr ctxt, xmlExpNodePtr exp, xmlExpNodePtr sub) {
7807    xmlExpNodePtr tmp;
7808
7809    if ((exp == NULL) || (ctxt == NULL) || (sub == NULL))
7810        return(-1);
7811
7812    /*
7813     * TODO: speedup by checking the language of sub is a subset of the
7814     *       language of exp
7815     */
7816    /*
7817     * O(1) speedups
7818     */
7819    if (IS_NILLABLE(sub) && (!IS_NILLABLE(exp))) {
7820#ifdef DEBUG_DERIV
7821	printf("Sub nillable and not exp : can't subsume\n");
7822#endif
7823        return(0);
7824    }
7825    if (xmlExpCheckCard(exp, sub) == 0) {
7826#ifdef DEBUG_DERIV
7827	printf("sub generate longuer sequances than exp : can't subsume\n");
7828#endif
7829        return(0);
7830    }
7831    tmp = xmlExpExpDeriveInt(ctxt, exp, sub);
7832#ifdef DEBUG_DERIV
7833    printf("Result derivation :\n");
7834    PRINT_EXP(tmp);
7835#endif
7836    if (tmp == NULL)
7837        return(-1);
7838    if (tmp == forbiddenExp)
7839	return(0);
7840    if (tmp == emptyExp)
7841	return(1);
7842    if ((tmp != NULL) && (IS_NILLABLE(tmp))) {
7843        xmlExpFree(ctxt, tmp);
7844        return(1);
7845    }
7846    xmlExpFree(ctxt, tmp);
7847    return(0);
7848}
7849
7850/************************************************************************
7851 *									*
7852 *			Parsing expression				*
7853 *									*
7854 ************************************************************************/
7855
7856static xmlExpNodePtr xmlExpParseExpr(xmlExpCtxtPtr ctxt);
7857
7858#undef CUR
7859#define CUR (*ctxt->cur)
7860#undef NEXT
7861#define NEXT ctxt->cur++;
7862#undef IS_BLANK
7863#define IS_BLANK(c) ((c == ' ') || (c == '\n') || (c == '\r') || (c == '\t'))
7864#define SKIP_BLANKS while (IS_BLANK(*ctxt->cur)) ctxt->cur++;
7865
7866static int
7867xmlExpParseNumber(xmlExpCtxtPtr ctxt) {
7868    int ret = 0;
7869
7870    SKIP_BLANKS
7871    if (CUR == '*') {
7872	NEXT
7873	return(-1);
7874    }
7875    if ((CUR < '0') || (CUR > '9'))
7876        return(-1);
7877    while ((CUR >= '0') && (CUR <= '9')) {
7878        ret = ret * 10 + (CUR - '0');
7879	NEXT
7880    }
7881    return(ret);
7882}
7883
7884static xmlExpNodePtr
7885xmlExpParseOr(xmlExpCtxtPtr ctxt) {
7886    const char *base;
7887    xmlExpNodePtr ret;
7888    const xmlChar *val;
7889
7890    SKIP_BLANKS
7891    base = ctxt->cur;
7892    if (*ctxt->cur == '(') {
7893        NEXT
7894	ret = xmlExpParseExpr(ctxt);
7895	SKIP_BLANKS
7896	if (*ctxt->cur != ')') {
7897	    fprintf(stderr, "unbalanced '(' : %s\n", base);
7898	    xmlExpFree(ctxt, ret);
7899	    return(NULL);
7900	}
7901	NEXT;
7902	SKIP_BLANKS
7903	goto parse_quantifier;
7904    }
7905    while ((CUR != 0) && (!(IS_BLANK(CUR))) && (CUR != '(') &&
7906           (CUR != ')') && (CUR != '|') && (CUR != ',') && (CUR != '{') &&
7907	   (CUR != '*') && (CUR != '+') && (CUR != '?') && (CUR != '}'))
7908	NEXT;
7909    val = xmlDictLookup(ctxt->dict, BAD_CAST base, ctxt->cur - base);
7910    if (val == NULL)
7911        return(NULL);
7912    ret = xmlExpHashGetEntry(ctxt, XML_EXP_ATOM, NULL, NULL, val, 0, 0);
7913    if (ret == NULL)
7914        return(NULL);
7915    SKIP_BLANKS
7916parse_quantifier:
7917    if (CUR == '{') {
7918        int min, max;
7919
7920        NEXT
7921	min = xmlExpParseNumber(ctxt);
7922	if (min < 0) {
7923	    xmlExpFree(ctxt, ret);
7924	    return(NULL);
7925	}
7926	SKIP_BLANKS
7927	if (CUR == ',') {
7928	    NEXT
7929	    max = xmlExpParseNumber(ctxt);
7930	    SKIP_BLANKS
7931	} else
7932	    max = min;
7933	if (CUR != '}') {
7934	    xmlExpFree(ctxt, ret);
7935	    return(NULL);
7936	}
7937        NEXT
7938	ret = xmlExpHashGetEntry(ctxt, XML_EXP_COUNT, ret, NULL, NULL,
7939	                         min, max);
7940	SKIP_BLANKS
7941    } else if (CUR == '?') {
7942        NEXT
7943	ret = xmlExpHashGetEntry(ctxt, XML_EXP_COUNT, ret, NULL, NULL,
7944	                         0, 1);
7945	SKIP_BLANKS
7946    } else if (CUR == '+') {
7947        NEXT
7948	ret = xmlExpHashGetEntry(ctxt, XML_EXP_COUNT, ret, NULL, NULL,
7949	                         1, -1);
7950	SKIP_BLANKS
7951    } else if (CUR == '*') {
7952        NEXT
7953	ret = xmlExpHashGetEntry(ctxt, XML_EXP_COUNT, ret, NULL, NULL,
7954	                         0, -1);
7955	SKIP_BLANKS
7956    }
7957    return(ret);
7958}
7959
7960
7961static xmlExpNodePtr
7962xmlExpParseSeq(xmlExpCtxtPtr ctxt) {
7963    xmlExpNodePtr ret, right;
7964
7965    ret = xmlExpParseOr(ctxt);
7966    SKIP_BLANKS
7967    while (CUR == '|') {
7968        NEXT
7969	right = xmlExpParseOr(ctxt);
7970	if (right == NULL) {
7971	    xmlExpFree(ctxt, ret);
7972	    return(NULL);
7973	}
7974	ret = xmlExpHashGetEntry(ctxt, XML_EXP_OR, ret, right, NULL, 0, 0);
7975	if (ret == NULL)
7976	    return(NULL);
7977    }
7978    return(ret);
7979}
7980
7981static xmlExpNodePtr
7982xmlExpParseExpr(xmlExpCtxtPtr ctxt) {
7983    xmlExpNodePtr ret, right;
7984
7985    ret = xmlExpParseSeq(ctxt);
7986    SKIP_BLANKS
7987    while (CUR == ',') {
7988        NEXT
7989	right = xmlExpParseSeq(ctxt);
7990	if (right == NULL) {
7991	    xmlExpFree(ctxt, ret);
7992	    return(NULL);
7993	}
7994	ret = xmlExpHashGetEntry(ctxt, XML_EXP_SEQ, ret, right, NULL, 0, 0);
7995	if (ret == NULL)
7996	    return(NULL);
7997    }
7998    return(ret);
7999}
8000
8001/**
8002 * xmlExpParse:
8003 * @ctxt: the expressions context
8004 * @expr: the 0 terminated string
8005 *
8006 * Minimal parser for regexps, it understand the following constructs
8007 *  - string terminals
8008 *  - choice operator |
8009 *  - sequence operator ,
8010 *  - subexpressions (...)
8011 *  - usual cardinality operators + * and ?
8012 *  - finite sequences  { min, max }
8013 *  - infinite sequences { min, * }
8014 * There is minimal checkings made especially no checking on strings values
8015 *
8016 * Returns a new expression or NULL in case of failure
8017 */
8018xmlExpNodePtr
8019xmlExpParse(xmlExpCtxtPtr ctxt, const char *expr) {
8020    xmlExpNodePtr ret;
8021
8022    ctxt->expr = expr;
8023    ctxt->cur = expr;
8024
8025    ret = xmlExpParseExpr(ctxt);
8026    SKIP_BLANKS
8027    if (*ctxt->cur != 0) {
8028        xmlExpFree(ctxt, ret);
8029        return(NULL);
8030    }
8031    return(ret);
8032}
8033
8034static void
8035xmlExpDumpInt(xmlBufferPtr buf, xmlExpNodePtr expr, int glob) {
8036    xmlExpNodePtr c;
8037
8038    if (expr == NULL) return;
8039    if (glob) xmlBufferWriteChar(buf, "(");
8040    switch (expr->type) {
8041        case XML_EXP_EMPTY:
8042	    xmlBufferWriteChar(buf, "empty");
8043	    break;
8044        case XML_EXP_FORBID:
8045	    xmlBufferWriteChar(buf, "forbidden");
8046	    break;
8047        case XML_EXP_ATOM:
8048	    xmlBufferWriteCHAR(buf, expr->exp_str);
8049	    break;
8050        case XML_EXP_SEQ:
8051	    c = expr->exp_left;
8052	    if ((c->type == XML_EXP_SEQ) || (c->type == XML_EXP_OR))
8053	        xmlExpDumpInt(buf, c, 1);
8054	    else
8055	        xmlExpDumpInt(buf, c, 0);
8056	    xmlBufferWriteChar(buf, " , ");
8057	    c = expr->exp_right;
8058	    if ((c->type == XML_EXP_SEQ) || (c->type == XML_EXP_OR))
8059	        xmlExpDumpInt(buf, c, 1);
8060	    else
8061	        xmlExpDumpInt(buf, c, 0);
8062            break;
8063        case XML_EXP_OR:
8064	    c = expr->exp_left;
8065	    if ((c->type == XML_EXP_SEQ) || (c->type == XML_EXP_OR))
8066	        xmlExpDumpInt(buf, c, 1);
8067	    else
8068	        xmlExpDumpInt(buf, c, 0);
8069	    xmlBufferWriteChar(buf, " | ");
8070	    c = expr->exp_right;
8071	    if ((c->type == XML_EXP_SEQ) || (c->type == XML_EXP_OR))
8072	        xmlExpDumpInt(buf, c, 1);
8073	    else
8074	        xmlExpDumpInt(buf, c, 0);
8075            break;
8076        case XML_EXP_COUNT: {
8077	    char rep[40];
8078
8079	    c = expr->exp_left;
8080	    if ((c->type == XML_EXP_SEQ) || (c->type == XML_EXP_OR))
8081	        xmlExpDumpInt(buf, c, 1);
8082	    else
8083	        xmlExpDumpInt(buf, c, 0);
8084	    if ((expr->exp_min == 0) && (expr->exp_max == 1)) {
8085		rep[0] = '?';
8086		rep[1] = 0;
8087	    } else if ((expr->exp_min == 0) && (expr->exp_max == -1)) {
8088		rep[0] = '*';
8089		rep[1] = 0;
8090	    } else if ((expr->exp_min == 1) && (expr->exp_max == -1)) {
8091		rep[0] = '+';
8092		rep[1] = 0;
8093	    } else if (expr->exp_max == expr->exp_min) {
8094	        snprintf(rep, 39, "{%d}", expr->exp_min);
8095	    } else if (expr->exp_max < 0) {
8096	        snprintf(rep, 39, "{%d,inf}", expr->exp_min);
8097	    } else {
8098	        snprintf(rep, 39, "{%d,%d}", expr->exp_min, expr->exp_max);
8099	    }
8100	    rep[39] = 0;
8101	    xmlBufferWriteChar(buf, rep);
8102	    break;
8103	}
8104	default:
8105	    fprintf(stderr, "Error in tree\n");
8106    }
8107    if (glob)
8108        xmlBufferWriteChar(buf, ")");
8109}
8110/**
8111 * xmlExpDump:
8112 * @buf:  a buffer to receive the output
8113 * @expr:  the compiled expression
8114 *
8115 * Serialize the expression as compiled to the buffer
8116 */
8117void
8118xmlExpDump(xmlBufferPtr buf, xmlExpNodePtr expr) {
8119    if ((buf == NULL) || (expr == NULL))
8120        return;
8121    xmlExpDumpInt(buf, expr, 0);
8122}
8123
8124/**
8125 * xmlExpMaxToken:
8126 * @expr: a compiled expression
8127 *
8128 * Indicate the maximum number of input a expression can accept
8129 *
8130 * Returns the maximum length or -1 in case of error
8131 */
8132int
8133xmlExpMaxToken(xmlExpNodePtr expr) {
8134    if (expr == NULL)
8135        return(-1);
8136    return(expr->c_max);
8137}
8138
8139/**
8140 * xmlExpCtxtNbNodes:
8141 * @ctxt: an expression context
8142 *
8143 * Debugging facility provides the number of allocated nodes at a that point
8144 *
8145 * Returns the number of nodes in use or -1 in case of error
8146 */
8147int
8148xmlExpCtxtNbNodes(xmlExpCtxtPtr ctxt) {
8149    if (ctxt == NULL)
8150        return(-1);
8151    return(ctxt->nb_nodes);
8152}
8153
8154/**
8155 * xmlExpCtxtNbCons:
8156 * @ctxt: an expression context
8157 *
8158 * Debugging facility provides the number of allocated nodes over lifetime
8159 *
8160 * Returns the number of nodes ever allocated or -1 in case of error
8161 */
8162int
8163xmlExpCtxtNbCons(xmlExpCtxtPtr ctxt) {
8164    if (ctxt == NULL)
8165        return(-1);
8166    return(ctxt->nb_cons);
8167}
8168
8169#endif /* LIBXML_EXPR_ENABLED */
8170#define bottom_xmlregexp
8171#include "elfgcchack.h"
8172#endif /* LIBXML_REGEXP_ENABLED */
8173