added Info.plist
[TestXSLT.git] / libxml2 / relaxng.c
1 /*
2  * relaxng.c : implementation of the Relax-NG handling and validity checking
3  *
4  * See Copyright for the status of this software.
5  *
6  * Daniel Veillard <veillard@redhat.com>
7  */
8
9 /**
10  * TODO:
11  * - add support for DTD compatibility spec
12  *   http://www.oasis-open.org/committees/relax-ng/compatibility-20011203.html
13  * - report better mem allocations pbms at runtime and abort immediately.
14  */
15
16 #define IN_LIBXML
17 #include "libxml.h"
18
19 #ifdef LIBXML_SCHEMAS_ENABLED
20
21 #include <string.h>
22 #include <stdio.h>
23 #include <libxml/xmlmemory.h>
24 #include <libxml/parser.h>
25 #include <libxml/parserInternals.h>
26 #include <libxml/hash.h>
27 #include <libxml/uri.h>
28
29 #include <libxml/relaxng.h>
30
31 #include <libxml/xmlschemastypes.h>
32 #include <libxml/xmlautomata.h>
33 #include <libxml/xmlregexp.h>
34 #include <libxml/xmlschemastypes.h>
35
36 /*
37  * The Relax-NG namespace
38  */
39 static const xmlChar *xmlRelaxNGNs = (const xmlChar *)
40     "http://relaxng.org/ns/structure/1.0";
41
42 #define IS_RELAXNG(node, type)                                          \
43    ((node != NULL) && (node->ns != NULL) &&                             \
44     (xmlStrEqual(node->name, (const xmlChar *) type)) &&                \
45     (xmlStrEqual(node->ns->href, xmlRelaxNGNs)))
46
47
48 /* #define DEBUG 1 */
49 /* #define DEBUG_GRAMMAR 1 */
50 /* #define DEBUG_CONTENT 1 */
51 /* #define DEBUG_TYPE 1 */
52 /* #define DEBUG_VALID 1 */
53 /* #define DEBUG_INTERLEAVE 1 */
54 /* #define DEBUG_LIST 1 */
55 /* #define DEBUG_INCLUDE */
56 /* #define DEBUG_ERROR 1 */
57 /* #define DEBUG_COMPILE 1 */
58 /* #define DEBUG_PROGRESSIVE 1 */
59
60 #define MAX_ERROR 5
61
62 #define TODO                                                            \
63     xmlGenericError(xmlGenericErrorContext,                             \
64             "Unimplemented block at %s:%d\n",                           \
65             __FILE__, __LINE__);
66
67 typedef struct _xmlRelaxNGSchema xmlRelaxNGSchema;
68 typedef xmlRelaxNGSchema *xmlRelaxNGSchemaPtr;
69
70 typedef struct _xmlRelaxNGDefine xmlRelaxNGDefine;
71 typedef xmlRelaxNGDefine *xmlRelaxNGDefinePtr;
72
73 typedef struct _xmlRelaxNGDocument xmlRelaxNGDocument;
74 typedef xmlRelaxNGDocument *xmlRelaxNGDocumentPtr;
75
76 typedef struct _xmlRelaxNGInclude xmlRelaxNGInclude;
77 typedef xmlRelaxNGInclude *xmlRelaxNGIncludePtr;
78
79 typedef enum {
80     XML_RELAXNG_COMBINE_UNDEFINED = 0,  /* undefined */
81     XML_RELAXNG_COMBINE_CHOICE,         /* choice */
82     XML_RELAXNG_COMBINE_INTERLEAVE      /* interleave */
83 } xmlRelaxNGCombine;
84
85 typedef enum {
86     XML_RELAXNG_CONTENT_ERROR = -1,
87     XML_RELAXNG_CONTENT_EMPTY = 0,
88     XML_RELAXNG_CONTENT_SIMPLE,
89     XML_RELAXNG_CONTENT_COMPLEX
90 } xmlRelaxNGContentType;
91
92 typedef struct _xmlRelaxNGGrammar xmlRelaxNGGrammar;
93 typedef xmlRelaxNGGrammar *xmlRelaxNGGrammarPtr;
94
95 struct _xmlRelaxNGGrammar {
96     xmlRelaxNGGrammarPtr parent;/* the parent grammar if any */
97     xmlRelaxNGGrammarPtr children;/* the children grammar if any */
98     xmlRelaxNGGrammarPtr next;  /* the next grammar if any */
99     xmlRelaxNGDefinePtr start;  /* <start> content */
100     xmlRelaxNGCombine combine;  /* the default combine value */
101     xmlRelaxNGDefinePtr startList;/* list of <start> definitions */
102     xmlHashTablePtr defs;       /* define* */
103     xmlHashTablePtr refs;       /* references */
104 };
105
106
107 typedef enum {
108     XML_RELAXNG_NOOP = -1,      /* a no operation from simplification  */
109     XML_RELAXNG_EMPTY = 0,      /* an empty pattern */
110     XML_RELAXNG_NOT_ALLOWED,    /* not allowed top */
111     XML_RELAXNG_EXCEPT,         /* except present in nameclass defs */
112     XML_RELAXNG_TEXT,           /* textual content */
113     XML_RELAXNG_ELEMENT,        /* an element */
114     XML_RELAXNG_DATATYPE,       /* extenal data type definition */
115     XML_RELAXNG_PARAM,          /* extenal data type parameter */
116     XML_RELAXNG_VALUE,          /* value from an extenal data type definition */
117     XML_RELAXNG_LIST,           /* a list of patterns */
118     XML_RELAXNG_ATTRIBUTE,      /* an attrbute following a pattern */
119     XML_RELAXNG_DEF,            /* a definition */
120     XML_RELAXNG_REF,            /* reference to a definition */
121     XML_RELAXNG_EXTERNALREF,    /* reference to an external def */
122     XML_RELAXNG_PARENTREF,      /* reference to a def in the parent grammar */
123     XML_RELAXNG_OPTIONAL,       /* optional patterns */
124     XML_RELAXNG_ZEROORMORE,     /* zero or more non empty patterns */
125     XML_RELAXNG_ONEORMORE,      /* one or more non empty patterns */
126     XML_RELAXNG_CHOICE,         /* a choice between non empty patterns */
127     XML_RELAXNG_GROUP,          /* a pair/group of non empty patterns */
128     XML_RELAXNG_INTERLEAVE,     /* interleaving choice of non-empty patterns */
129     XML_RELAXNG_START           /* Used to keep track of starts on grammars */
130 } xmlRelaxNGType;
131
132 #define IS_NULLABLE             (1 << 0)
133 #define IS_NOT_NULLABLE         (1 << 1)
134 #define IS_INDETERMINIST        (1 << 2)
135 #define IS_MIXED                (1 << 3)
136 #define IS_TRIABLE              (1 << 4)
137 #define IS_PROCESSED            (1 << 5)
138 #define IS_COMPILABLE           (1 << 6)
139 #define IS_NOT_COMPILABLE       (1 << 7)
140
141 struct _xmlRelaxNGDefine {
142     xmlRelaxNGType type;        /* the type of definition */
143     xmlNodePtr     node;        /* the node in the source */
144     xmlChar       *name;        /* the element local name if present */
145     xmlChar       *ns;          /* the namespace local name if present */
146     xmlChar       *value;       /* value when available */
147     void          *data;        /* data lib or specific pointer */
148     xmlRelaxNGDefinePtr content;/* the expected content */
149     xmlRelaxNGDefinePtr parent; /* the parent definition, if any */
150     xmlRelaxNGDefinePtr next;   /* list within grouping sequences */
151     xmlRelaxNGDefinePtr attrs;  /* list of attributes for elements */
152     xmlRelaxNGDefinePtr nameClass;/* the nameClass definition if any */
153     xmlRelaxNGDefinePtr nextHash;/* next define in defs/refs hash tables */
154     short           depth;       /* used for the cycle detection */
155     short           dflags;      /* define related flags */
156     xmlRegexpPtr    contModel;   /* a compiled content model if available */
157 };
158
159 /**
160  * _xmlRelaxNG:
161  *
162  * A RelaxNGs definition
163  */
164 struct _xmlRelaxNG {
165     void *_private;     /* unused by the library for users or bindings */
166     xmlRelaxNGGrammarPtr topgrammar;
167     xmlDocPtr doc;
168
169     int             idref;      /* requires idref checking */
170
171     xmlHashTablePtr defs;       /* define */
172     xmlHashTablePtr refs;       /* references */
173     xmlRelaxNGDocumentPtr documents; /* all the documents loaded */
174     xmlRelaxNGIncludePtr includes;   /* all the includes loaded */
175     int                  defNr; /* number of defines used */
176     xmlRelaxNGDefinePtr *defTab;/* pointer to the allocated definitions */
177
178 };
179
180 #define XML_RELAXNG_IN_ATTRIBUTE        (1 << 0)
181 #define XML_RELAXNG_IN_ONEORMORE        (1 << 1)
182 #define XML_RELAXNG_IN_LIST             (1 << 2)
183 #define XML_RELAXNG_IN_DATAEXCEPT       (1 << 3)
184 #define XML_RELAXNG_IN_START            (1 << 4)
185 #define XML_RELAXNG_IN_OOMGROUP         (1 << 5)
186 #define XML_RELAXNG_IN_OOMINTERLEAVE    (1 << 6)
187 #define XML_RELAXNG_IN_EXTERNALREF      (1 << 7)
188 #define XML_RELAXNG_IN_ANYEXCEPT        (1 << 8)
189 #define XML_RELAXNG_IN_NSEXCEPT         (1 << 9)
190
191 struct _xmlRelaxNGParserCtxt {
192     void *userData;                     /* user specific data block */
193     xmlRelaxNGValidityErrorFunc error;  /* the callback in case of errors */
194     xmlRelaxNGValidityWarningFunc warning;/* the callback in case of warning */
195     xmlRelaxNGValidErr err;
196
197     xmlRelaxNGPtr      schema;        /* The schema in use */
198     xmlRelaxNGGrammarPtr grammar;     /* the current grammar */
199     xmlRelaxNGGrammarPtr parentgrammar;/* the parent grammar */
200     int                flags;         /* parser flags */
201     int                nbErrors;      /* number of errors at parse time */
202     int                nbWarnings;    /* number of warnings at parse time */
203     const xmlChar     *define;        /* the current define scope */
204     xmlRelaxNGDefinePtr def;          /* the current define */
205
206     int                nbInterleaves;
207     xmlHashTablePtr    interleaves;   /* keep track of all the interleaves */
208
209     xmlRelaxNGDocumentPtr documents;  /* all the documents loaded */
210     xmlRelaxNGIncludePtr includes;    /* all the includes loaded */
211     xmlChar           *URL;
212     xmlDocPtr          document;
213
214     int                  defNr;       /* number of defines used */
215     int                  defMax;      /* number of defines aloocated */
216     xmlRelaxNGDefinePtr *defTab;      /* pointer to the allocated definitions */
217
218     const char     *buffer;
219     int               size;
220
221     /* the document stack */
222     xmlRelaxNGDocumentPtr doc;        /* Current parsed external ref */
223     int                   docNr;      /* Depth of the parsing stack */
224     int                   docMax;     /* Max depth of the parsing stack */
225     xmlRelaxNGDocumentPtr *docTab;    /* array of docs */
226
227     /* the include stack */
228     xmlRelaxNGIncludePtr  inc;        /* Current parsed include */
229     int                   incNr;      /* Depth of the include parsing stack */
230     int                   incMax;     /* Max depth of the parsing stack */
231     xmlRelaxNGIncludePtr *incTab;     /* array of incs */
232
233     int                   idref;      /* requires idref checking */
234
235     /* used to compile content models */
236     xmlAutomataPtr        am;         /* the automata */
237     xmlAutomataStatePtr   state;      /* used to build the automata */
238 };
239
240 #define FLAGS_IGNORABLE         1
241 #define FLAGS_NEGATIVE          2
242 #define FLAGS_MIXED_CONTENT     4
243
244 /**
245  * xmlRelaxNGInterleaveGroup:
246  *
247  * A RelaxNGs partition set associated to lists of definitions
248  */
249 typedef struct _xmlRelaxNGInterleaveGroup xmlRelaxNGInterleaveGroup;
250 typedef xmlRelaxNGInterleaveGroup *xmlRelaxNGInterleaveGroupPtr;
251 struct _xmlRelaxNGInterleaveGroup {
252     xmlRelaxNGDefinePtr  rule;  /* the rule to satisfy */
253     xmlRelaxNGDefinePtr *defs;  /* the array of element definitions */
254     xmlRelaxNGDefinePtr *attrs; /* the array of attributes definitions */
255 };
256
257 #define IS_DETERMINIST          1
258 #define IS_NEEDCHECK            2
259 /**
260  * xmlRelaxNGPartitions:
261  *
262  * A RelaxNGs partition associated to an interleave group
263  */
264 typedef struct _xmlRelaxNGPartition xmlRelaxNGPartition;
265 typedef xmlRelaxNGPartition *xmlRelaxNGPartitionPtr;
266 struct _xmlRelaxNGPartition {
267     int nbgroups;               /* number of groups in the partitions */
268     xmlHashTablePtr triage;     /* hash table used to direct nodes to the
269                                    right group when possible */
270     int flags;                  /* determinist ? */
271     xmlRelaxNGInterleaveGroupPtr *groups;
272 };
273
274 /**
275  * xmlRelaxNGValidState:
276  *
277  * A RelaxNGs validation state
278  */
279 #define MAX_ATTR 20
280 typedef struct _xmlRelaxNGValidState xmlRelaxNGValidState;
281 typedef xmlRelaxNGValidState *xmlRelaxNGValidStatePtr;
282 struct _xmlRelaxNGValidState {
283     xmlNodePtr   node;          /* the current node */
284     xmlNodePtr    seq;          /* the sequence of children left to validate */
285     int       nbAttrs;          /* the number of attributes */
286     int      maxAttrs;          /* the size of attrs */
287     int    nbAttrLeft;          /* the number of attributes left to validate */
288     xmlChar    *value;          /* the value when operating on string */
289     xmlChar *endvalue;          /* the end value when operating on string */
290     xmlAttrPtr *attrs;          /* the array of attributes */
291 };
292
293 /**
294  * xmlRelaxNGStates:
295  *
296  * A RelaxNGs container for validation state
297  */
298 typedef struct _xmlRelaxNGStates xmlRelaxNGStates;
299 typedef xmlRelaxNGStates *xmlRelaxNGStatesPtr;
300 struct _xmlRelaxNGStates {
301     int       nbState;          /* the number of states */
302     int      maxState;          /* the size of the array */
303     xmlRelaxNGValidStatePtr *tabState;
304 };
305
306 #define ERROR_IS_DUP    1
307 /**
308  * xmlRelaxNGValidError:
309  *
310  * A RelaxNGs validation error
311  */
312 typedef struct _xmlRelaxNGValidError xmlRelaxNGValidError;
313 typedef xmlRelaxNGValidError *xmlRelaxNGValidErrorPtr;
314 struct _xmlRelaxNGValidError {
315     xmlRelaxNGValidErr  err;    /* the error number */
316     int                 flags;  /* flags */
317     xmlNodePtr          node;   /* the current node */
318     xmlNodePtr          seq;    /* the current child */
319     const xmlChar *     arg1;   /* first arg */
320     const xmlChar *     arg2;   /* second arg */
321 };
322
323 /**
324  * xmlRelaxNGValidCtxt:
325  *
326  * A RelaxNGs validation context
327  */
328
329 struct _xmlRelaxNGValidCtxt {
330     void *userData;                     /* user specific data block */
331     xmlRelaxNGValidityErrorFunc error;  /* the callback in case of errors */
332     xmlRelaxNGValidityWarningFunc warning;/* the callback in case of warning */
333
334     xmlRelaxNGPtr           schema;     /* The schema in use */
335     xmlDocPtr               doc;        /* the document being validated */
336     int                     flags;      /* validation flags */
337     int                     depth;      /* validation depth */
338     int                     idref;      /* requires idref checking */
339     int                     errNo;      /* the first error found */
340
341     /*
342      * Errors accumulated in branches may have to be stacked to be
343      * provided back when it's sure they affect validation.
344      */
345     xmlRelaxNGValidErrorPtr err;        /* Last error */
346     int                     errNr;      /* Depth of the error stack */
347     int                     errMax;     /* Max depth of the error stack */
348     xmlRelaxNGValidErrorPtr errTab;     /* stack of errors */
349
350     xmlRelaxNGValidStatePtr state;      /* the current validation state */
351     xmlRelaxNGStatesPtr     states;     /* the accumulated state list */
352
353     xmlRelaxNGStatesPtr     freeState;  /* the pool of free valid states */
354     int                     freeStatesNr;
355     int                     freeStatesMax;
356     xmlRelaxNGStatesPtr    *freeStates; /* the pool of free state groups */
357
358     /*
359      * This is used for "progressive" validation
360      */
361     xmlRegExecCtxtPtr       elem;       /* the current element regexp */
362     int                     elemNr;     /* the number of element validated */
363     int                     elemMax;    /* the max depth of elements */
364     xmlRegExecCtxtPtr      *elemTab;    /* the stack of regexp runtime */
365     int                     pstate;     /* progressive state */
366     xmlNodePtr              pnode;      /* the current node */
367     xmlRelaxNGDefinePtr     pdef;       /* the non-streamable definition */
368 };
369
370 /**
371  * xmlRelaxNGInclude:
372  *
373  * Structure associated to a RelaxNGs document element
374  */
375 struct _xmlRelaxNGInclude {
376     xmlRelaxNGIncludePtr next;  /* keep a chain of includes */
377     xmlChar   *href;            /* the normalized href value */
378     xmlDocPtr  doc;             /* the associated XML document */
379     xmlRelaxNGDefinePtr content;/* the definitions */
380     xmlRelaxNGPtr       schema; /* the schema */
381 };
382
383 /**
384  * xmlRelaxNGDocument:
385  *
386  * Structure associated to a RelaxNGs document element
387  */
388 struct _xmlRelaxNGDocument {
389     xmlRelaxNGDocumentPtr next; /* keep a chain of documents */
390     xmlChar   *href;            /* the normalized href value */
391     xmlDocPtr  doc;             /* the associated XML document */
392     xmlRelaxNGDefinePtr content;/* the definitions */
393     xmlRelaxNGPtr       schema; /* the schema */
394 };
395
396
397 /************************************************************************
398  *                                                                      *
399  *              Preliminary type checking interfaces                    *
400  *                                                                      *
401  ************************************************************************/
402 /**
403  * xmlRelaxNGTypeHave:
404  * @data:  data needed for the library
405  * @type:  the type name
406  * @value:  the value to check
407  *
408  * Function provided by a type library to check if a type is exported
409  *
410  * Returns 1 if yes, 0 if no and -1 in case of error.
411  */
412 typedef int (*xmlRelaxNGTypeHave) (void *data, const xmlChar *type);
413
414 /**
415  * xmlRelaxNGTypeCheck:
416  * @data:  data needed for the library
417  * @type:  the type name
418  * @value:  the value to check
419  * @result:  place to store the result if needed
420  *
421  * Function provided by a type library to check if a value match a type
422  *
423  * Returns 1 if yes, 0 if no and -1 in case of error.
424  */
425 typedef int (*xmlRelaxNGTypeCheck) (void *data, const xmlChar *type,
426                                     const xmlChar *value, void **result,
427                                     xmlNodePtr node);
428
429 /**
430  * xmlRelaxNGFacetCheck:
431  * @data:  data needed for the library
432  * @type:  the type name
433  * @facet:  the facet name
434  * @val:  the facet value
435  * @strval:  the string value
436  * @value:  the value to check
437  *
438  * Function provided by a type library to check a value facet
439  *
440  * Returns 1 if yes, 0 if no and -1 in case of error.
441  */
442 typedef int (*xmlRelaxNGFacetCheck) (void *data, const xmlChar *type,
443                                      const xmlChar *facet, const xmlChar *val,
444                                      const xmlChar *strval, void *value);
445
446 /**
447  * xmlRelaxNGTypeFree:
448  * @data:  data needed for the library
449  * @result:  the value to free
450  *
451  * Function provided by a type library to free a returned result
452  */
453 typedef void (*xmlRelaxNGTypeFree) (void *data, void *result);
454
455 /**
456  * xmlRelaxNGTypeCompare:
457  * @data:  data needed for the library
458  * @type:  the type name
459  * @value1:  the first value
460  * @value2:  the second value
461  *
462  * Function provided by a type library to compare two values accordingly
463  * to a type.
464  *
465  * Returns 1 if yes, 0 if no and -1 in case of error.
466  */
467 typedef int (*xmlRelaxNGTypeCompare) (void *data, const xmlChar *type,
468                                       const xmlChar *value1,
469                                       xmlNodePtr ctxt1,
470                                       void *comp1,
471                                       const xmlChar *value2,
472                                       xmlNodePtr ctxt2);
473 typedef struct _xmlRelaxNGTypeLibrary xmlRelaxNGTypeLibrary;
474 typedef xmlRelaxNGTypeLibrary *xmlRelaxNGTypeLibraryPtr;
475 struct _xmlRelaxNGTypeLibrary {
476     const xmlChar     *namespace;       /* the datatypeLibrary value */
477     void                   *data;       /* data needed for the library */
478     xmlRelaxNGTypeHave      have;       /* the export function */
479     xmlRelaxNGTypeCheck    check;       /* the checking function */
480     xmlRelaxNGTypeCompare   comp;       /* the compare function */
481     xmlRelaxNGFacetCheck   facet;       /* the facet check function */
482     xmlRelaxNGTypeFree     freef;       /* the freeing function */
483 };
484
485 /************************************************************************
486  *                                                                      *
487  *                      Allocation functions                            *
488  *                                                                      *
489  ************************************************************************/
490 static void xmlRelaxNGFreeGrammar(xmlRelaxNGGrammarPtr grammar);
491 static void xmlRelaxNGFreeDefine(xmlRelaxNGDefinePtr define);
492 static void xmlRelaxNGNormExtSpace(xmlChar *value);
493 static void xmlRelaxNGFreeInnerSchema(xmlRelaxNGPtr schema);
494 static int xmlRelaxNGEqualValidState(
495                          xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
496                          xmlRelaxNGValidStatePtr state1,
497                          xmlRelaxNGValidStatePtr state2);
498 static void xmlRelaxNGFreeValidState(xmlRelaxNGValidCtxtPtr ctxt,
499                                      xmlRelaxNGValidStatePtr state);
500
501 /**
502  * xmlRelaxNGFreeDocument:
503  * @docu:  a document structure
504  *
505  * Deallocate a RelaxNG document structure.
506  */
507 static void
508 xmlRelaxNGFreeDocument(xmlRelaxNGDocumentPtr docu)
509 {
510     if (docu == NULL)
511         return;
512
513     if (docu->href != NULL)
514         xmlFree(docu->href);
515     if (docu->doc != NULL)
516         xmlFreeDoc(docu->doc);
517     if (docu->schema != NULL)
518         xmlRelaxNGFreeInnerSchema(docu->schema);
519     xmlFree(docu);
520 }
521
522 /**
523  * xmlRelaxNGFreeDocumentList:
524  * @docu:  a list of  document structure
525  *
526  * Deallocate a RelaxNG document structures.
527  */
528 static void
529 xmlRelaxNGFreeDocumentList(xmlRelaxNGDocumentPtr docu)
530 {
531     xmlRelaxNGDocumentPtr next;
532     while (docu != NULL) {
533         next = docu->next;
534         xmlRelaxNGFreeDocument(docu);
535         docu = next;
536     }
537 }
538
539 /**
540  * xmlRelaxNGFreeInclude:
541  * @incl:  a include structure
542  *
543  * Deallocate a RelaxNG include structure.
544  */
545 static void
546 xmlRelaxNGFreeInclude(xmlRelaxNGIncludePtr incl)
547 {
548     if (incl == NULL)
549         return;
550
551     if (incl->href != NULL)
552         xmlFree(incl->href);
553     if (incl->doc != NULL)
554         xmlFreeDoc(incl->doc);
555     if (incl->schema != NULL)
556         xmlRelaxNGFree(incl->schema);
557     xmlFree(incl);
558 }
559
560 /**
561  * xmlRelaxNGFreeIncludeList:
562  * @incl:  a include structure list
563  *
564  * Deallocate a RelaxNG include structure.
565  */
566 static void
567 xmlRelaxNGFreeIncludeList(xmlRelaxNGIncludePtr incl)
568 {
569     xmlRelaxNGIncludePtr next;
570     while (incl != NULL) {
571         next = incl->next;
572         xmlRelaxNGFreeInclude(incl);
573         incl = next;
574     }
575 }
576
577 /**
578  * xmlRelaxNGNewRelaxNG:
579  * @ctxt:  a Relax-NG validation context (optional)
580  *
581  * Allocate a new RelaxNG structure.
582  *
583  * Returns the newly allocated structure or NULL in case or error
584  */
585 static xmlRelaxNGPtr
586 xmlRelaxNGNewRelaxNG(xmlRelaxNGParserCtxtPtr ctxt)
587 {
588     xmlRelaxNGPtr ret;
589
590     ret = (xmlRelaxNGPtr) xmlMalloc(sizeof(xmlRelaxNG));
591     if (ret == NULL) {
592         if ((ctxt != NULL) && (ctxt->error != NULL))
593             ctxt->error(ctxt->userData, "Out of memory\n");
594         ctxt->nbErrors++;
595         return (NULL);
596     }
597     memset(ret, 0, sizeof(xmlRelaxNG));
598
599     return (ret);
600 }
601
602 /**
603  * xmlRelaxNGFreeInnerSchema:
604  * @schema:  a schema structure
605  *
606  * Deallocate a RelaxNG schema structure.
607  */
608 static void
609 xmlRelaxNGFreeInnerSchema(xmlRelaxNGPtr schema)
610 {
611     if (schema == NULL)
612         return;
613
614     if (schema->doc != NULL)
615         xmlFreeDoc(schema->doc);
616     if (schema->defTab != NULL) {
617         int i;
618
619         for (i = 0;i < schema->defNr;i++)
620             xmlRelaxNGFreeDefine(schema->defTab[i]);
621         xmlFree(schema->defTab);
622     }
623
624     xmlFree(schema);
625 }
626
627 /**
628  * xmlRelaxNGFree:
629  * @schema:  a schema structure
630  *
631  * Deallocate a RelaxNG structure.
632  */
633 void
634 xmlRelaxNGFree(xmlRelaxNGPtr schema)
635 {
636     if (schema == NULL)
637         return;
638
639     if (schema->topgrammar != NULL)
640         xmlRelaxNGFreeGrammar(schema->topgrammar);
641     if (schema->doc != NULL)
642         xmlFreeDoc(schema->doc);
643     if (schema->documents != NULL)
644         xmlRelaxNGFreeDocumentList(schema->documents);
645     if (schema->includes != NULL)
646         xmlRelaxNGFreeIncludeList(schema->includes);
647     if (schema->defTab != NULL) {
648         int i;
649
650         for (i = 0;i < schema->defNr;i++)
651             xmlRelaxNGFreeDefine(schema->defTab[i]);
652         xmlFree(schema->defTab);
653     }
654
655     xmlFree(schema);
656 }
657
658 /**
659  * xmlRelaxNGNewGrammar:
660  * @ctxt:  a Relax-NG validation context (optional)
661  *
662  * Allocate a new RelaxNG grammar.
663  *
664  * Returns the newly allocated structure or NULL in case or error
665  */
666 static xmlRelaxNGGrammarPtr
667 xmlRelaxNGNewGrammar(xmlRelaxNGParserCtxtPtr ctxt)
668 {
669     xmlRelaxNGGrammarPtr ret;
670
671     ret = (xmlRelaxNGGrammarPtr) xmlMalloc(sizeof(xmlRelaxNGGrammar));
672     if (ret == NULL) {
673         if ((ctxt != NULL) && (ctxt->error != NULL))
674             ctxt->error(ctxt->userData, "Out of memory\n");
675         ctxt->nbErrors++;
676         return (NULL);
677     }
678     memset(ret, 0, sizeof(xmlRelaxNGGrammar));
679
680     return (ret);
681 }
682
683 /**
684  * xmlRelaxNGFreeGrammar:
685  * @grammar:  a grammar structure
686  *
687  * Deallocate a RelaxNG grammar structure.
688  */
689 static void
690 xmlRelaxNGFreeGrammar(xmlRelaxNGGrammarPtr grammar)
691 {
692     if (grammar == NULL)
693         return;
694
695     if (grammar->children != NULL) {
696         xmlRelaxNGFreeGrammar(grammar->children);
697     }
698     if (grammar->next != NULL) {
699         xmlRelaxNGFreeGrammar(grammar->next);
700     }
701     if (grammar->refs != NULL) {
702         xmlHashFree(grammar->refs, NULL);
703     }
704     if (grammar->defs != NULL) {
705         xmlHashFree(grammar->defs, NULL);
706     }
707
708     xmlFree(grammar);
709 }
710
711 /**
712  * xmlRelaxNGNewDefine:
713  * @ctxt:  a Relax-NG validation context
714  * @node:  the node in the input document.
715  *
716  * Allocate a new RelaxNG define.
717  *
718  * Returns the newly allocated structure or NULL in case or error
719  */
720 static xmlRelaxNGDefinePtr
721 xmlRelaxNGNewDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
722 {
723     xmlRelaxNGDefinePtr ret;
724
725     if (ctxt->defMax == 0) {
726         ctxt->defMax = 16;
727         ctxt->defNr = 0;
728         ctxt->defTab = (xmlRelaxNGDefinePtr *)
729             xmlMalloc(ctxt->defMax * sizeof(xmlRelaxNGDefinePtr));
730         if (ctxt->defTab == NULL) {
731             if ((ctxt != NULL) && (ctxt->error != NULL))
732                 ctxt->error(ctxt->userData, "Out of memory\n");
733             ctxt->nbErrors++;
734             return (NULL);
735         }
736     } else if (ctxt->defMax <= ctxt->defNr) {
737         xmlRelaxNGDefinePtr *tmp;
738         ctxt->defMax *= 2;
739         tmp = (xmlRelaxNGDefinePtr *) xmlRealloc(ctxt->defTab,
740                 ctxt->defMax * sizeof(xmlRelaxNGDefinePtr));
741         if (tmp == NULL) {
742             if ((ctxt != NULL) && (ctxt->error != NULL))
743                 ctxt->error(ctxt->userData, "Out of memory\n");
744             ctxt->nbErrors++;
745             return (NULL);
746         }
747         ctxt->defTab = tmp;
748     }
749     ret = (xmlRelaxNGDefinePtr) xmlMalloc(sizeof(xmlRelaxNGDefine));
750     if (ret == NULL) {
751         if ((ctxt != NULL) && (ctxt->error != NULL))
752             ctxt->error(ctxt->userData, "Out of memory\n");
753         ctxt->nbErrors++;
754         return(NULL);
755     }
756     memset(ret, 0, sizeof(xmlRelaxNGDefine));
757     ctxt->defTab[ctxt->defNr++] = ret;
758     ret->node = node;
759     ret->depth = -1;
760     return (ret);
761 }
762
763 /**
764  * xmlRelaxNGFreePartition:
765  * @partitions:  a partition set structure
766  *
767  * Deallocate RelaxNG partition set structures.
768  */
769 static void
770 xmlRelaxNGFreePartition(xmlRelaxNGPartitionPtr partitions) {
771     xmlRelaxNGInterleaveGroupPtr group;
772     int j;
773
774     if (partitions != NULL) {
775         if (partitions->groups != NULL) {
776             for (j = 0;j < partitions->nbgroups;j++) {
777                 group = partitions->groups[j];
778                 if (group != NULL) {
779                     if (group->defs != NULL)
780                         xmlFree(group->defs);
781                     if (group->attrs != NULL)
782                         xmlFree(group->attrs);
783                     xmlFree(group);
784                 }
785             }
786             xmlFree(partitions->groups);
787         }
788         if (partitions->triage != NULL) {
789             xmlHashFree(partitions->triage, NULL);
790         }
791         xmlFree(partitions);
792     }
793 }
794 /**
795  * xmlRelaxNGFreeDefine:
796  * @define:  a define structure
797  *
798  * Deallocate a RelaxNG define structure.
799  */
800 static void
801 xmlRelaxNGFreeDefine(xmlRelaxNGDefinePtr define)
802 {
803     if (define == NULL)
804         return;
805
806     if ((define->type == XML_RELAXNG_VALUE) &&
807         (define->attrs != NULL)) {
808         xmlRelaxNGTypeLibraryPtr lib;
809
810         lib = (xmlRelaxNGTypeLibraryPtr) define->data;
811         if ((lib != NULL) && (lib->freef != NULL))
812             lib->freef(lib->data, (void *) define->attrs);
813     }
814     if ((define->data != NULL) &&
815         (define->type == XML_RELAXNG_INTERLEAVE))
816         xmlRelaxNGFreePartition((xmlRelaxNGPartitionPtr) define->data);
817     if ((define->data != NULL) &&
818         (define->type == XML_RELAXNG_CHOICE))
819         xmlHashFree((xmlHashTablePtr) define->data, NULL);
820     if (define->name != NULL)
821         xmlFree(define->name);
822     if (define->ns != NULL)
823         xmlFree(define->ns);
824     if (define->value != NULL)
825         xmlFree(define->value);
826     if (define->contModel != NULL)
827         xmlRegFreeRegexp(define->contModel);
828     xmlFree(define);
829 }
830
831 /**
832  * xmlRelaxNGNewStates:
833  * @ctxt:  a Relax-NG validation context
834  * @size:  the default size for the container
835  *
836  * Allocate a new RelaxNG validation state container
837  *
838  * Returns the newly allocated structure or NULL in case or error
839  */
840 static xmlRelaxNGStatesPtr
841 xmlRelaxNGNewStates(xmlRelaxNGValidCtxtPtr ctxt, int size)
842 {
843     xmlRelaxNGStatesPtr ret;
844
845     if ((ctxt != NULL) &&
846         (ctxt->freeState != NULL) && 
847         (ctxt->freeStatesNr > 0)) {
848         ctxt->freeStatesNr--;
849         ret = ctxt->freeStates[ctxt->freeStatesNr];
850         ret->nbState = 0;
851         return(ret);
852     }
853     if (size < 16) size = 16;
854
855     ret = (xmlRelaxNGStatesPtr) xmlMalloc(sizeof(xmlRelaxNGStates) +
856                               (size - 1) * sizeof(xmlRelaxNGValidStatePtr));
857     if (ret == NULL) {
858         if ((ctxt != NULL) && (ctxt->error != NULL))
859             ctxt->error(ctxt->userData, "Out of memory\n");
860         return (NULL);
861     }
862     ret->nbState = 0;
863     ret->maxState = size;
864     ret->tabState = (xmlRelaxNGValidStatePtr *) xmlMalloc(
865                             (size) * sizeof(xmlRelaxNGValidStatePtr));
866     if (ret->tabState == NULL) {
867         if ((ctxt != NULL) && (ctxt->error != NULL))
868             ctxt->error(ctxt->userData, "Out of memory\n");
869         xmlFree(ret->tabState);
870         return (NULL);
871     }
872     return(ret);
873 }
874
875 /**
876  * xmlRelaxNGAddStateUniq:
877  * @ctxt:  a Relax-NG validation context
878  * @states:  the states container
879  * @state:  the validation state
880  *
881  * Add a RelaxNG validation state to the container without checking
882  * for unicity.
883  *
884  * Return 1 in case of success and 0 if this is a duplicate and -1 on error
885  */
886 static int
887 xmlRelaxNGAddStatesUniq(xmlRelaxNGValidCtxtPtr ctxt,
888                     xmlRelaxNGStatesPtr states,
889                     xmlRelaxNGValidStatePtr state)
890 {
891     if (state == NULL) {
892         return(-1);
893     }
894     if (states->nbState >= states->maxState) {
895         xmlRelaxNGValidStatePtr *tmp;
896         int size;
897
898         size = states->maxState * 2;
899         tmp = (xmlRelaxNGValidStatePtr *) xmlRealloc(states->tabState,
900                               (size) * sizeof(xmlRelaxNGValidStatePtr));
901         if (tmp == NULL) {
902             if ((ctxt != NULL) && (ctxt->error != NULL))
903                 ctxt->error(ctxt->userData, "Out of memory\n");
904             return(-1);
905         }
906         states->tabState = tmp;
907         states->maxState = size;
908     }
909     states->tabState[states->nbState++] = state;
910     return(1);
911 }
912
913 /**
914  * xmlRelaxNGAddState:
915  * @ctxt:  a Relax-NG validation context
916  * @states:  the states container
917  * @state:  the validation state
918  *
919  * Add a RelaxNG validation state to the container
920  *
921  * Return 1 in case of success and 0 if this is a duplicate and -1 on error
922  */
923 static int
924 xmlRelaxNGAddStates(xmlRelaxNGValidCtxtPtr ctxt, xmlRelaxNGStatesPtr states,
925                     xmlRelaxNGValidStatePtr state)
926 {
927     int i;
928
929     if (state == NULL) {
930         return(-1);
931     }
932     if (states->nbState >= states->maxState) {
933         xmlRelaxNGValidStatePtr *tmp;
934         int size;
935
936         size = states->maxState * 2;
937         tmp = (xmlRelaxNGValidStatePtr *) xmlRealloc(states->tabState,
938                               (size) * sizeof(xmlRelaxNGValidStatePtr));
939         if (tmp == NULL) {
940             if ((ctxt != NULL) && (ctxt->error != NULL))
941                 ctxt->error(ctxt->userData, "Out of memory\n");
942             return(-1);
943         }
944         states->tabState = tmp;
945         states->maxState = size;
946     }
947     for (i = 0;i < states->nbState;i++) {
948         if (xmlRelaxNGEqualValidState(ctxt, state, states->tabState[i])) {
949             xmlRelaxNGFreeValidState(ctxt, state);
950             return(0);
951         }
952     }
953     states->tabState[states->nbState++] = state;
954     return(1);
955 }
956
957 /**
958  * xmlRelaxNGFreeStates:
959  * @ctxt:  a Relax-NG validation context
960  * @states:  teh container
961  *
962  * Free a RelaxNG validation state container
963  */
964 static void
965 xmlRelaxNGFreeStates(xmlRelaxNGValidCtxtPtr ctxt,
966                      xmlRelaxNGStatesPtr states)
967 {
968     if (states == NULL)
969         return;
970     if ((ctxt != NULL) && (ctxt->freeStates == NULL)) {
971         ctxt->freeStatesMax = 40;
972         ctxt->freeStatesNr = 0;
973         ctxt->freeStates = (xmlRelaxNGStatesPtr *)
974              xmlMalloc(ctxt->freeStatesMax * sizeof(xmlRelaxNGStatesPtr));
975         if (ctxt->freeStates == NULL) {
976             if ((ctxt != NULL) && (ctxt->error != NULL))
977                 ctxt->error(ctxt->userData, "Out of memory\n");
978         }
979     } else if ((ctxt != NULL) && (ctxt->freeStatesNr >= ctxt->freeStatesMax)) {
980         xmlRelaxNGStatesPtr *tmp;
981
982         tmp = (xmlRelaxNGStatesPtr *) xmlRealloc(ctxt->freeStates,
983                 2 * ctxt->freeStatesMax * sizeof(xmlRelaxNGStatesPtr));
984         if (tmp == NULL) {
985             if ((ctxt != NULL) && (ctxt->error != NULL))
986                 ctxt->error(ctxt->userData, "Out of memory\n");
987             xmlFree(states->tabState);
988             xmlFree(states);
989             return;
990         }
991         ctxt->freeStates = tmp;
992         ctxt->freeStatesMax *= 2;
993     }
994     if ((ctxt == NULL) || (ctxt->freeState == NULL)) {
995         xmlFree(states->tabState);
996         xmlFree(states);
997     } else {
998         ctxt->freeStates[ctxt->freeStatesNr++] = states;
999     }
1000 }
1001
1002 /**
1003  * xmlRelaxNGNewValidState:
1004  * @ctxt:  a Relax-NG validation context
1005  * @node:  the current node or NULL for the document
1006  *
1007  * Allocate a new RelaxNG validation state
1008  *
1009  * Returns the newly allocated structure or NULL in case or error
1010  */
1011 static xmlRelaxNGValidStatePtr
1012 xmlRelaxNGNewValidState(xmlRelaxNGValidCtxtPtr ctxt, xmlNodePtr node)
1013 {
1014     xmlRelaxNGValidStatePtr ret;
1015     xmlAttrPtr attr;
1016     xmlAttrPtr attrs[MAX_ATTR];
1017     int nbAttrs = 0;
1018     xmlNodePtr root = NULL;
1019
1020     if (node == NULL) {
1021         root = xmlDocGetRootElement(ctxt->doc);
1022         if (root == NULL)
1023             return(NULL);
1024     } else {
1025         attr = node->properties;
1026         while (attr != NULL) {
1027             if (nbAttrs < MAX_ATTR)
1028                 attrs[nbAttrs++] = attr;
1029             else
1030                 nbAttrs++;
1031             attr = attr->next;
1032         }
1033     }
1034     if ((ctxt->freeState != NULL) && 
1035         (ctxt->freeState->nbState > 0)) {
1036         ctxt->freeState->nbState--;
1037         ret = ctxt->freeState->tabState[ctxt->freeState->nbState];
1038     } else {
1039         ret = (xmlRelaxNGValidStatePtr) xmlMalloc(sizeof(xmlRelaxNGValidState));
1040         if (ret == NULL) {
1041             if ((ctxt != NULL) && (ctxt->error != NULL))
1042                 ctxt->error(ctxt->userData, "Out of memory\n");
1043             return (NULL);
1044         }
1045         memset(ret, 0, sizeof(xmlRelaxNGValidState));
1046     }
1047     ret->value = NULL;
1048     ret->endvalue = NULL;
1049     if (node == NULL) {
1050         ret->node = (xmlNodePtr) ctxt->doc;
1051         ret->seq = root;
1052     } else {
1053         ret->node = node;
1054         ret->seq = node->children;
1055     }
1056     ret->nbAttrs = 0;
1057     if (nbAttrs > 0) {
1058         if (ret->attrs == NULL) {
1059             if (nbAttrs < 4) ret->maxAttrs = 4;
1060             else ret->maxAttrs = nbAttrs;
1061             ret->attrs = (xmlAttrPtr *) xmlMalloc(ret->maxAttrs *
1062                                                 sizeof(xmlAttrPtr));
1063             if (ret->attrs == NULL) {
1064                 if ((ctxt != NULL) && (ctxt->error != NULL))
1065                     ctxt->error(ctxt->userData, "Out of memory\n");
1066                 return (ret);
1067             }
1068         } else if (ret->maxAttrs < nbAttrs) {
1069             xmlAttrPtr *tmp;
1070
1071             tmp = (xmlAttrPtr *) xmlRealloc(ret->attrs, nbAttrs *
1072                                           sizeof(xmlAttrPtr));
1073             if (tmp == NULL) {
1074                 if ((ctxt != NULL) && (ctxt->error != NULL))
1075                     ctxt->error(ctxt->userData, "Out of memory\n");
1076                 return (ret);
1077             }
1078             ret->attrs = tmp;
1079         }
1080         ret->nbAttrs = nbAttrs;
1081         if (nbAttrs < MAX_ATTR) {
1082             memcpy(ret->attrs, attrs, sizeof(xmlAttrPtr) * nbAttrs);
1083         } else {
1084             attr = node->properties;
1085             nbAttrs = 0;
1086             while (attr != NULL) {
1087                 ret->attrs[nbAttrs++] = attr;
1088                 attr = attr->next;
1089             }
1090         }
1091     }
1092     ret->nbAttrLeft = ret->nbAttrs;
1093     return (ret);
1094 }
1095
1096 /**
1097  * xmlRelaxNGCopyValidState:
1098  * @ctxt:  a Relax-NG validation context
1099  * @state:  a validation state
1100  *
1101  * Copy the validation state
1102  *
1103  * Returns the newly allocated structure or NULL in case or error
1104  */
1105 static xmlRelaxNGValidStatePtr
1106 xmlRelaxNGCopyValidState(xmlRelaxNGValidCtxtPtr ctxt,
1107                          xmlRelaxNGValidStatePtr state)
1108 {
1109     xmlRelaxNGValidStatePtr ret;
1110     unsigned int maxAttrs;
1111     xmlAttrPtr *attrs;
1112
1113     if (state == NULL)
1114         return(NULL);
1115     if ((ctxt->freeState != NULL) && 
1116         (ctxt->freeState->nbState > 0)) {
1117         ctxt->freeState->nbState--;
1118         ret = ctxt->freeState->tabState[ctxt->freeState->nbState];
1119     } else {
1120         ret = (xmlRelaxNGValidStatePtr) xmlMalloc(sizeof(xmlRelaxNGValidState));
1121         if (ret == NULL) {
1122             if ((ctxt != NULL) && (ctxt->error != NULL))
1123                 ctxt->error(ctxt->userData, "Out of memory\n");
1124             return (NULL);
1125         }
1126         memset(ret, 0, sizeof(xmlRelaxNGValidState));
1127     }
1128     attrs = ret->attrs;
1129     maxAttrs = ret->maxAttrs;
1130     memcpy(ret, state, sizeof(xmlRelaxNGValidState));
1131     ret->attrs = attrs;
1132     ret->maxAttrs = maxAttrs;
1133     if (state->nbAttrs > 0) {
1134         if (ret->attrs == NULL) {
1135             ret->maxAttrs = state->maxAttrs;
1136             ret->attrs = (xmlAttrPtr *) xmlMalloc(ret->maxAttrs *
1137                                                 sizeof(xmlAttrPtr));
1138             if (ret->attrs == NULL) {
1139                 if ((ctxt != NULL) && (ctxt->error != NULL))
1140                     ctxt->error(ctxt->userData, "Out of memory\n");
1141                 ret->nbAttrs = 0;
1142                 return (ret);
1143             }
1144         } else if (ret->maxAttrs < state->nbAttrs) {
1145             xmlAttrPtr *tmp;
1146
1147             tmp = (xmlAttrPtr *) xmlRealloc(ret->attrs, state->maxAttrs *
1148                                           sizeof(xmlAttrPtr));
1149             if (tmp == NULL) {
1150                 if ((ctxt != NULL) && (ctxt->error != NULL))
1151                     ctxt->error(ctxt->userData, "Out of memory\n");
1152                 ret->nbAttrs = 0;
1153                 return (ret);
1154             }
1155             ret->maxAttrs = state->maxAttrs;
1156         }
1157         memcpy(ret->attrs, state->attrs, state->nbAttrs * sizeof(xmlAttrPtr));
1158     }
1159     return(ret);
1160 }
1161
1162 /**
1163  * xmlRelaxNGEqualValidState:
1164  * @ctxt:  a Relax-NG validation context
1165  * @state1:  a validation state
1166  * @state2:  a validation state
1167  *
1168  * Compare the validation states for equality
1169  *
1170  * Returns 1 if equald, 0 otherwise
1171  */
1172 static int
1173 xmlRelaxNGEqualValidState(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
1174                          xmlRelaxNGValidStatePtr state1,
1175                          xmlRelaxNGValidStatePtr state2)
1176 {
1177     int i;
1178
1179     if ((state1 == NULL) || (state2 == NULL))
1180         return(0);
1181     if (state1 == state2)
1182         return(1);
1183     if (state1->node != state2->node)
1184         return(0);
1185     if (state1->seq != state2->seq)
1186         return(0);
1187     if (state1->nbAttrLeft != state2->nbAttrLeft)
1188         return(0);
1189     if (state1->nbAttrs != state2->nbAttrs)
1190         return(0);
1191     if (state1->endvalue != state2->endvalue)
1192         return(0);
1193     if ((state1->value != state2->value) &&
1194         (!xmlStrEqual(state1->value, state2->value)))
1195         return(0);
1196     for (i = 0;i < state1->nbAttrs;i++) {
1197         if (state1->attrs[i] != state2->attrs[i])
1198             return(0);
1199     }
1200     return(1);
1201 }
1202
1203 /**
1204  * xmlRelaxNGFreeValidState:
1205  * @state:  a validation state structure
1206  *
1207  * Deallocate a RelaxNG validation state structure.
1208  */
1209 static void
1210 xmlRelaxNGFreeValidState(xmlRelaxNGValidCtxtPtr ctxt,
1211                          xmlRelaxNGValidStatePtr state)
1212 {
1213     if (state == NULL)
1214         return;
1215
1216     if ((ctxt != NULL) && (ctxt->freeState == NULL)) {
1217         ctxt->freeState = xmlRelaxNGNewStates(ctxt, 40);
1218     }
1219     if ((ctxt == NULL) || (ctxt->freeState == NULL)) {
1220         if (state->attrs != NULL)
1221             xmlFree(state->attrs);
1222         xmlFree(state);
1223     } else {
1224         xmlRelaxNGAddStatesUniq(ctxt, ctxt->freeState, state);
1225     }
1226 }
1227
1228 /************************************************************************
1229  *                                                                      *
1230  *                      Document functions                                      *
1231  *                                                                      *
1232  ************************************************************************/
1233 static xmlDocPtr xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt,
1234                                       xmlDocPtr doc);
1235
1236 /**
1237  * xmlRelaxNGIncludePush:
1238  * @ctxt:  the parser context
1239  * @value:  the element doc
1240  *
1241  * Pushes a new include on top of the include stack
1242  *
1243  * Returns 0 in case of error, the index in the stack otherwise
1244  */
1245 static int
1246 xmlRelaxNGIncludePush(xmlRelaxNGParserCtxtPtr ctxt,
1247                        xmlRelaxNGIncludePtr value)
1248 {
1249     if (ctxt->incTab == NULL) {
1250         ctxt->incMax = 4;
1251         ctxt->incNr = 0;
1252         ctxt->incTab = (xmlRelaxNGIncludePtr *) xmlMalloc(
1253                         ctxt->incMax * sizeof(ctxt->incTab[0]));
1254         if (ctxt->incTab == NULL) {
1255             xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
1256             return (0);
1257         }
1258     }
1259     if (ctxt->incNr >= ctxt->incMax) {
1260         ctxt->incMax *= 2;
1261         ctxt->incTab =
1262             (xmlRelaxNGIncludePtr *) xmlRealloc(ctxt->incTab,
1263                                       ctxt->incMax *
1264                                       sizeof(ctxt->incTab[0]));
1265         if (ctxt->incTab == NULL) {
1266             xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
1267             return (0);
1268         }
1269     }
1270     ctxt->incTab[ctxt->incNr] = value;
1271     ctxt->inc = value;
1272     return (ctxt->incNr++);
1273 }
1274
1275 /**
1276  * xmlRelaxNGIncludePop:
1277  * @ctxt: the parser context
1278  *
1279  * Pops the top include from the include stack
1280  *
1281  * Returns the include just removed
1282  */
1283 static xmlRelaxNGIncludePtr
1284 xmlRelaxNGIncludePop(xmlRelaxNGParserCtxtPtr ctxt)
1285 {
1286     xmlRelaxNGIncludePtr ret;
1287
1288     if (ctxt->incNr <= 0)
1289         return (0);
1290     ctxt->incNr--;
1291     if (ctxt->incNr > 0)
1292         ctxt->inc = ctxt->incTab[ctxt->incNr - 1];
1293     else
1294         ctxt->inc = NULL;
1295     ret = ctxt->incTab[ctxt->incNr];
1296     ctxt->incTab[ctxt->incNr] = 0;
1297     return (ret);
1298 }
1299
1300 /**
1301  * xmlRelaxNGRemoveRedefine:
1302  * @ctxt: the parser context
1303  * @URL:  the normalized URL
1304  * @target:  the included target
1305  * @name:  the define name to eliminate
1306  *
1307  * Applies the elimination algorithm of 4.7
1308  *
1309  * Returns 0 in case of error, 1 in case of success.
1310  */
1311 static int
1312 xmlRelaxNGRemoveRedefine(xmlRelaxNGParserCtxtPtr ctxt,
1313                          const xmlChar *URL ATTRIBUTE_UNUSED,
1314                          xmlNodePtr target, const xmlChar *name) {
1315     int found = 0;
1316     xmlNodePtr tmp, tmp2;
1317     xmlChar *name2;
1318
1319 #ifdef DEBUG_INCLUDE
1320     if (name == NULL)
1321         xmlGenericError(xmlGenericErrorContext,
1322                     "Elimination of <include> start from %s\n", URL);
1323     else
1324         xmlGenericError(xmlGenericErrorContext,
1325                 "Elimination of <include> define %s from %s\n", name, URL);
1326 #endif
1327     tmp = target;
1328     while (tmp != NULL) {
1329         tmp2 = tmp->next;
1330         if ((name == NULL) && (IS_RELAXNG(tmp, "start"))) {
1331             found = 1;
1332             xmlUnlinkNode(tmp);
1333             xmlFreeNode(tmp);
1334         } else if ((name != NULL) && (IS_RELAXNG(tmp, "define"))) {
1335             name2 = xmlGetProp(tmp, BAD_CAST "name");
1336             xmlRelaxNGNormExtSpace(name2);
1337             if (name2 != NULL) {
1338                 if (xmlStrEqual(name, name2)) {
1339                     found = 1;
1340                     xmlUnlinkNode(tmp);
1341                     xmlFreeNode(tmp);
1342                 }
1343                 xmlFree(name2);
1344             }
1345         } else if (IS_RELAXNG(tmp, "include")) {
1346             xmlChar *href = NULL;
1347             xmlRelaxNGDocumentPtr inc = tmp->_private;
1348
1349             if ((inc != NULL) && (inc->doc != NULL) &&
1350                 (inc->doc->children != NULL)) {
1351
1352                 if (xmlStrEqual(inc->doc->children->name, BAD_CAST "grammar")) {
1353 #ifdef DEBUG_INCLUDE
1354                     href = xmlGetProp(tmp, BAD_CAST "href");
1355 #endif
1356                     if (xmlRelaxNGRemoveRedefine(ctxt, href,
1357                                 inc->doc->children->children, name) == 1) {
1358                         found = 1;
1359                     }
1360                     if (href != NULL)
1361                         xmlFree(href);
1362                 }
1363             }
1364         }
1365         tmp = tmp2;
1366     }
1367     return(found);
1368 }
1369
1370 /**
1371  * xmlRelaxNGLoadInclude:
1372  * @ctxt: the parser context
1373  * @URL:  the normalized URL
1374  * @node: the include node.
1375  * @ns:  the namespace passed from the context.
1376  *
1377  * First lookup if the document is already loaded into the parser context,
1378  * check against recursion. If not found the resource is loaded and
1379  * the content is preprocessed before being returned back to the caller.
1380  *
1381  * Returns the xmlRelaxNGIncludePtr or NULL in case of error
1382  */
1383 static xmlRelaxNGIncludePtr
1384 xmlRelaxNGLoadInclude(xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *URL,
1385                       xmlNodePtr node, const xmlChar *ns) {
1386     xmlRelaxNGIncludePtr ret = NULL;
1387     xmlDocPtr doc;
1388     int i;
1389     xmlNodePtr root, cur;
1390
1391 #ifdef DEBUG_INCLUDE
1392     xmlGenericError(xmlGenericErrorContext,
1393                     "xmlRelaxNGLoadInclude(%s)\n", URL);
1394 #endif
1395
1396     /*
1397      * check against recursion in the stack
1398      */
1399     for (i = 0;i < ctxt->incNr;i++) {
1400         if (xmlStrEqual(ctxt->incTab[i]->href, URL)) {
1401             if (ctxt->error != NULL)
1402                 ctxt->error(ctxt->userData,
1403                     "Detected an Include recursion for %s\n",
1404                             URL);
1405             ctxt->nbErrors++;
1406             return(NULL);
1407         }
1408     }
1409
1410     /*
1411      * load the document
1412      */
1413     doc = xmlParseFile((const char *) URL);
1414     if (doc == NULL) {
1415         if (ctxt->error != NULL)
1416             ctxt->error(ctxt->userData,
1417                         "xmlRelaxNG: could not load %s\n", URL);
1418         ctxt->nbErrors++;
1419         return (NULL);
1420     }
1421
1422 #ifdef DEBUG_INCLUDE
1423     xmlGenericError(xmlGenericErrorContext,
1424                     "Parsed %s Okay\n", URL);
1425 #endif
1426
1427     /*
1428      * Allocate the document structures and register it first.
1429      */
1430     ret = (xmlRelaxNGIncludePtr) xmlMalloc(sizeof(xmlRelaxNGInclude));
1431     if (ret == NULL) {
1432         if (ctxt->error != NULL)
1433             ctxt->error(ctxt->userData,
1434                         "xmlRelaxNG: allocate memory for doc %s\n", URL);
1435         ctxt->nbErrors++;
1436         xmlFreeDoc(doc);
1437         return (NULL);
1438     }
1439     memset(ret, 0, sizeof(xmlRelaxNGInclude));
1440     ret->doc = doc;
1441     ret->href = xmlStrdup(URL);
1442     ret->next = ctxt->includes;
1443     ctxt->includes = ret;
1444
1445     /*
1446      * transmit the ns if needed
1447      */
1448     if (ns != NULL) {
1449         root = xmlDocGetRootElement(doc);
1450         if (root != NULL) {
1451             if (xmlHasProp(root, BAD_CAST"ns") == NULL) {
1452                 xmlSetProp(root, BAD_CAST"ns", ns);
1453             }
1454         }
1455     }
1456
1457     /*
1458      * push it on the stack
1459      */
1460     xmlRelaxNGIncludePush(ctxt, ret);
1461
1462     /*
1463      * Some preprocessing of the document content, this include recursing
1464      * in the include stack.
1465      */
1466 #ifdef DEBUG_INCLUDE
1467     xmlGenericError(xmlGenericErrorContext,
1468                     "cleanup of %s\n", URL);
1469 #endif
1470
1471     doc = xmlRelaxNGCleanupDoc(ctxt, doc);
1472     if (doc == NULL) {
1473         ctxt->inc = NULL;
1474         return(NULL);
1475     }
1476
1477     /*
1478      * Pop up the include from the stack
1479      */
1480     xmlRelaxNGIncludePop(ctxt);
1481
1482 #ifdef DEBUG_INCLUDE
1483     xmlGenericError(xmlGenericErrorContext,
1484                     "Checking of %s\n", URL);
1485 #endif
1486     /*
1487      * Check that the top element is a grammar
1488      */
1489     root = xmlDocGetRootElement(doc);
1490     if (root == NULL) {
1491         if (ctxt->error != NULL)
1492             ctxt->error(ctxt->userData,
1493                         "xmlRelaxNG: included document is empty %s\n", URL);
1494         ctxt->nbErrors++;
1495         return (NULL);
1496     }
1497     if (!IS_RELAXNG(root, "grammar")) {
1498         if (ctxt->error != NULL)
1499             ctxt->error(ctxt->userData,
1500                     "xmlRelaxNG: included document %s root is not a grammar\n",
1501                         URL);
1502         ctxt->nbErrors++;
1503         return (NULL);
1504     }
1505
1506     /*
1507      * Elimination of redefined rules in the include.
1508      */
1509     cur = node->children;
1510     while (cur != NULL) {
1511         if (IS_RELAXNG(cur, "start")) {
1512             int found = 0;
1513
1514             found = xmlRelaxNGRemoveRedefine(ctxt, URL, root->children, NULL);
1515             if (!found) {
1516                 if (ctxt->error != NULL)
1517                     ctxt->error(ctxt->userData,
1518         "xmlRelaxNG: include %s has a start but not the included grammar\n",
1519                                 URL);
1520                 ctxt->nbErrors++;
1521             }
1522         } else if (IS_RELAXNG(cur, "define")) {
1523             xmlChar *name;
1524
1525             name = xmlGetProp(cur, BAD_CAST "name");
1526             if (name == NULL) {
1527                 if (ctxt->error != NULL)
1528                     ctxt->error(ctxt->userData,
1529                             "xmlRelaxNG: include %s has define without name\n",
1530                                 URL);
1531                 ctxt->nbErrors++;
1532             } else {
1533                 int found;
1534
1535                 xmlRelaxNGNormExtSpace(name);
1536                 found = xmlRelaxNGRemoveRedefine(ctxt, URL,
1537                                                  root->children, name);
1538                 if (!found) {
1539                     if (ctxt->error != NULL)
1540                         ctxt->error(ctxt->userData,
1541     "xmlRelaxNG: include %s has a define %s but not the included grammar\n",
1542                                     URL, name);
1543                     ctxt->nbErrors++;
1544                 }
1545                 xmlFree(name);
1546             }
1547         }
1548         cur = cur->next;
1549     }
1550
1551
1552     return(ret);
1553 }
1554
1555 /**
1556  * xmlRelaxNGValidErrorPush:
1557  * @ctxt:  the validation context
1558  * @err:  the error code
1559  * @arg1:  the first string argument
1560  * @arg2:  the second string argument
1561  * @dup:  arg need to be duplicated
1562  *
1563  * Pushes a new error on top of the error stack
1564  *
1565  * Returns 0 in case of error, the index in the stack otherwise
1566  */
1567 static int
1568 xmlRelaxNGValidErrorPush(xmlRelaxNGValidCtxtPtr ctxt, xmlRelaxNGValidErr err,
1569         const xmlChar *arg1, const xmlChar *arg2, int dup)
1570 {
1571     xmlRelaxNGValidErrorPtr cur;
1572 #ifdef DEBUG_ERROR
1573     xmlGenericError(xmlGenericErrorContext,
1574             "Pushing error %d at %d on stack\n", err, ctxt->errNr);
1575 #endif
1576     if (ctxt->errTab == NULL) {
1577         ctxt->errMax = 8;
1578         ctxt->errNr = 0;
1579         ctxt->errTab = (xmlRelaxNGValidErrorPtr) xmlMalloc(
1580                         ctxt->errMax * sizeof(xmlRelaxNGValidError));
1581         if (ctxt->errTab == NULL) {
1582             xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
1583             return (0);
1584         }
1585         ctxt->err = NULL;
1586     }
1587     if (ctxt->errNr >= ctxt->errMax) {
1588         ctxt->errMax *= 2;
1589         ctxt->errTab =
1590             (xmlRelaxNGValidErrorPtr) xmlRealloc(ctxt->errTab,
1591                             ctxt->errMax * sizeof(xmlRelaxNGValidError));
1592         if (ctxt->errTab == NULL) {
1593             xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
1594             return (0);
1595         }
1596         ctxt->err = &ctxt->errTab[ctxt->errNr - 1];
1597     }
1598     if ((ctxt->err != NULL) && (ctxt->state != NULL) &&
1599         (ctxt->err->node == ctxt->state->node) &&
1600         (ctxt->err->err == err))
1601         return(ctxt->errNr);
1602     cur = &ctxt->errTab[ctxt->errNr];
1603     cur->err = err;
1604     if (dup) {
1605         cur->arg1 = xmlStrdup(arg1);
1606         cur->arg2 = xmlStrdup(arg2);
1607         cur->flags = ERROR_IS_DUP;
1608     } else {
1609         cur->arg1 = arg1;
1610         cur->arg2 = arg2;
1611         cur->flags = 0;
1612     }
1613     if (ctxt->state != NULL) {
1614         cur->node = ctxt->state->node;
1615         cur->seq = ctxt->state->seq;
1616     } else {
1617         cur->node = NULL;
1618         cur->seq = NULL;
1619     }
1620     ctxt->err = cur;
1621     return (ctxt->errNr++);
1622 }
1623
1624 /**
1625  * xmlRelaxNGValidErrorPop:
1626  * @ctxt: the validation context
1627  *
1628  * Pops the top error from the error stack
1629  */
1630 static void
1631 xmlRelaxNGValidErrorPop(xmlRelaxNGValidCtxtPtr ctxt)
1632 {
1633     xmlRelaxNGValidErrorPtr cur;
1634
1635     if (ctxt->errNr <= 0) {
1636         ctxt->err = NULL;
1637         return;
1638     }
1639     ctxt->errNr--;
1640     if (ctxt->errNr > 0)
1641         ctxt->err = &ctxt->errTab[ctxt->errNr - 1];
1642     else
1643         ctxt->err = NULL;
1644     cur = &ctxt->errTab[ctxt->errNr];
1645     if (cur->flags & ERROR_IS_DUP) {
1646         if (cur->arg1 != NULL)
1647             xmlFree((xmlChar *)cur->arg1);
1648         cur->arg1 = NULL;
1649         if (cur->arg2 != NULL)
1650             xmlFree((xmlChar *)cur->arg2);
1651         cur->arg2 = NULL;
1652         cur->flags = 0;
1653     }
1654 }
1655
1656 /**
1657  * xmlRelaxNGDocumentPush:
1658  * @ctxt:  the parser context
1659  * @value:  the element doc
1660  *
1661  * Pushes a new doc on top of the doc stack
1662  *
1663  * Returns 0 in case of error, the index in the stack otherwise
1664  */
1665 static int
1666 xmlRelaxNGDocumentPush(xmlRelaxNGParserCtxtPtr ctxt,
1667                        xmlRelaxNGDocumentPtr value)
1668 {
1669     if (ctxt->docTab == NULL) {
1670         ctxt->docMax = 4;
1671         ctxt->docNr = 0;
1672         ctxt->docTab = (xmlRelaxNGDocumentPtr *) xmlMalloc(
1673                         ctxt->docMax * sizeof(ctxt->docTab[0]));
1674         if (ctxt->docTab == NULL) {
1675             xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
1676             return (0);
1677         }
1678     }
1679     if (ctxt->docNr >= ctxt->docMax) {
1680         ctxt->docMax *= 2;
1681         ctxt->docTab =
1682             (xmlRelaxNGDocumentPtr *) xmlRealloc(ctxt->docTab,
1683                                       ctxt->docMax *
1684                                       sizeof(ctxt->docTab[0]));
1685         if (ctxt->docTab == NULL) {
1686             xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
1687             return (0);
1688         }
1689     }
1690     ctxt->docTab[ctxt->docNr] = value;
1691     ctxt->doc = value;
1692     return (ctxt->docNr++);
1693 }
1694
1695 /**
1696  * xmlRelaxNGDocumentPop:
1697  * @ctxt: the parser context
1698  *
1699  * Pops the top doc from the doc stack
1700  *
1701  * Returns the doc just removed
1702  */
1703 static xmlRelaxNGDocumentPtr
1704 xmlRelaxNGDocumentPop(xmlRelaxNGParserCtxtPtr ctxt)
1705 {
1706     xmlRelaxNGDocumentPtr ret;
1707
1708     if (ctxt->docNr <= 0)
1709         return (0);
1710     ctxt->docNr--;
1711     if (ctxt->docNr > 0)
1712         ctxt->doc = ctxt->docTab[ctxt->docNr - 1];
1713     else
1714         ctxt->doc = NULL;
1715     ret = ctxt->docTab[ctxt->docNr];
1716     ctxt->docTab[ctxt->docNr] = 0;
1717     return (ret);
1718 }
1719
1720 /**
1721  * xmlRelaxNGLoadExternalRef:
1722  * @ctxt: the parser context
1723  * @URL:  the normalized URL
1724  * @ns:  the inherited ns if any
1725  *
1726  * First lookup if the document is already loaded into the parser context,
1727  * check against recursion. If not found the resource is loaded and
1728  * the content is preprocessed before being returned back to the caller.
1729  *
1730  * Returns the xmlRelaxNGDocumentPtr or NULL in case of error
1731  */
1732 static xmlRelaxNGDocumentPtr
1733 xmlRelaxNGLoadExternalRef(xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *URL,
1734                        const xmlChar *ns) {
1735     xmlRelaxNGDocumentPtr ret = NULL;
1736     xmlDocPtr doc;
1737     xmlNodePtr root;
1738     int i;
1739
1740     /*
1741      * check against recursion in the stack
1742      */
1743     for (i = 0;i < ctxt->docNr;i++) {
1744         if (xmlStrEqual(ctxt->docTab[i]->href, URL)) {
1745             if (ctxt->error != NULL)
1746                 ctxt->error(ctxt->userData,
1747                     "Detected an externalRef recursion for %s\n",
1748                             URL);
1749             ctxt->nbErrors++;
1750             return(NULL);
1751         }
1752     }
1753
1754     /*
1755      * load the document
1756      */
1757     doc = xmlParseFile((const char *) URL);
1758     if (doc == NULL) {
1759         if (ctxt->error != NULL)
1760             ctxt->error(ctxt->userData,
1761                         "xmlRelaxNG: could not load %s\n", URL);
1762         ctxt->nbErrors++;
1763         return (NULL);
1764     }
1765
1766     /*
1767      * Allocate the document structures and register it first.
1768      */
1769     ret = (xmlRelaxNGDocumentPtr) xmlMalloc(sizeof(xmlRelaxNGDocument));
1770     if (ret == NULL) {
1771         if (ctxt->error != NULL)
1772             ctxt->error(ctxt->userData,
1773                         "xmlRelaxNG: allocate memory for doc %s\n", URL);
1774         ctxt->nbErrors++;
1775         xmlFreeDoc(doc);
1776         return (NULL);
1777     }
1778     memset(ret, 0, sizeof(xmlRelaxNGDocument));
1779     ret->doc = doc;
1780     ret->href = xmlStrdup(URL);
1781     ret->next = ctxt->documents;
1782     ctxt->documents = ret;
1783
1784     /*
1785      * transmit the ns if needed
1786      */
1787     if (ns != NULL) {
1788         root = xmlDocGetRootElement(doc);
1789         if (root != NULL) {
1790             if (xmlHasProp(root, BAD_CAST"ns") == NULL) {
1791                 xmlSetProp(root, BAD_CAST"ns", ns);
1792             }
1793         }
1794     }
1795
1796     /*
1797      * push it on the stack and register it in the hash table
1798      */
1799     xmlRelaxNGDocumentPush(ctxt, ret);
1800
1801     /*
1802      * Some preprocessing of the document content
1803      */
1804     doc = xmlRelaxNGCleanupDoc(ctxt, doc);
1805     if (doc == NULL) {
1806         ctxt->doc = NULL;
1807         return(NULL);
1808     }
1809
1810     xmlRelaxNGDocumentPop(ctxt);
1811
1812     return(ret);
1813 }
1814
1815 /************************************************************************
1816  *                                                                      *
1817  *                      Error functions                                 *
1818  *                                                                      *
1819  ************************************************************************/
1820
1821 #define VALID_ERR(a) xmlRelaxNGAddValidError(ctxt, a, NULL, NULL, 0);
1822 #define VALID_ERR2(a, b) xmlRelaxNGAddValidError(ctxt, a, b, NULL, 0);
1823 #define VALID_ERR3(a, b, c) xmlRelaxNGAddValidError(ctxt, a, b, c, 0);
1824 #define VALID_ERR2P(a, b) xmlRelaxNGAddValidError(ctxt, a, b, NULL, 1);
1825 #define VALID_ERR3P(a, b, c) xmlRelaxNGAddValidError(ctxt, a, b, c, 1);
1826
1827 static const char *
1828 xmlRelaxNGDefName(xmlRelaxNGDefinePtr def) {
1829     if (def == NULL)
1830         return("none");
1831     switch(def->type) {
1832         case XML_RELAXNG_EMPTY: return("empty");
1833         case XML_RELAXNG_NOT_ALLOWED: return("notAllowed");
1834         case XML_RELAXNG_EXCEPT: return("except");
1835         case XML_RELAXNG_TEXT: return("text");
1836         case XML_RELAXNG_ELEMENT: return("element");
1837         case XML_RELAXNG_DATATYPE: return("datatype");
1838         case XML_RELAXNG_VALUE: return("value");
1839         case XML_RELAXNG_LIST: return("list");
1840         case XML_RELAXNG_ATTRIBUTE: return("attribute");
1841         case XML_RELAXNG_DEF: return("def");
1842         case XML_RELAXNG_REF: return("ref");
1843         case XML_RELAXNG_EXTERNALREF: return("externalRef");
1844         case XML_RELAXNG_PARENTREF: return("parentRef");
1845         case XML_RELAXNG_OPTIONAL: return("optional");
1846         case XML_RELAXNG_ZEROORMORE: return("zeroOrMore");
1847         case XML_RELAXNG_ONEORMORE: return("oneOrMore");
1848         case XML_RELAXNG_CHOICE: return("choice");
1849         case XML_RELAXNG_GROUP: return("group");
1850         case XML_RELAXNG_INTERLEAVE: return("interleave");
1851         case XML_RELAXNG_START: return("start");
1852         case XML_RELAXNG_NOOP: return("noop");
1853         case XML_RELAXNG_PARAM: return("param");
1854     }
1855     return("unknown");
1856 }
1857
1858 /**
1859  * xmlRelaxNGGetErrorString:
1860  * @err:  the error code
1861  * @arg1:  the first string argument
1862  * @arg2:  the second string argument
1863  *
1864  * computes a formatted error string for the given error code and args
1865  *
1866  * Returns the error string, it must be deallocated by the caller
1867  */
1868 static xmlChar *
1869 xmlRelaxNGGetErrorString(xmlRelaxNGValidErr err, const xmlChar *arg1,
1870                          const xmlChar *arg2) {
1871     char msg[1000];
1872
1873     if (arg1 == NULL)
1874         arg1 = BAD_CAST "";
1875     if (arg2 == NULL)
1876         arg2 = BAD_CAST "";
1877
1878     msg[0] = 0;
1879     switch (err) {
1880         case XML_RELAXNG_OK:
1881             return(NULL);
1882         case XML_RELAXNG_ERR_MEMORY:
1883             return(xmlCharStrdup("out of memory"));
1884         case XML_RELAXNG_ERR_TYPE:
1885             snprintf(msg, 1000, "failed to validate type %s", arg1);
1886             break;
1887         case XML_RELAXNG_ERR_TYPEVAL:
1888             snprintf(msg, 1000, "Type %s doesn't allow value '%s'", arg1, arg2);
1889             break;
1890         case XML_RELAXNG_ERR_DUPID:
1891             snprintf(msg, 1000, "ID %s redefined", arg1);
1892             break;
1893         case XML_RELAXNG_ERR_TYPECMP:
1894             snprintf(msg, 1000, "failed to compare type %s", arg1);
1895             break;
1896         case XML_RELAXNG_ERR_NOSTATE:
1897             return(xmlCharStrdup("Internal error: no state"));
1898         case XML_RELAXNG_ERR_NODEFINE:
1899             return(xmlCharStrdup("Internal error: no define"));
1900         case XML_RELAXNG_ERR_INTERNAL:
1901             snprintf(msg, 1000, "Internal error: %s", arg1);
1902             break;
1903         case XML_RELAXNG_ERR_LISTEXTRA:
1904             snprintf(msg, 1000, "Extra data in list: %s", arg1);
1905             break;
1906         case XML_RELAXNG_ERR_INTERNODATA:
1907             return(xmlCharStrdup("Internal: interleave block has no data"));
1908         case XML_RELAXNG_ERR_INTERSEQ:
1909             return(xmlCharStrdup("Invalid sequence in interleave"));
1910         case XML_RELAXNG_ERR_INTEREXTRA:
1911             snprintf(msg, 1000, "Extra element %s in interleave", arg1);
1912             break;
1913         case XML_RELAXNG_ERR_ELEMNAME:
1914             snprintf(msg, 1000, "Expecting element %s, got %s", arg1, arg2);
1915             break;
1916         case XML_RELAXNG_ERR_ELEMNONS:
1917             snprintf(msg, 1000, "Expecting a namespace for element %s", arg1);
1918             break;
1919         case XML_RELAXNG_ERR_ELEMWRONGNS:
1920             snprintf(msg, 1000, "Element %s has wrong namespace: expecting %s",
1921                      arg1, arg2);
1922             break;
1923         case XML_RELAXNG_ERR_ELEMWRONG:
1924             snprintf(msg, 1000, "Did not expect element %s there",
1925                      arg1);
1926             break;
1927         case XML_RELAXNG_ERR_TEXTWRONG:
1928             snprintf(msg, 1000, "Did not expect text in element %s content",
1929                      arg1);
1930             break;
1931         case XML_RELAXNG_ERR_ELEMEXTRANS:
1932             snprintf(msg, 1000, "Expecting no namespace for element %s", arg1);
1933             break;
1934         case XML_RELAXNG_ERR_ELEMNOTEMPTY:
1935             snprintf(msg, 1000, "Expecting element %s to be empty", arg1);
1936             break;
1937         case XML_RELAXNG_ERR_NOELEM:
1938             snprintf(msg, 1000, "Expecting an element %s, got nothing", arg1);
1939             break;
1940         case XML_RELAXNG_ERR_NOTELEM:
1941             return(xmlCharStrdup("Expecting an element got text"));
1942         case XML_RELAXNG_ERR_ATTRVALID:
1943             snprintf(msg, 1000, "Element %s failed to validate attributes",
1944                      arg1);
1945             break;
1946         case XML_RELAXNG_ERR_CONTENTVALID:
1947             snprintf(msg, 1000, "Element %s failed to validate content",
1948                      arg1);
1949             break;
1950         case XML_RELAXNG_ERR_EXTRACONTENT:
1951             snprintf(msg, 1000, "Element %s has extra content: %s",
1952                      arg1, arg2);
1953             break;
1954         case XML_RELAXNG_ERR_INVALIDATTR:
1955             snprintf(msg, 1000, "Invalid attribute %s for element %s",
1956                      arg1, arg2);
1957             break;
1958         case XML_RELAXNG_ERR_LACKDATA:
1959             snprintf(msg, 1000, "Datatype element %s contains no data",
1960                      arg1);
1961             break;
1962         case XML_RELAXNG_ERR_DATAELEM:
1963             snprintf(msg, 1000, "Datatype element %s has child elements",
1964                      arg1);
1965             break;
1966         case XML_RELAXNG_ERR_VALELEM:
1967             snprintf(msg, 1000, "Value element %s has child elements",
1968                      arg1);
1969             break;
1970         case XML_RELAXNG_ERR_LISTELEM:
1971             snprintf(msg, 1000, "List element %s has child elements",
1972                      arg1);
1973             break;
1974         case XML_RELAXNG_ERR_DATATYPE:
1975             snprintf(msg, 1000, "Error validating datatype %s",
1976                      arg1);
1977             break;
1978         case XML_RELAXNG_ERR_VALUE:
1979             snprintf(msg, 1000, "Error validating value %s",
1980                      arg1);
1981             break;
1982         case XML_RELAXNG_ERR_LIST:
1983             return(xmlCharStrdup("Error validating list"));
1984         case XML_RELAXNG_ERR_NOGRAMMAR:
1985             return(xmlCharStrdup("No top grammar defined"));
1986         case XML_RELAXNG_ERR_EXTRADATA:
1987             return(xmlCharStrdup("Extra data in the document"));
1988         default:
1989             return(xmlCharStrdup("Unknown error !"));
1990     }
1991     if (msg[0] == 0) {
1992         snprintf(msg, 1000, "Unknown error code %d", err);
1993     }
1994     msg[1000 - 1] = 0;
1995     return(xmlStrdup((xmlChar *) msg));
1996 }
1997
1998 /**
1999  * xmlRelaxNGValidErrorContext:
2000  * @ctxt:  the validation context
2001  * @node:  the node
2002  * @child:  the node child generating the problem.
2003  *
2004  * Dump informations about the kocation of the error in the instance
2005  */
2006 static void
2007 xmlRelaxNGValidErrorContext(xmlRelaxNGValidCtxtPtr ctxt, xmlNodePtr node,
2008                             xmlNodePtr child)
2009 {
2010     int line = 0;
2011     const xmlChar *file = NULL;
2012     const xmlChar *name = NULL;
2013     const char *type = "error";
2014
2015     if ((ctxt == NULL) || (ctxt->error == NULL))
2016         return;
2017
2018     if (child != NULL)
2019         node = child;
2020
2021     if (node != NULL)  {
2022         if ((node->type == XML_DOCUMENT_NODE) ||
2023             (node->type == XML_HTML_DOCUMENT_NODE)) {
2024             xmlDocPtr doc = (xmlDocPtr) node;
2025
2026             file = doc->URL;
2027         } else {
2028             /*
2029              * Try to find contextual informations to report
2030              */
2031             if (node->type == XML_ELEMENT_NODE) {
2032                 line = (long) node->content;
2033             } else if ((node->prev != NULL) &&
2034                        (node->prev->type == XML_ELEMENT_NODE)) {
2035                 line = (long) node->prev->content;
2036             } else if ((node->parent != NULL) &&
2037                        (node->parent->type == XML_ELEMENT_NODE)) {
2038                 line = (long) node->parent->content;
2039             }
2040             if ((node->doc != NULL) && (node->doc->URL != NULL))
2041                 file = node->doc->URL;
2042             if (node->name != NULL)
2043                 name = node->name;
2044         }
2045     } 
2046     
2047     type = "RNG validity error";
2048
2049     if ((file != NULL) && (line != 0) && (name != NULL))
2050         ctxt->error(ctxt->userData, "%s: file %s line %d element %s\n",
2051                 type, file, line, name);
2052     else if ((file != NULL) && (name != NULL))
2053         ctxt->error(ctxt->userData, "%s: file %s element %s\n",
2054                 type, file, name);
2055     else if ((file != NULL) && (line != 0))
2056         ctxt->error(ctxt->userData, "%s: file %s line %d\n", type, file, line);
2057     else if (file != NULL)
2058         ctxt->error(ctxt->userData, "%s: file %s\n", type, file);
2059     else if (name != NULL)
2060         ctxt->error(ctxt->userData, "%s: element %s\n", type, name);
2061     else
2062         ctxt->error(ctxt->userData, "%s\n", type);
2063 }
2064
2065 /**
2066  * xmlRelaxNGShowValidError:
2067  * @ctxt:  the validation context
2068  * @err:  the error number
2069  * @node:  the node
2070  * @child:  the node child generating the problem.
2071  * @arg1:  the first argument
2072  * @arg2:  the second argument
2073  *
2074  * Show a validation error.
2075  */
2076 static void
2077 xmlRelaxNGShowValidError(xmlRelaxNGValidCtxtPtr ctxt, xmlRelaxNGValidErr err,
2078                          xmlNodePtr node, xmlNodePtr child,
2079                          const xmlChar *arg1, const xmlChar *arg2)
2080 {
2081     xmlChar *msg;
2082
2083     if (ctxt->error == NULL)
2084         return;
2085
2086 #ifdef DEBUG_ERROR
2087     xmlGenericError(xmlGenericErrorContext,
2088             "Show error %d\n", err);
2089 #endif
2090     msg = xmlRelaxNGGetErrorString(err, arg1, arg2);
2091     if (msg == NULL)
2092         return;
2093
2094     if (ctxt->errNo == XML_RELAXNG_OK)
2095         ctxt->errNo = err;
2096     xmlRelaxNGValidErrorContext(ctxt, node, child);
2097     ctxt->error(ctxt->userData, "%s\n", msg);
2098     xmlFree(msg);
2099 }
2100
2101 /**
2102  * xmlRelaxNGPopErrors:
2103  * @ctxt:  the validation context
2104  * @level:  the error level in the stack
2105  *
2106  * pop and discard all errors until the given level is reached
2107  */
2108 static void
2109 xmlRelaxNGPopErrors(xmlRelaxNGValidCtxtPtr ctxt, int level) {
2110     int i;
2111     xmlRelaxNGValidErrorPtr err;
2112
2113 #ifdef DEBUG_ERROR
2114     xmlGenericError(xmlGenericErrorContext,
2115             "Pop errors till level %d\n", level);
2116 #endif
2117     for (i = level;i < ctxt->errNr;i++) {
2118         err = &ctxt->errTab[i];
2119         if (err->flags & ERROR_IS_DUP) {
2120             if (err->arg1 != NULL)
2121                 xmlFree((xmlChar *)err->arg1);
2122             err->arg1 = NULL;
2123             if (err->arg2 != NULL)
2124                 xmlFree((xmlChar *)err->arg2);
2125             err->arg2 = NULL;
2126             err->flags = 0;
2127         }
2128     }
2129     ctxt->errNr = level;
2130     if (ctxt->errNr <= 0)
2131         ctxt->err = NULL;
2132 }
2133 /**
2134  * xmlRelaxNGDumpValidError:
2135  * @ctxt:  the validation context
2136  *
2137  * Show all validation error over a given index.
2138  */
2139 static void
2140 xmlRelaxNGDumpValidError(xmlRelaxNGValidCtxtPtr ctxt) {
2141     int i, j, k;
2142     xmlRelaxNGValidErrorPtr err, dup;
2143
2144 #ifdef DEBUG_ERROR
2145     xmlGenericError(xmlGenericErrorContext,
2146             "Dumping error stack %d errors\n", ctxt->errNr);
2147 #endif
2148     for (i = 0, k = 0;i < ctxt->errNr;i++) {
2149         err = &ctxt->errTab[i];
2150         if (k < MAX_ERROR) {
2151             for (j = 0;j < i;j++) {
2152                 dup = &ctxt->errTab[j];
2153                 if ((err->err == dup->err) && (err->node == dup->node) &&
2154                     (xmlStrEqual(err->arg1, dup->arg1)) &&
2155                     (xmlStrEqual(err->arg2, dup->arg2))) {
2156                     goto skip;
2157                 }
2158             }
2159             xmlRelaxNGShowValidError(ctxt, err->err, err->node, err->seq,
2160                                      err->arg1, err->arg2);
2161             k++;
2162         }
2163 skip:
2164         if (err->flags & ERROR_IS_DUP) {
2165             if (err->arg1 != NULL)
2166                 xmlFree((xmlChar *)err->arg1);
2167             err->arg1 = NULL;
2168             if (err->arg2 != NULL)
2169                 xmlFree((xmlChar *)err->arg2);
2170             err->arg2 = NULL;
2171             err->flags = 0;
2172         }
2173     }
2174     ctxt->errNr = 0;
2175 }
2176 /**
2177  * xmlRelaxNGAddValidError:
2178  * @ctxt:  the validation context
2179  * @err:  the error number
2180  * @arg1:  the first argument
2181  * @arg2:  the second argument
2182  * @dup:  need to dup the args
2183  *
2184  * Register a validation error, either generating it if it's sure
2185  * or stacking it for later handling if unsure.
2186  */
2187 static void
2188 xmlRelaxNGAddValidError(xmlRelaxNGValidCtxtPtr ctxt, xmlRelaxNGValidErr err,
2189                         const xmlChar *arg1, const xmlChar *arg2, int dup)
2190 {
2191     if ((ctxt == NULL) || (ctxt->error == NULL))
2192         return;
2193
2194 #ifdef DEBUG_ERROR
2195     xmlGenericError(xmlGenericErrorContext,
2196             "Adding error %d\n", err);
2197 #endif
2198     /*
2199      * generate the error directly
2200      */
2201     if (((ctxt->flags & 1) == 0) || (ctxt->flags & 2)) {
2202         xmlNodePtr node, seq;
2203         /*
2204          * Flush first any stacked error which might be the
2205          * real cause of the problem.
2206          */
2207         if (ctxt->errNr != 0)
2208             xmlRelaxNGDumpValidError(ctxt);
2209         if (ctxt->state != NULL) {
2210             node = ctxt->state->node;
2211             seq = ctxt->state->seq;
2212         } else {
2213             node = seq = NULL;
2214         }
2215         xmlRelaxNGShowValidError(ctxt, err, node, seq, arg1, arg2);
2216     }
2217     /*
2218      * Stack the error for later processing if needed
2219      */
2220     else {
2221         xmlRelaxNGValidErrorPush(ctxt, err, arg1, arg2, dup);
2222     }
2223 }
2224
2225
2226 /************************************************************************
2227  *                                                                      *
2228  *                      Type library hooks                              *
2229  *                                                                      *
2230  ************************************************************************/
2231 static xmlChar *xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt,
2232                                     const xmlChar *str);
2233
2234 /**
2235  * xmlRelaxNGSchemaTypeHave:
2236  * @data:  data needed for the library
2237  * @type:  the type name
2238  *
2239  * Check if the given type is provided by
2240  * the W3C XMLSchema Datatype library.
2241  *
2242  * Returns 1 if yes, 0 if no and -1 in case of error.
2243  */
2244 static int
2245 xmlRelaxNGSchemaTypeHave(void *data ATTRIBUTE_UNUSED,
2246                          const xmlChar *type) {
2247     xmlSchemaTypePtr typ;
2248
2249     if (type == NULL)
2250         return(-1);
2251     typ = xmlSchemaGetPredefinedType(type, 
2252                BAD_CAST "http://www.w3.org/2001/XMLSchema");
2253     if (typ == NULL)
2254         return(0);
2255     return(1);
2256 }
2257
2258 /**
2259  * xmlRelaxNGSchemaTypeCheck:
2260  * @data:  data needed for the library
2261  * @type:  the type name
2262  * @value:  the value to check
2263  * @node:  the node
2264  *
2265  * Check if the given type and value are validated by
2266  * the W3C XMLSchema Datatype library.
2267  *
2268  * Returns 1 if yes, 0 if no and -1 in case of error.
2269  */
2270 static int
2271 xmlRelaxNGSchemaTypeCheck(void *data ATTRIBUTE_UNUSED,
2272                           const xmlChar *type,
2273                           const xmlChar *value,
2274                           void **result,
2275                           xmlNodePtr node) {
2276     xmlSchemaTypePtr typ;
2277     int ret;
2278
2279     if ((type == NULL) || (value == NULL))
2280         return(-1);
2281     typ = xmlSchemaGetPredefinedType(type, 
2282                BAD_CAST "http://www.w3.org/2001/XMLSchema");
2283     if (typ == NULL)
2284         return(-1);
2285     ret = xmlSchemaValPredefTypeNode(typ, value,
2286                                      (xmlSchemaValPtr *) result, node);
2287     if (ret == 2) /* special ID error code */
2288         return(2);
2289     if (ret == 0)
2290         return(1);
2291     if (ret > 0)
2292         return(0);
2293     return(-1);
2294 }
2295
2296 /**
2297  * xmlRelaxNGSchemaFacetCheck:
2298  * @data:  data needed for the library
2299  * @type:  the type name
2300  * @facet:  the facet name
2301  * @val:  the facet value
2302  * @strval:  the string value
2303  * @value:  the value to check
2304  *
2305  * Function provided by a type library to check a value facet
2306  *
2307  * Returns 1 if yes, 0 if no and -1 in case of error.
2308  */
2309 static int
2310 xmlRelaxNGSchemaFacetCheck (void *data ATTRIBUTE_UNUSED, const xmlChar *type,
2311                             const xmlChar *facetname, const xmlChar *val,
2312                             const xmlChar *strval, void *value) {
2313     xmlSchemaFacetPtr facet;
2314     xmlSchemaTypePtr typ;
2315     int ret;
2316
2317     if ((type == NULL) || (strval == NULL))
2318         return(-1);
2319     typ = xmlSchemaGetPredefinedType(type, 
2320                BAD_CAST "http://www.w3.org/2001/XMLSchema");
2321     if (typ == NULL)
2322         return(-1);
2323
2324     facet = xmlSchemaNewFacet();
2325     if (facet == NULL)
2326         return(-1);
2327
2328     if (xmlStrEqual(facetname, BAD_CAST "minInclusive"))  {
2329         facet->type = XML_SCHEMA_FACET_MININCLUSIVE;
2330     } else if (xmlStrEqual(facetname, BAD_CAST "minExclusive"))  {
2331         facet->type = XML_SCHEMA_FACET_MINEXCLUSIVE;
2332     } else if (xmlStrEqual(facetname, BAD_CAST "maxInclusive"))  {
2333         facet->type = XML_SCHEMA_FACET_MAXINCLUSIVE;
2334     } else if (xmlStrEqual(facetname, BAD_CAST "maxExclusive"))  {
2335         facet->type = XML_SCHEMA_FACET_MAXEXCLUSIVE;
2336     } else if (xmlStrEqual(facetname, BAD_CAST "totalDigits"))  {
2337         facet->type = XML_SCHEMA_FACET_TOTALDIGITS;
2338     } else if (xmlStrEqual(facetname, BAD_CAST "fractionDigits"))  {
2339         facet->type = XML_SCHEMA_FACET_FRACTIONDIGITS;
2340     } else if (xmlStrEqual(facetname, BAD_CAST "pattern"))  {
2341         facet->type = XML_SCHEMA_FACET_PATTERN;
2342     } else if (xmlStrEqual(facetname, BAD_CAST "enumeration"))  {
2343         facet->type = XML_SCHEMA_FACET_ENUMERATION;
2344     } else if (xmlStrEqual(facetname, BAD_CAST "whiteSpace"))  {
2345         facet->type = XML_SCHEMA_FACET_WHITESPACE;
2346     } else if (xmlStrEqual(facetname, BAD_CAST "length"))  {
2347         facet->type = XML_SCHEMA_FACET_LENGTH;
2348     } else if (xmlStrEqual(facetname, BAD_CAST "maxLength"))  {
2349         facet->type = XML_SCHEMA_FACET_MAXLENGTH;
2350     } else if (xmlStrEqual(facetname, BAD_CAST "minLength")) {
2351         facet->type = XML_SCHEMA_FACET_MINLENGTH;
2352     } else {
2353         xmlSchemaFreeFacet(facet);
2354         return(-1);
2355     }
2356     facet->value = xmlStrdup(val);
2357     ret = xmlSchemaCheckFacet(facet, typ, NULL, type);
2358     if (ret != 0) {
2359         xmlSchemaFreeFacet(facet);
2360         return(-1);
2361     }
2362     ret = xmlSchemaValidateFacet(typ, facet, strval, value);
2363     xmlSchemaFreeFacet(facet);
2364     if (ret != 0)
2365         return(-1);
2366     return(0);
2367 }
2368
2369 /**
2370  * xmlRelaxNGSchemaFreeValue:
2371  * @data:  data needed for the library
2372  * @value:  the value to free
2373  *
2374  * Function provided by a type library to free a Schemas value
2375  *
2376  * Returns 1 if yes, 0 if no and -1 in case of error.
2377  */
2378 static void
2379 xmlRelaxNGSchemaFreeValue (void *data ATTRIBUTE_UNUSED, void *value) {
2380     xmlSchemaFreeValue(value);
2381 }
2382
2383 /**
2384  * xmlRelaxNGSchemaTypeCompare:
2385  * @data:  data needed for the library
2386  * @type:  the type name
2387  * @value1:  the first value
2388  * @value2:  the second value
2389  *
2390  * Compare two values for equality accordingly a type from the W3C XMLSchema
2391  * Datatype library.
2392  *
2393  * Returns 1 if equal, 0 if no and -1 in case of error.
2394  */
2395 static int
2396 xmlRelaxNGSchemaTypeCompare(void *data ATTRIBUTE_UNUSED,
2397                             const xmlChar *type,
2398                             const xmlChar *value1,
2399                             xmlNodePtr ctxt1,
2400                             void *comp1,
2401                             const xmlChar *value2,
2402                             xmlNodePtr ctxt2) {
2403     int ret;
2404     xmlSchemaTypePtr typ;
2405     xmlSchemaValPtr res1 = NULL, res2 = NULL;
2406
2407     if ((type == NULL) || (value1 == NULL) || (value2 == NULL))
2408         return(-1);
2409     typ = xmlSchemaGetPredefinedType(type, 
2410                BAD_CAST "http://www.w3.org/2001/XMLSchema");
2411     if (typ == NULL)
2412         return(-1);
2413     if (comp1 == NULL) {
2414         ret = xmlSchemaValPredefTypeNode(typ, value1, &res1, ctxt1);
2415         if (ret != 0)
2416             return(-1);
2417         if (res1 == NULL)
2418             return(-1);
2419     } else {
2420         res1 = (xmlSchemaValPtr) comp1;
2421     }
2422     ret = xmlSchemaValPredefTypeNode(typ, value2, &res2, ctxt2);
2423     if (ret != 0) {
2424         xmlSchemaFreeValue(res1);
2425         return(-1);
2426     }
2427     if (res1 == NULL) {
2428         xmlSchemaFreeValue(res1);
2429         return(-1);
2430     }
2431     ret = xmlSchemaCompareValues(res1, res2);
2432     if (res1 != (xmlSchemaValPtr) comp1)
2433         xmlSchemaFreeValue(res1);
2434     xmlSchemaFreeValue(res2);
2435     if (ret == -2)
2436         return(-1);
2437     if (ret == 0)
2438         return(1);
2439     return(0);
2440 }
2441  
2442 /**
2443  * xmlRelaxNGDefaultTypeHave:
2444  * @data:  data needed for the library
2445  * @type:  the type name
2446  *
2447  * Check if the given type is provided by
2448  * the default datatype library.
2449  *
2450  * Returns 1 if yes, 0 if no and -1 in case of error.
2451  */
2452 static int
2453 xmlRelaxNGDefaultTypeHave(void *data ATTRIBUTE_UNUSED, const xmlChar *type) {
2454     if (type == NULL)
2455         return(-1);
2456     if (xmlStrEqual(type, BAD_CAST "string"))
2457         return(1);
2458     if (xmlStrEqual(type, BAD_CAST "token"))
2459         return(1);
2460     return(0);
2461 }
2462
2463 /**
2464  * xmlRelaxNGDefaultTypeCheck:
2465  * @data:  data needed for the library
2466  * @type:  the type name
2467  * @value:  the value to check
2468  * @node:  the node
2469  *
2470  * Check if the given type and value are validated by
2471  * the default datatype library.
2472  *
2473  * Returns 1 if yes, 0 if no and -1 in case of error.
2474  */
2475 static int
2476 xmlRelaxNGDefaultTypeCheck(void *data ATTRIBUTE_UNUSED,
2477                            const xmlChar *type ATTRIBUTE_UNUSED,
2478                            const xmlChar *value ATTRIBUTE_UNUSED,
2479                            void **result ATTRIBUTE_UNUSED,
2480                            xmlNodePtr node ATTRIBUTE_UNUSED) {
2481     if (value == NULL)
2482         return(-1);
2483     if (xmlStrEqual(type, BAD_CAST "string"))
2484         return(1);
2485     if (xmlStrEqual(type, BAD_CAST "token")) {
2486         return(1);
2487     }
2488
2489     return(0);
2490 }
2491
2492 /**
2493  * xmlRelaxNGDefaultTypeCompare:
2494  * @data:  data needed for the library
2495  * @type:  the type name
2496  * @value1:  the first value
2497  * @value2:  the second value
2498  *
2499  * Compare two values accordingly a type from the default
2500  * datatype library.
2501  *
2502  * Returns 1 if yes, 0 if no and -1 in case of error.
2503  */
2504 static int
2505 xmlRelaxNGDefaultTypeCompare(void *data ATTRIBUTE_UNUSED,
2506                              const xmlChar *type,
2507                              const xmlChar *value1,
2508                              xmlNodePtr ctxt1 ATTRIBUTE_UNUSED,
2509                              void *comp1 ATTRIBUTE_UNUSED,
2510                              const xmlChar *value2,
2511                              xmlNodePtr ctxt2 ATTRIBUTE_UNUSED) {
2512     int ret = -1;
2513
2514     if (xmlStrEqual(type, BAD_CAST "string")) {
2515         ret = xmlStrEqual(value1, value2);
2516     } else if (xmlStrEqual(type, BAD_CAST "token")) {
2517         if (!xmlStrEqual(value1, value2)) {
2518             xmlChar *nval, *nvalue;
2519
2520             /*
2521              * TODO: trivial optimizations are possible by
2522              * computing at compile-time
2523              */
2524             nval = xmlRelaxNGNormalize(NULL, value1);
2525             nvalue = xmlRelaxNGNormalize(NULL, value2);
2526
2527             if ((nval == NULL) || (nvalue == NULL))
2528                 ret = -1;
2529             else if (xmlStrEqual(nval, nvalue))
2530                 ret = 1;
2531             else
2532                 ret = 0;
2533             if (nval != NULL)
2534                 xmlFree(nval);
2535             if (nvalue != NULL)
2536                 xmlFree(nvalue);
2537         } else
2538             ret = 1;
2539     }
2540     return(ret);
2541 }
2542  
2543 static int xmlRelaxNGTypeInitialized = 0;
2544 static xmlHashTablePtr xmlRelaxNGRegisteredTypes = NULL;
2545
2546 /**
2547  * xmlRelaxNGFreeTypeLibrary:
2548  * @lib:  the type library structure
2549  * @namespace:  the URI bound to the library
2550  *
2551  * Free the structure associated to the type library
2552  */
2553 static void
2554 xmlRelaxNGFreeTypeLibrary(xmlRelaxNGTypeLibraryPtr lib,
2555                           const xmlChar *namespace ATTRIBUTE_UNUSED) {
2556     if (lib == NULL)
2557         return;
2558     if (lib->namespace != NULL)
2559         xmlFree((xmlChar *)lib->namespace);
2560     xmlFree(lib);
2561 }
2562
2563 /**
2564  * xmlRelaxNGRegisterTypeLibrary:
2565  * @namespace:  the URI bound to the library
2566  * @data:  data associated to the library
2567  * @have:  the provide function
2568  * @check:  the checking function
2569  * @comp:  the comparison function
2570  *
2571  * Register a new type library
2572  *
2573  * Returns 0 in case of success and -1 in case of error.
2574  */
2575 static int
2576 xmlRelaxNGRegisterTypeLibrary(const xmlChar *namespace, void *data,
2577     xmlRelaxNGTypeHave have, xmlRelaxNGTypeCheck check,
2578     xmlRelaxNGTypeCompare comp, xmlRelaxNGFacetCheck facet,
2579     xmlRelaxNGTypeFree freef) {
2580     xmlRelaxNGTypeLibraryPtr lib;
2581     int ret;
2582
2583     if ((xmlRelaxNGRegisteredTypes == NULL) || (namespace == NULL) ||
2584         (check == NULL) || (comp == NULL))
2585         return(-1);
2586     if (xmlHashLookup(xmlRelaxNGRegisteredTypes, namespace) != NULL) {
2587         xmlGenericError(xmlGenericErrorContext,
2588                 "Relax-NG types library '%s' already registered\n",
2589                         namespace);
2590         return(-1);
2591     }
2592     lib = (xmlRelaxNGTypeLibraryPtr) xmlMalloc(sizeof(xmlRelaxNGTypeLibrary));
2593     if (lib == NULL) {
2594         xmlGenericError(xmlGenericErrorContext,
2595                 "Relax-NG types library '%s' malloc() failed\n",
2596                         namespace);
2597         return (-1);
2598     }
2599     memset(lib, 0, sizeof(xmlRelaxNGTypeLibrary));
2600     lib->namespace = xmlStrdup(namespace);
2601     lib->data = data;
2602     lib->have = have;
2603     lib->comp = comp;
2604     lib->check = check;
2605     lib->facet = facet;
2606     lib->freef = freef;
2607     ret = xmlHashAddEntry(xmlRelaxNGRegisteredTypes, namespace, lib);
2608     if (ret < 0) {
2609         xmlGenericError(xmlGenericErrorContext,
2610                 "Relax-NG types library failed to register '%s'\n",
2611                         namespace);
2612         xmlRelaxNGFreeTypeLibrary(lib, namespace);
2613         return(-1);
2614     }
2615     return(0);
2616 }
2617
2618 /**
2619  * xmlRelaxNGInitTypes:
2620  *
2621  * Initilize the default type libraries.
2622  *
2623  * Returns 0 in case of success and -1 in case of error.
2624  */
2625 static int
2626 xmlRelaxNGInitTypes(void) {
2627     if (xmlRelaxNGTypeInitialized != 0)
2628         return(0);
2629     xmlRelaxNGRegisteredTypes = xmlHashCreate(10);
2630     if (xmlRelaxNGRegisteredTypes == NULL) {
2631         xmlGenericError(xmlGenericErrorContext,
2632                 "Failed to allocate sh table for Relax-NG types\n");
2633         return(-1);
2634     }
2635     xmlRelaxNGRegisterTypeLibrary(
2636             BAD_CAST "http://www.w3.org/2001/XMLSchema-datatypes",
2637             NULL,
2638             xmlRelaxNGSchemaTypeHave,
2639             xmlRelaxNGSchemaTypeCheck,
2640             xmlRelaxNGSchemaTypeCompare,
2641             xmlRelaxNGSchemaFacetCheck,
2642             xmlRelaxNGSchemaFreeValue);
2643     xmlRelaxNGRegisterTypeLibrary(
2644             xmlRelaxNGNs,
2645             NULL,
2646             xmlRelaxNGDefaultTypeHave,
2647             xmlRelaxNGDefaultTypeCheck,
2648             xmlRelaxNGDefaultTypeCompare,
2649             NULL,
2650             NULL);
2651     xmlRelaxNGTypeInitialized = 1;
2652     return(0);
2653 }
2654
2655 /**
2656  * xmlRelaxNGCleanupTypes:
2657  *
2658  * Cleanup the default Schemas type library associated to RelaxNG
2659  */
2660 void    
2661 xmlRelaxNGCleanupTypes(void) {
2662     xmlSchemaCleanupTypes();
2663     if (xmlRelaxNGTypeInitialized == 0)
2664         return;
2665     xmlHashFree(xmlRelaxNGRegisteredTypes, (xmlHashDeallocator)
2666                 xmlRelaxNGFreeTypeLibrary);
2667     xmlRelaxNGTypeInitialized = 0;
2668 }
2669
2670 /************************************************************************
2671  *                                                                      *
2672  *              Compiling element content into regexp                   *
2673  *                                                                      *
2674  * Sometime the element content can be compiled into a pure regexp,     *
2675  * This allows a faster execution and streamability at that level       *
2676  *                                                                      *
2677  ************************************************************************/
2678
2679 static int xmlRelaxNGTryCompile(xmlRelaxNGParserCtxtPtr ctxt,
2680                                 xmlRelaxNGDefinePtr def);
2681
2682 /**
2683  * xmlRelaxNGIsCompileable:
2684  * @define:  the definition to check
2685  *
2686  * Check if a definition is nullable.
2687  *
2688  * Returns 1 if yes, 0 if no and -1 in case of error
2689  */
2690 static int
2691 xmlRelaxNGIsCompileable(xmlRelaxNGDefinePtr def) {
2692     int ret = -1;
2693
2694     if (def == NULL) {
2695         return(-1);
2696     }
2697     if ((def->type != XML_RELAXNG_ELEMENT) &&
2698         (def->dflags & IS_COMPILABLE))
2699         return(1);
2700     if ((def->type != XML_RELAXNG_ELEMENT) &&
2701         (def->dflags & IS_NOT_COMPILABLE))
2702         return(0);
2703     switch(def->type) {
2704         case XML_RELAXNG_NOOP:
2705             ret = xmlRelaxNGIsCompileable(def->content);
2706             break;
2707         case XML_RELAXNG_TEXT:
2708         case XML_RELAXNG_EMPTY:
2709             ret = 1;
2710             break;
2711         case XML_RELAXNG_ELEMENT:
2712             /*
2713              * Check if the element content is compileable
2714              */
2715             if (((def->dflags & IS_NOT_COMPILABLE) == 0) &&
2716                 ((def->dflags & IS_COMPILABLE) == 0)) {
2717                 xmlRelaxNGDefinePtr list;
2718                 list = def->content;
2719                 while (list != NULL) {
2720                     ret = xmlRelaxNGIsCompileable(list);
2721                     if (ret != 1)
2722                         break;
2723                     list = list->next;
2724                 }
2725                 if (ret == 0) def->dflags |= IS_NOT_COMPILABLE;
2726                 if (ret == 1) def->dflags |= IS_COMPILABLE;
2727 #ifdef DEBUG_COMPILE
2728                 if (ret == 1) {
2729                     xmlGenericError(xmlGenericErrorContext,
2730                                 "element content for %s is compilable\n",
2731                                 def->name);
2732                 } else if (ret == 0) {
2733                     xmlGenericError(xmlGenericErrorContext,
2734                                 "element content for %s is not compilable\n",
2735                                 def->name);
2736                 } else {
2737                     xmlGenericError(xmlGenericErrorContext,
2738                             "Problem in RelaxNGIsCompileable for element %s\n",
2739                                 def->name);
2740                 }
2741 #endif
2742             }
2743             /*
2744              * All elements return a compileable status unless they
2745              * are generic like anyName
2746              */
2747             if ((def->nameClass != NULL) || (def->name == NULL))
2748                 ret = 0;
2749             else
2750                 ret = 1;
2751             return(ret);
2752         case XML_RELAXNG_REF:
2753         case XML_RELAXNG_EXTERNALREF:
2754         case XML_RELAXNG_PARENTREF:
2755             if (def->depth == -20) {
2756                 return(1);
2757             } else {
2758                 xmlRelaxNGDefinePtr list;
2759
2760                 def->depth = -20;
2761                 list = def->content;
2762                 while (list != NULL) {
2763                     ret = xmlRelaxNGIsCompileable(list);
2764                     if (ret != 1)
2765                         break;
2766                     list = list->next;
2767                 }
2768             }
2769             break;
2770         case XML_RELAXNG_START:
2771         case XML_RELAXNG_OPTIONAL:
2772         case XML_RELAXNG_ZEROORMORE:
2773         case XML_RELAXNG_ONEORMORE:
2774         case XML_RELAXNG_CHOICE:
2775         case XML_RELAXNG_GROUP:
2776         case XML_RELAXNG_DEF: {
2777             xmlRelaxNGDefinePtr list;
2778
2779             list = def->content;
2780             while (list != NULL) {
2781                 ret = xmlRelaxNGIsCompileable(list);
2782                 if (ret != 1)
2783                     break;
2784                 list = list->next;
2785             }
2786             break;
2787         }
2788         case XML_RELAXNG_EXCEPT:
2789         case XML_RELAXNG_ATTRIBUTE:
2790         case XML_RELAXNG_INTERLEAVE:
2791         case XML_RELAXNG_DATATYPE:
2792         case XML_RELAXNG_LIST:
2793         case XML_RELAXNG_PARAM:
2794         case XML_RELAXNG_VALUE:
2795             ret = 0;
2796             break;
2797         case XML_RELAXNG_NOT_ALLOWED:
2798             ret = -1;
2799             break;
2800     }
2801     if (ret == 0) def->dflags |= IS_NOT_COMPILABLE;
2802     if (ret == 1) def->dflags |= IS_COMPILABLE;
2803 #ifdef DEBUG_COMPILE
2804     if (ret == 1) {
2805         xmlGenericError(xmlGenericErrorContext,
2806                     "RelaxNGIsCompileable %s : true\n",
2807                     xmlRelaxNGDefName(def));
2808     } else if (ret == 0) {
2809         xmlGenericError(xmlGenericErrorContext,
2810                     "RelaxNGIsCompileable %s : false\n",
2811                     xmlRelaxNGDefName(def));
2812     } else {
2813         xmlGenericError(xmlGenericErrorContext,
2814                     "Problem in RelaxNGIsCompileable %s\n",
2815                     xmlRelaxNGDefName(def));
2816     }
2817 #endif
2818     return(ret);
2819 }
2820
2821 /**
2822  * xmlRelaxNGCompile:
2823  * ctxt:  the RelaxNG parser context
2824  * @define:  the definition tree to compile
2825  *
2826  * Compile the set of definitions, it works recursively, till the
2827  * element boundaries, where it tries to compile the content if possible
2828  *
2829  * Returns 0 if success and -1 in case of error
2830  */
2831 static int
2832 xmlRelaxNGCompile(xmlRelaxNGParserCtxtPtr ctxt, xmlRelaxNGDefinePtr def) {
2833     int ret = 0;
2834     xmlRelaxNGDefinePtr list;
2835
2836     if ((ctxt == NULL) || (def == NULL)) return(-1);
2837
2838     switch(def->type) {
2839         case XML_RELAXNG_START:
2840             if ((xmlRelaxNGIsCompileable(def) == 1) && (def->depth != -25)) {
2841                 xmlAutomataPtr oldam = ctxt->am;
2842                 xmlAutomataStatePtr oldstate = ctxt->state;
2843
2844                 def->depth = -25;
2845
2846                 list = def->content;
2847                 ctxt->am = xmlNewAutomata();
2848                 if (ctxt->am == NULL)
2849                     return(-1);
2850                 ctxt->state = xmlAutomataGetInitState(ctxt->am);
2851                 while (list != NULL) {
2852                     xmlRelaxNGCompile(ctxt, list);
2853                     list = list->next;
2854                 }
2855                 xmlAutomataSetFinalState(ctxt->am, ctxt->state);
2856                 def->contModel = xmlAutomataCompile(ctxt->am);
2857                 xmlRegexpIsDeterminist(def->contModel);
2858
2859                 xmlFreeAutomata(ctxt->am);
2860                 ctxt->state = oldstate;
2861                 ctxt->am = oldam;
2862             }
2863             break;
2864         case XML_RELAXNG_ELEMENT:
2865             if ((ctxt->am != NULL) && (def->name != NULL)) {
2866                 ctxt->state = xmlAutomataNewTransition2(ctxt->am,
2867                    ctxt->state, NULL, def->name, def->ns, def);
2868             }
2869             if ((def->dflags & IS_COMPILABLE) && (def->depth != -25)) {
2870                 xmlAutomataPtr oldam = ctxt->am;
2871                 xmlAutomataStatePtr oldstate = ctxt->state;
2872
2873                 def->depth = -25;
2874
2875                 list = def->content;
2876                 ctxt->am = xmlNewAutomata();
2877                 if (ctxt->am == NULL)
2878                     return(-1);
2879                 ctxt->state = xmlAutomataGetInitState(ctxt->am);
2880                 while (list != NULL) {
2881                     xmlRelaxNGCompile(ctxt, list);
2882                     list = list->next;
2883                 }
2884                 xmlAutomataSetFinalState(ctxt->am, ctxt->state);
2885                 def->contModel = xmlAutomataCompile(ctxt->am);
2886                 if (!xmlRegexpIsDeterminist(def->contModel)) {
2887                     /*
2888                      * we can only use the automata if it is determinist
2889                      */
2890                     xmlRegFreeRegexp(def->contModel);
2891                     def->contModel = NULL;
2892                 }
2893                 xmlFreeAutomata(ctxt->am);
2894                 ctxt->state = oldstate;
2895                 ctxt->am = oldam;
2896             } else {
2897                 xmlAutomataPtr oldam = ctxt->am;
2898
2899                 /*
2900                  * we can't build the content model for this element content
2901                  * but it still might be possible to build it for some of its
2902                  * children, recurse.
2903                  */
2904                 ret = xmlRelaxNGTryCompile(ctxt, def);
2905                 ctxt->am = oldam;
2906             }
2907             break;
2908         case XML_RELAXNG_NOOP:
2909             ret = xmlRelaxNGCompile(ctxt, def->content);
2910             break;
2911         case XML_RELAXNG_OPTIONAL: {
2912             xmlAutomataStatePtr oldstate = ctxt->state;
2913             
2914             xmlRelaxNGCompile(ctxt, def->content);
2915             xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
2916             break;
2917         }
2918         case XML_RELAXNG_ZEROORMORE: {
2919             xmlAutomataStatePtr oldstate;
2920
2921             ctxt->state = xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL);
2922             oldstate = ctxt->state;
2923             list = def->content;
2924             while (list != NULL) {
2925                 xmlRelaxNGCompile(ctxt, list);
2926                 list = list->next;
2927             }
2928             xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldstate);
2929             ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
2930             break;
2931         }
2932         case XML_RELAXNG_ONEORMORE: {
2933             xmlAutomataStatePtr oldstate;
2934
2935             list = def->content;
2936             while (list != NULL) {
2937                 xmlRelaxNGCompile(ctxt, list);
2938                 list = list->next;
2939             }
2940             oldstate = ctxt->state;
2941             list = def->content;
2942             while (list != NULL) {
2943                 xmlRelaxNGCompile(ctxt, list);
2944                 list = list->next;
2945             }
2946             xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldstate);
2947             ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
2948             break;
2949         }
2950         case XML_RELAXNG_CHOICE: {
2951             xmlAutomataStatePtr target = NULL;
2952             xmlAutomataStatePtr oldstate = ctxt->state;
2953             
2954             list = def->content;
2955             while (list != NULL) {
2956                 ctxt->state = oldstate;
2957                 ret = xmlRelaxNGCompile(ctxt, list);
2958                 if (ret != 0)
2959                     break;
2960                 if (target == NULL)
2961                     target = ctxt->state;
2962                 else {
2963                     xmlAutomataNewEpsilon(ctxt->am, ctxt->state, target);
2964                 }
2965                 list = list->next;
2966             }
2967             ctxt->state = target;
2968
2969             break;
2970         }
2971         case XML_RELAXNG_REF:
2972         case XML_RELAXNG_EXTERNALREF:
2973         case XML_RELAXNG_PARENTREF:
2974         case XML_RELAXNG_GROUP:
2975         case XML_RELAXNG_DEF:
2976             list = def->content;
2977             while (list != NULL) {
2978                 ret = xmlRelaxNGCompile(ctxt, list);
2979                 if (ret != 0)
2980                     break;
2981                 list = list->next;
2982             }
2983             break;
2984         case XML_RELAXNG_TEXT: {
2985             xmlAutomataStatePtr oldstate;
2986
2987             ctxt->state = xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL);
2988             oldstate = ctxt->state;
2989             xmlRelaxNGCompile(ctxt, def->content);
2990             xmlAutomataNewTransition(ctxt->am, ctxt->state, ctxt->state,
2991                                      BAD_CAST "#text", NULL);
2992             ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
2993             break;
2994         }
2995         case XML_RELAXNG_EMPTY:
2996             ctxt->state = xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL);
2997             break;
2998         case XML_RELAXNG_EXCEPT:
2999         case XML_RELAXNG_ATTRIBUTE:
3000         case XML_RELAXNG_INTERLEAVE:
3001         case XML_RELAXNG_NOT_ALLOWED:
3002         case XML_RELAXNG_DATATYPE:
3003         case XML_RELAXNG_LIST:
3004         case XML_RELAXNG_PARAM:
3005         case XML_RELAXNG_VALUE:
3006             /* This should not happen and generate an internal error */
3007             fprintf(stderr, "RNG internal error trying to compile %s\n",
3008                     xmlRelaxNGDefName(def));
3009             break;
3010     }
3011     return(ret);
3012 }
3013
3014 /**
3015  * xmlRelaxNGTryCompile:
3016  * ctxt:  the RelaxNG parser context
3017  * @define:  the definition tree to compile
3018  *
3019  * Try to compile the set of definitions, it works recursively,
3020  * possibly ignoring parts which cannot be compiled.
3021  *
3022  * Returns 0 if success and -1 in case of error
3023  */
3024 static int
3025 xmlRelaxNGTryCompile(xmlRelaxNGParserCtxtPtr ctxt, xmlRelaxNGDefinePtr def) {
3026     int ret = 0;
3027     xmlRelaxNGDefinePtr list;
3028
3029     if ((ctxt == NULL) || (def == NULL)) return(-1);
3030
3031     if ((def->type == XML_RELAXNG_START) ||
3032         (def->type == XML_RELAXNG_ELEMENT)) {
3033         ret = xmlRelaxNGIsCompileable(def);
3034         if ((def->dflags & IS_COMPILABLE) && (def->depth != -25)) {
3035             ctxt->am = NULL;
3036             ret = xmlRelaxNGCompile(ctxt, def);
3037 #ifdef DEBUG_PROGRESSIVE
3038             if (ret == 0) {
3039                 if (def->type == XML_RELAXNG_START)
3040                     xmlGenericError(xmlGenericErrorContext,
3041                         "compiled the start\n");
3042                 else
3043                     xmlGenericError(xmlGenericErrorContext,
3044                         "compiled element %s\n", def->name);
3045             } else {
3046                 if (def->type == XML_RELAXNG_START)
3047                     xmlGenericError(xmlGenericErrorContext,
3048                         "failed to compile the start\n");
3049                 else
3050                     xmlGenericError(xmlGenericErrorContext,
3051                         "failed to compile element %s\n", def->name);
3052             }
3053 #endif
3054             return(ret);
3055         }
3056     }
3057     switch(def->type) {
3058         case XML_RELAXNG_NOOP:
3059             ret = xmlRelaxNGTryCompile(ctxt, def->content);
3060             break;
3061         case XML_RELAXNG_TEXT:
3062         case XML_RELAXNG_DATATYPE:
3063         case XML_RELAXNG_LIST:
3064         case XML_RELAXNG_PARAM:
3065         case XML_RELAXNG_VALUE:
3066         case XML_RELAXNG_EMPTY:
3067         case XML_RELAXNG_ELEMENT:
3068             ret = 0;
3069             break;
3070         case XML_RELAXNG_OPTIONAL:
3071         case XML_RELAXNG_ZEROORMORE:
3072         case XML_RELAXNG_ONEORMORE:
3073         case XML_RELAXNG_CHOICE:
3074         case XML_RELAXNG_GROUP:
3075         case XML_RELAXNG_DEF:
3076         case XML_RELAXNG_START:
3077         case XML_RELAXNG_REF:
3078         case XML_RELAXNG_EXTERNALREF:
3079         case XML_RELAXNG_PARENTREF:
3080             list = def->content;
3081             while (list != NULL) {
3082                 ret = xmlRelaxNGTryCompile(ctxt, list);
3083                 if (ret != 0)
3084                     break;
3085                 list = list->next;
3086             }
3087             break;
3088         case XML_RELAXNG_EXCEPT:
3089         case XML_RELAXNG_ATTRIBUTE:
3090         case XML_RELAXNG_INTERLEAVE:
3091         case XML_RELAXNG_NOT_ALLOWED:
3092             ret = 0;
3093             break;
3094     }
3095     return(ret);
3096 }
3097
3098 /************************************************************************
3099  *                                                                      *
3100  *                      Parsing functions                               *
3101  *                                                                      *
3102  ************************************************************************/
3103
3104 static xmlRelaxNGDefinePtr xmlRelaxNGParseAttribute(
3105               xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node);
3106 static xmlRelaxNGDefinePtr xmlRelaxNGParseElement(
3107               xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node);
3108 static xmlRelaxNGDefinePtr xmlRelaxNGParsePatterns(
3109               xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes, int group);
3110 static xmlRelaxNGDefinePtr xmlRelaxNGParsePattern(
3111               xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node);
3112 static xmlRelaxNGPtr xmlRelaxNGParseDocument(
3113               xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node);
3114 static int xmlRelaxNGParseGrammarContent(
3115               xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes);
3116 static xmlRelaxNGDefinePtr xmlRelaxNGParseNameClass(
3117               xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node,
3118               xmlRelaxNGDefinePtr def);
3119 static xmlRelaxNGGrammarPtr xmlRelaxNGParseGrammar(
3120               xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes);
3121 static int xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt, 
3122               xmlRelaxNGDefinePtr define, xmlNodePtr elem);
3123
3124
3125 #define IS_BLANK_NODE(n) (xmlRelaxNGIsBlank((n)->content))
3126
3127 /**
3128  * xmlRelaxNGIsNullable:
3129  * @define:  the definition to verify
3130  *
3131  * Check if a definition is nullable.
3132  *
3133  * Returns 1 if yes, 0 if no and -1 in case of error
3134  */
3135 static int
3136 xmlRelaxNGIsNullable(xmlRelaxNGDefinePtr define) {
3137     int ret;
3138     if (define == NULL)
3139         return(-1);
3140
3141     if (define->dflags & IS_NULLABLE)
3142         return(1);
3143     if (define->dflags & IS_NOT_NULLABLE)
3144         return(0);
3145     switch (define->type) {
3146         case XML_RELAXNG_EMPTY:
3147         case XML_RELAXNG_TEXT:
3148             ret = 1; break;
3149         case XML_RELAXNG_NOOP:
3150         case XML_RELAXNG_DEF:
3151         case XML_RELAXNG_REF:
3152         case XML_RELAXNG_EXTERNALREF:
3153         case XML_RELAXNG_PARENTREF:
3154         case XML_RELAXNG_ONEORMORE:
3155             ret = xmlRelaxNGIsNullable(define->content);
3156             break;
3157         case XML_RELAXNG_EXCEPT:
3158         case XML_RELAXNG_NOT_ALLOWED:
3159         case XML_RELAXNG_ELEMENT:
3160         case XML_RELAXNG_DATATYPE:
3161         case XML_RELAXNG_PARAM:
3162         case XML_RELAXNG_VALUE:
3163         case XML_RELAXNG_LIST:
3164         case XML_RELAXNG_ATTRIBUTE:
3165             ret = 0; break;
3166         case XML_RELAXNG_CHOICE: {
3167             xmlRelaxNGDefinePtr list = define->content;
3168
3169             while (list != NULL) {
3170                 ret = xmlRelaxNGIsNullable(list);
3171                 if (ret != 0)
3172                     goto done;
3173                 list = list->next;
3174             }
3175             ret = 0; break;
3176         }
3177         case XML_RELAXNG_START:
3178         case XML_RELAXNG_INTERLEAVE:
3179         case XML_RELAXNG_GROUP: {
3180             xmlRelaxNGDefinePtr list = define->content;
3181
3182             while (list != NULL) {
3183                 ret = xmlRelaxNGIsNullable(list);
3184                 if (ret != 1)
3185                     goto done;
3186                 list = list->next;
3187             }
3188             return(1);
3189         }
3190         default:
3191             return(-1);
3192     }
3193 done:
3194     if (ret == 0)
3195         define->dflags |= IS_NOT_NULLABLE;
3196     if (ret == 1)
3197         define->dflags |= IS_NULLABLE;
3198     return(ret);
3199 }
3200
3201 /**
3202  * xmlRelaxNGIsBlank:
3203  * @str:  a string
3204  *
3205  * Check if a string is ignorable c.f. 4.2. Whitespace
3206  *
3207  * Returns 1 if the string is NULL or made of blanks chars, 0 otherwise
3208  */
3209 static int
3210 xmlRelaxNGIsBlank(xmlChar *str) {
3211     if (str == NULL)
3212         return(1);
3213     while (*str != 0) {
3214         if (!(IS_BLANK(*str))) return(0);
3215         str++;
3216     }
3217     return(1);
3218 }
3219
3220 /**
3221  * xmlRelaxNGGetDataTypeLibrary:
3222  * @ctxt:  a Relax-NG parser context
3223  * @node:  the current data or value element
3224  *
3225  * Applies algorithm from 4.3. datatypeLibrary attribute
3226  *
3227  * Returns the datatypeLibary value or NULL if not found
3228  */
3229 static xmlChar *
3230 xmlRelaxNGGetDataTypeLibrary(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
3231                              xmlNodePtr node) {
3232     xmlChar *ret, *escape;
3233
3234     if ((IS_RELAXNG(node, "data")) || (IS_RELAXNG(node, "value"))) {
3235         ret = xmlGetProp(node, BAD_CAST "datatypeLibrary");
3236         if (ret != NULL) {
3237             if (ret[0] == 0) {
3238                 xmlFree(ret);
3239                 return(NULL);
3240             }
3241             escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?");
3242             if (escape == NULL) {
3243                 return(ret);
3244             }
3245             xmlFree(ret);
3246             return(escape);
3247         }
3248     }
3249     node = node->parent;
3250     while ((node != NULL) && (node->type == XML_ELEMENT_NODE)) {
3251         ret = xmlGetProp(node, BAD_CAST "datatypeLibrary");
3252         if (ret != NULL) {
3253             if (ret[0] == 0) {
3254                 xmlFree(ret);
3255                 return(NULL);
3256             }
3257             escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?");
3258             if (escape == NULL) {
3259                 return(ret);
3260             }
3261             xmlFree(ret);
3262             return(escape);
3263         }
3264         node = node->parent;
3265     }
3266     return(NULL);
3267 }
3268
3269 /**
3270  * xmlRelaxNGParseValue:
3271  * @ctxt:  a Relax-NG parser context
3272  * @node:  the data node.
3273  *
3274  * parse the content of a RelaxNG value node.
3275  *
3276  * Returns the definition pointer or NULL in case of error
3277  */
3278 static xmlRelaxNGDefinePtr
3279 xmlRelaxNGParseValue(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
3280     xmlRelaxNGDefinePtr def = NULL;
3281     xmlRelaxNGTypeLibraryPtr lib = NULL;
3282     xmlChar *type;
3283     xmlChar *library;
3284     int success = 0;
3285
3286     def = xmlRelaxNGNewDefine(ctxt, node);
3287     if (def == NULL)
3288         return(NULL);
3289     def->type = XML_RELAXNG_VALUE;
3290
3291     type = xmlGetProp(node, BAD_CAST "type");
3292     if (type != NULL) {
3293         xmlRelaxNGNormExtSpace(type);
3294         if (xmlValidateNCName(type, 0)) {
3295             if (ctxt->error != NULL)
3296                 ctxt->error(ctxt->userData,
3297                     "value type '%s' is not an NCName\n",
3298                             type);
3299             ctxt->nbErrors++;
3300         }
3301         library = xmlRelaxNGGetDataTypeLibrary(ctxt, node);
3302         if (library == NULL)
3303             library = xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0");
3304
3305         def->name = type;
3306         def->ns = library;
3307
3308         lib = (xmlRelaxNGTypeLibraryPtr)
3309             xmlHashLookup(xmlRelaxNGRegisteredTypes, library);
3310         if (lib == NULL) {
3311             if (ctxt->error != NULL)
3312                 ctxt->error(ctxt->userData,
3313                     "Use of unregistered type library '%s'\n",
3314                             library);
3315             ctxt->nbErrors++;
3316             def->data = NULL;
3317         } else {
3318             def->data = lib;
3319             if (lib->have == NULL) {
3320                 if (ctxt->error != NULL)
3321                     ctxt->error(ctxt->userData,
3322                     "Internal error with type library '%s': no 'have'\n",
3323                             library);
3324                 ctxt->nbErrors++;
3325             } else {
3326                 success = lib->have(lib->data, def->name);
3327                 if (success != 1) {
3328                     if (ctxt->error != NULL)
3329                         ctxt->error(ctxt->userData,
3330                     "Error type '%s' is not exported by type library '%s'\n",
3331                                 def->name, library);
3332                     ctxt->nbErrors++;
3333                 }
3334             }
3335         }
3336     }
3337     if (node->children == NULL) {
3338         def->value = xmlStrdup(BAD_CAST "");
3339     } else if (((node->children->type != XML_TEXT_NODE) &&
3340                 (node->children->type != XML_CDATA_SECTION_NODE)) ||
3341                (node->children->next != NULL)) {
3342         if (ctxt->error != NULL)
3343             ctxt->error(ctxt->userData,
3344                 "Expecting a single text value for <value>content\n");
3345         ctxt->nbErrors++;
3346     } else if (def != NULL) {
3347         def->value = xmlNodeGetContent(node);
3348         if (def->value == NULL) {
3349             if (ctxt->error != NULL)
3350                 ctxt->error(ctxt->userData,
3351                             "Element <value> has no content\n");
3352             ctxt->nbErrors++;
3353         } else if ((lib != NULL) && (lib->check != NULL) && (success == 1)) {
3354             void *val = NULL;
3355
3356             success = lib->check(lib->data, def->name, def->value, &val, node);
3357             if (success != 1) {
3358                 if (ctxt->error != NULL)
3359                     ctxt->error(ctxt->userData,
3360                         "Value '%s' is not acceptable for type '%s'\n",
3361                                 def->value, def->name);
3362                 ctxt->nbErrors++;
3363             } else {
3364                 if (val != NULL)
3365                     def->attrs = val;
3366             }
3367         }
3368     }
3369     return(def);
3370 }
3371
3372 /**
3373  * xmlRelaxNGParseData:
3374  * @ctxt:  a Relax-NG parser context
3375  * @node:  the data node.
3376  *
3377  * parse the content of a RelaxNG data node.
3378  *
3379  * Returns the definition pointer or NULL in case of error
3380  */
3381 static xmlRelaxNGDefinePtr
3382 xmlRelaxNGParseData(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
3383     xmlRelaxNGDefinePtr def = NULL, except, last = NULL;
3384     xmlRelaxNGDefinePtr param, lastparam = NULL;
3385     xmlRelaxNGTypeLibraryPtr lib;
3386     xmlChar *type;
3387     xmlChar *library;
3388     xmlNodePtr content;
3389     int tmp;
3390
3391     type = xmlGetProp(node, BAD_CAST "type");
3392     if (type == NULL) {
3393         if (ctxt->error != NULL)
3394             ctxt->error(ctxt->userData,
3395                         "data has no type\n");
3396         ctxt->nbErrors++;
3397         return(NULL);
3398     }
3399     xmlRelaxNGNormExtSpace(type);
3400     if (xmlValidateNCName(type, 0)) {
3401         if (ctxt->error != NULL)
3402             ctxt->error(ctxt->userData,
3403                 "data type '%s' is not an NCName\n",
3404                         type);
3405         ctxt->nbErrors++;
3406     }
3407     library = xmlRelaxNGGetDataTypeLibrary(ctxt, node);
3408     if (library == NULL)
3409         library = xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0");
3410
3411     def = xmlRelaxNGNewDefine(ctxt, node);
3412     if (def == NULL) {
3413         xmlFree(type);
3414         return(NULL);
3415     }
3416     def->type = XML_RELAXNG_DATATYPE;
3417     def->name = type;
3418     def->ns = library;
3419
3420     lib = (xmlRelaxNGTypeLibraryPtr)
3421         xmlHashLookup(xmlRelaxNGRegisteredTypes, library);
3422     if (lib == NULL) {
3423         if (ctxt->error != NULL)
3424             ctxt->error(ctxt->userData,
3425                 "Use of unregistered type library '%s'\n",
3426                         library);
3427         ctxt->nbErrors++;
3428         def->data = NULL;
3429     } else {
3430         def->data = lib;
3431         if (lib->have == NULL) {
3432             if (ctxt->error != NULL)
3433                 ctxt->error(ctxt->userData,
3434                 "Internal error with type library '%s': no 'have'\n",
3435                         library);
3436             ctxt->nbErrors++;
3437         } else {
3438             tmp = lib->have(lib->data, def->name);
3439             if (tmp != 1) {
3440                 if (ctxt->error != NULL)
3441                     ctxt->error(ctxt->userData,
3442                     "Error type '%s' is not exported by type library '%s'\n",
3443                             def->name, library);
3444                 ctxt->nbErrors++;
3445             } else if ((xmlStrEqual(library, BAD_CAST
3446                            "http://www.w3.org/2001/XMLSchema-datatypes")) &&
3447                        ((xmlStrEqual(def->name, BAD_CAST "IDREF")) ||
3448                         (xmlStrEqual(def->name, BAD_CAST "IDREFS")))) {
3449                 ctxt->idref = 1;
3450             }
3451         }
3452     }
3453     content = node->children;
3454
3455     /*
3456      * Handle optional params
3457      */
3458     while (content != NULL) {
3459         if (!xmlStrEqual(content->name, BAD_CAST "param"))
3460             break;
3461         if (xmlStrEqual(library,
3462                         BAD_CAST"http://relaxng.org/ns/structure/1.0")) {
3463             if (ctxt->error != NULL)
3464                 ctxt->error(ctxt->userData,
3465                 "Type library '%s' does not allow type parameters\n",
3466                             library);
3467             ctxt->nbErrors++;
3468             content = content->next;
3469             while ((content != NULL) &&
3470                    (xmlStrEqual(content->name, BAD_CAST "param")))
3471                 content = content->next;
3472         } else {
3473             param = xmlRelaxNGNewDefine(ctxt, node);
3474             if (param != NULL) {
3475                 param->type = XML_RELAXNG_PARAM;
3476                 param->name = xmlGetProp(content, BAD_CAST "name");
3477                 if (param->name == NULL) {
3478                     if (ctxt->error != NULL)
3479                         ctxt->error(ctxt->userData,
3480                             "param has no name\n");
3481                     ctxt->nbErrors++;
3482                 }
3483                 param->value = xmlNodeGetContent(content);
3484                 if (lastparam == NULL) {
3485                     def->attrs = lastparam = param;
3486                 } else {
3487                     lastparam->next = param;
3488                     lastparam = param;
3489                 }
3490                 if (lib != NULL) {
3491                 }
3492             }
3493             content = content->next;
3494         }
3495     }
3496     /*
3497      * Handle optional except
3498      */
3499     if ((content != NULL) && (xmlStrEqual(content->name, BAD_CAST "except"))) {
3500         xmlNodePtr child;
3501         xmlRelaxNGDefinePtr tmp2, last2 = NULL;
3502
3503         except = xmlRelaxNGNewDefine(ctxt, node);
3504         if (except == NULL) {
3505             return(def);
3506         }
3507         except->type = XML_RELAXNG_EXCEPT;
3508         child = content->children;
3509         if (last == NULL) {
3510             def->content = except;
3511         } else {
3512             last->next = except;
3513         }
3514         if (child == NULL) {
3515             if (ctxt->error != NULL)
3516                 ctxt->error(ctxt->userData,
3517                     "except has no content\n");
3518             ctxt->nbErrors++;
3519         }
3520         while (child != NULL) {
3521             tmp2 = xmlRelaxNGParsePattern(ctxt, child);
3522             if (tmp2 != NULL) {
3523                 if (last2 == NULL) {
3524                     except->content = last2 = tmp2;
3525                 } else {
3526                     last2->next = tmp2;
3527                     last2 = tmp2;
3528                 }
3529             }
3530             child = child->next;
3531         }
3532         content = content->next;
3533     }
3534     /*
3535      * Check there is no unhandled data
3536      */
3537     if (content != NULL) {
3538         if (ctxt->error != NULL)
3539             ctxt->error(ctxt->userData,
3540                 "Element data has unexpected content %s\n", content->name);
3541         ctxt->nbErrors++;
3542     }
3543
3544     return(def);
3545 }
3546
3547 static const xmlChar *invalidName = BAD_CAST "\1";
3548
3549 /**
3550  * xmlRelaxNGCompareNameClasses:
3551  * @defs1:  the first element/attribute defs
3552  * @defs2:  the second element/attribute defs
3553  * @name:  the restriction on the name
3554  * @ns:  the restriction on the namespace
3555  *
3556  * Compare the 2 lists of element definitions. The comparison is
3557  * that if both lists do not accept the same QNames, it returns 1
3558  * If the 2 lists can accept the same QName the comparison returns 0
3559  *
3560  * Returns 1 disttinct, 0 if equal
3561  */
3562 static int
3563 xmlRelaxNGCompareNameClasses(xmlRelaxNGDefinePtr def1,
3564                              xmlRelaxNGDefinePtr def2) {
3565     int ret = 1;
3566     xmlNode node;
3567     xmlNs ns;
3568     xmlRelaxNGValidCtxt ctxt;
3569     ctxt.flags = FLAGS_IGNORABLE;
3570
3571     memset(&ctxt, 0, sizeof(xmlRelaxNGValidCtxt));
3572
3573     if ((def1->type == XML_RELAXNG_ELEMENT) ||
3574         (def1->type == XML_RELAXNG_ATTRIBUTE)) {
3575         if (def2->type == XML_RELAXNG_TEXT)
3576             return(1);
3577         if (def1->name != NULL) {
3578             node.name = def1->name;
3579         } else {
3580             node.name = invalidName;
3581         }
3582         node.ns = &ns;
3583         if (def1->ns != NULL) {
3584             if (def1->ns[0] == 0) {
3585                 node.ns = NULL;
3586             } else {
3587                 ns.href = def1->ns;
3588             }
3589         } else {
3590             ns.href = invalidName;
3591         }
3592         if (xmlRelaxNGElementMatch(&ctxt, def2, &node)) {
3593             if (def1->nameClass != NULL) {
3594                 ret = xmlRelaxNGCompareNameClasses(def1->nameClass, def2);
3595             } else {
3596                 ret = 0;
3597             }
3598         } else {
3599             ret = 1;
3600         }
3601     } else if (def1->type == XML_RELAXNG_TEXT) {
3602         if (def2->type == XML_RELAXNG_TEXT)
3603             return(0);
3604         return(1);
3605     } else if (def1->type == XML_RELAXNG_EXCEPT) {
3606         TODO
3607         ret = 0;
3608     } else {
3609         TODO
3610         ret = 0;
3611     }
3612     if (ret == 0)
3613         return(ret);
3614     if ((def2->type == XML_RELAXNG_ELEMENT) ||
3615         (def2->type == XML_RELAXNG_ATTRIBUTE)) {
3616         if (def2->name != NULL) {
3617             node.name = def2->name;
3618         } else {
3619             node.name = invalidName;
3620         }
3621         node.ns = &ns;
3622         if (def2->ns != NULL) {
3623             if (def2->ns[0] == 0) {
3624                 node.ns = NULL;
3625             } else {
3626                 ns.href = def2->ns;
3627             }
3628         } else {
3629             ns.href = invalidName;
3630         }
3631         if (xmlRelaxNGElementMatch(&ctxt, def1, &node)) {
3632             if (def2->nameClass != NULL) {
3633                 ret = xmlRelaxNGCompareNameClasses(def2->nameClass, def1);
3634             } else {
3635                 ret = 0;
3636             }
3637         } else {
3638             ret = 1;
3639         }
3640     } else {
3641         TODO
3642         ret = 0;
3643     }
3644
3645     return(ret);
3646 }
3647
3648 /**
3649  * xmlRelaxNGCompareElemDefLists:
3650  * @ctxt:  a Relax-NG parser context
3651  * @defs1:  the first list of element/attribute defs
3652  * @defs2:  the second list of element/attribute defs
3653  *
3654  * Compare the 2 lists of element or attribute definitions. The comparison
3655  * is that if both lists do not accept the same QNames, it returns 1
3656  * If the 2 lists can accept the same QName the comparison returns 0
3657  *
3658  * Returns 1 disttinct, 0 if equal
3659  */
3660 static int
3661 xmlRelaxNGCompareElemDefLists(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
3662                       xmlRelaxNGDefinePtr *def1,
3663                       xmlRelaxNGDefinePtr *def2) {
3664     xmlRelaxNGDefinePtr *basedef2 = def2;
3665     
3666     if ((def1 == NULL) || (def2 == NULL))
3667         return(1);
3668     if ((*def1 == NULL) || (*def2 == NULL))
3669         return(1);
3670     while (*def1 != NULL) {
3671         while ((*def2) != NULL) {
3672             if (xmlRelaxNGCompareNameClasses(*def1, *def2) == 0)
3673                 return(0);
3674             def2++;
3675         }
3676         def2 = basedef2;
3677         def1++;
3678     }
3679     return(1);
3680 }
3681
3682 /**
3683  * xmlRelaxNGGenerateAttributes:
3684  * @ctxt:  a Relax-NG parser context
3685  * @def:  the definition definition
3686  *
3687  * Check if the definition can only generate attributes
3688  *
3689  * Returns 1 if yes, 0 if no and -1 in case of error.
3690  */
3691 static int
3692 xmlRelaxNGGenerateAttributes(xmlRelaxNGParserCtxtPtr ctxt,
3693                              xmlRelaxNGDefinePtr def) {
3694     xmlRelaxNGDefinePtr parent, cur, tmp;
3695
3696     /*
3697      * Don't run that check in case of error. Infinite recursion
3698      * becomes possible.
3699      */
3700     if (ctxt->nbErrors != 0)
3701         return(-1);
3702
3703     parent = NULL;
3704     cur = def;
3705     while (cur != NULL) {
3706         if ((cur->type == XML_RELAXNG_ELEMENT) ||
3707             (cur->type == XML_RELAXNG_TEXT) ||
3708             (cur->type == XML_RELAXNG_DATATYPE) ||
3709             (cur->type == XML_RELAXNG_PARAM) ||
3710             (cur->type == XML_RELAXNG_LIST) ||
3711             (cur->type == XML_RELAXNG_VALUE) ||
3712             (cur->type == XML_RELAXNG_EMPTY))
3713             return(0);
3714         if ((cur->type == XML_RELAXNG_CHOICE) ||
3715             (cur->type == XML_RELAXNG_INTERLEAVE) ||
3716             (cur->type == XML_RELAXNG_GROUP) ||
3717             (cur->type == XML_RELAXNG_ONEORMORE) ||
3718             (cur->type == XML_RELAXNG_ZEROORMORE) ||
3719             (cur->type == XML_RELAXNG_OPTIONAL) ||
3720             (cur->type == XML_RELAXNG_PARENTREF) ||
3721             (cur->type == XML_RELAXNG_EXTERNALREF) ||
3722             (cur->type == XML_RELAXNG_REF) ||
3723             (cur->type == XML_RELAXNG_DEF)) {
3724             if (cur->content != NULL) {
3725                 parent = cur;
3726                 cur = cur->content;
3727                 tmp = cur;
3728                 while (tmp != NULL) {
3729                     tmp->parent = parent;
3730                     tmp = tmp->next;
3731                 }
3732                 continue;
3733             }
3734         }
3735         if (cur == def)
3736             break;
3737         if (cur->next != NULL) {
3738             cur = cur->next;
3739             continue;
3740         }
3741         do {
3742             cur = cur->parent;
3743             if (cur == NULL) break;
3744             if (cur == def) return(1);
3745             if (cur->next != NULL) {
3746                 cur = cur->next;
3747                 break;
3748             }
3749         } while (cur != NULL);
3750     }
3751     return(1);
3752 }
3753                              
3754 /**
3755  * xmlRelaxNGGetElements:
3756  * @ctxt:  a Relax-NG parser context
3757  * @def:  the definition definition
3758  * @eora:  gather elements (0) or attributes (1)
3759  *
3760  * Compute the list of top elements a definition can generate
3761  *
3762  * Returns a list of elements or NULL if none was found.
3763  */
3764 static xmlRelaxNGDefinePtr *
3765 xmlRelaxNGGetElements(xmlRelaxNGParserCtxtPtr ctxt,
3766                       xmlRelaxNGDefinePtr def,
3767                       int eora) {
3768     xmlRelaxNGDefinePtr *ret = NULL, parent, cur, tmp;
3769     int len = 0;
3770     int max = 0;
3771
3772     /*
3773      * Don't run that check in case of error. Infinite recursion
3774      * becomes possible.
3775      */
3776     if (ctxt->nbErrors != 0)
3777         return(NULL);
3778
3779     parent = NULL;
3780     cur = def;
3781     while (cur != NULL) {
3782         if (((eora == 0) && ((cur->type == XML_RELAXNG_ELEMENT) ||
3783              (cur->type == XML_RELAXNG_TEXT))) ||
3784             ((eora == 1) && (cur->type == XML_RELAXNG_ATTRIBUTE))) {
3785             if (ret == NULL) {
3786                 max = 10;
3787                 ret = (xmlRelaxNGDefinePtr *)
3788                     xmlMalloc((max + 1) * sizeof(xmlRelaxNGDefinePtr));
3789                 if (ret == NULL) {
3790                     if (ctxt->error != NULL)
3791                         ctxt->error(ctxt->userData,
3792                             "Out of memory in element search\n");
3793                     ctxt->nbErrors++;
3794                     return(NULL);
3795                 }
3796             } else if (max <= len) {
3797                 max *= 2;
3798                 ret = xmlRealloc(ret, (max + 1) * sizeof(xmlRelaxNGDefinePtr));
3799                 if (ret == NULL) {
3800                     if (ctxt->error != NULL)
3801                         ctxt->error(ctxt->userData,
3802                             "Out of memory in element search\n");
3803                     ctxt->nbErrors++;
3804                     return(NULL);
3805                 }
3806             }
3807             ret[len++] = cur;
3808             ret[len] = NULL;
3809         } else if ((cur->type == XML_RELAXNG_CHOICE) ||
3810                    (cur->type == XML_RELAXNG_INTERLEAVE) ||
3811                    (cur->type == XML_RELAXNG_GROUP) ||
3812                    (cur->type == XML_RELAXNG_ONEORMORE) ||
3813                    (cur->type == XML_RELAXNG_ZEROORMORE) ||
3814                    (cur->type == XML_RELAXNG_OPTIONAL) ||
3815                    (cur->type == XML_RELAXNG_PARENTREF) ||
3816                    (cur->type == XML_RELAXNG_REF) ||
3817                    (cur->type == XML_RELAXNG_DEF)) {
3818             /*
3819              * Don't go within elements or attributes or string values.
3820              * Just gather the element top list
3821              */
3822             if (cur->content != NULL) {
3823                 parent = cur;
3824                 cur = cur->content;
3825                 tmp = cur;
3826                 while (tmp != NULL) {
3827                     tmp->parent = parent;
3828                     tmp = tmp->next;
3829                 }
3830                 continue;
3831             }
3832         }
3833         if (cur == def)
3834             break;
3835         if (cur->next != NULL) {
3836             cur = cur->next;
3837             continue;
3838         }
3839         do {
3840             cur = cur->parent;
3841             if (cur == NULL) break;
3842             if (cur == def) return(ret);
3843             if (cur->next != NULL) {
3844                 cur = cur->next;
3845                 break;
3846             }
3847         } while (cur != NULL);
3848     }
3849     return(ret);
3850 }
3851                              
3852 /**
3853  * xmlRelaxNGCheckChoiceDeterminism:
3854  * @ctxt:  a Relax-NG parser context
3855  * @def:  the choice definition
3856  *
3857  * Also used to find indeterministic pattern in choice
3858  */
3859 static void
3860 xmlRelaxNGCheckChoiceDeterminism(xmlRelaxNGParserCtxtPtr ctxt,
3861                                  xmlRelaxNGDefinePtr def) {
3862     xmlRelaxNGDefinePtr **list;
3863     xmlRelaxNGDefinePtr cur;
3864     int nbchild = 0, i, j, ret;
3865     int is_nullable = 0;
3866     int is_indeterminist = 0;
3867     xmlHashTablePtr triage = NULL;
3868     int is_triable = 1;
3869
3870     if ((def == NULL) ||
3871         (def->type != XML_RELAXNG_CHOICE))
3872         return;
3873
3874     if (def->dflags & IS_PROCESSED)
3875         return;
3876
3877     /*
3878      * Don't run that check in case of error. Infinite recursion
3879      * becomes possible.
3880      */
3881     if (ctxt->nbErrors != 0)
3882         return;
3883
3884     is_nullable = xmlRelaxNGIsNullable(def);
3885
3886     cur = def->content;
3887     while (cur != NULL) {
3888         nbchild++;
3889         cur = cur->next;
3890     }
3891
3892     list = (xmlRelaxNGDefinePtr **) xmlMalloc(nbchild *
3893                                               sizeof(xmlRelaxNGDefinePtr *));
3894     if (list == NULL) {
3895         if (ctxt->error != NULL)
3896             ctxt->error(ctxt->userData,
3897                 "Out of memory in choice computation\n");
3898         ctxt->nbErrors++;
3899         return;
3900     }
3901     i = 0;
3902     /*
3903      * a bit strong but safe
3904      */
3905     if (is_nullable == 0) {
3906         triage = xmlHashCreate(10);
3907     } else {
3908         is_triable = 0;
3909     }
3910     cur = def->content;
3911     while (cur != NULL) {
3912         list[i] = xmlRelaxNGGetElements(ctxt, cur, 0);
3913         if ((list[i] == NULL) || (list[i][0] == NULL)) {
3914             is_triable = 0;
3915         } else if (is_triable == 1) {
3916             xmlRelaxNGDefinePtr *tmp;
3917             int res;
3918
3919             tmp = list[i];
3920             while ((*tmp != NULL) && (is_triable == 1)) {
3921                 if ((*tmp)->type == XML_RELAXNG_TEXT) {
3922                     res = xmlHashAddEntry2(triage,
3923                                            BAD_CAST "#text", NULL,
3924                                            (void *)cur);
3925                     if (res != 0)
3926                         is_triable = -1;
3927                 } else if (((*tmp)->type == XML_RELAXNG_ELEMENT) &&
3928                            ((*tmp)->name != NULL)) {
3929                     if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
3930                         res = xmlHashAddEntry2(triage,
3931                                        (*tmp)->name, NULL,
3932                                        (void *)cur);
3933                     else
3934                         res = xmlHashAddEntry2(triage,
3935                                        (*tmp)->name, (*tmp)->ns,
3936                                        (void *)cur);
3937                     if (res != 0)
3938                         is_triable = -1;
3939                 } else if ((*tmp)->type == XML_RELAXNG_ELEMENT) {
3940                     if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
3941                         res = xmlHashAddEntry2(triage,
3942                                        BAD_CAST "#any", NULL,
3943                                        (void *)cur);
3944                     else
3945                         res = xmlHashAddEntry2(triage,
3946                                        BAD_CAST "#any", (*tmp)->ns,
3947                                        (void *)cur);
3948                     if (res != 0)
3949                         is_triable = -1;
3950                 } else {
3951                     is_triable = -1;
3952                 }
3953                 tmp++;
3954             }
3955         }
3956         i++;
3957         cur = cur->next;
3958     }
3959
3960     for (i = 0;i < nbchild;i++) {
3961         if (list[i] == NULL)
3962             continue;
3963         for (j = 0;j < i;j++) {
3964             if (list[j] == NULL)
3965                 continue;
3966             ret = xmlRelaxNGCompareElemDefLists(ctxt, list[i], list[j]);
3967             if (ret == 0) {
3968                 is_indeterminist = 1;
3969             }
3970         }
3971     }
3972     for (i = 0;i < nbchild;i++) {
3973         if (list[i] != NULL)
3974             xmlFree(list[i]);
3975     }
3976
3977     xmlFree(list);
3978     if (is_indeterminist) {
3979         def->dflags |= IS_INDETERMINIST;
3980     }
3981     if (is_triable == 1) {
3982         def->dflags |= IS_TRIABLE;
3983         def->data = triage;
3984     } else if (triage != NULL) {
3985         xmlHashFree(triage, NULL);
3986     }
3987     def->dflags |= IS_PROCESSED;
3988 }
3989
3990 /**
3991  * xmlRelaxNGCheckGroupAttrs:
3992  * @ctxt:  a Relax-NG parser context
3993  * @def:  the group definition
3994  *
3995  * Detects violations of rule 7.3
3996  */
3997 static void
3998 xmlRelaxNGCheckGroupAttrs(xmlRelaxNGParserCtxtPtr ctxt,
3999                           xmlRelaxNGDefinePtr def) {
4000     xmlRelaxNGDefinePtr **list;
4001     xmlRelaxNGDefinePtr cur;
4002     int nbchild = 0, i, j, ret;
4003
4004     if ((def == NULL) ||
4005         ((def->type != XML_RELAXNG_GROUP) &&
4006          (def->type != XML_RELAXNG_ELEMENT)))
4007         return;
4008
4009     if (def->dflags & IS_PROCESSED)
4010         return;
4011
4012     /*
4013      * Don't run that check in case of error. Infinite recursion
4014      * becomes possible.
4015      */
4016     if (ctxt->nbErrors != 0)
4017         return;
4018
4019     cur = def->attrs;
4020     while (cur != NULL) {
4021         nbchild++;
4022         cur = cur->next;
4023     }
4024     cur = def->content;
4025     while (cur != NULL) {
4026         nbchild++;
4027         cur = cur->next;
4028     }
4029
4030     list = (xmlRelaxNGDefinePtr **) xmlMalloc(nbchild *
4031                                               sizeof(xmlRelaxNGDefinePtr *));
4032     if (list == NULL) {
4033         if (ctxt->error != NULL)
4034             ctxt->error(ctxt->userData,
4035                 "Out of memory in group computation\n");
4036         ctxt->nbErrors++;
4037         return;
4038     }
4039     i = 0;
4040     cur = def->attrs;
4041     while (cur != NULL) {
4042         list[i] = xmlRelaxNGGetElements(ctxt, cur, 1);
4043         i++;
4044         cur = cur->next;
4045     }
4046     cur = def->content;
4047     while (cur != NULL) {
4048         list[i] = xmlRelaxNGGetElements(ctxt, cur, 1);
4049         i++;
4050         cur = cur->next;
4051     }
4052
4053     for (i = 0;i < nbchild;i++) {
4054         if (list[i] == NULL)
4055             continue;
4056         for (j = 0;j < i;j++) {
4057             if (list[j] == NULL)
4058                 continue;
4059             ret = xmlRelaxNGCompareElemDefLists(ctxt, list[i], list[j]);
4060             if (ret == 0) {
4061                 if (ctxt->error != NULL)
4062                     ctxt->error(ctxt->userData,
4063                         "Attributes conflicts in group\n");
4064                 ctxt->nbErrors++;
4065             }
4066         }
4067     }
4068     for (i = 0;i < nbchild;i++) {
4069         if (list[i] != NULL)
4070             xmlFree(list[i]);
4071     }
4072
4073     xmlFree(list);
4074     def->dflags |= IS_PROCESSED;
4075 }
4076
4077 /**
4078  * xmlRelaxNGComputeInterleaves:
4079  * @def:  the interleave definition
4080  * @ctxt:  a Relax-NG parser context
4081  * @name:  the definition name
4082  *
4083  * A lot of work for preprocessing interleave definitions
4084  * is potentially needed to get a decent execution speed at runtime
4085  *   - trying to get a total order on the element nodes generated
4086  *     by the interleaves, order the list of interleave definitions
4087  *     following that order.
4088  *   - if <text/> is used to handle mixed content, it is better to
4089  *     flag this in the define and simplify the runtime checking
4090  *     algorithm
4091  */
4092 static void
4093 xmlRelaxNGComputeInterleaves(xmlRelaxNGDefinePtr def,
4094                              xmlRelaxNGParserCtxtPtr ctxt,
4095                              xmlChar *name ATTRIBUTE_UNUSED) {
4096     xmlRelaxNGDefinePtr cur, *tmp;
4097
4098     xmlRelaxNGPartitionPtr partitions = NULL;
4099     xmlRelaxNGInterleaveGroupPtr *groups = NULL;
4100     xmlRelaxNGInterleaveGroupPtr group;
4101     int i,j,ret, res;
4102     int nbgroups = 0;
4103     int nbchild = 0;
4104     int is_mixed = 0;
4105     int is_determinist = 1;
4106
4107     /*
4108      * Don't run that check in case of error. Infinite recursion
4109      * becomes possible.
4110      */
4111     if (ctxt->nbErrors != 0)
4112         return;
4113
4114 #ifdef DEBUG_INTERLEAVE
4115     xmlGenericError(xmlGenericErrorContext,
4116                     "xmlRelaxNGComputeInterleaves(%s)\n",
4117                     name);
4118 #endif
4119     cur = def->content;
4120     while (cur != NULL) {
4121         nbchild++;
4122         cur = cur->next;
4123     }
4124     
4125 #ifdef DEBUG_INTERLEAVE
4126     xmlGenericError(xmlGenericErrorContext, "  %d child\n", nbchild);
4127 #endif
4128     groups = (xmlRelaxNGInterleaveGroupPtr *)
4129         xmlMalloc(nbchild * sizeof(xmlRelaxNGInterleaveGroupPtr));
4130     if (groups == NULL)
4131         goto error;
4132     cur = def->content;
4133     while (cur != NULL) {
4134         groups[nbgroups] = (xmlRelaxNGInterleaveGroupPtr)
4135             xmlMalloc(sizeof(xmlRelaxNGInterleaveGroup));
4136         if (groups[nbgroups] == NULL)
4137             goto error;
4138         if (cur->type == XML_RELAXNG_TEXT)
4139             is_mixed++;
4140         groups[nbgroups]->rule = cur;
4141         groups[nbgroups]->defs = xmlRelaxNGGetElements(ctxt, cur, 0);
4142         groups[nbgroups]->attrs = xmlRelaxNGGetElements(ctxt, cur, 1);
4143         nbgroups++;
4144         cur = cur->next;
4145     }
4146 #ifdef DEBUG_INTERLEAVE
4147     xmlGenericError(xmlGenericErrorContext, "  %d groups\n", nbgroups);
4148 #endif
4149
4150     /*
4151      * Let's check that all rules makes a partitions according to 7.4
4152      */
4153     partitions = (xmlRelaxNGPartitionPtr)
4154                 xmlMalloc(sizeof(xmlRelaxNGPartition));
4155     if (partitions == NULL)
4156         goto error;
4157     memset(partitions, 0, sizeof(xmlRelaxNGPartition));
4158     partitions->nbgroups = nbgroups;
4159     partitions->triage = xmlHashCreate(nbgroups);
4160     for (i = 0;i < nbgroups;i++) {
4161         group = groups[i];
4162         for (j = i+1;j < nbgroups;j++) {
4163             if (groups[j] == NULL)
4164                 continue;
4165             
4166             ret = xmlRelaxNGCompareElemDefLists(ctxt, group->defs,
4167                                                 groups[j]->defs);
4168             if (ret == 0) {
4169                 if (ctxt->error != NULL)
4170                     ctxt->error(ctxt->userData,
4171                         "Element or text conflicts in interleave\n");
4172                 ctxt->nbErrors++;
4173             }
4174             ret = xmlRelaxNGCompareElemDefLists(ctxt, group->attrs,
4175                                                 groups[j]->attrs);
4176             if (ret == 0) {
4177                 if (ctxt->error != NULL)
4178                     ctxt->error(ctxt->userData,
4179                         "Attributes conflicts in interleave\n");
4180                 ctxt->nbErrors++;
4181             }
4182         }
4183         tmp = group->defs;
4184         if ((tmp != NULL) && (*tmp != NULL)) {
4185             while (*tmp != NULL) {
4186                 if ((*tmp)->type == XML_RELAXNG_TEXT) {
4187                     res = xmlHashAddEntry2(partitions->triage,
4188                                            BAD_CAST "#text", NULL,
4189                                            (void *)(long)(i + 1));
4190                     if (res != 0)
4191                         is_determinist = -1;
4192                 } else if (((*tmp)->type == XML_RELAXNG_ELEMENT) &&
4193                            ((*tmp)->name != NULL)) {
4194                     if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
4195                         res = xmlHashAddEntry2(partitions->triage,
4196                                        (*tmp)->name, NULL,
4197                                        (void *)(long)(i + 1));
4198                     else
4199                         res = xmlHashAddEntry2(partitions->triage,
4200                                        (*tmp)->name, (*tmp)->ns,
4201                                        (void *)(long)(i + 1));
4202                     if (res != 0)
4203                         is_determinist = -1;
4204                 } else if ((*tmp)->type == XML_RELAXNG_ELEMENT) {
4205                     if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
4206                         res = xmlHashAddEntry2(partitions->triage,
4207                                        BAD_CAST "#any", NULL,
4208                                        (void *)(long)(i + 1));
4209                     else
4210                         res = xmlHashAddEntry2(partitions->triage,
4211                                        BAD_CAST "#any", (*tmp)->ns,
4212                                        (void *)(long)(i + 1));
4213                     if ((*tmp)->nameClass != NULL)
4214                         is_determinist = 2;
4215                     if (res != 0)
4216                         is_determinist = -1;
4217                 } else {
4218                     is_determinist = -1;
4219                 }
4220                 tmp++;
4221             }
4222         } else {
4223             is_determinist = 0;
4224         }
4225     }
4226     partitions->groups = groups;
4227
4228     /*
4229      * and save the partition list back in the def
4230      */
4231     def->data = partitions;
4232     if (is_mixed != 0)
4233         def->dflags |= IS_MIXED;
4234     if (is_determinist == 1)
4235         partitions->flags = IS_DETERMINIST;
4236     if (is_determinist == 2)
4237         partitions->flags = IS_DETERMINIST | IS_NEEDCHECK;
4238     return;
4239
4240 error:
4241     if (ctxt->error != NULL)
4242         ctxt->error(ctxt->userData,
4243             "Out of memory in interleave computation\n");
4244     ctxt->nbErrors++;
4245     if (groups != NULL) {
4246         for (i = 0;i < nbgroups;i++)
4247             if (groups[i] != NULL) {
4248                 if (groups[i]->defs != NULL)
4249                     xmlFree(groups[i]->defs);
4250                 xmlFree(groups[i]);
4251             }
4252         xmlFree(groups);
4253     }
4254     xmlRelaxNGFreePartition(partitions);
4255 }
4256
4257 /**
4258  * xmlRelaxNGParseInterleave:
4259  * @ctxt:  a Relax-NG parser context
4260  * @node:  the data node.
4261  *
4262  * parse the content of a RelaxNG interleave node.
4263  *
4264  * Returns the definition pointer or NULL in case of error
4265  */
4266 static xmlRelaxNGDefinePtr
4267 xmlRelaxNGParseInterleave(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
4268     xmlRelaxNGDefinePtr def = NULL;
4269     xmlRelaxNGDefinePtr last = NULL, cur;
4270     xmlNodePtr child;
4271
4272     def = xmlRelaxNGNewDefine(ctxt, node);
4273     if (def == NULL) {
4274         return(NULL);
4275     }
4276     def->type = XML_RELAXNG_INTERLEAVE;
4277
4278     if (ctxt->interleaves == NULL)
4279         ctxt->interleaves = xmlHashCreate(10);
4280     if (ctxt->interleaves == NULL) {
4281         if (ctxt->error != NULL)
4282             ctxt->error(ctxt->userData,
4283                 "Failed to create interleaves hash table\n");
4284         ctxt->nbErrors++;
4285     } else {
4286         char name[32];
4287
4288         snprintf(name, 32, "interleave%d", ctxt->nbInterleaves++);
4289         if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST name, def) < 0) {
4290             if (ctxt->error != NULL)
4291                 ctxt->error(ctxt->userData,
4292                     "Failed to add %s to hash table\n", name);
4293             ctxt->nbErrors++;
4294         }
4295     }
4296     child = node->children;
4297     if (child == NULL) {
4298         if (ctxt->error != NULL)
4299             ctxt->error(ctxt->userData, "Element interleave is empty\n");
4300         ctxt->nbErrors++;
4301     }
4302     while (child != NULL) {
4303         if (IS_RELAXNG(child, "element")) {
4304             cur = xmlRelaxNGParseElement(ctxt, child);
4305         } else {
4306             cur = xmlRelaxNGParsePattern(ctxt, child);
4307         }
4308         if (cur != NULL) {
4309             cur->parent = def;
4310             if (last == NULL) {
4311                 def->content = last = cur;
4312             } else {
4313                 last->next = cur;
4314                 last = cur;
4315             }
4316         }
4317         child = child->next;
4318     }
4319
4320     return(def);
4321 }
4322
4323 /**
4324  * xmlRelaxNGParseInclude:
4325  * @ctxt:  a Relax-NG parser context
4326  * @node:  the include node
4327  *
4328  * Integrate the content of an include node in the current grammar
4329  *
4330  * Returns 0 in case of success or -1 in case of error
4331  */
4332 static int
4333 xmlRelaxNGParseInclude(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
4334     xmlRelaxNGIncludePtr incl;
4335     xmlNodePtr root;
4336     int ret = 0, tmp;
4337
4338     incl = node->_private;
4339     if (incl == NULL) {
4340         if (ctxt->error != NULL)
4341             ctxt->error(ctxt->userData,
4342                 "Include node has no data\n");
4343         ctxt->nbErrors++;
4344         return(-1);
4345     }
4346     root = xmlDocGetRootElement(incl->doc);
4347     if (root == NULL) {
4348         if (ctxt->error != NULL)
4349             ctxt->error(ctxt->userData,
4350                 "Include document is empty\n");
4351         ctxt->nbErrors++;
4352         return(-1);
4353     }
4354     if (!xmlStrEqual(root->name, BAD_CAST "grammar")) {
4355         if (ctxt->error != NULL)
4356             ctxt->error(ctxt->userData,
4357                 "Include document root is not a grammar\n");
4358         ctxt->nbErrors++;
4359         return(-1);
4360     }
4361
4362     /*
4363      * Merge the definition from both the include and the internal list
4364      */
4365     if (root->children != NULL) {
4366         tmp = xmlRelaxNGParseGrammarContent(ctxt, root->children);
4367         if (tmp != 0)
4368             ret = -1;
4369     }
4370     if (node->children != NULL) {
4371         tmp = xmlRelaxNGParseGrammarContent(ctxt, node->children);
4372         if (tmp != 0)
4373             ret = -1;
4374     }
4375     return(ret);
4376 }
4377
4378 /**
4379  * xmlRelaxNGParseDefine:
4380  * @ctxt:  a Relax-NG parser context
4381  * @node:  the define node
4382  *
4383  * parse the content of a RelaxNG define element node.
4384  *
4385  * Returns 0 in case of success or -1 in case of error
4386  */
4387 static int
4388 xmlRelaxNGParseDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
4389     xmlChar *name;
4390     int ret = 0, tmp;
4391     xmlRelaxNGDefinePtr def;
4392     const xmlChar *olddefine;
4393
4394     name = xmlGetProp(node, BAD_CAST "name");
4395     if (name == NULL) {
4396         if (ctxt->error != NULL)
4397             ctxt->error(ctxt->userData,
4398                         "define has no name\n");
4399         ctxt->nbErrors++;
4400     } else {
4401         xmlRelaxNGNormExtSpace(name);
4402         if (xmlValidateNCName(name, 0)) {
4403             if (ctxt->error != NULL)
4404                 ctxt->error(ctxt->userData,
4405                     "define name '%s' is not an NCName\n",
4406                             name);
4407             ctxt->nbErrors++;
4408         }
4409         def = xmlRelaxNGNewDefine(ctxt, node);
4410         if (def == NULL) {
4411             xmlFree(name);
4412             return(-1);
4413         }
4414         def->type = XML_RELAXNG_DEF;
4415         def->name = name;
4416         if (node->children == NULL) {
4417             if (ctxt->error != NULL)
4418                 ctxt->error(ctxt->userData,
4419                             "define has no children\n");
4420             ctxt->nbErrors++;
4421         } else {
4422             olddefine = ctxt->define;
4423             ctxt->define = name;
4424             def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4425             ctxt->define = olddefine;
4426         }
4427         if (ctxt->grammar->defs == NULL)
4428             ctxt->grammar->defs = xmlHashCreate(10);
4429         if (ctxt->grammar->defs == NULL) {
4430             if (ctxt->error != NULL)
4431                 ctxt->error(ctxt->userData,
4432                             "Could not create definition hash\n");
4433             ctxt->nbErrors++;
4434             ret = -1;
4435         } else {
4436             tmp = xmlHashAddEntry(ctxt->grammar->defs, name, def);
4437             if (tmp < 0) {
4438                 xmlRelaxNGDefinePtr prev;
4439
4440                 prev = xmlHashLookup(ctxt->grammar->defs, name);
4441                 if (prev == NULL) {
4442                     if (ctxt->error != NULL)
4443                         ctxt->error(ctxt->userData,
4444                             "Internal error on define aggregation of %s\n",
4445                                     name);
4446                     ctxt->nbErrors++;
4447                     ret = -1;
4448                 } else {
4449                     while (prev->nextHash != NULL)
4450                         prev = prev->nextHash;
4451                     prev->nextHash = def;
4452                 }
4453             }
4454         }
4455     }
4456     return(ret);
4457 }
4458
4459 /**
4460  * xmlRelaxNGProcessExternalRef:
4461  * @ctxt: the parser context
4462  * @node:  the externlRef node
4463  *
4464  * Process and compile an externlRef node
4465  *
4466  * Returns the xmlRelaxNGDefinePtr or NULL in case of error
4467  */
4468 static xmlRelaxNGDefinePtr
4469 xmlRelaxNGProcessExternalRef(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
4470     xmlRelaxNGDocumentPtr docu;
4471     xmlNodePtr root, tmp;
4472     xmlChar *ns;
4473     int newNs = 0, oldflags;
4474     xmlRelaxNGDefinePtr def;
4475
4476     docu = node->_private;
4477     if (docu != NULL) {
4478         def = xmlRelaxNGNewDefine(ctxt, node);
4479         if (def == NULL)
4480             return(NULL);
4481         def->type = XML_RELAXNG_EXTERNALREF;
4482         
4483         if (docu->content == NULL) {
4484             /*
4485              * Then do the parsing for good
4486              */
4487             root = xmlDocGetRootElement(docu->doc);
4488             if (root == NULL) {
4489                 if (ctxt->error != NULL)
4490                     ctxt->error(ctxt->userData,
4491                             "xmlRelaxNGParse: %s is empty\n",
4492                                 ctxt->URL);
4493                 ctxt->nbErrors++;
4494                 return (NULL);
4495             }
4496             /*
4497              * ns transmission rules
4498              */
4499             ns = xmlGetProp(root, BAD_CAST "ns");
4500             if (ns == NULL) {
4501                 tmp = node;
4502                 while ((tmp != NULL) &&
4503                        (tmp->type == XML_ELEMENT_NODE)) {
4504                     ns = xmlGetProp(tmp, BAD_CAST "ns");
4505                     if (ns != NULL) {
4506                         break;
4507                     }
4508                     tmp = tmp->parent;
4509                 }
4510                 if (ns != NULL) {
4511                     xmlSetProp(root, BAD_CAST "ns", ns);
4512                     newNs = 1;
4513                     xmlFree(ns);
4514                 }
4515             } else {
4516                 xmlFree(ns);
4517             }
4518
4519             /*
4520              * Parsing to get a precompiled schemas.
4521              */
4522             oldflags = ctxt->flags;
4523             ctxt->flags |= XML_RELAXNG_IN_EXTERNALREF;
4524             docu->schema = xmlRelaxNGParseDocument(ctxt, root);
4525             ctxt->flags = oldflags;
4526             if ((docu->schema != NULL) &&
4527                 (docu->schema->topgrammar != NULL)) {
4528                 docu->content = docu->schema->topgrammar->start;
4529             }
4530
4531             /*
4532              * the externalRef may be reused in a different ns context
4533              */
4534             if (newNs == 1) {
4535                 xmlUnsetProp(root, BAD_CAST "ns");
4536             }
4537         }
4538         def->content = docu->content;
4539     } else {
4540         def = NULL;
4541     }
4542     return(def);
4543 }
4544
4545 /**
4546  * xmlRelaxNGParsePattern:
4547  * @ctxt:  a Relax-NG parser context
4548  * @node:  the pattern node.
4549  *
4550  * parse the content of a RelaxNG pattern node.
4551  *
4552  * Returns the definition pointer or NULL in case of error or if no
4553  *     pattern is generated.
4554  */
4555 static xmlRelaxNGDefinePtr
4556 xmlRelaxNGParsePattern(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
4557     xmlRelaxNGDefinePtr def = NULL;
4558
4559     if (node == NULL) {
4560         return(NULL);
4561     }
4562     if (IS_RELAXNG(node, "element")) {
4563         def = xmlRelaxNGParseElement(ctxt, node);
4564     } else if (IS_RELAXNG(node, "attribute")) {
4565         def = xmlRelaxNGParseAttribute(ctxt, node);
4566     } else if (IS_RELAXNG(node, "empty")) {
4567         def = xmlRelaxNGNewDefine(ctxt, node);
4568         if (def == NULL)
4569             return(NULL);
4570         def->type = XML_RELAXNG_EMPTY;
4571         if (node->children != NULL) {
4572             if (ctxt->error != NULL)
4573                 ctxt->error(ctxt->userData, "empty: had a child node\n");
4574             ctxt->nbErrors++;
4575         }
4576     } else if (IS_RELAXNG(node, "text")) {
4577         def = xmlRelaxNGNewDefine(ctxt, node);
4578         if (def == NULL)
4579             return(NULL);
4580         def->type = XML_RELAXNG_TEXT;
4581         if (node->children != NULL) {
4582             if (ctxt->error != NULL)
4583                 ctxt->error(ctxt->userData, "text: had a child node\n");
4584             ctxt->nbErrors++;
4585         }
4586     } else if (IS_RELAXNG(node, "zeroOrMore")) {
4587         def = xmlRelaxNGNewDefine(ctxt, node);
4588         if (def == NULL)
4589             return(NULL);
4590         def->type = XML_RELAXNG_ZEROORMORE;
4591         if (node->children == NULL) {
4592             if (ctxt->error != NULL)
4593                 ctxt->error(ctxt->userData,
4594                             "Element %s is empty\n", node->name);
4595             ctxt->nbErrors++;
4596         } else {
4597             def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 1);
4598         } 
4599     } else if (IS_RELAXNG(node, "oneOrMore")) {
4600         def = xmlRelaxNGNewDefine(ctxt, node);
4601         if (def == NULL)
4602             return(NULL);
4603         def->type = XML_RELAXNG_ONEORMORE;
4604         if (node->children == NULL) {
4605             if (ctxt->error != NULL)
4606                 ctxt->error(ctxt->userData,
4607                             "Element %s is empty\n", node->name);
4608             ctxt->nbErrors++;
4609         } else {
4610             def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 1);
4611         } 
4612     } else if (IS_RELAXNG(node, "optional")) {
4613         def = xmlRelaxNGNewDefine(ctxt, node);
4614         if (def == NULL)
4615             return(NULL);
4616         def->type = XML_RELAXNG_OPTIONAL;
4617         if (node->children == NULL) {
4618             if (ctxt->error != NULL)
4619                 ctxt->error(ctxt->userData,
4620                             "Element %s is empty\n", node->name);
4621             ctxt->nbErrors++;
4622         } else {
4623             def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 1);
4624         } 
4625     } else if (IS_RELAXNG(node, "choice")) {
4626         def = xmlRelaxNGNewDefine(ctxt, node);
4627         if (def == NULL)
4628             return(NULL);
4629         def->type = XML_RELAXNG_CHOICE;
4630         if (node->children == NULL) {
4631             if (ctxt->error != NULL)
4632                 ctxt->error(ctxt->userData,
4633                             "Element %s is empty\n", node->name);
4634             ctxt->nbErrors++;
4635         } else {
4636             def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4637         } 
4638     } else if (IS_RELAXNG(node, "group")) {
4639         def = xmlRelaxNGNewDefine(ctxt, node);
4640         if (def == NULL)
4641             return(NULL);
4642         def->type = XML_RELAXNG_GROUP;
4643         if (node->children == NULL) {
4644             if (ctxt->error != NULL)
4645                 ctxt->error(ctxt->userData,
4646                             "Element %s is empty\n", node->name);
4647             ctxt->nbErrors++;
4648         } else {
4649             def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4650         } 
4651     } else if (IS_RELAXNG(node, "ref")) {
4652         def = xmlRelaxNGNewDefine(ctxt, node);
4653         if (def == NULL)
4654             return(NULL);
4655         def->type = XML_RELAXNG_REF;
4656         def->name = xmlGetProp(node, BAD_CAST "name");
4657         if (def->name == NULL) {
4658             if (ctxt->error != NULL)
4659                 ctxt->error(ctxt->userData,
4660                             "ref has no name\n");
4661             ctxt->nbErrors++;
4662         } else {
4663             xmlRelaxNGNormExtSpace(def->name);
4664             if (xmlValidateNCName(def->name, 0)) {
4665                 if (ctxt->error != NULL)
4666                     ctxt->error(ctxt->userData,
4667                         "ref name '%s' is not an NCName\n",
4668                                 def->name);
4669                 ctxt->nbErrors++;
4670             }
4671         }
4672         if (node->children != NULL) {
4673             if (ctxt->error != NULL)
4674                 ctxt->error(ctxt->userData,
4675                             "ref is not empty\n");
4676             ctxt->nbErrors++;
4677         }
4678         if (ctxt->grammar->refs == NULL)
4679             ctxt->grammar->refs = xmlHashCreate(10);
4680         if (ctxt->grammar->refs == NULL) {
4681             if (ctxt->error != NULL)
4682                 ctxt->error(ctxt->userData,
4683                             "Could not create references hash\n");
4684             ctxt->nbErrors++;
4685             def = NULL;
4686         } else {
4687             int tmp;
4688
4689             tmp = xmlHashAddEntry(ctxt->grammar->refs, def->name, def);
4690             if (tmp < 0) {
4691                 xmlRelaxNGDefinePtr prev;
4692
4693                 prev = (xmlRelaxNGDefinePtr)
4694                       xmlHashLookup(ctxt->grammar->refs, def->name);
4695                 if (prev == NULL) {
4696                     if (def->name != NULL) {
4697                         if (ctxt->error != NULL)
4698                             ctxt->error(ctxt->userData,
4699                                 "Error refs definitions '%s'\n",
4700                                         def->name);
4701                     } else {
4702                         if (ctxt->error != NULL)
4703                             ctxt->error(ctxt->userData,
4704                                 "Error refs definitions\n");
4705                     }
4706                     ctxt->nbErrors++;
4707                     def = NULL;
4708                 } else {
4709                     def->nextHash = prev->nextHash;
4710                     prev->nextHash = def;
4711                 }
4712             }
4713         }
4714     } else if (IS_RELAXNG(node, "data")) {
4715         def = xmlRelaxNGParseData(ctxt, node);
4716     } else if (IS_RELAXNG(node, "value")) {
4717         def = xmlRelaxNGParseValue(ctxt, node);
4718     } else if (IS_RELAXNG(node, "list")) {
4719         def = xmlRelaxNGNewDefine(ctxt, node);
4720         if (def == NULL)
4721             return(NULL);
4722         def->type = XML_RELAXNG_LIST;
4723         if (node->children == NULL) {
4724             if (ctxt->error != NULL)
4725                 ctxt->error(ctxt->userData,
4726                             "Element %s is empty\n", node->name);
4727             ctxt->nbErrors++;
4728         } else {
4729             def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4730         } 
4731     } else if (IS_RELAXNG(node, "interleave")) {
4732         def = xmlRelaxNGParseInterleave(ctxt, node);
4733     } else if (IS_RELAXNG(node, "externalRef")) {
4734         def = xmlRelaxNGProcessExternalRef(ctxt, node);
4735     } else if (IS_RELAXNG(node, "notAllowed")) {
4736         def = xmlRelaxNGNewDefine(ctxt, node);
4737         if (def == NULL)
4738             return(NULL);
4739         def->type = XML_RELAXNG_NOT_ALLOWED;
4740         if (node->children != NULL) {
4741             if (ctxt->error != NULL)
4742                 ctxt->error(ctxt->userData,
4743                         "xmlRelaxNGParse: notAllowed element is not empty\n");
4744             ctxt->nbErrors++;
4745         }
4746     } else if (IS_RELAXNG(node, "grammar")) {
4747         xmlRelaxNGGrammarPtr grammar, old;
4748         xmlRelaxNGGrammarPtr oldparent;
4749
4750 #ifdef DEBUG_GRAMMAR
4751         xmlGenericError(xmlGenericErrorContext, "Found <grammar> pattern\n");
4752 #endif
4753
4754         oldparent = ctxt->parentgrammar;
4755         old = ctxt->grammar;
4756         ctxt->parentgrammar = old;
4757         grammar = xmlRelaxNGParseGrammar(ctxt, node->children);
4758         if (old != NULL) {
4759             ctxt->grammar = old;
4760             ctxt->parentgrammar = oldparent;
4761 #if 0
4762             if (grammar != NULL) {
4763                 grammar->next = old->next;
4764                 old->next = grammar;
4765             }
4766 #endif
4767         }
4768         if (grammar != NULL)
4769             def = grammar->start;
4770         else
4771             def = NULL;
4772     } else if (IS_RELAXNG(node, "parentRef")) {
4773         if (ctxt->parentgrammar == NULL) {
4774             if (ctxt->error != NULL)
4775                 ctxt->error(ctxt->userData,
4776                         "Use of parentRef without a parent grammar\n");
4777             ctxt->nbErrors++;
4778             return(NULL);
4779         }
4780         def = xmlRelaxNGNewDefine(ctxt, node);
4781         if (def == NULL)
4782             return(NULL);
4783         def->type = XML_RELAXNG_PARENTREF;
4784         def->name = xmlGetProp(node, BAD_CAST "name");
4785         if (def->name == NULL) {
4786             if (ctxt->error != NULL)
4787                 ctxt->error(ctxt->userData,
4788                             "parentRef has no name\n");
4789             ctxt->nbErrors++;
4790         } else {
4791             xmlRelaxNGNormExtSpace(def->name);
4792             if (xmlValidateNCName(def->name, 0)) {
4793                 if (ctxt->error != NULL)
4794                     ctxt->error(ctxt->userData,
4795                         "parentRef name '%s' is not an NCName\n",
4796                                 def->name);
4797                 ctxt->nbErrors++;
4798             }
4799         }
4800         if (node->children != NULL) {
4801             if (ctxt->error != NULL)
4802                 ctxt->error(ctxt->userData,
4803                             "parentRef is not empty\n");
4804             ctxt->nbErrors++;
4805         }
4806         if (ctxt->parentgrammar->refs == NULL)
4807             ctxt->parentgrammar->refs = xmlHashCreate(10);
4808         if (ctxt->parentgrammar->refs == NULL) {
4809             if (ctxt->error != NULL)
4810                 ctxt->error(ctxt->userData,
4811                             "Could not create references hash\n");
4812             ctxt->nbErrors++;
4813             def = NULL;
4814         } else if (def->name != NULL) {
4815             int tmp;
4816
4817             tmp = xmlHashAddEntry(ctxt->parentgrammar->refs, def->name, def);
4818             if (tmp < 0) {
4819                 xmlRelaxNGDefinePtr prev;
4820
4821                 prev = (xmlRelaxNGDefinePtr)
4822                       xmlHashLookup(ctxt->parentgrammar->refs, def->name);
4823                 if (prev == NULL) {
4824                     if (ctxt->error != NULL)
4825                         ctxt->error(ctxt->userData,
4826                             "Internal error parentRef definitions '%s'\n",
4827                                     def->name);
4828                     ctxt->nbErrors++;
4829                     def = NULL;
4830                 } else {
4831                     def->nextHash = prev->nextHash;
4832                     prev->nextHash = def;
4833                 }
4834             }
4835         }
4836     } else if (IS_RELAXNG(node, "mixed")) {
4837         if (node->children == NULL) {
4838             if (ctxt->error != NULL)
4839                 ctxt->error(ctxt->userData,
4840                     "Mixed is empty\n");
4841             ctxt->nbErrors++;
4842             def = NULL;
4843         } else {
4844             def = xmlRelaxNGParseInterleave(ctxt, node);
4845             if (def != NULL) {
4846                 xmlRelaxNGDefinePtr tmp;
4847
4848                 if ((def->content != NULL) && (def->content->next != NULL)) {
4849                     tmp = xmlRelaxNGNewDefine(ctxt, node);
4850                     if (tmp != NULL) {
4851                         tmp->type = XML_RELAXNG_GROUP;
4852                         tmp->content = def->content;
4853                         def->content = tmp;
4854                     }
4855                 }
4856
4857                 tmp = xmlRelaxNGNewDefine(ctxt, node);
4858                 if (tmp == NULL)
4859                     return(def);
4860                 tmp->type = XML_RELAXNG_TEXT;
4861                 tmp->next = def->content;
4862                 def->content = tmp;
4863             }
4864         }
4865     } else {
4866         if (ctxt->error != NULL)
4867             ctxt->error(ctxt->userData,
4868                 "Unexpected node %s is not a pattern\n",
4869                         node->name);
4870         ctxt->nbErrors++;
4871         def = NULL;
4872     }
4873     return(def);
4874 }
4875
4876 /**
4877  * xmlRelaxNGParseAttribute:
4878  * @ctxt:  a Relax-NG parser context
4879  * @node:  the element node
4880  *
4881  * parse the content of a RelaxNG attribute node.
4882  *
4883  * Returns the definition pointer or NULL in case of error.
4884  */
4885 static xmlRelaxNGDefinePtr
4886 xmlRelaxNGParseAttribute(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
4887     xmlRelaxNGDefinePtr ret, cur;
4888     xmlNodePtr child;
4889     int old_flags;
4890
4891     ret = xmlRelaxNGNewDefine(ctxt, node);
4892     if (ret == NULL)
4893         return(NULL);
4894     ret->type = XML_RELAXNG_ATTRIBUTE;
4895     ret->parent = ctxt->def;
4896     child = node->children;
4897     if (child == NULL) {
4898         if (ctxt->error != NULL)
4899             ctxt->error(ctxt->userData,
4900                     "xmlRelaxNGParseattribute: attribute has no children\n");
4901         ctxt->nbErrors++;
4902         return(ret);
4903     } 
4904     old_flags = ctxt->flags;
4905     ctxt->flags |= XML_RELAXNG_IN_ATTRIBUTE;
4906     cur = xmlRelaxNGParseNameClass(ctxt, child, ret);
4907     if (cur != NULL)
4908         child = child->next;
4909
4910     if (child != NULL) {
4911         cur = xmlRelaxNGParsePattern(ctxt, child);
4912         if (cur != NULL) {
4913             switch (cur->type) {
4914                 case XML_RELAXNG_EMPTY:
4915                 case XML_RELAXNG_NOT_ALLOWED:
4916                 case XML_RELAXNG_TEXT:
4917                 case XML_RELAXNG_ELEMENT:
4918                 case XML_RELAXNG_DATATYPE:
4919                 case XML_RELAXNG_VALUE:
4920                 case XML_RELAXNG_LIST:
4921                 case XML_RELAXNG_REF:
4922                 case XML_RELAXNG_PARENTREF:
4923                 case XML_RELAXNG_EXTERNALREF:
4924                 case XML_RELAXNG_DEF:
4925                 case XML_RELAXNG_ONEORMORE:
4926                 case XML_RELAXNG_ZEROORMORE:
4927                 case XML_RELAXNG_OPTIONAL:
4928                 case XML_RELAXNG_CHOICE:
4929                 case XML_RELAXNG_GROUP:
4930                 case XML_RELAXNG_INTERLEAVE:
4931                 case XML_RELAXNG_ATTRIBUTE:
4932                     ret->content = cur;
4933                     cur->parent = ret;
4934                     break;
4935                 case XML_RELAXNG_START:
4936                 case XML_RELAXNG_PARAM:
4937                 case XML_RELAXNG_EXCEPT:
4938                     if (ctxt->error != NULL)
4939                         ctxt->error(ctxt->userData,
4940                 "attribute has invalid content\n");
4941                     ctxt->nbErrors++;
4942                     break;
4943                 case XML_RELAXNG_NOOP:
4944                     if (ctxt->error != NULL)
4945                         ctxt->error(ctxt->userData,
4946                 "RNG Internal error, noop found in attribute\n");
4947                     ctxt->nbErrors++;
4948                     break;
4949             }
4950         }
4951         child = child->next;
4952     }
4953     if (child != NULL) {
4954         if (ctxt->error != NULL)
4955             ctxt->error(ctxt->userData, "attribute has multiple children\n");
4956         ctxt->nbErrors++;
4957     }
4958     ctxt->flags = old_flags;
4959     return(ret);
4960 }
4961
4962 /**
4963  * xmlRelaxNGParseExceptNameClass:
4964  * @ctxt:  a Relax-NG parser context
4965  * @node:  the except node
4966  * @attr:  1 if within an attribute, 0 if within an element
4967  *
4968  * parse the content of a RelaxNG nameClass node.
4969  *
4970  * Returns the definition pointer or NULL in case of error.
4971  */
4972 static xmlRelaxNGDefinePtr
4973 xmlRelaxNGParseExceptNameClass(xmlRelaxNGParserCtxtPtr ctxt,
4974                                xmlNodePtr node, int attr) {
4975     xmlRelaxNGDefinePtr ret, cur, last = NULL;
4976     xmlNodePtr child;
4977
4978     if (!IS_RELAXNG(node, "except")) {
4979         if (ctxt->error != NULL)
4980             ctxt->error(ctxt->userData,
4981                 "Expecting an except node\n");
4982         ctxt->nbErrors++;
4983         return(NULL);
4984     }
4985     if (node->next != NULL) {
4986         if (ctxt->error != NULL)
4987             ctxt->error(ctxt->userData,
4988                 "exceptNameClass allows only a single except node\n");
4989         ctxt->nbErrors++;
4990     }
4991     if (node->children == NULL) {
4992         if (ctxt->error != NULL)
4993             ctxt->error(ctxt->userData,
4994                 "except has no content\n");
4995         ctxt->nbErrors++;
4996         return(NULL);
4997     }
4998
4999     ret = xmlRelaxNGNewDefine(ctxt, node);
5000     if (ret == NULL)
5001         return(NULL);
5002     ret->type = XML_RELAXNG_EXCEPT;
5003     child = node->children;
5004     while (child != NULL) {
5005         cur = xmlRelaxNGNewDefine(ctxt, child);
5006         if (cur == NULL)
5007             break;
5008         if (attr)
5009             cur->type = XML_RELAXNG_ATTRIBUTE;
5010         else
5011             cur->type = XML_RELAXNG_ELEMENT;
5012         
5013         if (xmlRelaxNGParseNameClass(ctxt, child, cur) != NULL) {
5014             if (last == NULL) {
5015                 ret->content = cur;
5016             } else {
5017                 last->next = cur;
5018             }
5019             last = cur;
5020         }
5021         child = child->next;
5022     }
5023
5024     return(ret);
5025 }
5026
5027 /**
5028  * xmlRelaxNGParseNameClass:
5029  * @ctxt:  a Relax-NG parser context
5030  * @node:  the nameClass node
5031  * @def:  the current definition
5032  *
5033  * parse the content of a RelaxNG nameClass node.
5034  *
5035  * Returns the definition pointer or NULL in case of error.
5036  */
5037 static xmlRelaxNGDefinePtr
5038 xmlRelaxNGParseNameClass(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node,
5039                          xmlRelaxNGDefinePtr def) {
5040     xmlRelaxNGDefinePtr ret, tmp;
5041     xmlChar *val;
5042
5043     ret = def;
5044     if ((IS_RELAXNG(node, "name")) || (IS_RELAXNG(node, "anyName"))  ||
5045         (IS_RELAXNG(node, "nsName"))) {
5046         if ((def->type != XML_RELAXNG_ELEMENT) &&
5047             (def->type != XML_RELAXNG_ATTRIBUTE)) {
5048             ret = xmlRelaxNGNewDefine(ctxt, node);
5049             if (ret == NULL)
5050                 return(NULL);
5051             ret->parent = def;
5052             if (ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE)
5053                 ret->type = XML_RELAXNG_ATTRIBUTE;
5054             else
5055                 ret->type = XML_RELAXNG_ELEMENT;
5056         }
5057     }
5058     if (IS_RELAXNG(node, "name")) {
5059         val = xmlNodeGetContent(node);
5060         xmlRelaxNGNormExtSpace(val);
5061         if (xmlValidateNCName(val, 0)) {
5062             if (ctxt->error != NULL) {
5063                 if (node->parent != NULL)
5064                     ctxt->error(ctxt->userData,
5065                         "Element %s name '%s' is not an NCName\n",
5066                                 node->parent->name, val);
5067                 else
5068                     ctxt->error(ctxt->userData,
5069                         "name '%s' is not an NCName\n",
5070                                 val);
5071             }
5072             ctxt->nbErrors++;
5073         }
5074         ret->name = val;
5075         val = xmlGetProp(node, BAD_CAST "ns");
5076         ret->ns = val;
5077         if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
5078             (val != NULL) &&
5079             (xmlStrEqual(val, BAD_CAST "http://www.w3.org/2000/xmlns"))) {
5080             ctxt->error(ctxt->userData,
5081                 "Attribute with namespace '%s' is not allowed\n",
5082                         val);
5083             ctxt->nbErrors++;
5084         }
5085         if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
5086             (val != NULL) &&
5087             (val[0] == 0) &&
5088             (xmlStrEqual(ret->name, BAD_CAST "xmlns"))) {
5089             ctxt->error(ctxt->userData,
5090                 "Attribute with QName 'xmlns' is not allowed\n",
5091                         val);
5092             ctxt->nbErrors++;
5093         }
5094     } else if (IS_RELAXNG(node, "anyName")) {
5095         ret->name = NULL;
5096         ret->ns = NULL;
5097         if (node->children != NULL) {
5098             ret->nameClass =
5099                 xmlRelaxNGParseExceptNameClass(ctxt, node->children,
5100                                (def->type == XML_RELAXNG_ATTRIBUTE));
5101         }
5102     } else if (IS_RELAXNG(node, "nsName")) {
5103         ret->name = NULL;
5104         ret->ns = xmlGetProp(node, BAD_CAST "ns");
5105         if (ret->ns == NULL) {
5106             if (ctxt->error != NULL)
5107                 ctxt->error(ctxt->userData,
5108                     "nsName has no ns attribute\n");
5109             ctxt->nbErrors++;
5110         }
5111         if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
5112             (ret->ns != NULL) &&
5113             (xmlStrEqual(ret->ns, BAD_CAST "http://www.w3.org/2000/xmlns"))) {
5114             ctxt->error(ctxt->userData,
5115                 "Attribute with namespace '%s' is not allowed\n",
5116                         ret->ns);
5117             ctxt->nbErrors++;
5118         }
5119         if (node->children != NULL) {
5120             ret->nameClass =
5121                 xmlRelaxNGParseExceptNameClass(ctxt, node->children,
5122                                (def->type == XML_RELAXNG_ATTRIBUTE));
5123         }
5124     } else if (IS_RELAXNG(node, "choice")) {
5125         xmlNodePtr child;
5126         xmlRelaxNGDefinePtr last = NULL;
5127
5128         ret = xmlRelaxNGNewDefine(ctxt, node);
5129         if (ret == NULL)
5130             return(NULL);
5131         ret->parent = def;
5132         ret->type = XML_RELAXNG_CHOICE;
5133
5134         if (node->children == NULL) {
5135             if (ctxt->error != NULL)
5136                 ctxt->error(ctxt->userData,
5137                     "Element choice is empty\n");
5138             ctxt->nbErrors++;
5139         } else {
5140
5141             child = node->children;
5142             while (child != NULL) {
5143                 tmp = xmlRelaxNGParseNameClass(ctxt, child, ret);
5144                 if (tmp != NULL) {
5145                     if (last == NULL) {
5146                         last = ret->nameClass = tmp;
5147                     } else {
5148                         last->next = tmp;
5149                         last = tmp;
5150                     }
5151                 }
5152                 child = child->next;
5153             }
5154         }
5155     } else {
5156         if (ctxt->error != NULL)
5157             ctxt->error(ctxt->userData,
5158     "expecting name, anyName, nsName or choice : got %s\n",
5159                         node->name);
5160         ctxt->nbErrors++;
5161         return(NULL);
5162     }
5163     if (ret != def) {
5164         if (def->nameClass == NULL) {
5165             def->nameClass = ret;
5166         } else {
5167             tmp = def->nameClass;
5168             while (tmp->next != NULL) {
5169                 tmp = tmp->next;
5170             }
5171             tmp->next = ret;
5172         }
5173     }
5174     return(ret);
5175 }
5176
5177 /**
5178  * xmlRelaxNGParseElement:
5179  * @ctxt:  a Relax-NG parser context
5180  * @node:  the element node
5181  *
5182  * parse the content of a RelaxNG element node.
5183  *
5184  * Returns the definition pointer or NULL in case of error.
5185  */
5186 static xmlRelaxNGDefinePtr
5187 xmlRelaxNGParseElement(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
5188     xmlRelaxNGDefinePtr ret, cur, last;
5189     xmlNodePtr child;
5190     const xmlChar *olddefine;
5191
5192     ret = xmlRelaxNGNewDefine(ctxt, node);
5193     if (ret == NULL)
5194         return(NULL);
5195     ret->type = XML_RELAXNG_ELEMENT;
5196     ret->parent = ctxt->def;
5197     child = node->children;
5198     if (child == NULL) {
5199         if (ctxt->error != NULL)
5200             ctxt->error(ctxt->userData,
5201                         "xmlRelaxNGParseElement: element has no children\n");
5202         ctxt->nbErrors++;
5203         return(ret);
5204     } 
5205     cur = xmlRelaxNGParseNameClass(ctxt, child, ret);
5206     if (cur != NULL)
5207         child = child->next;
5208
5209     if (child == NULL) {
5210         if (ctxt->error != NULL)
5211             ctxt->error(ctxt->userData,
5212                         "xmlRelaxNGParseElement: element has no content\n");
5213         ctxt->nbErrors++;
5214         return(ret);
5215     } 
5216     olddefine = ctxt->define;
5217     ctxt->define = NULL;
5218     last = NULL;
5219     while (child != NULL) {
5220         cur = xmlRelaxNGParsePattern(ctxt, child);
5221         if (cur != NULL) {
5222             cur->parent = ret;
5223             switch (cur->type) {
5224                 case XML_RELAXNG_EMPTY:
5225                 case XML_RELAXNG_NOT_ALLOWED:
5226                 case XML_RELAXNG_TEXT:
5227                 case XML_RELAXNG_ELEMENT:
5228                 case XML_RELAXNG_DATATYPE:
5229                 case XML_RELAXNG_VALUE:
5230                 case XML_RELAXNG_LIST:
5231                 case XML_RELAXNG_REF:
5232                 case XML_RELAXNG_PARENTREF:
5233                 case XML_RELAXNG_EXTERNALREF:
5234                 case XML_RELAXNG_DEF:
5235                 case XML_RELAXNG_ZEROORMORE:
5236                 case XML_RELAXNG_ONEORMORE:
5237                 case XML_RELAXNG_OPTIONAL:
5238                 case XML_RELAXNG_CHOICE:
5239                 case XML_RELAXNG_GROUP:
5240                 case XML_RELAXNG_INTERLEAVE:
5241                     if (last == NULL) {
5242                         ret->content = last = cur;
5243                     } else {
5244                         if ((last->type == XML_RELAXNG_ELEMENT) &&
5245                             (ret->content == last)) {
5246                             ret->content = xmlRelaxNGNewDefine(ctxt, node);
5247                             if (ret->content != NULL) {
5248                                 ret->content->type = XML_RELAXNG_GROUP;
5249                                 ret->content->content = last;
5250                             } else {
5251                                 ret->content = last;
5252                             }
5253                         }
5254                         last->next = cur;
5255                         last = cur;
5256                     }
5257                     break;
5258                 case XML_RELAXNG_ATTRIBUTE:
5259                     /* HERE !!! */
5260                     cur->next = ret->attrs;
5261                     ret->attrs = cur;
5262                     break;
5263                 case XML_RELAXNG_START:
5264                     if (ctxt->error != NULL)
5265                         ctxt->error(ctxt->userData,
5266                 "RNG Internal error, start found in element\n");
5267                     ctxt->nbErrors++;
5268                     break;
5269                 case XML_RELAXNG_PARAM:
5270                     if (ctxt->error != NULL)
5271                         ctxt->error(ctxt->userData,
5272                 "RNG Internal error, param found in element\n");
5273                     ctxt->nbErrors++;
5274                     break;
5275                 case XML_RELAXNG_EXCEPT:
5276                     if (ctxt->error != NULL)
5277                         ctxt->error(ctxt->userData,
5278                 "RNG Internal error, except found in element\n");
5279                     ctxt->nbErrors++;
5280                     break;
5281                 case XML_RELAXNG_NOOP:
5282                     if (ctxt->error != NULL)
5283                         ctxt->error(ctxt->userData,
5284                 "RNG Internal error, noop found in element\n");
5285                     ctxt->nbErrors++;
5286                     break;
5287             }
5288         }
5289         child = child->next;
5290     }
5291     ctxt->define = olddefine;
5292     return(ret);
5293 }
5294
5295 /**
5296  * xmlRelaxNGParsePatterns:
5297  * @ctxt:  a Relax-NG parser context
5298  * @nodes:  list of nodes
5299  * @group:  use an implicit <group> for elements
5300  *
5301  * parse the content of a RelaxNG start node.
5302  *
5303  * Returns the definition pointer or NULL in case of error.
5304  */
5305 static xmlRelaxNGDefinePtr
5306 xmlRelaxNGParsePatterns(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes,
5307                         int group) {
5308     xmlRelaxNGDefinePtr def = NULL, last = NULL, cur, parent;
5309
5310     parent = ctxt->def;
5311     while (nodes != NULL) {
5312         if (IS_RELAXNG(nodes, "element")) {
5313             cur = xmlRelaxNGParseElement(ctxt, nodes);
5314             if (def == NULL) {
5315                 def = last = cur;
5316             } else {
5317                 if ((group == 1) && (def->type == XML_RELAXNG_ELEMENT) &&
5318                     (def == last)) {
5319                     def = xmlRelaxNGNewDefine(ctxt, nodes);
5320                     def->type = XML_RELAXNG_GROUP;
5321                     def->content = last;
5322                 }
5323                 last->next = cur;
5324                 last = cur;
5325             }
5326             cur->parent = parent;
5327         } else {
5328             cur = xmlRelaxNGParsePattern(ctxt, nodes);
5329             if (cur != NULL) {
5330                 if (def == NULL) {
5331                     def = last = cur;
5332                 } else {
5333                     last->next = cur;
5334                     last = cur;
5335                 }
5336             }
5337         }
5338         nodes = nodes->next;
5339     }
5340     return(def);
5341 }
5342
5343 /**
5344  * xmlRelaxNGParseStart:
5345  * @ctxt:  a Relax-NG parser context
5346  * @nodes:  start children nodes
5347  *
5348  * parse the content of a RelaxNG start node.
5349  *
5350  * Returns 0 in case of success, -1 in case of error
5351  */
5352 static int
5353 xmlRelaxNGParseStart(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes) {
5354     int ret = 0;
5355     xmlRelaxNGDefinePtr def = NULL, last;
5356
5357     if (nodes == NULL) {
5358         if (ctxt->error != NULL)
5359             ctxt->error(ctxt->userData,
5360                         "start has no children\n");
5361         ctxt->nbErrors++;
5362         return(-1);
5363     }
5364     if (IS_RELAXNG(nodes, "empty")) {
5365         def = xmlRelaxNGNewDefine(ctxt, nodes);
5366         if (def == NULL)
5367             return(-1);
5368         def->type = XML_RELAXNG_EMPTY;
5369         if (nodes->children != NULL) {
5370             if (ctxt->error != NULL)
5371                 ctxt->error(ctxt->userData, "element empty is not empty\n");
5372             ctxt->nbErrors++;
5373         }
5374     } else if (IS_RELAXNG(nodes, "notAllowed")) {
5375         def = xmlRelaxNGNewDefine(ctxt, nodes);
5376         if (def == NULL)
5377             return(-1);
5378         def->type = XML_RELAXNG_NOT_ALLOWED;
5379         if (nodes->children != NULL) {
5380             if (ctxt->error != NULL)
5381                 ctxt->error(ctxt->userData,
5382                         "element notAllowed is not empty\n");
5383             ctxt->nbErrors++;
5384         }
5385     } else {
5386         def = xmlRelaxNGParsePatterns(ctxt, nodes, 1);
5387     }
5388     if (ctxt->grammar->start != NULL) {
5389         last = ctxt->grammar->start;
5390         while (last->next != NULL)
5391             last = last->next;
5392         last->next = def;
5393     } else {
5394         ctxt->grammar->start = def;
5395     }
5396     nodes = nodes->next;
5397     if (nodes != NULL) {
5398         if (ctxt->error != NULL)
5399             ctxt->error(ctxt->userData,
5400                         "start more than one children\n");
5401         ctxt->nbErrors++;
5402         return(-1);
5403     }
5404     return(ret);
5405 }
5406
5407 /**
5408  * xmlRelaxNGParseGrammarContent:
5409  * @ctxt:  a Relax-NG parser context
5410  * @nodes:  grammar children nodes
5411  *
5412  * parse the content of a RelaxNG grammar node.
5413  *
5414  * Returns 0 in case of success, -1 in case of error
5415  */
5416 static int
5417 xmlRelaxNGParseGrammarContent(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes)
5418 {
5419     int ret = 0, tmp;
5420
5421     if (nodes == NULL) {
5422         if (ctxt->error != NULL)
5423             ctxt->error(ctxt->userData,
5424                         "grammar has no children\n");
5425         ctxt->nbErrors++;
5426         return(-1);
5427     }
5428     while (nodes != NULL) {
5429         if (IS_RELAXNG(nodes, "start")) {
5430             if (nodes->children == NULL) {
5431                 if (ctxt->error != NULL)
5432                     ctxt->error(ctxt->userData,
5433                                 "start has no children\n");
5434                 ctxt->nbErrors++;
5435             } else {
5436                 tmp = xmlRelaxNGParseStart(ctxt, nodes->children);
5437                 if (tmp != 0)
5438                     ret = -1;
5439             }
5440         } else if (IS_RELAXNG(nodes, "define")) {
5441             tmp = xmlRelaxNGParseDefine(ctxt, nodes);
5442             if (tmp != 0)
5443                 ret = -1;
5444         } else if (IS_RELAXNG(nodes, "include")) {
5445             tmp = xmlRelaxNGParseInclude(ctxt, nodes);
5446             if (tmp != 0)
5447                 ret = -1;
5448         } else {
5449             if (ctxt->error != NULL)
5450                 ctxt->error(ctxt->userData,
5451                         "grammar has unexpected child %s\n", nodes->name);
5452             ctxt->nbErrors++;
5453             ret = -1;
5454         }
5455         nodes = nodes->next;
5456     }
5457     return (ret);
5458 }
5459
5460 /**
5461  * xmlRelaxNGCheckReference:
5462  * @ref:  the ref
5463  * @ctxt:  a Relax-NG parser context
5464  * @name:  the name associated to the defines
5465  *
5466  * Applies the 4.17. combine attribute rule for all the define
5467  * element of a given grammar using the same name.
5468  */
5469 static void
5470 xmlRelaxNGCheckReference(xmlRelaxNGDefinePtr ref,
5471                 xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *name) {
5472     xmlRelaxNGGrammarPtr grammar;
5473     xmlRelaxNGDefinePtr def, cur;
5474
5475     grammar = ctxt->grammar;
5476     if (grammar == NULL) {
5477         if (ctxt->error != NULL)
5478             ctxt->error(ctxt->userData,
5479                     "Internal error: no grammar in CheckReference %s\n",
5480                         name);
5481         ctxt->nbErrors++;
5482         return;
5483     }
5484     if (ref->content != NULL) {
5485         if (ctxt->error != NULL)
5486             ctxt->error(ctxt->userData,
5487             "Internal error: reference has content in CheckReference %s\n",
5488                         name);
5489         ctxt->nbErrors++;
5490         return;
5491     }
5492     if (grammar->defs != NULL) {
5493         def = xmlHashLookup(grammar->defs, name);
5494         if (def != NULL) {
5495             cur = ref;
5496             while (cur != NULL) {
5497                 cur->content = def;
5498                 cur = cur->nextHash;
5499             }
5500         } else {
5501             if (ctxt->error != NULL)
5502                 ctxt->error(ctxt->userData,
5503                 "Reference %s has no matching definition\n",
5504                             name);
5505             ctxt->nbErrors++;
5506         }
5507     } else {
5508         if (ctxt->error != NULL)
5509             ctxt->error(ctxt->userData,
5510             "Reference %s has no matching definition\n",
5511                         name);
5512         ctxt->nbErrors++;
5513     }
5514 }
5515
5516 /**
5517  * xmlRelaxNGCheckCombine:
5518  * @define:  the define(s) list
5519  * @ctxt:  a Relax-NG parser context
5520  * @name:  the name associated to the defines
5521  *
5522  * Applies the 4.17. combine attribute rule for all the define
5523  * element of a given grammar using the same name.
5524  */
5525 static void
5526 xmlRelaxNGCheckCombine(xmlRelaxNGDefinePtr define,
5527         xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *name) {
5528     xmlChar *combine;
5529     int choiceOrInterleave = -1;
5530     int missing = 0;
5531     xmlRelaxNGDefinePtr cur, last, tmp, tmp2;
5532
5533     if (define->nextHash == NULL)
5534         return;
5535     cur = define;
5536     while (cur != NULL) {
5537         combine = xmlGetProp(cur->node, BAD_CAST "combine");
5538         if (combine != NULL) {
5539             if (xmlStrEqual(combine, BAD_CAST "choice")) {
5540                 if (choiceOrInterleave == -1)
5541                     choiceOrInterleave = 1;
5542                 else if (choiceOrInterleave == 0) {
5543                     if (ctxt->error != NULL)
5544                         ctxt->error(ctxt->userData,
5545                     "Defines for %s use both 'choice' and 'interleave'\n",
5546                                     name);
5547                     ctxt->nbErrors++;
5548                 }
5549             } else if (xmlStrEqual(combine, BAD_CAST "interleave")) {
5550                 if (choiceOrInterleave == -1)
5551                     choiceOrInterleave = 0;
5552                 else if (choiceOrInterleave == 1) {
5553                     if (ctxt->error != NULL)
5554                         ctxt->error(ctxt->userData,
5555                     "Defines for %s use both 'choice' and 'interleave'\n",
5556                                     name);
5557                     ctxt->nbErrors++;
5558                 }
5559             } else {
5560                 if (ctxt->error != NULL)
5561                     ctxt->error(ctxt->userData,
5562                     "Defines for %s use unknown combine value '%s''\n",
5563                                 name, combine);
5564                 ctxt->nbErrors++;
5565             }
5566             xmlFree(combine);
5567         } else {
5568             if (missing == 0)
5569                 missing = 1;
5570             else {
5571                 if (ctxt->error != NULL)
5572                     ctxt->error(ctxt->userData,
5573                     "Some defines for %s needs the combine attribute\n",
5574                                 name);
5575                 ctxt->nbErrors++;
5576             }
5577         }
5578
5579         cur = cur->nextHash;
5580     }
5581 #ifdef DEBUG
5582     xmlGenericError(xmlGenericErrorContext,
5583                     "xmlRelaxNGCheckCombine(): merging %s defines: %d\n",
5584                     name, choiceOrInterleave);
5585 #endif
5586     if (choiceOrInterleave == -1)
5587         choiceOrInterleave = 0;
5588     cur = xmlRelaxNGNewDefine(ctxt, define->node);
5589     if (cur == NULL)
5590         return;
5591     if (choiceOrInterleave == 0)
5592         cur->type = XML_RELAXNG_INTERLEAVE;
5593     else
5594         cur->type = XML_RELAXNG_CHOICE;
5595     tmp = define;
5596     last = NULL;
5597     while (tmp != NULL) {
5598         if (tmp->content != NULL) {
5599             if (tmp->content->next != NULL) {
5600                 /*
5601                  * we need first to create a wrapper.
5602                  */
5603                 tmp2 = xmlRelaxNGNewDefine(ctxt, tmp->content->node);
5604                 if (tmp2 == NULL)
5605                     break;
5606                 tmp2->type = XML_RELAXNG_GROUP;
5607                 tmp2->content = tmp->content;
5608             } else {
5609                 tmp2 = tmp->content;
5610             }
5611             if (last == NULL) {
5612                 cur->content = tmp2;
5613             } else {
5614                 last->next = tmp2;
5615             }
5616             last = tmp2;
5617         }
5618         tmp->content = cur;
5619         tmp = tmp->nextHash;
5620     }
5621     define->content = cur;
5622     if (choiceOrInterleave == 0) {
5623         if (ctxt->interleaves == NULL)
5624             ctxt->interleaves = xmlHashCreate(10);
5625         if (ctxt->interleaves == NULL) {
5626             if (ctxt->error != NULL)
5627                 ctxt->error(ctxt->userData,
5628                     "Failed to create interleaves hash table\n");
5629             ctxt->nbErrors++;
5630         } else {
5631             char tmpname[32];
5632
5633             snprintf(tmpname, 32, "interleave%d", ctxt->nbInterleaves++);
5634             if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST tmpname, cur) < 0) {
5635                 if (ctxt->error != NULL)
5636                     ctxt->error(ctxt->userData,
5637                         "Failed to add %s to hash table\n", tmpname);
5638                 ctxt->nbErrors++;
5639             }
5640         }
5641     }
5642 }
5643
5644 /**
5645  * xmlRelaxNGCombineStart:
5646  * @ctxt:  a Relax-NG parser context
5647  * @grammar:  the grammar
5648  *
5649  * Applies the 4.17. combine rule for all the start
5650  * element of a given grammar.
5651  */
5652 static void
5653 xmlRelaxNGCombineStart(xmlRelaxNGParserCtxtPtr ctxt,
5654                        xmlRelaxNGGrammarPtr grammar) {
5655     xmlRelaxNGDefinePtr starts;
5656     xmlChar *combine;
5657     int choiceOrInterleave = -1;
5658     int missing = 0;
5659     xmlRelaxNGDefinePtr cur;
5660
5661     starts = grammar->start;
5662     if ((starts == NULL) || (starts->next == NULL))
5663         return;
5664     cur = starts;
5665     while (cur != NULL) {
5666         if ((cur->node == NULL) || (cur->node->parent == NULL) ||
5667             (!xmlStrEqual(cur->node->parent->name, BAD_CAST "start"))) {
5668             combine = NULL;
5669             if (ctxt->error != NULL)
5670                 ctxt->error(ctxt->userData,
5671                     "Internal error: start element not found\n");
5672             ctxt->nbErrors++;
5673         } else {
5674             combine = xmlGetProp(cur->node->parent, BAD_CAST "combine");
5675         }
5676         
5677         if (combine != NULL) {
5678             if (xmlStrEqual(combine, BAD_CAST "choice")) {
5679                 if (choiceOrInterleave == -1)
5680                     choiceOrInterleave = 1;
5681                 else if (choiceOrInterleave == 0) {
5682                     if (ctxt->error != NULL)
5683                         ctxt->error(ctxt->userData,
5684                     "<start> use both 'choice' and 'interleave'\n");
5685                     ctxt->nbErrors++;
5686                 }
5687             } else if (xmlStrEqual(combine, BAD_CAST "interleave")) {
5688                 if (choiceOrInterleave == -1)
5689                     choiceOrInterleave = 0;
5690                 else if (choiceOrInterleave == 1) {
5691                     if (ctxt->error != NULL)
5692                         ctxt->error(ctxt->userData,
5693                     "<start> use both 'choice' and 'interleave'\n");
5694                     ctxt->nbErrors++;
5695                 }
5696             } else {
5697                 if (ctxt->error != NULL)
5698                     ctxt->error(ctxt->userData,
5699                     "<start> uses unknown combine value '%s''\n", combine);
5700                 ctxt->nbErrors++;
5701             }
5702             xmlFree(combine);
5703         } else {
5704             if (missing == 0)
5705                 missing = 1;
5706             else {
5707                 if (ctxt->error != NULL)
5708                     ctxt->error(ctxt->userData,
5709                     "Some <start> element miss the combine attribute\n");
5710                 ctxt->nbErrors++;
5711             }
5712         }
5713
5714         cur = cur->next;
5715     }
5716 #ifdef DEBUG
5717     xmlGenericError(xmlGenericErrorContext,
5718                     "xmlRelaxNGCombineStart(): merging <start>: %d\n",
5719                     choiceOrInterleave);
5720 #endif
5721     if (choiceOrInterleave == -1)
5722         choiceOrInterleave = 0;
5723     cur = xmlRelaxNGNewDefine(ctxt, starts->node);
5724     if (cur == NULL)
5725         return;
5726     if (choiceOrInterleave == 0)
5727         cur->type = XML_RELAXNG_INTERLEAVE;
5728     else
5729         cur->type = XML_RELAXNG_CHOICE;
5730     cur->content = grammar->start;
5731     grammar->start = cur;
5732     if (choiceOrInterleave == 0) {
5733         if (ctxt->interleaves == NULL)
5734             ctxt->interleaves = xmlHashCreate(10);
5735         if (ctxt->interleaves == NULL) {
5736             if (ctxt->error != NULL)
5737                 ctxt->error(ctxt->userData,
5738                     "Failed to create interleaves hash table\n");
5739             ctxt->nbErrors++;
5740         } else {
5741             char tmpname[32];
5742
5743             snprintf(tmpname, 32, "interleave%d", ctxt->nbInterleaves++);
5744             if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST tmpname, cur) < 0) {
5745                 if (ctxt->error != NULL)
5746                     ctxt->error(ctxt->userData,
5747                         "Failed to add %s to hash table\n", tmpname);
5748                 ctxt->nbErrors++;
5749             }
5750         }
5751     }
5752 }
5753
5754 /**
5755  * xmlRelaxNGCheckCycles:
5756  * @ctxt:  a Relax-NG parser context
5757  * @nodes:  grammar children nodes
5758  * @depth:  the counter
5759  *
5760  * Check for cycles.
5761  *
5762  * Returns 0 if check passed, and -1 in case of error
5763  */
5764 static int
5765 xmlRelaxNGCheckCycles(xmlRelaxNGParserCtxtPtr ctxt, 
5766                       xmlRelaxNGDefinePtr cur, int depth) {
5767     int ret = 0;
5768
5769     while ((ret == 0) && (cur != NULL)) {
5770         if ((cur->type == XML_RELAXNG_REF) ||
5771             (cur->type == XML_RELAXNG_PARENTREF)) {
5772             if (cur->depth == -1) {
5773                 cur->depth = depth;
5774                 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth);
5775                 cur->depth = -2;
5776             } else if (depth == cur->depth) {
5777                 if (ctxt->error != NULL)
5778                     ctxt->error(ctxt->userData,
5779                     "Detected a cycle in %s references\n", cur->name);
5780                 ctxt->nbErrors++;
5781                 return(-1);
5782             }
5783         } else if (cur->type == XML_RELAXNG_ELEMENT) {
5784             ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth + 1);
5785         } else {
5786             ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth);
5787         }
5788         cur = cur->next;
5789     }
5790     return(ret);
5791 }
5792
5793 /**
5794  * xmlRelaxNGTryUnlink:
5795  * @ctxt:  a Relax-NG parser context
5796  * @cur:  the definition to unlink
5797  * @parent:  the parent definition
5798  * @prev:  the previous sibling definition
5799  *
5800  * Try to unlink a definition. If not possble make it a NOOP
5801  *
5802  * Returns the new prev definition
5803  */
5804 static xmlRelaxNGDefinePtr
5805 xmlRelaxNGTryUnlink(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED, 
5806                     xmlRelaxNGDefinePtr cur,
5807                     xmlRelaxNGDefinePtr parent,
5808                     xmlRelaxNGDefinePtr prev) {
5809     if (prev != NULL) {
5810         prev->next = cur->next;
5811     } else {
5812         if (parent != NULL) {
5813             if (parent->content == cur)
5814                 parent->content = cur->next;
5815             else if (parent->attrs == cur)
5816                 parent->attrs = cur->next;
5817             else if (parent->nameClass == cur)
5818                 parent->nameClass = cur->next;
5819         } else {
5820             cur->type = XML_RELAXNG_NOOP;
5821             prev = cur;
5822         }
5823     }
5824     return(prev);
5825 }
5826
5827 /**
5828  * xmlRelaxNGSimplify:
5829  * @ctxt:  a Relax-NG parser context
5830  * @nodes:  grammar children nodes
5831  *
5832  * Check for simplification of empty and notAllowed
5833  */
5834 static void
5835 xmlRelaxNGSimplify(xmlRelaxNGParserCtxtPtr ctxt, 
5836                      xmlRelaxNGDefinePtr cur,
5837                      xmlRelaxNGDefinePtr parent) {
5838     xmlRelaxNGDefinePtr prev = NULL;
5839
5840     while (cur != NULL) {
5841         if ((cur->type == XML_RELAXNG_REF) ||
5842             (cur->type == XML_RELAXNG_PARENTREF)) {
5843             if (cur->depth != -3) {
5844                 cur->depth = -3;
5845                 xmlRelaxNGSimplify(ctxt, cur->content, cur);
5846             }
5847         } else if (cur->type == XML_RELAXNG_NOT_ALLOWED) {
5848             cur->parent = parent;
5849             if ((parent != NULL) &&
5850                 ((parent->type == XML_RELAXNG_ATTRIBUTE) ||
5851                  (parent->type == XML_RELAXNG_LIST) ||
5852                  (parent->type == XML_RELAXNG_GROUP) ||
5853                  (parent->type == XML_RELAXNG_INTERLEAVE) ||
5854                  (parent->type == XML_RELAXNG_ONEORMORE) ||
5855                  (parent->type == XML_RELAXNG_ZEROORMORE))) {
5856                 parent->type = XML_RELAXNG_NOT_ALLOWED;
5857                 break;
5858             }
5859             if ((parent != NULL) &&
5860                 (parent->type == XML_RELAXNG_CHOICE)) {
5861                 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5862             } else
5863                 prev = cur;
5864         } else if (cur->type == XML_RELAXNG_EMPTY){
5865             cur->parent = parent;
5866             if ((parent != NULL) &&
5867                 ((parent->type == XML_RELAXNG_ONEORMORE) ||
5868                  (parent->type == XML_RELAXNG_ZEROORMORE))) {
5869                 parent->type = XML_RELAXNG_EMPTY;
5870                 break;
5871             }
5872             if ((parent != NULL) &&
5873                 ((parent->type == XML_RELAXNG_GROUP) ||
5874                  (parent->type == XML_RELAXNG_INTERLEAVE))) {
5875                 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5876             } else
5877                 prev = cur;
5878         } else {
5879             cur->parent = parent;
5880             if (cur->content != NULL)
5881                 xmlRelaxNGSimplify(ctxt, cur->content, cur);
5882             if ((cur->type != XML_RELAXNG_VALUE) && (cur->attrs != NULL))
5883                 xmlRelaxNGSimplify(ctxt, cur->attrs, cur);
5884             if (cur->nameClass != NULL)
5885                 xmlRelaxNGSimplify(ctxt, cur->nameClass, cur);
5886             /*
5887              * On Elements, try to move attribute only generating rules on
5888              * the attrs rules.
5889              */
5890             if (cur->type == XML_RELAXNG_ELEMENT) {
5891                 int attronly;
5892                 xmlRelaxNGDefinePtr tmp, pre;
5893
5894                 while (cur->content != NULL) {
5895                     attronly = xmlRelaxNGGenerateAttributes(ctxt, cur->content);
5896                     if (attronly == 1) {
5897                         /*
5898                          * migrate cur->content to attrs
5899                          */
5900                         tmp = cur->content;
5901                         cur->content = tmp->next;
5902                         tmp->next = cur->attrs;
5903                         cur->attrs = tmp;
5904                     } else {
5905                         /*
5906                          * cur->content can generate elements or text
5907                          */
5908                         break;
5909                     }
5910                 }
5911                 pre = cur->content;
5912                 while ((pre != NULL) && (pre->next != NULL)) {
5913                     tmp = pre->next;
5914                     attronly = xmlRelaxNGGenerateAttributes(ctxt, tmp);
5915                     if (attronly == 1) {
5916                         /*
5917                          * migrate tmp to attrs
5918                          */
5919                         pre->next = tmp->next;
5920                         tmp->next = cur->attrs;
5921                         cur->attrs = tmp;
5922                     } else {
5923                         pre = tmp;
5924                     }
5925                 }
5926             }
5927             /*
5928              * This may result in a simplification
5929              */
5930             if ((cur->type == XML_RELAXNG_GROUP) ||
5931                 (cur->type == XML_RELAXNG_INTERLEAVE)) {
5932                 if (cur->content == NULL)
5933                     cur->type = XML_RELAXNG_EMPTY;
5934                 else if (cur->content->next == NULL) {
5935                     if ((parent == NULL) && (prev == NULL)) {
5936                         cur->type = XML_RELAXNG_NOOP;
5937                     } else if (prev == NULL) {
5938                         parent->content = cur->content;
5939                         cur->content->next = cur->next;
5940                         cur = cur->content;
5941                     } else {
5942                         cur->content->next = cur->next;
5943                         prev->next = cur->content;
5944                         cur = cur->content;
5945                     }
5946                 }
5947             }
5948             /*
5949              * the current node may have been transformed back
5950              */
5951             if ((cur->type == XML_RELAXNG_EXCEPT) &&
5952                 (cur->content != NULL) &&
5953                 (cur->content->type == XML_RELAXNG_NOT_ALLOWED)) {
5954                 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5955             } else if (cur->type == XML_RELAXNG_NOT_ALLOWED) {
5956                 if ((parent != NULL) &&
5957                     ((parent->type == XML_RELAXNG_ATTRIBUTE) ||
5958                      (parent->type == XML_RELAXNG_LIST) ||
5959                      (parent->type == XML_RELAXNG_GROUP) ||
5960                      (parent->type == XML_RELAXNG_INTERLEAVE) ||
5961                      (parent->type == XML_RELAXNG_ONEORMORE) ||
5962                      (parent->type == XML_RELAXNG_ZEROORMORE))) {
5963                     parent->type = XML_RELAXNG_NOT_ALLOWED;
5964                     break;
5965                 }
5966                 if ((parent != NULL) &&
5967                     (parent->type == XML_RELAXNG_CHOICE)) {
5968                     prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5969                 } else
5970                     prev = cur;
5971             } else if (cur->type == XML_RELAXNG_EMPTY){
5972                 if ((parent != NULL) &&
5973                     ((parent->type == XML_RELAXNG_ONEORMORE) ||
5974                      (parent->type == XML_RELAXNG_ZEROORMORE))) {
5975                     parent->type = XML_RELAXNG_EMPTY;
5976                     break;
5977                 }
5978                 if ((parent != NULL) &&
5979                     ((parent->type == XML_RELAXNG_GROUP) ||
5980                      (parent->type == XML_RELAXNG_INTERLEAVE) ||
5981                      (parent->type == XML_RELAXNG_CHOICE))) {
5982                     prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5983                 } else
5984                     prev = cur;
5985             } else {
5986                 prev = cur;
5987             }
5988         }
5989         cur = cur->next;
5990     }
5991 }
5992
5993 /**
5994  * xmlRelaxNGGroupContentType:
5995  * @ct1:  the first content type
5996  * @ct2:  the second content type
5997  *
5998  * Try to group 2 content types
5999  *
6000  * Returns the content type
6001  */
6002 static xmlRelaxNGContentType
6003 xmlRelaxNGGroupContentType(xmlRelaxNGContentType ct1,
6004                            xmlRelaxNGContentType ct2) {
6005     if ((ct1 == XML_RELAXNG_CONTENT_ERROR) ||
6006         (ct2 == XML_RELAXNG_CONTENT_ERROR))
6007         return(XML_RELAXNG_CONTENT_ERROR);
6008     if (ct1 == XML_RELAXNG_CONTENT_EMPTY)
6009         return(ct2);
6010     if (ct2 == XML_RELAXNG_CONTENT_EMPTY)
6011         return(ct1);
6012     if ((ct1 == XML_RELAXNG_CONTENT_COMPLEX) &&
6013         (ct2 == XML_RELAXNG_CONTENT_COMPLEX))
6014         return(XML_RELAXNG_CONTENT_COMPLEX);
6015     return(XML_RELAXNG_CONTENT_ERROR);
6016 }
6017
6018 /**
6019  * xmlRelaxNGMaxContentType:
6020  * @ct1:  the first content type
6021  * @ct2:  the second content type
6022  *
6023  * Compute the max content-type
6024  *
6025  * Returns the content type
6026  */
6027 static xmlRelaxNGContentType
6028 xmlRelaxNGMaxContentType(xmlRelaxNGContentType ct1,
6029                      xmlRelaxNGContentType ct2) {
6030     if ((ct1 == XML_RELAXNG_CONTENT_ERROR) ||
6031         (ct2 == XML_RELAXNG_CONTENT_ERROR))
6032         return(XML_RELAXNG_CONTENT_ERROR);
6033     if ((ct1 == XML_RELAXNG_CONTENT_SIMPLE) ||
6034         (ct2 == XML_RELAXNG_CONTENT_SIMPLE))
6035         return(XML_RELAXNG_CONTENT_SIMPLE);
6036     if ((ct1 == XML_RELAXNG_CONTENT_COMPLEX) ||
6037         (ct2 == XML_RELAXNG_CONTENT_COMPLEX))
6038         return(XML_RELAXNG_CONTENT_COMPLEX);
6039     return(XML_RELAXNG_CONTENT_EMPTY);
6040 }
6041
6042 /**
6043  * xmlRelaxNGCheckRules:
6044  * @ctxt:  a Relax-NG parser context
6045  * @cur:  the current definition
6046  * @flags:  some accumulated flags
6047  * @ptype:  the parent type
6048  *
6049  * Check for rules in section 7.1 and 7.2
6050  *
6051  * Returns the content type of @cur
6052  */
6053 static xmlRelaxNGContentType
6054 xmlRelaxNGCheckRules(xmlRelaxNGParserCtxtPtr ctxt, 
6055                      xmlRelaxNGDefinePtr cur, int flags,
6056                      xmlRelaxNGType ptype) {
6057     int nflags = flags;
6058     xmlRelaxNGContentType ret, tmp, val = XML_RELAXNG_CONTENT_EMPTY;
6059
6060     while (cur != NULL) {
6061         ret = XML_RELAXNG_CONTENT_EMPTY;
6062         if ((cur->type == XML_RELAXNG_REF) ||
6063             (cur->type == XML_RELAXNG_PARENTREF)) {
6064             if (flags & XML_RELAXNG_IN_LIST) {
6065                 if (ctxt->error != NULL)
6066                     ctxt->error(ctxt->userData,
6067                 "Found forbidden pattern list//ref\n");
6068                 ctxt->nbErrors++;
6069             }
6070             if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6071                 if (ctxt->error != NULL)
6072                     ctxt->error(ctxt->userData,
6073                         "Found forbidden pattern data/except//ref\n");
6074                 ctxt->nbErrors++;
6075             }
6076             if (cur->depth > -4) {
6077                 cur->depth = -4;
6078                 ret = xmlRelaxNGCheckRules(ctxt, cur->content,
6079                                            flags, cur->type);
6080                 cur->depth = ret - 15 ;
6081             } else if (cur->depth == -4) {
6082                 ret = XML_RELAXNG_CONTENT_COMPLEX;
6083             } else {
6084                 ret = (xmlRelaxNGContentType) cur->depth + 15;
6085             }
6086         } else if (cur->type == XML_RELAXNG_ELEMENT) {
6087             /*
6088              * The 7.3 Attribute derivation rule for groups is plugged there
6089              */
6090             xmlRelaxNGCheckGroupAttrs(ctxt, cur);
6091             if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6092                 if (ctxt->error != NULL)
6093                     ctxt->error(ctxt->userData,
6094                         "Found forbidden pattern data/except//element(ref)\n");
6095                 ctxt->nbErrors++;
6096             }
6097             if (flags & XML_RELAXNG_IN_LIST) {
6098                 if (ctxt->error != NULL)
6099                     ctxt->error(ctxt->userData,
6100                 "Found forbidden pattern list//element(ref)\n");
6101                 ctxt->nbErrors++;
6102             }
6103             if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
6104                 if (ctxt->error != NULL)
6105                     ctxt->error(ctxt->userData,
6106                 "Found forbidden pattern attribute//element(ref)\n");
6107                 ctxt->nbErrors++;
6108             }
6109             if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
6110                 if (ctxt->error != NULL)
6111                     ctxt->error(ctxt->userData,
6112                         "Found forbidden pattern attribute//element(ref)\n");
6113                 ctxt->nbErrors++;
6114             }
6115             /*
6116              * reset since in the simple form elements are only child
6117              * of grammar/define
6118              */
6119             nflags = 0;
6120             ret = xmlRelaxNGCheckRules(ctxt, cur->attrs, nflags, cur->type);
6121             if (ret != XML_RELAXNG_CONTENT_EMPTY) {
6122                 if (ctxt->error != NULL)
6123                     ctxt->error(ctxt->userData,
6124                         "Element %s attributes have a content type error\n",
6125                                 cur->name);
6126                 ctxt->nbErrors++;
6127             }
6128             ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
6129             if (ret == XML_RELAXNG_CONTENT_ERROR) {
6130                 if (ctxt->error != NULL)
6131                     ctxt->error(ctxt->userData,
6132                         "Element %s has a content type error\n",
6133                                 cur->name);
6134                 ctxt->nbErrors++;
6135             } else {
6136                 ret = XML_RELAXNG_CONTENT_COMPLEX;
6137             }
6138         } else if (cur->type == XML_RELAXNG_ATTRIBUTE) {
6139             if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
6140                 if (ctxt->error != NULL)
6141                     ctxt->error(ctxt->userData,
6142                         "Found forbidden pattern attribute//attribute\n");
6143                 ctxt->nbErrors++;
6144             }
6145             if (flags & XML_RELAXNG_IN_LIST) {
6146                 if (ctxt->error != NULL)
6147                     ctxt->error(ctxt->userData,
6148                 "Found forbidden pattern list//attribute\n");
6149                 ctxt->nbErrors++;
6150             }
6151             if (flags & XML_RELAXNG_IN_OOMGROUP) {
6152                 if (ctxt->error != NULL)
6153                     ctxt->error(ctxt->userData,
6154                     "Found forbidden pattern oneOrMore//group//attribute\n");
6155                 ctxt->nbErrors++;
6156             }
6157             if (flags & XML_RELAXNG_IN_OOMINTERLEAVE) {
6158                 if (ctxt->error != NULL)
6159                     ctxt->error(ctxt->userData,
6160                 "Found forbidden pattern oneOrMore//interleave//attribute\n");
6161                 ctxt->nbErrors++;
6162             }
6163             if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6164                 if (ctxt->error != NULL)
6165                     ctxt->error(ctxt->userData,
6166                         "Found forbidden pattern data/except//attribute\n");
6167                 ctxt->nbErrors++;
6168             }
6169             if (flags & XML_RELAXNG_IN_START) {
6170                 if (ctxt->error != NULL)
6171                     ctxt->error(ctxt->userData,
6172                         "Found forbidden pattern start//attribute\n");
6173                 ctxt->nbErrors++;
6174             }
6175             if ((!(flags & XML_RELAXNG_IN_ONEORMORE)) && (cur->name == NULL)) {
6176                 if (cur->ns == NULL) {
6177                     if (ctxt->error != NULL)
6178                         ctxt->error(ctxt->userData,
6179                         "Found anyName attribute without oneOrMore ancestor\n");
6180                     ctxt->nbErrors++;
6181                 } else {
6182                     if (ctxt->error != NULL)
6183                         ctxt->error(ctxt->userData,
6184                         "Found nsName attribute without oneOrMore ancestor\n");
6185                     ctxt->nbErrors++;
6186                 }
6187             }
6188             nflags = flags | XML_RELAXNG_IN_ATTRIBUTE;
6189             xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
6190             ret = XML_RELAXNG_CONTENT_EMPTY;
6191         } else if ((cur->type == XML_RELAXNG_ONEORMORE) ||
6192                    (cur->type == XML_RELAXNG_ZEROORMORE)) {
6193             if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6194                 if (ctxt->error != NULL)
6195                     ctxt->error(ctxt->userData,
6196                         "Found forbidden pattern data/except//oneOrMore\n");
6197                 ctxt->nbErrors++;
6198             }
6199             if (flags & XML_RELAXNG_IN_START) {
6200                 if (ctxt->error != NULL)
6201                     ctxt->error(ctxt->userData,
6202                         "Found forbidden pattern start//oneOrMore\n");
6203                 ctxt->nbErrors++;
6204             }
6205             nflags = flags | XML_RELAXNG_IN_ONEORMORE;
6206             ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
6207             ret = xmlRelaxNGGroupContentType(ret, ret);
6208         } else if (cur->type == XML_RELAXNG_LIST) {
6209             if (flags & XML_RELAXNG_IN_LIST) {
6210                 if (ctxt->error != NULL)
6211                     ctxt->error(ctxt->userData,
6212                 "Found forbidden pattern list//list\n");
6213                 ctxt->nbErrors++;
6214             }
6215             if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6216                 if (ctxt->error != NULL)
6217                     ctxt->error(ctxt->userData,
6218                         "Found forbidden pattern data/except//list\n");
6219                 ctxt->nbErrors++;
6220             }
6221             if (flags & XML_RELAXNG_IN_START) {
6222                 if (ctxt->error != NULL)
6223                     ctxt->error(ctxt->userData,
6224                         "Found forbidden pattern start//list\n");
6225                 ctxt->nbErrors++;
6226             }
6227             nflags = flags | XML_RELAXNG_IN_LIST;
6228             ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
6229         } else if (cur->type == XML_RELAXNG_GROUP) {
6230             if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6231                 if (ctxt->error != NULL)
6232                     ctxt->error(ctxt->userData,
6233                         "Found forbidden pattern data/except//group\n");
6234                 ctxt->nbErrors++;
6235             }
6236             if (flags & XML_RELAXNG_IN_START) {
6237                 if (ctxt->error != NULL)
6238                     ctxt->error(ctxt->userData,
6239                         "Found forbidden pattern start//group\n");
6240                 ctxt->nbErrors++;
6241             }
6242             if (flags & XML_RELAXNG_IN_ONEORMORE)
6243                 nflags = flags | XML_RELAXNG_IN_OOMGROUP;
6244             else
6245                 nflags = flags;
6246             ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
6247             /*
6248              * The 7.3 Attribute derivation rule for groups is plugged there
6249              */
6250             xmlRelaxNGCheckGroupAttrs(ctxt, cur);
6251         } else if (cur->type == XML_RELAXNG_INTERLEAVE) {
6252             if (flags & XML_RELAXNG_IN_LIST) {
6253                 if (ctxt->error != NULL)
6254                     ctxt->error(ctxt->userData,
6255                 "Found forbidden pattern list//interleave\n");
6256                 ctxt->nbErrors++;
6257             }
6258             if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6259                 if (ctxt->error != NULL)
6260                     ctxt->error(ctxt->userData,
6261                         "Found forbidden pattern data/except//interleave\n");
6262                 ctxt->nbErrors++;
6263             }
6264             if (flags & XML_RELAXNG_IN_START) {
6265                 if (ctxt->error != NULL)
6266                     ctxt->error(ctxt->userData,
6267                         "Found forbidden pattern start//interleave\n");
6268                 ctxt->nbErrors++;
6269             }
6270             if (flags & XML_RELAXNG_IN_ONEORMORE)
6271                 nflags = flags | XML_RELAXNG_IN_OOMINTERLEAVE;
6272             else
6273                 nflags = flags;
6274             ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
6275         } else if (cur->type == XML_RELAXNG_EXCEPT) {
6276             if ((cur->parent != NULL) &&
6277                 (cur->parent->type == XML_RELAXNG_DATATYPE))
6278                 nflags = flags | XML_RELAXNG_IN_DATAEXCEPT;
6279             else
6280                 nflags = flags;
6281             ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
6282         } else if (cur->type == XML_RELAXNG_DATATYPE) {
6283             if (flags & XML_RELAXNG_IN_START) {
6284                 if (ctxt->error != NULL)
6285                     ctxt->error(ctxt->userData,
6286                         "Found forbidden pattern start//data\n");
6287                 ctxt->nbErrors++;
6288             }
6289             xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
6290             ret = XML_RELAXNG_CONTENT_SIMPLE;
6291         } else if (cur->type == XML_RELAXNG_VALUE) {
6292             if (flags & XML_RELAXNG_IN_START) {
6293                 if (ctxt->error != NULL)
6294                     ctxt->error(ctxt->userData,
6295                         "Found forbidden pattern start//value\n");
6296                 ctxt->nbErrors++;
6297             }
6298             xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
6299             ret = XML_RELAXNG_CONTENT_SIMPLE;
6300         } else if (cur->type == XML_RELAXNG_TEXT) {
6301             if (flags & XML_RELAXNG_IN_LIST) {
6302                 if (ctxt->error != NULL)
6303                     ctxt->error(ctxt->userData,
6304                 "Found forbidden pattern list//text\n");
6305                 ctxt->nbErrors++;
6306             }
6307             if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6308                 if (ctxt->error != NULL)
6309                     ctxt->error(ctxt->userData,
6310                         "Found forbidden pattern data/except//text\n");
6311                 ctxt->nbErrors++;
6312             }
6313             if (flags & XML_RELAXNG_IN_START) {
6314                 if (ctxt->error != NULL)
6315                     ctxt->error(ctxt->userData,
6316                         "Found forbidden pattern start//text\n");
6317                 ctxt->nbErrors++;
6318             }
6319             ret = XML_RELAXNG_CONTENT_COMPLEX;
6320         } else if (cur->type == XML_RELAXNG_EMPTY) {
6321             if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6322                 if (ctxt->error != NULL)
6323                     ctxt->error(ctxt->userData,
6324                         "Found forbidden pattern data/except//empty\n");
6325                 ctxt->nbErrors++;
6326             }
6327             if (flags & XML_RELAXNG_IN_START) {
6328                 if (ctxt->error != NULL)
6329                     ctxt->error(ctxt->userData,
6330                         "Found forbidden pattern start//empty\n");
6331                 ctxt->nbErrors++;
6332             }
6333             ret = XML_RELAXNG_CONTENT_EMPTY;
6334         } else if (cur->type == XML_RELAXNG_CHOICE) {
6335             xmlRelaxNGCheckChoiceDeterminism(ctxt, cur);
6336             ret = xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
6337         } else {
6338             ret = xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
6339         }
6340         cur = cur->next;
6341         if (ptype == XML_RELAXNG_GROUP) {
6342             val = xmlRelaxNGGroupContentType(val, ret);
6343         } else if (ptype == XML_RELAXNG_INTERLEAVE) {
6344             tmp = xmlRelaxNGGroupContentType(val, ret);
6345             if (tmp != XML_RELAXNG_CONTENT_ERROR)
6346                 tmp = xmlRelaxNGMaxContentType(val, ret);
6347         } else if (ptype == XML_RELAXNG_CHOICE) {
6348             val = xmlRelaxNGMaxContentType(val, ret);
6349         } else if (ptype == XML_RELAXNG_LIST) {
6350             val = XML_RELAXNG_CONTENT_SIMPLE;
6351         } else if (ptype == XML_RELAXNG_EXCEPT) {
6352             if (ret == XML_RELAXNG_CONTENT_ERROR)
6353                 val = XML_RELAXNG_CONTENT_ERROR;
6354             else
6355                 val = XML_RELAXNG_CONTENT_SIMPLE;
6356         } else {
6357             val = xmlRelaxNGGroupContentType(val, ret);
6358         }
6359
6360     }
6361     return(val);
6362 }
6363
6364 /**
6365  * xmlRelaxNGParseGrammar:
6366  * @ctxt:  a Relax-NG parser context
6367  * @nodes:  grammar children nodes
6368  *
6369  * parse a Relax-NG <grammar> node
6370  *
6371  * Returns the internal xmlRelaxNGGrammarPtr built or
6372  *         NULL in case of error
6373  */
6374 static xmlRelaxNGGrammarPtr
6375 xmlRelaxNGParseGrammar(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes) {
6376     xmlRelaxNGGrammarPtr ret, tmp, old;
6377
6378 #ifdef DEBUG_GRAMMAR
6379     xmlGenericError(xmlGenericErrorContext, "Parsing a new grammar\n");
6380 #endif
6381
6382     ret = xmlRelaxNGNewGrammar(ctxt);
6383     if (ret == NULL)
6384         return(NULL);
6385
6386     /*
6387      * Link the new grammar in the tree
6388      */
6389     ret->parent = ctxt->grammar;
6390     if (ctxt->grammar != NULL) {
6391         tmp = ctxt->grammar->children;
6392         if (tmp == NULL) {
6393             ctxt->grammar->children = ret;
6394         } else {
6395             while (tmp->next != NULL)
6396                 tmp = tmp->next;
6397             tmp->next = ret;
6398         }
6399     }
6400
6401     old = ctxt->grammar;
6402     ctxt->grammar = ret;
6403     xmlRelaxNGParseGrammarContent(ctxt, nodes);
6404     ctxt->grammar = ret;
6405     if (ctxt->grammar == NULL) {
6406         if (ctxt->error != NULL)
6407             ctxt->error(ctxt->userData,
6408             "Failed to parse <grammar> content\n");
6409         ctxt->nbErrors++;
6410     } else if (ctxt->grammar->start == NULL) {
6411         if (ctxt->error != NULL)
6412             ctxt->error(ctxt->userData,
6413             "Element <grammar> has no <start>\n");
6414         ctxt->nbErrors++;
6415     }
6416
6417     /*
6418      * Apply 4.17 mergingd rules to defines and starts
6419      */
6420     xmlRelaxNGCombineStart(ctxt, ret);
6421     if (ret->defs != NULL) {
6422         xmlHashScan(ret->defs, (xmlHashScanner) xmlRelaxNGCheckCombine,
6423                     ctxt);
6424     }
6425
6426     /*
6427      * link together defines and refs in this grammar
6428      */
6429     if (ret->refs != NULL) {
6430         xmlHashScan(ret->refs, (xmlHashScanner) xmlRelaxNGCheckReference,
6431                     ctxt);
6432     }
6433
6434     ctxt->grammar = old;
6435     return(ret);
6436 }
6437
6438 /**
6439  * xmlRelaxNGParseDocument:
6440  * @ctxt:  a Relax-NG parser context
6441  * @node:  the root node of the RelaxNG schema
6442  *
6443  * parse a Relax-NG definition resource and build an internal
6444  * xmlRelaxNG struture which can be used to validate instances.
6445  *
6446  * Returns the internal XML RelaxNG structure built or
6447  *         NULL in case of error
6448  */
6449 static xmlRelaxNGPtr
6450 xmlRelaxNGParseDocument(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
6451     xmlRelaxNGPtr schema = NULL;
6452     const xmlChar *olddefine;
6453     xmlRelaxNGGrammarPtr old;
6454
6455     if ((ctxt == NULL) || (node == NULL))
6456         return (NULL);
6457
6458     schema = xmlRelaxNGNewRelaxNG(ctxt);
6459     if (schema == NULL)
6460         return(NULL);
6461
6462     olddefine = ctxt->define;
6463     ctxt->define = NULL;
6464     if (IS_RELAXNG(node, "grammar")) {
6465         schema->topgrammar = xmlRelaxNGParseGrammar(ctxt, node->children);
6466     } else {
6467         xmlRelaxNGGrammarPtr tmp, ret;
6468
6469         schema->topgrammar = ret = xmlRelaxNGNewGrammar(ctxt);
6470         if (schema->topgrammar == NULL) {
6471             return(schema);
6472         }
6473         /*
6474          * Link the new grammar in the tree
6475          */
6476         ret->parent = ctxt->grammar;
6477         if (ctxt->grammar != NULL) {
6478             tmp = ctxt->grammar->children;
6479             if (tmp == NULL) {
6480                 ctxt->grammar->children = ret;
6481             } else {
6482                 while (tmp->next != NULL)
6483                     tmp = tmp->next;
6484                 tmp->next = ret;
6485             }
6486         }
6487         old = ctxt->grammar;
6488         ctxt->grammar = ret;
6489         xmlRelaxNGParseStart(ctxt, node);
6490         if (old != NULL)
6491             ctxt->grammar = old;
6492     }
6493     ctxt->define = olddefine;
6494     if (schema->topgrammar->start != NULL) {
6495         xmlRelaxNGCheckCycles(ctxt, schema->topgrammar->start, 0);
6496         if ((ctxt->flags & XML_RELAXNG_IN_EXTERNALREF) == 0) {
6497             xmlRelaxNGSimplify(ctxt, schema->topgrammar->start, NULL);
6498             while ((schema->topgrammar->start != NULL) &&
6499                    (schema->topgrammar->start->type == XML_RELAXNG_NOOP) &&
6500                    (schema->topgrammar->start->next != NULL))
6501                 schema->topgrammar->start = schema->topgrammar->start->content;
6502             xmlRelaxNGCheckRules(ctxt, schema->topgrammar->start,
6503                                  XML_RELAXNG_IN_START, XML_RELAXNG_NOOP);
6504         }
6505     }
6506
6507 #ifdef DEBUG
6508     if (schema == NULL)
6509         xmlGenericError(xmlGenericErrorContext,
6510                         "xmlRelaxNGParseDocument() failed\n");
6511 #endif
6512
6513     return (schema);
6514 }
6515
6516 /************************************************************************
6517  *                                                                      *
6518  *                      Reading RelaxNGs                                *
6519  *                                                                      *
6520  ************************************************************************/
6521
6522 /**
6523  * xmlRelaxNGNewParserCtxt:
6524  * @URL:  the location of the schema
6525  *
6526  * Create an XML RelaxNGs parse context for that file/resource expected
6527  * to contain an XML RelaxNGs file.
6528  *
6529  * Returns the parser context or NULL in case of error
6530  */
6531 xmlRelaxNGParserCtxtPtr
6532 xmlRelaxNGNewParserCtxt(const char *URL) {
6533     xmlRelaxNGParserCtxtPtr ret;
6534
6535     if (URL == NULL)
6536         return(NULL);
6537
6538     ret = (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
6539     if (ret == NULL) {
6540         xmlGenericError(xmlGenericErrorContext,
6541                 "Failed to allocate new schama parser context for %s\n", URL);
6542         return (NULL);
6543     }
6544     memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
6545     ret->URL = xmlStrdup((const xmlChar *)URL);
6546     ret->error = xmlGenericError;
6547     ret->userData = xmlGenericErrorContext;
6548     return (ret);
6549 }
6550
6551 /**
6552  * xmlRelaxNGNewMemParserCtxt:
6553  * @buffer:  a pointer to a char array containing the schemas
6554  * @size:  the size of the array
6555  *
6556  * Create an XML RelaxNGs parse context for that memory buffer expected
6557  * to contain an XML RelaxNGs file.
6558  *
6559  * Returns the parser context or NULL in case of error
6560  */
6561 xmlRelaxNGParserCtxtPtr
6562 xmlRelaxNGNewMemParserCtxt(const char *buffer, int size) {
6563     xmlRelaxNGParserCtxtPtr ret;
6564
6565     if ((buffer == NULL) || (size <= 0))
6566         return(NULL);
6567
6568     ret = (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
6569     if (ret == NULL) {
6570         xmlGenericError(xmlGenericErrorContext,
6571                 "Failed to allocate new schama parser context\n");
6572         return (NULL);
6573     }
6574     memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
6575     ret->buffer = buffer;
6576     ret->size = size;
6577     ret->error = xmlGenericError;
6578     ret->userData = xmlGenericErrorContext;
6579     return (ret);
6580 }
6581
6582 /**
6583  * xmlRelaxNGNewDocParserCtxt:
6584  * @doc:  a preparsed document tree
6585  *
6586  * Create an XML RelaxNGs parser context for that document.
6587  * Note: since the process of compiling a RelaxNG schemas modifies the
6588  *       document, the @doc parameter is duplicated internally.
6589  *
6590  * Returns the parser context or NULL in case of error
6591  */
6592 xmlRelaxNGParserCtxtPtr
6593 xmlRelaxNGNewDocParserCtxt(xmlDocPtr doc) {
6594     xmlRelaxNGParserCtxtPtr ret;
6595     xmlDocPtr copy;
6596
6597     if (doc == NULL)
6598         return(NULL);
6599     copy = xmlCopyDoc(doc, 1);
6600     if (copy == NULL)
6601         return(NULL);
6602
6603     ret = (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
6604     if (ret == NULL) {
6605         xmlGenericError(xmlGenericErrorContext,
6606                 "Failed to allocate new schama parser context\n");
6607         return (NULL);
6608     }
6609     memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
6610     ret->document = copy;
6611     ret->userData = xmlGenericErrorContext;
6612     return (ret);
6613 }
6614
6615 /**
6616  * xmlRelaxNGFreeParserCtxt:
6617  * @ctxt:  the schema parser context
6618  *
6619  * Free the resources associated to the schema parser context
6620  */
6621 void
6622 xmlRelaxNGFreeParserCtxt(xmlRelaxNGParserCtxtPtr ctxt) {
6623     if (ctxt == NULL)
6624         return;
6625     if (ctxt->URL != NULL)
6626         xmlFree(ctxt->URL);
6627     if (ctxt->doc != NULL)
6628         xmlRelaxNGFreeDocument(ctxt->doc);
6629     if (ctxt->interleaves != NULL)
6630         xmlHashFree(ctxt->interleaves, NULL);
6631     if (ctxt->documents != NULL)
6632         xmlRelaxNGFreeDocumentList(ctxt->documents);
6633     if (ctxt->includes != NULL)
6634         xmlRelaxNGFreeIncludeList(ctxt->includes);
6635     if (ctxt->docTab != NULL)
6636         xmlFree(ctxt->docTab);
6637     if (ctxt->incTab != NULL)
6638         xmlFree(ctxt->incTab);
6639     if (ctxt->defTab != NULL) {
6640         int i;
6641
6642         for (i = 0;i < ctxt->defNr;i++)
6643             xmlRelaxNGFreeDefine(ctxt->defTab[i]);
6644         xmlFree(ctxt->defTab);
6645     }
6646     xmlFree(ctxt);
6647 }
6648
6649 /**
6650  * xmlRelaxNGNormExtSpace:
6651  * @value:  a value
6652  *
6653  * Removes the leading and ending spaces of the value
6654  * The string is modified "in situ"
6655  */
6656 static void
6657 xmlRelaxNGNormExtSpace(xmlChar *value) {
6658     xmlChar *start = value;
6659     xmlChar *cur = value;
6660     if (value == NULL)
6661         return;
6662
6663     while (IS_BLANK(*cur)) cur++;
6664     if (cur == start) {
6665         do {
6666             while ((*cur != 0) && (!IS_BLANK(*cur))) cur++;
6667             if (*cur == 0)
6668                 return;
6669             start = cur;
6670             while (IS_BLANK(*cur)) cur++;
6671             if (*cur == 0) {
6672                 *start = 0;
6673                 return;
6674             }
6675         } while (1);
6676     } else {
6677         do {
6678             while ((*cur != 0) && (!IS_BLANK(*cur))) 
6679                 *start++ = *cur++;
6680             if (*cur == 0) {
6681                 *start = 0;
6682                 return;
6683             }
6684             /* don't try to normalize the inner spaces */
6685             while (IS_BLANK(*cur)) cur++;
6686                 *start++ = *cur++;
6687             if (*cur == 0) {
6688                 *start = 0;
6689                 return;
6690             }
6691         } while (1);
6692     }
6693 }
6694
6695 /**
6696  * xmlRelaxNGCheckAttributes:
6697  * @ctxt:  a Relax-NG parser context
6698  * @node:  a Relax-NG node
6699  *
6700  * Check all the attributes on the given node
6701  */
6702 static void
6703 xmlRelaxNGCleanupAttributes(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
6704     xmlAttrPtr cur, next;
6705
6706     cur = node->properties;
6707     while (cur != NULL) {
6708         next = cur->next;
6709         if ((cur->ns == NULL) ||
6710             (xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) {
6711             if (xmlStrEqual(cur->name, BAD_CAST "name")) {
6712                 if ((!xmlStrEqual(node->name, BAD_CAST "element")) &&
6713                     (!xmlStrEqual(node->name, BAD_CAST "attribute")) &&
6714                     (!xmlStrEqual(node->name, BAD_CAST "ref")) &&
6715                     (!xmlStrEqual(node->name, BAD_CAST "parentRef")) &&
6716                     (!xmlStrEqual(node->name, BAD_CAST "param")) &&
6717                     (!xmlStrEqual(node->name, BAD_CAST "define"))) {
6718                     if (ctxt->error != NULL)
6719                         ctxt->error(ctxt->userData,
6720                                 "Attribute %s is not allowed on %s\n",
6721                                     cur->name, node->name);
6722                     ctxt->nbErrors++;
6723                 }
6724             } else if (xmlStrEqual(cur->name, BAD_CAST "type")) {
6725                 if ((!xmlStrEqual(node->name, BAD_CAST "value")) &&
6726                     (!xmlStrEqual(node->name, BAD_CAST "data"))) {
6727                     if (ctxt->error != NULL)
6728                         ctxt->error(ctxt->userData,
6729                                 "Attribute %s is not allowed on %s\n",
6730                                     cur->name, node->name);
6731                     ctxt->nbErrors++;
6732                 }
6733             } else if (xmlStrEqual(cur->name, BAD_CAST "href")) {
6734                 if ((!xmlStrEqual(node->name, BAD_CAST "externalRef")) &&
6735                     (!xmlStrEqual(node->name, BAD_CAST "include"))) {
6736                     if (ctxt->error != NULL)
6737                         ctxt->error(ctxt->userData,
6738                                 "Attribute %s is not allowed on %s\n",
6739                                     cur->name, node->name);
6740                     ctxt->nbErrors++;
6741                 }
6742             } else if (xmlStrEqual(cur->name, BAD_CAST "combine")) {
6743                 if ((!xmlStrEqual(node->name, BAD_CAST "start")) &&
6744                     (!xmlStrEqual(node->name, BAD_CAST "define"))) {
6745                     if (ctxt->error != NULL)
6746                         ctxt->error(ctxt->userData,
6747                                 "Attribute %s is not allowed on %s\n",
6748                                     cur->name, node->name);
6749                     ctxt->nbErrors++;
6750                 }
6751             } else if (xmlStrEqual(cur->name, BAD_CAST "datatypeLibrary")) {
6752                 xmlChar *val;
6753                 xmlURIPtr uri;
6754
6755                 val = xmlNodeListGetString(node->doc, cur->children, 1);
6756                 if (val != NULL) {
6757                     if (val[0] != 0) {
6758                         uri = xmlParseURI((const char *) val);
6759                         if (uri == NULL) {
6760                             if (ctxt->error != NULL)
6761                                 ctxt->error(ctxt->userData,
6762                                 "Attribute %s contains invalid URI %s\n",
6763                                             cur->name, val);
6764                             ctxt->nbErrors++;
6765                         } else {
6766                             if (uri->scheme == NULL) {
6767                                 if (ctxt->error != NULL)
6768                                     ctxt->error(ctxt->userData,
6769                                     "Attribute %s URI %s is not absolute\n",
6770                                                 cur->name, val);
6771                                 ctxt->nbErrors++;
6772                             }
6773                             if (uri->fragment != NULL) {
6774                                 if (ctxt->error != NULL)
6775                                     ctxt->error(ctxt->userData,
6776                                     "Attribute %s URI %s has a fragment ID\n",
6777                                                 cur->name, val);
6778                                 ctxt->nbErrors++;
6779                             }
6780                             xmlFreeURI(uri);
6781                         }
6782                     }
6783                     xmlFree(val);
6784                 }
6785             } else if (!xmlStrEqual(cur->name, BAD_CAST "ns")) {
6786                 if (ctxt->error != NULL)
6787                     ctxt->error(ctxt->userData,
6788                             "Unknown attribute %s on %s\n",
6789                                 cur->name, node->name);
6790                 ctxt->nbErrors++;
6791             }
6792         }
6793         cur = next;
6794     }
6795 }
6796
6797 /**
6798  * xmlRelaxNGCleanupTree:
6799  * @ctxt:  a Relax-NG parser context
6800  * @root:  an xmlNodePtr subtree
6801  *
6802  * Cleanup the subtree from unwanted nodes for parsing, resolve
6803  * Include and externalRef lookups.
6804  */
6805 static void
6806 xmlRelaxNGCleanupTree(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr root) {
6807     xmlNodePtr cur, delete;
6808
6809     delete = NULL;
6810     cur = root;
6811     while (cur != NULL) {
6812         if (delete != NULL) {
6813             xmlUnlinkNode(delete);
6814             xmlFreeNode(delete);
6815             delete = NULL;
6816         }
6817         if (cur->type == XML_ELEMENT_NODE) {
6818             /*
6819              * Simplification 4.1. Annotations
6820              */
6821             if ((cur->ns == NULL) ||
6822                 (!xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) {
6823                 if ((cur->parent != NULL) &&
6824                     (cur->parent->type == XML_ELEMENT_NODE) &&
6825                     ((xmlStrEqual(cur->parent->name, BAD_CAST "name")) ||
6826                      (xmlStrEqual(cur->parent->name, BAD_CAST "value")) ||
6827                      (xmlStrEqual(cur->parent->name, BAD_CAST "param")))) {
6828                     if (ctxt->error != NULL)
6829                         ctxt->error(ctxt->userData,
6830                                 "element %s doesn't allow foreign elements\n",
6831                                     cur->parent->name);
6832                     ctxt->nbErrors++;
6833                 }
6834                 delete = cur;
6835                 goto skip_children;
6836             } else {
6837                 xmlRelaxNGCleanupAttributes(ctxt, cur);
6838                 if (xmlStrEqual(cur->name, BAD_CAST "externalRef")) {
6839                     xmlChar *href, *ns, *base, *URL;
6840                     xmlRelaxNGDocumentPtr docu;
6841                     xmlNodePtr tmp;
6842
6843                     ns = xmlGetProp(cur, BAD_CAST "ns");
6844                     if (ns == NULL) {
6845                         tmp = cur->parent;
6846                         while ((tmp != NULL) &&
6847                                (tmp->type == XML_ELEMENT_NODE)) {
6848                             ns = xmlGetProp(tmp, BAD_CAST "ns");
6849                             if (ns != NULL)
6850                                 break;
6851                             tmp = tmp->parent;
6852                         }
6853                     }
6854                     href = xmlGetProp(cur, BAD_CAST "href");
6855                     if (href == NULL) {
6856                         if (ctxt->error != NULL)
6857                             ctxt->error(ctxt->userData,
6858                     "xmlRelaxNGParse: externalRef has no href attribute\n");
6859                         ctxt->nbErrors++;
6860                         delete = cur;
6861                         goto skip_children;
6862                     }
6863                     base = xmlNodeGetBase(cur->doc, cur);
6864                     URL = xmlBuildURI(href, base);
6865                     if (URL == NULL) {
6866                         if (ctxt->error != NULL)
6867                             ctxt->error(ctxt->userData,
6868                         "Failed to compute URL for externalRef %s\n", href);
6869                         ctxt->nbErrors++;
6870                         if (href != NULL)
6871                             xmlFree(href);
6872                         if (base != NULL)
6873                             xmlFree(base);
6874                         delete = cur;
6875                         goto skip_children;
6876                     }
6877                     if (href != NULL)
6878                         xmlFree(href);
6879                     if (base != NULL)
6880                         xmlFree(base);
6881                     docu = xmlRelaxNGLoadExternalRef(ctxt, URL, ns);
6882                     if (docu == NULL) {
6883                         if (ctxt->error != NULL)
6884                             ctxt->error(ctxt->userData,
6885                                 "Failed to load externalRef %s\n", URL);
6886                         ctxt->nbErrors++;
6887                         xmlFree(URL);
6888                         delete = cur;
6889                         goto skip_children;
6890                     }
6891                     if (ns != NULL)
6892                         xmlFree(ns);
6893                     xmlFree(URL);
6894                     cur->_private = docu;
6895                 } else if (xmlStrEqual(cur->name, BAD_CAST "include")) {
6896                     xmlChar *href, *ns, *base, *URL;
6897                     xmlRelaxNGIncludePtr incl;
6898                     xmlNodePtr tmp;
6899
6900                     href = xmlGetProp(cur, BAD_CAST "href");
6901                     if (href == NULL) {
6902                         if (ctxt->error != NULL)
6903                             ctxt->error(ctxt->userData,
6904                     "xmlRelaxNGParse: include has no href attribute\n");
6905                         ctxt->nbErrors++;
6906                         delete = cur;
6907                         goto skip_children;
6908                     }
6909                     base = xmlNodeGetBase(cur->doc, cur);
6910                     URL = xmlBuildURI(href, base);
6911                     if (URL == NULL) {
6912                         if (ctxt->error != NULL)
6913                             ctxt->error(ctxt->userData,
6914                         "Failed to compute URL for include %s\n", href);
6915                         ctxt->nbErrors++;
6916                         if (href != NULL)
6917                             xmlFree(href);
6918                         if (base != NULL)
6919                             xmlFree(base);
6920                         delete = cur;
6921                         goto skip_children;
6922                     }
6923                     if (href != NULL)
6924                         xmlFree(href);
6925                     if (base != NULL)
6926                         xmlFree(base);
6927                     ns = xmlGetProp(cur, BAD_CAST "ns");
6928                     if (ns == NULL) {
6929                         tmp = cur->parent;
6930                         while ((tmp != NULL) &&
6931                                (tmp->type == XML_ELEMENT_NODE)) {
6932                             ns = xmlGetProp(tmp, BAD_CAST "ns");
6933                             if (ns != NULL)
6934                                 break;
6935                             tmp = tmp->parent;
6936                         }
6937                     }
6938                     incl = xmlRelaxNGLoadInclude(ctxt, URL, cur, ns);
6939                     if (ns != NULL)
6940                         xmlFree(ns);
6941                     if (incl == NULL) {
6942                         if (ctxt->error != NULL)
6943                             ctxt->error(ctxt->userData,
6944                                 "Failed to load include %s\n", URL);
6945                         ctxt->nbErrors++;
6946                         xmlFree(URL);
6947                         delete = cur;
6948                         goto skip_children;
6949                     }
6950                     xmlFree(URL);
6951                     cur->_private = incl;
6952                 } else if ((xmlStrEqual(cur->name, BAD_CAST "element")) ||
6953                     (xmlStrEqual(cur->name, BAD_CAST "attribute"))) {
6954                     xmlChar *name, *ns;
6955                     xmlNodePtr text = NULL;
6956                     
6957                     /*
6958                      * Simplification 4.8. name attribute of element
6959                      * and attribute elements
6960                      */
6961                     name = xmlGetProp(cur, BAD_CAST "name");
6962                     if (name != NULL) {
6963                         if (cur->children == NULL) {
6964                             text = xmlNewChild(cur, cur->ns, BAD_CAST "name",
6965                                                name);
6966                         } else {
6967                             xmlNodePtr node;
6968                             node = xmlNewNode(cur->ns, BAD_CAST "name");
6969                             if (node != NULL) {
6970                                 xmlAddPrevSibling(cur->children, node);
6971                                 text = xmlNewText(name);
6972                                 xmlAddChild(node, text);
6973                                 text = node;
6974                             }
6975                         }
6976                         if (text == NULL) {
6977                             if (ctxt->error != NULL)
6978                                 ctxt->error(ctxt->userData,
6979                                 "Failed to create a name %s element\n", name);
6980                             ctxt->nbErrors++;
6981                         }
6982                         xmlUnsetProp(cur, BAD_CAST "name");
6983                         xmlFree(name);
6984                         ns = xmlGetProp(cur, BAD_CAST "ns");
6985                         if (ns != NULL) {
6986                             if (text != NULL) {
6987                                 xmlSetProp(text, BAD_CAST "ns", ns);
6988                                 /* xmlUnsetProp(cur, BAD_CAST "ns"); */
6989                             }
6990                             xmlFree(ns);
6991                         } else if (xmlStrEqual(cur->name,
6992                                    BAD_CAST "attribute")) {
6993                             xmlSetProp(text, BAD_CAST "ns", BAD_CAST "");
6994                         }
6995                     }
6996                 } else if ((xmlStrEqual(cur->name, BAD_CAST "name")) ||
6997                            (xmlStrEqual(cur->name, BAD_CAST "nsName")) ||
6998                            (xmlStrEqual(cur->name, BAD_CAST "value"))) {
6999                     /*
7000                      * Simplification 4.8. name attribute of element
7001                      * and attribute elements
7002                      */
7003                     if (xmlHasProp(cur, BAD_CAST "ns") == NULL) {
7004                         xmlNodePtr node;
7005                         xmlChar *ns = NULL;
7006
7007                         node = cur->parent;
7008                         while ((node != NULL) &&
7009                                (node->type == XML_ELEMENT_NODE)) {
7010                             ns = xmlGetProp(node, BAD_CAST "ns");
7011                             if (ns != NULL) {
7012                                 break;
7013                             }
7014                             node = node->parent;
7015                         }
7016                         if (ns == NULL) {
7017                             xmlSetProp(cur, BAD_CAST "ns", BAD_CAST "");
7018                         } else {
7019                             xmlSetProp(cur, BAD_CAST "ns", ns);
7020                             xmlFree(ns);
7021                         }
7022                     }
7023                     if (xmlStrEqual(cur->name, BAD_CAST "name")) {
7024                         xmlChar *name, *local, *prefix;
7025
7026                         /*
7027                          * Simplification: 4.10. QNames
7028                          */
7029                         name = xmlNodeGetContent(cur);
7030                         if (name != NULL) {
7031                             local = xmlSplitQName2(name, &prefix);
7032                             if (local != NULL) {
7033                                 xmlNsPtr ns;
7034
7035                                 ns = xmlSearchNs(cur->doc, cur, prefix);
7036                                 if (ns == NULL) {
7037                                     if (ctxt->error != NULL)
7038                                         ctxt->error(ctxt->userData,
7039                     "xmlRelaxNGParse: no namespace for prefix %s\n", prefix);
7040                                     ctxt->nbErrors++;
7041                                 } else {
7042                                     xmlSetProp(cur, BAD_CAST "ns", ns->href);
7043                                     xmlNodeSetContent(cur, local);
7044                                 }
7045                                 xmlFree(local);
7046                                 xmlFree(prefix);
7047                             }
7048                             xmlFree(name);
7049                         } 
7050                     }
7051                     /*
7052                      * 4.16
7053                      */
7054                     if (xmlStrEqual(cur->name, BAD_CAST "nsName")) {
7055                         if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) {
7056                             if (ctxt->error != NULL)
7057                                 ctxt->error(ctxt->userData,
7058                     "Found nsName/except//nsName forbidden construct\n");
7059                             ctxt->nbErrors++;
7060                         }
7061                     }
7062                 } else if ((xmlStrEqual(cur->name, BAD_CAST "except")) &&
7063                            (cur != root)) {
7064                     int oldflags = ctxt->flags;
7065
7066                     /*
7067                      * 4.16
7068                      */
7069                     if ((cur->parent != NULL) &&
7070                         (xmlStrEqual(cur->parent->name, BAD_CAST "anyName"))) {
7071                         ctxt->flags |= XML_RELAXNG_IN_ANYEXCEPT;
7072                         xmlRelaxNGCleanupTree(ctxt, cur);
7073                         ctxt->flags = oldflags;
7074                         goto skip_children;
7075                     } else if ((cur->parent != NULL) &&
7076                         (xmlStrEqual(cur->parent->name, BAD_CAST "nsName"))) {
7077                         ctxt->flags |= XML_RELAXNG_IN_NSEXCEPT;
7078                         xmlRelaxNGCleanupTree(ctxt, cur);
7079                         ctxt->flags = oldflags;
7080                         goto skip_children;
7081                     }
7082                 } else if (xmlStrEqual(cur->name, BAD_CAST "anyName")) {
7083                     /*
7084                      * 4.16
7085                      */
7086                     if (ctxt->flags & XML_RELAXNG_IN_ANYEXCEPT) {
7087                         if (ctxt->error != NULL)
7088                             ctxt->error(ctxt->userData,
7089                 "Found anyName/except//anyName forbidden construct\n");
7090                         ctxt->nbErrors++;
7091                     } else if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) {
7092                         if (ctxt->error != NULL)
7093                             ctxt->error(ctxt->userData,
7094                 "Found nsName/except//anyName forbidden construct\n");
7095                         ctxt->nbErrors++;
7096                     }
7097                 }
7098                 /*
7099                  * Thisd is not an else since "include" is transformed
7100                  * into a div
7101                  */
7102                 if (xmlStrEqual(cur->name, BAD_CAST "div")) {
7103                     xmlChar *ns;
7104                     xmlNodePtr child, ins, tmp;
7105
7106                     /*
7107                      * implements rule 4.11
7108                      */
7109
7110                     ns = xmlGetProp(cur, BAD_CAST "ns");
7111
7112                     child = cur->children;
7113                     ins = cur;
7114                     while (child != NULL) {
7115                         if (ns != NULL) {
7116                             if (!xmlHasProp(child, BAD_CAST "ns")) {
7117                                 xmlSetProp(child, BAD_CAST "ns", ns);
7118                             }
7119                         }
7120                         tmp = child->next;
7121                         xmlUnlinkNode(child);
7122                         ins = xmlAddNextSibling(ins, child);
7123                         child = tmp;
7124                     }
7125                     if (ns != NULL)
7126                         xmlFree(ns);
7127                     delete = cur;
7128                     goto skip_children;
7129                 }
7130             }
7131         }
7132         /*
7133          * Simplification 4.2 whitespaces
7134          */
7135         else if ((cur->type == XML_TEXT_NODE) ||
7136                  (cur->type == XML_CDATA_SECTION_NODE)) {
7137             if (IS_BLANK_NODE(cur)) {
7138                 if (cur->parent->type == XML_ELEMENT_NODE) {
7139                     if ((!xmlStrEqual(cur->parent->name, BAD_CAST "value")) &&
7140                         (!xmlStrEqual(cur->parent->name, BAD_CAST "param")))
7141                         delete = cur;
7142                 } else {
7143                     delete = cur;
7144                     goto skip_children;
7145                 }
7146             }
7147         } else {
7148             delete = cur;
7149             goto skip_children;
7150         }
7151
7152         /*
7153          * Skip to next node
7154          */
7155         if (cur->children != NULL) {
7156             if ((cur->children->type != XML_ENTITY_DECL) &&
7157                 (cur->children->type != XML_ENTITY_REF_NODE) &&
7158                 (cur->children->type != XML_ENTITY_NODE)) {
7159                 cur = cur->children;
7160                 continue;
7161             }
7162         }
7163 skip_children:
7164         if (cur->next != NULL) {
7165             cur = cur->next;
7166             continue;
7167         }
7168         
7169         do {
7170             cur = cur->parent;
7171             if (cur == NULL)
7172                 break;
7173             if (cur == root) {
7174                 cur = NULL;
7175                 break;
7176             }
7177             if (cur->next != NULL) {
7178                 cur = cur->next;
7179                 break;
7180             }
7181         } while (cur != NULL);
7182     }
7183     if (delete != NULL) {
7184         xmlUnlinkNode(delete);
7185         xmlFreeNode(delete);
7186         delete = NULL;
7187     }
7188 }
7189
7190 /**
7191  * xmlRelaxNGCleanupDoc:
7192  * @ctxt:  a Relax-NG parser context
7193  * @doc:  an xmldocPtr document pointer
7194  *
7195  * Cleanup the document from unwanted nodes for parsing, resolve
7196  * Include and externalRef lookups.
7197  *
7198  * Returns the cleaned up document or NULL in case of error
7199  */
7200 static xmlDocPtr
7201 xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt, xmlDocPtr doc) {
7202     xmlNodePtr root;
7203
7204     /*
7205      * Extract the root
7206      */
7207     root = xmlDocGetRootElement(doc);
7208     if (root == NULL) {
7209         if (ctxt->error != NULL)
7210             ctxt->error(ctxt->userData, "xmlRelaxNGParse: %s is empty\n",
7211                         ctxt->URL);
7212         ctxt->nbErrors++;
7213         return (NULL);
7214     }
7215     xmlRelaxNGCleanupTree(ctxt, root);
7216     return(doc);
7217 }
7218
7219 /**
7220  * xmlRelaxNGParse:
7221  * @ctxt:  a Relax-NG parser context
7222  *
7223  * parse a schema definition resource and build an internal
7224  * XML Shema struture which can be used to validate instances.
7225  * *WARNING* this interface is highly subject to change
7226  *
7227  * Returns the internal XML RelaxNG structure built from the resource or
7228  *         NULL in case of error
7229  */
7230 xmlRelaxNGPtr
7231 xmlRelaxNGParse(xmlRelaxNGParserCtxtPtr ctxt)
7232 {
7233     xmlRelaxNGPtr ret = NULL;
7234     xmlDocPtr doc;
7235     xmlNodePtr root;
7236
7237     xmlRelaxNGInitTypes();
7238
7239     if (ctxt == NULL)
7240         return (NULL);
7241
7242     /*
7243      * First step is to parse the input document into an DOM/Infoset
7244      */
7245     if (ctxt->URL != NULL) {
7246         doc = xmlParseFile((const char *) ctxt->URL);
7247         if (doc == NULL) {
7248             if (ctxt->error != NULL)
7249                 ctxt->error(ctxt->userData,
7250                             "xmlRelaxNGParse: could not load %s\n", ctxt->URL);
7251             ctxt->nbErrors++;
7252             return (NULL);
7253         }
7254     } else if (ctxt->buffer != NULL) {
7255         doc = xmlParseMemory(ctxt->buffer, ctxt->size);
7256         if (doc == NULL) {
7257             if (ctxt->error != NULL)
7258                 ctxt->error(ctxt->userData,
7259                             "xmlRelaxNGParse: could not parse schemas\n");
7260             ctxt->nbErrors++;
7261             return (NULL);
7262         }
7263         doc->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
7264         ctxt->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
7265     } else if (ctxt->document != NULL) {
7266         doc = ctxt->document;
7267     } else {
7268         if (ctxt->error != NULL)
7269             ctxt->error(ctxt->userData,
7270                         "xmlRelaxNGParse: nothing to parse\n");
7271         ctxt->nbErrors++;
7272         return (NULL);
7273     }
7274     ctxt->document = doc;
7275
7276     /*
7277      * Some preprocessing of the document content
7278      */
7279     doc = xmlRelaxNGCleanupDoc(ctxt, doc);
7280     if (doc == NULL) {
7281         xmlFreeDoc(ctxt->document);
7282         ctxt->document = NULL;
7283         return(NULL);
7284     }
7285
7286     /*
7287      * Then do the parsing for good
7288      */
7289     root = xmlDocGetRootElement(doc);
7290     if (root == NULL) {
7291         if (ctxt->error != NULL)
7292             ctxt->error(ctxt->userData, "xmlRelaxNGParse: %s is empty\n",
7293                         ctxt->URL);
7294         ctxt->nbErrors++;
7295         xmlFreeDoc(doc);
7296         return (NULL);
7297     }
7298     ret = xmlRelaxNGParseDocument(ctxt, root);
7299     if (ret == NULL) {
7300         xmlFreeDoc(doc);
7301         return(NULL);
7302     }
7303
7304     /*
7305      * Check the ref/defines links
7306      */
7307     /*
7308      * try to preprocess interleaves
7309      */
7310     if (ctxt->interleaves != NULL) {
7311         xmlHashScan(ctxt->interleaves,
7312                 (xmlHashScanner)xmlRelaxNGComputeInterleaves, ctxt);
7313     }
7314
7315     /*
7316      * if there was a parsing error return NULL
7317      */
7318     if (ctxt->nbErrors > 0) {
7319         xmlRelaxNGFree(ret);
7320         ctxt->document = NULL;
7321         xmlFreeDoc(doc);
7322         return(NULL);
7323     }
7324
7325     /*
7326      * try to compile (parts of) the schemas
7327      */
7328     if ((ret->topgrammar != NULL) && (ret->topgrammar->start != NULL)) {
7329         if (ret->topgrammar->start->type != XML_RELAXNG_START) {
7330             xmlRelaxNGDefinePtr def;
7331
7332             def = xmlRelaxNGNewDefine(ctxt, NULL);
7333             if (def != NULL) {
7334                 def->type = XML_RELAXNG_START;
7335                 def->content = ret->topgrammar->start;
7336                 ret->topgrammar->start = def;
7337             }
7338         }
7339         xmlRelaxNGTryCompile(ctxt, ret->topgrammar->start);
7340     }
7341
7342     /*
7343      * Transfer the pointer for cleanup at the schema level.
7344      */
7345     ret->doc = doc;
7346     ctxt->document = NULL;
7347     ret->documents = ctxt->documents;
7348     ctxt->documents = NULL;
7349     
7350     ret->includes = ctxt->includes;
7351     ctxt->includes = NULL;
7352     ret->defNr = ctxt->defNr;
7353     ret->defTab = ctxt->defTab;
7354     ctxt->defTab = NULL;
7355     if (ctxt->idref == 1)
7356         ret->idref = 1;
7357
7358     return (ret);
7359 }
7360  
7361 /**
7362  * xmlRelaxNGSetParserErrors:
7363  * @ctxt:  a Relax-NG validation context
7364  * @err:  the error callback
7365  * @warn:  the warning callback
7366  * @ctx:  contextual data for the callbacks
7367  *
7368  * Set the callback functions used to handle errors for a validation context
7369  */
7370 void
7371 xmlRelaxNGSetParserErrors(xmlRelaxNGParserCtxtPtr ctxt,
7372         xmlRelaxNGValidityErrorFunc err,
7373         xmlRelaxNGValidityWarningFunc warn, void *ctx) {
7374     if (ctxt == NULL)
7375         return;
7376     ctxt->error = err;
7377     ctxt->warning = warn;
7378     ctxt->userData = ctx;
7379 }
7380
7381 /**
7382  * xmlRelaxNGGetParserErrors:
7383  * @ctxt:  a Relax-NG validation context
7384  * @err:  the error callback result
7385  * @warn:  the warning callback result
7386  * @ctx:  contextual data for the callbacks result
7387  *
7388  * Get the callback information used to handle errors for a validation context
7389  *
7390  * Returns -1 in case of failure, 0 otherwise.
7391  */
7392 int
7393 xmlRelaxNGGetParserErrors(xmlRelaxNGParserCtxtPtr ctxt,
7394         xmlRelaxNGValidityErrorFunc *err,
7395         xmlRelaxNGValidityWarningFunc *warn, void **ctx) {
7396     if (ctxt == NULL)
7397         return(-1);
7398     if (err != NULL) *err = ctxt->error;
7399     if (warn != NULL) *warn = ctxt->warning;
7400     if (ctx != NULL) *ctx = ctxt->userData;
7401     return(0);
7402 }
7403
7404 /************************************************************************
7405  *                                                                      *
7406  *                      Dump back a compiled form                       *
7407  *                                                                      *
7408  ************************************************************************/
7409 static void xmlRelaxNGDumpDefine(FILE * output, xmlRelaxNGDefinePtr define);
7410
7411 /**
7412  * xmlRelaxNGDumpDefines:
7413  * @output:  the file output
7414  * @defines:  a list of define structures
7415  *
7416  * Dump a RelaxNG structure back
7417  */
7418 static void
7419 xmlRelaxNGDumpDefines(FILE * output, xmlRelaxNGDefinePtr defines) {
7420     while (defines != NULL) {
7421         xmlRelaxNGDumpDefine(output, defines);
7422         defines = defines->next;
7423     }
7424 }
7425
7426 /**
7427  * xmlRelaxNGDumpDefine:
7428  * @output:  the file output
7429  * @define:  a define structure
7430  *
7431  * Dump a RelaxNG structure back
7432  */
7433 static void
7434 xmlRelaxNGDumpDefine(FILE * output, xmlRelaxNGDefinePtr define) {
7435     if (define == NULL)
7436         return;
7437     switch(define->type) {
7438         case XML_RELAXNG_EMPTY:
7439             fprintf(output, "<empty/>\n");
7440             break;
7441         case XML_RELAXNG_NOT_ALLOWED:
7442             fprintf(output, "<notAllowed/>\n");
7443             break;
7444         case XML_RELAXNG_TEXT:
7445             fprintf(output, "<text/>\n");
7446             break;
7447         case XML_RELAXNG_ELEMENT:
7448             fprintf(output, "<element>\n");
7449             if (define->name != NULL) {
7450                 fprintf(output, "<name");
7451                 if (define->ns != NULL)
7452                     fprintf(output, " ns=\"%s\"", define->ns);
7453                 fprintf(output, ">%s</name>\n", define->name);
7454             }
7455             xmlRelaxNGDumpDefines(output, define->attrs);
7456             xmlRelaxNGDumpDefines(output, define->content);
7457             fprintf(output, "</element>\n");
7458             break;
7459         case XML_RELAXNG_LIST:
7460             fprintf(output, "<list>\n");
7461             xmlRelaxNGDumpDefines(output, define->content);
7462             fprintf(output, "</list>\n");
7463             break;
7464         case XML_RELAXNG_ONEORMORE:
7465             fprintf(output, "<oneOrMore>\n");
7466             xmlRelaxNGDumpDefines(output, define->content);
7467             fprintf(output, "</oneOrMore>\n");
7468             break;
7469         case XML_RELAXNG_ZEROORMORE:
7470             fprintf(output, "<zeroOrMore>\n");
7471             xmlRelaxNGDumpDefines(output, define->content);
7472             fprintf(output, "</zeroOrMore>\n");
7473             break;
7474         case XML_RELAXNG_CHOICE:
7475             fprintf(output, "<choice>\n");
7476             xmlRelaxNGDumpDefines(output, define->content);
7477             fprintf(output, "</choice>\n");
7478             break;
7479         case XML_RELAXNG_GROUP:
7480             fprintf(output, "<group>\n");
7481             xmlRelaxNGDumpDefines(output, define->content);
7482             fprintf(output, "</group>\n");
7483             break;
7484         case XML_RELAXNG_INTERLEAVE:
7485             fprintf(output, "<interleave>\n");
7486             xmlRelaxNGDumpDefines(output, define->content);
7487             fprintf(output, "</interleave>\n");
7488             break;
7489         case XML_RELAXNG_OPTIONAL:
7490             fprintf(output, "<optional>\n");
7491             xmlRelaxNGDumpDefines(output, define->content);
7492             fprintf(output, "</optional>\n");
7493             break;
7494         case XML_RELAXNG_ATTRIBUTE:
7495             fprintf(output, "<attribute>\n");
7496             xmlRelaxNGDumpDefines(output, define->content);
7497             fprintf(output, "</attribute>\n");
7498             break;
7499         case XML_RELAXNG_DEF:
7500             fprintf(output, "<define");
7501             if (define->name != NULL)
7502                 fprintf(output, " name=\"%s\"", define->name);
7503             fprintf(output, ">\n");
7504             xmlRelaxNGDumpDefines(output, define->content);
7505             fprintf(output, "</define>\n");
7506             break;
7507         case XML_RELAXNG_REF:
7508             fprintf(output, "<ref");
7509             if (define->name != NULL)
7510                 fprintf(output, " name=\"%s\"", define->name);
7511             fprintf(output, ">\n");
7512             xmlRelaxNGDumpDefines(output, define->content);
7513             fprintf(output, "</ref>\n");
7514             break;
7515         case XML_RELAXNG_PARENTREF:
7516             fprintf(output, "<parentRef");
7517             if (define->name != NULL)
7518                 fprintf(output, " name=\"%s\"", define->name);
7519             fprintf(output, ">\n");
7520             xmlRelaxNGDumpDefines(output, define->content);
7521             fprintf(output, "</parentRef>\n");
7522             break;
7523         case XML_RELAXNG_EXTERNALREF:
7524             fprintf(output, "<externalRef>");
7525             xmlRelaxNGDumpDefines(output, define->content);
7526             fprintf(output, "</externalRef>\n");
7527             break;
7528         case XML_RELAXNG_DATATYPE:
7529         case XML_RELAXNG_VALUE:
7530             TODO
7531             break;
7532         case XML_RELAXNG_START:
7533         case XML_RELAXNG_EXCEPT:
7534         case XML_RELAXNG_PARAM:
7535             TODO
7536             break;
7537         case XML_RELAXNG_NOOP:
7538             xmlRelaxNGDumpDefines(output, define->content);
7539             break;
7540     }
7541 }
7542    
7543 /**
7544  * xmlRelaxNGDumpGrammar:
7545  * @output:  the file output
7546  * @grammar:  a grammar structure
7547  * @top:  is this a top grammar 
7548  *
7549  * Dump a RelaxNG structure back
7550  */
7551 static void
7552 xmlRelaxNGDumpGrammar(FILE * output, xmlRelaxNGGrammarPtr grammar, int top)
7553 {
7554     if (grammar == NULL)
7555         return;
7556    
7557     fprintf(output, "<grammar");
7558     if (top)
7559         fprintf(output,
7560                 " xmlns=\"http://relaxng.org/ns/structure/1.0\"");
7561     switch(grammar->combine) {
7562         case XML_RELAXNG_COMBINE_UNDEFINED:
7563             break;
7564         case XML_RELAXNG_COMBINE_CHOICE:
7565             fprintf(output, " combine=\"choice\"");
7566             break;
7567         case XML_RELAXNG_COMBINE_INTERLEAVE:
7568             fprintf(output, " combine=\"interleave\"");
7569             break;
7570         default:
7571             fprintf(output, " <!-- invalid combine value -->");
7572     }
7573     fprintf(output, ">\n");
7574     if (grammar->start == NULL) {
7575         fprintf(output, " <!-- grammar had no start -->");
7576     } else {
7577         fprintf(output, "<start>\n");
7578         xmlRelaxNGDumpDefine(output, grammar->start);
7579         fprintf(output, "</start>\n");
7580     }
7581     /* TODO ? Dump the defines ? */
7582     fprintf(output, "</grammar>\n");
7583 }
7584
7585 /**
7586  * xmlRelaxNGDump:
7587  * @output:  the file output
7588  * @schema:  a schema structure
7589  *
7590  * Dump a RelaxNG structure back
7591  */
7592 void
7593 xmlRelaxNGDump(FILE * output, xmlRelaxNGPtr schema)
7594 {
7595     if (schema == NULL) {
7596         fprintf(output, "RelaxNG empty or failed to compile\n");
7597         return;
7598     }
7599     fprintf(output, "RelaxNG: ");
7600     if (schema->doc == NULL) {
7601         fprintf(output, "no document\n");
7602     } else if (schema->doc->URL != NULL) {
7603         fprintf(output, "%s\n", schema->doc->URL);
7604     } else {
7605         fprintf(output, "\n");
7606     }
7607     if (schema->topgrammar == NULL) {
7608         fprintf(output, "RelaxNG has no top grammar\n");
7609         return;
7610     }
7611     xmlRelaxNGDumpGrammar(output, schema->topgrammar, 1);
7612 }
7613
7614 /**
7615  * xmlRelaxNGDumpTree:
7616  * @output:  the file output
7617  * @schema:  a schema structure
7618  *
7619  * Dump the transformed RelaxNG tree.
7620  */
7621 void
7622 xmlRelaxNGDumpTree(FILE * output, xmlRelaxNGPtr schema)
7623 {
7624     if (schema == NULL) {
7625         fprintf(output, "RelaxNG empty or failed to compile\n");
7626         return;
7627     }
7628     if (schema->doc == NULL) {
7629         fprintf(output, "no document\n");
7630     } else {
7631         xmlDocDump(output, schema->doc); 
7632     }
7633 }
7634
7635 /************************************************************************
7636  *                                                                      *
7637  *              Validation of compiled content                          *
7638  *                                                                      *
7639  ************************************************************************/
7640 static int xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt, 
7641                                         xmlRelaxNGDefinePtr define);
7642
7643 /**
7644  * xmlRelaxNGValidateCompiledCallback:
7645  * @exec:  the regular expression instance
7646  * @token:  the token which matched
7647  * @transdata:  callback data, the define for the subelement if available
7648  @ @inputdata:  callback data, the Relax NG validation context
7649  *
7650  * Handle the callback and if needed validate the element children.
7651  */
7652 static void 
7653 xmlRelaxNGValidateCompiledCallback(xmlRegExecCtxtPtr exec ATTRIBUTE_UNUSED,
7654                                    const xmlChar *token,
7655                                    void *transdata,
7656                                    void *inputdata) {
7657     xmlRelaxNGValidCtxtPtr ctxt = (xmlRelaxNGValidCtxtPtr) inputdata;
7658     xmlRelaxNGDefinePtr define = (xmlRelaxNGDefinePtr) transdata;
7659     int ret;
7660
7661 #ifdef DEBUG_COMPILE
7662     xmlGenericError(xmlGenericErrorContext,
7663                     "Compiled callback for: '%s'\n", token);
7664 #endif
7665     if (ctxt == NULL) {
7666         fprintf(stderr, "callback on %s missing context\n", token);
7667         if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
7668             ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7669         return;
7670     }
7671     if (define == NULL) {
7672         if (token[0] == '#')
7673             return;
7674         fprintf(stderr, "callback on %s missing define\n", token);
7675         if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
7676             ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7677         return;
7678     }
7679     if ((ctxt == NULL) || (define == NULL)) {
7680         fprintf(stderr, "callback on %s missing info\n", token);
7681         if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
7682             ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7683         return;
7684     } else if (define->type != XML_RELAXNG_ELEMENT) {
7685         fprintf(stderr, "callback on %s define is not element\n", token);
7686         if (ctxt->errNo == XML_RELAXNG_OK)
7687             ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7688         return;
7689     }
7690     ret = xmlRelaxNGValidateDefinition(ctxt, define);
7691 }
7692
7693 /**
7694  * xmlRelaxNGValidateCompiledContent:
7695  * @ctxt:  the RelaxNG validation context
7696  * @regexp:  the regular expression as compiled
7697  * @content:  list of children to test against the regexp
7698  *
7699  * Validate the content model of an element or start using the regexp
7700  *
7701  * Returns 0 in case of success, -1 in case of error.
7702  */
7703 static int
7704 xmlRelaxNGValidateCompiledContent(xmlRelaxNGValidCtxtPtr ctxt,
7705                                   xmlRegexpPtr regexp, xmlNodePtr content) {
7706     xmlRegExecCtxtPtr exec;
7707     xmlNodePtr cur;
7708     int ret = 0;
7709
7710     if ((ctxt == NULL) || (regexp == NULL))
7711         return(-1);
7712     exec = xmlRegNewExecCtxt(regexp, 
7713                              xmlRelaxNGValidateCompiledCallback, ctxt);
7714     cur = content;
7715     while (cur != NULL) {
7716         ctxt->state->seq = cur;
7717         switch (cur->type) {
7718             case XML_TEXT_NODE:
7719             case XML_CDATA_SECTION_NODE:
7720                 if (xmlIsBlankNode(cur))
7721                     break;
7722                 ret = xmlRegExecPushString(exec, BAD_CAST "#text", ctxt);
7723                 if (ret < 0) {
7724                     VALID_ERR2(XML_RELAXNG_ERR_TEXTWRONG, cur->parent->name);
7725                 }
7726                 break;
7727             case XML_ELEMENT_NODE:
7728                 if (cur->ns != NULL) {
7729                     ret = xmlRegExecPushString2(exec, cur->name,
7730                                                 cur->ns->href, ctxt);
7731                 } else {
7732                     ret = xmlRegExecPushString(exec, cur->name, ctxt);
7733                 }
7734                 if (ret < 0) {
7735                     VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG, cur->name);
7736                 }
7737                 break;
7738             default:
7739                 break;
7740         }
7741         if (ret < 0) break;
7742         /*
7743          * Switch to next element
7744          */
7745         cur = cur->next;
7746     }
7747     ret = xmlRegExecPushString(exec, NULL, NULL);
7748     if (ret == 1) {
7749         ret = 0;
7750         ctxt->state->seq = NULL;
7751     } else if (ret == 0) {
7752         /*
7753          * TODO: get some of the names needed to exit the current state of exec
7754          */
7755         VALID_ERR2(XML_RELAXNG_ERR_NOELEM, BAD_CAST "");
7756         ret = -1;
7757         if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
7758             xmlRelaxNGDumpValidError(ctxt);
7759     } else {
7760         ret = -1;
7761     }
7762     xmlRegFreeExecCtxt(exec);
7763     return(ret);
7764 }
7765
7766 /************************************************************************
7767  *                                                                      *
7768  *              Progressive validation of when possible                 *
7769  *                                                                      *
7770  ************************************************************************/
7771 static int xmlRelaxNGValidateAttributeList(xmlRelaxNGValidCtxtPtr ctxt, 
7772                                            xmlRelaxNGDefinePtr defines);
7773 static int xmlRelaxNGValidateElementEnd(xmlRelaxNGValidCtxtPtr ctxt);
7774
7775 /**
7776  * xmlRelaxNGElemPush:
7777  * @ctxt:  the validation context
7778  * @exec:  the regexp runtime for the new content model
7779  *
7780  * Push a new regexp for the current node content model on the stack
7781  *
7782  * Returns 0 in case of success and -1 in case of error.
7783  */
7784 static int
7785 xmlRelaxNGElemPush(xmlRelaxNGValidCtxtPtr ctxt, xmlRegExecCtxtPtr exec) {
7786     if (ctxt->elemTab == NULL) {
7787         ctxt->elemMax = 10;
7788         ctxt->elemTab = (xmlRegExecCtxtPtr *) xmlMalloc(ctxt->elemMax *
7789                               sizeof(xmlRegExecCtxtPtr));
7790         if (ctxt->elemTab == NULL) {
7791             VALID_ERR(XML_RELAXNG_ERR_MEMORY);
7792             return(-1);
7793         }
7794     }
7795     if (ctxt->elemNr >= ctxt->elemMax) {
7796         ctxt->elemMax *= 2;
7797         ctxt->elemTab = (xmlRegExecCtxtPtr *) xmlRealloc(ctxt->elemTab,
7798                      ctxt->elemMax * sizeof(xmlRegExecCtxtPtr));
7799         if (ctxt->elemTab == NULL) {
7800             VALID_ERR(XML_RELAXNG_ERR_MEMORY);
7801             return(-1);
7802         }
7803     }
7804     ctxt->elemTab[ctxt->elemNr++] = exec;
7805     ctxt->elem = exec;
7806     return(0);
7807 }
7808
7809 /**
7810  * xmlRelaxNGElemPop:
7811  * @ctxt:  the validation context
7812  *
7813  * Pop the regexp of the current node content model from the stack
7814  *
7815  * Returns the exec or NULL if empty
7816  */
7817 static xmlRegExecCtxtPtr
7818 xmlRelaxNGElemPop(xmlRelaxNGValidCtxtPtr ctxt) {
7819     xmlRegExecCtxtPtr ret;
7820
7821     if (ctxt->elemNr <= 0) return(NULL);
7822     ctxt->elemNr--;
7823     ret = ctxt->elemTab[ctxt->elemNr];
7824     ctxt->elemTab[ctxt->elemNr] = NULL;
7825     if (ctxt->elemNr > 0) 
7826         ctxt->elem = ctxt->elemTab[ctxt->elemNr - 1];
7827     else
7828         ctxt->elem = NULL;
7829     return(ret);
7830 }
7831
7832 /**
7833  * xmlRelaxNGValidateProgressiveCallback:
7834  * @exec:  the regular expression instance
7835  * @token:  the token which matched
7836  * @transdata:  callback data, the define for the subelement if available
7837  @ @inputdata:  callback data, the Relax NG validation context
7838  *
7839  * Handle the callback and if needed validate the element children.
7840  * some of the in/out informations are passed via the context in @inputdata.
7841  */
7842 static void 
7843 xmlRelaxNGValidateProgressiveCallback(xmlRegExecCtxtPtr exec ATTRIBUTE_UNUSED,
7844                                    const xmlChar *token,
7845                                    void *transdata,
7846                                    void *inputdata) {
7847     xmlRelaxNGValidCtxtPtr ctxt = (xmlRelaxNGValidCtxtPtr) inputdata;
7848     xmlRelaxNGDefinePtr define = (xmlRelaxNGDefinePtr) transdata;
7849     xmlRelaxNGValidStatePtr state, oldstate;
7850     xmlNodePtr node = ctxt->pnode;
7851     int ret = 0, oldflags;
7852
7853 #ifdef DEBUG_PROGRESSIVE
7854     xmlGenericError(xmlGenericErrorContext,
7855                     "Progressive callback for: '%s'\n", token);
7856 #endif
7857     if (ctxt == NULL) {
7858         fprintf(stderr, "callback on %s missing context\n", token);
7859         return;
7860     }
7861     ctxt->pstate = 1;
7862     if (define == NULL) {
7863         if (token[0] == '#')
7864             return;
7865         fprintf(stderr, "callback on %s missing define\n", token);
7866         if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
7867             ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7868         ctxt->pstate = -1;
7869         return;
7870     }
7871     if ((ctxt == NULL) || (define == NULL)) {
7872         fprintf(stderr, "callback on %s missing info\n", token);
7873         if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
7874             ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7875         ctxt->pstate = -1;
7876         return;
7877     } else if (define->type != XML_RELAXNG_ELEMENT) {
7878         fprintf(stderr, "callback on %s define is not element\n", token);
7879         if (ctxt->errNo == XML_RELAXNG_OK)
7880             ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7881         ctxt->pstate = -1;
7882         return;
7883     }
7884     if (node->type != XML_ELEMENT_NODE) {
7885         VALID_ERR(XML_RELAXNG_ERR_NOTELEM);
7886         if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
7887             xmlRelaxNGDumpValidError(ctxt);
7888         ctxt->pstate = -1;
7889         return;
7890     }
7891     if (define->contModel == NULL) {
7892         /*
7893          * this node cannot be validated in a streamable fashion
7894          */
7895 #ifdef DEBUG_PROGRESSIVE
7896         xmlGenericError(xmlGenericErrorContext,
7897                     "Element '%s' validation is not streamable\n", token);
7898 #endif
7899         ctxt->pstate = 0;
7900         ctxt->pdef = define;
7901         return;
7902     }
7903     exec = xmlRegNewExecCtxt(define->contModel,
7904                              xmlRelaxNGValidateProgressiveCallback,
7905                              ctxt);
7906     if (exec == NULL) {
7907         ctxt->pstate = -1;
7908         return;
7909     }
7910     xmlRelaxNGElemPush(ctxt, exec);
7911
7912     /*
7913      * Validate the attributes part of the content.
7914      */
7915     state = xmlRelaxNGNewValidState(ctxt, node);
7916     if (state == NULL) {
7917         ctxt->pstate = -1;
7918         return;
7919     }
7920     oldstate = ctxt->state;
7921     ctxt->state = state;
7922     if (define->attrs != NULL) {
7923         ret = xmlRelaxNGValidateAttributeList(ctxt, define->attrs);
7924         if (ret != 0) {
7925             ctxt->pstate = -1;
7926             VALID_ERR2(XML_RELAXNG_ERR_ATTRVALID, node->name);
7927         }
7928     }
7929     if (ctxt->state != NULL) {
7930         ctxt->state->seq = NULL;
7931         ret = xmlRelaxNGValidateElementEnd(ctxt);
7932         if (ret != 0) {
7933             ctxt->pstate = -1;
7934         }
7935         xmlRelaxNGFreeValidState(ctxt, ctxt->state);
7936     } else if (ctxt->states != NULL) {
7937         int tmp = -1, i;
7938
7939         oldflags = ctxt->flags;
7940         ctxt->flags |= FLAGS_IGNORABLE;
7941
7942         for (i = 0; i < ctxt->states->nbState; i++) {
7943             state = ctxt->states->tabState[i];
7944             ctxt->state = state;
7945             ctxt->state->seq = NULL;
7946
7947             if (xmlRelaxNGValidateElementEnd(ctxt) == 0)
7948                 tmp = 0;
7949             xmlRelaxNGFreeValidState(ctxt, state);
7950         }
7951         xmlRelaxNGFreeStates(ctxt, ctxt->states);
7952         ctxt->states = NULL;
7953         if ((ret == 0) && (tmp == -1))
7954             ctxt->pstate = -1;
7955         ctxt->flags = oldflags;
7956     }
7957     if (ctxt->pstate == -1) {
7958         if ((ctxt->flags & FLAGS_IGNORABLE) == 0) {
7959             xmlRelaxNGDumpValidError(ctxt);
7960         }
7961     }
7962     ctxt->state = oldstate;
7963 }
7964
7965 /**
7966  * xmlRelaxNGValidatePushElement:
7967  * @ctxt:  the validation context
7968  * @doc:  a document instance
7969  * @elem:  an element instance
7970  *
7971  * Push a new element start on the RelaxNG validation stack.
7972  *
7973  * returns 1 if no validation problem was found or 0 if validating the
7974  *         element requires a full node, and -1 in case of error.
7975  */
7976 int
7977 xmlRelaxNGValidatePushElement(xmlRelaxNGValidCtxtPtr ctxt,
7978                               xmlDocPtr doc ATTRIBUTE_UNUSED,
7979                               xmlNodePtr elem)
7980 {
7981     int ret = 1;
7982
7983     if ((ctxt == NULL) || (elem == NULL))
7984         return (-1);
7985
7986 #ifdef DEBUG_PROGRESSIVE
7987     xmlGenericError(xmlGenericErrorContext, "PushElem %s\n", elem->name);
7988 #endif
7989     if (ctxt->elem == 0) {
7990         xmlRelaxNGPtr schema;
7991         xmlRelaxNGGrammarPtr grammar;
7992         xmlRegExecCtxtPtr exec;
7993         xmlRelaxNGDefinePtr define;
7994
7995         schema = ctxt->schema;
7996         if (schema == NULL) {
7997             VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR);
7998             return (-1);
7999         }
8000         grammar = schema->topgrammar;
8001         if ((grammar == NULL) || (grammar->start == NULL)) {
8002             VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR);
8003             return (-1);
8004         }
8005         define = grammar->start;
8006         if (define->contModel == NULL) {
8007             ctxt->pdef = define;
8008             return (0);
8009         }
8010         exec = xmlRegNewExecCtxt(define->contModel,
8011                                  xmlRelaxNGValidateProgressiveCallback,
8012                                  ctxt);
8013         if (exec == NULL) {
8014             return (-1);
8015         }
8016         xmlRelaxNGElemPush(ctxt, exec);
8017     }
8018     ctxt->pnode = elem;
8019     ctxt->pstate = 0;
8020     if (elem->ns != NULL) {
8021         ret =
8022             xmlRegExecPushString2(ctxt->elem, elem->name, elem->ns->href,
8023                                   ctxt);
8024     } else {
8025         ret = xmlRegExecPushString(ctxt->elem, elem->name, ctxt);
8026     }
8027     if (ret < 0) {
8028         VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG, elem->name);
8029     } else {
8030         if (ctxt->pstate == 0)
8031             ret = 0;
8032         else if (ctxt->pstate < 0)
8033             ret = -1;
8034         else
8035             ret = 1;
8036     }
8037 #ifdef DEBUG_PROGRESSIVE
8038     if (ret < 0)
8039         xmlGenericError(xmlGenericErrorContext, "PushElem %s failed\n",
8040                         elem->name);
8041 #endif
8042     return (ret);
8043 }
8044
8045 /**
8046  * xmlRelaxNGValidatePushCData:
8047  * @ctxt:  the RelaxNG validation context
8048  * @data:  some character data read
8049  * @len:  the lenght of the data
8050  *
8051  * check the CData parsed for validation in the current stack
8052  *
8053  * returns 1 if no validation problem was found or -1 otherwise
8054  */
8055 int
8056 xmlRelaxNGValidatePushCData(xmlRelaxNGValidCtxtPtr ctxt,
8057                             const xmlChar * data,
8058                             int len ATTRIBUTE_UNUSED)
8059 {
8060     int ret = 1;
8061
8062     if ((ctxt == NULL) || (ctxt->elem == NULL) || (data == NULL))
8063         return (-1);
8064
8065 #ifdef DEBUG_PROGRESSIVE
8066     xmlGenericError(xmlGenericErrorContext, "CDATA %s %d\n", data, len);
8067 #endif
8068
8069     while (*data != 0) {
8070         if (!IS_BLANK(*data))
8071             break;
8072         data++;
8073     }
8074     if (*data == 0)
8075         return(1);
8076
8077     ret = xmlRegExecPushString(ctxt->elem, BAD_CAST "#text", ctxt);
8078     if (ret < 0) {
8079         VALID_ERR2(XML_RELAXNG_ERR_TEXTWRONG, BAD_CAST " TODO ");
8080 #ifdef DEBUG_PROGRESSIVE
8081         xmlGenericError(xmlGenericErrorContext, "CDATA failed\n");
8082 #endif
8083
8084         return(-1);
8085     }
8086     return(1);
8087 }
8088
8089 /**
8090  * xmlRelaxNGValidatePopElement:
8091  * @ctxt:  the RelaxNG validation context
8092  * @doc:  a document instance
8093  * @elem:  an element instance
8094  *
8095  * Pop the element end from the RelaxNG validation stack.
8096  *
8097  * returns 1 if no validation problem was found or 0 otherwise
8098  */
8099 int
8100 xmlRelaxNGValidatePopElement(xmlRelaxNGValidCtxtPtr ctxt,
8101                              xmlDocPtr doc ATTRIBUTE_UNUSED,
8102                              xmlNodePtr elem) {
8103     int ret;
8104     xmlRegExecCtxtPtr exec;
8105
8106     if ((ctxt == NULL) || (ctxt->elem == NULL) || (elem == NULL)) return(-1);
8107 #ifdef DEBUG_PROGRESSIVE
8108     xmlGenericError(xmlGenericErrorContext, "PopElem %s\n", elem->name);
8109 #endif
8110     /*
8111      * verify that we reached a terminal state of the content model.
8112      */
8113     exec = xmlRelaxNGElemPop(ctxt);
8114     ret = xmlRegExecPushString(exec, NULL, NULL);
8115     if (ret == 0) {
8116         /*
8117          * TODO: get some of the names needed to exit the current state of exec
8118          */
8119         VALID_ERR2(XML_RELAXNG_ERR_NOELEM, BAD_CAST "");
8120         ret = -1;
8121     } else if (ret < 0) {
8122         ret = -1;
8123     } else {
8124         ret = 1;
8125     }
8126     xmlRegFreeExecCtxt(exec);
8127 #ifdef DEBUG_PROGRESSIVE
8128     if (ret < 0)
8129         xmlGenericError(xmlGenericErrorContext, "PopElem %s failed\n",
8130                         elem->name);
8131 #endif
8132     return(ret);
8133 }
8134
8135 /**
8136  * xmlRelaxNGValidateFullElement:
8137  * @ctxt:  the validation context
8138  * @doc:  a document instance
8139  * @elem:  an element instance
8140  *
8141  * Validate a full subtree when xmlRelaxNGValidatePushElement() returned
8142  * 0 and the content of the node has been expanded.
8143  *
8144  * returns 1 if no validation problem was found or -1 in case of error.
8145  */
8146 int
8147 xmlRelaxNGValidateFullElement(xmlRelaxNGValidCtxtPtr ctxt,
8148                               xmlDocPtr doc ATTRIBUTE_UNUSED,
8149                               xmlNodePtr elem) {
8150     int ret;
8151     xmlRelaxNGValidStatePtr state;
8152
8153     if ((ctxt == NULL) || (ctxt->pdef == NULL) || (elem == NULL)) return(-1);
8154 #ifdef DEBUG_PROGRESSIVE
8155     xmlGenericError(xmlGenericErrorContext, "FullElem %s\n", elem->name);
8156 #endif
8157     state = xmlRelaxNGNewValidState(ctxt, elem->parent);
8158     if (state == NULL) {
8159         return(-1);
8160     }
8161     state->seq = elem;
8162     ctxt->state = state;
8163     ctxt->errNo = XML_RELAXNG_OK;
8164     ret = xmlRelaxNGValidateDefinition(ctxt, ctxt->pdef);
8165     if ((ret != 0) || (ctxt->errNo != XML_RELAXNG_OK)) ret = -1;
8166     else ret = 1;
8167     xmlRelaxNGFreeValidState(ctxt, state);
8168     ctxt->state = NULL;
8169 #ifdef DEBUG_PROGRESSIVE
8170     if (ret < 0)
8171         xmlGenericError(xmlGenericErrorContext, "FullElem %s failed\n",
8172                         elem->name);
8173 #endif
8174     return(ret);
8175 }
8176
8177 /************************************************************************
8178  *                                                                      *
8179  *              Generic interpreted validation implementation           *
8180  *                                                                      *
8181  ************************************************************************/
8182 static int xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt, 
8183                                    xmlRelaxNGDefinePtr define);
8184
8185 /**
8186  * xmlRelaxNGSkipIgnored:
8187  * @ctxt:  a schema validation context
8188  * @node:  the top node.
8189  *
8190  * Skip ignorable nodes in that context
8191  *
8192  * Returns the new sibling or NULL in case of error.
8193  */
8194 static xmlNodePtr
8195 xmlRelaxNGSkipIgnored(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
8196                       xmlNodePtr node) {
8197     /*
8198      * TODO complete and handle entities
8199      */
8200     while ((node != NULL) &&
8201            ((node->type == XML_COMMENT_NODE) ||
8202             (node->type == XML_PI_NODE) ||
8203             (((node->type == XML_TEXT_NODE) || 
8204               (node->type == XML_CDATA_SECTION_NODE)) &&
8205              ((ctxt->flags & FLAGS_MIXED_CONTENT) ||
8206              (IS_BLANK_NODE(node)))))) {
8207         node = node->next;
8208     }
8209     return(node);
8210 }
8211
8212 /**
8213  * xmlRelaxNGNormalize:
8214  * @ctxt:  a schema validation context
8215  * @str:  the string to normalize
8216  *
8217  * Implements the  normalizeWhiteSpace( s ) function from
8218  * section 6.2.9 of the spec
8219  *
8220  * Returns the new string or NULL in case of error.
8221  */
8222 static xmlChar *
8223 xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt, const xmlChar *str) {
8224     xmlChar *ret, *p;
8225     const xmlChar *tmp;
8226     int len;
8227     
8228     if (str == NULL)
8229         return(NULL);
8230     tmp = str;
8231     while (*tmp != 0) tmp++;
8232     len = tmp - str;
8233
8234     ret = (xmlChar *) xmlMallocAtomic((len + 1) * sizeof(xmlChar));
8235     if (ret == NULL) {
8236         if (ctxt != NULL) {
8237             VALID_ERR(XML_RELAXNG_ERR_MEMORY);
8238         } else {
8239             xmlGenericError(xmlGenericErrorContext,
8240                 "xmlRelaxNGNormalize: out of memory\n");
8241         }
8242         return(NULL);
8243     }
8244     p = ret;
8245     while (IS_BLANK(*str)) str++;
8246     while (*str != 0) {
8247         if (IS_BLANK(*str)) {
8248             while (IS_BLANK(*str)) str++;
8249             if (*str == 0)
8250                 break;
8251             *p++ = ' ';
8252         } else 
8253             *p++ = *str++;
8254     }
8255     *p = 0;
8256     return(ret);
8257 }
8258
8259 /**
8260  * xmlRelaxNGValidateDatatype:
8261  * @ctxt:  a Relax-NG validation context
8262  * @value:  the string value
8263  * @type:  the datatype definition
8264  * @node:  the node
8265  *
8266  * Validate the given value against the dataype
8267  *
8268  * Returns 0 if the validation succeeded or an error code.
8269  */
8270 static int
8271 xmlRelaxNGValidateDatatype(xmlRelaxNGValidCtxtPtr ctxt, const xmlChar *value,
8272                            xmlRelaxNGDefinePtr define, xmlNodePtr node) {
8273     int ret, tmp;
8274     xmlRelaxNGTypeLibraryPtr lib;
8275     void *result = NULL;
8276     xmlRelaxNGDefinePtr cur;
8277
8278     if ((define == NULL) || (define->data == NULL)) {
8279         return(-1);
8280     }
8281     lib = (xmlRelaxNGTypeLibraryPtr) define->data;
8282     if (lib->check != NULL) {
8283         if ((define->attrs != NULL) &&
8284             (define->attrs->type == XML_RELAXNG_PARAM)) {
8285             ret = lib->check(lib->data, define->name, value, &result, node);
8286         } else {
8287             ret = lib->check(lib->data, define->name, value, NULL, node);
8288         }
8289     } else 
8290         ret = -1;
8291     if (ret < 0) {
8292         VALID_ERR2(XML_RELAXNG_ERR_TYPE, define->name);
8293         if ((result != NULL) && (lib != NULL) && (lib->freef != NULL))
8294             lib->freef(lib->data, result);
8295         return(-1);
8296     } else if (ret == 1) {
8297         ret = 0;
8298     } else if (ret == 2) {
8299         VALID_ERR2P(XML_RELAXNG_ERR_DUPID, value);
8300     } else {
8301         VALID_ERR3P(XML_RELAXNG_ERR_TYPEVAL, define->name, value);
8302         ret = -1;
8303     }
8304     cur = define->attrs;
8305     while ((ret == 0) && (cur != NULL) && (cur->type == XML_RELAXNG_PARAM)) {
8306         if (lib->facet != NULL) {
8307             tmp = lib->facet(lib->data, define->name, cur->name,
8308                              cur->value, value, result);
8309             if (tmp != 0)
8310                 ret = -1;
8311         }
8312         cur = cur->next;
8313     }
8314     if ((ret == 0) && (define->content != NULL)) {
8315         const xmlChar *oldvalue, *oldendvalue;
8316
8317         oldvalue = ctxt->state->value;
8318         oldendvalue = ctxt->state->endvalue;
8319         ctxt->state->value = (xmlChar *) value;
8320         ctxt->state->endvalue = NULL;
8321         ret = xmlRelaxNGValidateValue(ctxt, define->content);
8322         ctxt->state->value = (xmlChar *) oldvalue;
8323         ctxt->state->endvalue = (xmlChar *) oldendvalue;
8324     }
8325     if ((result != NULL) && (lib != NULL) && (lib->freef != NULL))
8326         lib->freef(lib->data, result);
8327     return(ret);
8328 }
8329
8330 /**
8331  * xmlRelaxNGNextValue:
8332  * @ctxt:  a Relax-NG validation context
8333  *
8334  * Skip to the next value when validating within a list
8335  *
8336  * Returns 0 if the operation succeeded or an error code.
8337  */
8338 static int
8339 xmlRelaxNGNextValue(xmlRelaxNGValidCtxtPtr ctxt) {
8340     xmlChar *cur;
8341
8342     cur = ctxt->state->value;
8343     if ((cur == NULL) || (ctxt->state->endvalue == NULL)) {
8344         ctxt->state->value = NULL;
8345         ctxt->state->endvalue = NULL;
8346         return(0);
8347     }
8348     while (*cur != 0) cur++;
8349     while ((cur != ctxt->state->endvalue) && (*cur == 0)) cur++;
8350     if (cur == ctxt->state->endvalue)
8351         ctxt->state->value = NULL;
8352     else
8353         ctxt->state->value = cur;
8354     return(0);
8355 }
8356
8357 /**
8358  * xmlRelaxNGValidateValueList:
8359  * @ctxt:  a Relax-NG validation context
8360  * @defines:  the list of definitions to verify
8361  *
8362  * Validate the given set of definitions for the current value
8363  *
8364  * Returns 0 if the validation succeeded or an error code.
8365  */
8366 static int
8367 xmlRelaxNGValidateValueList(xmlRelaxNGValidCtxtPtr ctxt, 
8368                         xmlRelaxNGDefinePtr defines) {
8369     int ret = 0;
8370
8371     while (defines != NULL) {
8372         ret = xmlRelaxNGValidateValue(ctxt, defines);
8373         if (ret != 0)
8374             break;
8375         defines = defines->next;
8376     }
8377     return(ret);
8378 }
8379
8380 /**
8381  * xmlRelaxNGValidateValue:
8382  * @ctxt:  a Relax-NG validation context
8383  * @define:  the definition to verify
8384  *
8385  * Validate the given definition for the current value
8386  *
8387  * Returns 0 if the validation succeeded or an error code.
8388  */
8389 static int
8390 xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt, 
8391                         xmlRelaxNGDefinePtr define) {
8392     int ret = 0, oldflags;
8393     xmlChar *value;
8394
8395     value = ctxt->state->value;
8396     switch (define->type) {
8397         case XML_RELAXNG_EMPTY: {
8398             if ((value != NULL) && (value[0] != 0)) {
8399                 int idx = 0;
8400
8401                 while (IS_BLANK(value[idx]))
8402                     idx++;
8403                 if (value[idx] != 0)
8404                     ret = -1;
8405             }
8406             break;
8407         }
8408         case XML_RELAXNG_TEXT:
8409             break;
8410         case XML_RELAXNG_VALUE: {
8411             if (!xmlStrEqual(value, define->value)) {
8412                 if (define->name != NULL) {
8413                     xmlRelaxNGTypeLibraryPtr lib;
8414                     
8415                     lib = (xmlRelaxNGTypeLibraryPtr) define->data;
8416                     if ((lib != NULL) && (lib->comp != NULL)) {
8417                         ret = lib->comp(lib->data, define->name,
8418                                         define->value, define->node,
8419                                         (void *) define->attrs,
8420                                         value, ctxt->state->node);
8421                     } else
8422                         ret = -1;
8423                     if (ret < 0) {
8424                         VALID_ERR2(XML_RELAXNG_ERR_TYPECMP, define->name);
8425                         return(-1);
8426                     } else if (ret == 1) {
8427                         ret = 0;
8428                     } else {
8429                         ret = -1;
8430                     }
8431                 } else {
8432                     xmlChar *nval, *nvalue;
8433
8434                     /*
8435                      * TODO: trivial optimizations are possible by
8436                      * computing at compile-time
8437                      */
8438                     nval = xmlRelaxNGNormalize(ctxt, define->value);
8439                     nvalue = xmlRelaxNGNormalize(ctxt, value);
8440
8441                     if ((nval == NULL) || (nvalue == NULL) ||
8442                         (!xmlStrEqual(nval, nvalue)))
8443                         ret = -1;
8444                     if (nval != NULL)
8445                         xmlFree(nval);
8446                     if (nvalue != NULL)
8447                         xmlFree(nvalue);
8448                 }
8449             }
8450             if (ret == 0)
8451                 xmlRelaxNGNextValue(ctxt);
8452             break;
8453         }
8454         case XML_RELAXNG_DATATYPE: {
8455             ret = xmlRelaxNGValidateDatatype(ctxt, value, define,
8456                                              ctxt->state->seq);
8457             if (ret == 0)
8458                 xmlRelaxNGNextValue(ctxt);
8459             
8460             break;
8461         }
8462         case XML_RELAXNG_CHOICE: {
8463             xmlRelaxNGDefinePtr list = define->content;
8464             xmlChar *oldvalue;
8465
8466             oldflags = ctxt->flags;
8467             ctxt->flags |= FLAGS_IGNORABLE;
8468
8469             oldvalue = ctxt->state->value;
8470             while (list != NULL) {
8471                 ret = xmlRelaxNGValidateValue(ctxt, list);
8472                 if (ret == 0) {
8473                     break;
8474                 }
8475                 ctxt->state->value = oldvalue;
8476                 list = list->next;
8477             }
8478             ctxt->flags = oldflags;
8479             if (ret != 0) {
8480                 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8481                     xmlRelaxNGDumpValidError(ctxt);
8482             } else {
8483                 if (ctxt->errNr > 0) xmlRelaxNGPopErrors(ctxt, 0);
8484             }
8485             if (ret == 0)
8486                 xmlRelaxNGNextValue(ctxt);
8487             break;
8488         }
8489         case XML_RELAXNG_LIST: {
8490             xmlRelaxNGDefinePtr list = define->content;
8491             xmlChar *oldvalue, *oldend, *val, *cur;
8492 #ifdef DEBUG_LIST
8493             int nb_values = 0;
8494 #endif
8495
8496             oldvalue = ctxt->state->value;
8497             oldend = ctxt->state->endvalue;
8498
8499             val = xmlStrdup(oldvalue);
8500             if (val == NULL) {
8501                 val = xmlStrdup(BAD_CAST "");
8502             }
8503             if (val == NULL) {
8504                 VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
8505                 return(-1);
8506             }
8507             cur = val;
8508             while (*cur != 0) {
8509                 if (IS_BLANK(*cur)) {
8510                     *cur = 0;
8511                     cur++;
8512 #ifdef DEBUG_LIST
8513                     nb_values++;
8514 #endif
8515                     while (IS_BLANK(*cur))
8516                         *cur++ = 0;
8517                 } else
8518                     cur++;
8519             }
8520 #ifdef DEBUG_LIST
8521             xmlGenericError(xmlGenericErrorContext,
8522                     "list value: '%s' found %d items\n", oldvalue, nb_values);
8523             nb_values = 0;
8524 #endif 
8525             ctxt->state->endvalue = cur;
8526             cur = val;
8527             while ((*cur == 0) && (cur != ctxt->state->endvalue)) cur++;
8528
8529             ctxt->state->value = cur;
8530
8531             while (list != NULL) {
8532                 if (ctxt->state->value == ctxt->state->endvalue)
8533                     ctxt->state->value = NULL;
8534                 ret = xmlRelaxNGValidateValue(ctxt, list);
8535                 if (ret != 0) {
8536 #ifdef DEBUG_LIST
8537                     xmlGenericError(xmlGenericErrorContext,
8538                         "Failed to validate value: '%s' with %d rule\n",
8539                                     ctxt->state->value, nb_values);
8540 #endif
8541                     break;
8542                 }
8543 #ifdef DEBUG_LIST
8544                 nb_values++;
8545 #endif
8546                 list = list->next;
8547             }
8548
8549             if ((ret == 0) && (ctxt->state->value != NULL) &&
8550                 (ctxt->state->value != ctxt->state->endvalue)) {
8551                 VALID_ERR2(XML_RELAXNG_ERR_LISTEXTRA, ctxt->state->value);
8552                 ret = -1;
8553             }
8554             xmlFree(val);
8555             ctxt->state->value = oldvalue;
8556             ctxt->state->endvalue = oldend;
8557             break;
8558         }
8559         case XML_RELAXNG_ONEORMORE:
8560             ret = xmlRelaxNGValidateValueList(ctxt, define->content);
8561             if (ret != 0) {
8562                 break;
8563             }
8564             /* no break on purpose */
8565         case XML_RELAXNG_ZEROORMORE: {
8566             xmlChar *cur, *temp;
8567
8568             oldflags = ctxt->flags;
8569             ctxt->flags |= FLAGS_IGNORABLE;
8570             cur = ctxt->state->value;
8571             temp = NULL;
8572             while ((cur != NULL) && (cur != ctxt->state->endvalue) &&
8573                    (temp != cur)) {
8574                 temp = cur;
8575                 ret = xmlRelaxNGValidateValueList(ctxt, define->content);
8576                 if (ret != 0) {
8577                     ctxt->state->value = temp;
8578                     ret = 0;
8579                     break;
8580                 }
8581                 cur = ctxt->state->value;
8582             }
8583             ctxt->flags = oldflags;
8584             if (ret != 0) {
8585                 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8586                     xmlRelaxNGDumpValidError(ctxt);
8587             } else {
8588                 if (ctxt->errNr > 0) xmlRelaxNGPopErrors(ctxt, 0);
8589             }
8590             break;
8591         }
8592         case XML_RELAXNG_EXCEPT: {
8593             xmlRelaxNGDefinePtr list;
8594
8595             list = define->content;
8596             while (list != NULL) {
8597                 ret = xmlRelaxNGValidateValue(ctxt, list);
8598                 if (ret == 0) {
8599                     ret = -1;
8600                     break;
8601                 } else 
8602                     ret = 0;
8603                 list = list->next;
8604             }
8605             break;
8606         }
8607         case XML_RELAXNG_DEF:
8608         case XML_RELAXNG_GROUP: {
8609             xmlRelaxNGDefinePtr list;
8610
8611             list = define->content;
8612             while (list != NULL) {
8613                 ret = xmlRelaxNGValidateValue(ctxt, list);
8614                 if (ret != 0) {
8615                     ret = -1;
8616                     break;
8617                 } else 
8618                     ret = 0;
8619                 list = list->next;
8620             }
8621             break;
8622         }
8623         case XML_RELAXNG_REF:
8624         case XML_RELAXNG_PARENTREF:
8625             ret = xmlRelaxNGValidateValue(ctxt, define->content);
8626             break;
8627         default:
8628             TODO
8629             ret = -1;
8630     }
8631     return(ret);
8632 }
8633
8634 /**
8635  * xmlRelaxNGValidateValueContent:
8636  * @ctxt:  a Relax-NG validation context
8637  * @defines:  the list of definitions to verify
8638  *
8639  * Validate the given definitions for the current value
8640  *
8641  * Returns 0 if the validation succeeded or an error code.
8642  */
8643 static int
8644 xmlRelaxNGValidateValueContent(xmlRelaxNGValidCtxtPtr ctxt, 
8645                                xmlRelaxNGDefinePtr defines) {
8646     int ret = 0;
8647
8648     while (defines != NULL) {
8649         ret = xmlRelaxNGValidateValue(ctxt, defines);
8650         if (ret != 0)
8651             break;
8652         defines = defines->next;
8653     }
8654     return(ret);
8655 }
8656
8657 /**
8658  * xmlRelaxNGAttributeMatch:
8659  * @ctxt:  a Relax-NG validation context
8660  * @define:  the definition to check
8661  * @prop:  the attribute
8662  *
8663  * Check if the attribute matches the definition nameClass
8664  *
8665  * Returns 1 if the attribute matches, 0 if no, or -1 in case of error
8666  */
8667 static int
8668 xmlRelaxNGAttributeMatch(xmlRelaxNGValidCtxtPtr ctxt, 
8669                          xmlRelaxNGDefinePtr define,
8670                          xmlAttrPtr prop) {
8671     int ret;
8672
8673     if (define->name != NULL) {
8674         if (!xmlStrEqual(define->name, prop->name))
8675             return(0);
8676     }
8677     if (define->ns != NULL) {
8678         if (define->ns[0] == 0) {
8679             if (prop->ns != NULL)
8680                 return(0);
8681         } else {
8682             if ((prop->ns == NULL) ||
8683                 (!xmlStrEqual(define->ns, prop->ns->href)))
8684                 return(0);
8685         }
8686     }
8687     if (define->nameClass == NULL)
8688         return(1);
8689     define = define->nameClass;
8690     if (define->type == XML_RELAXNG_EXCEPT) {
8691         xmlRelaxNGDefinePtr list;
8692
8693         list = define->content;
8694         while (list != NULL) {
8695             ret = xmlRelaxNGAttributeMatch(ctxt, list, prop);
8696             if (ret == 1)
8697                 return(0);
8698             if (ret < 0)
8699                 return(ret);
8700             list = list->next;
8701         }
8702     } else {
8703         TODO
8704     }
8705     return(1);
8706 }
8707
8708 /**
8709  * xmlRelaxNGValidateAttribute:
8710  * @ctxt:  a Relax-NG validation context
8711  * @define:  the definition to verify
8712  *
8713  * Validate the given attribute definition for that node
8714  *
8715  * Returns 0 if the validation succeeded or an error code.
8716  */
8717 static int
8718 xmlRelaxNGValidateAttribute(xmlRelaxNGValidCtxtPtr ctxt, 
8719                             xmlRelaxNGDefinePtr define) {
8720     int ret = 0, i;
8721     xmlChar *value, *oldvalue;
8722     xmlAttrPtr prop = NULL, tmp;
8723     xmlNodePtr oldseq;
8724
8725     if (ctxt->state->nbAttrLeft <= 0)
8726         return(-1);
8727     if (define->name != NULL) {
8728         for (i = 0;i < ctxt->state->nbAttrs;i++) {
8729             tmp = ctxt->state->attrs[i];
8730             if ((tmp != NULL) && (xmlStrEqual(define->name, tmp->name))) {
8731                 if ((((define->ns == NULL) || (define->ns[0] == 0)) &&
8732                      (tmp->ns == NULL)) ||
8733                     ((tmp->ns != NULL) &&
8734                      (xmlStrEqual(define->ns, tmp->ns->href)))) {
8735                     prop = tmp;
8736                     break;
8737                 }
8738             }
8739         }
8740         if (prop != NULL) {
8741             value = xmlNodeListGetString(prop->doc, prop->children, 1);
8742             oldvalue = ctxt->state->value;
8743             oldseq = ctxt->state->seq;
8744             ctxt->state->seq = (xmlNodePtr) prop;
8745             ctxt->state->value = value;
8746             ctxt->state->endvalue = NULL;
8747             ret = xmlRelaxNGValidateValueContent(ctxt, define->content);
8748             if (ctxt->state->value != NULL)
8749                 value = ctxt->state->value;
8750             if (value != NULL)
8751                 xmlFree(value);
8752             ctxt->state->value = oldvalue;
8753             ctxt->state->seq = oldseq;
8754             if (ret == 0) {
8755                 /*
8756                  * flag the attribute as processed
8757                  */
8758                 ctxt->state->attrs[i] = NULL;
8759                 ctxt->state->nbAttrLeft--;
8760             }
8761         } else {
8762             ret = -1;
8763         }
8764 #ifdef DEBUG
8765         xmlGenericError(xmlGenericErrorContext,
8766                     "xmlRelaxNGValidateAttribute(%s): %d\n", define->name, ret);
8767 #endif
8768     } else {
8769         for (i = 0;i < ctxt->state->nbAttrs;i++) {
8770             tmp = ctxt->state->attrs[i];
8771             if ((tmp != NULL) &&
8772                 (xmlRelaxNGAttributeMatch(ctxt, define, tmp) == 1)) {
8773                 prop = tmp;
8774                 break;
8775             }
8776         }
8777         if (prop != NULL) {
8778             value = xmlNodeListGetString(prop->doc, prop->children, 1);
8779             oldvalue = ctxt->state->value;
8780             oldseq = ctxt->state->seq;
8781             ctxt->state->seq = (xmlNodePtr) prop;
8782             ctxt->state->value = value;
8783             ret = xmlRelaxNGValidateValueContent(ctxt, define->content);
8784             if (ctxt->state->value != NULL)
8785                 value = ctxt->state->value;
8786             if (value != NULL)
8787                 xmlFree(value);
8788             ctxt->state->value = oldvalue;
8789             ctxt->state->seq = oldseq;
8790             if (ret == 0) {
8791                 /*
8792                  * flag the attribute as processed
8793                  */
8794                 ctxt->state->attrs[i] = NULL;
8795                 ctxt->state->nbAttrLeft--;
8796             }
8797         } else {
8798             ret = -1;
8799         }
8800 #ifdef DEBUG
8801         if (define->ns != NULL) {
8802             xmlGenericError(xmlGenericErrorContext,
8803                         "xmlRelaxNGValidateAttribute(nsName ns = %s): %d\n",
8804                             define->ns, ret);
8805         } else {
8806             xmlGenericError(xmlGenericErrorContext,
8807                         "xmlRelaxNGValidateAttribute(anyName): %d\n",
8808                             ret);
8809         }
8810 #endif
8811     }
8812     
8813     return(ret);
8814 }
8815
8816 /**
8817  * xmlRelaxNGValidateAttributeList:
8818  * @ctxt:  a Relax-NG validation context
8819  * @define:  the list of definition to verify
8820  *
8821  * Validate the given node against the list of attribute definitions
8822  *
8823  * Returns 0 if the validation succeeded or an error code.
8824  */
8825 static int
8826 xmlRelaxNGValidateAttributeList(xmlRelaxNGValidCtxtPtr ctxt, 
8827                                 xmlRelaxNGDefinePtr defines) {
8828     int ret = 0, res;
8829     int needmore = 0;
8830     xmlRelaxNGDefinePtr cur;
8831
8832     cur = defines;
8833     while (cur != NULL) {
8834         if (cur->type == XML_RELAXNG_ATTRIBUTE) {
8835             if (xmlRelaxNGValidateAttribute(ctxt, cur) != 0)
8836                 ret = -1;
8837         } else
8838             needmore = 1;
8839         cur = cur->next;
8840     }
8841     if (!needmore)
8842         return(ret);
8843     cur = defines;
8844     while (cur != NULL) {
8845         if (cur->type != XML_RELAXNG_ATTRIBUTE) {
8846             if ((ctxt->state != NULL) || (ctxt->states != NULL)) {
8847                 res = xmlRelaxNGValidateDefinition(ctxt, cur);
8848                 if (res < 0)
8849                     ret = -1;
8850             } else {
8851                 VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
8852                 return(-1);
8853             }
8854             if (res == -1) /* continues on -2 */
8855                 break;
8856         }
8857         cur = cur->next;
8858     }
8859       
8860     return(ret);
8861 }
8862
8863 /**
8864  * xmlRelaxNGNodeMatchesList:
8865  * @node:  the node
8866  * @list:  a NULL terminated array of definitions
8867  *
8868  * Check if a node can be matched by one of the definitions
8869  *
8870  * Returns 1 if matches 0 otherwise
8871  */
8872 static int
8873 xmlRelaxNGNodeMatchesList(xmlNodePtr node, xmlRelaxNGDefinePtr *list) {
8874     xmlRelaxNGDefinePtr cur;
8875     int i = 0, tmp;
8876
8877     if ((node == NULL) || (list == NULL))
8878         return(0);
8879
8880     cur = list[i++];
8881     while (cur != NULL) {
8882         if ((node->type == XML_ELEMENT_NODE) &&
8883             (cur->type == XML_RELAXNG_ELEMENT)) {
8884             tmp = xmlRelaxNGElementMatch(NULL, cur, node);
8885             if (tmp == 1)
8886                 return(1);
8887         } else if (((node->type == XML_TEXT_NODE) ||
8888                     (node->type == XML_CDATA_SECTION_NODE)) &&
8889                    (cur->type == XML_RELAXNG_TEXT)) {
8890             return(1);
8891         }
8892         cur = list[i++];
8893     }
8894     return(0);
8895 }
8896
8897 /**
8898  * xmlRelaxNGValidateInterleave:
8899  * @ctxt:  a Relax-NG validation context
8900  * @define:  the definition to verify
8901  *
8902  * Validate an interleave definition for a node.
8903  *
8904  * Returns 0 if the validation succeeded or an error code.
8905  */
8906 static int
8907 xmlRelaxNGValidateInterleave(xmlRelaxNGValidCtxtPtr ctxt, 
8908                              xmlRelaxNGDefinePtr define) {
8909     int ret = 0, i, nbgroups;
8910     int errNr = ctxt->errNr;
8911     int oldflags;
8912
8913     xmlRelaxNGValidStatePtr oldstate;
8914     xmlRelaxNGPartitionPtr partitions;
8915     xmlRelaxNGInterleaveGroupPtr group = NULL;
8916     xmlNodePtr cur, start, last = NULL, lastchg = NULL, lastelem;
8917     xmlNodePtr *list = NULL, *lasts = NULL;
8918
8919     if (define->data != NULL) {
8920         partitions = (xmlRelaxNGPartitionPtr) define->data;
8921         nbgroups = partitions->nbgroups;
8922     } else {
8923         VALID_ERR(XML_RELAXNG_ERR_INTERNODATA);
8924         return(-1);
8925     }
8926     /*
8927      * Optimizations for MIXED
8928      */
8929     oldflags = ctxt->flags;
8930     if (define->dflags & IS_MIXED) {
8931         ctxt->flags |= FLAGS_MIXED_CONTENT;
8932         if (nbgroups == 2) {
8933             /*
8934              * this is a pure <mixed> case
8935              */
8936             if (ctxt->state != NULL)
8937                 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt,
8938                                                          ctxt->state->seq);
8939             if (partitions->groups[0]->rule->type == XML_RELAXNG_TEXT)
8940                 ret = xmlRelaxNGValidateDefinition(ctxt, 
8941                                    partitions->groups[1]->rule);
8942             else
8943                 ret = xmlRelaxNGValidateDefinition(ctxt, 
8944                                    partitions->groups[0]->rule);
8945             if (ret == 0) {
8946                 if (ctxt->state != NULL)
8947                     ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt,
8948                                                          ctxt->state->seq);
8949             }
8950             ctxt->flags = oldflags;
8951             return(ret);
8952         }
8953     }
8954
8955     /*
8956      * Build arrays to store the first and last node of the chain
8957      * pertaining to each group
8958      */
8959     list = (xmlNodePtr *) xmlMalloc(nbgroups * sizeof(xmlNodePtr));
8960     if (list == NULL) {
8961         VALID_ERR(XML_RELAXNG_ERR_MEMORY);
8962         return(-1);
8963     }
8964     memset(list, 0, nbgroups * sizeof(xmlNodePtr));
8965     lasts = (xmlNodePtr *) xmlMalloc(nbgroups * sizeof(xmlNodePtr));
8966     if (lasts == NULL) {
8967         VALID_ERR(XML_RELAXNG_ERR_MEMORY);
8968         return(-1);
8969     }
8970     memset(lasts, 0, nbgroups * sizeof(xmlNodePtr));
8971
8972     /*
8973      * Walk the sequence of children finding the right group and
8974      * sorting them in sequences.
8975      */
8976     cur = ctxt->state->seq;
8977     cur = xmlRelaxNGSkipIgnored(ctxt, cur);
8978     start = cur;
8979     while (cur != NULL) {
8980         ctxt->state->seq = cur;
8981         if ((partitions->triage != NULL) &&
8982             (partitions->flags & IS_DETERMINIST)) {
8983             void *tmp = NULL;
8984
8985             if ((cur->type == XML_TEXT_NODE) ||
8986                 (cur->type == XML_CDATA_SECTION_NODE)) {
8987                 tmp = xmlHashLookup2(partitions->triage, BAD_CAST "#text",
8988                                      NULL);
8989             } else if (cur->type == XML_ELEMENT_NODE) {
8990                 if (cur->ns != NULL) {
8991                     tmp = xmlHashLookup2(partitions->triage, cur->name,
8992                                          cur->ns->href);
8993                     if (tmp == NULL)
8994                         tmp = xmlHashLookup2(partitions->triage,
8995                                          BAD_CAST "#any", cur->ns->href);
8996                 } else
8997                     tmp = xmlHashLookup2(partitions->triage, cur->name, NULL);
8998                 if (tmp == NULL)
8999                     tmp = xmlHashLookup2(partitions->triage, BAD_CAST "#any",
9000                                          NULL);
9001             }
9002
9003             if (tmp == NULL) {
9004                 i = nbgroups;
9005             } else {
9006                 i = ((long) tmp) - 1;
9007                 if (partitions->flags & IS_NEEDCHECK) {
9008                     group = partitions->groups[i];
9009                     if (!xmlRelaxNGNodeMatchesList(cur, group->defs))
9010                         i = nbgroups;
9011                 }
9012             }
9013         } else {
9014             for (i = 0;i < nbgroups;i++) {
9015                 group = partitions->groups[i];
9016                 if (group == NULL)
9017                     continue;
9018                 if (xmlRelaxNGNodeMatchesList(cur, group->defs))
9019                     break;
9020             }
9021         }
9022         /*
9023          * We break as soon as an element not matched is found
9024          */
9025         if (i >= nbgroups) {
9026             break;
9027         }
9028         if (lasts[i] != NULL) {
9029             lasts[i]->next = cur;
9030             lasts[i] = cur;
9031         } else {
9032             list[i] = cur;
9033             lasts[i] = cur;
9034         }
9035         if (cur->next != NULL)
9036             lastchg = cur->next;
9037         else
9038             lastchg = cur;
9039         cur = xmlRelaxNGSkipIgnored(ctxt, cur->next);
9040     }
9041     if (ret != 0) {
9042         VALID_ERR(XML_RELAXNG_ERR_INTERSEQ);
9043         ret = -1;
9044         goto done;
9045     }
9046     lastelem = cur;
9047     oldstate = ctxt->state;
9048     for (i = 0;i < nbgroups;i++) {
9049         ctxt->state = xmlRelaxNGCopyValidState(ctxt, oldstate);
9050         group = partitions->groups[i];
9051         if (lasts[i] != NULL) {
9052             last = lasts[i]->next;
9053             lasts[i]->next = NULL;
9054         }
9055         ctxt->state->seq = list[i];
9056         ret = xmlRelaxNGValidateDefinition(ctxt, group->rule);
9057         if (ret != 0)
9058             break;
9059         if (ctxt->state != NULL) {
9060             cur = ctxt->state->seq;
9061             cur = xmlRelaxNGSkipIgnored(ctxt, cur);
9062             xmlRelaxNGFreeValidState(ctxt,oldstate);
9063             oldstate = ctxt->state;
9064             ctxt->state = NULL;
9065             if (cur != NULL) {
9066                 VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA, cur->name);
9067                 ret = -1;
9068                 ctxt->state = oldstate;
9069                 goto done;
9070             }
9071         } else if (ctxt->states != NULL) {
9072             int j;
9073             int found = 0;
9074
9075             for (j = 0;j < ctxt->states->nbState;j++) {
9076                 cur = ctxt->states->tabState[j]->seq;
9077                 cur = xmlRelaxNGSkipIgnored(ctxt, cur);
9078                 if (cur == NULL) {
9079                     found = 1;
9080                     break;
9081                 }
9082             }
9083             if (ctxt->states->nbState > 0) {
9084                 xmlRelaxNGFreeValidState(ctxt,oldstate);
9085                 oldstate = ctxt->states->tabState[ctxt->states->nbState - 1];
9086             }
9087             for (j = 0;j < ctxt->states->nbState - 1;j++) {
9088                 xmlRelaxNGFreeValidState(ctxt,ctxt->states->tabState[j]);
9089             }
9090             xmlRelaxNGFreeStates(ctxt, ctxt->states);
9091             ctxt->states = NULL;
9092             if (found == 0) {
9093                 VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA, cur->name);
9094                 ret = -1;
9095                 ctxt->state = oldstate;
9096                 goto done;
9097             }
9098         } else {
9099             ret = -1;
9100             break;
9101         }
9102         if (lasts[i] != NULL) {
9103             lasts[i]->next = last;
9104         }
9105     }
9106     if (ctxt->state != NULL)
9107         xmlRelaxNGFreeValidState(ctxt,ctxt->state);
9108     ctxt->state = oldstate;
9109     ctxt->state->seq = lastelem;
9110     if (ret != 0) {
9111         VALID_ERR(XML_RELAXNG_ERR_INTERSEQ);
9112         ret = -1;
9113         goto done;
9114     }
9115
9116 done:
9117     ctxt->flags = oldflags;
9118     /*
9119      * builds the next links chain from the prev one
9120      */
9121     cur = lastchg;
9122     while (cur != NULL) {
9123         if ((cur == start) || (cur->prev == NULL))
9124             break;
9125         cur->prev->next = cur;
9126         cur = cur->prev;
9127     }
9128     if (ret == 0) {
9129         if (ctxt->errNr > errNr) xmlRelaxNGPopErrors(ctxt, errNr);
9130     }
9131
9132     xmlFree(list);
9133     xmlFree(lasts);
9134     return(ret);
9135 }
9136
9137 /**
9138  * xmlRelaxNGValidateDefinitionList:
9139  * @ctxt:  a Relax-NG validation context
9140  * @define:  the list of definition to verify
9141  *
9142  * Validate the given node content against the (list) of definitions
9143  *
9144  * Returns 0 if the validation succeeded or an error code.
9145  */
9146 static int
9147 xmlRelaxNGValidateDefinitionList(xmlRelaxNGValidCtxtPtr ctxt, 
9148                           xmlRelaxNGDefinePtr defines) {
9149     int ret = 0, res;
9150
9151
9152     if (defines == NULL) {
9153         VALID_ERR2(XML_RELAXNG_ERR_INTERNAL, BAD_CAST "NULL definition list");
9154         return(-1);
9155     }
9156     while (defines != NULL) {
9157         if ((ctxt->state != NULL) || (ctxt->states != NULL)) {
9158             res = xmlRelaxNGValidateDefinition(ctxt, defines);
9159             if (res < 0)
9160                 ret = -1;
9161         } else {
9162             VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
9163             return(-1);
9164         }
9165         if (res == -1) /* continues on -2 */
9166             break;
9167         defines = defines->next;
9168     }
9169
9170     return(ret);
9171 }
9172
9173 /**
9174  * xmlRelaxNGElementMatch:
9175  * @ctxt:  a Relax-NG validation context
9176  * @define:  the definition to check
9177  * @elem:  the element
9178  *
9179  * Check if the element matches the definition nameClass
9180  *
9181  * Returns 1 if the element matches, 0 if no, or -1 in case of error
9182  */
9183 static int
9184 xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt, 
9185                        xmlRelaxNGDefinePtr define,
9186                        xmlNodePtr elem) {
9187     int ret = 0, oldflags = 0;
9188
9189     if (define->name != NULL) {
9190         if (!xmlStrEqual(elem->name, define->name)) {
9191             VALID_ERR3(XML_RELAXNG_ERR_ELEMNAME, define->name, elem->name);
9192             return(0);
9193         }
9194     }
9195     if ((define->ns != NULL) && (define->ns[0] != 0)) {
9196         if (elem->ns == NULL) {
9197             VALID_ERR2(XML_RELAXNG_ERR_ELEMNONS,
9198                         elem->name);
9199             return(0);
9200         } else if (!xmlStrEqual(elem->ns->href, define->ns)) {
9201             VALID_ERR3(XML_RELAXNG_ERR_ELEMWRONGNS,
9202                         elem->name, define->ns);
9203             return(0);
9204         }
9205     } else if ((elem->ns != NULL) && (define->ns != NULL) &&
9206                (define->name == NULL)) {
9207         VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS,
9208                      elem->name);
9209         return(0);
9210     } else if ((elem->ns != NULL) && (define->name != NULL)) {
9211         VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS,
9212                     define->name);
9213         return(0);
9214     }
9215
9216     if (define->nameClass == NULL)
9217         return(1);
9218
9219     define = define->nameClass;
9220     if (define->type == XML_RELAXNG_EXCEPT) {
9221         xmlRelaxNGDefinePtr list;
9222         if (ctxt != NULL) {
9223             oldflags = ctxt->flags;
9224             ctxt->flags |= FLAGS_IGNORABLE;
9225         }
9226
9227         list = define->content;
9228         while (list != NULL) {
9229             ret = xmlRelaxNGElementMatch(ctxt, list, elem);
9230             if (ret == 1) {
9231                 if (ctxt != NULL)
9232                     ctxt->flags = oldflags;
9233                 return(0);
9234             }
9235             if (ret < 0) {
9236                 if (ctxt != NULL)
9237                     ctxt->flags = oldflags;
9238                 return(ret);
9239             }
9240             list = list->next;
9241         }
9242         ret = 1;
9243         if (ctxt != NULL) {
9244             ctxt->flags = oldflags;
9245         }
9246     } else if (define->type == XML_RELAXNG_CHOICE) {
9247         xmlRelaxNGDefinePtr list;
9248
9249         if (ctxt != NULL) {
9250             oldflags = ctxt->flags;
9251             ctxt->flags |= FLAGS_IGNORABLE;
9252         }
9253
9254         list = define->nameClass;
9255         while (list != NULL) {
9256             ret = xmlRelaxNGElementMatch(ctxt, list, elem);
9257             if (ret == 1) {
9258                 if (ctxt != NULL)
9259                     ctxt->flags = oldflags;
9260                 return(1);
9261             }
9262             if (ret < 0) {
9263                 if (ctxt != NULL)
9264                     ctxt->flags = oldflags;
9265                 return(ret);
9266             }
9267             list = list->next;
9268         }
9269         if (ctxt != NULL) {
9270             if (ret != 0) {
9271                 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9272                     xmlRelaxNGDumpValidError(ctxt);
9273             } else {
9274                 if (ctxt->errNr > 0) xmlRelaxNGPopErrors(ctxt, 0);
9275             }
9276         }
9277         ret = 0;
9278         if (ctxt != NULL) {
9279             ctxt->flags = oldflags;
9280         }
9281     } else {
9282         TODO
9283         ret = -1;
9284     }
9285     return(ret);
9286 }
9287
9288 /**
9289  * xmlRelaxNGValidateElementEnd:
9290  * @ctxt:  a Relax-NG validation context
9291  *
9292  * Validate the end of the element, implements check that
9293  * there is nothing left not consumed in the element content
9294  * or in the attribute list.
9295  *
9296  * Returns 0 if the validation succeeded or an error code.
9297  */
9298 static int
9299 xmlRelaxNGValidateElementEnd(xmlRelaxNGValidCtxtPtr ctxt) {
9300     int ret = 0, i;
9301     xmlRelaxNGValidStatePtr state;
9302
9303     state = ctxt->state;
9304     if (state->seq != NULL) {
9305         state->seq = xmlRelaxNGSkipIgnored(ctxt, state->seq);
9306         if (state->seq != NULL) {
9307             VALID_ERR3(XML_RELAXNG_ERR_EXTRACONTENT,
9308                 state->node->name, state->seq->name);
9309             ret = -1;
9310         }
9311     }
9312     for (i = 0;i < state->nbAttrs;i++) {
9313         if (state->attrs[i] != NULL) {
9314             VALID_ERR3(XML_RELAXNG_ERR_INVALIDATTR,
9315                        state->attrs[i]->name, state->node->name);
9316             ret = -1;
9317         }
9318     }
9319     return(ret);
9320 }
9321
9322 /**
9323  * xmlRelaxNGValidateState:
9324  * @ctxt:  a Relax-NG validation context
9325  * @define:  the definition to verify
9326  *
9327  * Validate the current state against the definition
9328  *
9329  * Returns 0 if the validation succeeded or an error code.
9330  */
9331 static int
9332 xmlRelaxNGValidateState(xmlRelaxNGValidCtxtPtr ctxt,
9333                         xmlRelaxNGDefinePtr define)
9334 {
9335     xmlNodePtr node;
9336     int ret = 0, i, tmp, oldflags, errNr;
9337     xmlRelaxNGValidStatePtr oldstate = NULL, state;
9338
9339     if (define == NULL) {
9340         VALID_ERR(XML_RELAXNG_ERR_NODEFINE);
9341         return (-1);
9342     }
9343
9344     if (ctxt->state != NULL) {
9345         node = ctxt->state->seq;
9346     } else {
9347         node = NULL;
9348     }
9349 #ifdef DEBUG
9350     for (i = 0; i < ctxt->depth; i++)
9351         xmlGenericError(xmlGenericErrorContext, " ");
9352     xmlGenericError(xmlGenericErrorContext,
9353                     "Start validating %s ", xmlRelaxNGDefName(define));
9354     if (define->name != NULL)
9355         xmlGenericError(xmlGenericErrorContext, "%s ", define->name);
9356     if ((node != NULL) && (node->name != NULL))
9357         xmlGenericError(xmlGenericErrorContext, "on %s\n", node->name);
9358     else
9359         xmlGenericError(xmlGenericErrorContext, "\n");
9360 #endif
9361     ctxt->depth++;
9362     switch (define->type) {
9363         case XML_RELAXNG_EMPTY:
9364             node = xmlRelaxNGSkipIgnored(ctxt, node);
9365             ret = 0;
9366             break;
9367         case XML_RELAXNG_NOT_ALLOWED:
9368             ret = -1;
9369             break;
9370         case XML_RELAXNG_TEXT:
9371             while ((node != NULL) &&
9372                    ((node->type == XML_TEXT_NODE) ||
9373                     (node->type == XML_COMMENT_NODE) ||
9374                     (node->type == XML_PI_NODE) ||
9375                     (node->type == XML_CDATA_SECTION_NODE)))
9376                 node = node->next;
9377             ctxt->state->seq = node;
9378             break;
9379         case XML_RELAXNG_ELEMENT:
9380             errNr = ctxt->errNr;
9381             node = xmlRelaxNGSkipIgnored(ctxt, node);
9382             if (node == NULL) {
9383                 VALID_ERR2(XML_RELAXNG_ERR_NOELEM, define->name);
9384                 ret = -1;
9385                 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9386                     xmlRelaxNGDumpValidError(ctxt);
9387                 break;
9388             }
9389             if (node->type != XML_ELEMENT_NODE) {
9390                 VALID_ERR(XML_RELAXNG_ERR_NOTELEM);
9391                 ret = -1;
9392                 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9393                     xmlRelaxNGDumpValidError(ctxt);
9394                 break;
9395             }
9396             /*
9397              * This node was already validated successfully against
9398              * this definition.
9399              */
9400             if (node->_private == define) {
9401                 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt, node->next);
9402                 if (ctxt->errNr > errNr)
9403                     xmlRelaxNGPopErrors(ctxt, errNr);
9404                 if (ctxt->errNr != 0) {
9405                     while ((ctxt->err != NULL) &&
9406                            (((ctxt->err->err == XML_RELAXNG_ERR_ELEMNAME)
9407                              && (xmlStrEqual(ctxt->err->arg2, node->name)))
9408                             ||
9409                             ((ctxt->err->err ==
9410                               XML_RELAXNG_ERR_ELEMEXTRANS)
9411                              && (xmlStrEqual(ctxt->err->arg1, node->name)))
9412                             || (ctxt->err->err == XML_RELAXNG_ERR_NOELEM)
9413                             || (ctxt->err->err ==
9414                                 XML_RELAXNG_ERR_NOTELEM)))
9415                         xmlRelaxNGValidErrorPop(ctxt);
9416                 }
9417                 break;
9418             }
9419
9420             ret = xmlRelaxNGElementMatch(ctxt, define, node);
9421             if (ret <= 0) {
9422                 ret = -1;
9423                 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9424                     xmlRelaxNGDumpValidError(ctxt);
9425                 break;
9426             }
9427             ret = 0;
9428             if (ctxt->errNr != 0) {
9429                 if (ctxt->errNr > errNr)
9430                     xmlRelaxNGPopErrors(ctxt, errNr);
9431                 while ((ctxt->err != NULL) &&
9432                        (((ctxt->err->err == XML_RELAXNG_ERR_ELEMNAME) &&
9433                          (xmlStrEqual(ctxt->err->arg2, node->name))) ||
9434                         ((ctxt->err->err == XML_RELAXNG_ERR_ELEMEXTRANS) &&
9435                          (xmlStrEqual(ctxt->err->arg1, node->name))) ||
9436                         (ctxt->err->err == XML_RELAXNG_ERR_NOELEM) ||
9437                         (ctxt->err->err == XML_RELAXNG_ERR_NOTELEM)))
9438                     xmlRelaxNGValidErrorPop(ctxt);
9439             }
9440             errNr = ctxt->errNr;
9441
9442             oldflags = ctxt->flags;
9443             if (ctxt->flags & FLAGS_MIXED_CONTENT) {
9444                 ctxt->flags -= FLAGS_MIXED_CONTENT;
9445             }
9446             state = xmlRelaxNGNewValidState(ctxt, node);
9447             if (state == NULL) {
9448                 ret = -1;
9449                 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9450                     xmlRelaxNGDumpValidError(ctxt);
9451                 break;
9452             }
9453
9454             oldstate = ctxt->state;
9455             ctxt->state = state;
9456             if (define->attrs != NULL) {
9457                 tmp = xmlRelaxNGValidateAttributeList(ctxt, define->attrs);
9458                 if (tmp != 0) {
9459                     ret = -1;
9460                     VALID_ERR2(XML_RELAXNG_ERR_ATTRVALID, node->name);
9461                 }
9462             }
9463             if (define->contModel != NULL) {
9464                 xmlRelaxNGValidStatePtr nstate, tmpstate = ctxt->state;
9465                 xmlRelaxNGStatesPtr tmpstates = ctxt->states;
9466                 xmlNodePtr nseq;
9467
9468                 nstate = xmlRelaxNGNewValidState(ctxt, node);
9469                 ctxt->state = nstate;
9470                 ctxt->states = NULL;
9471
9472                 tmp = xmlRelaxNGValidateCompiledContent(ctxt,
9473                                                         define->contModel,
9474                                                         ctxt->state->seq);
9475                 nseq = ctxt->state->seq;
9476                 ctxt->state = tmpstate;
9477                 ctxt->states = tmpstates;
9478                 xmlRelaxNGFreeValidState(ctxt, nstate);
9479
9480 #ifdef DEBUG_COMPILE
9481                 xmlGenericError(xmlGenericErrorContext,
9482                         "Validating content of '%s' : %d\n", define->name, tmp);
9483 #endif
9484                 if (tmp != 0)
9485                     ret = -1;
9486
9487                 if (ctxt->states != NULL) {
9488                     tmp = -1;
9489
9490                     ctxt->flags |= FLAGS_IGNORABLE;
9491
9492                     for (i = 0; i < ctxt->states->nbState; i++) {
9493                         state = ctxt->states->tabState[i];
9494                         ctxt->state = state;
9495                         ctxt->state->seq = nseq;
9496
9497                         if (xmlRelaxNGValidateElementEnd(ctxt) == 0)
9498                             tmp = 0;
9499                         xmlRelaxNGFreeValidState(ctxt, state);
9500                     }
9501                     xmlRelaxNGFreeStates(ctxt, ctxt->states);
9502                     ctxt->flags = oldflags;
9503                     ctxt->states = NULL;
9504                     if ((ret == 0) && (tmp == -1))
9505                         ret = -1;
9506                 } else {
9507                     state = ctxt->state;
9508                     ctxt->state->seq = nseq;
9509                     if (ret == 0)
9510                         ret = xmlRelaxNGValidateElementEnd(ctxt);
9511                     xmlRelaxNGFreeValidState(ctxt, state);
9512                 }
9513             } else {
9514                 if (define->content != NULL) {
9515                     tmp = xmlRelaxNGValidateDefinitionList(ctxt,
9516                                                            define->content);
9517                     if (tmp != 0) {
9518                         ret = -1;
9519                         if (ctxt->state == NULL) {
9520                             ctxt->state = oldstate;
9521                             VALID_ERR2(XML_RELAXNG_ERR_CONTENTVALID,
9522                                        node->name);
9523                             ctxt->state = NULL;
9524                         } else {
9525                             VALID_ERR2(XML_RELAXNG_ERR_CONTENTVALID,
9526                                        node->name);
9527                         }
9528
9529                     }
9530                 }
9531                 if (ctxt->states != NULL) {
9532                     tmp = -1;
9533
9534                     ctxt->flags |= FLAGS_IGNORABLE;
9535
9536                     for (i = 0; i < ctxt->states->nbState; i++) {
9537                         state = ctxt->states->tabState[i];
9538                         ctxt->state = state;
9539
9540                         if (xmlRelaxNGValidateElementEnd(ctxt) == 0)
9541                             tmp = 0;
9542                         xmlRelaxNGFreeValidState(ctxt, state);
9543                     }
9544                     xmlRelaxNGFreeStates(ctxt, ctxt->states);
9545                     ctxt->flags = oldflags;
9546                     ctxt->states = NULL;
9547                     if ((ret == 0) && (tmp == -1))
9548                         ret = -1;
9549                 } else {
9550                     state = ctxt->state;
9551                     if (ret == 0)
9552                         ret = xmlRelaxNGValidateElementEnd(ctxt);
9553                     xmlRelaxNGFreeValidState(ctxt, state);
9554                 }
9555             }
9556             if (ret == 0) {
9557                 node->_private = define;
9558             }
9559             ctxt->flags = oldflags;
9560             ctxt->state = oldstate;
9561             if (oldstate != NULL)
9562                 oldstate->seq = xmlRelaxNGSkipIgnored(ctxt, node->next);
9563             if (ret != 0) {
9564                 if ((ctxt->flags & FLAGS_IGNORABLE) == 0) {
9565                     xmlRelaxNGDumpValidError(ctxt);
9566                     ret = 0;
9567                 } else {
9568                     ret = -2;
9569                 }
9570             } else {
9571                 if (ctxt->errNr > errNr)
9572                     xmlRelaxNGPopErrors(ctxt, errNr);
9573             }
9574
9575 #ifdef DEBUG
9576             xmlGenericError(xmlGenericErrorContext,
9577                             "xmlRelaxNGValidateDefinition(): validated %s : %d",
9578                             node->name, ret);
9579             if (oldstate == NULL)
9580                 xmlGenericError(xmlGenericErrorContext, ": no state\n");
9581             else if (oldstate->seq == NULL)
9582                 xmlGenericError(xmlGenericErrorContext, ": done\n");
9583             else if (oldstate->seq->type == XML_ELEMENT_NODE)
9584                 xmlGenericError(xmlGenericErrorContext, ": next elem %s\n",
9585                                 oldstate->seq->name);
9586             else
9587                 xmlGenericError(xmlGenericErrorContext, ": next %s %d\n",
9588                                 oldstate->seq->name, oldstate->seq->type);
9589 #endif
9590             break;
9591         case XML_RELAXNG_OPTIONAL:{
9592                 errNr = ctxt->errNr;
9593                 oldflags = ctxt->flags;
9594                 ctxt->flags |= FLAGS_IGNORABLE;
9595                 oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state);
9596                 ret =
9597                     xmlRelaxNGValidateDefinitionList(ctxt,
9598                                                      define->content);
9599                 if (ret != 0) {
9600                     if (ctxt->state != NULL)
9601                         xmlRelaxNGFreeValidState(ctxt, ctxt->state);
9602                     ctxt->state = oldstate;
9603                     ctxt->flags = oldflags;
9604                     ret = 0;
9605                     if (ctxt->errNr > errNr)
9606                         xmlRelaxNGPopErrors(ctxt, errNr);
9607                     break;
9608                 }
9609                 if (ctxt->states != NULL) {
9610                     xmlRelaxNGAddStates(ctxt, ctxt->states, oldstate);
9611                 } else {
9612                     ctxt->states = xmlRelaxNGNewStates(ctxt, 1);
9613                     if (ctxt->states == NULL) {
9614                         xmlRelaxNGFreeValidState(ctxt, oldstate);
9615                         ctxt->flags = oldflags;
9616                         ret = -1;
9617                         if (ctxt->errNr > errNr)
9618                             xmlRelaxNGPopErrors(ctxt, errNr);
9619                         break;
9620                     }
9621                     xmlRelaxNGAddStates(ctxt, ctxt->states, oldstate);
9622                     xmlRelaxNGAddStates(ctxt, ctxt->states, ctxt->state);
9623                     ctxt->state = NULL;
9624                 }
9625                 ctxt->flags = oldflags;
9626                 ret = 0;
9627                 if (ctxt->errNr > errNr)
9628                     xmlRelaxNGPopErrors(ctxt, errNr);
9629                 break;
9630             }
9631         case XML_RELAXNG_ONEORMORE:
9632             errNr = ctxt->errNr;
9633             ret = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
9634             if (ret != 0) {
9635                 break;
9636             }
9637             if (ctxt->errNr > errNr)
9638                 xmlRelaxNGPopErrors(ctxt, errNr);
9639             /* no break on purpose */
9640         case XML_RELAXNG_ZEROORMORE:{
9641                 int progress;
9642                 xmlRelaxNGStatesPtr states = NULL, res = NULL;
9643                 int base, j;
9644
9645                 errNr = ctxt->errNr;
9646                 res = xmlRelaxNGNewStates(ctxt, 1);
9647                 if (res == NULL) {
9648                     ret = -1;
9649                     break;
9650                 }
9651                 /*
9652                  * All the input states are also exit states
9653                  */
9654                 if (ctxt->state != NULL) {
9655                     xmlRelaxNGAddStates(ctxt, res,
9656                                         xmlRelaxNGCopyValidState(ctxt,
9657                                                                  ctxt->
9658                                                                  state));
9659                 } else {
9660                     for (j = 0; j < ctxt->states->nbState; j++) {
9661                         xmlRelaxNGAddStates(ctxt, res,
9662                                             xmlRelaxNGCopyValidState(ctxt,
9663                                                                      ctxt->
9664                                                                      states->
9665                                                                      tabState
9666                                                                      [j]));
9667                     }
9668                 }
9669                 oldflags = ctxt->flags;
9670                 ctxt->flags |= FLAGS_IGNORABLE;
9671                 do {
9672                     progress = 0;
9673                     base = res->nbState;
9674
9675                     if (ctxt->states != NULL) {
9676                         states = ctxt->states;
9677                         for (i = 0; i < states->nbState; i++) {
9678                             ctxt->state = states->tabState[i];
9679                             ctxt->states = NULL;
9680                             ret = xmlRelaxNGValidateDefinitionList(ctxt,
9681                                                                    define->
9682                                                                    content);
9683                             if (ret == 0) {
9684                                 if (ctxt->state != NULL) {
9685                                     tmp = xmlRelaxNGAddStates(ctxt, res,
9686                                                               ctxt->state);
9687                                     ctxt->state = NULL;
9688                                     if (tmp == 1)
9689                                         progress = 1;
9690                                 } else if (ctxt->states != NULL) {
9691                                     for (j = 0; j < ctxt->states->nbState;
9692                                          j++) {
9693                                         tmp =
9694                                             xmlRelaxNGAddStates(ctxt, res,
9695                                                                 ctxt->
9696                                                                 states->
9697                                                                 tabState
9698                                                                 [j]);
9699                                         if (tmp == 1)
9700                                             progress = 1;
9701                                     }
9702                                     xmlRelaxNGFreeStates(ctxt,
9703                                                          ctxt->states);
9704                                     ctxt->states = NULL;
9705                                 }
9706                             } else {
9707                                 if (ctxt->state != NULL) {
9708                                     xmlRelaxNGFreeValidState(ctxt,
9709                                                              ctxt->state);
9710                                     ctxt->state = NULL;
9711                                 }
9712                             }
9713                         }
9714                     } else {
9715                         ret = xmlRelaxNGValidateDefinitionList(ctxt,
9716                                                                define->
9717                                                                content);
9718                         if (ret != 0) {
9719                             xmlRelaxNGFreeValidState(ctxt, ctxt->state);
9720                             ctxt->state = NULL;
9721                         } else {
9722                             base = res->nbState;
9723                             if (ctxt->state != NULL) {
9724                                 tmp = xmlRelaxNGAddStates(ctxt, res,
9725                                                           ctxt->state);
9726                                 ctxt->state = NULL;
9727                                 if (tmp == 1)
9728                                     progress = 1;
9729                             } else if (ctxt->states != NULL) {
9730                                 for (j = 0; j < ctxt->states->nbState; j++) {
9731                                     tmp = xmlRelaxNGAddStates(ctxt, res,
9732                                                               ctxt->
9733                                                               states->
9734                                                               tabState[j]);
9735                                     if (tmp == 1)
9736                                         progress = 1;
9737                                 }
9738                                 if (states == NULL) {
9739                                     states = ctxt->states;
9740                                 } else {
9741                                     xmlRelaxNGFreeStates(ctxt,
9742                                                          ctxt->states);
9743                                 }
9744                                 ctxt->states = NULL;
9745                             }
9746                         }
9747                     }
9748                     if (progress) {
9749                         /*
9750                          * Collect all the new nodes added at that step
9751                          * and make them the new node set
9752                          */
9753                         if (res->nbState - base == 1) {
9754                             ctxt->state = xmlRelaxNGCopyValidState(ctxt,
9755                                                                    res->
9756                                                                    tabState
9757                                                                    [base]);
9758                         } else {
9759                             if (states == NULL) {
9760                                 xmlRelaxNGNewStates(ctxt,
9761                                                     res->nbState - base);
9762                             }
9763                             states->nbState = 0;
9764                             for (i = base; i < res->nbState; i++)
9765                                 xmlRelaxNGAddStates(ctxt, states,
9766                                                     xmlRelaxNGCopyValidState
9767                                                     (ctxt,
9768                                                      res->tabState[i]));
9769                             ctxt->states = states;
9770                         }
9771                     }
9772                 } while (progress == 1);
9773                 if (states != NULL) {
9774                     xmlRelaxNGFreeStates(ctxt, states);
9775                 }
9776                 ctxt->states = res;
9777                 ctxt->flags = oldflags;
9778                 if (ctxt->errNr > errNr)
9779                     xmlRelaxNGPopErrors(ctxt, errNr);
9780                 ret = 0;
9781                 break;
9782             }
9783         case XML_RELAXNG_CHOICE:{
9784                 xmlRelaxNGDefinePtr list = NULL;
9785                 xmlRelaxNGStatesPtr states = NULL;
9786
9787                 node = xmlRelaxNGSkipIgnored(ctxt, node);
9788
9789                 errNr = ctxt->errNr;
9790                 if ((define->dflags & IS_TRIABLE)
9791                     && (define->data != NULL)) {
9792                     xmlHashTablePtr triage =
9793                         (xmlHashTablePtr) define->data;
9794
9795                     /*
9796                      * Something we can optimize cleanly there is only one
9797                      * possble branch out !
9798                      */
9799                     if (node == NULL) {
9800                         ret = -1;
9801                         break;
9802                     }
9803                     if ((node->type == XML_TEXT_NODE) ||
9804                         (node->type == XML_CDATA_SECTION_NODE)) {
9805                         list =
9806                             xmlHashLookup2(triage, BAD_CAST "#text", NULL);
9807                     } else if (node->type == XML_ELEMENT_NODE) {
9808                         if (node->ns != NULL) {
9809                             list = xmlHashLookup2(triage, node->name,
9810                                                   node->ns->href);
9811                             if (list == NULL)
9812                                 list =
9813                                     xmlHashLookup2(triage, BAD_CAST "#any",
9814                                                    node->ns->href);
9815                         } else
9816                             list =
9817                                 xmlHashLookup2(triage, node->name, NULL);
9818                         if (list == NULL)
9819                             list =
9820                                 xmlHashLookup2(triage, BAD_CAST "#any",
9821                                                NULL);
9822                     }
9823                     if (list == NULL) {
9824                         ret = -1;
9825                         break;
9826                     }
9827                     ret = xmlRelaxNGValidateDefinition(ctxt, list);
9828                     if (ret == 0) {
9829                     }
9830                     break;
9831                 }
9832
9833                 list = define->content;
9834                 oldflags = ctxt->flags;
9835                 ctxt->flags |= FLAGS_IGNORABLE;
9836
9837                 while (list != NULL) {
9838                     oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state);
9839                     ret = xmlRelaxNGValidateDefinition(ctxt, list);
9840                     if (ret == 0) {
9841                         if (states == NULL) {
9842                             states = xmlRelaxNGNewStates(ctxt, 1);
9843                         }
9844                         if (ctxt->state != NULL) {
9845                             xmlRelaxNGAddStates(ctxt, states, ctxt->state);
9846                         } else if (ctxt->states != NULL) {
9847                             for (i = 0; i < ctxt->states->nbState; i++) {
9848                                 xmlRelaxNGAddStates(ctxt, states,
9849                                                     ctxt->states->
9850                                                     tabState[i]);
9851                             }
9852                             xmlRelaxNGFreeStates(ctxt, ctxt->states);
9853                             ctxt->states = NULL;
9854                         }
9855                     } else {
9856                         xmlRelaxNGFreeValidState(ctxt, ctxt->state);
9857                     }
9858                     ctxt->state = oldstate;
9859                     list = list->next;
9860                 }
9861                 if (states != NULL) {
9862                     xmlRelaxNGFreeValidState(ctxt, oldstate);
9863                     ctxt->states = states;
9864                     ctxt->state = NULL;
9865                     ret = 0;
9866                 } else {
9867                     ctxt->states = NULL;
9868                 }
9869                 ctxt->flags = oldflags;
9870                 if (ret != 0) {
9871                     if ((ctxt->flags & FLAGS_IGNORABLE) == 0) {
9872                         xmlRelaxNGDumpValidError(ctxt);
9873                     }
9874                 } else {
9875                     if (ctxt->errNr > errNr)
9876                         xmlRelaxNGPopErrors(ctxt, errNr);
9877                 }
9878                 break;
9879             }
9880         case XML_RELAXNG_DEF:
9881         case XML_RELAXNG_GROUP:
9882             ret = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
9883             break;
9884         case XML_RELAXNG_INTERLEAVE:
9885             ret = xmlRelaxNGValidateInterleave(ctxt, define);
9886             break;
9887         case XML_RELAXNG_ATTRIBUTE:
9888             ret = xmlRelaxNGValidateAttribute(ctxt, define);
9889             break;
9890         case XML_RELAXNG_START:
9891         case XML_RELAXNG_NOOP:
9892         case XML_RELAXNG_REF:
9893         case XML_RELAXNG_EXTERNALREF:
9894         case XML_RELAXNG_PARENTREF:
9895             ret = xmlRelaxNGValidateDefinition(ctxt, define->content);
9896             break;
9897         case XML_RELAXNG_DATATYPE:{
9898                 xmlNodePtr child;
9899                 xmlChar *content = NULL;
9900
9901                 child = node;
9902                 while (child != NULL) {
9903                     if (child->type == XML_ELEMENT_NODE) {
9904                         VALID_ERR2(XML_RELAXNG_ERR_DATAELEM,
9905                                    node->parent->name);
9906                         ret = -1;
9907                         break;
9908                     } else if ((child->type == XML_TEXT_NODE) ||
9909                                (child->type == XML_CDATA_SECTION_NODE)) {
9910                         content = xmlStrcat(content, child->content);
9911                     }
9912                     /* TODO: handle entities ... */
9913                     child = child->next;
9914                 }
9915                 if (ret == -1) {
9916                     if (content != NULL)
9917                         xmlFree(content);
9918                     break;
9919                 }
9920                 if (content == NULL) {
9921                     content = xmlStrdup(BAD_CAST "");
9922                     if (content == NULL) {
9923                         VALID_ERR(XML_RELAXNG_ERR_MEMORY);
9924                         ret = -1;
9925                         break;
9926                     }
9927                 }
9928                 ret = xmlRelaxNGValidateDatatype(ctxt, content, define,
9929                                                  ctxt->state->seq);
9930                 if (ret == -1) {
9931                     VALID_ERR2(XML_RELAXNG_ERR_DATATYPE, define->name);
9932                 } else if (ret == 0) {
9933                     ctxt->state->seq = NULL;
9934                 }
9935                 if (content != NULL)
9936                     xmlFree(content);
9937                 break;
9938             }
9939         case XML_RELAXNG_VALUE:{
9940                 xmlChar *content = NULL;
9941                 xmlChar *oldvalue;
9942                 xmlNodePtr child;
9943
9944                 child = node;
9945                 while (child != NULL) {
9946                     if (child->type == XML_ELEMENT_NODE) {
9947                         VALID_ERR2(XML_RELAXNG_ERR_VALELEM,
9948                                    node->parent->name);
9949                         ret = -1;
9950                         break;
9951                     } else if ((child->type == XML_TEXT_NODE) ||
9952                                (child->type == XML_CDATA_SECTION_NODE)) {
9953                         content = xmlStrcat(content, child->content);
9954                     }
9955                     /* TODO: handle entities ... */
9956                     child = child->next;
9957                 }
9958                 if (ret == -1) {
9959                     if (content != NULL)
9960                         xmlFree(content);
9961                     break;
9962                 }
9963                 if (content == NULL) {
9964                     content = xmlStrdup(BAD_CAST "");
9965                     if (content == NULL) {
9966                         VALID_ERR(XML_RELAXNG_ERR_MEMORY);
9967                         ret = -1;
9968                         break;
9969                     }
9970                 }
9971                 oldvalue = ctxt->state->value;
9972                 ctxt->state->value = content;
9973                 ret = xmlRelaxNGValidateValue(ctxt, define);
9974                 ctxt->state->value = oldvalue;
9975                 if (ret == -1) {
9976                     VALID_ERR2(XML_RELAXNG_ERR_VALUE, define->name);
9977                 } else if (ret == 0) {
9978                     ctxt->state->seq = NULL;
9979                 }
9980                 if (content != NULL)
9981                     xmlFree(content);
9982                 break;
9983             }
9984         case XML_RELAXNG_LIST:{
9985                 xmlChar *content;
9986                 xmlNodePtr child;
9987                 xmlChar *oldvalue, *oldendvalue;
9988                 int len;
9989
9990                 /*
9991                  * Make sure it's only text nodes
9992                  */
9993
9994                 content = NULL;
9995                 child = node;
9996                 while (child != NULL) {
9997                     if (child->type == XML_ELEMENT_NODE) {
9998                         VALID_ERR2(XML_RELAXNG_ERR_LISTELEM,
9999                                    node->parent->name);
10000                         ret = -1;
10001                         break;
10002                     } else if ((child->type == XML_TEXT_NODE) ||
10003                                (child->type == XML_CDATA_SECTION_NODE)) {
10004                         content = xmlStrcat(content, child->content);
10005                     }
10006                     /* TODO: handle entities ... */
10007                     child = child->next;
10008                 }
10009                 if (ret == -1) {
10010                     if (content != NULL)
10011                         xmlFree(content);
10012                     break;
10013                 }
10014                 if (content == NULL) {
10015                     content = xmlStrdup(BAD_CAST "");
10016                     if (content == NULL) {
10017                         VALID_ERR(XML_RELAXNG_ERR_MEMORY);
10018                         ret = -1;
10019                         break;
10020                     }
10021                 }
10022                 len = xmlStrlen(content);
10023                 oldvalue = ctxt->state->value;
10024                 oldendvalue = ctxt->state->endvalue;
10025                 ctxt->state->value = content;
10026                 ctxt->state->endvalue = content + len;
10027                 ret = xmlRelaxNGValidateValue(ctxt, define);
10028                 ctxt->state->value = oldvalue;
10029                 ctxt->state->endvalue = oldendvalue;
10030                 if (ret == -1) {
10031                     VALID_ERR(XML_RELAXNG_ERR_LIST);
10032                 } else if ((ret == 0) && (node != NULL)) {
10033                     ctxt->state->seq = node->next;
10034                 }
10035                 if (content != NULL)
10036                     xmlFree(content);
10037                 break;
10038             }
10039         case XML_RELAXNG_EXCEPT:
10040         case XML_RELAXNG_PARAM:
10041             TODO ret = -1;
10042             break;
10043     }
10044     ctxt->depth--;
10045 #ifdef DEBUG
10046     for (i = 0; i < ctxt->depth; i++)
10047         xmlGenericError(xmlGenericErrorContext, " ");
10048     xmlGenericError(xmlGenericErrorContext,
10049                     "Validating %s ", xmlRelaxNGDefName(define));
10050     if (define->name != NULL)
10051         xmlGenericError(xmlGenericErrorContext, "%s ", define->name);
10052     if (ret == 0)
10053         xmlGenericError(xmlGenericErrorContext, "suceeded\n");
10054     else
10055         xmlGenericError(xmlGenericErrorContext, "failed\n");
10056 #endif
10057     return (ret);
10058 }
10059
10060 /**
10061  * xmlRelaxNGValidateDefinition:
10062  * @ctxt:  a Relax-NG validation context
10063  * @define:  the definition to verify
10064  *
10065  * Validate the current node lists against the definition
10066  *
10067  * Returns 0 if the validation succeeded or an error code.
10068  */
10069 static int
10070 xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt, 
10071                              xmlRelaxNGDefinePtr define) {
10072     xmlRelaxNGStatesPtr states, res;
10073     int i, j, k, ret, oldflags;
10074
10075     /*
10076      * We should NOT have both ctxt->state and ctxt->states
10077      */
10078     if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
10079         TODO
10080         xmlRelaxNGFreeValidState(ctxt,ctxt->state);
10081         ctxt->state = NULL;
10082     }
10083
10084     if ((ctxt->states == NULL) || (ctxt->states->nbState == 1)) {
10085         if (ctxt->states != NULL) {
10086             ctxt->state = ctxt->states->tabState[0];
10087             xmlRelaxNGFreeStates(ctxt, ctxt->states);
10088             ctxt->states = NULL;
10089         }
10090         ret = xmlRelaxNGValidateState(ctxt, define);
10091         if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
10092             TODO
10093             xmlRelaxNGFreeValidState(ctxt,ctxt->state);
10094             ctxt->state = NULL;
10095         }
10096         if ((ctxt->states != NULL) && (ctxt->states->nbState == 1)) {
10097             ctxt->state = ctxt->states->tabState[0];
10098             xmlRelaxNGFreeStates(ctxt, ctxt->states);
10099             ctxt->states = NULL;
10100         }
10101         return(ret);
10102     }
10103
10104     states = ctxt->states;
10105     ctxt->states = NULL;
10106     res = NULL;
10107     j = 0;
10108     oldflags = ctxt->flags;
10109     ctxt->flags |= FLAGS_IGNORABLE;
10110     for (i = 0;i < states->nbState;i++) {
10111         ctxt->state = states->tabState[i];
10112         ctxt->states = NULL;
10113         ret = xmlRelaxNGValidateState(ctxt, define);
10114         /*
10115          * We should NOT have both ctxt->state and ctxt->states
10116          */
10117         if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
10118             TODO
10119             xmlRelaxNGFreeValidState(ctxt,ctxt->state);
10120             ctxt->state = NULL;
10121         }
10122         if (ret == 0) {
10123             if (ctxt->states == NULL) {
10124                 if (res != NULL) {
10125                     /* add the state to the container */
10126                     xmlRelaxNGAddStates(ctxt, res, ctxt->state);
10127                     ctxt->state = NULL;
10128                 } else {
10129                     /* add the state directly in states */
10130                     states->tabState[j++] = ctxt->state;
10131                     ctxt->state = NULL;
10132                 }
10133             } else {
10134                 if (res == NULL) {
10135                     /* make it the new container and copy other results */
10136                     res = ctxt->states;
10137                     ctxt->states = NULL;
10138                     for (k = 0;k < j;k++)
10139                         xmlRelaxNGAddStates(ctxt, res, states->tabState[k]);
10140                 } else {
10141                     /* add all the new results to res and reff the container */
10142                     for (k = 0;k < ctxt->states->nbState;k++)
10143                         xmlRelaxNGAddStates(ctxt, res,
10144                                             ctxt->states->tabState[k]);
10145                     xmlRelaxNGFreeStates(ctxt, ctxt->states);
10146                     ctxt->states = NULL;
10147                 }
10148             }
10149         } else {
10150             if (ctxt->state != NULL) {
10151                 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
10152                 ctxt->state = NULL;
10153             } else if (ctxt->states != NULL) {
10154                 for (k = 0;k < ctxt->states->nbState;k++)
10155                     xmlRelaxNGFreeValidState(ctxt,ctxt->states->tabState[k]);
10156                 xmlRelaxNGFreeStates(ctxt, ctxt->states);
10157                 ctxt->states = NULL;
10158             }
10159         }
10160     }
10161     ctxt->flags = oldflags;
10162     if (res != NULL) {
10163         xmlRelaxNGFreeStates(ctxt, states);
10164         ctxt->states = res;
10165         ret = 0;
10166     } else if (j > 1) {
10167         states->nbState = j;
10168         ctxt->states = states;
10169         ret =0;
10170     } else if (j == 1) {
10171         ctxt->state = states->tabState[0];
10172         xmlRelaxNGFreeStates(ctxt, states);
10173         ret = 0;
10174     } else {
10175         ret = -1;
10176         xmlRelaxNGFreeStates(ctxt, states);
10177         if (ctxt->states != NULL) {
10178             xmlRelaxNGFreeStates(ctxt, ctxt->states);
10179             ctxt->states = NULL;
10180         }
10181     }
10182     if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
10183         TODO
10184         xmlRelaxNGFreeValidState(ctxt,ctxt->state);
10185         ctxt->state = NULL;
10186     }
10187     return(ret);
10188 }
10189
10190 /**
10191  * xmlRelaxNGValidateDocument:
10192  * @ctxt:  a Relax-NG validation context
10193  * @doc:  the document
10194  *
10195  * Validate the given document
10196  *
10197  * Returns 0 if the validation succeeded or an error code.
10198  */
10199 static int
10200 xmlRelaxNGValidateDocument(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc) {
10201     int ret;
10202     xmlRelaxNGPtr schema;
10203     xmlRelaxNGGrammarPtr grammar;
10204     xmlRelaxNGValidStatePtr state;
10205     xmlNodePtr node;
10206
10207     if ((ctxt == NULL) || (ctxt->schema == NULL) || (doc == NULL))
10208         return(-1);
10209
10210     ctxt->errNo = XML_RELAXNG_OK;
10211     schema = ctxt->schema;
10212     grammar = schema->topgrammar;
10213     if (grammar == NULL) {
10214         VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR);
10215         return(-1);
10216     }
10217     state = xmlRelaxNGNewValidState(ctxt, NULL);
10218     ctxt->state = state;
10219     ret = xmlRelaxNGValidateDefinition(ctxt, grammar->start);
10220     if ((ctxt->state != NULL) && (state->seq != NULL)) {
10221         state = ctxt->state;
10222         node = state->seq;
10223         node = xmlRelaxNGSkipIgnored(ctxt, node);
10224         if (node != NULL) {
10225             if (ret != -1) {
10226                 VALID_ERR(XML_RELAXNG_ERR_EXTRADATA);
10227                 ret = -1;
10228             }
10229         }
10230     } else if (ctxt->states != NULL) {
10231         int i;
10232         int tmp = -1;
10233
10234         for (i = 0;i < ctxt->states->nbState;i++) {
10235             state = ctxt->states->tabState[i];
10236             node = state->seq;
10237             node = xmlRelaxNGSkipIgnored(ctxt, node);
10238             if (node == NULL)
10239                 tmp = 0;
10240             xmlRelaxNGFreeValidState(ctxt,state);
10241         }
10242         if (tmp == -1) {
10243             if (ret != -1) {
10244                 VALID_ERR(XML_RELAXNG_ERR_EXTRADATA);
10245                 ret = -1;
10246             }
10247         }
10248     }
10249     if (ctxt->state != NULL) {
10250         xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10251         ctxt->state = NULL;
10252     }
10253     if (ret != 0) 
10254         xmlRelaxNGDumpValidError(ctxt);
10255 #ifdef DEBUG
10256     else if (ctxt->errNr != 0) {
10257         ctxt->error(ctxt->userData, "%d Extra error messages left on stack !\n",
10258                     ctxt->errNr);
10259         xmlRelaxNGDumpValidError(ctxt);
10260     }
10261 #endif
10262     if (ctxt->idref == 1) {
10263         xmlValidCtxt vctxt;
10264
10265         memset(&vctxt, 0, sizeof(xmlValidCtxt));
10266         vctxt.valid = 1;
10267         vctxt.error = ctxt->error;
10268         vctxt.warning = ctxt->warning;
10269         vctxt.userData = ctxt->userData;
10270
10271         if (xmlValidateDocumentFinal(&vctxt, doc) != 1)
10272             ret = -1;
10273     }
10274     if ((ret == 0) && (ctxt->errNo != XML_RELAXNG_OK))
10275         ret = -1;
10276
10277     return(ret);
10278 }
10279
10280 /************************************************************************
10281  *                                                                      *
10282  *                      Validation interfaces                           *
10283  *                                                                      *
10284  ************************************************************************/
10285 /**
10286  * xmlRelaxNGNewValidCtxt:
10287  * @schema:  a precompiled XML RelaxNGs
10288  *
10289  * Create an XML RelaxNGs validation context based on the given schema
10290  *
10291  * Returns the validation context or NULL in case of error
10292  */
10293 xmlRelaxNGValidCtxtPtr
10294 xmlRelaxNGNewValidCtxt(xmlRelaxNGPtr schema) {
10295     xmlRelaxNGValidCtxtPtr ret;
10296
10297     ret = (xmlRelaxNGValidCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGValidCtxt));
10298     if (ret == NULL) {
10299         xmlGenericError(xmlGenericErrorContext,
10300                 "Failed to allocate new schema validation context\n");
10301         return (NULL);
10302     }
10303     memset(ret, 0, sizeof(xmlRelaxNGValidCtxt));
10304     ret->schema = schema;
10305     ret->error = xmlGenericError;
10306     ret->userData = xmlGenericErrorContext;
10307     ret->errNr = 0;
10308     ret->errMax = 0;
10309     ret->err = NULL;
10310     ret->errTab = NULL;
10311     ret->idref = schema->idref;
10312     ret->states = NULL;
10313     ret->freeState = NULL;
10314     ret->freeStates = NULL;
10315     ret->errNo = XML_RELAXNG_OK;
10316     return (ret);
10317 }
10318
10319 /**
10320  * xmlRelaxNGFreeValidCtxt:
10321  * @ctxt:  the schema validation context
10322  *
10323  * Free the resources associated to the schema validation context
10324  */
10325 void
10326 xmlRelaxNGFreeValidCtxt(xmlRelaxNGValidCtxtPtr ctxt) {
10327     int k;
10328
10329     if (ctxt == NULL)
10330         return;
10331     if (ctxt->states != NULL)
10332         xmlRelaxNGFreeStates(NULL, ctxt->states);
10333     if (ctxt->freeState != NULL) {
10334         for (k = 0;k < ctxt->freeState->nbState;k++) {
10335             xmlRelaxNGFreeValidState(NULL, ctxt->freeState->tabState[k]);
10336         }
10337         xmlRelaxNGFreeStates(NULL, ctxt->freeState);
10338     }
10339     if (ctxt->freeStates != NULL) {
10340         for (k = 0;k < ctxt->freeStatesNr;k++) {
10341             xmlRelaxNGFreeStates(NULL, ctxt->freeStates[k]);
10342         }
10343         xmlFree(ctxt->freeStates);
10344     }
10345     if (ctxt->errTab != NULL)
10346         xmlFree(ctxt->errTab);
10347     if (ctxt->elemTab != NULL) {
10348         xmlRegExecCtxtPtr exec;
10349
10350         exec = xmlRelaxNGElemPop(ctxt);
10351         while (exec != NULL) {
10352             xmlRegFreeExecCtxt(exec);
10353             exec = xmlRelaxNGElemPop(ctxt);
10354         }
10355         xmlFree(ctxt->elemTab);
10356     }
10357     xmlFree(ctxt);
10358 }
10359
10360 /**
10361  * xmlRelaxNGSetValidErrors:
10362  * @ctxt:  a Relax-NG validation context
10363  * @err:  the error function
10364  * @warn: the warning function
10365  * @ctx: the functions context
10366  *
10367  * Set the error and warning callback informations
10368  */
10369 void
10370 xmlRelaxNGSetValidErrors(xmlRelaxNGValidCtxtPtr ctxt,
10371         xmlRelaxNGValidityErrorFunc err,
10372         xmlRelaxNGValidityWarningFunc warn, void *ctx) {
10373     if (ctxt == NULL)
10374         return;
10375     ctxt->error = err;
10376     ctxt->warning = warn;
10377     ctxt->userData = ctx;
10378 }
10379
10380 /**
10381  * xmlRelaxNGGetValidErrors:
10382  * @ctxt:  a Relax-NG validation context
10383  * @err:  the error function result
10384  * @warn: the warning function result
10385  * @ctx: the functions context result
10386  *
10387  * Get the error and warning callback informations
10388  *
10389  * Returns -1 in case of error and 0 otherwise
10390  */
10391 int
10392 xmlRelaxNGGetValidErrors(xmlRelaxNGValidCtxtPtr ctxt,
10393         xmlRelaxNGValidityErrorFunc *err,
10394         xmlRelaxNGValidityWarningFunc *warn, void **ctx) {
10395     if (ctxt == NULL)
10396         return(-1);
10397     if (err != NULL) *err = ctxt->error;
10398     if (warn != NULL) *warn = ctxt->warning;
10399     if (ctx != NULL) *ctx = ctxt->userData;
10400     return(0);
10401 }
10402
10403 /**
10404  * xmlRelaxNGValidateDoc:
10405  * @ctxt:  a Relax-NG validation context
10406  * @doc:  a parsed document tree
10407  *
10408  * Validate a document tree in memory.
10409  *
10410  * Returns 0 if the document is valid, a positive error code
10411  *     number otherwise and -1 in case of internal or API error.
10412  */
10413 int
10414 xmlRelaxNGValidateDoc(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc) {
10415     int ret;
10416
10417     if ((ctxt == NULL) || (doc == NULL))
10418         return(-1);
10419
10420     ctxt->doc = doc;
10421
10422     ret = xmlRelaxNGValidateDocument(ctxt, doc);
10423     /*
10424      * TODO: build error codes
10425      */
10426     if (ret == -1)
10427         return(1);
10428     return(ret);
10429 }
10430
10431 #endif /* LIBXML_SCHEMAS_ENABLED */
10432