BRANCH release for 2.5.x critical patches
[baserock-morphs:libxml2.git] / xmlregexp.c
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 thise includes:
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 #include <stdio.h>
23 #include <string.h>
24 #include <libxml/tree.h>
25 #include <libxml/parserInternals.h>
26 #include <libxml/xmlregexp.h>
27 #include <libxml/xmlautomata.h>
28 #include <libxml/xmlunicode.h>
29
30 /* #define DEBUG_REGEXP_GRAPH  */
31 /* #define DEBUG_REGEXP_EXEC */
32 /* #define DEBUG_PUSH */
33 /* #define DEBUG_COMPACTION */
34
35 #define ERROR(str) ctxt->error = 1;                                     \
36     xmlGenericError(xmlGenericErrorContext, "Regexp: %s: %s\n", str, ctxt->cur)
37 #define NEXT ctxt->cur++
38 #define CUR (*(ctxt->cur))
39 #define NXT(index) (ctxt->cur[index])
40
41 #define CUR_SCHAR(s, l) xmlStringCurrentChar(NULL, s, &l)
42 #define NEXTL(l) ctxt->cur += l;
43
44 /**
45  * TODO:
46  *
47  * macro to flag unimplemented blocks
48  */
49 #define TODO                                                            \
50     xmlGenericError(xmlGenericErrorContext,                             \
51             "Unimplemented block at %s:%d\n",                           \
52             __FILE__, __LINE__);
53
54
55 /************************************************************************
56  *                                                                      *
57  *                      Datatypes and structures                        *
58  *                                                                      *
59  ************************************************************************/
60
61 typedef enum {
62     XML_REGEXP_EPSILON = 1,
63     XML_REGEXP_CHARVAL,
64     XML_REGEXP_RANGES,
65     XML_REGEXP_SUBREG,
66     XML_REGEXP_STRING,
67     XML_REGEXP_ANYCHAR, /* . */
68     XML_REGEXP_ANYSPACE, /* \s */
69     XML_REGEXP_NOTSPACE, /* \S */
70     XML_REGEXP_INITNAME, /* \l */
71     XML_REGEXP_NOTINITNAME, /* \l */
72     XML_REGEXP_NAMECHAR, /* \c */
73     XML_REGEXP_NOTNAMECHAR, /* \C */
74     XML_REGEXP_DECIMAL, /* \d */
75     XML_REGEXP_NOTDECIMAL, /* \d */
76     XML_REGEXP_REALCHAR, /* \w */
77     XML_REGEXP_NOTREALCHAR, /* \w */
78     XML_REGEXP_LETTER,
79     XML_REGEXP_LETTER_UPPERCASE,
80     XML_REGEXP_LETTER_LOWERCASE,
81     XML_REGEXP_LETTER_TITLECASE,
82     XML_REGEXP_LETTER_MODIFIER,
83     XML_REGEXP_LETTER_OTHERS,
84     XML_REGEXP_MARK,
85     XML_REGEXP_MARK_NONSPACING,
86     XML_REGEXP_MARK_SPACECOMBINING,
87     XML_REGEXP_MARK_ENCLOSING,
88     XML_REGEXP_NUMBER,
89     XML_REGEXP_NUMBER_DECIMAL,
90     XML_REGEXP_NUMBER_LETTER,
91     XML_REGEXP_NUMBER_OTHERS,
92     XML_REGEXP_PUNCT,
93     XML_REGEXP_PUNCT_CONNECTOR,
94     XML_REGEXP_PUNCT_DASH,
95     XML_REGEXP_PUNCT_OPEN,
96     XML_REGEXP_PUNCT_CLOSE,
97     XML_REGEXP_PUNCT_INITQUOTE,
98     XML_REGEXP_PUNCT_FINQUOTE,
99     XML_REGEXP_PUNCT_OTHERS,
100     XML_REGEXP_SEPAR,
101     XML_REGEXP_SEPAR_SPACE,
102     XML_REGEXP_SEPAR_LINE,
103     XML_REGEXP_SEPAR_PARA,
104     XML_REGEXP_SYMBOL,
105     XML_REGEXP_SYMBOL_MATH,
106     XML_REGEXP_SYMBOL_CURRENCY,
107     XML_REGEXP_SYMBOL_MODIFIER,
108     XML_REGEXP_SYMBOL_OTHERS,
109     XML_REGEXP_OTHER,
110     XML_REGEXP_OTHER_CONTROL,
111     XML_REGEXP_OTHER_FORMAT,
112     XML_REGEXP_OTHER_PRIVATE,
113     XML_REGEXP_OTHER_NA,
114     XML_REGEXP_BLOCK_NAME
115 } xmlRegAtomType;
116
117 typedef enum {
118     XML_REGEXP_QUANT_EPSILON = 1,
119     XML_REGEXP_QUANT_ONCE,
120     XML_REGEXP_QUANT_OPT,
121     XML_REGEXP_QUANT_MULT,
122     XML_REGEXP_QUANT_PLUS,
123     XML_REGEXP_QUANT_ONCEONLY,
124     XML_REGEXP_QUANT_ALL,
125     XML_REGEXP_QUANT_RANGE
126 } xmlRegQuantType;
127
128 typedef enum {
129     XML_REGEXP_START_STATE = 1,
130     XML_REGEXP_FINAL_STATE,
131     XML_REGEXP_TRANS_STATE
132 } xmlRegStateType;
133
134 typedef enum {
135     XML_REGEXP_MARK_NORMAL = 0,
136     XML_REGEXP_MARK_START,
137     XML_REGEXP_MARK_VISITED
138 } xmlRegMarkedType;
139
140 typedef struct _xmlRegRange xmlRegRange;
141 typedef xmlRegRange *xmlRegRangePtr;
142
143 struct _xmlRegRange {
144     int neg;
145     xmlRegAtomType type;
146     int start;
147     int end;
148     xmlChar *blockName;
149 };
150
151 typedef struct _xmlRegAtom xmlRegAtom;
152 typedef xmlRegAtom *xmlRegAtomPtr;
153
154 typedef struct _xmlAutomataState xmlRegState;
155 typedef xmlRegState *xmlRegStatePtr;
156
157 struct _xmlRegAtom {
158     int no;
159     xmlRegAtomType type;
160     xmlRegQuantType quant;
161     int min;
162     int max;
163
164     void *valuep;
165     void *valuep2;
166     int neg;
167     int codepoint;
168     xmlRegStatePtr start;
169     xmlRegStatePtr stop;
170     int maxRanges;
171     int nbRanges;
172     xmlRegRangePtr *ranges;
173     void *data;
174 };
175
176 typedef struct _xmlRegCounter xmlRegCounter;
177 typedef xmlRegCounter *xmlRegCounterPtr;
178
179 struct _xmlRegCounter {
180     int min;
181     int max;
182 };
183
184 typedef struct _xmlRegTrans xmlRegTrans;
185 typedef xmlRegTrans *xmlRegTransPtr;
186
187 struct _xmlRegTrans {
188     xmlRegAtomPtr atom;
189     int to;
190     int counter;
191     int count;
192 };
193
194 struct _xmlAutomataState {
195     xmlRegStateType type;
196     xmlRegMarkedType mark;
197     xmlRegMarkedType reached;
198     int no;
199
200     int maxTrans;
201     int nbTrans;
202     xmlRegTrans *trans;
203 };
204
205 typedef struct _xmlAutomata xmlRegParserCtxt;
206 typedef xmlRegParserCtxt *xmlRegParserCtxtPtr;
207
208 struct _xmlAutomata {
209     xmlChar *string;
210     xmlChar *cur;
211
212     int error;
213     int neg;
214
215     xmlRegStatePtr start;
216     xmlRegStatePtr end;
217     xmlRegStatePtr state;
218
219     xmlRegAtomPtr atom;
220
221     int maxAtoms;
222     int nbAtoms;
223     xmlRegAtomPtr *atoms;
224
225     int maxStates;
226     int nbStates;
227     xmlRegStatePtr *states;
228
229     int maxCounters;
230     int nbCounters;
231     xmlRegCounter *counters;
232
233     int determinist;
234 };
235
236 struct _xmlRegexp {
237     xmlChar *string;
238     int nbStates;
239     xmlRegStatePtr *states;
240     int nbAtoms;
241     xmlRegAtomPtr *atoms;
242     int nbCounters;
243     xmlRegCounter *counters;
244     int determinist;
245     /*
246      * That's the compact form for determinists automatas
247      */
248     int nbstates;
249     int *compact;
250     void **transdata;
251     int nbstrings;
252     xmlChar **stringMap;
253 };
254
255 typedef struct _xmlRegExecRollback xmlRegExecRollback;
256 typedef xmlRegExecRollback *xmlRegExecRollbackPtr;
257
258 struct _xmlRegExecRollback {
259     xmlRegStatePtr state;/* the current state */
260     int index;          /* the index in the input stack */
261     int nextbranch;     /* the next transition to explore in that state */
262     int *counts;        /* save the automate state if it has some */
263 };
264
265 typedef struct _xmlRegInputToken xmlRegInputToken;
266 typedef xmlRegInputToken *xmlRegInputTokenPtr;
267
268 struct _xmlRegInputToken {
269     xmlChar *value;
270     void *data;
271 };
272
273 struct _xmlRegExecCtxt {
274     int status;         /* execution status != 0 indicate an error */
275     int determinist;    /* did we found an inderterministic behaviour */
276     xmlRegexpPtr comp;  /* the compiled regexp */
277     xmlRegExecCallbacks callback;
278     void *data;
279
280     xmlRegStatePtr state;/* the current state */
281     int transno;        /* the current transition on that state */
282     int transcount;     /* the number of char in char counted transitions */
283
284     /*
285      * A stack of rollback states
286      */
287     int maxRollbacks;
288     int nbRollbacks;
289     xmlRegExecRollback *rollbacks;
290
291     /*
292      * The state of the automata if any
293      */
294     int *counts;
295
296     /*
297      * The input stack
298      */
299     int inputStackMax;
300     int inputStackNr;
301     int index;
302     int *charStack;
303     const xmlChar *inputString; /* when operating on characters */
304     xmlRegInputTokenPtr inputStack;/* when operating on strings */
305
306 };
307
308 #define REGEXP_ALL_COUNTER      0x123456
309 #define REGEXP_ALL_LAX_COUNTER  0x123457
310
311 static void xmlFAParseRegExp(xmlRegParserCtxtPtr ctxt, int top);
312 static void xmlRegFreeState(xmlRegStatePtr state);
313 static void xmlRegFreeAtom(xmlRegAtomPtr atom);
314
315 /************************************************************************
316  *                                                                      *
317  *                      Allocation/Deallocation                         *
318  *                                                                      *
319  ************************************************************************/
320
321 static int xmlFAComputesDeterminism(xmlRegParserCtxtPtr ctxt);
322 /**
323  * xmlRegEpxFromParse:
324  * @ctxt:  the parser context used to build it
325  *
326  * Allocate a new regexp and fill it with the reult from the parser
327  *
328  * Returns the new regexp or NULL in case of error
329  */
330 static xmlRegexpPtr
331 xmlRegEpxFromParse(xmlRegParserCtxtPtr ctxt) {
332     xmlRegexpPtr ret;
333
334     ret = (xmlRegexpPtr) xmlMalloc(sizeof(xmlRegexp));
335     if (ret == NULL) {
336         xmlGenericError(xmlGenericErrorContext,
337              "out of memory compiling regexp\n");
338         return(NULL);
339     }
340     memset(ret, 0, sizeof(xmlRegexp));
341     ret->string = ctxt->string;
342     ret->nbStates = ctxt->nbStates;
343     ret->states = ctxt->states;
344     ret->nbAtoms = ctxt->nbAtoms;
345     ret->atoms = ctxt->atoms;
346     ret->nbCounters = ctxt->nbCounters;
347     ret->counters = ctxt->counters;
348     ret->determinist = ctxt->determinist;
349
350     if ((ret->determinist != 0) &&
351         (ret->nbCounters == 0) &&
352         (ret->atoms != NULL) &&
353         (ret->atoms[0] != NULL) &&
354         (ret->atoms[0]->type == XML_REGEXP_STRING)) {
355         int i, j, nbstates = 0, nbatoms = 0;
356         int *stateRemap;
357         int *stringRemap;
358         int *transitions;
359         void **transdata;
360         xmlChar **stringMap;
361         xmlChar *value;
362
363         /*
364          * Switch to a compact representation
365          * 1/ counting the effective number of states left
366          * 2/ conting the unique number of atoms, and check that
367          *    they are all of the string type
368          * 3/ build a table state x atom for the transitions
369          */
370
371         stateRemap = xmlMalloc(ret->nbStates * sizeof(int));
372         if (stateRemap == NULL) {
373             xmlGenericError(xmlGenericErrorContext,
374                  "out of memory compiling regexp\n");
375             xmlFree(ret);
376             return(NULL);
377         }
378         for (i = 0;i < ret->nbStates;i++) {
379             if (ret->states[i] != NULL) {
380                 stateRemap[i] = nbstates;
381                 nbstates++;
382             } else {
383                 stateRemap[i] = -1;
384             }
385         }
386 #ifdef DEBUG_COMPACTION
387         printf("Final: %d states\n", nbstates);
388 #endif
389         stringMap = xmlMalloc(ret->nbAtoms * sizeof(char *));
390         if (stringMap == NULL) {
391             xmlGenericError(xmlGenericErrorContext,
392                  "out of memory compiling regexp\n");
393             xmlFree(stateRemap);
394             xmlFree(ret);
395             return(NULL);
396         }
397         stringRemap = xmlMalloc(ret->nbAtoms * sizeof(int));
398         if (stringRemap == NULL) {
399             xmlGenericError(xmlGenericErrorContext,
400                  "out of memory compiling regexp\n");
401             xmlFree(stringMap);
402             xmlFree(stateRemap);
403             xmlFree(ret);
404             return(NULL);
405         }
406         for (i = 0;i < ret->nbAtoms;i++) {
407             if ((ret->atoms[i]->type == XML_REGEXP_STRING) &&
408                 (ret->atoms[i]->quant == XML_REGEXP_QUANT_ONCE)) {
409                 value = ret->atoms[i]->valuep;
410                 for (j = 0;j < nbatoms;j++) {
411                     if (xmlStrEqual(stringMap[j], value)) {
412                         stringRemap[i] = j;
413                         break;
414                     }
415                 }
416                 if (j >= nbatoms) {
417                     stringRemap[i] = nbatoms;
418                     stringMap[nbatoms] = xmlStrdup(value);
419                     if (stringMap[nbatoms] == NULL) {
420                         for (i = 0;i < nbatoms;i++)
421                             xmlFree(stringMap[i]);
422                         xmlFree(stringRemap);
423                         xmlFree(stringMap);
424                         xmlFree(stateRemap);
425                         xmlFree(ret);
426                         return(NULL);
427                     }
428                     nbatoms++;
429                 }
430             } else {
431                 xmlFree(stateRemap);
432                 xmlFree(stringRemap);
433                 for (i = 0;i < nbatoms;i++)
434                     xmlFree(stringMap[i]);
435                 xmlFree(stringMap);
436                 xmlFree(ret);
437                 return(NULL);
438             }
439         }
440 #ifdef DEBUG_COMPACTION
441         printf("Final: %d atoms\n", nbatoms);
442 #endif
443         transitions = (int *) xmlMalloc((nbstates + 1) *
444                                         (nbatoms + 1) * sizeof(int));
445         if (transitions == NULL) {
446             xmlFree(stateRemap);
447             xmlFree(stringRemap);
448             xmlFree(stringMap);
449             xmlFree(ret);
450             return(NULL);
451         }
452         memset(transitions, 0, (nbstates + 1) * (nbatoms + 1) * sizeof(int));
453
454         /*
455          * Allocate the transition table. The first entry for each
456          * state correspond to the state type.
457          */
458         transdata = NULL;
459
460         for (i = 0;i < ret->nbStates;i++) {
461             int stateno, atomno, targetno, prev;
462             xmlRegStatePtr state;
463             xmlRegTransPtr trans;
464
465             stateno = stateRemap[i];
466             if (stateno == -1)
467                 continue;
468             state = ret->states[i];
469
470             transitions[stateno * (nbatoms + 1)] = state->type;
471
472             for (j = 0;j < state->nbTrans;j++) {
473                 trans = &(state->trans[j]);
474                 if ((trans->to == -1) || (trans->atom == NULL))
475                     continue;
476                 atomno = stringRemap[trans->atom->no];
477                 if ((trans->atom->data != NULL) && (transdata == NULL)) {
478                     transdata = (void **) xmlMalloc(nbstates * nbatoms *
479                                                     sizeof(void *));
480                     if (transdata != NULL)
481                         memset(transdata, 0,
482                                nbstates * nbatoms * sizeof(void *));
483                     else {
484                         xmlGenericError(xmlGenericErrorContext,
485                              "out of memory compiling regexp\n");
486                         break;
487                     }
488                 }
489                 targetno = stateRemap[trans->to];
490                 /*
491                  * if the same atome can generate transition to 2 different
492                  * states then it means the automata is not determinist and
493                  * the compact form can't be used !
494                  */
495                 prev = transitions[stateno * (nbatoms + 1) + atomno + 1];
496                 if (prev != 0) {
497                     if (prev != targetno + 1) {
498                         ret->determinist = 0;
499 #ifdef DEBUG_COMPACTION
500                         printf("Indet: state %d trans %d, atom %d to %d : %d to %d\n",
501                                i, j, trans->atom->no, trans->to, atomno, targetno);
502                         printf("       previous to is %d\n", prev);
503 #endif
504                         ret->determinist = 0;
505                         if (transdata != NULL)
506                             xmlFree(transdata);
507                         xmlFree(transitions);
508                         xmlFree(stateRemap);
509                         xmlFree(stringRemap);
510                         for (i = 0;i < nbatoms;i++)
511                             xmlFree(stringMap[i]);
512                         xmlFree(stringMap);
513                         goto not_determ;
514                     }
515                 } else {
516 #if 0
517                     printf("State %d trans %d: atom %d to %d : %d to %d\n",
518                            i, j, trans->atom->no, trans->to, atomno, targetno);
519 #endif
520                     transitions[stateno * (nbatoms + 1) + atomno + 1] =
521                         targetno + 1; /* to avoid 0 */
522                     if (transdata != NULL)
523                         transdata[stateno * nbatoms + atomno] =
524                             trans->atom->data;
525                 }
526             }
527         }
528         ret->determinist = 1;
529 #ifdef DEBUG_COMPACTION
530         /*
531          * Debug
532          */
533         for (i = 0;i < nbstates;i++) {
534             for (j = 0;j < nbatoms + 1;j++) {
535                 printf("%02d ", transitions[i * (nbatoms + 1) + j]);
536             }
537             printf("\n");
538         }
539         printf("\n");
540 #endif
541         /*
542          * Cleanup of the old data
543          */
544         if (ret->states != NULL) {
545             for (i = 0;i < ret->nbStates;i++)
546                 xmlRegFreeState(ret->states[i]);
547             xmlFree(ret->states);
548         }
549         ret->states = NULL;
550         ret->nbStates = 0;
551         if (ret->atoms != NULL) {
552             for (i = 0;i < ret->nbAtoms;i++)
553                 xmlRegFreeAtom(ret->atoms[i]);
554             xmlFree(ret->atoms);
555         }
556         ret->atoms = NULL;
557         ret->nbAtoms = 0;
558
559         ret->compact = transitions;
560         ret->transdata = transdata;
561         ret->stringMap = stringMap;
562         ret->nbstrings = nbatoms;
563         ret->nbstates = nbstates;
564         xmlFree(stateRemap);
565         xmlFree(stringRemap);
566     }
567 not_determ:
568     ctxt->string = NULL;
569     ctxt->nbStates = 0;
570     ctxt->states = NULL;
571     ctxt->nbAtoms = 0;
572     ctxt->atoms = NULL;
573     ctxt->nbCounters = 0;
574     ctxt->counters = NULL;
575     return(ret);
576 }
577
578 /**
579  * xmlRegNewParserCtxt:
580  * @string:  the string to parse
581  *
582  * Allocate a new regexp parser context
583  *
584  * Returns the new context or NULL in case of error
585  */
586 static xmlRegParserCtxtPtr
587 xmlRegNewParserCtxt(const xmlChar *string) {
588     xmlRegParserCtxtPtr ret;
589
590     ret = (xmlRegParserCtxtPtr) xmlMalloc(sizeof(xmlRegParserCtxt));
591     if (ret == NULL)
592         return(NULL);
593     memset(ret, 0, sizeof(xmlRegParserCtxt));
594     if (string != NULL)
595         ret->string = xmlStrdup(string);
596     ret->cur = ret->string;
597     ret->neg = 0;
598     ret->error = 0;
599     ret->determinist = -1;
600     return(ret);
601 }
602
603 /**
604  * xmlRegNewRange:
605  * @ctxt:  the regexp parser context
606  * @neg:  is that negative
607  * @type:  the type of range
608  * @start:  the start codepoint
609  * @end:  the end codepoint
610  *
611  * Allocate a new regexp range
612  *
613  * Returns the new range or NULL in case of error
614  */
615 static xmlRegRangePtr
616 xmlRegNewRange(xmlRegParserCtxtPtr ctxt,
617                int neg, xmlRegAtomType type, int start, int end) {
618     xmlRegRangePtr ret;
619
620     ret = (xmlRegRangePtr) xmlMalloc(sizeof(xmlRegRange));
621     if (ret == NULL) {
622         ERROR("failed to allocate regexp range");
623         return(NULL);
624     }
625     ret->neg = neg;
626     ret->type = type;
627     ret->start = start;
628     ret->end = end;
629     return(ret);
630 }
631
632 /**
633  * xmlRegFreeRange:
634  * @range:  the regexp range
635  *
636  * Free a regexp range
637  */
638 static void
639 xmlRegFreeRange(xmlRegRangePtr range) {
640     if (range == NULL)
641         return;
642
643     if (range->blockName != NULL)
644         xmlFree(range->blockName);
645     xmlFree(range);
646 }
647
648 /**
649  * xmlRegNewAtom:
650  * @ctxt:  the regexp parser context
651  * @type:  the type of atom
652  *
653  * Allocate a new regexp range
654  *
655  * Returns the new atom or NULL in case of error
656  */
657 static xmlRegAtomPtr
658 xmlRegNewAtom(xmlRegParserCtxtPtr ctxt, xmlRegAtomType type) {
659     xmlRegAtomPtr ret;
660
661     ret = (xmlRegAtomPtr) xmlMalloc(sizeof(xmlRegAtom));
662     if (ret == NULL) {
663         ERROR("failed to allocate regexp atom");
664         return(NULL);
665     }
666     memset(ret, 0, sizeof(xmlRegAtom));
667     ret->type = type;
668     ret->quant = XML_REGEXP_QUANT_ONCE;
669     ret->min = 0;
670     ret->max = 0;
671     return(ret);
672 }
673
674 /**
675  * xmlRegFreeAtom:
676  * @atom:  the regexp atom
677  *
678  * Free a regexp atom
679  */
680 static void
681 xmlRegFreeAtom(xmlRegAtomPtr atom) {
682     int i;
683
684     if (atom == NULL)
685         return;
686
687     for (i = 0;i < atom->nbRanges;i++)
688         xmlRegFreeRange(atom->ranges[i]);
689     if (atom->ranges != NULL)
690         xmlFree(atom->ranges);
691     if (atom->type == XML_REGEXP_STRING)
692         xmlFree(atom->valuep);
693     xmlFree(atom);
694 }
695
696 static xmlRegStatePtr
697 xmlRegNewState(xmlRegParserCtxtPtr ctxt) {
698     xmlRegStatePtr ret;
699
700     ret = (xmlRegStatePtr) xmlMalloc(sizeof(xmlRegState));
701     if (ret == NULL) {
702         ERROR("failed to allocate regexp state");
703         return(NULL);
704     }
705     memset(ret, 0, sizeof(xmlRegState));
706     ret->type = XML_REGEXP_TRANS_STATE;
707     ret->mark = XML_REGEXP_MARK_NORMAL;
708     return(ret);
709 }
710
711 /**
712  * xmlRegFreeState:
713  * @state:  the regexp state
714  *
715  * Free a regexp state
716  */
717 static void
718 xmlRegFreeState(xmlRegStatePtr state) {
719     if (state == NULL)
720         return;
721
722     if (state->trans != NULL)
723         xmlFree(state->trans);
724     xmlFree(state);
725 }
726
727 /**
728  * xmlRegFreeParserCtxt:
729  * @ctxt:  the regexp parser context
730  *
731  * Free a regexp parser context
732  */
733 static void
734 xmlRegFreeParserCtxt(xmlRegParserCtxtPtr ctxt) {
735     int i;
736     if (ctxt == NULL)
737         return;
738
739     if (ctxt->string != NULL)
740         xmlFree(ctxt->string);
741     if (ctxt->states != NULL) {
742         for (i = 0;i < ctxt->nbStates;i++)
743             xmlRegFreeState(ctxt->states[i]);
744         xmlFree(ctxt->states);
745     }
746     if (ctxt->atoms != NULL) {
747         for (i = 0;i < ctxt->nbAtoms;i++)
748             xmlRegFreeAtom(ctxt->atoms[i]);
749         xmlFree(ctxt->atoms);
750     }
751     if (ctxt->counters != NULL)
752         xmlFree(ctxt->counters);
753     xmlFree(ctxt);
754 }
755
756 /************************************************************************
757  *                                                                      *
758  *                      Display of Data structures                      *
759  *                                                                      *
760  ************************************************************************/
761
762 static void
763 xmlRegPrintAtomType(FILE *output, xmlRegAtomType type) {
764     switch (type) {
765         case XML_REGEXP_EPSILON:
766             fprintf(output, "epsilon "); break;
767         case XML_REGEXP_CHARVAL:
768             fprintf(output, "charval "); break;
769         case XML_REGEXP_RANGES:
770             fprintf(output, "ranges "); break;
771         case XML_REGEXP_SUBREG:
772             fprintf(output, "subexpr "); break;
773         case XML_REGEXP_STRING:
774             fprintf(output, "string "); break;
775         case XML_REGEXP_ANYCHAR:
776             fprintf(output, "anychar "); break;
777         case XML_REGEXP_ANYSPACE:
778             fprintf(output, "anyspace "); break;
779         case XML_REGEXP_NOTSPACE:
780             fprintf(output, "notspace "); break;
781         case XML_REGEXP_INITNAME:
782             fprintf(output, "initname "); break;
783         case XML_REGEXP_NOTINITNAME:
784             fprintf(output, "notinitname "); break;
785         case XML_REGEXP_NAMECHAR:
786             fprintf(output, "namechar "); break;
787         case XML_REGEXP_NOTNAMECHAR:
788             fprintf(output, "notnamechar "); break;
789         case XML_REGEXP_DECIMAL:
790             fprintf(output, "decimal "); break;
791         case XML_REGEXP_NOTDECIMAL:
792             fprintf(output, "notdecimal "); break;
793         case XML_REGEXP_REALCHAR:
794             fprintf(output, "realchar "); break;
795         case XML_REGEXP_NOTREALCHAR:
796             fprintf(output, "notrealchar "); break;
797         case XML_REGEXP_LETTER:
798             fprintf(output, "LETTER "); break;
799         case XML_REGEXP_LETTER_UPPERCASE:
800             fprintf(output, "LETTER_UPPERCASE "); break;
801         case XML_REGEXP_LETTER_LOWERCASE:
802             fprintf(output, "LETTER_LOWERCASE "); break;
803         case XML_REGEXP_LETTER_TITLECASE:
804             fprintf(output, "LETTER_TITLECASE "); break;
805         case XML_REGEXP_LETTER_MODIFIER:
806             fprintf(output, "LETTER_MODIFIER "); break;
807         case XML_REGEXP_LETTER_OTHERS:
808             fprintf(output, "LETTER_OTHERS "); break;
809         case XML_REGEXP_MARK:
810             fprintf(output, "MARK "); break;
811         case XML_REGEXP_MARK_NONSPACING:
812             fprintf(output, "MARK_NONSPACING "); break;
813         case XML_REGEXP_MARK_SPACECOMBINING:
814             fprintf(output, "MARK_SPACECOMBINING "); break;
815         case XML_REGEXP_MARK_ENCLOSING:
816             fprintf(output, "MARK_ENCLOSING "); break;
817         case XML_REGEXP_NUMBER:
818             fprintf(output, "NUMBER "); break;
819         case XML_REGEXP_NUMBER_DECIMAL:
820             fprintf(output, "NUMBER_DECIMAL "); break;
821         case XML_REGEXP_NUMBER_LETTER:
822             fprintf(output, "NUMBER_LETTER "); break;
823         case XML_REGEXP_NUMBER_OTHERS:
824             fprintf(output, "NUMBER_OTHERS "); break;
825         case XML_REGEXP_PUNCT:
826             fprintf(output, "PUNCT "); break;
827         case XML_REGEXP_PUNCT_CONNECTOR:
828             fprintf(output, "PUNCT_CONNECTOR "); break;
829         case XML_REGEXP_PUNCT_DASH:
830             fprintf(output, "PUNCT_DASH "); break;
831         case XML_REGEXP_PUNCT_OPEN:
832             fprintf(output, "PUNCT_OPEN "); break;
833         case XML_REGEXP_PUNCT_CLOSE:
834             fprintf(output, "PUNCT_CLOSE "); break;
835         case XML_REGEXP_PUNCT_INITQUOTE:
836             fprintf(output, "PUNCT_INITQUOTE "); break;
837         case XML_REGEXP_PUNCT_FINQUOTE:
838             fprintf(output, "PUNCT_FINQUOTE "); break;
839         case XML_REGEXP_PUNCT_OTHERS:
840             fprintf(output, "PUNCT_OTHERS "); break;
841         case XML_REGEXP_SEPAR:
842             fprintf(output, "SEPAR "); break;
843         case XML_REGEXP_SEPAR_SPACE:
844             fprintf(output, "SEPAR_SPACE "); break;
845         case XML_REGEXP_SEPAR_LINE:
846             fprintf(output, "SEPAR_LINE "); break;
847         case XML_REGEXP_SEPAR_PARA:
848             fprintf(output, "SEPAR_PARA "); break;
849         case XML_REGEXP_SYMBOL:
850             fprintf(output, "SYMBOL "); break;
851         case XML_REGEXP_SYMBOL_MATH:
852             fprintf(output, "SYMBOL_MATH "); break;
853         case XML_REGEXP_SYMBOL_CURRENCY:
854             fprintf(output, "SYMBOL_CURRENCY "); break;
855         case XML_REGEXP_SYMBOL_MODIFIER:
856             fprintf(output, "SYMBOL_MODIFIER "); break;
857         case XML_REGEXP_SYMBOL_OTHERS:
858             fprintf(output, "SYMBOL_OTHERS "); break;
859         case XML_REGEXP_OTHER:
860             fprintf(output, "OTHER "); break;
861         case XML_REGEXP_OTHER_CONTROL:
862             fprintf(output, "OTHER_CONTROL "); break;
863         case XML_REGEXP_OTHER_FORMAT:
864             fprintf(output, "OTHER_FORMAT "); break;
865         case XML_REGEXP_OTHER_PRIVATE:
866             fprintf(output, "OTHER_PRIVATE "); break;
867         case XML_REGEXP_OTHER_NA:
868             fprintf(output, "OTHER_NA "); break;
869         case XML_REGEXP_BLOCK_NAME:
870             fprintf(output, "BLOCK "); break;
871     }
872 }
873
874 static void
875 xmlRegPrintQuantType(FILE *output, xmlRegQuantType type) {
876     switch (type) {
877         case XML_REGEXP_QUANT_EPSILON:
878             fprintf(output, "epsilon "); break;
879         case XML_REGEXP_QUANT_ONCE:
880             fprintf(output, "once "); break;
881         case XML_REGEXP_QUANT_OPT:
882             fprintf(output, "? "); break;
883         case XML_REGEXP_QUANT_MULT:
884             fprintf(output, "* "); break;
885         case XML_REGEXP_QUANT_PLUS:
886             fprintf(output, "+ "); break;
887         case XML_REGEXP_QUANT_RANGE:
888             fprintf(output, "range "); break;
889         case XML_REGEXP_QUANT_ONCEONLY:
890             fprintf(output, "onceonly "); break;
891         case XML_REGEXP_QUANT_ALL:
892             fprintf(output, "all "); break;
893     }
894 }
895 static void
896 xmlRegPrintRange(FILE *output, xmlRegRangePtr range) {
897     fprintf(output, "  range: ");
898     if (range->neg)
899         fprintf(output, "negative ");
900     xmlRegPrintAtomType(output, range->type);
901     fprintf(output, "%c - %c\n", range->start, range->end);
902 }
903
904 static void
905 xmlRegPrintAtom(FILE *output, xmlRegAtomPtr atom) {
906     fprintf(output, " atom: ");
907     if (atom == NULL) {
908         fprintf(output, "NULL\n");
909         return;
910     }
911     xmlRegPrintAtomType(output, atom->type);
912     xmlRegPrintQuantType(output, atom->quant);
913     if (atom->quant == XML_REGEXP_QUANT_RANGE)
914         fprintf(output, "%d-%d ", atom->min, atom->max);
915     if (atom->type == XML_REGEXP_STRING)
916         fprintf(output, "'%s' ", (char *) atom->valuep);
917     if (atom->type == XML_REGEXP_CHARVAL)
918         fprintf(output, "char %c\n", atom->codepoint);
919     else if (atom->type == XML_REGEXP_RANGES) {
920         int i;
921         fprintf(output, "%d entries\n", atom->nbRanges);
922         for (i = 0; i < atom->nbRanges;i++)
923             xmlRegPrintRange(output, atom->ranges[i]);
924     } else if (atom->type == XML_REGEXP_SUBREG) {
925         fprintf(output, "start %d end %d\n", atom->start->no, atom->stop->no);
926     } else {
927         fprintf(output, "\n");
928     }
929 }
930
931 static void
932 xmlRegPrintTrans(FILE *output, xmlRegTransPtr trans) {
933     fprintf(output, "  trans: ");
934     if (trans == NULL) {
935         fprintf(output, "NULL\n");
936         return;
937     }
938     if (trans->to < 0) {
939         fprintf(output, "removed\n");
940         return;
941     }
942     if (trans->counter >= 0) {
943         fprintf(output, "counted %d, ", trans->counter);
944     }
945     if (trans->count == REGEXP_ALL_COUNTER) {
946         fprintf(output, "all transition, ");
947     } else if (trans->count >= 0) {
948         fprintf(output, "count based %d, ", trans->count);
949     }
950     if (trans->atom == NULL) {
951         fprintf(output, "epsilon to %d\n", trans->to);
952         return;
953     }
954     if (trans->atom->type == XML_REGEXP_CHARVAL)
955         fprintf(output, "char %c ", trans->atom->codepoint);
956     fprintf(output, "atom %d, to %d\n", trans->atom->no, trans->to);
957 }
958     
959 static void
960 xmlRegPrintState(FILE *output, xmlRegStatePtr state) {
961     int i;
962
963     fprintf(output, " state: ");
964     if (state == NULL) {
965         fprintf(output, "NULL\n");
966         return;
967     }
968     if (state->type == XML_REGEXP_START_STATE)
969         fprintf(output, "START ");
970     if (state->type == XML_REGEXP_FINAL_STATE)
971         fprintf(output, "FINAL ");
972     
973     fprintf(output, "%d, %d transitions:\n", state->no, state->nbTrans);
974     for (i = 0;i < state->nbTrans; i++) {
975         xmlRegPrintTrans(output, &(state->trans[i]));
976     }
977 }
978
979 #ifdef DEBUG_REGEXP_GRAPH
980 static void
981 xmlRegPrintCtxt(FILE *output, xmlRegParserCtxtPtr ctxt) {
982     int i;
983
984     fprintf(output, " ctxt: ");
985     if (ctxt == NULL) {
986         fprintf(output, "NULL\n");
987         return;
988     }
989     fprintf(output, "'%s' ", ctxt->string);
990     if (ctxt->error)
991         fprintf(output, "error ");
992     if (ctxt->neg)
993         fprintf(output, "neg ");
994     fprintf(output, "\n");
995     fprintf(output, "%d atoms:\n", ctxt->nbAtoms);
996     for (i = 0;i < ctxt->nbAtoms; i++) {
997         fprintf(output, " %02d ", i);
998         xmlRegPrintAtom(output, ctxt->atoms[i]);
999     }
1000     if (ctxt->atom != NULL) {
1001         fprintf(output, "current atom:\n");
1002         xmlRegPrintAtom(output, ctxt->atom);
1003     }
1004     fprintf(output, "%d states:", ctxt->nbStates);
1005     if (ctxt->start != NULL)
1006         fprintf(output, " start: %d", ctxt->start->no);
1007     if (ctxt->end != NULL)
1008         fprintf(output, " end: %d", ctxt->end->no);
1009     fprintf(output, "\n");
1010     for (i = 0;i < ctxt->nbStates; i++) {
1011         xmlRegPrintState(output, ctxt->states[i]);
1012     }
1013     fprintf(output, "%d counters:\n", ctxt->nbCounters);
1014     for (i = 0;i < ctxt->nbCounters; i++) {
1015         fprintf(output, " %d: min %d max %d\n", i, ctxt->counters[i].min,
1016                                                 ctxt->counters[i].max);
1017     }
1018 }
1019 #endif
1020
1021 /************************************************************************
1022  *                                                                      *
1023  *               Finite Automata structures manipulations               *
1024  *                                                                      *
1025  ************************************************************************/
1026
1027 static void 
1028 xmlRegAtomAddRange(xmlRegParserCtxtPtr ctxt, xmlRegAtomPtr atom,
1029                    int neg, xmlRegAtomType type, int start, int end,
1030                    xmlChar *blockName) {
1031     xmlRegRangePtr range;
1032
1033     if (atom == NULL) {
1034         ERROR("add range: atom is NULL");
1035         return;
1036     }
1037     if (atom->type != XML_REGEXP_RANGES) {
1038         ERROR("add range: atom is not ranges");
1039         return;
1040     }
1041     if (atom->maxRanges == 0) {
1042         atom->maxRanges = 4;
1043         atom->ranges = (xmlRegRangePtr *) xmlMalloc(atom->maxRanges *
1044                                              sizeof(xmlRegRangePtr));
1045         if (atom->ranges == NULL) {
1046             ERROR("add range: allocation failed");
1047             atom->maxRanges = 0;
1048             return;
1049         }
1050     } else if (atom->nbRanges >= atom->maxRanges) {
1051         xmlRegRangePtr *tmp;
1052         atom->maxRanges *= 2;
1053         tmp = (xmlRegRangePtr *) xmlRealloc(atom->ranges, atom->maxRanges *
1054                                              sizeof(xmlRegRangePtr));
1055         if (tmp == NULL) {
1056             ERROR("add range: allocation failed");
1057             atom->maxRanges /= 2;
1058             return;
1059         }
1060         atom->ranges = tmp;
1061     }
1062     range = xmlRegNewRange(ctxt, neg, type, start, end);
1063     if (range == NULL)
1064         return;
1065     range->blockName = blockName;
1066     atom->ranges[atom->nbRanges++] = range;
1067     
1068 }
1069
1070 static int
1071 xmlRegGetCounter(xmlRegParserCtxtPtr ctxt) {
1072     if (ctxt->maxCounters == 0) {
1073         ctxt->maxCounters = 4;
1074         ctxt->counters = (xmlRegCounter *) xmlMalloc(ctxt->maxCounters *
1075                                              sizeof(xmlRegCounter));
1076         if (ctxt->counters == NULL) {
1077             ERROR("reg counter: allocation failed");
1078             ctxt->maxCounters = 0;
1079             return(-1);
1080         }
1081     } else if (ctxt->nbCounters >= ctxt->maxCounters) {
1082         xmlRegCounter *tmp;
1083         ctxt->maxCounters *= 2;
1084         tmp = (xmlRegCounter *) xmlRealloc(ctxt->counters, ctxt->maxCounters *
1085                                            sizeof(xmlRegCounter));
1086         if (tmp == NULL) {
1087             ERROR("reg counter: allocation failed");
1088             ctxt->maxCounters /= 2;
1089             return(-1);
1090         }
1091         ctxt->counters = tmp;
1092     }
1093     ctxt->counters[ctxt->nbCounters].min = -1;
1094     ctxt->counters[ctxt->nbCounters].max = -1;
1095     return(ctxt->nbCounters++);
1096 }
1097
1098 static int 
1099 xmlRegAtomPush(xmlRegParserCtxtPtr ctxt, xmlRegAtomPtr atom) {
1100     if (atom == NULL) {
1101         ERROR("atom push: atom is NULL");
1102         return(-1);
1103     }
1104     if (ctxt->maxAtoms == 0) {
1105         ctxt->maxAtoms = 4;
1106         ctxt->atoms = (xmlRegAtomPtr *) xmlMalloc(ctxt->maxAtoms *
1107                                              sizeof(xmlRegAtomPtr));
1108         if (ctxt->atoms == NULL) {
1109             ERROR("atom push: allocation failed");
1110             ctxt->maxAtoms = 0;
1111             return(-1);
1112         }
1113     } else if (ctxt->nbAtoms >= ctxt->maxAtoms) {
1114         xmlRegAtomPtr *tmp;
1115         ctxt->maxAtoms *= 2;
1116         tmp = (xmlRegAtomPtr *) xmlRealloc(ctxt->atoms, ctxt->maxAtoms *
1117                                              sizeof(xmlRegAtomPtr));
1118         if (tmp == NULL) {
1119             ERROR("atom push: allocation failed");
1120             ctxt->maxAtoms /= 2;
1121             return(-1);
1122         }
1123         ctxt->atoms = tmp;
1124     }
1125     atom->no = ctxt->nbAtoms;
1126     ctxt->atoms[ctxt->nbAtoms++] = atom;
1127     return(0);
1128 }
1129
1130 static void 
1131 xmlRegStateAddTrans(xmlRegParserCtxtPtr ctxt, xmlRegStatePtr state,
1132                     xmlRegAtomPtr atom, xmlRegStatePtr target,
1133                     int counter, int count) {
1134     if (state == NULL) {
1135         ERROR("add state: state is NULL");
1136         return;
1137     }
1138     if (target == NULL) {
1139         ERROR("add state: target is NULL");
1140         return;
1141     }
1142     if (state->maxTrans == 0) {
1143         state->maxTrans = 4;
1144         state->trans = (xmlRegTrans *) xmlMalloc(state->maxTrans *
1145                                              sizeof(xmlRegTrans));
1146         if (state->trans == NULL) {
1147             ERROR("add range: allocation failed");
1148             state->maxTrans = 0;
1149             return;
1150         }
1151     } else if (state->nbTrans >= state->maxTrans) {
1152         xmlRegTrans *tmp;
1153         state->maxTrans *= 2;
1154         tmp = (xmlRegTrans *) xmlRealloc(state->trans, state->maxTrans *
1155                                              sizeof(xmlRegTrans));
1156         if (tmp == NULL) {
1157             ERROR("add range: allocation failed");
1158             state->maxTrans /= 2;
1159             return;
1160         }
1161         state->trans = tmp;
1162     }
1163 #ifdef DEBUG_REGEXP_GRAPH
1164     printf("Add trans from %d to %d ", state->no, target->no);
1165     if (count == REGEXP_ALL_COUNTER)
1166         printf("all transition");
1167     else if (count >= 0)
1168         printf("count based %d", count);
1169     else if (counter >= 0)
1170         printf("counted %d", counter);
1171     else if (atom == NULL)
1172         printf("epsilon transition");
1173     printf("\n");
1174 #endif
1175
1176     state->trans[state->nbTrans].atom = atom;
1177     state->trans[state->nbTrans].to = target->no;
1178     state->trans[state->nbTrans].counter = counter;
1179     state->trans[state->nbTrans].count = count;
1180     state->nbTrans++;
1181 }
1182
1183 static int
1184 xmlRegStatePush(xmlRegParserCtxtPtr ctxt, xmlRegStatePtr state) {
1185     if (state == NULL) return(-1);
1186     if (ctxt->maxStates == 0) {
1187         ctxt->maxStates = 4;
1188         ctxt->states = (xmlRegStatePtr *) xmlMalloc(ctxt->maxStates *
1189                                              sizeof(xmlRegStatePtr));
1190         if (ctxt->states == NULL) {
1191             ERROR("add range: allocation failed");
1192             ctxt->maxStates = 0;
1193             return(-1);
1194         }
1195     } else if (ctxt->nbStates >= ctxt->maxStates) {
1196         xmlRegStatePtr *tmp;
1197         ctxt->maxStates *= 2;
1198         tmp = (xmlRegStatePtr *) xmlRealloc(ctxt->states, ctxt->maxStates *
1199                                              sizeof(xmlRegStatePtr));
1200         if (tmp == NULL) {
1201             ERROR("add range: allocation failed");
1202             ctxt->maxStates /= 2;
1203             return(-1);
1204         }
1205         ctxt->states = tmp;
1206     }
1207     state->no = ctxt->nbStates;
1208     ctxt->states[ctxt->nbStates++] = state;
1209     return(0);
1210 }
1211
1212 /**
1213  * xmlFAGenerateAllTransition:
1214  * @ctxt:  a regexp parser context
1215  * @from:  the from state
1216  * @to:  the target state or NULL for building a new one
1217  * @lax:
1218  *
1219  */
1220 static void
1221 xmlFAGenerateAllTransition(xmlRegParserCtxtPtr ctxt,
1222                            xmlRegStatePtr from, xmlRegStatePtr to,
1223                            int lax) {
1224     if (to == NULL) {
1225         to = xmlRegNewState(ctxt);
1226         xmlRegStatePush(ctxt, to);
1227         ctxt->state = to;
1228     }
1229     if (lax)
1230         xmlRegStateAddTrans(ctxt, from, NULL, to, -1, REGEXP_ALL_LAX_COUNTER);
1231     else
1232         xmlRegStateAddTrans(ctxt, from, NULL, to, -1, REGEXP_ALL_COUNTER);
1233 }
1234
1235 /**
1236  * xmlFAGenerateEpsilonTransition:
1237  * @ctxt:  a regexp parser context
1238  * @from:  the from state
1239  * @to:  the target state or NULL for building a new one
1240  *
1241  */
1242 static void
1243 xmlFAGenerateEpsilonTransition(xmlRegParserCtxtPtr ctxt,
1244                                xmlRegStatePtr from, xmlRegStatePtr to) {
1245     if (to == NULL) {
1246         to = xmlRegNewState(ctxt);
1247         xmlRegStatePush(ctxt, to);
1248         ctxt->state = to;
1249     }
1250     xmlRegStateAddTrans(ctxt, from, NULL, to, -1, -1);
1251 }
1252
1253 /**
1254  * xmlFAGenerateCountedEpsilonTransition:
1255  * @ctxt:  a regexp parser context
1256  * @from:  the from state
1257  * @to:  the target state or NULL for building a new one
1258  * counter:  the counter for that transition
1259  *
1260  */
1261 static void
1262 xmlFAGenerateCountedEpsilonTransition(xmlRegParserCtxtPtr ctxt,
1263             xmlRegStatePtr from, xmlRegStatePtr to, int counter) {
1264     if (to == NULL) {
1265         to = xmlRegNewState(ctxt);
1266         xmlRegStatePush(ctxt, to);
1267         ctxt->state = to;
1268     }
1269     xmlRegStateAddTrans(ctxt, from, NULL, to, counter, -1);
1270 }
1271
1272 /**
1273  * xmlFAGenerateCountedTransition:
1274  * @ctxt:  a regexp parser context
1275  * @from:  the from state
1276  * @to:  the target state or NULL for building a new one
1277  * counter:  the counter for that transition
1278  *
1279  */
1280 static void
1281 xmlFAGenerateCountedTransition(xmlRegParserCtxtPtr ctxt,
1282             xmlRegStatePtr from, xmlRegStatePtr to, int counter) {
1283     if (to == NULL) {
1284         to = xmlRegNewState(ctxt);
1285         xmlRegStatePush(ctxt, to);
1286         ctxt->state = to;
1287     }
1288     xmlRegStateAddTrans(ctxt, from, NULL, to, -1, counter);
1289 }
1290
1291 /**
1292  * xmlFAGenerateTransitions:
1293  * @ctxt:  a regexp parser context
1294  * @from:  the from state
1295  * @to:  the target state or NULL for building a new one
1296  * @atom:  the atom generating the transition
1297  *
1298  * Returns 0 if succes and -1 in case of error.
1299  */
1300 static int
1301 xmlFAGenerateTransitions(xmlRegParserCtxtPtr ctxt, xmlRegStatePtr from,
1302                          xmlRegStatePtr to, xmlRegAtomPtr atom) {
1303     if (atom == NULL) {
1304         ERROR("genrate transition: atom == NULL");
1305         return(-1);
1306     }
1307     if (atom->type == XML_REGEXP_SUBREG) {
1308         /*
1309          * this is a subexpression handling one should not need to
1310          * create a new node excep for XML_REGEXP_QUANT_RANGE.
1311          */
1312         if (xmlRegAtomPush(ctxt, atom) < 0) {
1313             return(-1);
1314         }
1315         if ((to != NULL) && (atom->stop != to) &&
1316             (atom->quant != XML_REGEXP_QUANT_RANGE)) {
1317             /*
1318              * Generate an epsilon transition to link to the target
1319              */
1320             xmlFAGenerateEpsilonTransition(ctxt, atom->stop, to);
1321         }
1322         switch (atom->quant) {
1323             case XML_REGEXP_QUANT_OPT:
1324                 atom->quant = XML_REGEXP_QUANT_ONCE;
1325                 xmlFAGenerateEpsilonTransition(ctxt, atom->start, atom->stop);
1326                 break;
1327             case XML_REGEXP_QUANT_MULT:
1328                 atom->quant = XML_REGEXP_QUANT_ONCE;
1329                 xmlFAGenerateEpsilonTransition(ctxt, atom->start, atom->stop);
1330                 xmlFAGenerateEpsilonTransition(ctxt, atom->stop, atom->start);
1331                 break;
1332             case XML_REGEXP_QUANT_PLUS:
1333                 atom->quant = XML_REGEXP_QUANT_ONCE;
1334                 xmlFAGenerateEpsilonTransition(ctxt, atom->stop, atom->start);
1335                 break;
1336             case XML_REGEXP_QUANT_RANGE: {
1337                 int counter;
1338                 xmlRegStatePtr newstate;
1339
1340                 /*
1341                  * This one is nasty:
1342                  *   1/ register a new counter
1343                  *   2/ register an epsilon transition associated to
1344                  *      this counter going from atom->stop to atom->start
1345                  *   3/ create a new state
1346                  *   4/ generate a counted transition from atom->stop to
1347                  *      that state
1348                  */
1349                 counter = xmlRegGetCounter(ctxt);
1350                 ctxt->counters[counter].min = atom->min - 1;
1351                 ctxt->counters[counter].max = atom->max - 1;
1352                 atom->min = 0;
1353                 atom->max = 0;
1354                 atom->quant = XML_REGEXP_QUANT_ONCE;
1355                 xmlFAGenerateCountedEpsilonTransition(ctxt, atom->stop,
1356                                                       atom->start, counter);
1357                 if (to != NULL) {
1358                     newstate = to;
1359                 } else {
1360                     newstate = xmlRegNewState(ctxt);
1361                     xmlRegStatePush(ctxt, newstate);
1362                     ctxt->state = newstate;
1363                 }
1364                 xmlFAGenerateCountedTransition(ctxt, atom->stop,
1365                                                newstate, counter);
1366             }
1367             default:
1368                 break;
1369         }
1370         return(0);
1371     } else {
1372         if (to == NULL) {
1373             to = xmlRegNewState(ctxt);
1374             if (to != NULL)
1375                 xmlRegStatePush(ctxt, to);
1376             else {
1377                 return(-1);
1378             }
1379         }
1380         if (xmlRegAtomPush(ctxt, atom) < 0) {
1381             return(-1);
1382         }
1383         xmlRegStateAddTrans(ctxt, from, atom, to, -1, -1);
1384         ctxt->state = to;
1385     }
1386     switch (atom->quant) {
1387         case XML_REGEXP_QUANT_OPT:
1388             atom->quant = XML_REGEXP_QUANT_ONCE;
1389             xmlFAGenerateEpsilonTransition(ctxt, from, to);
1390             break;
1391         case XML_REGEXP_QUANT_MULT:
1392             atom->quant = XML_REGEXP_QUANT_ONCE;
1393             xmlFAGenerateEpsilonTransition(ctxt, from, to);
1394             xmlRegStateAddTrans(ctxt, to, atom, to, -1, -1);
1395             break;
1396         case XML_REGEXP_QUANT_PLUS:
1397             atom->quant = XML_REGEXP_QUANT_ONCE;
1398             xmlRegStateAddTrans(ctxt, to, atom, to, -1, -1);
1399             break;
1400         default:
1401             break;
1402     }
1403     return(0);
1404 }
1405
1406 /**
1407  * xmlFAReduceEpsilonTransitions:
1408  * @ctxt:  a regexp parser context
1409  * @fromnr:  the from state
1410  * @tonr:  the to state 
1411  * @cpunter:  should that transition be associted to a counted
1412  *
1413  */
1414 static void
1415 xmlFAReduceEpsilonTransitions(xmlRegParserCtxtPtr ctxt, int fromnr,
1416                               int tonr, int counter) {
1417     int transnr;
1418     xmlRegStatePtr from;
1419     xmlRegStatePtr to;
1420
1421 #ifdef DEBUG_REGEXP_GRAPH
1422     printf("xmlFAReduceEpsilonTransitions(%d, %d)\n", fromnr, tonr);
1423 #endif
1424     from = ctxt->states[fromnr];
1425     if (from == NULL)
1426         return;
1427     to = ctxt->states[tonr];
1428     if (to == NULL)
1429         return;
1430     if ((to->mark == XML_REGEXP_MARK_START) ||
1431         (to->mark == XML_REGEXP_MARK_VISITED))
1432         return;
1433
1434     to->mark = XML_REGEXP_MARK_VISITED;
1435     if (to->type == XML_REGEXP_FINAL_STATE) {
1436 #ifdef DEBUG_REGEXP_GRAPH
1437         printf("State %d is final, so %d becomes final\n", tonr, fromnr);
1438 #endif
1439         from->type = XML_REGEXP_FINAL_STATE;
1440     }
1441     for (transnr = 0;transnr < to->nbTrans;transnr++) {
1442         if (to->trans[transnr].atom == NULL) {
1443             /*
1444              * Don't remove counted transitions
1445              * Don't loop either
1446              */
1447             if (to->trans[transnr].to != fromnr) {
1448                 if (to->trans[transnr].count >= 0) {
1449                     int newto = to->trans[transnr].to;
1450
1451                     xmlRegStateAddTrans(ctxt, from, NULL,
1452                                         ctxt->states[newto], 
1453                                         -1, to->trans[transnr].count);
1454                 } else {
1455 #ifdef DEBUG_REGEXP_GRAPH
1456                     printf("Found epsilon trans %d from %d to %d\n",
1457                            transnr, tonr, to->trans[transnr].to);
1458 #endif
1459                     if (to->trans[transnr].counter >= 0) {
1460                         xmlFAReduceEpsilonTransitions(ctxt, fromnr,
1461                                               to->trans[transnr].to,
1462                                               to->trans[transnr].counter);
1463                     } else {
1464                         xmlFAReduceEpsilonTransitions(ctxt, fromnr,
1465                                               to->trans[transnr].to,
1466                                               counter);
1467                     }
1468                 }
1469             }
1470         } else {
1471             int newto = to->trans[transnr].to;
1472
1473             if (to->trans[transnr].counter >= 0) {
1474                 xmlRegStateAddTrans(ctxt, from, to->trans[transnr].atom, 
1475                                     ctxt->states[newto], 
1476                                     to->trans[transnr].counter, -1);
1477             } else {
1478                 xmlRegStateAddTrans(ctxt, from, to->trans[transnr].atom, 
1479                                     ctxt->states[newto], counter, -1);
1480             }
1481         }
1482     }
1483     to->mark = XML_REGEXP_MARK_NORMAL;
1484 }
1485
1486 /**
1487  * xmlFAEliminateEpsilonTransitions:
1488  * @ctxt:  a regexp parser context
1489  *
1490  */
1491 static void
1492 xmlFAEliminateEpsilonTransitions(xmlRegParserCtxtPtr ctxt) {
1493     int statenr, transnr;
1494     xmlRegStatePtr state;
1495
1496     if (ctxt->states == NULL) return;
1497
1498
1499     /*
1500      * build the completed transitions bypassing the epsilons
1501      * Use a marking algorithm to avoid loops
1502      */
1503     for (statenr = 0;statenr < ctxt->nbStates;statenr++) {
1504         state = ctxt->states[statenr];
1505         if (state == NULL)
1506             continue;
1507         for (transnr = 0;transnr < state->nbTrans;transnr++) {
1508             if ((state->trans[transnr].atom == NULL) &&
1509                 (state->trans[transnr].to >= 0)) {
1510                 if (state->trans[transnr].to == statenr) {
1511                     state->trans[transnr].to = -1;
1512 #ifdef DEBUG_REGEXP_GRAPH
1513                     printf("Removed loopback epsilon trans %d on %d\n",
1514                            transnr, statenr);
1515 #endif
1516                 } else if (state->trans[transnr].count < 0) {
1517                     int newto = state->trans[transnr].to;
1518
1519 #ifdef DEBUG_REGEXP_GRAPH
1520                     printf("Found epsilon trans %d from %d to %d\n",
1521                            transnr, statenr, newto);
1522 #endif
1523                     state->mark = XML_REGEXP_MARK_START;
1524                     xmlFAReduceEpsilonTransitions(ctxt, statenr,
1525                                       newto, state->trans[transnr].counter);
1526                     state->mark = XML_REGEXP_MARK_NORMAL;
1527 #ifdef DEBUG_REGEXP_GRAPH
1528                 } else {
1529                     printf("Found counted transition %d on %d\n",
1530                            transnr, statenr);
1531 #endif
1532                 }
1533             }
1534         }
1535     }
1536     /*
1537      * Eliminate the epsilon transitions
1538      */
1539     for (statenr = 0;statenr < ctxt->nbStates;statenr++) {
1540         state = ctxt->states[statenr];
1541         if (state == NULL)
1542             continue;
1543         for (transnr = 0;transnr < state->nbTrans;transnr++) {
1544             if ((state->trans[transnr].atom == NULL) &&
1545                 (state->trans[transnr].count < 0) &&
1546                 (state->trans[transnr].to >= 0)) {
1547                 state->trans[transnr].to = -1;
1548             }
1549         }
1550     }
1551
1552     /*
1553      * Use this pass to detect unreachable states too
1554      */
1555     for (statenr = 0;statenr < ctxt->nbStates;statenr++) {
1556         state = ctxt->states[statenr];
1557         if (state != NULL)
1558             state->reached = XML_REGEXP_MARK_NORMAL;
1559     }
1560     state = ctxt->states[0];
1561     if (state != NULL)
1562         state->reached = XML_REGEXP_MARK_START;
1563     while (state != NULL) {
1564         xmlRegStatePtr target = NULL;
1565         state->reached = XML_REGEXP_MARK_VISITED;
1566         /*
1567          * Mark all state reachable from the current reachable state
1568          */
1569         for (transnr = 0;transnr < state->nbTrans;transnr++) {
1570             if ((state->trans[transnr].to >= 0) &&
1571                 ((state->trans[transnr].atom != NULL) ||
1572                  (state->trans[transnr].count >= 0))) {
1573                 int newto = state->trans[transnr].to;
1574
1575                 if (ctxt->states[newto] == NULL)
1576                     continue;
1577                 if (ctxt->states[newto]->reached == XML_REGEXP_MARK_NORMAL) {
1578                     ctxt->states[newto]->reached = XML_REGEXP_MARK_START;
1579                     target = ctxt->states[newto];
1580                 }
1581             }
1582         }
1583         /*
1584          * find the next accessible state not explored
1585          */
1586         if (target == NULL) {
1587             for (statenr = 1;statenr < ctxt->nbStates;statenr++) {
1588                 state = ctxt->states[statenr];
1589                 if ((state != NULL) && (state->reached ==
1590                         XML_REGEXP_MARK_START)) {
1591                     target = state;
1592                     break;
1593                 }
1594             }
1595         }
1596         state = target;
1597     }
1598     for (statenr = 0;statenr < ctxt->nbStates;statenr++) {
1599         state = ctxt->states[statenr];
1600         if ((state != NULL) && (state->reached == XML_REGEXP_MARK_NORMAL)) {
1601 #ifdef DEBUG_REGEXP_GRAPH
1602             printf("Removed unreachable state %d\n", statenr);
1603 #endif
1604             xmlRegFreeState(state);
1605             ctxt->states[statenr] = NULL;
1606         }
1607     }
1608
1609 }
1610
1611 /**
1612  * xmlFACompareAtoms:
1613  * @atom1:  an atom
1614  * @atom2:  an atom
1615  *
1616  * Compares two atoms to check whether they are equivatents
1617  *
1618  * Returns 1 if yes and 0 otherwise
1619  */
1620 static int
1621 xmlFACompareAtoms(xmlRegAtomPtr atom1, xmlRegAtomPtr atom2) {
1622     if (atom1 == atom2)
1623         return(1);
1624     if ((atom1 == NULL) || (atom2 == NULL))
1625         return(0);
1626
1627     if (atom1->type != atom2->type)
1628         return(0);
1629     switch (atom1->type) {
1630         case XML_REGEXP_STRING:
1631             return(xmlStrEqual((xmlChar *)atom1->valuep,
1632                                (xmlChar *)atom2->valuep));
1633         case XML_REGEXP_EPSILON:
1634             return(1);
1635         case XML_REGEXP_CHARVAL:
1636             return(atom1->codepoint == atom2->codepoint);
1637         case XML_REGEXP_RANGES:
1638             TODO;
1639             return(0);
1640         default:
1641             break;
1642     }
1643     return(1);
1644 }
1645
1646 /**
1647  * xmlFARecurseDeterminism:
1648  * @ctxt:  a regexp parser context
1649  *
1650  * Check whether the associated regexp is determinist,
1651  * should be called after xmlFAEliminateEpsilonTransitions()
1652  *
1653  */
1654 static int
1655 xmlFARecurseDeterminism(xmlRegParserCtxtPtr ctxt, xmlRegStatePtr state,
1656                          int to, xmlRegAtomPtr atom) {
1657     int ret = 1;
1658     int transnr;
1659     xmlRegTransPtr t1;
1660
1661     if (state == NULL)
1662         return(ret);
1663     for (transnr = 0;transnr < state->nbTrans;transnr++) {
1664         t1 = &(state->trans[transnr]);
1665         /*
1666          * check transitions conflicting with the one looked at
1667          */
1668         if (t1->atom == NULL) {
1669             if (t1->to == -1)
1670                 continue;
1671             ret = xmlFARecurseDeterminism(ctxt, ctxt->states[t1->to],
1672                                            to, atom);
1673             if (ret == 0)
1674                 return(0);
1675             continue;
1676         }
1677         if (t1->to != to)
1678             continue;
1679         if (xmlFACompareAtoms(t1->atom, atom))
1680             return(0);
1681     }
1682     return(ret);
1683 }
1684
1685 /**
1686  * xmlFAComputesDeterminism:
1687  * @ctxt:  a regexp parser context
1688  *
1689  * Check whether the associated regexp is determinist,
1690  * should be called after xmlFAEliminateEpsilonTransitions()
1691  *
1692  */
1693 static int
1694 xmlFAComputesDeterminism(xmlRegParserCtxtPtr ctxt) {
1695     int statenr, transnr;
1696     xmlRegStatePtr state;
1697     xmlRegTransPtr t1, t2;
1698     int i;
1699     int ret = 1;
1700
1701 #ifdef DEBUG_REGEXP_GRAPH
1702     printf("xmlFAComputesDeterminism\n");
1703     xmlRegPrintCtxt(stdout, ctxt);
1704 #endif
1705     if (ctxt->determinist != -1)
1706         return(ctxt->determinist);
1707
1708     /*
1709      * Check for all states that there isn't 2 transitions
1710      * with the same atom and a different target.
1711      */
1712     for (statenr = 0;statenr < ctxt->nbStates;statenr++) {
1713         state = ctxt->states[statenr];
1714         if (state == NULL)
1715             continue;
1716         for (transnr = 0;transnr < state->nbTrans;transnr++) {
1717             t1 = &(state->trans[transnr]);
1718             /*
1719              * Determinism checks in case of counted or all transitions
1720              * will have to be handled separately
1721              */
1722             if (t1->atom == NULL)
1723                 continue;
1724             if (t1->to == -1) /* eliminated */
1725                 continue;
1726             for (i = 0;i < transnr;i++) {
1727                 t2 = &(state->trans[i]);
1728                 if (t2->to == -1) /* eliminated */
1729                     continue;
1730                 if (t2->atom != NULL) {
1731                     if (t1->to == t2->to) {
1732                         if (xmlFACompareAtoms(t1->atom, t2->atom))
1733                             t2->to = -1; /* eliminate */
1734                     } else {
1735                         /* not determinist ! */
1736                         if (xmlFACompareAtoms(t1->atom, t2->atom))
1737                             ret = 0;
1738                     }
1739                 } else if (t1->to != -1) {
1740                     /*
1741                      * do the closure in case of remaining specific
1742                      * epsilon transitions like choices or all
1743                      */
1744                     ret = xmlFARecurseDeterminism(ctxt, ctxt->states[t1->to],
1745                                                    t2->to, t2->atom);
1746                     if (ret == 0)
1747                         return(0);
1748                 }
1749             }
1750             if (ret == 0)
1751                 break;
1752         }
1753         if (ret == 0)
1754             break;
1755     }
1756     ctxt->determinist = ret;
1757     return(ret);
1758 }
1759
1760 /************************************************************************
1761  *                                                                      *
1762  *      Routines to check input against transition atoms                *
1763  *                                                                      *
1764  ************************************************************************/
1765
1766 static int
1767 xmlRegCheckCharacterRange(xmlRegAtomType type, int codepoint, int neg,
1768                           int start, int end, const xmlChar *blockName) {
1769     int ret = 0;
1770
1771     switch (type) {
1772         case XML_REGEXP_STRING:
1773         case XML_REGEXP_SUBREG:
1774         case XML_REGEXP_RANGES:
1775         case XML_REGEXP_EPSILON:
1776             return(-1);
1777         case XML_REGEXP_ANYCHAR:
1778             ret = ((codepoint != '\n') && (codepoint != '\r'));
1779             break;
1780         case XML_REGEXP_CHARVAL:
1781             ret = ((codepoint >= start) && (codepoint <= end));
1782             break;
1783         case XML_REGEXP_NOTSPACE:
1784             neg = !neg;
1785         case XML_REGEXP_ANYSPACE:
1786             ret = ((codepoint == '\n') || (codepoint == '\r') ||
1787                    (codepoint == '\t') || (codepoint == ' '));
1788             break;
1789         case XML_REGEXP_NOTINITNAME:
1790             neg = !neg;
1791         case XML_REGEXP_INITNAME:
1792             ret = (xmlIsLetter(codepoint) || 
1793                    (codepoint == '_') || (codepoint == ':'));
1794             break;
1795         case XML_REGEXP_NOTNAMECHAR:
1796             neg = !neg;
1797         case XML_REGEXP_NAMECHAR:
1798             ret = (xmlIsLetter(codepoint) || xmlIsDigit(codepoint) ||
1799                    (codepoint == '.') || (codepoint == '-') ||
1800                    (codepoint == '_') || (codepoint == ':') ||
1801                    xmlIsCombining(codepoint) || xmlIsExtender(codepoint));
1802             break;
1803         case XML_REGEXP_NOTDECIMAL:
1804             neg = !neg;
1805         case XML_REGEXP_DECIMAL:
1806             ret = xmlUCSIsCatNd(codepoint);
1807             break;
1808         case XML_REGEXP_REALCHAR:
1809             neg = !neg;
1810         case XML_REGEXP_NOTREALCHAR:
1811             ret = xmlUCSIsCatP(codepoint);
1812             if (ret == 0)
1813                 ret = xmlUCSIsCatZ(codepoint);
1814             if (ret == 0)
1815                 ret = xmlUCSIsCatC(codepoint);
1816             break;
1817         case XML_REGEXP_LETTER:
1818             ret = xmlUCSIsCatL(codepoint);
1819             break;
1820         case XML_REGEXP_LETTER_UPPERCASE:
1821             ret = xmlUCSIsCatLu(codepoint);
1822             break;
1823         case XML_REGEXP_LETTER_LOWERCASE:
1824             ret = xmlUCSIsCatLl(codepoint);
1825             break;
1826         case XML_REGEXP_LETTER_TITLECASE:
1827             ret = xmlUCSIsCatLt(codepoint);
1828             break;
1829         case XML_REGEXP_LETTER_MODIFIER:
1830             ret = xmlUCSIsCatLm(codepoint);
1831             break;
1832         case XML_REGEXP_LETTER_OTHERS:
1833             ret = xmlUCSIsCatLo(codepoint);
1834             break;
1835         case XML_REGEXP_MARK:
1836             ret = xmlUCSIsCatM(codepoint);
1837             break;
1838         case XML_REGEXP_MARK_NONSPACING:
1839             ret = xmlUCSIsCatMn(codepoint);
1840             break;
1841         case XML_REGEXP_MARK_SPACECOMBINING:
1842             ret = xmlUCSIsCatMc(codepoint);
1843             break;
1844         case XML_REGEXP_MARK_ENCLOSING:
1845             ret = xmlUCSIsCatMe(codepoint);
1846             break;
1847         case XML_REGEXP_NUMBER:
1848             ret = xmlUCSIsCatN(codepoint);
1849             break;
1850         case XML_REGEXP_NUMBER_DECIMAL:
1851             ret = xmlUCSIsCatNd(codepoint);
1852             break;
1853         case XML_REGEXP_NUMBER_LETTER:
1854             ret = xmlUCSIsCatNl(codepoint);
1855             break;
1856         case XML_REGEXP_NUMBER_OTHERS:
1857             ret = xmlUCSIsCatNo(codepoint);
1858             break;
1859         case XML_REGEXP_PUNCT:
1860             ret = xmlUCSIsCatP(codepoint);
1861             break;
1862         case XML_REGEXP_PUNCT_CONNECTOR:
1863             ret = xmlUCSIsCatPc(codepoint);
1864             break;
1865         case XML_REGEXP_PUNCT_DASH:
1866             ret = xmlUCSIsCatPd(codepoint);
1867             break;
1868         case XML_REGEXP_PUNCT_OPEN:
1869             ret = xmlUCSIsCatPs(codepoint);
1870             break;
1871         case XML_REGEXP_PUNCT_CLOSE:
1872             ret = xmlUCSIsCatPe(codepoint);
1873             break;
1874         case XML_REGEXP_PUNCT_INITQUOTE:
1875             ret = xmlUCSIsCatPi(codepoint);
1876             break;
1877         case XML_REGEXP_PUNCT_FINQUOTE:
1878             ret = xmlUCSIsCatPf(codepoint);
1879             break;
1880         case XML_REGEXP_PUNCT_OTHERS:
1881             ret = xmlUCSIsCatPo(codepoint);
1882             break;
1883         case XML_REGEXP_SEPAR:
1884             ret = xmlUCSIsCatZ(codepoint);
1885             break;
1886         case XML_REGEXP_SEPAR_SPACE:
1887             ret = xmlUCSIsCatZs(codepoint);
1888             break;
1889         case XML_REGEXP_SEPAR_LINE:
1890             ret = xmlUCSIsCatZl(codepoint);
1891             break;
1892         case XML_REGEXP_SEPAR_PARA:
1893             ret = xmlUCSIsCatZp(codepoint);
1894             break;
1895         case XML_REGEXP_SYMBOL:
1896             ret = xmlUCSIsCatS(codepoint);
1897             break;
1898         case XML_REGEXP_SYMBOL_MATH:
1899             ret = xmlUCSIsCatSm(codepoint);
1900             break;
1901         case XML_REGEXP_SYMBOL_CURRENCY:
1902             ret = xmlUCSIsCatSc(codepoint);
1903             break;
1904         case XML_REGEXP_SYMBOL_MODIFIER:
1905             ret = xmlUCSIsCatSk(codepoint);
1906             break;
1907         case XML_REGEXP_SYMBOL_OTHERS:
1908             ret = xmlUCSIsCatSo(codepoint);
1909             break;
1910         case XML_REGEXP_OTHER:
1911             ret = xmlUCSIsCatC(codepoint);
1912             break;
1913         case XML_REGEXP_OTHER_CONTROL:
1914             ret = xmlUCSIsCatCc(codepoint);
1915             break;
1916         case XML_REGEXP_OTHER_FORMAT:
1917             ret = xmlUCSIsCatCf(codepoint);
1918             break;
1919         case XML_REGEXP_OTHER_PRIVATE:
1920             ret = xmlUCSIsCatCo(codepoint);
1921             break;
1922         case XML_REGEXP_OTHER_NA:
1923             /* ret = xmlUCSIsCatCn(codepoint); */
1924             /* Seems it doesn't exist anymore in recent Unicode releases */
1925             ret = 0;
1926             break;
1927         case XML_REGEXP_BLOCK_NAME:
1928             ret = xmlUCSIsBlock(codepoint, (const char *) blockName);
1929             break;
1930     }
1931     if (neg)
1932         return(!ret);
1933     return(ret);
1934 }
1935
1936 static int
1937 xmlRegCheckCharacter(xmlRegAtomPtr atom, int codepoint) {
1938     int i, ret = 0;
1939     xmlRegRangePtr range;
1940
1941     if ((atom == NULL) || (!xmlIsChar(codepoint)))
1942         return(-1);
1943
1944     switch (atom->type) {
1945         case XML_REGEXP_SUBREG:
1946         case XML_REGEXP_EPSILON:
1947             return(-1);
1948         case XML_REGEXP_CHARVAL:
1949             return(codepoint == atom->codepoint);
1950         case XML_REGEXP_RANGES: {
1951             int accept = 0;
1952             for (i = 0;i < atom->nbRanges;i++) {
1953                 range = atom->ranges[i];
1954                 if (range->neg) {
1955                     ret = xmlRegCheckCharacterRange(range->type, codepoint,
1956                                                 0, range->start, range->end,
1957                                                 range->blockName);
1958                     if (ret != 0)
1959                         return(0); /* excluded char */
1960                 } else {
1961                     ret = xmlRegCheckCharacterRange(range->type, codepoint,
1962                                                 0, range->start, range->end,
1963                                                 range->blockName);
1964                     if (ret != 0)
1965                         accept = 1; /* might still be excluded */
1966                 }
1967             }
1968             return(accept);
1969         }
1970         case XML_REGEXP_STRING:
1971             printf("TODO: XML_REGEXP_STRING\n");
1972             return(-1);
1973         case XML_REGEXP_ANYCHAR:
1974         case XML_REGEXP_ANYSPACE:
1975         case XML_REGEXP_NOTSPACE:
1976         case XML_REGEXP_INITNAME:
1977         case XML_REGEXP_NOTINITNAME:
1978         case XML_REGEXP_NAMECHAR:
1979         case XML_REGEXP_NOTNAMECHAR:
1980         case XML_REGEXP_DECIMAL:
1981         case XML_REGEXP_NOTDECIMAL:
1982         case XML_REGEXP_REALCHAR:
1983         case XML_REGEXP_NOTREALCHAR:
1984         case XML_REGEXP_LETTER:
1985         case XML_REGEXP_LETTER_UPPERCASE:
1986         case XML_REGEXP_LETTER_LOWERCASE:
1987         case XML_REGEXP_LETTER_TITLECASE:
1988         case XML_REGEXP_LETTER_MODIFIER:
1989         case XML_REGEXP_LETTER_OTHERS:
1990         case XML_REGEXP_MARK:
1991         case XML_REGEXP_MARK_NONSPACING:
1992         case XML_REGEXP_MARK_SPACECOMBINING:
1993         case XML_REGEXP_MARK_ENCLOSING:
1994         case XML_REGEXP_NUMBER:
1995         case XML_REGEXP_NUMBER_DECIMAL:
1996         case XML_REGEXP_NUMBER_LETTER:
1997         case XML_REGEXP_NUMBER_OTHERS:
1998         case XML_REGEXP_PUNCT:
1999         case XML_REGEXP_PUNCT_CONNECTOR:
2000         case XML_REGEXP_PUNCT_DASH:
2001         case XML_REGEXP_PUNCT_OPEN:
2002         case XML_REGEXP_PUNCT_CLOSE:
2003         case XML_REGEXP_PUNCT_INITQUOTE:
2004         case XML_REGEXP_PUNCT_FINQUOTE:
2005         case XML_REGEXP_PUNCT_OTHERS:
2006         case XML_REGEXP_SEPAR:
2007         case XML_REGEXP_SEPAR_SPACE:
2008         case XML_REGEXP_SEPAR_LINE:
2009         case XML_REGEXP_SEPAR_PARA:
2010         case XML_REGEXP_SYMBOL:
2011         case XML_REGEXP_SYMBOL_MATH:
2012         case XML_REGEXP_SYMBOL_CURRENCY:
2013         case XML_REGEXP_SYMBOL_MODIFIER:
2014         case XML_REGEXP_SYMBOL_OTHERS:
2015         case XML_REGEXP_OTHER:
2016         case XML_REGEXP_OTHER_CONTROL:
2017         case XML_REGEXP_OTHER_FORMAT:
2018         case XML_REGEXP_OTHER_PRIVATE:
2019         case XML_REGEXP_OTHER_NA:
2020         case XML_REGEXP_BLOCK_NAME:
2021             ret = xmlRegCheckCharacterRange(atom->type, codepoint, 0, 0, 0,
2022                                             (const xmlChar *)atom->valuep);
2023             if (atom->neg)
2024                 ret = !ret;
2025             break;
2026     }
2027     return(ret);
2028 }
2029
2030 /************************************************************************
2031  *                                                                      *
2032  *      Saving an restoring state of an execution context               *
2033  *                                                                      *
2034  ************************************************************************/
2035
2036 #ifdef DEBUG_REGEXP_EXEC
2037 static void
2038 xmlFARegDebugExec(xmlRegExecCtxtPtr exec) {
2039     printf("state: %d:%d:idx %d", exec->state->no, exec->transno, exec->index);
2040     if (exec->inputStack != NULL) {
2041         int i;
2042         printf(": ");
2043         for (i = 0;(i < 3) && (i < exec->inputStackNr);i++)
2044             printf("%s ", exec->inputStack[exec->inputStackNr - (i + 1)]);
2045     } else {
2046         printf(": %s", &(exec->inputString[exec->index]));
2047     }
2048     printf("\n");
2049 }
2050 #endif
2051
2052 static void
2053 xmlFARegExecSave(xmlRegExecCtxtPtr exec) {
2054 #ifdef DEBUG_REGEXP_EXEC
2055     printf("saving ");
2056     exec->transno++;
2057     xmlFARegDebugExec(exec);
2058     exec->transno--;
2059 #endif
2060
2061     if (exec->maxRollbacks == 0) {
2062         exec->maxRollbacks = 4;
2063         exec->rollbacks = (xmlRegExecRollback *) xmlMalloc(exec->maxRollbacks *
2064                                              sizeof(xmlRegExecRollback));
2065         if (exec->rollbacks == NULL) {
2066             fprintf(stderr, "exec save: allocation failed");
2067             exec->maxRollbacks = 0;
2068             return;
2069         }
2070         memset(exec->rollbacks, 0,
2071                exec->maxRollbacks * sizeof(xmlRegExecRollback));
2072     } else if (exec->nbRollbacks >= exec->maxRollbacks) {
2073         xmlRegExecRollback *tmp;
2074         int len = exec->maxRollbacks;
2075
2076         exec->maxRollbacks *= 2;
2077         tmp = (xmlRegExecRollback *) xmlRealloc(exec->rollbacks,
2078                         exec->maxRollbacks * sizeof(xmlRegExecRollback));
2079         if (tmp == NULL) {
2080             fprintf(stderr, "exec save: allocation failed");
2081             exec->maxRollbacks /= 2;
2082             return;
2083         }
2084         exec->rollbacks = tmp;
2085         tmp = &exec->rollbacks[len];
2086         memset(tmp, 0, (exec->maxRollbacks - len) * sizeof(xmlRegExecRollback));
2087     }
2088     exec->rollbacks[exec->nbRollbacks].state = exec->state;
2089     exec->rollbacks[exec->nbRollbacks].index = exec->index;
2090     exec->rollbacks[exec->nbRollbacks].nextbranch = exec->transno + 1;
2091     if (exec->comp->nbCounters > 0) {
2092         if (exec->rollbacks[exec->nbRollbacks].counts == NULL) {
2093             exec->rollbacks[exec->nbRollbacks].counts = (int *)
2094                 xmlMalloc(exec->comp->nbCounters * sizeof(int));
2095             if (exec->rollbacks[exec->nbRollbacks].counts == NULL) {
2096                 fprintf(stderr, "exec save: allocation failed");
2097                 exec->status = -5;
2098                 return;
2099             }
2100         }
2101         memcpy(exec->rollbacks[exec->nbRollbacks].counts, exec->counts,
2102                exec->comp->nbCounters * sizeof(int));
2103     }
2104     exec->nbRollbacks++;
2105 }
2106
2107 static void
2108 xmlFARegExecRollBack(xmlRegExecCtxtPtr exec) {
2109     if (exec->nbRollbacks <= 0) {
2110         exec->status = -1;
2111 #ifdef DEBUG_REGEXP_EXEC
2112         printf("rollback failed on empty stack\n");
2113 #endif
2114         return;
2115     }
2116     exec->nbRollbacks--;
2117     exec->state = exec->rollbacks[exec->nbRollbacks].state;
2118     exec->index = exec->rollbacks[exec->nbRollbacks].index;
2119     exec->transno = exec->rollbacks[exec->nbRollbacks].nextbranch;
2120     if (exec->comp->nbCounters > 0) {
2121         if (exec->rollbacks[exec->nbRollbacks].counts == NULL) {
2122             fprintf(stderr, "exec save: allocation failed");
2123             exec->status = -6;
2124             return;
2125         }
2126         memcpy(exec->counts, exec->rollbacks[exec->nbRollbacks].counts,
2127                exec->comp->nbCounters * sizeof(int));
2128     }
2129
2130 #ifdef DEBUG_REGEXP_EXEC
2131     printf("restored ");
2132     xmlFARegDebugExec(exec);
2133 #endif
2134 }
2135
2136 /************************************************************************
2137  *                                                                      *
2138  *      Verifyer, running an input against a compiled regexp            *
2139  *                                                                      *
2140  ************************************************************************/
2141
2142 static int
2143 xmlFARegExec(xmlRegexpPtr comp, const xmlChar *content) {
2144     xmlRegExecCtxt execval;
2145     xmlRegExecCtxtPtr exec = &execval;
2146     int ret, codepoint, len;
2147
2148     exec->inputString = content;
2149     exec->index = 0;
2150     exec->determinist = 1;
2151     exec->maxRollbacks = 0;
2152     exec->nbRollbacks = 0;
2153     exec->rollbacks = NULL;
2154     exec->status = 0;
2155     exec->comp = comp;
2156     exec->state = comp->states[0];
2157     exec->transno = 0;
2158     exec->transcount = 0;
2159     if (comp->nbCounters > 0) {
2160         exec->counts = (int *) xmlMalloc(comp->nbCounters * sizeof(int));
2161         if (exec->counts == NULL)
2162             return(-1);
2163         memset(exec->counts, 0, comp->nbCounters * sizeof(int));
2164     } else
2165         exec->counts = NULL;
2166     while ((exec->status == 0) &&
2167            ((exec->inputString[exec->index] != 0) ||
2168             (exec->state->type != XML_REGEXP_FINAL_STATE))) {
2169         xmlRegTransPtr trans;
2170         xmlRegAtomPtr atom;
2171
2172         /*
2173          * End of input on non-terminal state, rollback, however we may
2174          * still have epsilon like transition for counted transitions
2175          * on counters, in that case don't break too early.
2176          */
2177         if ((exec->inputString[exec->index] == 0) && (exec->counts == NULL))
2178             goto rollback;
2179
2180         exec->transcount = 0;
2181         for (;exec->transno < exec->state->nbTrans;exec->transno++) {
2182             trans = &exec->state->trans[exec->transno];
2183             if (trans->to < 0)
2184                 continue;
2185             atom = trans->atom;
2186             ret = 0;
2187             if (trans->count >= 0) {
2188                 int count;
2189                 xmlRegCounterPtr counter;
2190
2191                 /*
2192                  * A counted transition.
2193                  */
2194
2195                 count = exec->counts[trans->count];
2196                 counter = &exec->comp->counters[trans->count];
2197 #ifdef DEBUG_REGEXP_EXEC
2198                 printf("testing count %d: val %d, min %d, max %d\n",
2199                        trans->count, count, counter->min,  counter->max);
2200 #endif
2201                 ret = ((count >= counter->min) && (count <= counter->max));
2202             } else if (atom == NULL) {
2203                 fprintf(stderr, "epsilon transition left at runtime\n");
2204                 exec->status = -2;
2205                 break;
2206             } else if (exec->inputString[exec->index] != 0) {
2207                 codepoint = CUR_SCHAR(&(exec->inputString[exec->index]), len);
2208                 ret = xmlRegCheckCharacter(atom, codepoint);
2209                 if ((ret == 1) && (atom->min > 0) && (atom->max > 0)) {
2210                     xmlRegStatePtr to = comp->states[trans->to];
2211
2212                     /*
2213                      * this is a multiple input sequence
2214                      */
2215                     if (exec->state->nbTrans > exec->transno + 1) {
2216                         xmlFARegExecSave(exec);
2217                     }
2218                     exec->transcount = 1;
2219                     do {
2220                         /*
2221                          * Try to progress as much as possible on the input
2222                          */
2223                         if (exec->transcount == atom->max) {
2224                             break;
2225                         }
2226                         exec->index += len;
2227                         /*
2228                          * End of input: stop here
2229                          */
2230                         if (exec->inputString[exec->index] == 0) {
2231                             exec->index -= len;
2232                             break;
2233                         }
2234                         if (exec->transcount >= atom->min) {
2235                             int transno = exec->transno;
2236                             xmlRegStatePtr state = exec->state;
2237
2238                             /*
2239                              * The transition is acceptable save it
2240                              */
2241                             exec->transno = -1; /* trick */
2242                             exec->state = to;
2243                             xmlFARegExecSave(exec);
2244                             exec->transno = transno;
2245                             exec->state = state;
2246                         }
2247                         codepoint = CUR_SCHAR(&(exec->inputString[exec->index]),
2248                                               len);
2249                         ret = xmlRegCheckCharacter(atom, codepoint);
2250                         exec->transcount++;
2251                     } while (ret == 1);
2252                     if (exec->transcount < atom->min)
2253                         ret = 0;
2254
2255                     /*
2256                      * If the last check failed but one transition was found
2257                      * possible, rollback
2258                      */
2259                     if (ret < 0)
2260                         ret = 0;
2261                     if (ret == 0) {
2262                         goto rollback;
2263                     }
2264                 }
2265             }
2266             if (ret == 1) {
2267                 if (exec->state->nbTrans > exec->transno + 1) {
2268                     xmlFARegExecSave(exec);
2269                 }
2270                 if (trans->counter >= 0) {
2271 #ifdef DEBUG_REGEXP_EXEC
2272                     printf("Increasing count %d\n", trans->counter);
2273 #endif
2274                     exec->counts[trans->counter]++;
2275                 }
2276 #ifdef DEBUG_REGEXP_EXEC
2277                 printf("entering state %d\n", trans->to);
2278 #endif
2279                 exec->state = comp->states[trans->to];
2280                 exec->transno = 0;
2281                 if (trans->atom != NULL) {
2282                     exec->index += len;
2283                 }
2284                 goto progress;
2285             } else if (ret < 0) {
2286                 exec->status = -4;
2287                 break;
2288             }
2289         }
2290         if ((exec->transno != 0) || (exec->state->nbTrans == 0)) {
2291 rollback:
2292             /*
2293              * Failed to find a way out
2294              */
2295             exec->determinist = 0;
2296             xmlFARegExecRollBack(exec);
2297         }
2298 progress:
2299         continue;
2300     }
2301     if (exec->rollbacks != NULL) {
2302         if (exec->counts != NULL) {
2303             int i;
2304
2305             for (i = 0;i < exec->maxRollbacks;i++)
2306                 if (exec->rollbacks[i].counts != NULL)
2307                     xmlFree(exec->rollbacks[i].counts);
2308         }
2309         xmlFree(exec->rollbacks);
2310     }
2311     if (exec->counts != NULL)
2312         xmlFree(exec->counts);
2313     if (exec->status == 0)
2314         return(1);
2315     if (exec->status == -1)
2316         return(0);
2317     return(exec->status);
2318 }
2319
2320 /************************************************************************
2321  *                                                                      *
2322  *      Progressive interface to the verifyer one atom at a time        *
2323  *                                                                      *
2324  ************************************************************************/
2325
2326 /**
2327  * xmlRegNewExecCtxt:
2328  * @comp: a precompiled regular expression
2329  * @callback: a callback function used for handling progresses in the
2330  *            automata matching phase
2331  * @data: the context data associated to the callback in this context
2332  *
2333  * Build a context used for progressive evaluation of a regexp.
2334  *
2335  * Returns the new context
2336  */
2337 xmlRegExecCtxtPtr
2338 xmlRegNewExecCtxt(xmlRegexpPtr comp, xmlRegExecCallbacks callback, void *data) {
2339     xmlRegExecCtxtPtr exec;
2340
2341     if (comp == NULL)
2342         return(NULL);
2343     if ((comp->compact == NULL) && (comp->states == NULL))
2344         return(NULL);
2345     exec = (xmlRegExecCtxtPtr) xmlMalloc(sizeof(xmlRegExecCtxt));
2346     if (exec == NULL) {
2347         return(NULL);
2348     }
2349     memset(exec, 0, sizeof(xmlRegExecCtxt));
2350     exec->inputString = NULL;
2351     exec->index = 0;
2352     exec->determinist = 1;
2353     exec->maxRollbacks = 0;
2354     exec->nbRollbacks = 0;
2355     exec->rollbacks = NULL;
2356     exec->status = 0;
2357     exec->comp = comp;
2358     if (comp->compact == NULL)
2359         exec->state = comp->states[0];
2360     exec->transno = 0;
2361     exec->transcount = 0;
2362     exec->callback = callback;
2363     exec->data = data;
2364     if (comp->nbCounters > 0) {
2365         exec->counts = (int *) xmlMalloc(comp->nbCounters * sizeof(int));
2366         if (exec->counts == NULL) {
2367             xmlFree(exec);
2368             return(NULL);
2369         }
2370         memset(exec->counts, 0, comp->nbCounters * sizeof(int));
2371     } else
2372         exec->counts = NULL;
2373     exec->inputStackMax = 0;
2374     exec->inputStackNr = 0;
2375     exec->inputStack = NULL;
2376     return(exec);
2377 }
2378
2379 /**
2380  * xmlRegFreeExecCtxt:
2381  * @exec: a regular expression evaulation context
2382  *
2383  * Free the structures associated to a regular expression evaulation context.
2384  */
2385 void
2386 xmlRegFreeExecCtxt(xmlRegExecCtxtPtr exec) {
2387     if (exec == NULL)
2388         return;
2389
2390     if (exec->rollbacks != NULL) {
2391         if (exec->counts != NULL) {
2392             int i;
2393
2394             for (i = 0;i < exec->maxRollbacks;i++)
2395                 if (exec->rollbacks[i].counts != NULL)
2396                     xmlFree(exec->rollbacks[i].counts);
2397         }
2398         xmlFree(exec->rollbacks);
2399     }
2400     if (exec->counts != NULL)
2401         xmlFree(exec->counts);
2402     if (exec->inputStack != NULL) {
2403         int i;
2404
2405         for (i = 0;i < exec->inputStackNr;i++) {
2406             if (exec->inputStack[i].value != NULL)
2407                 xmlFree(exec->inputStack[i].value);
2408         }
2409         xmlFree(exec->inputStack);
2410     }
2411     xmlFree(exec);
2412 }
2413
2414 static void
2415 xmlFARegExecSaveInputString(xmlRegExecCtxtPtr exec, const xmlChar *value,
2416                             void *data) {
2417 #ifdef DEBUG_PUSH
2418     printf("saving value: %d:%s\n", exec->inputStackNr, value);
2419 #endif
2420     if (exec->inputStackMax == 0) {
2421         exec->inputStackMax = 4;
2422         exec->inputStack = (xmlRegInputTokenPtr) 
2423             xmlMalloc(exec->inputStackMax * sizeof(xmlRegInputToken));
2424         if (exec->inputStack == NULL) {
2425             fprintf(stderr, "push input: allocation failed");
2426             exec->inputStackMax = 0;
2427             return;
2428         }
2429     } else if (exec->inputStackNr + 1 >= exec->inputStackMax) {
2430         xmlRegInputTokenPtr tmp;
2431
2432         exec->inputStackMax *= 2;
2433         tmp = (xmlRegInputTokenPtr) xmlRealloc(exec->inputStack,
2434                         exec->inputStackMax * sizeof(xmlRegInputToken));
2435         if (tmp == NULL) {
2436             fprintf(stderr, "push input: allocation failed");
2437             exec->inputStackMax /= 2;
2438             return;
2439         }
2440         exec->inputStack = tmp;
2441     }
2442     exec->inputStack[exec->inputStackNr].value = xmlStrdup(value);
2443     exec->inputStack[exec->inputStackNr].data = data;
2444     exec->inputStackNr++;
2445     exec->inputStack[exec->inputStackNr].value = NULL;
2446     exec->inputStack[exec->inputStackNr].data = NULL;
2447 }
2448
2449
2450 /**
2451  * xmlRegCompactPushString:
2452  * @exec: a regexp execution context
2453  * @comp:  the precompiled exec with a compact table
2454  * @value: a string token input
2455  * @data: data associated to the token to reuse in callbacks
2456  *
2457  * Push one input token in the execution context
2458  *
2459  * Returns: 1 if the regexp reached a final state, 0 if non-final, and
2460  *     a negative value in case of error.
2461  */
2462 static int
2463 xmlRegCompactPushString(xmlRegExecCtxtPtr exec,
2464                         xmlRegexpPtr comp,
2465                         const xmlChar *value,
2466                         void *data) {
2467     int state = exec->index;
2468     int i, target;
2469
2470     if ((comp == NULL) || (comp->compact == NULL) || (comp->stringMap == NULL))
2471         return(-1);
2472     
2473     if (value == NULL) {
2474         /*
2475          * are we at a final state ?
2476          */
2477         if (comp->compact[state * (comp->nbstrings + 1)] ==
2478             XML_REGEXP_FINAL_STATE)
2479             return(1);
2480         return(0);
2481     }
2482
2483 #ifdef DEBUG_PUSH
2484     printf("value pushed: %s\n", value);
2485 #endif
2486
2487     /*
2488      * Examine all outside transition from current state
2489      */
2490     for (i = 0;i < comp->nbstrings;i++) {
2491         target = comp->compact[state * (comp->nbstrings + 1) + i + 1];
2492         if ((target > 0) && (target <= comp->nbstates)) {
2493             target--; /* to avoid 0 */
2494             if (xmlStrEqual(comp->stringMap[i], value)) {
2495                 exec->index = target;
2496                 if ((exec->callback != NULL) && (comp->transdata != NULL)) {
2497                     exec->callback(exec->data, value,
2498                           comp->transdata[state * comp->nbstrings + i], data);
2499                 }
2500 #ifdef DEBUG_PUSH
2501                 printf("entering state %d\n", target);
2502 #endif
2503                 if (comp->compact[target * (comp->nbstrings + 1)] ==
2504                     XML_REGEXP_FINAL_STATE)
2505                     return(1);
2506                 return(0);
2507             }
2508         }
2509     }
2510     /*
2511      * Failed to find an exit transition out from current state for the
2512      * current token
2513      */
2514 #ifdef DEBUG_PUSH
2515     printf("failed to find a transition for %s on state %d\n", value, state);
2516 #endif
2517     exec->status = -1;
2518     return(-1);
2519 }
2520
2521 /**
2522  * xmlRegExecPushString:
2523  * @exec: a regexp execution context or NULL to indicate the end
2524  * @value: a string token input
2525  * @data: data associated to the token to reuse in callbacks
2526  *
2527  * Push one input token in the execution context
2528  *
2529  * Returns: 1 if the regexp reached a final state, 0 if non-final, and
2530  *     a negative value in case of error.
2531  */
2532 int
2533 xmlRegExecPushString(xmlRegExecCtxtPtr exec, const xmlChar *value,
2534                      void *data) {
2535     xmlRegTransPtr trans;
2536     xmlRegAtomPtr atom;
2537     int ret;
2538     int final = 0;
2539
2540     if (exec == NULL)
2541         return(-1);
2542     if (exec->comp == NULL)
2543         return(-1);
2544     if (exec->status != 0)
2545         return(exec->status);
2546
2547     if (exec->comp->compact != NULL)
2548         return(xmlRegCompactPushString(exec, exec->comp, value, data));
2549
2550     if (value == NULL) {
2551         if (exec->state->type == XML_REGEXP_FINAL_STATE)
2552             return(1);
2553         final = 1;
2554     }
2555
2556 #ifdef DEBUG_PUSH
2557     printf("value pushed: %s\n", value);
2558 #endif
2559     /*
2560      * If we have an active rollback stack push the new value there
2561      * and get back to where we were left
2562      */
2563     if ((value != NULL) && (exec->inputStackNr > 0)) {
2564         xmlFARegExecSaveInputString(exec, value, data);
2565         value = exec->inputStack[exec->index].value;
2566         data = exec->inputStack[exec->index].data;
2567 #ifdef DEBUG_PUSH
2568         printf("value loaded: %s\n", value);
2569 #endif
2570     }
2571
2572     while ((exec->status == 0) &&
2573            ((value != NULL) ||
2574             ((final == 1) &&
2575              (exec->state->type != XML_REGEXP_FINAL_STATE)))) {
2576
2577         /*
2578          * End of input on non-terminal state, rollback, however we may
2579          * still have epsilon like transition for counted transitions
2580          * on counters, in that case don't break too early.
2581          */
2582         if ((value == NULL) && (exec->counts == NULL))
2583             goto rollback;
2584
2585         exec->transcount = 0;
2586         for (;exec->transno < exec->state->nbTrans;exec->transno++) {
2587             trans = &exec->state->trans[exec->transno];
2588             if (trans->to < 0)
2589                 continue;
2590             atom = trans->atom;
2591             ret = 0;
2592             if (trans->count == REGEXP_ALL_LAX_COUNTER) {
2593                 int i;
2594                 int count;
2595                 xmlRegTransPtr t;
2596                 xmlRegCounterPtr counter;
2597
2598                 ret = 0;
2599
2600 #ifdef DEBUG_PUSH
2601                 printf("testing all lax %d\n", trans->count);
2602 #endif
2603                 /*
2604                  * Check all counted transitions from the current state
2605                  */
2606                 if ((value == NULL) && (final)) {
2607                     ret = 1;
2608                 } else if (value != NULL) {
2609                     for (i = 0;i < exec->state->nbTrans;i++) {
2610                         t = &exec->state->trans[i];
2611                         if ((t->counter < 0) || (t == trans))
2612                             continue;
2613                         counter = &exec->comp->counters[t->counter];
2614                         count = exec->counts[t->counter];
2615                         if ((count < counter->max) && 
2616                             (t->atom != NULL) &&
2617                             (xmlStrEqual(value, t->atom->valuep))) {
2618                             ret = 0;
2619                             break;
2620                         }
2621                         if ((count >= counter->min) &&
2622                             (count < counter->max) &&
2623                             (xmlStrEqual(value, t->atom->valuep))) {
2624                             ret = 1;
2625                             break;
2626                         }
2627                     }
2628                 }
2629             } else if (trans->count == REGEXP_ALL_COUNTER) {
2630                 int i;
2631                 int count;
2632                 xmlRegTransPtr t;
2633                 xmlRegCounterPtr counter;
2634
2635                 ret = 1;
2636
2637 #ifdef DEBUG_PUSH
2638                 printf("testing all %d\n", trans->count);
2639 #endif
2640                 /*
2641                  * Check all counted transitions from the current state
2642                  */
2643                 for (i = 0;i < exec->state->nbTrans;i++) {
2644                     t = &exec->state->trans[i];
2645                     if ((t->counter < 0) || (t == trans))
2646                         continue;
2647                     counter = &exec->comp->counters[t->counter];
2648                     count = exec->counts[t->counter];
2649                     if ((count < counter->min) || (count > counter->max)) {
2650                         ret = 0;
2651                         break;
2652                     }
2653                 }
2654             } else if (trans->count >= 0) {
2655                 int count;
2656                 xmlRegCounterPtr counter;
2657
2658                 /*
2659                  * A counted transition.
2660                  */
2661
2662                 count = exec->counts[trans->count];
2663                 counter = &exec->comp->counters[trans->count];
2664 #ifdef DEBUG_PUSH
2665                 printf("testing count %d: val %d, min %d, max %d\n",
2666                        trans->count, count, counter->min,  counter->max);
2667 #endif
2668                 ret = ((count >= counter->min) && (count <= counter->max));
2669             } else if (atom == NULL) {
2670                 fprintf(stderr, "epsilon transition left at runtime\n");
2671                 exec->status = -2;
2672                 break;
2673             } else if (value != NULL) {
2674                 ret = xmlStrEqual(value, atom->valuep);
2675                 if ((ret == 1) && (trans->counter >= 0)) {
2676                     xmlRegCounterPtr counter;
2677                     int count;
2678
2679                     count = exec->counts[trans->counter];
2680                     counter = &exec->comp->counters[trans->counter];
2681                     if (count >= counter->max)
2682                         ret = 0;
2683                 }
2684
2685                 if ((ret == 1) && (atom->min > 0) && (atom->max > 0)) {
2686                     xmlRegStatePtr to = exec->comp->states[trans->to];
2687
2688                     /*
2689                      * this is a multiple input sequence
2690                      */
2691                     if (exec->state->nbTrans > exec->transno + 1) {
2692                         if (exec->inputStackNr <= 0) {
2693                             xmlFARegExecSaveInputString(exec, value, data);
2694                         }
2695                         xmlFARegExecSave(exec);
2696                     }
2697                     exec->transcount = 1;
2698                     do {
2699                         /*
2700                          * Try to progress as much as possible on the input
2701                          */
2702                         if (exec->transcount == atom->max) {
2703                             break;
2704                         }
2705                         exec->index++;
2706                         value = exec->inputStack[exec->index].value;
2707                         data = exec->inputStack[exec->index].data;
2708 #ifdef DEBUG_PUSH
2709                         printf("value loaded: %s\n", value);
2710 #endif
2711
2712                         /*
2713                          * End of input: stop here
2714                          */
2715                         if (value == NULL) {
2716                             exec->index --;
2717                             break;
2718                         }
2719                         if (exec->transcount >= atom->min) {
2720                             int transno = exec->transno;
2721                             xmlRegStatePtr state = exec->state;
2722
2723                             /*
2724                              * The transition is acceptable save it
2725                              */
2726                             exec->transno = -1; /* trick */
2727                             exec->state = to;
2728                             if (exec->inputStackNr <= 0) {
2729                                 xmlFARegExecSaveInputString(exec, value, data);
2730                             }
2731                             xmlFARegExecSave(exec);
2732                             exec->transno = transno;
2733                             exec->state = state;
2734                         }
2735                         ret = xmlStrEqual(value, atom->valuep);
2736                         exec->transcount++;
2737                     } while (ret == 1);
2738                     if (exec->transcount < atom->min)
2739                         ret = 0;
2740
2741                     /*
2742                      * If the last check failed but one transition was found
2743                      * possible, rollback
2744                      */
2745                     if (ret < 0)
2746                         ret = 0;
2747                     if (ret == 0) {
2748                         goto rollback;
2749                     }
2750                 }
2751             }
2752             if (ret == 1) {
2753                 if ((exec->callback != NULL) && (atom != NULL)) {
2754                     exec->callback(exec->data, atom->valuep,
2755                                    atom->data, data);
2756                 }
2757                 if (exec->state->nbTrans > exec->transno + 1) {
2758                     if (exec->inputStackNr <= 0) {
2759                         xmlFARegExecSaveInputString(exec, value, data);
2760                     }
2761                     xmlFARegExecSave(exec);
2762                 }
2763                 if (trans->counter >= 0) {
2764 #ifdef DEBUG_PUSH
2765                     printf("Increasing count %d\n", trans->counter);
2766 #endif
2767                     exec->counts[trans->counter]++;
2768                 }
2769 #ifdef DEBUG_PUSH
2770                 printf("entering state %d\n", trans->to);
2771 #endif
2772                 exec->state = exec->comp->states[trans->to];
2773                 exec->transno = 0;
2774                 if (trans->atom != NULL) {
2775                     if (exec->inputStack != NULL) {
2776                         exec->index++;
2777                         if (exec->index < exec->inputStackNr) {
2778                             value = exec->inputStack[exec->index].value;
2779                             data = exec->inputStack[exec->index].data;
2780 #ifdef DEBUG_PUSH
2781                             printf("value loaded: %s\n", value);
2782 #endif
2783                         } else {
2784                             value = NULL;
2785                             data = NULL;
2786 #ifdef DEBUG_PUSH
2787                             printf("end of input\n");
2788 #endif
2789                         }
2790                     } else {
2791                         value = NULL;
2792                         data = NULL;
2793 #ifdef DEBUG_PUSH
2794                         printf("end of input\n");
2795 #endif
2796                     }
2797                 }
2798                 goto progress;
2799             } else if (ret < 0) {
2800                 exec->status = -4;
2801                 break;
2802             }
2803         }
2804         if ((exec->transno != 0) || (exec->state->nbTrans == 0)) {
2805 rollback:
2806             /*
2807              * Failed to find a way out
2808              */
2809             exec->determinist = 0;
2810             xmlFARegExecRollBack(exec);
2811             if (exec->status == 0) {
2812                 value = exec->inputStack[exec->index].value;
2813                 data = exec->inputStack[exec->index].data;
2814 #ifdef DEBUG_PUSH
2815                 printf("value loaded: %s\n", value);
2816 #endif
2817             }
2818         }
2819 progress:
2820         continue;
2821     }
2822     if (exec->status == 0) {
2823         return(exec->state->type == XML_REGEXP_FINAL_STATE);
2824     }
2825     return(exec->status);
2826 }
2827
2828 /**
2829  * xmlRegExecPushString2:
2830  * @exec: a regexp execution context or NULL to indicate the end
2831  * @value: the first string token input
2832  * @value2: the second string token input
2833  * @data: data associated to the token to reuse in callbacks
2834  *
2835  * Push one input token in the execution context
2836  *
2837  * Returns: 1 if the regexp reached a final state, 0 if non-final, and
2838  *     a negative value in case of error.
2839  */
2840 int
2841 xmlRegExecPushString2(xmlRegExecCtxtPtr exec, const xmlChar *value,
2842                       const xmlChar *value2, void *data) {
2843     xmlChar buf[150];
2844     int lenn, lenp, ret;
2845     xmlChar *str;
2846
2847     if (exec == NULL)
2848         return(-1);
2849     if (exec->comp == NULL)
2850         return(-1);
2851     if (exec->status != 0)
2852         return(exec->status);
2853
2854     if (value2 == NULL)
2855         return(xmlRegExecPushString(exec, value, data));
2856
2857     lenn = strlen((char *) value2);
2858     lenp = strlen((char *) value);
2859
2860     if (150 < lenn + lenp + 2) {
2861         str = (xmlChar *) xmlMallocAtomic(lenn + lenp + 2);
2862         if (str == NULL) {
2863             exec->status = -1;
2864             return(-1);
2865         }
2866     } else {
2867         str = buf;
2868     }
2869     memcpy(&str[0], value, lenp);
2870     str[lenp] = '|';
2871     memcpy(&str[lenp + 1], value2, lenn);
2872     str[lenn + lenp + 1] = 0;
2873
2874     if (exec->comp->compact != NULL)
2875         ret = xmlRegCompactPushString(exec, exec->comp, str, data);
2876     else
2877         ret = xmlRegExecPushString(exec, str, data);
2878
2879     if (str != buf)
2880         xmlFree(buf);
2881     return(ret);
2882 }
2883
2884 #if 0
2885 static int
2886 xmlRegExecPushChar(xmlRegExecCtxtPtr exec, int UCS) {
2887     xmlRegTransPtr trans;
2888     xmlRegAtomPtr atom;
2889     int ret;
2890     int codepoint, len;
2891
2892     if (exec == NULL)
2893         return(-1);
2894     if (exec->status != 0)
2895         return(exec->status);
2896
2897     while ((exec->status == 0) &&
2898            ((exec->inputString[exec->index] != 0) ||
2899             (exec->state->type != XML_REGEXP_FINAL_STATE))) {
2900
2901         /*
2902          * End of input on non-terminal state, rollback, however we may
2903          * still have epsilon like transition for counted transitions
2904          * on counters, in that case don't break too early.
2905          */
2906         if ((exec->inputString[exec->index] == 0) && (exec->counts == NULL))
2907             goto rollback;
2908
2909         exec->transcount = 0;
2910         for (;exec->transno < exec->state->nbTrans;exec->transno++) {
2911             trans = &exec->state->trans[exec->transno];
2912             if (trans->to < 0)
2913                 continue;
2914             atom = trans->atom;
2915             ret = 0;
2916             if (trans->count >= 0) {
2917                 int count;
2918                 xmlRegCounterPtr counter;
2919
2920                 /*
2921                  * A counted transition.
2922                  */
2923
2924                 count = exec->counts[trans->count];
2925                 counter = &exec->comp->counters[trans->count];
2926 #ifdef DEBUG_REGEXP_EXEC
2927                 printf("testing count %d: val %d, min %d, max %d\n",
2928                        trans->count, count, counter->min,  counter->max);
2929 #endif
2930                 ret = ((count >= counter->min) && (count <= counter->max));
2931             } else if (atom == NULL) {
2932                 fprintf(stderr, "epsilon transition left at runtime\n");
2933                 exec->status = -2;
2934                 break;
2935             } else if (exec->inputString[exec->index] != 0) {
2936                 codepoint = CUR_SCHAR(&(exec->inputString[exec->index]), len);
2937                 ret = xmlRegCheckCharacter(atom, codepoint);
2938                 if ((ret == 1) && (atom->min > 0) && (atom->max > 0)) {
2939                     xmlRegStatePtr to = exec->comp->states[trans->to];
2940
2941                     /*
2942                      * this is a multiple input sequence
2943                      */
2944                     if (exec->state->nbTrans > exec->transno + 1) {
2945                         xmlFARegExecSave(exec);
2946                     }
2947                     exec->transcount = 1;
2948                     do {
2949                         /*
2950                          * Try to progress as much as possible on the input
2951                          */
2952                         if (exec->transcount == atom->max) {
2953                             break;
2954                         }
2955                         exec->index += len;
2956                         /*
2957                          * End of input: stop here
2958                          */
2959                         if (exec->inputString[exec->index] == 0) {
2960                             exec->index -= len;
2961                             break;
2962                         }
2963                         if (exec->transcount >= atom->min) {
2964                             int transno = exec->transno;
2965                             xmlRegStatePtr state = exec->state;
2966
2967                             /*
2968                              * The transition is acceptable save it
2969                              */
2970                             exec->transno = -1; /* trick */
2971                             exec->state = to;
2972                             xmlFARegExecSave(exec);
2973                             exec->transno = transno;
2974                             exec->state = state;
2975                         }
2976                         codepoint = CUR_SCHAR(&(exec->inputString[exec->index]),
2977                                               len);
2978                         ret = xmlRegCheckCharacter(atom, codepoint);
2979                         exec->transcount++;
2980                     } while (ret == 1);
2981                     if (exec->transcount < atom->min)
2982                         ret = 0;
2983
2984                     /*
2985                      * If the last check failed but one transition was found
2986                      * possible, rollback
2987                      */
2988                     if (ret < 0)
2989                         ret = 0;
2990                     if (ret == 0) {
2991                         goto rollback;
2992                     }
2993                 }
2994             }
2995             if (ret == 1) {
2996                 if (exec->state->nbTrans > exec->transno + 1) {
2997                     xmlFARegExecSave(exec);
2998                 }
2999                 if (trans->counter >= 0) {
3000 #ifdef DEBUG_REGEXP_EXEC
3001                     printf("Increasing count %d\n", trans->counter);
3002 #endif
3003                     exec->counts[trans->counter]++;
3004                 }
3005 #ifdef DEBUG_REGEXP_EXEC
3006                 printf("entering state %d\n", trans->to);
3007 #endif
3008                 exec->state = exec->comp->states[trans->to];
3009                 exec->transno = 0;
3010                 if (trans->atom != NULL) {
3011                     exec->index += len;
3012                 }
3013                 goto progress;
3014             } else if (ret < 0) {
3015                 exec->status = -4;
3016                 break;
3017             }
3018         }
3019         if ((exec->transno != 0) || (exec->state->nbTrans == 0)) {
3020 rollback:
3021             /*
3022              * Failed to find a way out
3023              */
3024             exec->determinist = 0;
3025             xmlFARegExecRollBack(exec);
3026         }
3027 progress:
3028         continue;
3029     }
3030 }
3031 #endif
3032 /************************************************************************
3033  *                                                                      *
3034  *      Parser for the Shemas Datatype Regular Expressions              *
3035  *      http://www.w3.org/TR/2001/REC-xmlschema-2-20010502/#regexs      *
3036  *                                                                      *
3037  ************************************************************************/
3038
3039 /**
3040  * xmlFAIsChar:
3041  * @ctxt:  a regexp parser context
3042  *
3043  * [10]   Char   ::=   [^.\?*+()|#x5B#x5D]
3044  */
3045 static int
3046 xmlFAIsChar(xmlRegParserCtxtPtr ctxt) {
3047     int cur;
3048     int len;
3049
3050     cur = CUR_SCHAR(ctxt->cur, len);
3051     if ((cur == '.') || (cur == '\\') || (cur == '?') ||
3052         (cur == '*') || (cur == '+') || (cur == '(') ||
3053         (cur == ')') || (cur == '|') || (cur == 0x5B) ||
3054         (cur == 0x5D) || (cur == 0))
3055         return(-1);
3056     return(cur);
3057 }
3058
3059 /**
3060  * xmlFAParseCharProp:
3061  * @ctxt:  a regexp parser context
3062  *
3063  * [27]   charProp   ::=   IsCategory | IsBlock
3064  * [28]   IsCategory ::= Letters | Marks | Numbers | Punctuation |
3065  *                       Separators | Symbols | Others 
3066  * [29]   Letters   ::=   'L' [ultmo]?
3067  * [30]   Marks   ::=   'M' [nce]?
3068  * [31]   Numbers   ::=   'N' [dlo]?
3069  * [32]   Punctuation   ::=   'P' [cdseifo]?
3070  * [33]   Separators   ::=   'Z' [slp]?
3071  * [34]   Symbols   ::=   'S' [mcko]?
3072  * [35]   Others   ::=   'C' [cfon]?
3073  * [36]   IsBlock   ::=   'Is' [a-zA-Z0-9#x2D]+
3074  */
3075 static void
3076 xmlFAParseCharProp(xmlRegParserCtxtPtr ctxt) {
3077     int cur;
3078     xmlRegAtomType type = (xmlRegAtomType) 0;
3079     xmlChar *blockName = NULL;
3080     
3081     cur = CUR;
3082     if (cur == 'L') {
3083         NEXT;
3084         cur = CUR;
3085         if (cur == 'u') {
3086             NEXT;
3087             type = XML_REGEXP_LETTER_UPPERCASE;
3088         } else if (cur == 'l') {
3089             NEXT;
3090             type = XML_REGEXP_LETTER_LOWERCASE;
3091         } else if (cur == 't') {
3092             NEXT;
3093             type = XML_REGEXP_LETTER_TITLECASE;
3094         } else if (cur == 'm') {
3095             NEXT;
3096             type = XML_REGEXP_LETTER_MODIFIER;
3097         } else if (cur == 'o') {
3098             NEXT;
3099             type = XML_REGEXP_LETTER_OTHERS;
3100         } else {
3101             type = XML_REGEXP_LETTER;
3102         }
3103     } else if (cur == 'M') {
3104         NEXT;
3105         cur = CUR;
3106         if (cur == 'n') {
3107             NEXT;
3108             /* nonspacing */
3109             type = XML_REGEXP_MARK_NONSPACING;
3110         } else if (cur == 'c') {
3111             NEXT;
3112             /* spacing combining */
3113             type = XML_REGEXP_MARK_SPACECOMBINING;
3114         } else if (cur == 'e') {
3115             NEXT;
3116             /* enclosing */
3117             type = XML_REGEXP_MARK_ENCLOSING;
3118         } else {
3119             /* all marks */
3120             type = XML_REGEXP_MARK;
3121         }
3122     } else if (cur == 'N') {
3123         NEXT;
3124         cur = CUR;
3125         if (cur == 'd') {
3126             NEXT;
3127             /* digital */
3128             type = XML_REGEXP_NUMBER_DECIMAL;
3129         } else if (cur == 'l') {
3130             NEXT;
3131             /* letter */
3132             type = XML_REGEXP_NUMBER_LETTER;
3133         } else if (cur == 'o') {
3134             NEXT;
3135             /* other */
3136             type = XML_REGEXP_NUMBER_OTHERS;
3137         } else {
3138             /* all numbers */
3139             type = XML_REGEXP_NUMBER;
3140         }
3141     } else if (cur == 'P') {
3142         NEXT;
3143         cur = CUR;
3144         if (cur == 'c') {
3145             NEXT;
3146             /* connector */
3147             type = XML_REGEXP_PUNCT_CONNECTOR;
3148         } else if (cur == 'd') {
3149             NEXT;
3150             /* dash */
3151             type = XML_REGEXP_PUNCT_DASH;
3152         } else if (cur == 's') {
3153             NEXT;
3154             /* open */
3155             type = XML_REGEXP_PUNCT_OPEN;
3156         } else if (cur == 'e') {
3157             NEXT;
3158             /* close */
3159             type = XML_REGEXP_PUNCT_CLOSE;
3160         } else if (cur == 'i') {
3161             NEXT;
3162             /* initial quote */
3163             type = XML_REGEXP_PUNCT_INITQUOTE;
3164         } else if (cur == 'f') {
3165             NEXT;
3166             /* final quote */
3167             type = XML_REGEXP_PUNCT_FINQUOTE;
3168         } else if (cur == 'o') {
3169             NEXT;
3170             /* other */
3171             type = XML_REGEXP_PUNCT_OTHERS;
3172         } else {
3173             /* all punctuation */
3174             type = XML_REGEXP_PUNCT;
3175         }
3176     } else if (cur == 'Z') {
3177         NEXT;
3178         cur = CUR;
3179         if (cur == 's') {
3180             NEXT;
3181             /* space */
3182             type = XML_REGEXP_SEPAR_SPACE;
3183         } else if (cur == 'l') {
3184             NEXT;
3185             /* line */
3186             type = XML_REGEXP_SEPAR_LINE;
3187         } else if (cur == 'p') {
3188             NEXT;
3189             /* paragraph */
3190             type = XML_REGEXP_SEPAR_PARA;
3191         } else {
3192             /* all separators */
3193             type = XML_REGEXP_SEPAR;
3194         }
3195     } else if (cur == 'S') {
3196         NEXT;
3197         cur = CUR;
3198         if (cur == 'm') {
3199             NEXT;
3200             type = XML_REGEXP_SYMBOL_MATH;
3201             /* math */
3202         } else if (cur == 'c') {
3203             NEXT;
3204             type = XML_REGEXP_SYMBOL_CURRENCY;
3205             /* currency */
3206         } else if (cur == 'k') {
3207             NEXT;
3208             type = XML_REGEXP_SYMBOL_MODIFIER;
3209             /* modifiers */
3210         } else if (cur == 'o') {
3211             NEXT;
3212             type = XML_REGEXP_SYMBOL_OTHERS;
3213             /* other */
3214         } else {
3215             /* all symbols */
3216             type = XML_REGEXP_SYMBOL;
3217         }
3218     } else if (cur == 'C') {
3219         NEXT;
3220         cur = CUR;
3221         if (cur == 'c') {
3222             NEXT;
3223             /* control */
3224             type = XML_REGEXP_OTHER_CONTROL;
3225         } else if (cur == 'f') {
3226             NEXT;
3227             /* format */
3228             type = XML_REGEXP_OTHER_FORMAT;
3229         } else if (cur == 'o') {
3230             NEXT;
3231             /* private use */
3232             type = XML_REGEXP_OTHER_PRIVATE;
3233         } else if (cur == 'n') {
3234             NEXT;
3235             /* not assigned */
3236             type = XML_REGEXP_OTHER_NA;
3237         } else {
3238             /* all others */
3239             type = XML_REGEXP_OTHER;
3240         }
3241     } else if (cur == 'I') {
3242         const xmlChar *start;
3243         NEXT;
3244         cur = CUR;
3245         if (cur != 's') {
3246             ERROR("IsXXXX expected");
3247             return;
3248         }
3249         NEXT;
3250         start = ctxt->cur;
3251         cur = CUR;
3252         if (((cur >= 'a') && (cur <= 'z')) || 
3253             ((cur >= 'A') && (cur <= 'Z')) || 
3254             ((cur >= '0') && (cur <= '9')) || 
3255             (cur == 0x2D)) {
3256             NEXT;
3257             cur = CUR;
3258             while (((cur >= 'a') && (cur <= 'z')) || 
3259                 ((cur >= 'A') && (cur <= 'Z')) || 
3260                 ((cur >= '0') && (cur <= '9')) || 
3261                 (cur == 0x2D)) {
3262                 NEXT;
3263                 cur = CUR;
3264             }
3265         }
3266         type = XML_REGEXP_BLOCK_NAME;
3267         blockName = xmlStrndup(start, ctxt->cur - start);
3268     } else {
3269         ERROR("Unknown char property");
3270         return;
3271     }
3272     if (ctxt->atom == NULL) {
3273         ctxt->atom = xmlRegNewAtom(ctxt, type);
3274         if (ctxt->atom != NULL)
3275             ctxt->atom->valuep = blockName;
3276     } else if (ctxt->atom->type == XML_REGEXP_RANGES) {
3277         xmlRegAtomAddRange(ctxt, ctxt->atom, ctxt->neg,
3278                            type, 0, 0, blockName);
3279     }
3280 }
3281
3282 /**
3283  * xmlFAParseCharClassEsc:
3284  * @ctxt:  a regexp parser context
3285  *
3286  * [23] charClassEsc ::= ( SingleCharEsc | MultiCharEsc | catEsc | complEsc ) 
3287  * [24] SingleCharEsc ::= '\' [nrt\|.?*+(){}#x2D#x5B#x5D#x5E]
3288  * [25] catEsc   ::=   '\p{' charProp '}'
3289  * [26] complEsc ::=   '\P{' charProp '}'
3290  * [37] MultiCharEsc ::= '.' | ('\' [sSiIcCdDwW])
3291  */
3292 static void
3293 xmlFAParseCharClassEsc(xmlRegParserCtxtPtr ctxt) {
3294     int cur;
3295
3296     if (CUR == '.') {
3297         if (ctxt->atom == NULL) {
3298             ctxt->atom = xmlRegNewAtom(ctxt, XML_REGEXP_ANYCHAR);
3299         } else if (ctxt->atom->type == XML_REGEXP_RANGES) {
3300             xmlRegAtomAddRange(ctxt, ctxt->atom, ctxt->neg,
3301                                XML_REGEXP_ANYCHAR, 0, 0, NULL);
3302         }
3303         NEXT;
3304         return;
3305     }
3306     if (CUR != '\\') {
3307         ERROR("Escaped sequence: expecting \\");
3308         return;
3309     }
3310     NEXT;
3311     cur = CUR;
3312     if (cur == 'p') {
3313         NEXT;
3314         if (CUR != '{') {
3315             ERROR("Expecting '{'");
3316             return;
3317         }
3318         NEXT;
3319         xmlFAParseCharProp(ctxt);
3320         if (CUR != '}') {
3321             ERROR("Expecting '}'");
3322             return;
3323         }
3324         NEXT;
3325     } else if (cur == 'P') {
3326         NEXT;
3327         if (CUR != '{') {
3328             ERROR("Expecting '{'");
3329             return;
3330         }
3331         NEXT;
3332         xmlFAParseCharProp(ctxt);
3333         ctxt->atom->neg = 1;
3334         if (CUR != '}') {
3335             ERROR("Expecting '}'");
3336             return;
3337         }
3338         NEXT;
3339     } else if ((cur == 'n') || (cur == 'r') || (cur == 't') || (cur == '\\') ||
3340