Initial revision
[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  * - error reporting
12  * - simplification of the resulting compiled trees:
13  *    - NOT_ALLOWED
14  *    - EMPTY
15  * - handle namespace declarations as attributes.
16  * - add support for DTD compatibility spec
17  *   http://www.oasis-open.org/committees/relax-ng/compatibility-20011203.html
18  */
19
20 #define IN_LIBXML
21 #include "libxml.h"
22
23 #ifdef LIBXML_SCHEMAS_ENABLED
24
25 #include <string.h>
26 #include <stdio.h>
27 #include <libxml/xmlmemory.h>
28 #include <libxml/parser.h>
29 #include <libxml/parserInternals.h>
30 #include <libxml/hash.h>
31 #include <libxml/uri.h>
32
33 #include <libxml/relaxng.h>
34
35 #include <libxml/xmlschemastypes.h>
36 #include <libxml/xmlautomata.h>
37 #include <libxml/xmlregexp.h>
38 #include <libxml/xmlschemastypes.h>
39
40 /*
41  * The Relax-NG namespace
42  */
43 static const xmlChar *xmlRelaxNGNs = (const xmlChar *)
44     "http://relaxng.org/ns/structure/1.0";
45
46 #define IS_RELAXNG(node, type)                                          \
47    ((node != NULL) && (node->ns != NULL) &&                             \
48     (xmlStrEqual(node->name, (const xmlChar *) type)) &&                \
49     (xmlStrEqual(node->ns->href, xmlRelaxNGNs)))
50
51
52 /* #define DEBUG 1 */                /* very verbose output */
53 /* #define DEBUG_CONTENT 1 */
54 /* #define DEBUG_TYPE 1 */
55 /* #define DEBUG_VALID 1 */
56 /* #define DEBUG_INTERLEAVE 1 */
57 /* #define DEBUG_LIST 1 */
58
59 #define UNBOUNDED (1 << 30)
60 #define TODO                                                            \
61     xmlGenericError(xmlGenericErrorContext,                             \
62             "Unimplemented block at %s:%d\n",                           \
63             __FILE__, __LINE__);
64
65 typedef struct _xmlRelaxNGSchema xmlRelaxNGSchema;
66 typedef xmlRelaxNGSchema *xmlRelaxNGSchemaPtr;
67
68 typedef struct _xmlRelaxNGDefine xmlRelaxNGDefine;
69 typedef xmlRelaxNGDefine *xmlRelaxNGDefinePtr;
70
71 typedef struct _xmlRelaxNGDocument xmlRelaxNGDocument;
72 typedef xmlRelaxNGDocument *xmlRelaxNGDocumentPtr;
73
74 typedef struct _xmlRelaxNGInclude xmlRelaxNGInclude;
75 typedef xmlRelaxNGInclude *xmlRelaxNGIncludePtr;
76
77 typedef enum {
78     XML_RELAXNG_COMBINE_UNDEFINED = 0,  /* undefined */
79     XML_RELAXNG_COMBINE_CHOICE,         /* choice */
80     XML_RELAXNG_COMBINE_INTERLEAVE      /* interleave */
81 } xmlRelaxNGCombine;
82
83 typedef enum {
84     XML_RELAXNG_CONTENT_ERROR = -1,
85     XML_RELAXNG_CONTENT_EMPTY = 0,
86     XML_RELAXNG_CONTENT_SIMPLE,
87     XML_RELAXNG_CONTENT_COMPLEX
88 } xmlRelaxNGContentType;
89
90 typedef struct _xmlRelaxNGGrammar xmlRelaxNGGrammar;
91 typedef xmlRelaxNGGrammar *xmlRelaxNGGrammarPtr;
92
93 struct _xmlRelaxNGGrammar {
94     xmlRelaxNGGrammarPtr parent;/* the parent grammar if any */
95     xmlRelaxNGGrammarPtr children;/* the children grammar if any */
96     xmlRelaxNGGrammarPtr next;  /* the next grammar if any */
97     xmlRelaxNGDefinePtr start;  /* <start> content */
98     xmlRelaxNGCombine combine;  /* the default combine value */
99     xmlRelaxNGDefinePtr startList;/* list of <start> definitions */
100     xmlHashTablePtr defs;       /* define* */
101     xmlHashTablePtr refs;       /* references */
102 };
103
104
105 typedef enum {
106     XML_RELAXNG_NOOP = -1,      /* a no operation from simplification  */
107     XML_RELAXNG_EMPTY = 0,      /* an empty pattern */
108     XML_RELAXNG_NOT_ALLOWED,    /* not allowed top */
109     XML_RELAXNG_EXCEPT,         /* except present in nameclass defs */
110     XML_RELAXNG_TEXT,           /* textual content */
111     XML_RELAXNG_ELEMENT,        /* an element */
112     XML_RELAXNG_DATATYPE,       /* extenal data type definition */
113     XML_RELAXNG_PARAM,          /* extenal data type parameter */
114     XML_RELAXNG_VALUE,          /* value from an extenal data type definition */
115     XML_RELAXNG_LIST,           /* a list of patterns */
116     XML_RELAXNG_ATTRIBUTE,      /* an attrbute following a pattern */
117     XML_RELAXNG_DEF,            /* a definition */
118     XML_RELAXNG_REF,            /* reference to a definition */
119     XML_RELAXNG_EXTERNALREF,    /* reference to an external def */
120     XML_RELAXNG_PARENTREF,      /* reference to a def in the parent grammar */
121     XML_RELAXNG_OPTIONAL,       /* optional patterns */
122     XML_RELAXNG_ZEROORMORE,     /* zero or more non empty patterns */
123     XML_RELAXNG_ONEORMORE,      /* one or more non empty patterns */
124     XML_RELAXNG_CHOICE,         /* a choice between non empty patterns */
125     XML_RELAXNG_GROUP,          /* a pair/group of non empty patterns */
126     XML_RELAXNG_INTERLEAVE,     /* interleaving choice of non-empty patterns */
127     XML_RELAXNG_START           /* Used to keep track of starts on grammars */
128 } xmlRelaxNGType;
129
130 struct _xmlRelaxNGDefine {
131     xmlRelaxNGType type;        /* the type of definition */
132     xmlNodePtr     node;        /* the node in the source */
133     xmlChar       *name;        /* the element local name if present */
134     xmlChar       *ns;          /* the namespace local name if present */
135     xmlChar       *value;       /* value when available */
136     void          *data;        /* data lib or specific pointer */
137     int            depth;       /* used for the cycle detection */
138     xmlRelaxNGDefinePtr content;/* the expected content */
139     xmlRelaxNGDefinePtr parent; /* the parent definition, if any */
140     xmlRelaxNGDefinePtr next;   /* list within grouping sequences */
141     xmlRelaxNGDefinePtr attrs;  /* list of attributes for elements */
142     xmlRelaxNGDefinePtr nameClass;/* the nameClass definition if any */
143     xmlRelaxNGDefinePtr nextHash;/* next define in defs/refs hash tables */
144 };
145
146 /**
147  * _xmlRelaxNG:
148  *
149  * A RelaxNGs definition
150  */
151 struct _xmlRelaxNG {
152     xmlRelaxNGGrammarPtr topgrammar;
153     xmlDocPtr doc;
154
155     xmlHashTablePtr defs;       /* define */
156     xmlHashTablePtr refs;       /* references */
157     xmlHashTablePtr documents;  /* all the documents loaded */
158     xmlHashTablePtr includes;   /* all the includes loaded */
159     int                  defNr; /* number of defines used */
160     xmlRelaxNGDefinePtr *defTab;/* pointer to the allocated definitions */
161     void *_private;     /* unused by the library for users or bindings */
162 };
163
164 typedef enum {
165     XML_RELAXNG_ERR_OK          = 0,
166     XML_RELAXNG_ERR_NOROOT      = 1,
167     XML_RELAXNG_ERR_
168 } xmlRelaxNGValidError;
169
170 #define XML_RELAXNG_IN_ATTRIBUTE        (1 << 0)
171 #define XML_RELAXNG_IN_ONEORMORE        (1 << 1)
172 #define XML_RELAXNG_IN_LIST             (1 << 2)
173 #define XML_RELAXNG_IN_DATAEXCEPT       (1 << 3)
174 #define XML_RELAXNG_IN_START            (1 << 4)
175 #define XML_RELAXNG_IN_OOMGROUP         (1 << 5)
176 #define XML_RELAXNG_IN_OOMINTERLEAVE    (1 << 6)
177 #define XML_RELAXNG_IN_EXTERNALREF      (1 << 7)
178 #define XML_RELAXNG_IN_ANYEXCEPT        (1 << 8)
179 #define XML_RELAXNG_IN_NSEXCEPT         (1 << 9)
180
181 struct _xmlRelaxNGParserCtxt {
182     void *userData;                     /* user specific data block */
183     xmlRelaxNGValidityErrorFunc error;  /* the callback in case of errors */
184     xmlRelaxNGValidityWarningFunc warning;/* the callback in case of warning */
185     xmlRelaxNGValidError err;
186
187     xmlRelaxNGPtr      schema;        /* The schema in use */
188     xmlRelaxNGGrammarPtr grammar;     /* the current grammar */
189     xmlRelaxNGGrammarPtr parentgrammar;/* the parent grammar */
190     int                flags;         /* parser flags */
191     int                nbErrors;      /* number of errors at parse time */
192     int                nbWarnings;    /* number of warnings at parse time */
193     const xmlChar     *define;        /* the current define scope */
194     xmlRelaxNGDefinePtr def;          /* the current define */
195
196     int                nbInterleaves;
197     xmlHashTablePtr    interleaves;   /* keep track of all the interleaves */
198
199     xmlHashTablePtr    documents;     /* all the documents loaded */
200     xmlHashTablePtr    includes;      /* all the includes loaded */
201     xmlChar           *URL;
202     xmlDocPtr          document;
203
204     int                  defNr;       /* number of defines used */
205     int                  defMax;      /* number of defines aloocated */
206     xmlRelaxNGDefinePtr *defTab;      /* pointer to the allocated definitions */
207
208     const char     *buffer;
209     int               size;
210
211     /* the document stack */
212     xmlRelaxNGDocumentPtr doc;        /* Current parsed external ref */
213     int                   docNr;      /* Depth of the parsing stack */
214     int                   docMax;     /* Max depth of the parsing stack */
215     xmlRelaxNGDocumentPtr *docTab;    /* array of docs */
216
217     /* the include stack */
218     xmlRelaxNGIncludePtr  inc;        /* Current parsed include */
219     int                   incNr;      /* Depth of the include parsing stack */
220     int                   incMax;     /* Max depth of the parsing stack */
221     xmlRelaxNGIncludePtr *incTab;     /* array of incs */
222 };
223
224 #define FLAGS_IGNORABLE         1
225 #define FLAGS_NEGATIVE          2
226
227 /**
228  * xmlRelaxNGInterleaveGroup:
229  *
230  * A RelaxNGs partition set associated to lists of definitions
231  */
232 typedef struct _xmlRelaxNGInterleaveGroup xmlRelaxNGInterleaveGroup;
233 typedef xmlRelaxNGInterleaveGroup *xmlRelaxNGInterleaveGroupPtr;
234 struct _xmlRelaxNGInterleaveGroup {
235     xmlRelaxNGDefinePtr  rule;  /* the rule to satisfy */
236     xmlRelaxNGDefinePtr *defs;  /* the array of element definitions */
237     xmlRelaxNGDefinePtr *attrs; /* the array of attributes definitions */
238 };
239
240 /**
241  * xmlRelaxNGPartitions:
242  *
243  * A RelaxNGs partition associated to an interleave group
244  */
245 typedef struct _xmlRelaxNGPartition xmlRelaxNGPartition;
246 typedef xmlRelaxNGPartition *xmlRelaxNGPartitionPtr;
247 struct _xmlRelaxNGPartition {
248     int nbgroups;               /* number of groups in the partitions */
249     xmlRelaxNGInterleaveGroupPtr *groups;
250 };
251
252 /**
253  * xmlRelaxNGValidState:
254  *
255  * A RelaxNGs validation state
256  */
257 #define MAX_ATTR 20
258 typedef struct _xmlRelaxNGValidState xmlRelaxNGValidState;
259 typedef xmlRelaxNGValidState *xmlRelaxNGValidStatePtr;
260 struct _xmlRelaxNGValidState {
261     xmlNodePtr   node;          /* the current node */
262     xmlNodePtr    seq;          /* the sequence of children left to validate */
263     int       nbAttrs;          /* the number of attributes */
264     int    nbAttrLeft;          /* the number of attributes left to validate */
265     xmlChar    *value;          /* the value when operating on string */
266     xmlChar *endvalue;          /* the end value when operating on string */
267     xmlAttrPtr attrs[1];        /* the array of attributes */
268 };
269
270 /**
271  * xmlRelaxNGValidCtxt:
272  *
273  * A RelaxNGs validation context
274  */
275
276 struct _xmlRelaxNGValidCtxt {
277     void *userData;                     /* user specific data block */
278     xmlRelaxNGValidityErrorFunc error;  /* the callback in case of errors */
279     xmlRelaxNGValidityWarningFunc warning;/* the callback in case of warning */
280
281     xmlRelaxNGPtr           schema;     /* The schema in use */
282     xmlDocPtr               doc;        /* the document being validated */
283     xmlRelaxNGValidStatePtr state;      /* the current validation state */
284     int                     flags;      /* validation flags */
285     int                     depth;      /* validation depth */
286 };
287
288 /**
289  * xmlRelaxNGInclude:
290  *
291  * Structure associated to a RelaxNGs document element
292  */
293 struct _xmlRelaxNGInclude {
294     xmlChar   *href;            /* the normalized href value */
295     xmlDocPtr  doc;             /* the associated XML document */
296     xmlRelaxNGDefinePtr content;/* the definitions */
297     xmlRelaxNGPtr       schema; /* the schema */
298 };
299
300 /**
301  * xmlRelaxNGDocument:
302  *
303  * Structure associated to a RelaxNGs document element
304  */
305 struct _xmlRelaxNGDocument {
306     xmlChar   *href;            /* the normalized href value */
307     xmlDocPtr  doc;             /* the associated XML document */
308     xmlRelaxNGDefinePtr content;/* the definitions */
309     xmlRelaxNGPtr       schema; /* the schema */
310 };
311
312
313 /************************************************************************
314  *                                                                      *
315  *              Preliminary type checking interfaces                    *
316  *                                                                      *
317  ************************************************************************/
318 /**
319  * xmlRelaxNGTypeHave:
320  * @data:  data needed for the library
321  * @type:  the type name
322  * @value:  the value to check
323  *
324  * Function provided by a type library to check if a type is exported
325  *
326  * Returns 1 if yes, 0 if no and -1 in case of error.
327  */
328 typedef int (*xmlRelaxNGTypeHave) (void *data, const xmlChar *type);
329
330 /**
331  * xmlRelaxNGTypeCheck:
332  * @data:  data needed for the library
333  * @type:  the type name
334  * @value:  the value to check
335  *
336  * Function provided by a type library to check if a value match a type
337  *
338  * Returns 1 if yes, 0 if no and -1 in case of error.
339  */
340 typedef int (*xmlRelaxNGTypeCheck) (void *data, const xmlChar *type,
341                                     const xmlChar *value);
342
343 /**
344  * xmlRelaxNGTypeCompare:
345  * @data:  data needed for the library
346  * @type:  the type name
347  * @value1:  the first value
348  * @value2:  the second value
349  *
350  * Function provided by a type library to compare two values accordingly
351  * to a type.
352  *
353  * Returns 1 if yes, 0 if no and -1 in case of error.
354  */
355 typedef int (*xmlRelaxNGTypeCompare) (void *data, const xmlChar *type,
356                                       const xmlChar *value1,
357                                       const xmlChar *value2);
358 typedef struct _xmlRelaxNGTypeLibrary xmlRelaxNGTypeLibrary;
359 typedef xmlRelaxNGTypeLibrary *xmlRelaxNGTypeLibraryPtr;
360 struct _xmlRelaxNGTypeLibrary {
361     const xmlChar     *namespace;       /* the datatypeLibrary value */
362     void                   *data;       /* data needed for the library */
363     xmlRelaxNGTypeHave      have;       /* the export function */
364     xmlRelaxNGTypeCheck    check;       /* the checking function */
365     xmlRelaxNGTypeCompare   comp;       /* the compare function */
366 };
367
368 /************************************************************************
369  *                                                                      *
370  *                      Allocation functions                            *
371  *                                                                      *
372  ************************************************************************/
373 static void xmlRelaxNGFreeGrammar(xmlRelaxNGGrammarPtr grammar);
374 static void xmlRelaxNGFreeDefine(xmlRelaxNGDefinePtr define);
375 static void xmlRelaxNGNormExtSpace(xmlChar *value);
376
377 /**
378  * xmlRelaxNGFreeDocument:
379  * @docu:  a document structure
380  *
381  * Deallocate a RelaxNG document structure.
382  */
383 static void
384 xmlRelaxNGFreeDocument(xmlRelaxNGDocumentPtr docu)
385 {
386     if (docu == NULL)
387         return;
388
389     if (docu->href != NULL)
390         xmlFree(docu->href);
391     if (docu->doc != NULL)
392         xmlFreeDoc(docu->doc);
393     if (docu->schema != NULL)
394         xmlRelaxNGFree(docu->schema);
395     xmlFree(docu);
396 }
397
398 /**
399  * xmlRelaxNGFreeInclude:
400  * @incl:  a include structure
401  *
402  * Deallocate a RelaxNG include structure.
403  */
404 static void
405 xmlRelaxNGFreeInclude(xmlRelaxNGIncludePtr incl)
406 {
407     if (incl == NULL)
408         return;
409
410     if (incl->href != NULL)
411         xmlFree(incl->href);
412     if (incl->doc != NULL)
413         xmlFreeDoc(incl->doc);
414     if (incl->schema != NULL)
415         xmlRelaxNGFree(incl->schema);
416     xmlFree(incl);
417 }
418
419 /**
420  * xmlRelaxNGNewRelaxNG:
421  * @ctxt:  a Relax-NG validation context (optional)
422  *
423  * Allocate a new RelaxNG structure.
424  *
425  * Returns the newly allocated structure or NULL in case or error
426  */
427 static xmlRelaxNGPtr
428 xmlRelaxNGNewRelaxNG(xmlRelaxNGParserCtxtPtr ctxt)
429 {
430     xmlRelaxNGPtr ret;
431
432     ret = (xmlRelaxNGPtr) xmlMalloc(sizeof(xmlRelaxNG));
433     if (ret == NULL) {
434         if ((ctxt != NULL) && (ctxt->error != NULL))
435             ctxt->error(ctxt->userData, "Out of memory\n");
436         ctxt->nbErrors++;
437         return (NULL);
438     }
439     memset(ret, 0, sizeof(xmlRelaxNG));
440
441     return (ret);
442 }
443
444 /**
445  * xmlRelaxNGFree:
446  * @schema:  a schema structure
447  *
448  * Deallocate a RelaxNG structure.
449  */
450 void
451 xmlRelaxNGFree(xmlRelaxNGPtr schema)
452 {
453     if (schema == NULL)
454         return;
455
456     if (schema->topgrammar != NULL)
457         xmlRelaxNGFreeGrammar(schema->topgrammar);
458     if (schema->doc != NULL)
459         xmlFreeDoc(schema->doc);
460     if (schema->documents != NULL)
461         xmlHashFree(schema->documents, (xmlHashDeallocator)
462                 xmlRelaxNGFreeDocument);
463     if (schema->includes != NULL)
464         xmlHashFree(schema->includes, (xmlHashDeallocator)
465                 xmlRelaxNGFreeInclude);
466     if (schema->defTab != NULL) {
467         int i;
468
469         for (i = 0;i < schema->defNr;i++)
470             xmlRelaxNGFreeDefine(schema->defTab[i]);
471         xmlFree(schema->defTab);
472     }
473
474     xmlFree(schema);
475 }
476
477 /**
478  * xmlRelaxNGNewGrammar:
479  * @ctxt:  a Relax-NG validation context (optional)
480  *
481  * Allocate a new RelaxNG grammar.
482  *
483  * Returns the newly allocated structure or NULL in case or error
484  */
485 static xmlRelaxNGGrammarPtr
486 xmlRelaxNGNewGrammar(xmlRelaxNGParserCtxtPtr ctxt)
487 {
488     xmlRelaxNGGrammarPtr ret;
489
490     ret = (xmlRelaxNGGrammarPtr) xmlMalloc(sizeof(xmlRelaxNGGrammar));
491     if (ret == NULL) {
492         if ((ctxt != NULL) && (ctxt->error != NULL))
493             ctxt->error(ctxt->userData, "Out of memory\n");
494         ctxt->nbErrors++;
495         return (NULL);
496     }
497     memset(ret, 0, sizeof(xmlRelaxNGGrammar));
498
499     return (ret);
500 }
501
502 /**
503  * xmlRelaxNGFreeGrammar:
504  * @grammar:  a grammar structure
505  *
506  * Deallocate a RelaxNG grammar structure.
507  */
508 static void
509 xmlRelaxNGFreeGrammar(xmlRelaxNGGrammarPtr grammar)
510 {
511     if (grammar == NULL)
512         return;
513
514     if (grammar->next != NULL) {
515         xmlRelaxNGFreeGrammar(grammar->next);
516     }
517     if (grammar->refs != NULL) {
518         xmlHashFree(grammar->refs, NULL);
519     }
520     if (grammar->defs != NULL) {
521         xmlHashFree(grammar->defs, NULL);
522     }
523
524     xmlFree(grammar);
525 }
526
527 /**
528  * xmlRelaxNGNewDefine:
529  * @ctxt:  a Relax-NG validation context
530  * @node:  the node in the input document.
531  *
532  * Allocate a new RelaxNG define.
533  *
534  * Returns the newly allocated structure or NULL in case or error
535  */
536 static xmlRelaxNGDefinePtr
537 xmlRelaxNGNewDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
538 {
539     xmlRelaxNGDefinePtr ret;
540
541     if (ctxt->defMax == 0) {
542         ctxt->defMax = 16;
543         ctxt->defNr = 0;
544         ctxt->defTab = (xmlRelaxNGDefinePtr *)
545             xmlMalloc(ctxt->defMax * sizeof(xmlRelaxNGDefinePtr));
546         if (ctxt->defTab == NULL) {
547             if ((ctxt != NULL) && (ctxt->error != NULL))
548                 ctxt->error(ctxt->userData, "Out of memory\n");
549             ctxt->nbErrors++;
550             return (NULL);
551         }
552     } else if (ctxt->defMax <= ctxt->defNr) {
553         xmlRelaxNGDefinePtr *tmp;
554         ctxt->defMax *= 2;
555         tmp = (xmlRelaxNGDefinePtr *) xmlRealloc(ctxt->defTab,
556                 ctxt->defMax * sizeof(xmlRelaxNGDefinePtr));
557         if (tmp == NULL) {
558             if ((ctxt != NULL) && (ctxt->error != NULL))
559                 ctxt->error(ctxt->userData, "Out of memory\n");
560             ctxt->nbErrors++;
561             return (NULL);
562         }
563         ctxt->defTab = tmp;
564     }
565     ret = (xmlRelaxNGDefinePtr) xmlMalloc(sizeof(xmlRelaxNGDefine));
566     if (ret == NULL) {
567         if ((ctxt != NULL) && (ctxt->error != NULL))
568             ctxt->error(ctxt->userData, "Out of memory\n");
569         ctxt->nbErrors++;
570         return(NULL);
571     }
572     memset(ret, 0, sizeof(xmlRelaxNGDefine));
573     ctxt->defTab[ctxt->defNr++] = ret;
574     ret->node = node;
575     ret->depth = -1;
576     return (ret);
577 }
578
579 /**
580  * xmlRelaxNGFreePartition:
581  * @partitions:  a partition set structure
582  *
583  * Deallocate RelaxNG partition set structures.
584  */
585 static void
586 xmlRelaxNGFreePartition(xmlRelaxNGPartitionPtr partitions) {
587     xmlRelaxNGInterleaveGroupPtr group;
588     int j;
589
590     if (partitions != NULL) {
591         if (partitions->groups != NULL) {
592             for (j = 0;j < partitions->nbgroups;j++) {
593                 group = partitions->groups[j];
594                 if (group != NULL) {
595                     if (group->defs != NULL)
596                         xmlFree(group->defs);
597                     if (group->attrs != NULL)
598                         xmlFree(group->attrs);
599                     xmlFree(group);
600                 }
601             }
602             xmlFree(partitions->groups);
603         }
604         xmlFree(partitions);
605     }
606 }
607 /**
608  * xmlRelaxNGFreeDefine:
609  * @define:  a define structure
610  *
611  * Deallocate a RelaxNG define structure.
612  */
613 static void
614 xmlRelaxNGFreeDefine(xmlRelaxNGDefinePtr define)
615 {
616     if (define == NULL)
617         return;
618
619     if ((define->data != NULL) &&
620         (define->type == XML_RELAXNG_INTERLEAVE))
621         xmlRelaxNGFreePartition((xmlRelaxNGPartitionPtr) define->data);
622     if (define->name != NULL)
623         xmlFree(define->name);
624     if (define->ns != NULL)
625         xmlFree(define->ns);
626     if (define->value != NULL)
627         xmlFree(define->value);
628     xmlFree(define);
629 }
630
631 /**
632  * xmlRelaxNGNewValidState:
633  * @ctxt:  a Relax-NG validation context
634  * @node:  the current node or NULL for the document
635  *
636  * Allocate a new RelaxNG validation state
637  *
638  * Returns the newly allocated structure or NULL in case or error
639  */
640 static xmlRelaxNGValidStatePtr
641 xmlRelaxNGNewValidState(xmlRelaxNGValidCtxtPtr ctxt, xmlNodePtr node)
642 {
643     xmlRelaxNGValidStatePtr ret;
644     xmlAttrPtr attr;
645     xmlAttrPtr attrs[MAX_ATTR];
646     int nbAttrs = 0;
647     xmlNodePtr root = NULL;
648
649     if (node == NULL) {
650         root = xmlDocGetRootElement(ctxt->doc);
651         if (root == NULL)
652             return(NULL);
653     } else {
654         attr = node->properties;
655         while (attr != NULL) {
656             if (nbAttrs < MAX_ATTR)
657                 attrs[nbAttrs++] = attr;
658             else
659                 nbAttrs++;
660             attr = attr->next;
661         }
662     }
663     
664     if (nbAttrs < MAX_ATTR)
665         attrs[nbAttrs] = NULL;
666     ret = (xmlRelaxNGValidStatePtr) xmlMalloc(sizeof(xmlRelaxNGValidState) +
667                                               nbAttrs * sizeof(xmlAttrPtr));
668     if (ret == NULL) {
669         if ((ctxt != NULL) && (ctxt->error != NULL))
670             ctxt->error(ctxt->userData, "Out of memory\n");
671         return (NULL);
672     }
673     ret->value = NULL;
674     ret->endvalue = NULL;
675     if (node == NULL) {
676         ret->node = (xmlNodePtr) ctxt->doc;
677         ret->seq = root;
678         ret->nbAttrs = 0;
679     } else {
680         ret->node = node;
681         ret->seq = node->children;
682         ret->nbAttrs = nbAttrs;
683         if (nbAttrs > 0) {
684             if (nbAttrs < MAX_ATTR) {
685                 memcpy(&(ret->attrs[0]), attrs,
686                         sizeof(xmlAttrPtr) * (nbAttrs + 1));
687             } else {
688                 attr = node->properties;
689                 nbAttrs = 0;
690                 while (attr != NULL) {
691                     ret->attrs[nbAttrs++] = attr;
692                     attr = attr->next;
693                 }
694                 ret->attrs[nbAttrs] = NULL;
695             }
696         }
697     }
698     ret->nbAttrLeft = ret->nbAttrs;
699     return (ret);
700 }
701
702 /**
703  * xmlRelaxNGCopyValidState:
704  * @ctxt:  a Relax-NG validation context
705  * @state:  a validation state
706  *
707  * Copy the validation state
708  *
709  * Returns the newly allocated structure or NULL in case or error
710  */
711 static xmlRelaxNGValidStatePtr
712 xmlRelaxNGCopyValidState(xmlRelaxNGValidCtxtPtr ctxt,
713                          xmlRelaxNGValidStatePtr state)
714 {
715     xmlRelaxNGValidStatePtr ret;
716     unsigned int size;
717
718     if (state == NULL)
719         return(NULL);
720     
721     size = sizeof(xmlRelaxNGValidState) +
722            state->nbAttrs * sizeof(xmlAttrPtr);
723     ret = (xmlRelaxNGValidStatePtr) xmlMalloc(size);
724     if (ret == NULL) {
725         if ((ctxt != NULL) && (ctxt->error != NULL))
726             ctxt->error(ctxt->userData, "Out of memory\n");
727         return (NULL);
728     }
729     memcpy(ret, state, size);
730     return(ret);
731 }
732
733 /**
734  * xmlRelaxNGEqualValidState:
735  * @ctxt:  a Relax-NG validation context
736  * @state1:  a validation state
737  * @state2:  a validation state
738  *
739  * Compare the validation states for equality
740  *
741  * Returns 1 if equald, 0 otherwise
742  */
743 static int
744 xmlRelaxNGEqualValidState(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
745                          xmlRelaxNGValidStatePtr state1,
746                          xmlRelaxNGValidStatePtr state2)
747 {
748     int i;
749
750     if ((state1 == NULL) || (state2 == NULL))
751         return(0);
752     if (state1 == state2)
753         return(1);
754     if (state1->node != state2->node)
755         return(0);
756     if (state1->seq != state2->seq)
757         return(0);
758     if (state1->nbAttrLeft != state2->nbAttrLeft)
759         return(0);
760     if (state1->nbAttrs != state2->nbAttrs)
761         return(0);
762     if (state1->endvalue != state2->endvalue)
763         return(0);
764     if ((state1->value != state2->value) &&
765         (!xmlStrEqual(state1->value, state2->value)))
766         return(0);
767     for (i = 0;i < state1->nbAttrs;i++) {
768         if (state1->attrs[i] != state2->attrs[i])
769             return(0);
770     }
771     return(1);
772 }
773
774 /**
775  * xmlRelaxNGFreeValidState:
776  * @state:  a validation state structure
777  *
778  * Deallocate a RelaxNG validation state structure.
779  */
780 static void
781 xmlRelaxNGFreeValidState(xmlRelaxNGValidStatePtr state)
782 {
783     if (state == NULL)
784         return;
785
786     xmlFree(state);
787 }
788
789 /************************************************************************
790  *                                                                      *
791  *                      Document functions                                      *
792  *                                                                      *
793  ************************************************************************/
794 static xmlDocPtr xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt,
795                                       xmlDocPtr doc);
796
797 /**
798  * xmlRelaxNGIncludePush:
799  * @ctxt:  the parser context
800  * @value:  the element doc
801  *
802  * Pushes a new include on top of the include stack
803  *
804  * Returns 0 in case of error, the index in the stack otherwise
805  */
806 static int
807 xmlRelaxNGIncludePush(xmlRelaxNGParserCtxtPtr ctxt,
808                        xmlRelaxNGIncludePtr value)
809 {
810     if (ctxt->incTab == NULL) {
811         ctxt->incMax = 4;
812         ctxt->incNr = 0;
813         ctxt->incTab = (xmlRelaxNGIncludePtr *) xmlMalloc(
814                         ctxt->incMax * sizeof(ctxt->incTab[0]));
815         if (ctxt->incTab == NULL) {
816             xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
817             return (0);
818         }
819     }
820     if (ctxt->incNr >= ctxt->incMax) {
821         ctxt->incMax *= 2;
822         ctxt->incTab =
823             (xmlRelaxNGIncludePtr *) xmlRealloc(ctxt->incTab,
824                                       ctxt->incMax *
825                                       sizeof(ctxt->incTab[0]));
826         if (ctxt->incTab == NULL) {
827             xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
828             return (0);
829         }
830     }
831     ctxt->incTab[ctxt->incNr] = value;
832     ctxt->inc = value;
833     return (ctxt->incNr++);
834 }
835
836 /**
837  * xmlRelaxNGIncludePop:
838  * @ctxt: the parser context
839  *
840  * Pops the top include from the include stack
841  *
842  * Returns the include just removed
843  */
844 static xmlRelaxNGIncludePtr
845 xmlRelaxNGIncludePop(xmlRelaxNGParserCtxtPtr ctxt)
846 {
847     xmlRelaxNGIncludePtr ret;
848
849     if (ctxt->incNr <= 0)
850         return (0);
851     ctxt->incNr--;
852     if (ctxt->incNr > 0)
853         ctxt->inc = ctxt->incTab[ctxt->incNr - 1];
854     else
855         ctxt->inc = NULL;
856     ret = ctxt->incTab[ctxt->incNr];
857     ctxt->incTab[ctxt->incNr] = 0;
858     return (ret);
859 }
860
861 /**
862  * xmlRelaxNGLoadInclude:
863  * @ctxt: the parser context
864  * @URL:  the normalized URL
865  * @node: the include node.
866  * @ns:  the namespace passed from the context.
867  *
868  * First lookup if the document is already loaded into the parser context,
869  * check against recursion. If not found the resource is loaded and
870  * the content is preprocessed before being returned back to the caller.
871  *
872  * Returns the xmlRelaxNGIncludePtr or NULL in case of error
873  */
874 static xmlRelaxNGIncludePtr
875 xmlRelaxNGLoadInclude(xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *URL,
876                       xmlNodePtr node, const xmlChar *ns) {
877     xmlRelaxNGIncludePtr ret = NULL;
878     xmlDocPtr doc;
879     int i;
880     xmlNodePtr root, tmp, tmp2, cur;
881
882     /*
883      * check against recursion in the stack
884      */
885     for (i = 0;i < ctxt->incNr;i++) {
886         if (xmlStrEqual(ctxt->incTab[i]->href, URL)) {
887             if (ctxt->error != NULL)
888                 ctxt->error(ctxt->userData,
889                     "Detected an externalRef recursion for %s\n",
890                             URL);
891             ctxt->nbErrors++;
892             return(NULL);
893         }
894     }
895
896     /*
897      * Lookup in the hash table
898      */
899     if (ctxt->includes == NULL) {
900         ctxt->includes = xmlHashCreate(10);
901         if (ctxt->includes == NULL) {
902             if (ctxt->error != NULL)
903                 ctxt->error(ctxt->userData,
904                     "Failed to allocate hash table for document\n");
905             ctxt->nbErrors++;
906             return(NULL);
907         }
908     } else {
909         if (ns == NULL)
910             ret = xmlHashLookup2(ctxt->includes, BAD_CAST "", URL);
911         else
912             ret = xmlHashLookup2(ctxt->includes, ns, URL);
913         if (ret != NULL)
914             return(ret);
915     }
916
917
918     /*
919      * load the document
920      */
921     doc = xmlParseFile((const char *) URL);
922     if (doc == NULL) {
923         if (ctxt->error != NULL)
924             ctxt->error(ctxt->userData,
925                         "xmlRelaxNG: could not load %s\n", URL);
926         ctxt->nbErrors++;
927         return (NULL);
928     }
929
930     /*
931      * Allocate the document structures and register it first.
932      */
933     ret = (xmlRelaxNGIncludePtr) xmlMalloc(sizeof(xmlRelaxNGInclude));
934     if (ret == NULL) {
935         if (ctxt->error != NULL)
936             ctxt->error(ctxt->userData,
937                         "xmlRelaxNG: allocate memory for doc %s\n", URL);
938         ctxt->nbErrors++;
939         xmlFreeDoc(doc);
940         return (NULL);
941     }
942     memset(ret, 0, sizeof(xmlRelaxNGInclude));
943     ret->doc = doc;
944     ret->href = xmlStrdup(URL);
945
946     /*
947      * transmit the ns if needed
948      */
949     if (ns != NULL) {
950         root = xmlDocGetRootElement(doc);
951         if (root != NULL) {
952             if (xmlHasProp(root, BAD_CAST"ns") == NULL) {
953                 xmlSetProp(root, BAD_CAST"ns", ns);
954             }
955         }
956     }
957
958     /*
959      * push it on the stack and register it in the hash table
960      */
961     if (ns == NULL)
962         xmlHashAddEntry2(ctxt->includes, BAD_CAST "", URL, ret);
963     else
964         xmlHashAddEntry2(ctxt->includes, ns, URL, ret);
965     xmlRelaxNGIncludePush(ctxt, ret);
966
967     /*
968      * Some preprocessing of the document content, this include recursing
969      * in the include stack.
970      */
971     doc = xmlRelaxNGCleanupDoc(ctxt, doc);
972     if (doc == NULL) {
973         ctxt->inc = NULL;
974         return(NULL);
975     }
976
977     /*
978      * Pop up the include from the stack
979      */
980     xmlRelaxNGIncludePop(ctxt);
981
982     /*
983      * Check that the top element is a grammar
984      */
985     root = xmlDocGetRootElement(doc);
986     if (root == NULL) {
987         if (ctxt->error != NULL)
988             ctxt->error(ctxt->userData,
989                         "xmlRelaxNG: included document is empty %s\n", URL);
990         ctxt->nbErrors++;
991         return (NULL);
992     }
993     if (!IS_RELAXNG(root, "grammar")) {
994         if (ctxt->error != NULL)
995             ctxt->error(ctxt->userData,
996                     "xmlRelaxNG: included document %s root is not a grammar\n",
997                         URL);
998         ctxt->nbErrors++;
999         return (NULL);
1000     }
1001
1002     /*
1003      * Elimination of redefined rules in the include.
1004      */
1005     cur = node->children;
1006     while (cur != NULL) {
1007         if (IS_RELAXNG(cur, "start")) {
1008             int found = 0;
1009
1010             tmp = root->children;
1011             while (tmp != NULL) {
1012                 tmp2 = tmp->next;
1013                 if (IS_RELAXNG(tmp, "start")) {
1014                     found = 1;
1015                     xmlUnlinkNode(tmp);
1016                     xmlFreeNode(tmp);
1017                 }
1018                 tmp = tmp2;
1019             }
1020             if (!found) {
1021                 if (ctxt->error != NULL)
1022                     ctxt->error(ctxt->userData,
1023         "xmlRelaxNG: include %s has a start but not the included grammar\n",
1024                                 URL);
1025                 ctxt->nbErrors++;
1026             }
1027         } else if (IS_RELAXNG(cur, "define")) {
1028             xmlChar *name, *name2;
1029
1030             name = xmlGetProp(cur, BAD_CAST "name");
1031             if (name == NULL) {
1032                 if (ctxt->error != NULL)
1033                     ctxt->error(ctxt->userData,
1034                             "xmlRelaxNG: include %s has define without name\n",
1035                                 URL);
1036                 ctxt->nbErrors++;
1037             } else {
1038                 int found = 0;
1039
1040                 xmlRelaxNGNormExtSpace(name);
1041                 tmp = root->children;
1042                 while (tmp != NULL) {
1043                     tmp2 = tmp->next;
1044                     if (IS_RELAXNG(tmp, "define")) {
1045                         name2 = xmlGetProp(tmp, BAD_CAST "name");
1046                         xmlRelaxNGNormExtSpace(name2);
1047                         if (name2 != NULL) {
1048                             if (xmlStrEqual(name, name2)) {
1049                                 found = 1;
1050                                 xmlUnlinkNode(tmp);
1051                                 xmlFreeNode(tmp);
1052                             }
1053                             xmlFree(name2);
1054                         }
1055                     }
1056                     tmp = tmp2;
1057                 }
1058                 if (!found) {
1059                     if (ctxt->error != NULL)
1060                         ctxt->error(ctxt->userData,
1061     "xmlRelaxNG: include %s has a define %s but not the included grammar\n",
1062                                     URL, name);
1063                     ctxt->nbErrors++;
1064                 }
1065                 xmlFree(name);
1066             }
1067         }
1068         cur = cur->next;
1069     }
1070
1071
1072     return(ret);
1073 }
1074
1075 /**
1076  * xmlRelaxNGDocumentPush:
1077  * @ctxt:  the parser context
1078  * @value:  the element doc
1079  *
1080  * Pushes a new doc on top of the doc stack
1081  *
1082  * Returns 0 in case of error, the index in the stack otherwise
1083  */
1084 static int
1085 xmlRelaxNGDocumentPush(xmlRelaxNGParserCtxtPtr ctxt,
1086                        xmlRelaxNGDocumentPtr value)
1087 {
1088     if (ctxt->docTab == NULL) {
1089         ctxt->docMax = 4;
1090         ctxt->docNr = 0;
1091         ctxt->docTab = (xmlRelaxNGDocumentPtr *) xmlMalloc(
1092                         ctxt->docMax * sizeof(ctxt->docTab[0]));
1093         if (ctxt->docTab == NULL) {
1094             xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
1095             return (0);
1096         }
1097     }
1098     if (ctxt->docNr >= ctxt->docMax) {
1099         ctxt->docMax *= 2;
1100         ctxt->docTab =
1101             (xmlRelaxNGDocumentPtr *) xmlRealloc(ctxt->docTab,
1102                                       ctxt->docMax *
1103                                       sizeof(ctxt->docTab[0]));
1104         if (ctxt->docTab == NULL) {
1105             xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
1106             return (0);
1107         }
1108     }
1109     ctxt->docTab[ctxt->docNr] = value;
1110     ctxt->doc = value;
1111     return (ctxt->docNr++);
1112 }
1113
1114 /**
1115  * xmlRelaxNGDocumentPop:
1116  * @ctxt: the parser context
1117  *
1118  * Pops the top doc from the doc stack
1119  *
1120  * Returns the doc just removed
1121  */
1122 static xmlRelaxNGDocumentPtr
1123 xmlRelaxNGDocumentPop(xmlRelaxNGParserCtxtPtr ctxt)
1124 {
1125     xmlRelaxNGDocumentPtr ret;
1126
1127     if (ctxt->docNr <= 0)
1128         return (0);
1129     ctxt->docNr--;
1130     if (ctxt->docNr > 0)
1131         ctxt->doc = ctxt->docTab[ctxt->docNr - 1];
1132     else
1133         ctxt->doc = NULL;
1134     ret = ctxt->docTab[ctxt->docNr];
1135     ctxt->docTab[ctxt->docNr] = 0;
1136     return (ret);
1137 }
1138
1139 /**
1140  * xmlRelaxNGLoadExternalRef:
1141  * @ctxt: the parser context
1142  * @URL:  the normalized URL
1143  * @ns:  the inherited ns if any
1144  *
1145  * First lookup if the document is already loaded into the parser context,
1146  * check against recursion. If not found the resource is loaded and
1147  * the content is preprocessed before being returned back to the caller.
1148  *
1149  * Returns the xmlRelaxNGDocumentPtr or NULL in case of error
1150  */
1151 static xmlRelaxNGDocumentPtr
1152 xmlRelaxNGLoadExternalRef(xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *URL,
1153                        const xmlChar *ns) {
1154     xmlRelaxNGDocumentPtr ret = NULL;
1155     xmlDocPtr doc;
1156     xmlNodePtr root;
1157     int i;
1158
1159     /*
1160      * check against recursion in the stack
1161      */
1162     for (i = 0;i < ctxt->docNr;i++) {
1163         if (xmlStrEqual(ctxt->docTab[i]->href, URL)) {
1164             if (ctxt->error != NULL)
1165                 ctxt->error(ctxt->userData,
1166                     "Detected an externalRef recursion for %s\n",
1167                             URL);
1168             ctxt->nbErrors++;
1169             return(NULL);
1170         }
1171     }
1172
1173     /*
1174      * Lookup in the hash table
1175      */
1176     if (ctxt->documents == NULL) {
1177         ctxt->documents = xmlHashCreate(10);
1178         if (ctxt->documents == NULL) {
1179             if (ctxt->error != NULL)
1180                 ctxt->error(ctxt->userData,
1181                     "Failed to allocate hash table for document\n");
1182             ctxt->nbErrors++;
1183             return(NULL);
1184         }
1185     } else {
1186         if (ns == NULL)
1187             ret = xmlHashLookup2(ctxt->documents, BAD_CAST "", URL);
1188         else
1189             ret = xmlHashLookup2(ctxt->documents, ns, URL);
1190         if (ret != NULL)
1191             return(ret);
1192     }
1193
1194
1195     /*
1196      * load the document
1197      */
1198     doc = xmlParseFile((const char *) URL);
1199     if (doc == NULL) {
1200         if (ctxt->error != NULL)
1201             ctxt->error(ctxt->userData,
1202                         "xmlRelaxNG: could not load %s\n", URL);
1203         ctxt->nbErrors++;
1204         return (NULL);
1205     }
1206
1207     /*
1208      * Allocate the document structures and register it first.
1209      */
1210     ret = (xmlRelaxNGDocumentPtr) xmlMalloc(sizeof(xmlRelaxNGDocument));
1211     if (ret == NULL) {
1212         if (ctxt->error != NULL)
1213             ctxt->error(ctxt->userData,
1214                         "xmlRelaxNG: allocate memory for doc %s\n", URL);
1215         ctxt->nbErrors++;
1216         xmlFreeDoc(doc);
1217         return (NULL);
1218     }
1219     memset(ret, 0, sizeof(xmlRelaxNGDocument));
1220     ret->doc = doc;
1221     ret->href = xmlStrdup(URL);
1222
1223     /*
1224      * transmit the ns if needed
1225      */
1226     if (ns != NULL) {
1227         root = xmlDocGetRootElement(doc);
1228         if (root != NULL) {
1229             if (xmlHasProp(root, BAD_CAST"ns") == NULL) {
1230                 xmlSetProp(root, BAD_CAST"ns", ns);
1231             }
1232         }
1233     }
1234
1235     /*
1236      * push it on the stack and register it in the hash table
1237      */
1238     if (ns == NULL)
1239         xmlHashAddEntry2(ctxt->documents, BAD_CAST "", URL, ret);
1240     else
1241         xmlHashAddEntry2(ctxt->documents, ns, URL, ret);
1242     xmlRelaxNGDocumentPush(ctxt, ret);
1243
1244     /*
1245      * Some preprocessing of the document content
1246      */
1247     doc = xmlRelaxNGCleanupDoc(ctxt, doc);
1248     if (doc == NULL) {
1249         ctxt->doc = NULL;
1250         return(NULL);
1251     }
1252
1253     xmlRelaxNGDocumentPop(ctxt);
1254
1255     return(ret);
1256 }
1257
1258 /************************************************************************
1259  *                                                                      *
1260  *                      Error functions                                 *
1261  *                                                                      *
1262  ************************************************************************/
1263
1264 #define VALID_CTXT()                                                    \
1265     if (((ctxt->flags & 1) == 0) || (ctxt->flags & 2))                  \
1266          xmlGenericError(xmlGenericErrorContext,                        \
1267             "error detected at %s:%d\n",                                \
1268             __FILE__, __LINE__);
1269
1270 #define VALID_ERROR(a)                                                  \
1271     if (((ctxt->flags & 1) == 0) || (ctxt->flags & 2))                  \
1272         if (ctxt->error != NULL) ctxt->error(ctxt->userData, a)
1273 #define VALID_ERROR2(a, b)                                              \
1274     if (((ctxt->flags & 1) == 0) || (ctxt->flags & 2))                  \
1275         if (ctxt->error != NULL) ctxt->error(ctxt->userData, a, b)
1276 #define VALID_ERROR3(a, b, c)                                           \
1277     if (((ctxt->flags & 1) == 0) || (ctxt->flags & 2))                  \
1278         if (ctxt->error != NULL) ctxt->error(ctxt->userData, a, b, c)
1279
1280 #ifdef DEBUG
1281 static const char *
1282 xmlRelaxNGDefName(xmlRelaxNGDefinePtr def) {
1283     if (def == NULL)
1284         return("none");
1285     switch(def->type) {
1286         case XML_RELAXNG_EMPTY: return("empty");
1287         case XML_RELAXNG_NOT_ALLOWED: return("notAllowed");
1288         case XML_RELAXNG_EXCEPT: return("except");
1289         case XML_RELAXNG_TEXT: return("text");
1290         case XML_RELAXNG_ELEMENT: return("element");
1291         case XML_RELAXNG_DATATYPE: return("datatype");
1292         case XML_RELAXNG_VALUE: return("value");
1293         case XML_RELAXNG_LIST: return("list");
1294         case XML_RELAXNG_ATTRIBUTE: return("attribute");
1295         case XML_RELAXNG_DEF: return("def");
1296         case XML_RELAXNG_REF: return("ref");
1297         case XML_RELAXNG_EXTERNALREF: return("externalRef");
1298         case XML_RELAXNG_PARENTREF: return("parentRef");
1299         case XML_RELAXNG_OPTIONAL: return("optional");
1300         case XML_RELAXNG_ZEROORMORE: return("zeroOrMore");
1301         case XML_RELAXNG_ONEORMORE: return("oneOrMore");
1302         case XML_RELAXNG_CHOICE: return("choice");
1303         case XML_RELAXNG_GROUP: return("group");
1304         case XML_RELAXNG_INTERLEAVE: return("interleave");
1305         case XML_RELAXNG_START: return("start");
1306     }
1307     return("unknown");
1308 }
1309 #endif
1310
1311 #if 0
1312 /**
1313  * xmlRelaxNGErrorContext:
1314  * @ctxt:  the parsing context
1315  * @schema:  the schema being built
1316  * @node:  the node being processed
1317  * @child:  the child being processed
1318  *
1319  * Dump a RelaxNGType structure
1320  */
1321 static void
1322 xmlRelaxNGErrorContext(xmlRelaxNGParserCtxtPtr ctxt, xmlRelaxNGPtr schema,
1323                       xmlNodePtr node, xmlNodePtr child)
1324 {
1325     int line = 0;
1326     const xmlChar *file = NULL;
1327     const xmlChar *name = NULL;
1328     const char *type = "error";
1329
1330     if ((ctxt == NULL) || (ctxt->error == NULL))
1331         return;
1332
1333     if (child != NULL)
1334         node = child;
1335
1336     if (node != NULL)  {
1337         if ((node->type == XML_DOCUMENT_NODE) ||
1338             (node->type == XML_HTML_DOCUMENT_NODE)) {
1339             xmlDocPtr doc = (xmlDocPtr) node;
1340
1341             file = doc->URL;
1342         } else {
1343             /*
1344              * Try to find contextual informations to report
1345              */
1346             if (node->type == XML_ELEMENT_NODE) {
1347                 line = (int) node->content;
1348             } else if ((node->prev != NULL) &&
1349                        (node->prev->type == XML_ELEMENT_NODE)) {
1350                 line = (int) node->prev->content;
1351             } else if ((node->parent != NULL) &&
1352                        (node->parent->type == XML_ELEMENT_NODE)) {
1353                 line = (int) node->parent->content;
1354             }
1355             if ((node->doc != NULL) && (node->doc->URL != NULL))
1356                 file = node->doc->URL;
1357             if (node->name != NULL)
1358                 name = node->name;
1359         }
1360     } 
1361     
1362     if (ctxt != NULL)
1363         type = "compilation error";
1364     else if (schema != NULL)
1365         type = "runtime error";
1366
1367     if ((file != NULL) && (line != 0) && (name != NULL))
1368         ctxt->error(ctxt->userData, "%s: file %s line %d element %s\n",
1369                 type, file, line, name);
1370     else if ((file != NULL) && (name != NULL))
1371         ctxt->error(ctxt->userData, "%s: file %s element %s\n",
1372                 type, file, name);
1373     else if ((file != NULL) && (line != 0))
1374         ctxt->error(ctxt->userData, "%s: file %s line %d\n", type, file, line);
1375     else if (file != NULL)
1376         ctxt->error(ctxt->userData, "%s: file %s\n", type, file);
1377     else if (name != NULL)
1378         ctxt->error(ctxt->userData, "%s: element %s\n", type, name);
1379     else
1380         ctxt->error(ctxt->userData, "%s\n", type);
1381 }
1382 #endif
1383
1384 /************************************************************************
1385  *                                                                      *
1386  *                      Type library hooks                              *
1387  *                                                                      *
1388  ************************************************************************/
1389 static xmlChar *xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt,
1390                                     const xmlChar *str);
1391
1392 /**
1393  * xmlRelaxNGSchemaTypeHave:
1394  * @data:  data needed for the library
1395  * @type:  the type name
1396  *
1397  * Check if the given type is provided by
1398  * the W3C XMLSchema Datatype library.
1399  *
1400  * Returns 1 if yes, 0 if no and -1 in case of error.
1401  */
1402 static int
1403 xmlRelaxNGSchemaTypeHave(void *data ATTRIBUTE_UNUSED,
1404                          const xmlChar *type) {
1405     xmlSchemaTypePtr typ;
1406
1407     if (type == NULL)
1408         return(-1);
1409     typ = xmlSchemaGetPredefinedType(type, 
1410                BAD_CAST "http://www.w3.org/2001/XMLSchema");
1411     if (typ == NULL)
1412         return(0);
1413     return(1);
1414 }
1415
1416 /**
1417  * xmlRelaxNGSchemaTypeCheck:
1418  * @data:  data needed for the library
1419  * @type:  the type name
1420  * @value:  the value to check
1421  *
1422  * Check if the given type and value are validated by
1423  * the W3C XMLSchema Datatype library.
1424  *
1425  * Returns 1 if yes, 0 if no and -1 in case of error.
1426  */
1427 static int
1428 xmlRelaxNGSchemaTypeCheck(void *data ATTRIBUTE_UNUSED,
1429                           const xmlChar *type,
1430                           const xmlChar *value) {
1431     xmlSchemaTypePtr typ;
1432     int ret;
1433
1434     /*
1435      * TODO: the type should be cached ab provided back, interface subject
1436      * to changes.
1437      * TODO: handle facets, may require an additional interface and keep
1438      * the value returned from the validation.
1439      */
1440     if ((type == NULL) || (value == NULL))
1441         return(-1);
1442     typ = xmlSchemaGetPredefinedType(type, 
1443                BAD_CAST "http://www.w3.org/2001/XMLSchema");
1444     if (typ == NULL)
1445         return(-1);
1446     ret = xmlSchemaValidatePredefinedType(typ, value, NULL);
1447     if (ret == 0)
1448         return(1);
1449     if (ret > 0)
1450         return(0);
1451     return(-1);
1452 }
1453
1454 /**
1455  * xmlRelaxNGSchemaTypeCompare:
1456  * @data:  data needed for the library
1457  * @type:  the type name
1458  * @value1:  the first value
1459  * @value2:  the second value
1460  *
1461  * Compare two values accordingly a type from the W3C XMLSchema
1462  * Datatype library.
1463  *
1464  * Returns 1 if yes, 0 if no and -1 in case of error.
1465  */
1466 static int
1467 xmlRelaxNGSchemaTypeCompare(void *data ATTRIBUTE_UNUSED,
1468                             const xmlChar *type ATTRIBUTE_UNUSED,
1469                             const xmlChar *value1 ATTRIBUTE_UNUSED,
1470                             const xmlChar *value2 ATTRIBUTE_UNUSED) {
1471     TODO
1472     return(1);
1473 }
1474  
1475 /**
1476  * xmlRelaxNGDefaultTypeHave:
1477  * @data:  data needed for the library
1478  * @type:  the type name
1479  *
1480  * Check if the given type is provided by
1481  * the default datatype library.
1482  *
1483  * Returns 1 if yes, 0 if no and -1 in case of error.
1484  */
1485 static int
1486 xmlRelaxNGDefaultTypeHave(void *data ATTRIBUTE_UNUSED, const xmlChar *type) {
1487     if (type == NULL)
1488         return(-1);
1489     if (xmlStrEqual(type, BAD_CAST "string"))
1490         return(1);
1491     if (xmlStrEqual(type, BAD_CAST "token"))
1492         return(1);
1493     return(0);
1494 }
1495
1496 /**
1497  * xmlRelaxNGDefaultTypeCheck:
1498  * @data:  data needed for the library
1499  * @type:  the type name
1500  * @value:  the value to check
1501  *
1502  * Check if the given type and value are validated by
1503  * the default datatype library.
1504  *
1505  * Returns 1 if yes, 0 if no and -1 in case of error.
1506  */
1507 static int
1508 xmlRelaxNGDefaultTypeCheck(void *data ATTRIBUTE_UNUSED,
1509                            const xmlChar *type ATTRIBUTE_UNUSED,
1510                           const xmlChar *value ATTRIBUTE_UNUSED) {
1511     if (value == NULL)
1512         return(-1);
1513     if (xmlStrEqual(type, BAD_CAST "string"))
1514         return(1);
1515     if (xmlStrEqual(type, BAD_CAST "token")) {
1516 #if 0
1517         const xmlChar *cur = value;
1518
1519         while (*cur != 0) {
1520             if (!IS_BLANK(*cur))
1521                 return(1);
1522             cur++;
1523         }
1524 #endif
1525         return(1);
1526     }
1527
1528     return(0);
1529 }
1530
1531 /**
1532  * xmlRelaxNGDefaultTypeCompare:
1533  * @data:  data needed for the library
1534  * @type:  the type name
1535  * @value1:  the first value
1536  * @value2:  the second value
1537  *
1538  * Compare two values accordingly a type from the default
1539  * datatype library.
1540  *
1541  * Returns 1 if yes, 0 if no and -1 in case of error.
1542  */
1543 static int
1544 xmlRelaxNGDefaultTypeCompare(void *data ATTRIBUTE_UNUSED,
1545                              const xmlChar *type ATTRIBUTE_UNUSED,
1546                              const xmlChar *value1 ATTRIBUTE_UNUSED,
1547                              const xmlChar *value2 ATTRIBUTE_UNUSED) {
1548     int ret = -1;
1549
1550     if (xmlStrEqual(type, BAD_CAST "string")) {
1551         ret = xmlStrEqual(value1, value2);
1552     } else if (xmlStrEqual(type, BAD_CAST "token")) {
1553         if (!xmlStrEqual(value1, value2)) {
1554             xmlChar *nval, *nvalue;
1555
1556             /*
1557              * TODO: trivial optimizations are possible by
1558              * computing at compile-time
1559              */
1560             nval = xmlRelaxNGNormalize(NULL, value1);
1561             nvalue = xmlRelaxNGNormalize(NULL, value2);
1562
1563             if ((nval == NULL) || (nvalue == NULL))
1564                 ret = -1;
1565             else if (xmlStrEqual(nval, nvalue))
1566                 ret = 1;
1567             else
1568                 ret = 0;
1569             if (nval != NULL)
1570                 xmlFree(nval);
1571             if (nvalue != NULL)
1572                 xmlFree(nvalue);
1573         } else
1574             ret = 1;
1575     }
1576     return(ret);
1577 }
1578  
1579 static int xmlRelaxNGTypeInitialized = 0;
1580 static xmlHashTablePtr xmlRelaxNGRegisteredTypes = NULL;
1581
1582 /**
1583  * xmlRelaxNGFreeTypeLibrary:
1584  * @lib:  the type library structure
1585  * @namespace:  the URI bound to the library
1586  *
1587  * Free the structure associated to the type library
1588  */
1589 static void
1590 xmlRelaxNGFreeTypeLibrary(xmlRelaxNGTypeLibraryPtr lib,
1591                           const xmlChar *namespace ATTRIBUTE_UNUSED) {
1592     if (lib == NULL)
1593         return;
1594     if (lib->namespace != NULL)
1595         xmlFree((xmlChar *)lib->namespace);
1596     xmlFree(lib);
1597 }
1598
1599 /**
1600  * xmlRelaxNGRegisterTypeLibrary:
1601  * @namespace:  the URI bound to the library
1602  * @data:  data associated to the library
1603  * @have:  the provide function
1604  * @check:  the checking function
1605  * @comp:  the comparison function
1606  *
1607  * Register a new type library
1608  *
1609  * Returns 0 in case of success and -1 in case of error.
1610  */
1611 static int
1612 xmlRelaxNGRegisterTypeLibrary(const xmlChar *namespace, void *data,
1613     xmlRelaxNGTypeHave have, xmlRelaxNGTypeCheck check,
1614     xmlRelaxNGTypeCompare comp) {
1615     xmlRelaxNGTypeLibraryPtr lib;
1616     int ret;
1617
1618     if ((xmlRelaxNGRegisteredTypes == NULL) || (namespace == NULL) ||
1619         (check == NULL) || (comp == NULL))
1620         return(-1);
1621     if (xmlHashLookup(xmlRelaxNGRegisteredTypes, namespace) != NULL) {
1622         xmlGenericError(xmlGenericErrorContext,
1623                 "Relax-NG types library '%s' already registered\n",
1624                         namespace);
1625         return(-1);
1626     }
1627     lib = (xmlRelaxNGTypeLibraryPtr) xmlMalloc(sizeof(xmlRelaxNGTypeLibrary));
1628     if (lib == NULL) {
1629         xmlGenericError(xmlGenericErrorContext,
1630                 "Relax-NG types library '%s' malloc() failed\n",
1631                         namespace);
1632         return (-1);
1633     }
1634     memset(lib, 0, sizeof(xmlRelaxNGTypeLibrary));
1635     lib->namespace = xmlStrdup(namespace);
1636     lib->data = data;
1637     lib->have = have;
1638     lib->comp = comp;
1639     lib->check = check;
1640     ret = xmlHashAddEntry(xmlRelaxNGRegisteredTypes, namespace, lib);
1641     if (ret < 0) {
1642         xmlGenericError(xmlGenericErrorContext,
1643                 "Relax-NG types library failed to register '%s'\n",
1644                         namespace);
1645         xmlRelaxNGFreeTypeLibrary(lib, namespace);
1646         return(-1);
1647     }
1648     return(0);
1649 }
1650
1651 /**
1652  * xmlRelaxNGInitTypes:
1653  *
1654  * Initilize the default type libraries.
1655  *
1656  * Returns 0 in case of success and -1 in case of error.
1657  */
1658 static int
1659 xmlRelaxNGInitTypes(void) {
1660     if (xmlRelaxNGTypeInitialized != 0)
1661         return(0);
1662     xmlRelaxNGRegisteredTypes = xmlHashCreate(10);
1663     if (xmlRelaxNGRegisteredTypes == NULL) {
1664         xmlGenericError(xmlGenericErrorContext,
1665                 "Failed to allocate sh table for Relax-NG types\n");
1666         return(-1);
1667     }
1668     xmlRelaxNGRegisterTypeLibrary(
1669             BAD_CAST "http://www.w3.org/2001/XMLSchema-datatypes",
1670             NULL,
1671             xmlRelaxNGSchemaTypeHave,
1672             xmlRelaxNGSchemaTypeCheck,
1673             xmlRelaxNGSchemaTypeCompare);
1674     xmlRelaxNGRegisterTypeLibrary(
1675             xmlRelaxNGNs,
1676             NULL,
1677             xmlRelaxNGDefaultTypeHave,
1678             xmlRelaxNGDefaultTypeCheck,
1679             xmlRelaxNGDefaultTypeCompare);
1680     xmlRelaxNGTypeInitialized = 1;
1681     return(0);
1682 }
1683
1684 /**
1685  * xmlRelaxNGCleanupTypes:
1686  *
1687  * Cleanup the default Schemas type library associated to RelaxNG
1688  */
1689 void    
1690 xmlRelaxNGCleanupTypes(void) {
1691     if (xmlRelaxNGTypeInitialized == 0)
1692         return;
1693     xmlSchemaCleanupTypes();
1694     xmlHashFree(xmlRelaxNGRegisteredTypes, (xmlHashDeallocator)
1695                 xmlRelaxNGFreeTypeLibrary);
1696     xmlRelaxNGTypeInitialized = 0;
1697 }
1698
1699 /************************************************************************
1700  *                                                                      *
1701  *                      Parsing functions                               *
1702  *                                                                      *
1703  ************************************************************************/
1704
1705 static xmlRelaxNGDefinePtr xmlRelaxNGParseAttribute(
1706               xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node);
1707 static xmlRelaxNGDefinePtr xmlRelaxNGParseElement(
1708               xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node);
1709 static xmlRelaxNGDefinePtr xmlRelaxNGParsePatterns(
1710               xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes, int group);
1711 static xmlRelaxNGDefinePtr xmlRelaxNGParsePattern(
1712               xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node);
1713 static xmlRelaxNGPtr xmlRelaxNGParseDocument(
1714               xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node);
1715 static int xmlRelaxNGParseGrammarContent(
1716               xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes);
1717 static xmlRelaxNGDefinePtr xmlRelaxNGParseNameClass(
1718               xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node,
1719               xmlRelaxNGDefinePtr def);
1720 static xmlRelaxNGGrammarPtr xmlRelaxNGParseGrammar(
1721               xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes);
1722 static int xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt, 
1723               xmlRelaxNGDefinePtr define, xmlNodePtr elem);
1724
1725
1726 #define IS_BLANK_NODE(n)                                                \
1727     (((n)->type == XML_TEXT_NODE) && (xmlRelaxNGIsBlank((n)->content)))
1728
1729 /**
1730  * xmlRelaxNGIsBlank:
1731  * @str:  a string
1732  *
1733  * Check if a string is ignorable c.f. 4.2. Whitespace
1734  *
1735  * Returns 1 if the string is NULL or made of blanks chars, 0 otherwise
1736  */
1737 static int
1738 xmlRelaxNGIsBlank(xmlChar *str) {
1739     if (str == NULL)
1740         return(1);
1741     while (*str != 0) {
1742         if (!(IS_BLANK(*str))) return(0);
1743         str++;
1744     }
1745     return(1);
1746 }
1747
1748 /**
1749  * xmlRelaxNGGetDataTypeLibrary:
1750  * @ctxt:  a Relax-NG parser context
1751  * @node:  the current data or value element
1752  *
1753  * Applies algorithm from 4.3. datatypeLibrary attribute
1754  *
1755  * Returns the datatypeLibary value or NULL if not found
1756  */
1757 static xmlChar *
1758 xmlRelaxNGGetDataTypeLibrary(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
1759                              xmlNodePtr node) {
1760     xmlChar *ret, *escape;
1761
1762     if ((IS_RELAXNG(node, "data")) || (IS_RELAXNG(node, "value"))) {
1763         ret = xmlGetProp(node, BAD_CAST "datatypeLibrary");
1764         if (ret != NULL) {
1765             if (ret[0] == 0) {
1766                 xmlFree(ret);
1767                 return(NULL);
1768             }
1769             escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?");
1770             if (escape == NULL) {
1771                 return(ret);
1772             }
1773             xmlFree(ret);
1774             return(escape);
1775         }
1776     }
1777     node = node->parent;
1778     while ((node != NULL) && (node->type == XML_ELEMENT_NODE)) {
1779         ret = xmlGetProp(node, BAD_CAST "datatypeLibrary");
1780         if (ret != NULL) {
1781             if (ret[0] == 0) {
1782                 xmlFree(ret);
1783                 return(NULL);
1784             }
1785             escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?");
1786             if (escape == NULL) {
1787                 return(ret);
1788             }
1789             xmlFree(ret);
1790             return(escape);
1791         }
1792         node = node->parent;
1793     }
1794     return(NULL);
1795 }
1796
1797 /**
1798  * xmlRelaxNGParseValue:
1799  * @ctxt:  a Relax-NG parser context
1800  * @node:  the data node.
1801  *
1802  * parse the content of a RelaxNG value node.
1803  *
1804  * Returns the definition pointer or NULL in case of error
1805  */
1806 static xmlRelaxNGDefinePtr
1807 xmlRelaxNGParseValue(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
1808     xmlRelaxNGDefinePtr def = NULL;
1809     xmlRelaxNGTypeLibraryPtr lib;
1810     xmlChar *type;
1811     xmlChar *library;
1812     int tmp;
1813
1814     def = xmlRelaxNGNewDefine(ctxt, node);
1815     if (def == NULL)
1816         return(NULL);
1817     def->type = XML_RELAXNG_VALUE;
1818
1819     type = xmlGetProp(node, BAD_CAST "type");
1820     if (type != NULL) {
1821         xmlRelaxNGNormExtSpace(type);
1822         if (xmlValidateNCName(type, 0)) {
1823             if (ctxt->error != NULL)
1824                 ctxt->error(ctxt->userData,
1825                     "value type '%s' is not an NCName\n",
1826                             type);
1827             ctxt->nbErrors++;
1828         }
1829         library = xmlRelaxNGGetDataTypeLibrary(ctxt, node);
1830         if (library == NULL)
1831             library = xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0");
1832
1833         def->name = type;
1834         def->ns = library;
1835
1836         lib = (xmlRelaxNGTypeLibraryPtr)
1837             xmlHashLookup(xmlRelaxNGRegisteredTypes, library);
1838         if (lib == NULL) {
1839             if (ctxt->error != NULL)
1840                 ctxt->error(ctxt->userData,
1841                     "Use of unregistered type library '%s'\n",
1842                             library);
1843             ctxt->nbErrors++;
1844             def->data = NULL;
1845         } else {
1846             def->data = lib;
1847             if (lib->have == NULL) {
1848                 if (ctxt->error != NULL)
1849                     ctxt->error(ctxt->userData,
1850                     "Internal error with type library '%s': no 'have'\n",
1851                             library);
1852                 ctxt->nbErrors++;
1853             } else {
1854                 tmp = lib->have(lib->data, def->name);
1855                 if (tmp != 1) {
1856                     if (ctxt->error != NULL)
1857                         ctxt->error(ctxt->userData,
1858                     "Error type '%s' is not exported by type library '%s'\n",
1859                                 def->name, library);
1860                     ctxt->nbErrors++;
1861                 }
1862             }
1863         }
1864     }
1865     if (node->children == NULL) {
1866         def->value = xmlStrdup(BAD_CAST "");
1867     } else if ((node->children->type != XML_TEXT_NODE) ||
1868                (node->children->next != NULL)) {
1869         if (ctxt->error != NULL)
1870             ctxt->error(ctxt->userData,
1871                 "Expecting a single text value for <value>content\n");
1872         ctxt->nbErrors++;
1873     } else {
1874         def->value = xmlNodeGetContent(node);
1875         if (def->value == NULL) {
1876             if (ctxt->error != NULL)
1877                 ctxt->error(ctxt->userData,
1878                             "Element <value> has no content\n");
1879             ctxt->nbErrors++;
1880         }
1881     }
1882     /* TODO check ahead of time that the value is okay per the type */
1883     return(def);
1884 }
1885
1886 /**
1887  * xmlRelaxNGParseData:
1888  * @ctxt:  a Relax-NG parser context
1889  * @node:  the data node.
1890  *
1891  * parse the content of a RelaxNG data node.
1892  *
1893  * Returns the definition pointer or NULL in case of error
1894  */
1895 static xmlRelaxNGDefinePtr
1896 xmlRelaxNGParseData(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
1897     xmlRelaxNGDefinePtr def = NULL, except, last = NULL;
1898     xmlRelaxNGDefinePtr param, lastparam = NULL;
1899     xmlRelaxNGTypeLibraryPtr lib;
1900     xmlChar *type;
1901     xmlChar *library;
1902     xmlNodePtr content;
1903     int tmp;
1904
1905     type = xmlGetProp(node, BAD_CAST "type");
1906     if (type == NULL) {
1907         if (ctxt->error != NULL)
1908             ctxt->error(ctxt->userData,
1909                         "data has no type\n");
1910         ctxt->nbErrors++;
1911         return(NULL);
1912     }
1913     xmlRelaxNGNormExtSpace(type);
1914     if (xmlValidateNCName(type, 0)) {
1915         if (ctxt->error != NULL)
1916             ctxt->error(ctxt->userData,
1917                 "data type '%s' is not an NCName\n",
1918                         type);
1919         ctxt->nbErrors++;
1920     }
1921     library = xmlRelaxNGGetDataTypeLibrary(ctxt, node);
1922     if (library == NULL)
1923         library = xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0");
1924
1925     def = xmlRelaxNGNewDefine(ctxt, node);
1926     if (def == NULL) {
1927         xmlFree(type);
1928         return(NULL);
1929     }
1930     def->type = XML_RELAXNG_DATATYPE;
1931     def->name = type;
1932     def->ns = library;
1933
1934     lib = (xmlRelaxNGTypeLibraryPtr)
1935         xmlHashLookup(xmlRelaxNGRegisteredTypes, library);
1936     if (lib == NULL) {
1937         if (ctxt->error != NULL)
1938             ctxt->error(ctxt->userData,
1939                 "Use of unregistered type library '%s'\n",
1940                         library);
1941         ctxt->nbErrors++;
1942         def->data = NULL;
1943     } else {
1944         def->data = lib;
1945         if (lib->have == NULL) {
1946             if (ctxt->error != NULL)
1947                 ctxt->error(ctxt->userData,
1948                 "Internal error with type library '%s': no 'have'\n",
1949                         library);
1950             ctxt->nbErrors++;
1951         } else {
1952             tmp = lib->have(lib->data, def->name);
1953             if (tmp != 1) {
1954                 if (ctxt->error != NULL)
1955                     ctxt->error(ctxt->userData,
1956                     "Error type '%s' is not exported by type library '%s'\n",
1957                             def->name, library);
1958                 ctxt->nbErrors++;
1959             }
1960         }
1961     }
1962     content = node->children;
1963
1964     /*
1965      * Handle optional params
1966      */
1967     while (content != NULL) {
1968         if (!xmlStrEqual(content->name, BAD_CAST "param"))
1969             break;
1970         if (xmlStrEqual(library,
1971                         BAD_CAST"http://relaxng.org/ns/structure/1.0")) {
1972             if (ctxt->error != NULL)
1973                 ctxt->error(ctxt->userData,
1974                 "Type library '%s' does not allow type parameters\n",
1975                             library);
1976             ctxt->nbErrors++;
1977             content = content->next;
1978             while ((content != NULL) &&
1979                    (xmlStrEqual(content->name, BAD_CAST "param")))
1980                 content = content->next;
1981         } else {
1982             param = xmlRelaxNGNewDefine(ctxt, node);
1983             if (param != NULL) {
1984                 param->type = XML_RELAXNG_PARAM;
1985                 param->name = xmlGetProp(content, BAD_CAST "name");
1986                 if (param->name == NULL) {
1987                     if (ctxt->error != NULL)
1988                         ctxt->error(ctxt->userData,
1989                             "param has no name\n");
1990                     ctxt->nbErrors++;
1991                 }
1992                 param->value = xmlNodeGetContent(content);
1993                 if (lastparam == NULL) {
1994                     def->attrs = lastparam = param;
1995                 } else {
1996                     lastparam->next = param;
1997                     lastparam = param;
1998                 }
1999             }
2000             content = content->next;
2001         }
2002     }
2003     /*
2004      * Handle optional except
2005      */
2006     if ((content != NULL) && (xmlStrEqual(content->name, BAD_CAST "except"))) {
2007         xmlNodePtr child;
2008         xmlRelaxNGDefinePtr tmp2, last2 = NULL;
2009
2010         except = xmlRelaxNGNewDefine(ctxt, node);
2011         if (except == NULL) {
2012             return(def);
2013         }
2014         except->type = XML_RELAXNG_EXCEPT;
2015         child = content->children;
2016         if (last == NULL) {
2017             def->content = except;
2018         } else {
2019             last->next = except;
2020         }
2021         if (child == NULL) {
2022             if (ctxt->error != NULL)
2023                 ctxt->error(ctxt->userData,
2024                     "except has no content\n");
2025             ctxt->nbErrors++;
2026         }
2027         while (child != NULL) {
2028             tmp2 = xmlRelaxNGParsePattern(ctxt, child);
2029             if (tmp2 != NULL) {
2030                 if (last2 == NULL) {
2031                     except->content = last2 = tmp2;
2032                 } else {
2033                     last2->next = tmp2;
2034                     last2 = tmp2;
2035                 }
2036             }
2037             child = child->next;
2038         }
2039         content = content->next;
2040     }
2041     /*
2042      * Check there is no unhandled data
2043      */
2044     if (content != NULL) {
2045         if (ctxt->error != NULL)
2046             ctxt->error(ctxt->userData,
2047                 "Element data has unexpected content %s\n", content->name);
2048         ctxt->nbErrors++;
2049     }
2050
2051     return(def);
2052 }
2053
2054 static const xmlChar *invalidName = BAD_CAST "\1";
2055
2056 /**
2057  * xmlRelaxNGCompareNameClasses:
2058  * @defs1:  the first element/attribute defs
2059  * @defs2:  the second element/attribute defs
2060  * @name:  the restriction on the name
2061  * @ns:  the restriction on the namespace
2062  *
2063  * Compare the 2 lists of element definitions. The comparison is
2064  * that if both lists do not accept the same QNames, it returns 1
2065  * If the 2 lists can accept the same QName the comparison returns 0
2066  *
2067  * Returns 1 disttinct, 0 if equal
2068  */
2069 static int
2070 xmlRelaxNGCompareNameClasses(xmlRelaxNGDefinePtr def1,
2071                              xmlRelaxNGDefinePtr def2) {
2072     int ret = 1;
2073     xmlNode node;
2074     xmlNs ns;
2075     xmlRelaxNGValidCtxt ctxt;
2076     ctxt.flags = FLAGS_IGNORABLE;
2077
2078     if ((def1->type == XML_RELAXNG_ELEMENT) ||
2079         (def1->type == XML_RELAXNG_ATTRIBUTE)) {
2080         if (def2->type == XML_RELAXNG_TEXT)
2081             return(1);
2082         if (def1->name != NULL) {
2083             node.name = def1->name;
2084         } else {
2085             node.name = invalidName;
2086         }
2087         node.ns = &ns;
2088         if (def1->ns != NULL) {
2089             if (def1->ns[0] == 0) {
2090                 node.ns = NULL;
2091             } else {
2092                 ns.href = def1->ns;
2093             }
2094         } else {
2095             ns.href = invalidName;
2096         }
2097         if (xmlRelaxNGElementMatch(&ctxt, def2, &node)) {
2098             if (def1->nameClass != NULL) {
2099                 ret = xmlRelaxNGCompareNameClasses(def1->nameClass, def2);
2100             } else {
2101                 ret = 0;
2102             }
2103         } else {
2104             ret = 1;
2105         }
2106     } else if (def1->type == XML_RELAXNG_TEXT) {
2107         if (def2->type == XML_RELAXNG_TEXT)
2108             return(0);
2109         return(1);
2110     } else if (def1->type == XML_RELAXNG_EXCEPT) {
2111         TODO
2112         ret = 0;
2113     } else {
2114         TODO
2115         ret = 0;
2116     }
2117     if (ret == 0)
2118         return(ret);
2119     if ((def2->type == XML_RELAXNG_ELEMENT) ||
2120         (def2->type == XML_RELAXNG_ATTRIBUTE)) {
2121         if (def2->name != NULL) {
2122             node.name = def2->name;
2123         } else {
2124             node.name = invalidName;
2125         }
2126         node.ns = &ns;
2127         if (def2->ns != NULL) {
2128             if (def2->ns[0] == 0) {
2129                 node.ns = NULL;
2130             } else {
2131                 ns.href = def2->ns;
2132             }
2133         } else {
2134             ns.href = invalidName;
2135         }
2136         if (xmlRelaxNGElementMatch(&ctxt, def1, &node)) {
2137             if (def2->nameClass != NULL) {
2138                 ret = xmlRelaxNGCompareNameClasses(def2->nameClass, def1);
2139             } else {
2140                 ret = 0;
2141             }
2142         } else {
2143             ret = 1;
2144         }
2145     } else {
2146         TODO
2147         ret = 0;
2148     }
2149
2150     return(ret);
2151 }
2152
2153 /**
2154  * xmlRelaxNGCompareElemDefLists:
2155  * @ctxt:  a Relax-NG parser context
2156  * @defs1:  the first list of element/attribute defs
2157  * @defs2:  the second list of element/attribute defs
2158  *
2159  * Compare the 2 lists of element or attribute definitions. The comparison
2160  * is that if both lists do not accept the same QNames, it returns 1
2161  * If the 2 lists can accept the same QName the comparison returns 0
2162  *
2163  * Returns 1 disttinct, 0 if equal
2164  */
2165 static int
2166 xmlRelaxNGCompareElemDefLists(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
2167                       xmlRelaxNGDefinePtr *def1,
2168                       xmlRelaxNGDefinePtr *def2) {
2169     xmlRelaxNGDefinePtr *basedef2 = def2;
2170     
2171     if ((def1 == NULL) || (def2 == NULL))
2172         return(1);
2173     if ((*def1 == NULL) || (*def2 == NULL))
2174         return(1);
2175     while (*def1 != NULL) {
2176         while ((*def2) != NULL) {
2177             if (xmlRelaxNGCompareNameClasses(*def1, *def2) == 0)
2178                 return(0);
2179             def2++;
2180         }
2181         def2 = basedef2;
2182         def1++;
2183     }
2184     return(1);
2185 }
2186
2187 /**
2188  * xmlRelaxNGGetElements:
2189  * @ctxt:  a Relax-NG parser context
2190  * @def:  the definition definition
2191  * @eora:  gather elements (0) or attributes (1)
2192  *
2193  * Compute the list of top elements a definition can generate
2194  *
2195  * Returns a list of elements or NULL if none was found.
2196  */
2197 static xmlRelaxNGDefinePtr *
2198 xmlRelaxNGGetElements(xmlRelaxNGParserCtxtPtr ctxt,
2199                       xmlRelaxNGDefinePtr def,
2200                       int eora) {
2201     xmlRelaxNGDefinePtr *ret = NULL, parent, cur, tmp;
2202     int len = 0;
2203     int max = 0;
2204
2205     /*
2206      * Don't run that check in case of error. Infinite recursion
2207      * becomes possible.
2208      */
2209     if (ctxt->nbErrors != 0)
2210         return(NULL);
2211
2212     parent = NULL;
2213     cur = def;
2214     while (cur != NULL) {
2215         if (((eora == 0) && ((cur->type == XML_RELAXNG_ELEMENT) ||
2216              (cur->type == XML_RELAXNG_TEXT))) ||
2217             ((eora == 1) && (cur->type == XML_RELAXNG_ATTRIBUTE))) {
2218             if (ret == NULL) {
2219                 max = 10;
2220                 ret = (xmlRelaxNGDefinePtr *)
2221                     xmlMalloc((max + 1) * sizeof(xmlRelaxNGDefinePtr));
2222                 if (ret == NULL) {
2223                     if (ctxt->error != NULL)
2224                         ctxt->error(ctxt->userData,
2225                             "Out of memory in element search\n");
2226                     ctxt->nbErrors++;
2227                     return(NULL);
2228                 }
2229             } else if (max <= len) {
2230                 max *= 2;
2231                 ret = xmlRealloc(ret, (max + 1) * sizeof(xmlRelaxNGDefinePtr));
2232                 if (ret == NULL) {
2233                     if (ctxt->error != NULL)
2234                         ctxt->error(ctxt->userData,
2235                             "Out of memory in element search\n");
2236                     ctxt->nbErrors++;
2237                     return(NULL);
2238                 }
2239             }
2240             ret[len++] = cur;
2241             ret[len] = NULL;
2242         } else if ((cur->type == XML_RELAXNG_CHOICE) ||
2243                    (cur->type == XML_RELAXNG_INTERLEAVE) ||
2244                    (cur->type == XML_RELAXNG_GROUP) ||
2245                    (cur->type == XML_RELAXNG_ONEORMORE) ||
2246                    (cur->type == XML_RELAXNG_ZEROORMORE) ||
2247                    (cur->type == XML_RELAXNG_OPTIONAL) ||
2248                    (cur->type == XML_RELAXNG_REF) ||
2249                    (cur->type == XML_RELAXNG_DEF)) {
2250             /*
2251              * Don't go within elements or attributes or string values.
2252              * Just gather the element top list
2253              */
2254             if (cur->content != NULL) {
2255                 parent = cur;
2256                 cur = cur->content;
2257                 tmp = cur;
2258                 while (tmp != NULL) {
2259                     tmp->parent = parent;
2260                     tmp = tmp->next;
2261                 }
2262                 continue;
2263             }
2264         }
2265         if (cur == def)
2266             break;
2267         if (cur->next != NULL) {
2268             cur = cur->next;
2269             continue;
2270         }
2271         do {
2272             cur = cur->parent;
2273             if (cur == NULL) break;
2274             if (cur == def) return(ret);
2275             if (cur->next != NULL) {
2276                 cur = cur->next;
2277                 break;
2278             }
2279         } while (cur != NULL);
2280     }
2281     return(ret);
2282 }
2283                              
2284 /**
2285  * xmlRelaxNGCheckGroupAttrs:
2286  * @ctxt:  a Relax-NG parser context
2287  * @def:  the group definition
2288  *
2289  * Detects violations of rule 7.3
2290  */
2291 static void
2292 xmlRelaxNGCheckGroupAttrs(xmlRelaxNGParserCtxtPtr ctxt,
2293                           xmlRelaxNGDefinePtr def) {
2294     xmlRelaxNGDefinePtr **list;
2295     xmlRelaxNGDefinePtr cur;
2296     int nbchild = 0, i, j, ret;
2297
2298     if ((def == NULL) ||
2299         ((def->type != XML_RELAXNG_GROUP) &&
2300          (def->type != XML_RELAXNG_ELEMENT)))
2301         return;
2302
2303     /*
2304      * Don't run that check in case of error. Infinite recursion
2305      * becomes possible.
2306      */
2307     if (ctxt->nbErrors != 0)
2308         return;
2309
2310     cur = def->attrs;
2311     while (cur != NULL) {
2312         nbchild++;
2313         cur = cur->next;
2314     }
2315     cur = def->content;
2316     while (cur != NULL) {
2317         nbchild++;
2318         cur = cur->next;
2319     }
2320
2321     list = (xmlRelaxNGDefinePtr **) xmlMalloc(nbchild *
2322                                               sizeof(xmlRelaxNGDefinePtr *));
2323     if (list == NULL) {
2324         if (ctxt->error != NULL)
2325             ctxt->error(ctxt->userData,
2326                 "Out of memory in group computation\n");
2327         ctxt->nbErrors++;
2328         return;
2329     }
2330     i = 0;
2331     cur = def->attrs;
2332     while (cur != NULL) {
2333         list[i] = xmlRelaxNGGetElements(ctxt, cur, 1);
2334         i++;
2335         cur = cur->next;
2336     }
2337     cur = def->content;
2338     while (cur != NULL) {
2339         list[i] = xmlRelaxNGGetElements(ctxt, cur, 1);
2340         i++;
2341         cur = cur->next;
2342     }
2343
2344     for (i = 0;i < nbchild;i++) {
2345         if (list[i] == NULL)
2346             continue;
2347         for (j = 0;j < i;j++) {
2348             if (list[j] == NULL)
2349                 continue;
2350             ret = xmlRelaxNGCompareElemDefLists(ctxt, list[i], list[j]);
2351             if (ret == 0) {
2352                 if (ctxt->error != NULL)
2353                     ctxt->error(ctxt->userData,
2354                         "Attributes conflicts in group\n");
2355                 ctxt->nbErrors++;
2356             }
2357         }
2358     }
2359     for (i = 0;i < nbchild;i++) {
2360         if (list[i] != NULL)
2361             xmlFree(list[i]);
2362     }
2363     xmlFree(list);
2364 }
2365
2366 /**
2367  * xmlRelaxNGComputeInterleaves:
2368  * @def:  the interleave definition
2369  * @ctxt:  a Relax-NG parser context
2370  * @name:  the definition name
2371  *
2372  * A lot of work for preprocessing interleave definitions
2373  * is potentially needed to get a decent execution speed at runtime
2374  *   - trying to get a total order on the element nodes generated
2375  *     by the interleaves, order the list of interleave definitions
2376  *     following that order.
2377  *   - if <text/> is used to handle mixed content, it is better to
2378  *     flag this in the define and simplify the runtime checking
2379  *     algorithm
2380  */
2381 static void
2382 xmlRelaxNGComputeInterleaves(xmlRelaxNGDefinePtr def,
2383                              xmlRelaxNGParserCtxtPtr ctxt,
2384                              xmlChar *name ATTRIBUTE_UNUSED) {
2385     xmlRelaxNGDefinePtr cur;
2386
2387     xmlRelaxNGPartitionPtr partitions = NULL;
2388     xmlRelaxNGInterleaveGroupPtr *groups = NULL;
2389     xmlRelaxNGInterleaveGroupPtr group;
2390     int i,j,ret;
2391     int nbgroups = 0;
2392     int nbchild = 0;
2393
2394     /*
2395      * Don't run that check in case of error. Infinite recursion
2396      * becomes possible.
2397      */
2398     if (ctxt->nbErrors != 0)
2399         return;
2400
2401 #ifdef DEBUG_INTERLEAVE
2402     xmlGenericError(xmlGenericErrorContext,
2403                     "xmlRelaxNGComputeInterleaves(%s)\n",
2404                     name);
2405 #endif
2406     cur = def->content;
2407     while (cur != NULL) {
2408         nbchild++;
2409         cur = cur->next;
2410     }
2411     
2412 #ifdef DEBUG_INTERLEAVE
2413     xmlGenericError(xmlGenericErrorContext, "  %d child\n", nbchild);
2414 #endif
2415     groups = (xmlRelaxNGInterleaveGroupPtr *)
2416         xmlMalloc(nbchild * sizeof(xmlRelaxNGInterleaveGroupPtr));
2417     if (groups == NULL)
2418         goto error;
2419     cur = def->content;
2420     while (cur != NULL) {
2421         groups[nbgroups] = (xmlRelaxNGInterleaveGroupPtr)
2422             xmlMalloc(sizeof(xmlRelaxNGInterleaveGroup));
2423         if (groups[nbgroups] == NULL)
2424             goto error;
2425         groups[nbgroups]->rule = cur;
2426         groups[nbgroups]->defs = xmlRelaxNGGetElements(ctxt, cur, 0);
2427         groups[nbgroups]->attrs = xmlRelaxNGGetElements(ctxt, cur, 1);
2428         nbgroups++;
2429         cur = cur->next;
2430     }
2431 #ifdef DEBUG_INTERLEAVE
2432     xmlGenericError(xmlGenericErrorContext, "  %d groups\n", nbgroups);
2433 #endif
2434
2435     /*
2436      * Let's check that all rules makes a partitions according to 7.4
2437      */
2438     partitions = (xmlRelaxNGPartitionPtr)
2439                 xmlMalloc(sizeof(xmlRelaxNGPartition));
2440     if (partitions == NULL)
2441         goto error;
2442     partitions->nbgroups = nbgroups;
2443     for (i = 0;i < nbgroups;i++) {
2444         group = groups[i];
2445         for (j = i+1;j < nbgroups;j++) {
2446             if (groups[j] == NULL)
2447                 continue;
2448             ret = xmlRelaxNGCompareElemDefLists(ctxt, group->defs,
2449                                                 groups[j]->defs);
2450             if (ret == 0) {
2451                 if (ctxt->error != NULL)
2452                     ctxt->error(ctxt->userData,
2453                         "Element or text conflicts in interleave\n");
2454                 ctxt->nbErrors++;
2455             }
2456             ret = xmlRelaxNGCompareElemDefLists(ctxt, group->attrs,
2457                                                 groups[j]->attrs);
2458             if (ret == 0) {
2459                 if (ctxt->error != NULL)
2460                     ctxt->error(ctxt->userData,
2461                         "Attributes conflicts in interleave\n");
2462                 ctxt->nbErrors++;
2463             }
2464         }
2465     }
2466     partitions->groups = groups;
2467
2468     /*
2469      * and save the partition list back in the def
2470      */
2471     def->data = partitions;
2472     return;
2473
2474 error:
2475     if (ctxt->error != NULL)
2476         ctxt->error(ctxt->userData,
2477             "Out of memory in interleave computation\n");
2478     ctxt->nbErrors++;
2479     if (groups != NULL) {
2480         for (i = 0;i < nbgroups;i++)
2481             if (groups[i] != NULL) {
2482                 if (groups[i]->defs != NULL)
2483                     xmlFree(groups[i]->defs);
2484                 xmlFree(groups[i]);
2485             }
2486         xmlFree(groups);
2487     }
2488     xmlRelaxNGFreePartition(partitions);
2489 }
2490
2491 /**
2492  * xmlRelaxNGParseInterleave:
2493  * @ctxt:  a Relax-NG parser context
2494  * @node:  the data node.
2495  *
2496  * parse the content of a RelaxNG interleave node.
2497  *
2498  * Returns the definition pointer or NULL in case of error
2499  */
2500 static xmlRelaxNGDefinePtr
2501 xmlRelaxNGParseInterleave(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
2502     xmlRelaxNGDefinePtr def = NULL;
2503     xmlRelaxNGDefinePtr last = NULL, cur;
2504     xmlNodePtr child;
2505
2506     def = xmlRelaxNGNewDefine(ctxt, node);
2507     if (def == NULL) {
2508         return(NULL);
2509     }
2510     def->type = XML_RELAXNG_INTERLEAVE;
2511
2512     if (ctxt->interleaves == NULL)
2513         ctxt->interleaves = xmlHashCreate(10);
2514     if (ctxt->interleaves == NULL) {
2515         if (ctxt->error != NULL)
2516             ctxt->error(ctxt->userData,
2517                 "Failed to create interleaves hash table\n");
2518         ctxt->nbErrors++;
2519     } else {
2520         char name[32];
2521
2522         snprintf(name, 32, "interleave%d", ctxt->nbInterleaves++);
2523         if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST name, def) < 0) {
2524             if (ctxt->error != NULL)
2525                 ctxt->error(ctxt->userData,
2526                     "Failed to add %s to hash table\n", name);
2527             ctxt->nbErrors++;
2528         }
2529     }
2530     child = node->children;
2531     if (child == NULL) {
2532         if (ctxt->error != NULL)
2533             ctxt->error(ctxt->userData, "Element interleave is empty\n");
2534         ctxt->nbErrors++;
2535     }
2536     while (child != NULL) {
2537         if (IS_RELAXNG(child, "element")) {
2538             cur = xmlRelaxNGParseElement(ctxt, child);
2539         } else {
2540             cur = xmlRelaxNGParsePattern(ctxt, child);
2541         }
2542         if (cur != NULL) {
2543             cur->parent = def;
2544             if (last == NULL) {
2545                 def->content = last = cur;
2546             } else {
2547                 last->next = cur;
2548                 last = cur;
2549             }
2550         }
2551         child = child->next;
2552     }
2553
2554     return(def);
2555 }
2556
2557 /**
2558  * xmlRelaxNGParseInclude:
2559  * @ctxt:  a Relax-NG parser context
2560  * @node:  the include node
2561  *
2562  * Integrate the content of an include node in the current grammar
2563  *
2564  * Returns 0 in case of success or -1 in case of error
2565  */
2566 static int
2567 xmlRelaxNGParseInclude(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
2568     xmlRelaxNGIncludePtr incl;
2569     xmlNodePtr root;
2570     int ret = 0, tmp;
2571
2572     incl = node->_private;
2573     if (incl == NULL) {
2574         if (ctxt->error != NULL)
2575             ctxt->error(ctxt->userData,
2576                 "Include node has no data\n");
2577         ctxt->nbErrors++;
2578         return(-1);
2579     }
2580     root = xmlDocGetRootElement(incl->doc);
2581     if (root == NULL) {
2582         if (ctxt->error != NULL)
2583             ctxt->error(ctxt->userData,
2584                 "Include document is empty\n");
2585         ctxt->nbErrors++;
2586         return(-1);
2587     }
2588     if (!xmlStrEqual(root->name, BAD_CAST "grammar")) {
2589         if (ctxt->error != NULL)
2590             ctxt->error(ctxt->userData,
2591                 "Include document root is not a grammar\n");
2592         ctxt->nbErrors++;
2593         return(-1);
2594     }
2595
2596     /*
2597      * Merge the definition from both the include and the internal list
2598      */
2599     if (root->children != NULL) {
2600         tmp = xmlRelaxNGParseGrammarContent(ctxt, root->children);
2601         if (tmp != 0)
2602             ret = -1;
2603     }
2604     if (node->children != NULL) {
2605         tmp = xmlRelaxNGParseGrammarContent(ctxt, node->children);
2606         if (tmp != 0)
2607             ret = -1;
2608     }
2609     return(ret);
2610 }
2611
2612 /**
2613  * xmlRelaxNGParseDefine:
2614  * @ctxt:  a Relax-NG parser context
2615  * @node:  the define node
2616  *
2617  * parse the content of a RelaxNG define element node.
2618  *
2619  * Returns 0 in case of success or -1 in case of error
2620  */
2621 static int
2622 xmlRelaxNGParseDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
2623     xmlChar *name;
2624     int ret = 0, tmp;
2625     xmlRelaxNGDefinePtr def;
2626     const xmlChar *olddefine;
2627
2628     name = xmlGetProp(node, BAD_CAST "name");
2629     if (name == NULL) {
2630         if (ctxt->error != NULL)
2631             ctxt->error(ctxt->userData,
2632                         "define has no name\n");
2633         ctxt->nbErrors++;
2634     } else {
2635         xmlRelaxNGNormExtSpace(name);
2636         if (xmlValidateNCName(name, 0)) {
2637             if (ctxt->error != NULL)
2638                 ctxt->error(ctxt->userData,
2639                     "define name '%s' is not an NCName\n",
2640                             name);
2641             ctxt->nbErrors++;
2642         }
2643         def = xmlRelaxNGNewDefine(ctxt, node);
2644         if (def == NULL) {
2645             xmlFree(name);
2646             return(-1);
2647         }
2648         def->type = XML_RELAXNG_DEF;
2649         def->name = name;
2650         if (node->children == NULL) {
2651             if (ctxt->error != NULL)
2652                 ctxt->error(ctxt->userData,
2653                             "define has no children\n");
2654             ctxt->nbErrors++;
2655         } else {
2656             olddefine = ctxt->define;
2657             ctxt->define = name;
2658             def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
2659             ctxt->define = olddefine;
2660         }
2661         if (ctxt->grammar->defs == NULL)
2662             ctxt->grammar->defs = xmlHashCreate(10);
2663         if (ctxt->grammar->defs == NULL) {
2664             if (ctxt->error != NULL)
2665                 ctxt->error(ctxt->userData,
2666                             "Could not create definition hash\n");
2667             ctxt->nbErrors++;
2668             ret = -1;
2669         } else {
2670             tmp = xmlHashAddEntry(ctxt->grammar->defs, name, def);
2671             if (tmp < 0) {
2672                 xmlRelaxNGDefinePtr prev;
2673
2674                 prev = xmlHashLookup(ctxt->grammar->defs, name);
2675                 if (prev == NULL) {
2676                     if (ctxt->error != NULL)
2677                         ctxt->error(ctxt->userData,
2678                             "Internal error on define aggregation of %s\n",
2679                                     name);
2680                     ctxt->nbErrors++;
2681                     ret = -1;
2682                 } else {
2683                     while (prev->nextHash != NULL)
2684                         prev = prev->nextHash;
2685                     prev->nextHash = def;
2686                 }
2687             }
2688         }
2689     }
2690     return(ret);
2691 }
2692
2693 /**
2694  * xmlRelaxNGProcessExternalRef:
2695  * @ctxt: the parser context
2696  * @node:  the externlRef node
2697  *
2698  * Process and compile an externlRef node
2699  *
2700  * Returns the xmlRelaxNGDefinePtr or NULL in case of error
2701  */
2702 static xmlRelaxNGDefinePtr
2703 xmlRelaxNGProcessExternalRef(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
2704     xmlRelaxNGDocumentPtr docu;
2705     xmlNodePtr root, tmp;
2706     xmlChar *ns;
2707     int newNs = 0, oldflags;
2708     xmlRelaxNGDefinePtr def;
2709
2710     docu = node->_private;
2711     if (docu != NULL) {
2712         def = xmlRelaxNGNewDefine(ctxt, node);
2713         if (def == NULL)
2714             return(NULL);
2715         def->type = XML_RELAXNG_EXTERNALREF;
2716         
2717         if (docu->content == NULL) {
2718             /*
2719              * Then do the parsing for good
2720              */
2721             root = xmlDocGetRootElement(docu->doc);
2722             if (root == NULL) {
2723                 if (ctxt->error != NULL)
2724                     ctxt->error(ctxt->userData,
2725                             "xmlRelaxNGParse: %s is empty\n",
2726                                 ctxt->URL);
2727                 ctxt->nbErrors++;
2728                 return (NULL);
2729             }
2730             /*
2731              * ns transmission rules
2732              */
2733             ns = xmlGetProp(root, BAD_CAST "ns");
2734             if (ns == NULL) {
2735                 tmp = node;
2736                 while ((tmp != NULL) &&
2737                        (tmp->type == XML_ELEMENT_NODE)) {
2738                     ns = xmlGetProp(tmp, BAD_CAST "ns");
2739                     if (ns != NULL) {
2740                         break;
2741                     }
2742                     tmp = tmp->parent;
2743                 }
2744                 if (ns != NULL) {
2745                     xmlSetProp(root, BAD_CAST "ns", ns);
2746                     newNs = 1;
2747                     xmlFree(ns);
2748                 }
2749             } else {
2750                 xmlFree(ns);
2751             }
2752
2753             /*
2754              * Parsing to get a precompiled schemas.
2755              */
2756             oldflags = ctxt->flags;
2757             ctxt->flags |= XML_RELAXNG_IN_EXTERNALREF;
2758             docu->schema = xmlRelaxNGParseDocument(ctxt, root);
2759             ctxt->flags = oldflags;
2760             if ((docu->schema != NULL) &&
2761                 (docu->schema->topgrammar != NULL)) {
2762                 docu->content = docu->schema->topgrammar->start;
2763             }
2764
2765             /*
2766              * the externalRef may be reused in a different ns context
2767              */
2768             if (newNs == 1) {
2769                 xmlUnsetProp(root, BAD_CAST "ns");
2770             }
2771         }
2772         def->content = docu->content;
2773     } else {
2774         def = NULL;
2775     }
2776     return(def);
2777 }
2778
2779 /**
2780  * xmlRelaxNGParsePattern:
2781  * @ctxt:  a Relax-NG parser context
2782  * @node:  the pattern node.
2783  *
2784  * parse the content of a RelaxNG pattern node.
2785  *
2786  * Returns the definition pointer or NULL in case of error or if no
2787  *     pattern is generated.
2788  */
2789 static xmlRelaxNGDefinePtr
2790 xmlRelaxNGParsePattern(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
2791     xmlRelaxNGDefinePtr def = NULL;
2792
2793     if (node == NULL) {
2794         return(NULL);
2795     }
2796     if (IS_RELAXNG(node, "element")) {
2797         def = xmlRelaxNGParseElement(ctxt, node);
2798     } else if (IS_RELAXNG(node, "attribute")) {
2799         def = xmlRelaxNGParseAttribute(ctxt, node);
2800     } else if (IS_RELAXNG(node, "empty")) {
2801         def = xmlRelaxNGNewDefine(ctxt, node);
2802         if (def == NULL)
2803             return(NULL);
2804         def->type = XML_RELAXNG_EMPTY;
2805         if (node->children != NULL) {
2806             if (ctxt->error != NULL)
2807                 ctxt->error(ctxt->userData, "empty: had a child node\n");
2808             ctxt->nbErrors++;
2809         }
2810     } else if (IS_RELAXNG(node, "text")) {
2811         def = xmlRelaxNGNewDefine(ctxt, node);
2812         if (def == NULL)
2813             return(NULL);
2814         def->type = XML_RELAXNG_TEXT;
2815         if (node->children != NULL) {
2816             if (ctxt->error != NULL)
2817                 ctxt->error(ctxt->userData, "text: had a child node\n");
2818             ctxt->nbErrors++;
2819         }
2820     } else if (IS_RELAXNG(node, "zeroOrMore")) {
2821         def = xmlRelaxNGNewDefine(ctxt, node);
2822         if (def == NULL)
2823             return(NULL);
2824         def->type = XML_RELAXNG_ZEROORMORE;
2825         if (node->children == NULL) {
2826             if (ctxt->error != NULL)
2827                 ctxt->error(ctxt->userData,
2828                             "Element %s is empty\n", node->name);
2829             ctxt->nbErrors++;
2830         } else {
2831             def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 1);
2832         } 
2833     } else if (IS_RELAXNG(node, "oneOrMore")) {
2834         def = xmlRelaxNGNewDefine(ctxt, node);
2835         if (def == NULL)
2836             return(NULL);
2837         def->type = XML_RELAXNG_ONEORMORE;
2838         if (node->children == NULL) {
2839             if (ctxt->error != NULL)
2840                 ctxt->error(ctxt->userData,
2841                             "Element %s is empty\n", node->name);
2842             ctxt->nbErrors++;
2843         } else {
2844             def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 1);
2845         } 
2846     } else if (IS_RELAXNG(node, "optional")) {
2847         def = xmlRelaxNGNewDefine(ctxt, node);
2848         if (def == NULL)
2849             return(NULL);
2850         def->type = XML_RELAXNG_OPTIONAL;
2851         if (node->children == NULL) {
2852             if (ctxt->error != NULL)
2853                 ctxt->error(ctxt->userData,
2854                             "Element %s is empty\n", node->name);
2855             ctxt->nbErrors++;
2856         } else {
2857             def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 1);
2858         } 
2859     } else if (IS_RELAXNG(node, "choice")) {
2860         def = xmlRelaxNGNewDefine(ctxt, node);
2861         if (def == NULL)
2862             return(NULL);
2863         def->type = XML_RELAXNG_CHOICE;
2864         if (node->children == NULL) {
2865             if (ctxt->error != NULL)
2866                 ctxt->error(ctxt->userData,
2867                             "Element %s is empty\n", node->name);
2868             ctxt->nbErrors++;
2869         } else {
2870             def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
2871         } 
2872     } else if (IS_RELAXNG(node, "group")) {
2873         def = xmlRelaxNGNewDefine(ctxt, node);
2874         if (def == NULL)
2875             return(NULL);
2876         def->type = XML_RELAXNG_GROUP;
2877         if (node->children == NULL) {
2878             if (ctxt->error != NULL)
2879                 ctxt->error(ctxt->userData,
2880                             "Element %s is empty\n", node->name);
2881             ctxt->nbErrors++;
2882         } else {
2883             def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
2884         } 
2885     } else if (IS_RELAXNG(node, "ref")) {
2886         def = xmlRelaxNGNewDefine(ctxt, node);
2887         if (def == NULL)
2888             return(NULL);
2889         def->type = XML_RELAXNG_REF;
2890         def->name = xmlGetProp(node, BAD_CAST "name");
2891         if (def->name == NULL) {
2892             if (ctxt->error != NULL)
2893                 ctxt->error(ctxt->userData,
2894                             "ref has no name\n");
2895             ctxt->nbErrors++;
2896         } else {
2897             xmlRelaxNGNormExtSpace(def->name);
2898             if (xmlValidateNCName(def->name, 0)) {
2899                 if (ctxt->error != NULL)
2900                     ctxt->error(ctxt->userData,
2901                         "ref name '%s' is not an NCName\n",
2902                                 def->name);
2903                 ctxt->nbErrors++;
2904             }
2905         }
2906         if (node->children != NULL) {
2907             if (ctxt->error != NULL)
2908                 ctxt->error(ctxt->userData,
2909                             "ref is not empty\n");
2910             ctxt->nbErrors++;
2911         }
2912         if (ctxt->grammar->refs == NULL)
2913             ctxt->grammar->refs = xmlHashCreate(10);
2914         if (ctxt->grammar->refs == NULL) {
2915             if (ctxt->error != NULL)
2916                 ctxt->error(ctxt->userData,
2917                             "Could not create references hash\n");
2918             ctxt->nbErrors++;
2919             def = NULL;
2920         } else {
2921             int tmp;
2922
2923             tmp = xmlHashAddEntry(ctxt->grammar->refs, def->name, def);
2924             if (tmp < 0) {
2925                 xmlRelaxNGDefinePtr prev;
2926
2927                 prev = (xmlRelaxNGDefinePtr)
2928                       xmlHashLookup(ctxt->grammar->refs, def->name);
2929                 if (prev == NULL) {
2930                     if (def->name != NULL) {
2931                         if (ctxt->error != NULL)
2932                             ctxt->error(ctxt->userData,
2933                                 "Error refs definitions '%s'\n",
2934                                         def->name);
2935                     } else {
2936                         if (ctxt->error != NULL)
2937                             ctxt->error(ctxt->userData,
2938                                 "Error refs definitions\n");
2939                     }
2940                     ctxt->nbErrors++;
2941                     def = NULL;
2942                 } else {
2943                     def->nextHash = prev->nextHash;
2944                     prev->nextHash = def;
2945                 }
2946             }
2947         }
2948     } else if (IS_RELAXNG(node, "data")) {
2949         def = xmlRelaxNGParseData(ctxt, node);
2950 #if 0
2951     } else if (IS_RELAXNG(node, "define")) {
2952         xmlRelaxNGParseDefine(ctxt, node);
2953         def = NULL;
2954 #endif
2955     } else if (IS_RELAXNG(node, "value")) {
2956         def = xmlRelaxNGParseValue(ctxt, node);
2957     } else if (IS_RELAXNG(node, "list")) {
2958         def = xmlRelaxNGNewDefine(ctxt, node);
2959         if (def == NULL)
2960             return(NULL);
2961         def->type = XML_RELAXNG_LIST;
2962         if (node->children == NULL) {
2963             if (ctxt->error != NULL)
2964                 ctxt->error(ctxt->userData,
2965                             "Element %s is empty\n", node->name);
2966             ctxt->nbErrors++;
2967         } else {
2968             def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
2969         } 
2970     } else if (IS_RELAXNG(node, "interleave")) {
2971         def = xmlRelaxNGParseInterleave(ctxt, node);
2972     } else if (IS_RELAXNG(node, "externalRef")) {
2973         def = xmlRelaxNGProcessExternalRef(ctxt, node);
2974     } else if (IS_RELAXNG(node, "notAllowed")) {
2975         def = xmlRelaxNGNewDefine(ctxt, node);
2976         if (def == NULL)
2977             return(NULL);
2978         def->type = XML_RELAXNG_NOT_ALLOWED;
2979         if (node->children != NULL) {
2980             if (ctxt->error != NULL)
2981                 ctxt->error(ctxt->userData,
2982                         "xmlRelaxNGParse: notAllowed element is not empty\n");
2983             ctxt->nbErrors++;
2984         }
2985     } else if (IS_RELAXNG(node, "grammar")) {
2986         xmlRelaxNGGrammarPtr grammar, old;
2987         xmlRelaxNGGrammarPtr oldparent;
2988
2989         oldparent = ctxt->parentgrammar;
2990         old = ctxt->grammar;
2991         ctxt->parentgrammar = old;
2992         grammar = xmlRelaxNGParseGrammar(ctxt, node->children);
2993         if (old != NULL) {
2994             ctxt->grammar = old;
2995             ctxt->parentgrammar = oldparent;
2996             if (grammar != NULL) {
2997                 grammar->next = old->next;
2998                 old->next = grammar;
2999             }
3000         }
3001         if (grammar != NULL)
3002             def = grammar->start;
3003         else
3004             def = NULL;
3005     } else if (IS_RELAXNG(node, "parentRef")) {
3006         if (ctxt->parentgrammar == NULL) {
3007             if (ctxt->error != NULL)
3008                 ctxt->error(ctxt->userData,
3009                         "Use of parentRef without a parent grammar\n");
3010             ctxt->nbErrors++;
3011             return(NULL);
3012         }
3013         def = xmlRelaxNGNewDefine(ctxt, node);
3014         if (def == NULL)
3015             return(NULL);
3016         def->type = XML_RELAXNG_PARENTREF;
3017         def->name = xmlGetProp(node, BAD_CAST "name");
3018         if (def->name == NULL) {
3019             if (ctxt->error != NULL)
3020                 ctxt->error(ctxt->userData,
3021                             "parentRef has no name\n");
3022             ctxt->nbErrors++;
3023         } else {
3024             xmlRelaxNGNormExtSpace(def->name);
3025             if (xmlValidateNCName(def->name, 0)) {
3026                 if (ctxt->error != NULL)
3027                     ctxt->error(ctxt->userData,
3028                         "parentRef name '%s' is not an NCName\n",
3029                                 def->name);
3030                 ctxt->nbErrors++;
3031             }
3032         }
3033         if (node->children != NULL) {
3034             if (ctxt->error != NULL)
3035                 ctxt->error(ctxt->userData,
3036                             "parentRef is not empty\n");
3037             ctxt->nbErrors++;
3038         }
3039         if (ctxt->parentgrammar->refs == NULL)
3040             ctxt->parentgrammar->refs = xmlHashCreate(10);
3041         if (ctxt->parentgrammar->refs == NULL) {
3042             if (ctxt->error != NULL)
3043                 ctxt->error(ctxt->userData,
3044                             "Could not create references hash\n");
3045             ctxt->nbErrors++;
3046             def = NULL;
3047         } else if (def->name != NULL) {
3048             int tmp;
3049
3050             tmp = xmlHashAddEntry(ctxt->parentgrammar->refs, def->name, def);
3051             if (tmp < 0) {
3052                 xmlRelaxNGDefinePtr prev;
3053
3054                 prev = (xmlRelaxNGDefinePtr)
3055                       xmlHashLookup(ctxt->parentgrammar->refs, def->name);
3056                 if (prev == NULL) {
3057                     if (ctxt->error != NULL)
3058                         ctxt->error(ctxt->userData,
3059                             "Internal error parentRef definitions '%s'\n",
3060                                     def->name);
3061                     ctxt->nbErrors++;
3062                     def = NULL;
3063                 } else {
3064                     def->nextHash = prev->nextHash;
3065                     prev->nextHash = def;
3066                 }
3067             }
3068         }
3069     } else if (IS_RELAXNG(node, "mixed")) {
3070         if (node->children == NULL) {
3071             if (ctxt->error != NULL)
3072                 ctxt->error(ctxt->userData,
3073                     "Mixed is empty\n");
3074             ctxt->nbErrors++;
3075             def = NULL;
3076         } else {
3077             def = xmlRelaxNGParseInterleave(ctxt, node);
3078             if (def != NULL) {
3079                 xmlRelaxNGDefinePtr tmp;
3080
3081                 if ((def->content != NULL) && (def->content->next != NULL)) {
3082                     tmp = xmlRelaxNGNewDefine(ctxt, node);
3083                     if (tmp != NULL) {
3084                         tmp->type = XML_RELAXNG_GROUP;
3085                         tmp->content = def->content;
3086                         def->content = tmp;
3087                     }
3088                 }
3089
3090                 tmp = xmlRelaxNGNewDefine(ctxt, node);
3091                 if (tmp == NULL)
3092                     return(def);
3093                 tmp->type = XML_RELAXNG_TEXT;
3094                 tmp->next = def->content;
3095                 def->content = tmp;
3096             }
3097         }
3098     } else {
3099         if (ctxt->error != NULL)
3100             ctxt->error(ctxt->userData,
3101                 "Unexpected node %s is not a pattern\n",
3102                         node->name);
3103         ctxt->nbErrors++;
3104         def = NULL;
3105     }
3106     return(def);
3107 }
3108
3109 /**
3110  * xmlRelaxNGParseAttribute:
3111  * @ctxt:  a Relax-NG parser context
3112  * @node:  the element node
3113  *
3114  * parse the content of a RelaxNG attribute node.
3115  *
3116  * Returns the definition pointer or NULL in case of error.
3117  */
3118 static xmlRelaxNGDefinePtr
3119 xmlRelaxNGParseAttribute(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
3120     xmlRelaxNGDefinePtr ret, cur;
3121     xmlNodePtr child;
3122     int old_flags;
3123
3124     ret = xmlRelaxNGNewDefine(ctxt, node);
3125     if (ret == NULL)
3126         return(NULL);
3127     ret->type = XML_RELAXNG_ATTRIBUTE;
3128     ret->parent = ctxt->def;
3129     child = node->children;
3130     if (child == NULL) {
3131         if (ctxt->error != NULL)
3132             ctxt->error(ctxt->userData,
3133                     "xmlRelaxNGParseattribute: attribute has no children\n");
3134         ctxt->nbErrors++;
3135         return(ret);
3136     } 
3137     old_flags = ctxt->flags;
3138     ctxt->flags |= XML_RELAXNG_IN_ATTRIBUTE;
3139     cur = xmlRelaxNGParseNameClass(ctxt, child, ret);
3140     if (cur != NULL)
3141         child = child->next;
3142
3143     if (child != NULL) {
3144         cur = xmlRelaxNGParsePattern(ctxt, child);
3145         if (cur != NULL) {
3146             switch (cur->type) {
3147                 case XML_RELAXNG_EMPTY:
3148                 case XML_RELAXNG_NOT_ALLOWED:
3149                 case XML_RELAXNG_TEXT:
3150                 case XML_RELAXNG_ELEMENT:
3151                 case XML_RELAXNG_DATATYPE:
3152                 case XML_RELAXNG_VALUE:
3153                 case XML_RELAXNG_LIST:
3154                 case XML_RELAXNG_REF:
3155                 case XML_RELAXNG_PARENTREF:
3156                 case XML_RELAXNG_EXTERNALREF:
3157                 case XML_RELAXNG_DEF:
3158                 case XML_RELAXNG_ONEORMORE:
3159                 case XML_RELAXNG_ZEROORMORE:
3160                 case XML_RELAXNG_OPTIONAL:
3161                 case XML_RELAXNG_CHOICE:
3162                 case XML_RELAXNG_GROUP:
3163                 case XML_RELAXNG_INTERLEAVE:
3164                 case XML_RELAXNG_ATTRIBUTE:
3165                     ret->content = cur;
3166                     cur->parent = ret;
3167                     break;
3168                 case XML_RELAXNG_START:
3169                 case XML_RELAXNG_PARAM:
3170                 case XML_RELAXNG_EXCEPT:
3171                     if (ctxt->error != NULL)
3172                         ctxt->error(ctxt->userData,
3173                 "attribute has invalid content\n");
3174                     ctxt->nbErrors++;
3175                     break;
3176                 case XML_RELAXNG_NOOP:
3177                     TODO
3178                     if (ctxt->error != NULL)
3179                         ctxt->error(ctxt->userData,
3180                 "Internal error, noop found\n");
3181                     ctxt->nbErrors++;
3182                     break;
3183             }
3184         }
3185         child = child->next;
3186     }
3187     if (child != NULL) {
3188         if (ctxt->error != NULL)
3189             ctxt->error(ctxt->userData, "attribute has multiple children\n");
3190         ctxt->nbErrors++;
3191     }
3192     ctxt->flags = old_flags;
3193     return(ret);
3194 }
3195
3196 /**
3197  * xmlRelaxNGParseExceptNameClass:
3198  * @ctxt:  a Relax-NG parser context
3199  * @node:  the except node
3200  * @attr:  1 if within an attribute, 0 if within an element
3201  *
3202  * parse the content of a RelaxNG nameClass node.
3203  *
3204  * Returns the definition pointer or NULL in case of error.
3205  */
3206 static xmlRelaxNGDefinePtr
3207 xmlRelaxNGParseExceptNameClass(xmlRelaxNGParserCtxtPtr ctxt,
3208                                xmlNodePtr node, int attr) {
3209     xmlRelaxNGDefinePtr ret, cur, last = NULL;
3210     xmlNodePtr child;
3211
3212     if (!IS_RELAXNG(node, "except")) {
3213         if (ctxt->error != NULL)
3214             ctxt->error(ctxt->userData,
3215                 "Expecting an except node\n");
3216         ctxt->nbErrors++;
3217         return(NULL);
3218     }
3219     if (node->next != NULL) {
3220         if (ctxt->error != NULL)
3221             ctxt->error(ctxt->userData,
3222                 "exceptNameClass allows only a single except node\n");
3223         ctxt->nbErrors++;
3224     }
3225     if (node->children == NULL) {
3226         if (ctxt->error != NULL)
3227             ctxt->error(ctxt->userData,
3228                 "except has no content\n");
3229         ctxt->nbErrors++;
3230         return(NULL);
3231     }
3232
3233     ret = xmlRelaxNGNewDefine(ctxt, node);
3234     if (ret == NULL)
3235         return(NULL);
3236     ret->type = XML_RELAXNG_EXCEPT;
3237     child = node->children;
3238     while (child != NULL) {
3239         cur = xmlRelaxNGNewDefine(ctxt, child);
3240         if (cur == NULL)
3241             break;
3242         if (attr)
3243             cur->type = XML_RELAXNG_ATTRIBUTE;
3244         else
3245             cur->type = XML_RELAXNG_ELEMENT;
3246         
3247         if (xmlRelaxNGParseNameClass(ctxt, child, cur) != NULL) {
3248             if (last == NULL) {
3249                 ret->content = cur;
3250             } else {
3251                 last->next = cur;
3252             }
3253             last = cur;
3254         }
3255         child = child->next;
3256     }
3257
3258     return(ret);
3259 }
3260
3261 /**
3262  * xmlRelaxNGParseNameClass:
3263  * @ctxt:  a Relax-NG parser context
3264  * @node:  the nameClass node
3265  * @def:  the current definition
3266  *
3267  * parse the content of a RelaxNG nameClass node.
3268  *
3269  * Returns the definition pointer or NULL in case of error.
3270  */
3271 static xmlRelaxNGDefinePtr
3272 xmlRelaxNGParseNameClass(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node,
3273                          xmlRelaxNGDefinePtr def) {
3274     xmlRelaxNGDefinePtr ret, tmp;
3275     xmlChar *val;
3276
3277     ret = def;
3278     if ((IS_RELAXNG(node, "name")) || (IS_RELAXNG(node, "anyName"))  ||
3279         (IS_RELAXNG(node, "nsName"))) {
3280         if ((def->type != XML_RELAXNG_ELEMENT) &&
3281             (def->type != XML_RELAXNG_ATTRIBUTE)) {
3282             ret = xmlRelaxNGNewDefine(ctxt, node);
3283             if (ret == NULL)
3284                 return(NULL);
3285             ret->parent = def;
3286             if (ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE)
3287                 ret->type = XML_RELAXNG_ATTRIBUTE;
3288             else
3289                 ret->type = XML_RELAXNG_ELEMENT;
3290         }
3291     }
3292     if (IS_RELAXNG(node, "name")) {
3293         val = xmlNodeGetContent(node);
3294         xmlRelaxNGNormExtSpace(val);
3295         if (xmlValidateNCName(val, 0)) {
3296             if (ctxt->error != NULL) {
3297                 if (node->parent != NULL)
3298                     ctxt->error(ctxt->userData,
3299                         "Element %s name '%s' is not an NCName\n",
3300                                 node->parent->name, val);
3301                 else
3302                     ctxt->error(ctxt->userData,
3303                         "name '%s' is not an NCName\n",
3304                                 val);
3305             }
3306             ctxt->nbErrors++;
3307         }
3308         ret->name = val;
3309         val = xmlGetProp(node, BAD_CAST "ns");
3310         ret->ns = val;
3311         if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
3312             (val != NULL) &&
3313             (xmlStrEqual(val, BAD_CAST "http://www.w3.org/2000/xmlns"))) {
3314             ctxt->error(ctxt->userData,
3315                 "Attribute with namespace '%s' is not allowed\n",
3316                         val);
3317             ctxt->nbErrors++;
3318         }
3319         if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
3320             (val != NULL) &&
3321             (val[0] == 0) &&
3322             (xmlStrEqual(ret->name, BAD_CAST "xmlns"))) {
3323             ctxt->error(ctxt->userData,
3324                 "Attribute with QName 'xmlns' is not allowed\n",
3325                         val);
3326             ctxt->nbErrors++;
3327         }
3328     } else if (IS_RELAXNG(node, "anyName")) {
3329         ret->name = NULL;
3330         ret->ns = NULL;
3331         if (node->children != NULL) {
3332             ret->nameClass =
3333                 xmlRelaxNGParseExceptNameClass(ctxt, node->children,
3334                                (def->type == XML_RELAXNG_ATTRIBUTE));
3335         }
3336     } else if (IS_RELAXNG(node, "nsName")) {
3337         ret->name = NULL;
3338         ret->ns = xmlGetProp(node, BAD_CAST "ns");
3339         if (ret->ns == NULL) {
3340             if (ctxt->error != NULL)
3341                 ctxt->error(ctxt->userData,
3342                     "nsName has no ns attribute\n");
3343             ctxt->nbErrors++;
3344         }
3345         if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
3346             (ret->ns != NULL) &&
3347             (xmlStrEqual(ret->ns, BAD_CAST "http://www.w3.org/2000/xmlns"))) {
3348             ctxt->error(ctxt->userData,
3349                 "Attribute with namespace '%s' is not allowed\n",
3350                         ret->ns);
3351             ctxt->nbErrors++;
3352         }
3353         if (node->children != NULL) {
3354             ret->nameClass =
3355                 xmlRelaxNGParseExceptNameClass(ctxt, node->children,
3356                                (def->type == XML_RELAXNG_ATTRIBUTE));
3357         }
3358     } else if (IS_RELAXNG(node, "choice")) {
3359         xmlNodePtr child;
3360         xmlRelaxNGDefinePtr last = NULL;
3361
3362         ret = xmlRelaxNGNewDefine(ctxt, node);
3363         if (ret == NULL)
3364             return(NULL);
3365         ret->parent = def;
3366         ret->type = XML_RELAXNG_CHOICE;
3367
3368         if (node->children == NULL) {
3369             if (ctxt->error != NULL)
3370                 ctxt->error(ctxt->userData,
3371                     "Element choice is empty\n");
3372             ctxt->nbErrors++;
3373         } else {
3374
3375             child = node->children;
3376             while (child != NULL) {
3377                 tmp = xmlRelaxNGParseNameClass(ctxt, child, ret);
3378                 if (tmp != NULL) {
3379                     if (last == NULL) {
3380                         last = ret->nameClass = tmp;
3381                     } else {
3382                         last->next = tmp;
3383                         last = tmp;
3384                     }
3385                 }
3386                 child = child->next;
3387             }
3388         }
3389     } else {
3390         if (ctxt->error != NULL)
3391             ctxt->error(ctxt->userData,
3392     "expecting name, anyName, nsName or choice : got %s\n",
3393                         node->name);
3394         ctxt->nbErrors++;
3395         return(NULL);
3396     }
3397     if (ret != def) {
3398         if (def->nameClass == NULL) {
3399             def->nameClass = ret;
3400         } else {
3401             tmp = def->nameClass;
3402             while (tmp->next != NULL) {
3403                 tmp = tmp->next;
3404             }
3405             tmp->next = ret;
3406         }
3407     }
3408     return(ret);
3409 }
3410
3411 /**
3412  * xmlRelaxNGParseElement:
3413  * @ctxt:  a Relax-NG parser context
3414  * @node:  the element node
3415  *
3416  * parse the content of a RelaxNG element node.
3417  *
3418  * Returns the definition pointer or NULL in case of error.
3419  */
3420 static xmlRelaxNGDefinePtr
3421 xmlRelaxNGParseElement(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
3422     xmlRelaxNGDefinePtr ret, cur, last;
3423     xmlNodePtr child;
3424     const xmlChar *olddefine;
3425
3426     ret = xmlRelaxNGNewDefine(ctxt, node);
3427     if (ret == NULL)
3428         return(NULL);
3429     ret->type = XML_RELAXNG_ELEMENT;
3430     ret->parent = ctxt->def;
3431     child = node->children;
3432     if (child == NULL) {
3433         if (ctxt->error != NULL)
3434             ctxt->error(ctxt->userData,
3435                         "xmlRelaxNGParseElement: element has no children\n");
3436         ctxt->nbErrors++;
3437         return(ret);
3438     } 
3439     cur = xmlRelaxNGParseNameClass(ctxt, child, ret);
3440     if (cur != NULL)
3441         child = child->next;
3442
3443     if (child == NULL) {
3444         if (ctxt->error != NULL)
3445             ctxt->error(ctxt->userData,
3446                         "xmlRelaxNGParseElement: element has no content\n");
3447         ctxt->nbErrors++;
3448         return(ret);
3449     } 
3450     olddefine = ctxt->define;
3451     ctxt->define = NULL;
3452     last = NULL;
3453     while (child != NULL) {
3454         cur = xmlRelaxNGParsePattern(ctxt, child);
3455         if (cur != NULL) {
3456             cur->parent = ret;
3457             switch (cur->type) {
3458                 case XML_RELAXNG_EMPTY:
3459                 case XML_RELAXNG_NOT_ALLOWED:
3460                 case XML_RELAXNG_TEXT:
3461                 case XML_RELAXNG_ELEMENT:
3462                 case XML_RELAXNG_DATATYPE:
3463                 case XML_RELAXNG_VALUE:
3464                 case XML_RELAXNG_LIST:
3465                 case XML_RELAXNG_REF:
3466                 case XML_RELAXNG_PARENTREF:
3467                 case XML_RELAXNG_EXTERNALREF:
3468                 case XML_RELAXNG_DEF:
3469                 case XML_RELAXNG_ZEROORMORE:
3470                 case XML_RELAXNG_ONEORMORE:
3471                 case XML_RELAXNG_OPTIONAL:
3472                 case XML_RELAXNG_CHOICE:
3473                 case XML_RELAXNG_GROUP:
3474                 case XML_RELAXNG_INTERLEAVE:
3475                     if (last == NULL) {
3476                         ret->content = last = cur;
3477                     } else {
3478                         if ((last->type == XML_RELAXNG_ELEMENT) &&
3479                             (ret->content == last)) {
3480                             ret->content = xmlRelaxNGNewDefine(ctxt, node);
3481                             if (ret->content != NULL) {
3482                                 ret->content->type = XML_RELAXNG_GROUP;
3483                                 ret->content->content = last;
3484                             } else {
3485                                 ret->content = last;
3486                             }
3487                         }
3488                         last->next = cur;
3489                         last = cur;
3490                     }
3491                     break;
3492                 case XML_RELAXNG_ATTRIBUTE:
3493                     cur->next = ret->attrs;
3494                     ret->attrs = cur;
3495                     break;
3496                 case XML_RELAXNG_START:
3497                 case XML_RELAXNG_PARAM:
3498                 case XML_RELAXNG_EXCEPT:
3499                     TODO
3500                     ctxt->nbErrors++;
3501                     break;
3502                 case XML_RELAXNG_NOOP:
3503                     TODO
3504                     if (ctxt->error != NULL)
3505                         ctxt->error(ctxt->userData,
3506                 "Internal error, noop found\n");
3507                     ctxt->nbErrors++;
3508                     break;
3509             }
3510         }
3511         child = child->next;
3512     }
3513     ctxt->define = olddefine;
3514     return(ret);
3515 }
3516
3517 /**
3518  * xmlRelaxNGParsePatterns:
3519  * @ctxt:  a Relax-NG parser context
3520  * @nodes:  list of nodes
3521  * @group:  use an implicit <group> for elements
3522  *
3523  * parse the content of a RelaxNG start node.
3524  *
3525  * Returns the definition pointer or NULL in case of error.
3526  */
3527 static xmlRelaxNGDefinePtr
3528 xmlRelaxNGParsePatterns(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes,
3529                         int group) {
3530     xmlRelaxNGDefinePtr def = NULL, last = NULL, cur, parent;
3531
3532     parent = ctxt->def;
3533     while (nodes != NULL) {
3534         if (IS_RELAXNG(nodes, "element")) {
3535             cur = xmlRelaxNGParseElement(ctxt, nodes);
3536             if (def == NULL) {
3537                 def = last = cur;
3538             } else {
3539                 if ((group == 1) && (def->type == XML_RELAXNG_ELEMENT) &&
3540                     (def == last)) {
3541                     def = xmlRelaxNGNewDefine(ctxt, nodes);
3542                     def->type = XML_RELAXNG_GROUP;
3543                     def->content = last;
3544                 }
3545                 last->next = cur;
3546                 last = cur;
3547             }
3548             cur->parent = parent;
3549         } else {
3550             cur = xmlRelaxNGParsePattern(ctxt, nodes);
3551             if (cur != NULL) {
3552                 if (def == NULL) {
3553                     def = last = cur;
3554                 } else {
3555                     last->next = cur;
3556                     last = cur;
3557                 }
3558             }
3559         }
3560         nodes = nodes->next;
3561     }
3562     return(def);
3563 }
3564
3565 /**
3566  * xmlRelaxNGParseStart:
3567  * @ctxt:  a Relax-NG parser context
3568  * @nodes:  start children nodes
3569  *
3570  * parse the content of a RelaxNG start node.
3571  *
3572  * Returns 0 in case of success, -1 in case of error
3573  */
3574 static int
3575 xmlRelaxNGParseStart(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes) {
3576     int ret = 0;
3577     xmlRelaxNGDefinePtr def = NULL, last;
3578
3579     if (nodes == NULL) {
3580         if (ctxt->error != NULL)
3581             ctxt->error(ctxt->userData,
3582                         "start has no children\n");
3583         ctxt->nbErrors++;
3584         return(-1);
3585     }
3586     if (IS_RELAXNG(nodes, "empty")) {
3587         def = xmlRelaxNGNewDefine(ctxt, nodes);
3588         if (def == NULL)
3589             return(-1);
3590         def->type = XML_RELAXNG_EMPTY;
3591         if (nodes->children != NULL) {
3592             if (ctxt->error != NULL)
3593                 ctxt->error(ctxt->userData, "element empty is not empty\n");
3594             ctxt->nbErrors++;
3595         }
3596     } else if (IS_RELAXNG(nodes, "notAllowed")) {
3597         def = xmlRelaxNGNewDefine(ctxt, nodes);
3598         if (def == NULL)
3599             return(-1);
3600         def->type = XML_RELAXNG_NOT_ALLOWED;
3601         if (nodes->children != NULL) {
3602             if (ctxt->error != NULL)
3603                 ctxt->error(ctxt->userData,
3604                         "element notAllowed is not empty\n");
3605             ctxt->nbErrors++;
3606         }
3607     } else {
3608         def = xmlRelaxNGParsePatterns(ctxt, nodes, 1);
3609     }
3610     if (ctxt->grammar->start != NULL) {
3611         last = ctxt->grammar->start;
3612         while (last->next != NULL)
3613             last = last->next;
3614         last->next = def;
3615     } else {
3616         ctxt->grammar->start = def;
3617     }
3618     nodes = nodes->next;
3619     if (nodes != NULL) {
3620         if (ctxt->error != NULL)
3621             ctxt->error(ctxt->userData,
3622                         "start more than one children\n");
3623         ctxt->nbErrors++;
3624         return(-1);
3625     }
3626     return(ret);
3627 }
3628
3629 /**
3630  * xmlRelaxNGParseGrammarContent:
3631  * @ctxt:  a Relax-NG parser context
3632  * @nodes:  grammar children nodes
3633  *
3634  * parse the content of a RelaxNG grammar node.
3635  *
3636  * Returns 0 in case of success, -1 in case of error
3637  */
3638 static int
3639 xmlRelaxNGParseGrammarContent(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes)
3640 {
3641     int ret = 0, tmp;
3642
3643     if (nodes == NULL) {
3644         if (ctxt->error != NULL)
3645             ctxt->error(ctxt->userData,
3646                         "grammar has no children\n");
3647         ctxt->nbErrors++;
3648         return(-1);
3649     }
3650     while (nodes != NULL) {
3651         if (IS_RELAXNG(nodes, "start")) {
3652             if (nodes->children == NULL) {
3653                 if (ctxt->error != NULL)
3654                     ctxt->error(ctxt->userData,
3655                                 "start has no children\n");
3656                 ctxt->nbErrors++;
3657             } else {
3658                 tmp = xmlRelaxNGParseStart(ctxt, nodes->children);
3659                 if (tmp != 0)
3660                     ret = -1;
3661             }
3662         } else if (IS_RELAXNG(nodes, "define")) {
3663             tmp = xmlRelaxNGParseDefine(ctxt, nodes);
3664             if (tmp != 0)
3665                 ret = -1;
3666         } else if (IS_RELAXNG(nodes, "include")) {
3667             tmp = xmlRelaxNGParseInclude(ctxt, nodes);
3668             if (tmp != 0)
3669                 ret = -1;
3670         } else {
3671             if (ctxt->error != NULL)
3672                 ctxt->error(ctxt->userData,
3673                         "grammar has unexpected child %s\n", nodes->name);
3674             ctxt->nbErrors++;
3675             ret = -1;
3676         }
3677         nodes = nodes->next;
3678     }
3679     return (ret);
3680 }
3681
3682 /**
3683  * xmlRelaxNGCheckReference:
3684  * @ref:  the ref
3685  * @ctxt:  a Relax-NG parser context
3686  * @name:  the name associated to the defines
3687  *
3688  * Applies the 4.17. combine attribute rule for all the define
3689  * element of a given grammar using the same name.
3690  */
3691 static void
3692 xmlRelaxNGCheckReference(xmlRelaxNGDefinePtr ref,
3693                 xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *name) {
3694     xmlRelaxNGGrammarPtr grammar;
3695     xmlRelaxNGDefinePtr def, cur;
3696
3697     grammar = ctxt->grammar;
3698     if (grammar == NULL) {
3699         if (ctxt->error != NULL)
3700             ctxt->error(ctxt->userData,
3701                     "Internal error: no grammar in CheckReference %s\n",
3702                         name);
3703         ctxt->nbErrors++;
3704         return;
3705     }
3706     if (ref->content != NULL) {
3707         if (ctxt->error != NULL)
3708             ctxt->error(ctxt->userData,
3709             "Internal error: reference has content in CheckReference %s\n",
3710                         name);
3711         ctxt->nbErrors++;
3712         return;
3713     }
3714     if (grammar->defs != NULL) {
3715         def = xmlHashLookup(grammar->defs, name);
3716         if (def != NULL) {
3717             cur = ref;
3718             while (cur != NULL) {
3719                 cur->content = def;
3720                 cur = cur->nextHash;
3721             }
3722         } else {
3723             if (ctxt->error != NULL)
3724                 ctxt->error(ctxt->userData,
3725                 "Reference %s has no matching definition\n",
3726                             name);
3727             ctxt->nbErrors++;
3728         }
3729     } else {
3730         if (ctxt->error != NULL)
3731             ctxt->error(ctxt->userData,
3732             "Reference %s has no matching definition\n",
3733                         name);
3734         ctxt->nbErrors++;
3735     }
3736     /*
3737      * TODO: make a closure and verify there is no loop !
3738      */
3739 }
3740
3741 /**
3742  * xmlRelaxNGCheckCombine:
3743  * @define:  the define(s) list
3744  * @ctxt:  a Relax-NG parser context
3745  * @name:  the name associated to the defines
3746  *
3747  * Applies the 4.17. combine attribute rule for all the define
3748  * element of a given grammar using the same name.
3749  */
3750 static void
3751 xmlRelaxNGCheckCombine(xmlRelaxNGDefinePtr define,
3752         xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *name) {
3753     xmlChar *combine;
3754     int choiceOrInterleave = -1;
3755     int missing = 0;
3756     xmlRelaxNGDefinePtr cur, last, tmp, tmp2;
3757
3758     if (define->nextHash == NULL)
3759         return;
3760     cur = define;
3761     while (cur != NULL) {
3762         combine = xmlGetProp(cur->node, BAD_CAST "combine");
3763         if (combine != NULL) {
3764             if (xmlStrEqual(combine, BAD_CAST "choice")) {
3765                 if (choiceOrInterleave == -1)
3766                     choiceOrInterleave = 1;
3767                 else if (choiceOrInterleave == 0) {
3768                     if (ctxt->error != NULL)
3769                         ctxt->error(ctxt->userData,
3770                     "Defines for %s use both 'choice' and 'interleave'\n",
3771                                     name);
3772                     ctxt->nbErrors++;
3773                 }
3774             } else if (xmlStrEqual(combine, BAD_CAST "interleave")) {
3775                 if (choiceOrInterleave == -1)
3776                     choiceOrInterleave = 0;
3777                 else if (choiceOrInterleave == 1) {
3778                     if (ctxt->error != NULL)
3779                         ctxt->error(ctxt->userData,
3780                     "Defines for %s use both 'choice' and 'interleave'\n",
3781                                     name);
3782                     ctxt->nbErrors++;
3783                 }
3784             } else {
3785                 if (ctxt->error != NULL)
3786                     ctxt->error(ctxt->userData,
3787                     "Defines for %s use unknown combine value '%s''\n",
3788                                 name, combine);
3789                 ctxt->nbErrors++;
3790             }
3791             xmlFree(combine);
3792         } else {
3793             if (missing == 0)
3794                 missing = 1;
3795             else {
3796                 if (ctxt->error != NULL)
3797                     ctxt->error(ctxt->userData,
3798                     "Some defines for %s lacks the combine attribute\n",
3799                                 name);
3800                 ctxt->nbErrors++;
3801             }
3802         }
3803
3804         cur = cur->nextHash;
3805     }
3806 #ifdef DEBUG
3807     xmlGenericError(xmlGenericErrorContext,
3808                     "xmlRelaxNGCheckCombine(): merging %s defines: %d\n",
3809                     name, choiceOrInterleave);
3810 #endif
3811     if (choiceOrInterleave == -1)
3812         choiceOrInterleave = 0;
3813     cur = xmlRelaxNGNewDefine(ctxt, define->node);
3814     if (cur == NULL)
3815         return;
3816     if (choiceOrInterleave == 0)
3817         cur->type = XML_RELAXNG_INTERLEAVE;
3818     else
3819         cur->type = XML_RELAXNG_CHOICE;
3820     tmp = define;
3821     last = NULL;
3822     while (tmp != NULL) {
3823         if (tmp->content != NULL) {
3824             if (tmp->content->next != NULL) {
3825                 /*
3826                  * we need first to create a wrapper.
3827                  */
3828                 tmp2 = xmlRelaxNGNewDefine(ctxt, tmp->content->node);
3829                 if (tmp2 == NULL)
3830                     break;
3831                 tmp2->type = XML_RELAXNG_GROUP;
3832                 tmp2->content = tmp->content;
3833             } else {
3834                 tmp2 = tmp->content;
3835             }
3836             if (last == NULL) {
3837                 cur->content = tmp2;
3838             } else {
3839                 last->next = tmp2;
3840             }
3841             last = tmp2;
3842             tmp->content = NULL;
3843         }
3844         tmp = tmp->nextHash;
3845     }
3846     define->content = cur;
3847     if (choiceOrInterleave == 0) {
3848         if (ctxt->interleaves == NULL)
3849             ctxt->interleaves = xmlHashCreate(10);
3850         if (ctxt->interleaves == NULL) {
3851             if (ctxt->error != NULL)
3852                 ctxt->error(ctxt->userData,
3853                     "Failed to create interleaves hash table\n");
3854             ctxt->nbErrors++;
3855         } else {
3856             char tmpname[32];
3857
3858             snprintf(tmpname, 32, "interleave%d", ctxt->nbInterleaves++);
3859             if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST tmpname, cur) < 0) {
3860                 if (ctxt->error != NULL)
3861                     ctxt->error(ctxt->userData,
3862                         "Failed to add %s to hash table\n", tmpname);
3863                 ctxt->nbErrors++;
3864             }
3865         }
3866     }
3867 }
3868
3869 /**
3870  * xmlRelaxNGCombineStart:
3871  * @ctxt:  a Relax-NG parser context
3872  * @grammar:  the grammar
3873  *
3874  * Applies the 4.17. combine rule for all the start
3875  * element of a given grammar.
3876  */
3877 static void
3878 xmlRelaxNGCombineStart(xmlRelaxNGParserCtxtPtr ctxt,
3879                        xmlRelaxNGGrammarPtr grammar) {
3880     xmlRelaxNGDefinePtr starts;
3881     xmlChar *combine;
3882     int choiceOrInterleave = -1;
3883     int missing = 0;
3884     xmlRelaxNGDefinePtr cur;
3885
3886     starts = grammar->start;
3887     if ((starts == NULL) || (starts->next == NULL))
3888         return;
3889     cur = starts;
3890     while (cur != NULL) {
3891         if ((cur->node == NULL) || (cur->node->parent == NULL) ||
3892             (!xmlStrEqual(cur->node->parent->name, BAD_CAST "start"))) {
3893             combine = NULL;
3894             if (ctxt->error != NULL)
3895                 ctxt->error(ctxt->userData,
3896                     "Internal error: start element not found\n");
3897             ctxt->nbErrors++;
3898         } else {
3899             combine = xmlGetProp(cur->node->parent, BAD_CAST "combine");
3900         }
3901         
3902         if (combine != NULL) {
3903             if (xmlStrEqual(combine, BAD_CAST "choice")) {
3904                 if (choiceOrInterleave == -1)
3905                     choiceOrInterleave = 1;
3906                 else if (choiceOrInterleave == 0) {
3907                     if (ctxt->error != NULL)
3908                         ctxt->error(ctxt->userData,
3909                     "<start> use both 'choice' and 'interleave'\n");
3910                     ctxt->nbErrors++;
3911                 }
3912             } else if (xmlStrEqual(combine, BAD_CAST "interleave")) {
3913                 if (choiceOrInterleave == -1)
3914                     choiceOrInterleave = 0;
3915                 else if (choiceOrInterleave == 1) {
3916                     if (ctxt->error != NULL)
3917                         ctxt->error(ctxt->userData,
3918                     "<start> use both 'choice' and 'interleave'\n");
3919                     ctxt->nbErrors++;
3920                 }
3921             } else {
3922                 if (ctxt->error != NULL)
3923                     ctxt->error(ctxt->userData,
3924                     "<start> uses unknown combine value '%s''\n", combine);
3925                 ctxt->nbErrors++;
3926             }
3927             xmlFree(combine);
3928         } else {
3929             if (missing == 0)
3930                 missing = 1;
3931             else {
3932                 if (ctxt->error != NULL)
3933                     ctxt->error(ctxt->userData,
3934                     "Some <start> elements lacks the combine attribute\n");
3935                 ctxt->nbErrors++;
3936             }
3937         }
3938
3939         cur = cur->next;
3940     }
3941 #ifdef DEBUG
3942     xmlGenericError(xmlGenericErrorContext,
3943                     "xmlRelaxNGCombineStart(): merging <start>: %d\n",
3944                     choiceOrInterleave);
3945 #endif
3946     if (choiceOrInterleave == -1)
3947         choiceOrInterleave = 0;
3948     cur = xmlRelaxNGNewDefine(ctxt, starts->node);
3949     if (cur == NULL)
3950         return;
3951     if (choiceOrInterleave == 0)
3952         cur->type = XML_RELAXNG_INTERLEAVE;
3953     else
3954         cur->type = XML_RELAXNG_CHOICE;
3955     cur->content = grammar->start;
3956     grammar->start = cur;
3957     if (choiceOrInterleave == 0) {
3958         if (ctxt->interleaves == NULL)
3959             ctxt->interleaves = xmlHashCreate(10);
3960         if (ctxt->interleaves == NULL) {
3961             if (ctxt->error != NULL)
3962                 ctxt->error(ctxt->userData,
3963                     "Failed to create interleaves hash table\n");
3964             ctxt->nbErrors++;
3965         } else {
3966             char tmpname[32];
3967
3968             snprintf(tmpname, 32, "interleave%d", ctxt->nbInterleaves++);
3969             if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST tmpname, cur) < 0) {
3970                 if (ctxt->error != NULL)
3971                     ctxt->error(ctxt->userData,
3972                         "Failed to add %s to hash table\n", tmpname);
3973                 ctxt->nbErrors++;
3974             }
3975         }
3976     }
3977 }
3978
3979 /**
3980  * xmlRelaxNGCheckCycles:
3981  * @ctxt:  a Relax-NG parser context
3982  * @nodes:  grammar children nodes
3983  * @depth:  the counter
3984  *
3985  * Check for cycles.
3986  *
3987  * Returns 0 if check passed, and -1 in case of error
3988  */
3989 static int
3990 xmlRelaxNGCheckCycles(xmlRelaxNGParserCtxtPtr ctxt, 
3991                       xmlRelaxNGDefinePtr cur, int depth) {
3992     int ret = 0;
3993
3994     while ((ret == 0) && (cur != NULL)) {
3995         if ((cur->type == XML_RELAXNG_REF) ||
3996             (cur->type == XML_RELAXNG_PARENTREF)) {
3997             if (cur->depth == -1) {
3998                 cur->depth = depth;
3999                 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth);
4000                 cur->depth = -2;
4001             } else if (depth == cur->depth) {
4002                 if (ctxt->error != NULL)
4003                     ctxt->error(ctxt->userData,
4004                     "Detected a cycle in %s references\n", cur->name);
4005                 ctxt->nbErrors++;
4006                 return(-1);
4007             }
4008         } else if (cur->type == XML_RELAXNG_ELEMENT) {
4009             ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth + 1);
4010         } else {
4011             ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth);
4012         }
4013         cur = cur->next;
4014     }
4015     return(ret);
4016 }
4017
4018 /**
4019  * xmlRelaxNGTryUnlink:
4020  * @ctxt:  a Relax-NG parser context
4021  * @cur:  the definition to unlink
4022  * @parent:  the parent definition
4023  * @prev:  the previous sibling definition
4024  *
4025  * Try to unlink a definition. If not possble make it a NOOP
4026  *
4027  * Returns the new prev definition
4028  */
4029 static xmlRelaxNGDefinePtr
4030 xmlRelaxNGTryUnlink(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED, 
4031                     xmlRelaxNGDefinePtr cur,
4032                     xmlRelaxNGDefinePtr parent,
4033                     xmlRelaxNGDefinePtr prev) {
4034     if (prev != NULL) {
4035         prev->next = cur->next;
4036     } else {
4037         if (parent != NULL) {
4038             if (parent->content == cur)
4039                 parent->content = cur->next;
4040             else if (parent->attrs == cur)
4041                 parent->attrs = cur->next;
4042             else if (parent->nameClass == cur)
4043                 parent->nameClass = cur->next;
4044         } else {
4045             cur->type = XML_RELAXNG_NOOP;
4046             prev = cur;
4047         }
4048     }
4049     return(prev);
4050 }
4051
4052 /**
4053  * xmlRelaxNGSimplify:
4054  * @ctxt:  a Relax-NG parser context
4055  * @nodes:  grammar children nodes
4056  *
4057  * Check for simplification of empty and notAllowed
4058  */
4059 static void
4060 xmlRelaxNGSimplify(xmlRelaxNGParserCtxtPtr ctxt, 
4061                      xmlRelaxNGDefinePtr cur,
4062                      xmlRelaxNGDefinePtr parent) {
4063     xmlRelaxNGDefinePtr prev = NULL;
4064
4065     while (cur != NULL) {
4066         if ((cur->type == XML_RELAXNG_REF) ||
4067             (cur->type == XML_RELAXNG_PARENTREF)) {
4068             if (cur->depth != -3) {
4069                 cur->depth = -3;
4070                 xmlRelaxNGSimplify(ctxt, cur->content, cur);
4071             }
4072         } else if (cur->type == XML_RELAXNG_NOT_ALLOWED) {
4073             cur->parent = parent;
4074             if ((parent != NULL) &&
4075                 ((parent->type == XML_RELAXNG_ATTRIBUTE) ||
4076                  (parent->type == XML_RELAXNG_LIST) ||
4077                  (parent->type == XML_RELAXNG_GROUP) ||
4078                  (parent->type == XML_RELAXNG_INTERLEAVE) ||
4079                  (parent->type == XML_RELAXNG_ONEORMORE) ||
4080                  (parent->type == XML_RELAXNG_ZEROORMORE))) {
4081                 parent->type = XML_RELAXNG_NOT_ALLOWED;
4082                 break;
4083             }
4084             if ((parent != NULL) &&
4085                 (parent->type == XML_RELAXNG_CHOICE)) {
4086                 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
4087             } else
4088                 prev = cur;
4089         } else if (cur->type == XML_RELAXNG_EMPTY){
4090             cur->parent = parent;
4091             if ((parent != NULL) &&
4092                 ((parent->type == XML_RELAXNG_ONEORMORE) ||
4093                  (parent->type == XML_RELAXNG_ZEROORMORE))) {
4094                 parent->type = XML_RELAXNG_EMPTY;
4095                 break;
4096             }
4097             if ((parent != NULL) &&
4098                 ((parent->type == XML_RELAXNG_GROUP) ||
4099                  (parent->type == XML_RELAXNG_INTERLEAVE))) {
4100                 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
4101             } else
4102                 prev = cur;
4103         } else {
4104             cur->parent = parent;
4105             if (cur->content != NULL)
4106                 xmlRelaxNGSimplify(ctxt, cur->content, cur);
4107             if (cur->attrs != NULL)
4108                 xmlRelaxNGSimplify(ctxt, cur->attrs, cur);
4109             if (cur->nameClass != NULL)
4110                 xmlRelaxNGSimplify(ctxt, cur->nameClass, cur);
4111             /*
4112              * This may result in a simplification
4113              */
4114             if ((cur->type == XML_RELAXNG_GROUP) ||
4115                 (cur->type == XML_RELAXNG_INTERLEAVE)) {
4116                 if (cur->content == NULL)
4117                     cur->type = XML_RELAXNG_EMPTY;
4118                 else if (cur->content->next == NULL) {
4119                     if ((parent == NULL) && (prev == NULL)) {
4120                         cur->type = XML_RELAXNG_NOOP;
4121                     } else if (prev == NULL) {
4122                         parent->content = cur->content;
4123                         cur->content->next = cur->next;
4124                         cur = cur->content;
4125                     } else {
4126                         cur->content->next = cur->next;
4127                         prev->next = cur->content;
4128                         cur = cur->content;
4129                     }
4130                 }
4131             }
4132             /*
4133              * the current node may have been transformed back
4134              */
4135             if ((cur->type == XML_RELAXNG_EXCEPT) &&
4136                 (cur->content != NULL) &&
4137                 (cur->content->type == XML_RELAXNG_NOT_ALLOWED)) {
4138                 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
4139             } else if (cur->type == XML_RELAXNG_NOT_ALLOWED) {
4140                 if ((parent != NULL) &&
4141                     ((parent->type == XML_RELAXNG_ATTRIBUTE) ||
4142                      (parent->type == XML_RELAXNG_LIST) ||
4143                      (parent->type == XML_RELAXNG_GROUP) ||
4144                      (parent->type == XML_RELAXNG_INTERLEAVE) ||
4145                      (parent->type == XML_RELAXNG_ONEORMORE) ||
4146                      (parent->type == XML_RELAXNG_ZEROORMORE))) {
4147                     parent->type = XML_RELAXNG_NOT_ALLOWED;
4148                     break;
4149                 }
4150                 if ((parent != NULL) &&
4151                     (parent->type == XML_RELAXNG_CHOICE)) {
4152                     prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
4153                 } else
4154                     prev = cur;
4155             } else if (cur->type == XML_RELAXNG_EMPTY){
4156                 if ((parent != NULL) &&
4157                     ((parent->type == XML_RELAXNG_ONEORMORE) ||
4158                      (parent->type == XML_RELAXNG_ZEROORMORE))) {
4159                     parent->type = XML_RELAXNG_EMPTY;
4160                     break;
4161                 }
4162                 if ((parent != NULL) &&
4163                     ((parent->type == XML_RELAXNG_GROUP) ||
4164                      (parent->type == XML_RELAXNG_INTERLEAVE) ||
4165                      (parent->type == XML_RELAXNG_CHOICE))) {
4166                     prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
4167                 } else
4168                     prev = cur;
4169             } else {
4170                 prev = cur;
4171             }
4172         }
4173         cur = cur->next;
4174     }
4175 }
4176
4177 /**
4178  * xmlRelaxNGGroupContentType:
4179  * @ct1:  the first content type
4180  * @ct2:  the second content type
4181  *
4182  * Try to group 2 content types
4183  *
4184  * Returns the content type
4185  */
4186 static xmlRelaxNGContentType
4187 xmlRelaxNGGroupContentType(xmlRelaxNGContentType ct1,
4188                            xmlRelaxNGContentType ct2) {
4189     if ((ct1 == XML_RELAXNG_CONTENT_ERROR) ||
4190         (ct2 == XML_RELAXNG_CONTENT_ERROR))
4191         return(XML_RELAXNG_CONTENT_ERROR);
4192     if (ct1 == XML_RELAXNG_CONTENT_EMPTY)
4193         return(ct2);
4194     if (ct2 == XML_RELAXNG_CONTENT_EMPTY)
4195         return(ct1);
4196     if ((ct1 == XML_RELAXNG_CONTENT_COMPLEX) &&
4197         (ct2 == XML_RELAXNG_CONTENT_COMPLEX))
4198         return(XML_RELAXNG_CONTENT_COMPLEX);
4199     return(XML_RELAXNG_CONTENT_ERROR);
4200 }
4201
4202 /**
4203  * xmlRelaxNGMaxContentType:
4204  * @ct1:  the first content type
4205  * @ct2:  the second content type
4206  *
4207  * Compute the max content-type
4208  *
4209  * Returns the content type
4210  */
4211 static xmlRelaxNGContentType
4212 xmlRelaxNGMaxContentType(xmlRelaxNGContentType ct1,
4213                      xmlRelaxNGContentType ct2) {
4214     if ((ct1 == XML_RELAXNG_CONTENT_ERROR) ||
4215         (ct2 == XML_RELAXNG_CONTENT_ERROR))
4216         return(XML_RELAXNG_CONTENT_ERROR);
4217     if ((ct1 == XML_RELAXNG_CONTENT_SIMPLE) ||
4218         (ct2 == XML_RELAXNG_CONTENT_SIMPLE))
4219         return(XML_RELAXNG_CONTENT_SIMPLE);
4220     if ((ct1 == XML_RELAXNG_CONTENT_COMPLEX) ||
4221         (ct2 == XML_RELAXNG_CONTENT_COMPLEX))
4222         return(XML_RELAXNG_CONTENT_COMPLEX);
4223     return(XML_RELAXNG_CONTENT_EMPTY);
4224 }
4225
4226 /**
4227  * xmlRelaxNGCheckRules:
4228  * @ctxt:  a Relax-NG parser context
4229  * @cur:  the current definition
4230  * @flags:  some accumulated flags
4231  * @ptype:  the parent type
4232  *
4233  * Check for rules in section 7.1 and 7.2
4234  *
4235  * Returns the content type of @cur
4236  */
4237 static xmlRelaxNGContentType
4238 xmlRelaxNGCheckRules(xmlRelaxNGParserCtxtPtr ctxt, 
4239                      xmlRelaxNGDefinePtr cur, int flags,
4240                      xmlRelaxNGType ptype) {
4241     int nflags = flags;
4242     xmlRelaxNGContentType ret, tmp, val = XML_RELAXNG_CONTENT_EMPTY;
4243
4244     while (cur != NULL) {
4245         ret = XML_RELAXNG_CONTENT_EMPTY;
4246         if ((cur->type == XML_RELAXNG_REF) ||
4247             (cur->type == XML_RELAXNG_PARENTREF)) {
4248             if (flags & XML_RELAXNG_IN_LIST) {
4249                 if (ctxt->error != NULL)
4250                     ctxt->error(ctxt->userData,
4251                 "Found forbidden pattern list//ref\n");
4252                 ctxt->nbErrors++;
4253             }
4254             if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
4255                 if (ctxt->error != NULL)
4256                     ctxt->error(ctxt->userData,
4257                         "Found forbidden pattern attribute//ref\n");
4258                 ctxt->nbErrors++;
4259             }
4260             if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
4261                 if (ctxt->error != NULL)
4262                     ctxt->error(ctxt->userData,
4263                         "Found forbidden pattern data/except//ref\n");
4264                 ctxt->nbErrors++;
4265             }
4266             if (cur->depth > -4) {
4267                 cur->depth = -4;
4268                 ret = xmlRelaxNGCheckRules(ctxt, cur->content,
4269                                            flags, cur->type);
4270                 cur->depth = ret - 15 ;
4271             } else if (cur->depth == -4) {
4272                 ret = XML_RELAXNG_CONTENT_COMPLEX;
4273             } else {
4274                 ret = (xmlRelaxNGContentType) cur->depth + 15;
4275             }
4276         } else if (cur->type == XML_RELAXNG_ELEMENT) {
4277             /*
4278              * The 7.3 Attribute derivation rule for groups is plugged there
4279              */
4280             xmlRelaxNGCheckGroupAttrs(ctxt, cur);
4281             if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
4282                 if (ctxt->error != NULL)
4283                     ctxt->error(ctxt->userData,
4284                         "Found forbidden pattern data/except//element(ref)\n");
4285                 ctxt->nbErrors++;
4286             }
4287             if (flags & XML_RELAXNG_IN_LIST) {
4288                 if (ctxt->error != NULL)
4289                     ctxt->error(ctxt->userData,
4290                 "Found forbidden pattern list//element(ref)\n");
4291                 ctxt->nbErrors++;
4292             }
4293             if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
4294                 if (ctxt->error != NULL)
4295                     ctxt->error(ctxt->userData,
4296                 "Found forbidden pattern attribute//element(ref)\n");
4297                 ctxt->nbErrors++;
4298             }
4299             /*
4300              * reset since in the simple form elements are only child
4301              * of grammar/define
4302              */
4303             nflags = 0;
4304             ret = xmlRelaxNGCheckRules(ctxt, cur->attrs, nflags, cur->type);
4305             if (ret != XML_RELAXNG_CONTENT_EMPTY) {
4306                 if (ctxt->error != NULL)
4307                     ctxt->error(ctxt->userData,
4308                         "Element %s attributes have a content type error\n",
4309                                 cur->name);
4310                 ctxt->nbErrors++;
4311             }
4312             ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
4313             if (ret == XML_RELAXNG_CONTENT_ERROR) {
4314                 if (ctxt->error != NULL)
4315                     ctxt->error(ctxt->userData,
4316                         "Element %s has a content type error\n",
4317                                 cur->name);
4318                 ctxt->nbErrors++;
4319             } else {
4320                 ret = XML_RELAXNG_CONTENT_COMPLEX;
4321             }
4322         } else if (cur->type == XML_RELAXNG_ATTRIBUTE) {
4323             if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
4324                 if (ctxt->error != NULL)
4325                     ctxt->error(ctxt->userData,
4326                         "Found forbidden pattern attribute//attribute\n");
4327                 ctxt->nbErrors++;
4328             }
4329             if (flags & XML_RELAXNG_IN_LIST) {
4330                 if (ctxt->error != NULL)
4331                     ctxt->error(ctxt->userData,
4332                 "Found forbidden pattern list//attribute\n");
4333                 ctxt->nbErrors++;
4334             }
4335             if (flags & XML_RELAXNG_IN_OOMGROUP) {
4336                 if (ctxt->error != NULL)
4337                     ctxt->error(ctxt->userData,
4338                     "Found forbidden pattern oneOrMore//group//attribute\n");
4339                 ctxt->nbErrors++;
4340             }
4341             if (flags & XML_RELAXNG_IN_OOMINTERLEAVE) {
4342                 if (ctxt->error != NULL)
4343                     ctxt->error(ctxt->userData,
4344                 "Found forbidden pattern oneOrMore//interleave//attribute\n");
4345                 ctxt->nbErrors++;
4346             }
4347             if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
4348                 if (ctxt->error != NULL)
4349                     ctxt->error(ctxt->userData,
4350                         "Found forbidden pattern data/except//attribute\n");
4351                 ctxt->nbErrors++;
4352             }
4353             if (flags & XML_RELAXNG_IN_START) {
4354                 if (ctxt->error != NULL)
4355                     ctxt->error(ctxt->userData,
4356                         "Found forbidden pattern start//attribute\n");
4357                 ctxt->nbErrors++;
4358             }
4359             nflags = flags | XML_RELAXNG_IN_ATTRIBUTE;
4360             xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
4361             ret = XML_RELAXNG_CONTENT_EMPTY;
4362         } else if ((cur->type == XML_RELAXNG_ONEORMORE) ||
4363                    (cur->type == XML_RELAXNG_ZEROORMORE)) {
4364             if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
4365                 if (ctxt->error != NULL)
4366                     ctxt->error(ctxt->userData,
4367                         "Found forbidden pattern data/except//oneOrMore\n");
4368                 ctxt->nbErrors++;
4369             }
4370             if (flags & XML_RELAXNG_IN_START) {
4371                 if (ctxt->error != NULL)
4372                     ctxt->error(ctxt->userData,
4373                         "Found forbidden pattern start//oneOrMore\n");
4374                 ctxt->nbErrors++;
4375             }
4376             nflags = flags | XML_RELAXNG_IN_ONEORMORE;
4377             ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
4378             ret = xmlRelaxNGGroupContentType(ret, ret);
4379         } else if (cur->type == XML_RELAXNG_LIST) {
4380             if (flags & XML_RELAXNG_IN_LIST) {
4381                 if (ctxt->error != NULL)
4382                     ctxt->error(ctxt->userData,
4383                 "Found forbidden pattern list//list\n");
4384                 ctxt->nbErrors++;
4385             }
4386             if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
4387                 if (ctxt->error != NULL)
4388                     ctxt->error(ctxt->userData,
4389                         "Found forbidden pattern data/except//list\n");
4390                 ctxt->nbErrors++;
4391             }
4392             if (flags & XML_RELAXNG_IN_START) {
4393                 if (ctxt->error != NULL)
4394                     ctxt->error(ctxt->userData,
4395                         "Found forbidden pattern start//list\n");
4396                 ctxt->nbErrors++;
4397             }
4398             nflags = flags | XML_RELAXNG_IN_LIST;
4399             ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
4400         } else if (cur->type == XML_RELAXNG_GROUP) {
4401             if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
4402                 if (ctxt->error != NULL)
4403                     ctxt->error(ctxt->userData,
4404                         "Found forbidden pattern data/except//group\n");
4405                 ctxt->nbErrors++;
4406             }
4407             if (flags & XML_RELAXNG_IN_START) {
4408                 if (ctxt->error != NULL)
4409                     ctxt->error(ctxt->userData,
4410                         "Found forbidden pattern start//group\n");
4411                 ctxt->nbErrors++;
4412             }
4413             if (flags & XML_RELAXNG_IN_ONEORMORE)
4414                 nflags = flags | XML_RELAXNG_IN_OOMGROUP;
4415             else
4416                 nflags = flags;
4417             ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
4418             /*
4419              * The 7.3 Attribute derivation rule for groups is plugged there
4420              */
4421             xmlRelaxNGCheckGroupAttrs(ctxt, cur);
4422         } else if (cur->type == XML_RELAXNG_INTERLEAVE) {
4423             if (flags & XML_RELAXNG_IN_LIST) {
4424                 if (ctxt->error != NULL)
4425                     ctxt->error(ctxt->userData,
4426                 "Found forbidden pattern list//interleave\n");
4427                 ctxt->nbErrors++;
4428             }
4429             if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
4430                 if (ctxt->error != NULL)
4431                     ctxt->error(ctxt->userData,
4432                         "Found forbidden pattern data/except//interleave\n");
4433                 ctxt->nbErrors++;
4434             }
4435             if (flags & XML_RELAXNG_IN_START) {
4436                 if (ctxt->error != NULL)
4437                     ctxt->error(ctxt->userData,
4438                         "Found forbidden pattern start//interleave\n");
4439                 ctxt->nbErrors++;
4440             }
4441             if (flags & XML_RELAXNG_IN_ONEORMORE)
4442                 nflags = flags | XML_RELAXNG_IN_OOMINTERLEAVE;
4443             else
4444                 nflags = flags;
4445             ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
4446         } else if (cur->type == XML_RELAXNG_EXCEPT) {
4447             if ((cur->parent != NULL) &&
4448                 (cur->parent->type == XML_RELAXNG_DATATYPE))
4449                 nflags = flags | XML_RELAXNG_IN_DATAEXCEPT;
4450             else
4451                 nflags = flags;
4452             ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
4453         } else if (cur->type == XML_RELAXNG_DATATYPE) {
4454             if (flags & XML_RELAXNG_IN_START) {
4455                 if (ctxt->error != NULL)
4456                     ctxt->error(ctxt->userData,
4457                         "Found forbidden pattern start//data\n");
4458                 ctxt->nbErrors++;
4459             }
4460             xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
4461             ret = XML_RELAXNG_CONTENT_SIMPLE;
4462         } else if (cur->type == XML_RELAXNG_VALUE) {
4463             if (flags & XML_RELAXNG_IN_START) {
4464                 if (ctxt->error != NULL)
4465                     ctxt->error(ctxt->userData,
4466                         "Found forbidden pattern start//value\n");
4467                 ctxt->nbErrors++;
4468             }
4469             xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
4470             ret = XML_RELAXNG_CONTENT_SIMPLE;
4471         } else if (cur->type == XML_RELAXNG_TEXT) {
4472             if (flags & XML_RELAXNG_IN_LIST) {
4473                 if (ctxt->error != NULL)
4474                     ctxt->error(ctxt->userData,
4475                 "Found forbidden pattern list//text\n");
4476                 ctxt->nbErrors++;
4477             }
4478             if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
4479                 if (ctxt->error != NULL)
4480                     ctxt->error(ctxt->userData,
4481                         "Found forbidden pattern data/except//text\n");
4482                 ctxt->nbErrors++;
4483             }
4484             if (flags & XML_RELAXNG_IN_START) {
4485                 if (ctxt->error != NULL)
4486                     ctxt->error(ctxt->userData,
4487                         "Found forbidden pattern start//text\n");
4488                 ctxt->nbErrors++;
4489             }
4490             ret = XML_RELAXNG_CONTENT_COMPLEX;
4491         } else if (cur->type == XML_RELAXNG_EMPTY) {
4492             if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
4493                 if (ctxt->error != NULL)
4494                     ctxt->error(ctxt->userData,
4495                         "Found forbidden pattern data/except//empty\n");
4496                 ctxt->nbErrors++;
4497             }
4498             if (flags & XML_RELAXNG_IN_START) {
4499                 if (ctxt->error != NULL)
4500                     ctxt->error(ctxt->userData,
4501                         "Found forbidden pattern start//empty\n");
4502                 ctxt->nbErrors++;
4503             }
4504             ret = XML_RELAXNG_CONTENT_EMPTY;
4505         } else {
4506             ret = xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
4507         }
4508         cur = cur->next;
4509         if (ptype == XML_RELAXNG_GROUP) {
4510             val = xmlRelaxNGGroupContentType(val, ret);
4511         } else if (ptype == XML_RELAXNG_INTERLEAVE) {
4512             tmp = xmlRelaxNGGroupContentType(val, ret);
4513             if (tmp != XML_RELAXNG_CONTENT_ERROR)
4514                 tmp = xmlRelaxNGMaxContentType(val, ret);
4515         } else if (ptype == XML_RELAXNG_CHOICE) {
4516             val = xmlRelaxNGMaxContentType(val, ret);
4517         } else if (ptype == XML_RELAXNG_LIST) {
4518             val = XML_RELAXNG_CONTENT_SIMPLE;
4519         } else if (ptype == XML_RELAXNG_EXCEPT) {
4520             if (ret == XML_RELAXNG_CONTENT_ERROR)
4521                 val = XML_RELAXNG_CONTENT_ERROR;
4522             else
4523                 val = XML_RELAXNG_CONTENT_SIMPLE;
4524         } else {
4525             val = xmlRelaxNGGroupContentType(val, ret);
4526         }
4527
4528     }
4529     return(val);
4530 }
4531
4532 /**
4533  * xmlRelaxNGParseGrammar:
4534  * @ctxt:  a Relax-NG parser context
4535  * @nodes:  grammar children nodes
4536  *
4537  * parse a Relax-NG <grammar> node
4538  *
4539  * Returns the internal xmlRelaxNGGrammarPtr built or
4540  *         NULL in case of error
4541  */
4542 static xmlRelaxNGGrammarPtr
4543 xmlRelaxNGParseGrammar(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes) {
4544     xmlRelaxNGGrammarPtr ret, tmp, old;
4545
4546     ret = xmlRelaxNGNewGrammar(ctxt);
4547     if (ret == NULL)
4548         return(NULL);
4549
4550     /*
4551      * Link the new grammar in the tree
4552      */
4553     ret->parent = ctxt->grammar;
4554     if (ctxt->grammar != NULL) {
4555         tmp = ctxt->grammar->children;
4556         if (tmp == NULL) {
4557             ctxt->grammar->children = ret;
4558         } else {
4559             while (tmp->next != NULL)
4560                 tmp = tmp->next;
4561             tmp->next = ret;
4562         }
4563     }
4564
4565     old = ctxt->grammar;
4566     ctxt->grammar = ret;
4567     xmlRelaxNGParseGrammarContent(ctxt, nodes);
4568     ctxt->grammar = ret;
4569     if (ctxt->grammar == NULL) {
4570         if (ctxt->error != NULL)
4571             ctxt->error(ctxt->userData,
4572             "Failed to parse <grammar> content\n");
4573         ctxt->nbErrors++;
4574     } else if (ctxt->grammar->start == NULL) {
4575         if (ctxt->error != NULL)
4576             ctxt->error(ctxt->userData,
4577             "Element <grammar> has no <start>\n");
4578         ctxt->nbErrors++;
4579     }
4580
4581     /*
4582      * Apply 4.17 mergingd rules to defines and starts
4583      */
4584     xmlRelaxNGCombineStart(ctxt, ret);
4585     if (ret->defs != NULL) {
4586         xmlHashScan(ret->defs, (xmlHashScanner) xmlRelaxNGCheckCombine,
4587                     ctxt);
4588     }
4589
4590     /*
4591      * link together defines and refs in this grammar
4592      */
4593     if (ret->refs != NULL) {
4594         xmlHashScan(ret->refs, (xmlHashScanner) xmlRelaxNGCheckReference,
4595                     ctxt);
4596     }
4597     ctxt->grammar = old;
4598     return(ret);
4599 }
4600
4601 /**
4602  * xmlRelaxNGParseDocument:
4603  * @ctxt:  a Relax-NG parser context
4604  * @node:  the root node of the RelaxNG schema
4605  *
4606  * parse a Relax-NG definition resource and build an internal
4607  * xmlRelaxNG struture which can be used to validate instances.
4608  *
4609  * Returns the internal XML RelaxNG structure built or
4610  *         NULL in case of error
4611  */
4612 static xmlRelaxNGPtr
4613 xmlRelaxNGParseDocument(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
4614     xmlRelaxNGPtr schema = NULL;
4615     const xmlChar *olddefine;
4616     xmlRelaxNGGrammarPtr old;
4617
4618     if ((ctxt == NULL) || (node == NULL))
4619         return (NULL);
4620
4621     schema = xmlRelaxNGNewRelaxNG(ctxt);
4622     if (schema == NULL)
4623         return(NULL);
4624
4625     olddefine = ctxt->define;
4626     ctxt->define = NULL;
4627     if (IS_RELAXNG(node, "grammar")) {
4628         schema->topgrammar = xmlRelaxNGParseGrammar(ctxt, node->children);
4629     } else {
4630         schema->topgrammar = xmlRelaxNGNewGrammar(ctxt);
4631         if (schema->topgrammar == NULL) {
4632             return(schema);
4633         }
4634         schema->topgrammar->parent = NULL;
4635         old = ctxt->grammar;
4636         ctxt->grammar = schema->topgrammar;
4637         xmlRelaxNGParseStart(ctxt, node);
4638         if (old != NULL)
4639             ctxt->grammar = old;
4640     }
4641     ctxt->define = olddefine;
4642     if (schema->topgrammar->start != NULL) {
4643         xmlRelaxNGCheckCycles(ctxt, schema->topgrammar->start, 0);
4644         if ((ctxt->flags & XML_RELAXNG_IN_EXTERNALREF) == 0) {
4645             xmlRelaxNGSimplify(ctxt, schema->topgrammar->start, NULL);
4646             while ((schema->topgrammar->start != NULL) &&
4647                    (schema->topgrammar->start->type == XML_RELAXNG_NOOP) &&
4648                    (schema->topgrammar->start->next != NULL))
4649                 schema->topgrammar->start = schema->topgrammar->start->content;
4650             xmlRelaxNGCheckRules(ctxt, schema->topgrammar->start,
4651                                  XML_RELAXNG_IN_START, XML_RELAXNG_NOOP);
4652         }
4653     }
4654
4655 #ifdef DEBUG
4656     if (schema == NULL)
4657         xmlGenericError(xmlGenericErrorContext,
4658                         "xmlRelaxNGParseDocument() failed\n");
4659 #endif
4660
4661     return (schema);
4662 }
4663
4664 /************************************************************************
4665  *                                                                      *
4666  *                      Reading RelaxNGs                                *
4667  *                                                                      *
4668  ************************************************************************/
4669
4670 /**
4671  * xmlRelaxNGNewParserCtxt:
4672  * @URL:  the location of the schema
4673  *
4674  * Create an XML RelaxNGs parse context for that file/resource expected
4675  * to contain an XML RelaxNGs file.
4676  *
4677  * Returns the parser context or NULL in case of error
4678  */
4679 xmlRelaxNGParserCtxtPtr
4680 xmlRelaxNGNewParserCtxt(const char *URL) {
4681     xmlRelaxNGParserCtxtPtr ret;
4682
4683     if (URL == NULL)
4684         return(NULL);
4685
4686     ret = (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
4687     if (ret == NULL) {
4688         xmlGenericError(xmlGenericErrorContext,
4689                 "Failed to allocate new schama parser context for %s\n", URL);
4690         return (NULL);
4691     }
4692     memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
4693     ret->URL = xmlStrdup((const xmlChar *)URL);
4694     ret->error = xmlGenericError;
4695     ret->userData = xmlGenericErrorContext;
4696     return (ret);
4697 }
4698
4699 /**
4700  * xmlRelaxNGNewMemParserCtxt:
4701  * @buffer:  a pointer to a char array containing the schemas
4702  * @size:  the size of the array
4703  *
4704  * Create an XML RelaxNGs parse context for that memory buffer expected
4705  * to contain an XML RelaxNGs file.
4706  *
4707  * Returns the parser context or NULL in case of error
4708  */
4709 xmlRelaxNGParserCtxtPtr
4710 xmlRelaxNGNewMemParserCtxt(const char *buffer, int size) {
4711     xmlRelaxNGParserCtxtPtr ret;
4712
4713     if ((buffer == NULL) || (size <= 0))
4714         return(NULL);
4715
4716     ret = (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
4717     if (ret == NULL) {
4718         xmlGenericError(xmlGenericErrorContext,
4719                 "Failed to allocate new schama parser context\n");
4720         return (NULL);
4721     }
4722     memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
4723     ret->buffer = buffer;
4724     ret->size = size;
4725     ret->error = xmlGenericError;
4726     ret->userData = xmlGenericErrorContext;
4727     return (ret);
4728 }
4729
4730 /**
4731  * xmlRelaxNGFreeParserCtxt:
4732  * @ctxt:  the schema parser context
4733  *
4734  * Free the resources associated to the schema parser context
4735  */
4736 void
4737 xmlRelaxNGFreeParserCtxt(xmlRelaxNGParserCtxtPtr ctxt) {
4738     if (ctxt == NULL)
4739         return;
4740     if (ctxt->URL != NULL)
4741         xmlFree(ctxt->URL);
4742     if (ctxt->doc != NULL)
4743         xmlFreeDoc(ctxt->document);
4744     if (ctxt->interleaves != NULL)
4745         xmlHashFree(ctxt->interleaves, NULL);
4746     if (ctxt->documents != NULL)
4747         xmlHashFree(ctxt->documents, (xmlHashDeallocator)
4748                 xmlRelaxNGFreeDocument);
4749     if (ctxt->includes != NULL)
4750         xmlHashFree(ctxt->includes, (xmlHashDeallocator)
4751                 xmlRelaxNGFreeInclude);
4752     if (ctxt->docTab != NULL)
4753         xmlFree(ctxt->docTab);
4754     if (ctxt->incTab != NULL)
4755         xmlFree(ctxt->incTab);
4756     if (ctxt->defTab != NULL) {
4757         int i;
4758
4759         for (i = 0;i < ctxt->defNr;i++)
4760             xmlRelaxNGFreeDefine(ctxt->defTab[i]);
4761         xmlFree(ctxt->defTab);
4762     }
4763     xmlFree(ctxt);
4764 }
4765
4766 /**
4767  * xmlRelaxNGNormExtSpace:
4768  * @value:  a value
4769  *
4770  * Removes the leading and ending spaces of the value
4771  * The string is modified "in situ"
4772  */
4773 static void
4774 xmlRelaxNGNormExtSpace(xmlChar *value) {
4775     xmlChar *start = value;
4776     xmlChar *cur = value;
4777     if (value == NULL)
4778         return;
4779
4780     while (IS_BLANK(*cur)) cur++;
4781     if (cur == start) {
4782         do {
4783             while ((*cur != 0) && (!IS_BLANK(*cur))) cur++;
4784             if (*cur == 0)
4785                 return;
4786             start = cur;
4787             while (IS_BLANK(*cur)) cur++;
4788             if (*cur == 0) {
4789                 *start = 0;
4790                 return;
4791             }
4792         } while (1);
4793     } else {
4794         do {
4795             while ((*cur != 0) && (!IS_BLANK(*cur))) 
4796                 *start++ = *cur++;
4797             if (*cur == 0) {
4798                 *start = 0;
4799                 return;
4800             }
4801             /* don't try to normalize the inner spaces */
4802             while (IS_BLANK(*cur)) cur++;
4803                 *start++ = *cur++;
4804             if (*cur == 0) {
4805                 *start = 0;
4806                 return;
4807             }
4808         } while (1);
4809     }
4810 }
4811
4812 /**
4813  * xmlRelaxNGCheckAttributes:
4814  * @ctxt:  a Relax-NG parser context
4815  * @node:  a Relax-NG node
4816  *
4817  * Check all the attributes on the given node
4818  */
4819 static void
4820 xmlRelaxNGCleanupAttributes(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
4821     xmlAttrPtr cur, next;
4822
4823     cur = node->properties;
4824     while (cur != NULL) {
4825         next = cur->next;
4826         if ((cur->ns == NULL) ||
4827             (xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) {
4828             if (xmlStrEqual(cur->name, BAD_CAST "name")) {
4829                 if ((!xmlStrEqual(node->name, BAD_CAST "element")) &&
4830                     (!xmlStrEqual(node->name, BAD_CAST "attribute")) &&
4831                     (!xmlStrEqual(node->name, BAD_CAST "ref")) &&
4832                     (!xmlStrEqual(node->name, BAD_CAST "parentRef")) &&
4833                     (!xmlStrEqual(node->name, BAD_CAST "param")) &&
4834                     (!xmlStrEqual(node->name, BAD_CAST "define"))) {
4835                     if (ctxt->error != NULL)
4836                         ctxt->error(ctxt->userData,
4837                                 "Attribute %s is not allowed on %s\n",
4838                                     cur->name, node->name);
4839                     ctxt->nbErrors++;
4840                 }
4841             } else if (xmlStrEqual(cur->name, BAD_CAST "type")) {
4842                 if ((!xmlStrEqual(node->name, BAD_CAST "value")) &&
4843                     (!xmlStrEqual(node->name, BAD_CAST "data"))) {
4844                     if (ctxt->error != NULL)
4845                         ctxt->error(ctxt->userData,
4846                                 "Attribute %s is not allowed on %s\n",
4847                                     cur->name, node->name);
4848                     ctxt->nbErrors++;
4849                 }
4850             } else if (xmlStrEqual(cur->name, BAD_CAST "href")) {
4851                 if ((!xmlStrEqual(node->name, BAD_CAST "externalRef")) &&
4852                     (!xmlStrEqual(node->name, BAD_CAST "include"))) {
4853                     if (ctxt->error != NULL)
4854                         ctxt->error(ctxt->userData,
4855                                 "Attribute %s is not allowed on %s\n",
4856                                     cur->name, node->name);
4857                     ctxt->nbErrors++;
4858                 }
4859             } else if (xmlStrEqual(cur->name, BAD_CAST "combine")) {
4860                 if ((!xmlStrEqual(node->name, BAD_CAST "start")) &&
4861                     (!xmlStrEqual(node->name, BAD_CAST "define"))) {
4862                     if (ctxt->error != NULL)
4863                         ctxt->error(ctxt->userData,
4864                                 "Attribute %s is not allowed on %s\n",
4865                                     cur->name, node->name);
4866                     ctxt->nbErrors++;
4867                 }
4868             } else if (xmlStrEqual(cur->name, BAD_CAST "datatypeLibrary")) {
4869                 xmlChar *val;
4870                 xmlURIPtr uri;
4871
4872                 val = xmlNodeListGetString(node->doc, cur->children, 1);
4873                 if (val != NULL) {
4874                     if (val[0] != 0) {
4875                         uri = xmlParseURI((const char *) val);
4876                         if (uri == NULL) {
4877                             if (ctxt->error != NULL)
4878                                 ctxt->error(ctxt->userData,
4879                                 "Attribute %s contains invalid URI %s\n",
4880                                             cur->name, val);
4881                             ctxt->nbErrors++;
4882                         } else {
4883                             if (uri->scheme == NULL) {
4884                                 if (ctxt->error != NULL)
4885                                     ctxt->error(ctxt->userData,
4886                                     "Attribute %s URI %s is not absolute\n",
4887                                                 cur->name, val);
4888                                 ctxt->nbErrors++;
4889                             }
4890                             if (uri->fragment != NULL) {
4891                                 if (ctxt->error != NULL)
4892                                     ctxt->error(ctxt->userData,
4893                                     "Attribute %s URI %s has a fragment ID\n",
4894                                                 cur->name, val);
4895                                 ctxt->nbErrors++;
4896                             }
4897                             xmlFreeURI(uri);
4898                         }
4899                     }
4900                     xmlFree(val);
4901                 }
4902             } else if (!xmlStrEqual(cur->name, BAD_CAST "ns")) {
4903                 if (ctxt->error != NULL)
4904                     ctxt->error(ctxt->userData,
4905                             "Unknown attribute %s on %s\n",
4906                                 cur->name, node->name);
4907                 ctxt->nbErrors++;
4908             }
4909         }
4910         cur = next;
4911     }
4912 }
4913
4914 /**
4915  * xmlRelaxNGCleanupTree:
4916  * @ctxt:  a Relax-NG parser context
4917  * @root:  an xmlNodePtr subtree
4918  *
4919  * Cleanup the subtree from unwanted nodes for parsing, resolve
4920  * Include and externalRef lookups.
4921  */
4922 static void
4923 xmlRelaxNGCleanupTree(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr root) {
4924     xmlNodePtr cur, delete;
4925
4926     delete = NULL;
4927     cur = root;
4928     while (cur != NULL) {
4929         if (delete != NULL) {
4930             xmlUnlinkNode(delete);
4931             xmlFreeNode(delete);
4932             delete = NULL;
4933         }
4934         if (cur->type == XML_ELEMENT_NODE) {
4935             /*
4936              * Simplification 4.1. Annotations
4937              */
4938             if ((cur->ns == NULL) ||
4939                 (!xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) {
4940                 if ((cur->parent != NULL) &&
4941                     (cur->parent->type == XML_ELEMENT_NODE) &&
4942                     ((xmlStrEqual(cur->parent->name, BAD_CAST "name")) ||
4943                      (xmlStrEqual(cur->parent->name, BAD_CAST "value")) ||
4944                      (xmlStrEqual(cur->parent->name, BAD_CAST "param")))) {
4945                     if (ctxt->error != NULL)
4946                         ctxt->error(ctxt->userData,
4947                                 "element %s doesn't allow foreign elements\n",
4948                                     cur->parent->name);
4949                     ctxt->nbErrors++;
4950                 }
4951                 delete = cur;
4952                 goto skip_children;
4953             } else {
4954                 xmlRelaxNGCleanupAttributes(ctxt, cur);
4955                 if (xmlStrEqual(cur->name, BAD_CAST "externalRef")) {
4956                     xmlChar *href, *ns, *base, *URL;
4957                     xmlRelaxNGDocumentPtr docu;
4958                     xmlNodePtr tmp;
4959
4960                     ns = xmlGetProp(cur, BAD_CAST "ns");
4961                     if (ns == NULL) {
4962                         tmp = cur->parent;
4963                         while ((tmp != NULL) &&
4964                                (tmp->type == XML_ELEMENT_NODE)) {
4965                             ns = xmlGetProp(tmp, BAD_CAST "ns");
4966                             if (ns != NULL)
4967                                 break;
4968                             tmp = tmp->parent;
4969                         }
4970                     }
4971                     href = xmlGetProp(cur, BAD_CAST "href");
4972                     if (href == NULL) {
4973                         if (ctxt->error != NULL)
4974                             ctxt->error(ctxt->userData,
4975                     "xmlRelaxNGParse: externalRef has no href attribute\n");
4976                         ctxt->nbErrors++;
4977                         delete = cur;
4978                         goto skip_children;
4979                     }
4980                     base = xmlNodeGetBase(cur->doc, cur);
4981                     URL = xmlBuildURI(href, base);
4982                     if (URL == NULL) {
4983                         if (ctxt->error != NULL)
4984                             ctxt->error(ctxt->userData,
4985                         "Failed to compute URL for externalRef %s\n", href);
4986                         ctxt->nbErrors++;
4987                         if (href != NULL)
4988                             xmlFree(href);
4989                         if (base != NULL)
4990                             xmlFree(base);
4991                         delete = cur;
4992                         goto skip_children;
4993                     }
4994                     if (href != NULL)
4995                         xmlFree(href);
4996                     if (base != NULL)
4997                         xmlFree(base);
4998                     docu = xmlRelaxNGLoadExternalRef(ctxt, URL, ns);
4999                     if (docu == NULL) {
5000                         if (ctxt->error != NULL)
5001                             ctxt->error(ctxt->userData,
5002                                 "Failed to load externalRef %s\n", URL);
5003                         ctxt->nbErrors++;
5004                         xmlFree(URL);
5005                         delete = cur;
5006                         goto skip_children;
5007                     }
5008                     if (ns != NULL)
5009                         xmlFree(ns);
5010                     xmlFree(URL);
5011                     cur->_private = docu;
5012                 } else if (xmlStrEqual(cur->name, BAD_CAST "include")) {
5013                     xmlChar *href, *ns, *base, *URL;
5014                     xmlRelaxNGIncludePtr incl;
5015                     xmlNodePtr tmp;
5016
5017                     href = xmlGetProp(cur, BAD_CAST "href");
5018                     if (href == NULL) {
5019                         if (ctxt->error != NULL)
5020                             ctxt->error(ctxt->userData,
5021                     "xmlRelaxNGParse: include has no href attribute\n");
5022                         ctxt->nbErrors++;
5023                         delete = cur;
5024                         goto skip_children;
5025                     }
5026                     base = xmlNodeGetBase(cur->doc, cur);
5027                     URL = xmlBuildURI(href, base);
5028                     if (URL == NULL) {
5029                         if (ctxt->error != NULL)
5030                             ctxt->error(ctxt->userData,
5031                         "Failed to compute URL for include %s\n", href);
5032                         ctxt->nbErrors++;
5033                         if (href != NULL)
5034                             xmlFree(href);
5035                         if (base != NULL)
5036                             xmlFree(base);
5037                         delete = cur;
5038                         goto skip_children;
5039                     }
5040                     if (href != NULL)
5041                         xmlFree(href);
5042                     if (base != NULL)
5043                         xmlFree(base);
5044                     ns = xmlGetProp(cur, BAD_CAST "ns");
5045                     if (ns == NULL) {
5046                         tmp = cur->parent;
5047                         while ((tmp != NULL) &&
5048                                (tmp->type == XML_ELEMENT_NODE)) {
5049                             ns = xmlGetProp(tmp, BAD_CAST "ns");
5050                             if (ns != NULL)
5051                                 break;
5052                             tmp = tmp->parent;
5053                         }
5054                     }
5055                     incl = xmlRelaxNGLoadInclude(ctxt, URL, cur, ns);
5056                     if (ns != NULL)
5057                         xmlFree(ns);
5058                     if (incl == NULL) {
5059                         if (ctxt->error != NULL)
5060                             ctxt->error(ctxt->userData,
5061                                 "Failed to load include %s\n", URL);
5062                         ctxt->nbErrors++;
5063                         xmlFree(URL);
5064                         delete = cur;
5065                         goto skip_children;
5066                     }
5067                     xmlFree(URL);
5068                     cur->_private = incl;
5069                 } else if ((xmlStrEqual(cur->name, BAD_CAST "element")) ||
5070                     (xmlStrEqual(cur->name, BAD_CAST "attribute"))) {
5071                     xmlChar *name, *ns;
5072                     xmlNodePtr text = NULL;
5073                     
5074                     /*
5075                      * Simplification 4.8. name attribute of element
5076                      * and attribute elements
5077                      */
5078                     name = xmlGetProp(cur, BAD_CAST "name");
5079                     if (name != NULL) {
5080                         if (cur->children == NULL) {
5081                             text = xmlNewChild(cur, cur->ns, BAD_CAST "name",
5082                                                name);
5083                         } else {
5084                             xmlNodePtr node;
5085                             node = xmlNewNode(cur->ns, BAD_CAST "name");
5086                             if (node != NULL) {
5087                                 xmlAddPrevSibling(cur->children, node);
5088                                 text = xmlNewText(name);
5089                                 xmlAddChild(node, text);
5090                                 text = node;
5091                             }
5092                         }
5093                         if (text == NULL) {
5094                             if (ctxt->error != NULL)
5095                                 ctxt->error(ctxt->userData,
5096                                 "Failed to create a name %s element\n", name);
5097                             ctxt->nbErrors++;
5098                         }
5099                         xmlUnsetProp(cur, BAD_CAST "name");
5100                         xmlFree(name);
5101                         ns = xmlGetProp(cur, BAD_CAST "ns");
5102                         if (ns != NULL) {
5103                             if (text != NULL) {
5104                                 xmlSetProp(text, BAD_CAST "ns", ns);
5105                                 /* xmlUnsetProp(cur, BAD_CAST "ns"); */
5106                             }
5107                             xmlFree(ns);
5108                         } else if (xmlStrEqual(cur->name,
5109                                    BAD_CAST "attribute")) {
5110                             xmlSetProp(text, BAD_CAST "ns", BAD_CAST "");
5111                         }
5112                     }
5113                 } else if ((xmlStrEqual(cur->name, BAD_CAST "name")) ||
5114                            (xmlStrEqual(cur->name, BAD_CAST "nsName")) ||
5115                            (xmlStrEqual(cur->name, BAD_CAST "value"))) {
5116                     /*
5117                      * Simplification 4.8. name attribute of element
5118                      * and attribute elements
5119                      */
5120                     if (xmlHasProp(cur, BAD_CAST "ns") == NULL) {
5121                         xmlNodePtr node;
5122                         xmlChar *ns = NULL;
5123
5124                         node = cur->parent;
5125                         while ((node != NULL) &&
5126                                (node->type == XML_ELEMENT_NODE)) {
5127                             ns = xmlGetProp(node, BAD_CAST "ns");
5128                             if (ns != NULL) {
5129                                 break;
5130                             }
5131                             node = node->parent;
5132                         }
5133                         if (ns == NULL) {
5134                             xmlSetProp(cur, BAD_CAST "ns", BAD_CAST "");
5135                         } else {
5136                             xmlSetProp(cur, BAD_CAST "ns", ns);
5137                             xmlFree(ns);
5138                         }
5139                     }
5140                     if (xmlStrEqual(cur->name, BAD_CAST "name")) {
5141                         xmlChar *name, *local, *prefix;
5142
5143                         /*
5144                          * Simplification: 4.10. QNames
5145                          */
5146                         name = xmlNodeGetContent(cur);
5147                         if (name != NULL) {
5148                             local = xmlSplitQName2(name, &prefix);
5149                             if (local != NULL) {
5150                                 xmlNsPtr ns;
5151
5152                                 ns = xmlSearchNs(cur->doc, cur, prefix);
5153                                 if (ns == NULL) {
5154                                     if (ctxt->error != NULL)
5155                                         ctxt->error(ctxt->userData,
5156                     "xmlRelaxNGParse: no namespace for prefix %s\n", prefix);
5157                                     ctxt->nbErrors++;
5158                                 } else {
5159                                     xmlSetProp(cur, BAD_CAST "ns", ns->href);
5160                                     xmlNodeSetContent(cur, local);
5161                                 }
5162                                 xmlFree(local);
5163                                 xmlFree(prefix);
5164                             }
5165                             xmlFree(name);
5166                         } 
5167                     }
5168                     /*
5169                      * 4.16
5170                      */
5171                     if (xmlStrEqual(cur->name, BAD_CAST "nsName")) {
5172                         if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) {
5173                             if (ctxt->error != NULL)
5174                                 ctxt->error(ctxt->userData,
5175                     "Found nsName/except//nsName forbidden construct\n");
5176                             ctxt->nbErrors++;
5177                         }
5178                     }
5179                 } else if ((xmlStrEqual(cur->name, BAD_CAST "except")) &&
5180                            (cur != root)) {
5181                     int oldflags = ctxt->flags;
5182
5183                     /*
5184                      * 4.16
5185                      */
5186                     if ((cur->parent != NULL) &&
5187                         (xmlStrEqual(cur->parent->name, BAD_CAST "anyName"))) {
5188                         ctxt->flags |= XML_RELAXNG_IN_ANYEXCEPT;
5189                         xmlRelaxNGCleanupTree(ctxt, cur);
5190                         ctxt->flags = oldflags;
5191                         goto skip_children;
5192                     } else if ((cur->parent != NULL) &&
5193                         (xmlStrEqual(cur->parent->name, BAD_CAST "nsName"))) {
5194                         ctxt->flags |= XML_RELAXNG_IN_NSEXCEPT;
5195                         xmlRelaxNGCleanupTree(ctxt, cur);
5196                         ctxt->flags = oldflags;
5197                         goto skip_children;
5198                     }
5199                 } else if (xmlStrEqual(cur->name, BAD_CAST "anyName")) {
5200                     /*
5201                      * 4.16
5202                      */
5203                     if (ctxt->flags & XML_RELAXNG_IN_ANYEXCEPT) {
5204                         if (ctxt->error != NULL)
5205                             ctxt->error(ctxt->userData,
5206                 "Found anyName/except//anyName forbidden construct\n");
5207                         ctxt->nbErrors++;
5208                     } else if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) {
5209                         if (ctxt->error != NULL)
5210                             ctxt->error(ctxt->userData,
5211                 "Found nsName/except//anyName forbidden construct\n");
5212                         ctxt->nbErrors++;
5213                     }
5214                 }
5215                 /*
5216                  * Thisd is not an else since "include" is transformed
5217                  * into a div
5218                  */
5219                 if (xmlStrEqual(cur->name, BAD_CAST "div")) {
5220                     xmlChar *ns;
5221                     xmlNodePtr child, ins, tmp;
5222
5223                     /*
5224                      * implements rule 4.11
5225                      */
5226
5227                     ns = xmlGetProp(cur, BAD_CAST "ns");
5228
5229                     child = cur->children;
5230                     ins = cur;
5231                     while (child != NULL) {
5232                         if (ns != NULL) {
5233                             if (!xmlHasProp(child, BAD_CAST "ns")) {
5234                                 xmlSetProp(child, BAD_CAST "ns", ns);
5235                             }
5236                         }
5237                         tmp = child->next;
5238                         xmlUnlinkNode(child);
5239                         ins = xmlAddNextSibling(ins, child);
5240                         child = tmp;
5241                     }
5242                     if (ns != NULL)
5243                         xmlFree(ns);
5244                     delete = cur;
5245                     goto skip_children;
5246                 }
5247             }
5248         }
5249         /*
5250          * Simplification 4.2 whitespaces
5251          */
5252         else if (cur->type == XML_TEXT_NODE) {
5253             if (IS_BLANK_NODE(cur)) {
5254                 if (cur->parent->type == XML_ELEMENT_NODE) {
5255                     if ((!xmlStrEqual(cur->parent->name, BAD_CAST "value")) &&
5256                         (!xmlStrEqual(cur->parent->name, BAD_CAST "param")))
5257                         delete = cur;
5258                 } else {
5259                     delete = cur;
5260                     goto skip_children;
5261                 }
5262             }
5263         } else if (cur->type != XML_CDATA_SECTION_NODE) {
5264             delete = cur;
5265             goto skip_children;
5266         }
5267
5268         /*
5269          * Skip to next node
5270          */
5271         if (cur->children != NULL) {
5272             if ((cur->children->type != XML_ENTITY_DECL) &&
5273                 (cur->children->type != XML_ENTITY_REF_NODE) &&
5274                 (cur->children->type != XML_ENTITY_NODE)) {
5275                 cur = cur->children;
5276                 continue;
5277             }
5278         }
5279 skip_children:
5280         if (cur->next != NULL) {
5281             cur = cur->next;
5282             continue;
5283         }
5284         
5285         do {
5286             cur = cur->parent;
5287             if (cur == NULL)
5288                 break;
5289             if (cur == root) {
5290                 cur = NULL;
5291                 break;
5292             }
5293             if (cur->next != NULL) {
5294                 cur = cur->next;
5295                 break;
5296             }
5297         } while (cur != NULL);
5298     }
5299     if (delete != NULL) {
5300         xmlUnlinkNode(delete);
5301         xmlFreeNode(delete);
5302         delete = NULL;
5303     }
5304 }
5305
5306 /**
5307  * xmlRelaxNGCleanupDoc:
5308  * @ctxt:  a Relax-NG parser context
5309  * @doc:  an xmldocPtr document pointer
5310  *
5311  * Cleanup the document from unwanted nodes for parsing, resolve
5312  * Include and externalRef lookups.
5313  *
5314  * Returns the cleaned up document or NULL in case of error
5315  */
5316 static xmlDocPtr
5317 xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt, xmlDocPtr doc) {
5318     xmlNodePtr root;
5319
5320     /*
5321      * Extract the root
5322      */
5323     root = xmlDocGetRootElement(doc);
5324     if (root == NULL) {
5325         if (ctxt->error != NULL)
5326             ctxt->error(ctxt->userData, "xmlRelaxNGParse: %s is empty\n",
5327                         ctxt->URL);
5328         ctxt->nbErrors++;
5329         return (NULL);
5330     }
5331     xmlRelaxNGCleanupTree(ctxt, root);
5332     return(doc);
5333 }
5334
5335 /**
5336  * xmlRelaxNGParse:
5337  * @ctxt:  a Relax-NG parser context
5338  *
5339  * parse a schema definition resource and build an internal
5340  * XML Shema struture which can be used to validate instances.
5341  * *WARNING* this interface is highly subject to change
5342  *
5343  * Returns the internal XML RelaxNG structure built from the resource or
5344  *         NULL in case of error
5345  */
5346 xmlRelaxNGPtr
5347 xmlRelaxNGParse(xmlRelaxNGParserCtxtPtr ctxt)
5348 {
5349     xmlRelaxNGPtr ret = NULL;
5350     xmlDocPtr doc;
5351     xmlNodePtr root;
5352
5353     xmlRelaxNGInitTypes();
5354
5355     if (ctxt == NULL)
5356         return (NULL);
5357
5358     /*
5359      * First step is to parse the input document into an DOM/Infoset
5360      */
5361     if (ctxt->URL != NULL) {
5362         doc = xmlParseFile((const char *) ctxt->URL);
5363         if (doc == NULL) {
5364             if (ctxt->error != NULL)
5365                 ctxt->error(ctxt->userData,
5366                             "xmlRelaxNGParse: could not load %s\n", ctxt->URL);
5367             ctxt->nbErrors++;
5368             return (NULL);
5369         }
5370     } else if (ctxt->buffer != NULL) {
5371         doc = xmlParseMemory(ctxt->buffer, ctxt->size);
5372         if (doc == NULL) {
5373             if (ctxt->error != NULL)
5374                 ctxt->error(ctxt->userData,
5375                             "xmlRelaxNGParse: could not parse schemas\n");
5376             ctxt->nbErrors++;
5377             return (NULL);
5378         }
5379         doc->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
5380         ctxt->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
5381     } else {
5382         if (ctxt->error != NULL)
5383             ctxt->error(ctxt->userData,
5384                         "xmlRelaxNGParse: nothing to parse\n");
5385         ctxt->nbErrors++;
5386         return (NULL);
5387     }
5388     ctxt->document = doc;
5389
5390     /*
5391      * Some preprocessing of the document content
5392      */
5393     doc = xmlRelaxNGCleanupDoc(ctxt, doc);
5394     if (doc == NULL) {
5395         xmlFreeDoc(ctxt->document);
5396         ctxt->document = NULL;
5397         return(NULL);
5398     }
5399
5400     /*
5401      * Then do the parsing for good
5402      */
5403     root = xmlDocGetRootElement(doc);
5404     if (root == NULL) {
5405         if (ctxt->error != NULL)
5406             ctxt->error(ctxt->userData, "xmlRelaxNGParse: %s is empty\n",
5407                         ctxt->URL);
5408         ctxt->nbErrors++;
5409         xmlFreeDoc(doc);
5410         return (NULL);
5411     }
5412     ret = xmlRelaxNGParseDocument(ctxt, root);
5413     if (ret == NULL) {
5414         xmlFreeDoc(doc);
5415         return(NULL);
5416     }
5417
5418     /*
5419      * Check the ref/defines links
5420      */
5421     /*
5422      * try to preprocess interleaves
5423      */
5424     if (ctxt->interleaves != NULL) {
5425         xmlHashScan(ctxt->interleaves,
5426                 (xmlHashScanner)xmlRelaxNGComputeInterleaves, ctxt);
5427     }
5428
5429     /*
5430      * if there was a parsing error return NULL
5431      */
5432     if (ctxt->nbErrors > 0) {
5433         xmlRelaxNGFree(ret);
5434         ctxt->document = NULL;
5435         xmlFreeDoc(doc);
5436         return(NULL);
5437     }
5438
5439     /*
5440      * Transfer the pointer for cleanup at the schema level.
5441      */
5442     ret->doc = doc;
5443     ctxt->document = NULL;
5444     ret->documents = ctxt->documents;
5445     ctxt->documents = NULL;
5446     
5447     ret->includes = ctxt->includes;
5448     ctxt->includes = NULL;
5449     ret->defNr = ctxt->defNr;
5450     ret->defTab = ctxt->defTab;
5451     ctxt->defTab = NULL;
5452
5453     return (ret);
5454 }
5455  
5456 /**
5457  * xmlRelaxNGSetParserErrors:
5458  * @ctxt:  a Relax-NG validation context
5459  * @err:  the error callback
5460  * @warn:  the warning callback
5461  * @ctx:  contextual data for the callbacks
5462  *
5463  * Set the callback functions used to handle errors for a validation context
5464  */
5465 void
5466 xmlRelaxNGSetParserErrors(xmlRelaxNGParserCtxtPtr ctxt,
5467         xmlRelaxNGValidityErrorFunc err,
5468         xmlRelaxNGValidityWarningFunc warn, void *ctx) {
5469     if (ctxt == NULL)
5470         return;
5471     ctxt->error = err;
5472     ctxt->warning = warn;
5473     ctxt->userData = ctx;
5474 }
5475 /************************************************************************
5476  *                                                                      *
5477  *                      Dump back a compiled form                       *
5478  *                                                                      *
5479  ************************************************************************/
5480 static void xmlRelaxNGDumpDefine(FILE * output, xmlRelaxNGDefinePtr define);
5481
5482 /**
5483  * xmlRelaxNGDumpDefines:
5484  * @output:  the file output
5485  * @defines:  a list of define structures
5486  *
5487  * Dump a RelaxNG structure back
5488  */
5489 static void
5490 xmlRelaxNGDumpDefines(FILE * output, xmlRelaxNGDefinePtr defines) {
5491     while (defines != NULL) {
5492         xmlRelaxNGDumpDefine(output, defines);
5493         defines = defines->next;
5494     }
5495 }
5496
5497 /**
5498  * xmlRelaxNGDumpDefine:
5499  * @output:  the file output
5500  * @define:  a define structure
5501  *
5502  * Dump a RelaxNG structure back
5503  */
5504 static void
5505 xmlRelaxNGDumpDefine(FILE * output, xmlRelaxNGDefinePtr define) {
5506     if (define == NULL)
5507         return;
5508     switch(define->type) {
5509         case XML_RELAXNG_EMPTY:
5510             fprintf(output, "<empty/>\n");
5511             break;
5512         case XML_RELAXNG_NOT_ALLOWED:
5513             fprintf(output, "<notAllowed/>\n");
5514             break;
5515         case XML_RELAXNG_TEXT:
5516             fprintf(output, "<text/>\n");
5517             break;
5518         case XML_RELAXNG_ELEMENT:
5519             fprintf(output, "<element>\n");
5520             if (define->name != NULL) {
5521                 fprintf(output, "<name");
5522                 if (define->ns != NULL)
5523                     fprintf(output, " ns=\"%s\"", define->ns);
5524                 fprintf(output, ">%s</name>\n", define->name);
5525             }
5526             xmlRelaxNGDumpDefines(output, define->attrs);
5527             xmlRelaxNGDumpDefines(output, define->content);
5528             fprintf(output, "</element>\n");
5529             break;
5530         case XML_RELAXNG_LIST:
5531             fprintf(output, "<list>\n");
5532             xmlRelaxNGDumpDefines(output, define->content);
5533             fprintf(output, "</list>\n");
5534             break;
5535         case XML_RELAXNG_ONEORMORE:
5536             fprintf(output, "<oneOrMore>\n");
5537             xmlRelaxNGDumpDefines(output, define->content);
5538             fprintf(output, "</oneOrMore>\n");
5539             break;
5540         case XML_RELAXNG_ZEROORMORE:
5541             fprintf(output, "<zeroOrMore>\n");
5542             xmlRelaxNGDumpDefines(output, define->content);
5543             fprintf(output, "</zeroOrMore>\n");
5544             break;
5545         case XML_RELAXNG_CHOICE:
5546             fprintf(output, "<choice>\n");
5547             xmlRelaxNGDumpDefines(output, define->content);
5548             fprintf(output, "</choice>\n");
5549             break;
5550         case XML_RELAXNG_GROUP:
5551             fprintf(output, "<group>\n");
5552             xmlRelaxNGDumpDefines(output, define->content);
5553             fprintf(output, "</group>\n");
5554             break;
5555         case XML_RELAXNG_INTERLEAVE:
5556             fprintf(output, "<interleave>\n");
5557             xmlRelaxNGDumpDefines(output, define->content);
5558             fprintf(output, "</interleave>\n");
5559             break;
5560         case XML_RELAXNG_OPTIONAL:
5561             fprintf(output, "<optional>\n");
5562             xmlRelaxNGDumpDefines(output, define->content);
5563             fprintf(output, "</optional>\n");
5564             break;
5565         case XML_RELAXNG_ATTRIBUTE:
5566             fprintf(output, "<attribute>\n");
5567             xmlRelaxNGDumpDefines(output, define->content);
5568             fprintf(output, "</attribute>\n");
5569             break;
5570         case XML_RELAXNG_DEF:
5571             fprintf(output, "<define");
5572             if (define->name != NULL)
5573                 fprintf(output, " name=\"%s\"", define->name);
5574             fprintf(output, ">\n");
5575             xmlRelaxNGDumpDefines(output, define->content);
5576             fprintf(output, "</define>\n");
5577             break;
5578         case XML_RELAXNG_REF:
5579             fprintf(output, "<ref");
5580             if (define->name != NULL)
5581                 fprintf(output, " name=\"%s\"", define->name);
5582             fprintf(output, ">\n");
5583             xmlRelaxNGDumpDefines(output, define->content);
5584             fprintf(output, "</ref>\n");
5585             break;
5586         case XML_RELAXNG_PARENTREF:
5587             fprintf(output, "<parentRef");
5588             if (define->name != NULL)
5589                 fprintf(output, " name=\"%s\"", define->name);
5590             fprintf(output, ">\n");
5591             xmlRelaxNGDumpDefines(output, define->content);
5592             fprintf(output, "</parentRef>\n");
5593             break;
5594         case XML_RELAXNG_EXTERNALREF:
5595             fprintf(output, "<externalRef>");
5596             xmlRelaxNGDumpDefines(output, define->content);
5597             fprintf(output, "</externalRef>\n");
5598             break;
5599         case XML_RELAXNG_DATATYPE:
5600         case XML_RELAXNG_VALUE:
5601             TODO
5602             break;
5603         case XML_RELAXNG_START:
5604         case XML_RELAXNG_EXCEPT:
5605         case XML_RELAXNG_PARAM:
5606             TODO
5607             break;
5608         case XML_RELAXNG_NOOP:
5609             xmlRelaxNGDumpDefines(output, define->content);
5610             break;
5611     }
5612 }
5613    
5614 /**
5615  * xmlRelaxNGDumpGrammar:
5616  * @output:  the file output
5617  * @grammar:  a grammar structure
5618  * @top:  is this a top grammar 
5619  *
5620  * Dump a RelaxNG structure back
5621  */
5622 static void
5623 xmlRelaxNGDumpGrammar(FILE * output, xmlRelaxNGGrammarPtr grammar, int top)
5624 {
5625     if (grammar == NULL)
5626         return;
5627    
5628     fprintf(output, "<grammar");
5629     if (top)
5630         fprintf(output,
5631                 " xmlns=\"http://relaxng.org/ns/structure/1.0\"");
5632     switch(grammar->combine) {
5633         case XML_RELAXNG_COMBINE_UNDEFINED:
5634             break;
5635         case XML_RELAXNG_COMBINE_CHOICE:
5636             fprintf(output, " combine=\"choice\"");
5637             break;
5638         case XML_RELAXNG_COMBINE_INTERLEAVE:
5639             fprintf(output, " combine=\"interleave\"");
5640             break;
5641         default:
5642             fprintf(output, " <!-- invalid combine value -->");
5643     }
5644     fprintf(output, ">\n");
5645     if (grammar->start == NULL) {
5646         fprintf(output, " <!-- grammar had no start -->");
5647     } else {
5648         fprintf(output, "<start>\n");
5649         xmlRelaxNGDumpDefine(output, grammar->start);
5650         fprintf(output, "</start>\n");
5651     }
5652     /* TODO ? Dump the defines ? */
5653     fprintf(output, "</grammar>\n");
5654 }
5655
5656 /**
5657  * xmlRelaxNGDump:
5658  * @output:  the file output
5659  * @schema:  a schema structure
5660  *
5661  * Dump a RelaxNG structure back
5662  */
5663 void
5664 xmlRelaxNGDump(FILE * output, xmlRelaxNGPtr schema)
5665 {
5666     if (schema == NULL) {
5667         fprintf(output, "RelaxNG empty or failed to compile\n");
5668         return;
5669     }
5670     fprintf(output, "RelaxNG: ");
5671     if (schema->doc == NULL) {
5672         fprintf(output, "no document\n");
5673     } else if (schema->doc->URL != NULL) {
5674         fprintf(output, "%s\n", schema->doc->URL);
5675     } else {
5676         fprintf(output, "\n");
5677     }
5678     if (schema->topgrammar == NULL) {
5679         fprintf(output, "RelaxNG has no top grammar\n");
5680         return;
5681     }
5682     xmlRelaxNGDumpGrammar(output, schema->topgrammar, 1);
5683 }
5684
5685 /**
5686  * xmlRelaxNGDumpTree:
5687  * @output:  the file output
5688  * @schema:  a schema structure
5689  *
5690  * Dump the transformed RelaxNG tree.
5691  */
5692 void
5693 xmlRelaxNGDumpTree(FILE * output, xmlRelaxNGPtr schema)
5694 {
5695     if (schema == NULL) {
5696         fprintf(output, "RelaxNG empty or failed to compile\n");
5697         return;
5698     }
5699     if (schema->doc == NULL) {
5700         fprintf(output, "no document\n");
5701     } else {
5702         xmlDocDump(output, schema->doc); 
5703     }
5704 }
5705
5706 /************************************************************************
5707  *                                                                      *
5708  *                      Validation implementation                       *
5709  *                                                                      *
5710  ************************************************************************/
5711 static int xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt, 
5712                                         xmlRelaxNGDefinePtr define);
5713 static int xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt, 
5714                                    xmlRelaxNGDefinePtr define);
5715
5716 /**
5717  * xmlRelaxNGSkipIgnored:
5718  * @ctxt:  a schema validation context
5719  * @node:  the top node.
5720  *
5721  * Skip ignorable nodes in that context
5722  *
5723  * Returns the new sibling or NULL in case of error.
5724  */
5725 static xmlNodePtr
5726 xmlRelaxNGSkipIgnored(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
5727                       xmlNodePtr node) {
5728     /*
5729      * TODO complete and handle entities
5730      */
5731     while ((node != NULL) &&
5732            ((node->type == XML_COMMENT_NODE) ||
5733             (node->type == XML_PI_NODE) ||
5734             ((node->type == XML_TEXT_NODE) &&
5735              (IS_BLANK_NODE(node))))) {
5736         node = node->next;
5737     }
5738     return(node);
5739 }
5740
5741 /**
5742  * xmlRelaxNGNormalize:
5743  * @ctxt:  a schema validation context
5744  * @str:  the string to normalize
5745  *
5746  * Implements the  normalizeWhiteSpace( s ) function from
5747  * section 6.2.9 of the spec
5748  *
5749  * Returns the new string or NULL in case of error.
5750  */
5751 static xmlChar *
5752 xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt, const xmlChar *str) {
5753     xmlChar *ret, *p;
5754     const xmlChar *tmp;
5755     int len;
5756     
5757     if (str == NULL)
5758         return(NULL);
5759     tmp = str;
5760     while (*tmp != 0) tmp++;
5761     len = tmp - str;
5762
5763     ret = (xmlChar *) xmlMalloc((len + 1) * sizeof(xmlChar));
5764     if (ret == NULL) {
5765         if (ctxt != NULL) {
5766             VALID_CTXT();
5767             VALID_ERROR("xmlRelaxNGNormalize: out of memory\n");
5768         } else {
5769             xmlGenericError(xmlGenericErrorContext,
5770                 "xmlRelaxNGNormalize: out of memory\n");
5771         }
5772         return(NULL);
5773     }
5774     p = ret;
5775     while (IS_BLANK(*str)) str++;
5776     while (*str != 0) {
5777         if (IS_BLANK(*str)) {
5778             while (IS_BLANK(*str)) str++;
5779             if (*str == 0)
5780                 break;
5781             *p++ = ' ';
5782         } else 
5783             *p++ = *str++;
5784     }
5785     *p = 0;
5786     return(ret);
5787 }
5788
5789 /**
5790  * xmlRelaxNGValidateDatatype:
5791  * @ctxt:  a Relax-NG validation context
5792  * @value:  the string value
5793  * @type:  the datatype definition
5794  *
5795  * Validate the given value against the dataype
5796  *
5797  * Returns 0 if the validation succeeded or an error code.
5798  */
5799 static int
5800 xmlRelaxNGValidateDatatype(xmlRelaxNGValidCtxtPtr ctxt, const xmlChar *value,
5801                            xmlRelaxNGDefinePtr define) {
5802     int ret;
5803     xmlRelaxNGTypeLibraryPtr lib;
5804
5805     if ((define == NULL) || (define->data == NULL)) {
5806         return(-1);
5807     }
5808     lib = (xmlRelaxNGTypeLibraryPtr) define->data;
5809     if (lib->check != NULL)
5810         ret = lib->check(lib->data, define->name, value);
5811     else 
5812         ret = -1;
5813     if (ret < 0) {
5814         VALID_CTXT();
5815         VALID_ERROR2("Internal: failed to validate type %s\n", define->name);
5816         return(-1);
5817     } else if (ret == 1) {
5818         ret = 0;
5819     } else {
5820         VALID_CTXT();
5821         VALID_ERROR3("Type %s doesn't allow value %s\n", define->name, value);
5822         return(-1);
5823         ret = -1;
5824     }
5825     if ((ret == 0) && (define->content != NULL)) {
5826         const xmlChar *oldvalue, *oldendvalue;
5827
5828         oldvalue = ctxt->state->value;
5829         oldendvalue = ctxt->state->endvalue;
5830         ctxt->state->value = (xmlChar *) value;
5831         ctxt->state->endvalue = NULL;
5832         ret = xmlRelaxNGValidateValue(ctxt, define->content);
5833         ctxt->state->value = (xmlChar *) oldvalue;
5834         ctxt->state->endvalue = (xmlChar *) oldendvalue;
5835     }
5836     return(ret);
5837 }
5838
5839 /**
5840  * xmlRelaxNGNextValue:
5841  * @ctxt:  a Relax-NG validation context
5842  *
5843  * Skip to the next value when validating within a list
5844  *
5845  * Returns 0 if the operation succeeded or an error code.
5846  */
5847 static int
5848 xmlRelaxNGNextValue(xmlRelaxNGValidCtxtPtr ctxt) {
5849     xmlChar *cur;
5850
5851     cur = ctxt->state->value;
5852     if ((cur == NULL) || (ctxt->state->endvalue == NULL)) {
5853         ctxt->state->value = NULL;
5854         ctxt->state->endvalue = NULL;
5855         return(0);
5856     }
5857     while (*cur != 0) cur++;
5858     while ((cur != ctxt->state->endvalue) && (*cur == 0)) cur++;
5859     if (cur == ctxt->state->endvalue)
5860         ctxt->state->value = NULL;
5861     else
5862         ctxt->state->value = cur;
5863     return(0);
5864 }
5865
5866 /**
5867  * xmlRelaxNGValidateValueList:
5868  * @ctxt:  a Relax-NG validation context
5869  * @defines:  the list of definitions to verify
5870  *
5871  * Validate the given set of definitions for the current value
5872  *
5873  * Returns 0 if the validation succeeded or an error code.
5874  */
5875 static int
5876 xmlRelaxNGValidateValueList(xmlRelaxNGValidCtxtPtr ctxt, 
5877                         xmlRelaxNGDefinePtr defines) {
5878     int ret = 0;
5879
5880     while (defines != NULL) {
5881         ret = xmlRelaxNGValidateValue(ctxt, defines);
5882         if (ret != 0)
5883             break;
5884         defines = defines->next;
5885     }
5886     return(ret);
5887 }
5888
5889 /**
5890  * xmlRelaxNGValidateValue:
5891  * @ctxt:  a Relax-NG validation context
5892  * @define:  the definition to verify
5893  *
5894  * Validate the given definition for the current value
5895  *
5896  * Returns 0 if the validation succeeded or an error code.
5897  */
5898 static int
5899 xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt, 
5900                         xmlRelaxNGDefinePtr define) {
5901     int ret = 0, oldflags;
5902     xmlChar *value;
5903
5904     value = ctxt->state->value;
5905     switch (define->type) {
5906         case XML_RELAXNG_EMPTY: {
5907             if ((value != NULL) && (value[0] != 0)) {
5908                 int idx = 0;
5909
5910                 while (IS_BLANK(value[idx]))
5911                     idx++;
5912                 if (value[idx] != 0)
5913                     ret = -1;
5914             }
5915             break;
5916         }
5917         case XML_RELAXNG_TEXT:
5918             break;
5919         case XML_RELAXNG_VALUE: {
5920             if (!xmlStrEqual(value, define->value)) {
5921                 if (define->name != NULL) {
5922                     xmlRelaxNGTypeLibraryPtr lib;
5923                     
5924                     lib = (xmlRelaxNGTypeLibraryPtr) define->data;
5925                     if ((lib != NULL) && (lib->comp != NULL))
5926                         ret = lib->comp(lib->data, define->name, value,
5927                                         define->value);
5928                     else
5929                         ret = -1;
5930                     if (ret < 0) {
5931                         VALID_CTXT();
5932                         VALID_ERROR2("Internal: failed to compare type %s\n",
5933                                     define->name);
5934                         return(-1);
5935                     } else if (ret == 1) {
5936                         ret = 0;
5937                     } else {
5938                         ret = -1;
5939                     }
5940                 } else {
5941                     xmlChar *nval, *nvalue;
5942
5943                     /*
5944                      * TODO: trivial optimizations are possible by
5945                      * computing at compile-time
5946                      */
5947                     nval = xmlRelaxNGNormalize(ctxt, define->value);
5948                     nvalue = xmlRelaxNGNormalize(ctxt, value);
5949
5950                     if ((nval == NULL) || (nvalue == NULL) ||
5951                         (!xmlStrEqual(nval, nvalue)))
5952                         ret = -1;
5953                     if (nval != NULL)
5954                         xmlFree(nval);
5955                     if (nvalue != NULL)
5956                         xmlFree(nvalue);
5957                 }
5958             }
5959             if (ret == 0)
5960                 xmlRelaxNGNextValue(ctxt);
5961             break;
5962         }
5963         case XML_RELAXNG_DATATYPE: {
5964             ret = xmlRelaxNGValidateDatatype(ctxt, value, define);
5965             if (ret == 0)
5966                 xmlRelaxNGNextValue(ctxt);
5967             
5968             break;
5969         }
5970         case XML_RELAXNG_CHOICE: {
5971             xmlRelaxNGDefinePtr list = define->content;
5972             xmlChar *oldvalue;
5973
5974             oldflags = ctxt->flags;
5975             ctxt->flags |= FLAGS_IGNORABLE;
5976
5977             oldvalue = ctxt->state->value;
5978             while (list != NULL) {
5979                 ret = xmlRelaxNGValidateValue(ctxt, list);
5980                 if (ret == 0) {
5981                     break;
5982                 }
5983                 ctxt->state->value = oldvalue;
5984                 list = list->next;
5985             }
5986             ctxt->flags = oldflags;
5987             if (ret == 0)
5988                 xmlRelaxNGNextValue(ctxt);
5989             break;
5990         }
5991         case XML_RELAXNG_LIST: {
5992             xmlRelaxNGDefinePtr list = define->content;
5993             xmlChar *oldvalue, *oldend, *val, *cur;
5994 #ifdef DEBUG_LIST
5995             int nb_values = 0;
5996 #endif
5997
5998             oldvalue = ctxt->state->value;
5999             oldend = ctxt->state->endvalue;
6000
6001             val = xmlStrdup(oldvalue);
6002             if (val == NULL) {
6003                 val = xmlStrdup(BAD_CAST "");
6004             }
6005             if (val == NULL) {
6006                 VALID_CTXT();
6007                 VALID_ERROR("Internal: no state\n");
6008                 return(-1);
6009             }
6010             cur = val;
6011             while (*cur != 0) {
6012                 if (IS_BLANK(*cur)) {
6013                     *cur = 0;
6014                     cur++;
6015 #ifdef DEBUG_LIST
6016                     nb_values++;
6017 #endif
6018                     while (IS_BLANK(*cur))
6019                         *cur++ = 0;
6020                 } else
6021                     cur++;
6022             }
6023 #ifdef DEBUG_LIST
6024             xmlGenericError(xmlGenericErrorContext,
6025                     "list value: '%s' found %d items\n", oldvalue, nb_values);
6026             nb_values = 0;
6027 #endif 
6028             ctxt->state->endvalue = cur;
6029             cur = val;
6030             while ((*cur == 0) && (cur != ctxt->state->endvalue)) cur++;
6031
6032             ctxt->state->value = cur;
6033
6034             while (list != NULL) {
6035                 if (ctxt->state->value == ctxt->state->endvalue)
6036                     ctxt->state->value = NULL;
6037                 ret = xmlRelaxNGValidateValue(ctxt, list);
6038                 if (ret != 0) {
6039 #ifdef DEBUG_LIST
6040                     xmlGenericError(xmlGenericErrorContext,
6041                         "Failed to validate value: '%s' with %d rule\n",
6042                                     ctxt->state->value, nb_values);
6043 #endif
6044                     break;
6045                 }
6046 #ifdef DEBUG_LIST
6047                 nb_values++;
6048 #endif
6049                 list = list->next;
6050             }
6051
6052             if ((ret == 0) && (ctxt->state->value != NULL) &&
6053                 (ctxt->state->value != ctxt->state->endvalue)) {
6054                 VALID_CTXT();
6055                 VALID_ERROR2("Extra data in list: %s\n", ctxt->state->value);
6056                 ret = -1;
6057             }
6058             xmlFree(val);
6059             ctxt->state->value = oldvalue;
6060             ctxt->state->endvalue = oldend;
6061             break;
6062         }
6063         case XML_RELAXNG_ONEORMORE:
6064             ret = xmlRelaxNGValidateValueList(ctxt, define->content);
6065             if (ret != 0) {
6066                 break;
6067             }
6068             /* no break on purpose */
6069         case XML_RELAXNG_ZEROORMORE: {
6070             xmlChar *cur, *temp;
6071
6072             oldflags = ctxt->flags;
6073             ctxt->flags |= FLAGS_IGNORABLE;
6074             cur = ctxt->state->value;
6075             temp = NULL;
6076             while ((cur != NULL) && (cur != ctxt->state->endvalue) &&
6077                    (temp != cur)) {
6078                 temp = cur;
6079                 ret = xmlRelaxNGValidateValueList(ctxt, define->content);
6080                 if (ret != 0) {
6081                     ctxt->state->value = temp;
6082                     ret = 0;
6083                     break;
6084                 }
6085                 cur = ctxt->state->value;
6086             }
6087             ctxt->flags = oldflags;
6088             break;
6089         }
6090         case XML_RELAXNG_EXCEPT: {
6091             xmlRelaxNGDefinePtr list;
6092
6093             list = define->content;
6094             while (list != NULL) {
6095                 ret = xmlRelaxNGValidateValue(ctxt, list);
6096                 if (ret == 0) {
6097                     ret = -1;
6098                     break;
6099                 } else 
6100                     ret = 0;
6101                 list = list->next;
6102             }
6103             break;
6104         }
6105         case XML_RELAXNG_GROUP: {
6106             xmlRelaxNGDefinePtr list;
6107
6108             list = define->content;
6109             while (list != NULL) {
6110                 ret = xmlRelaxNGValidateValue(ctxt, list);
6111                 if (ret != 0) {
6112                     ret = -1;
6113                     break;
6114                 } else 
6115                     ret = 0;
6116                 list = list->next;
6117             }
6118             break;
6119         }
6120         default:
6121             TODO
6122             ret = -1;
6123     }
6124     return(ret);
6125 }
6126
6127 /**
6128  * xmlRelaxNGValidateValueContent:
6129  * @ctxt:  a Relax-NG validation context
6130  * @defines:  the list of definitions to verify
6131  *
6132  * Validate the given definitions for the current value
6133  *
6134  * Returns 0 if the validation succeeded or an error code.
6135  */
6136 static int
6137 xmlRelaxNGValidateValueContent(xmlRelaxNGValidCtxtPtr ctxt, 
6138                                xmlRelaxNGDefinePtr defines) {
6139     int ret = 0;
6140
6141     while (defines != NULL) {
6142         ret = xmlRelaxNGValidateValue(ctxt, defines);
6143         if (ret != 0)
6144             break;
6145         defines = defines->next;
6146     }
6147     return(ret);
6148 }
6149
6150 /**
6151  * xmlRelaxNGAttributeMatch:
6152  * @ctxt:  a Relax-NG validation context
6153  * @define:  the definition to check
6154  * @prop:  the attribute
6155  *
6156  * Check if the attribute matches the definition nameClass
6157  *
6158  * Returns 1 if the attribute matches, 0 if no, or -1 in case of error
6159  */
6160 static int
6161 xmlRelaxNGAttributeMatch(xmlRelaxNGValidCtxtPtr ctxt, 
6162                          xmlRelaxNGDefinePtr define,
6163                          xmlAttrPtr prop) {
6164     int ret;
6165
6166     if (define->name != NULL) {
6167         if (!xmlStrEqual(define->name, prop->name))
6168             return(0);
6169     }
6170     if (define->ns != NULL) {
6171         if (define->ns[0] == 0) {
6172             if (prop->ns != NULL)
6173                 return(0);
6174         } else {
6175             if ((prop->ns == NULL) ||
6176                 (!xmlStrEqual(define->ns, prop->ns->href)))
6177                 return(0);
6178         }
6179     }
6180     if (define->nameClass == NULL)
6181         return(1);
6182     define = define->nameClass;
6183     if (define->type == XML_RELAXNG_EXCEPT) {
6184         xmlRelaxNGDefinePtr list;
6185
6186         list = define->content;
6187         while (list != NULL) {
6188             ret = xmlRelaxNGAttributeMatch(ctxt, list, prop);
6189             if (ret == 1)
6190                 return(0);
6191             if (ret < 0)
6192                 return(ret);
6193             list = list->next;
6194         }
6195     } else {
6196         TODO
6197     }
6198     return(1);
6199 }
6200
6201 /**
6202  * xmlRelaxNGValidateAttribute:
6203  * @ctxt:  a Relax-NG validation context
6204  * @define:  the definition to verify
6205  *
6206  * Validate the given attribute definition for that node
6207  *
6208  * Returns 0 if the validation succeeded or an error code.
6209  */
6210 static int
6211 xmlRelaxNGValidateAttribute(xmlRelaxNGValidCtxtPtr ctxt, 
6212                             xmlRelaxNGDefinePtr define) {
6213     int ret = 0, i;
6214     xmlChar *value, *oldvalue;
6215     xmlAttrPtr prop = NULL, tmp;
6216
6217     if (ctxt->state->nbAttrLeft <= 0)
6218         return(-1);
6219     if (define->name != NULL) {
6220         for (i = 0;i < ctxt->state->nbAttrs;i++) {
6221             tmp = ctxt->state->attrs[i];
6222             if ((tmp != NULL) && (xmlStrEqual(define->name, tmp->name))) {
6223                 if ((((define->ns == NULL) || (define->ns[0] == 0)) &&
6224                      (tmp->ns == NULL)) ||
6225                     ((tmp->ns != NULL) &&
6226                      (xmlStrEqual(define->ns, tmp->ns->href)))) {
6227                     prop = tmp;
6228                     break;
6229                 }
6230             }
6231         }
6232         if (prop != NULL) {
6233             value = xmlNodeListGetString(prop->doc, prop->children, 1);
6234             oldvalue = ctxt->state->value;
6235             ctxt->state->value = value;
6236             ctxt->state->endvalue = NULL;
6237             ret = xmlRelaxNGValidateValueContent(ctxt, define->content);
6238             if (ctxt->state->value != NULL)
6239                 value = ctxt->state->value;
6240             if (value != NULL)
6241                 xmlFree(value);
6242             ctxt->state->value = oldvalue;
6243             if (ret == 0) {
6244                 /*
6245                  * flag the attribute as processed
6246                  */
6247                 ctxt->state->attrs[i] = NULL;
6248                 ctxt->state->nbAttrLeft--;
6249             }
6250         } else {
6251             ret = -1;
6252         }
6253 #ifdef DEBUG
6254         xmlGenericError(xmlGenericErrorContext,
6255                     "xmlRelaxNGValidateAttribute(%s): %d\n", define->name, ret);
6256 #endif
6257     } else {
6258         for (i = 0;i < ctxt->state->nbAttrs;i++) {
6259             tmp = ctxt->state->attrs[i];
6260             if ((tmp != NULL) &&
6261                 (xmlRelaxNGAttributeMatch(ctxt, define, tmp) == 1)) {
6262                 prop = tmp;
6263                 break;
6264             }
6265         }
6266         if (prop != NULL) {
6267             value = xmlNodeListGetString(prop->doc, prop->children, 1);
6268             oldvalue = ctxt->state->value;
6269             ctxt->state->value = value;
6270             ret = xmlRelaxNGValidateValueContent(ctxt, define->content);
6271             if (ctxt->state->value != NULL)
6272                 value = ctxt->state->value;
6273             if (value != NULL)
6274                 xmlFree(value);
6275             ctxt->state->value = oldvalue;
6276             if (ret == 0) {
6277                 /*
6278                  * flag the attribute as processed
6279                  */
6280                 ctxt->state->attrs[i] = NULL;
6281                 ctxt->state->nbAttrLeft--;
6282             }
6283         } else {
6284             ret = -1;
6285         }
6286 #ifdef DEBUG
6287         if (define->ns != NULL) {
6288             xmlGenericError(xmlGenericErrorContext,
6289                         "xmlRelaxNGValidateAttribute(nsName ns = %s): %d\n",
6290                             define->ns, ret);
6291         } else {
6292             xmlGenericError(xmlGenericErrorContext,
6293                         "xmlRelaxNGValidateAttribute(anyName): %d\n",
6294                             ret);
6295         }
6296 #endif
6297     }
6298     
6299     return(ret);
6300 }
6301
6302 /**
6303  * xmlRelaxNGValidateAttributeList:
6304  * @ctxt:  a Relax-NG validation context
6305  * @define:  the list of definition to verify
6306  *
6307  * Validate the given node against the list of attribute definitions
6308  *
6309  * Returns 0 if the validation succeeded or an error code.
6310  */
6311 static int
6312 xmlRelaxNGValidateAttributeList(xmlRelaxNGValidCtxtPtr ctxt, 
6313                                 xmlRelaxNGDefinePtr defines) {
6314     int ret = 0;
6315     while (defines != NULL) {
6316         if (xmlRelaxNGValidateAttribute(ctxt, defines) != 0)
6317             ret = -1;
6318         defines = defines->next;
6319     }
6320     return(ret);
6321 }
6322
6323 /**
6324  * xmlRelaxNGNodeMatchesList:
6325  * @node:  the node
6326  * @list:  a NULL terminated array of definitions
6327  *
6328  * Check if a node can be matched by one of the definitions
6329  *
6330  * Returns 1 if matches 0 otherwise
6331  */
6332 static int
6333 xmlRelaxNGNodeMatchesList(xmlNodePtr node, xmlRelaxNGDefinePtr *list) {
6334     xmlRelaxNGDefinePtr cur;
6335     int i = 0;
6336
6337     if ((node == NULL) || (list == NULL))
6338         return(0);
6339
6340     cur = list[i++];
6341     while (cur != NULL) {
6342         if ((node->type == XML_ELEMENT_NODE) &&
6343             (cur->type == XML_RELAXNG_ELEMENT)) {
6344             if (cur->name == NULL) {
6345                 if ((node->ns != NULL) &&
6346                     (xmlStrEqual(node->ns->href, cur->ns)))
6347                     return(1);
6348             } else if (xmlStrEqual(cur->name, node->name)) {
6349                 if ((cur->ns == NULL) || (cur->ns[0] == 0)) {
6350                     if (node->ns == NULL)
6351                         return(1);
6352                 } else {
6353                     if ((node->ns != NULL) &&
6354                         (xmlStrEqual(node->ns->href, cur->ns)))
6355                         return(1);
6356                 }
6357             }
6358         } else if ((node->type == XML_TEXT_NODE) &&
6359                    (cur->type == XML_RELAXNG_TEXT)) {
6360             return(1);
6361         }
6362         cur = list[i++];
6363     }
6364     return(0);
6365 }
6366
6367 /**
6368  * xmlRelaxNGValidateInterleave:
6369  * @ctxt:  a Relax-NG validation context
6370  * @define:  the definition to verify
6371  *
6372  * Validate an interleave definition for a node.
6373  *
6374  * Returns 0 if the validation succeeded or an error code.
6375  */
6376 static int
6377 xmlRelaxNGValidateInterleave(xmlRelaxNGValidCtxtPtr ctxt, 
6378                              xmlRelaxNGDefinePtr define) {
6379     int ret = 0, i, nbgroups, left;
6380     xmlRelaxNGPartitionPtr partitions;
6381     xmlRelaxNGInterleaveGroupPtr group = NULL;
6382     xmlNodePtr cur, start, last = NULL, lastchg = NULL, lastelem;
6383     xmlNodePtr *list = NULL, *lasts = NULL;
6384
6385     if (define->data != NULL) {
6386         partitions = (xmlRelaxNGPartitionPtr) define->data;
6387         nbgroups = partitions->nbgroups;
6388         left = nbgroups;
6389     } else {
6390         VALID_CTXT();
6391         VALID_ERROR("Internal: interleave block has no data\n");
6392         return(-1);
6393     }
6394
6395     /*
6396      * Build arrays to store the first and last node of the chain
6397      * pertaining to each group
6398      */
6399     list = (xmlNodePtr *) xmlMalloc(nbgroups * sizeof(xmlNodePtr));
6400     if (list == NULL) {
6401         VALID_CTXT();
6402         VALID_ERROR("Internal: out of memory in interleave check\n");
6403         return(-1);
6404     }
6405     memset(list, 0, nbgroups * sizeof(xmlNodePtr));
6406     lasts = (xmlNodePtr *) xmlMalloc(nbgroups * sizeof(xmlNodePtr));
6407     if (lasts == NULL) {
6408         VALID_CTXT();
6409         VALID_ERROR("Internal: out of memory in interleave check\n");
6410         return(-1);
6411     }
6412     memset(lasts, 0, nbgroups * sizeof(xmlNodePtr));
6413
6414     /*
6415      * Walk the sequence of children finding the right group and
6416      * sorting them in sequences.
6417      */
6418     cur = ctxt->state->seq;
6419     cur = xmlRelaxNGSkipIgnored(ctxt, cur);
6420     start = cur;
6421     while (cur != NULL) {
6422         ctxt->state->seq = cur;
6423         for (i = 0;i < nbgroups;i++) {
6424             group = partitions->groups[i];
6425             if (group == NULL)
6426                 continue;
6427             if (xmlRelaxNGNodeMatchesList(cur, group->defs))
6428                 break;
6429         }
6430         /*
6431          * We break as soon as an element not matched is found
6432          */
6433         if (i >= nbgroups) {
6434             break;
6435         }
6436         if (lasts[i] != NULL) {
6437             lasts[i]->next = cur;
6438             lasts[i] = cur;
6439         } else {
6440             list[i] = cur;
6441             lasts[i] = cur;
6442         }
6443         if (cur->next != NULL)
6444             lastchg = cur->next;
6445         else
6446             lastchg = cur;
6447         cur = xmlRelaxNGSkipIgnored(ctxt, cur->next);
6448     }
6449     if (ret != 0) {
6450         VALID_CTXT();
6451         VALID_ERROR("Invalid sequence in interleave\n");
6452         ret = -1;
6453         goto done;
6454     }
6455     lastelem = cur;
6456     for (i = 0;i < nbgroups;i++) {
6457         group = partitions->groups[i];
6458         if (lasts[i] != NULL) {
6459             last = lasts[i]->next;
6460             lasts[i]->next = NULL;
6461         }
6462         ctxt->state->seq = list[i];
6463         ret = xmlRelaxNGValidateDefinition(ctxt, group->rule);
6464         if (ret != 0)
6465             break;
6466         cur = ctxt->state->seq;
6467         cur = xmlRelaxNGSkipIgnored(ctxt, cur);
6468         if (cur != NULL) {
6469             VALID_CTXT();
6470             VALID_ERROR2("Extra element %s in interleave\n", cur->name);
6471             ret = -1;
6472             goto done;
6473         }
6474         if (lasts[i] != NULL) {
6475             lasts[i]->next = last;
6476         }
6477     }
6478     ctxt->state->seq = lastelem;
6479     if (ret != 0) {
6480         VALID_CTXT();
6481         VALID_ERROR("Invalid sequence in interleave\n");
6482         ret = -1;
6483         goto done;
6484     }
6485
6486 done:
6487     /*
6488      * builds the next links chain from the prev one
6489      */
6490     cur = lastchg;
6491     while (cur != NULL) {
6492         if ((cur == start) || (cur->prev == NULL))
6493             break;
6494         cur->prev->next = cur;
6495         cur = cur->prev;
6496     }
6497
6498     xmlFree(list);
6499     xmlFree(lasts);
6500     return(ret);
6501 }
6502
6503 /**
6504  * xmlRelaxNGValidateElementContent:
6505  * @ctxt:  a Relax-NG validation context
6506  * @define:  the list of definition to verify
6507  *
6508  * Validate the given node content against the (list) of definitions
6509  *
6510  * Returns 0 if the validation succeeded or an error code.
6511  */
6512 static int
6513 xmlRelaxNGValidateElementContent(xmlRelaxNGValidCtxtPtr ctxt, 
6514                           xmlRelaxNGDefinePtr defines) {
6515     int ret = 0, res;
6516
6517     if (ctxt->state == NULL) {
6518         VALID_CTXT();
6519         VALID_ERROR("Internal: no state\n");
6520         return(-1);
6521     }
6522     while (defines != NULL) {
6523         res = xmlRelaxNGValidateDefinition(ctxt, defines);
6524         if (res < 0)
6525             ret = -1;
6526         defines = defines->next;
6527     }
6528
6529     return(ret);
6530 }
6531
6532 /**
6533  * xmlRelaxNGElementMatch:
6534  * @ctxt:  a Relax-NG validation context
6535  * @define:  the definition to check
6536  * @elem:  the element
6537  *
6538  * Check if the element matches the definition nameClass
6539  *
6540  * Returns 1 if the element matches, 0 if no, or -1 in case of error
6541  */
6542 static int
6543 xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt, 
6544                        xmlRelaxNGDefinePtr define,
6545                        xmlNodePtr elem) {
6546     int ret, oldflags;
6547
6548     if (define->name != NULL) {
6549         if (!xmlStrEqual(elem->name, define->name)) {
6550             VALID_CTXT();
6551             VALID_ERROR3("Expecting element %s, got %s\n",
6552                         define->name, elem->name);
6553             return(0);
6554         }
6555     }
6556     if ((define->ns != NULL) && (define->ns[0] != 0)) {
6557         if (elem->ns == NULL) {
6558             VALID_CTXT();
6559             VALID_ERROR2("Expecting a namespace for element %s\n",
6560                         elem->name);
6561             return(0);
6562         } else if (!xmlStrEqual(elem->ns->href, define->ns)) {
6563             VALID_CTXT();
6564             VALID_ERROR3("Expecting element %s has wrong namespace: expecting %s\n",
6565                         elem->name, define->ns);
6566             return(0);
6567         }
6568     } else if ((elem->ns != NULL) && (define->ns != NULL) &&
6569                (define->name == NULL)) {
6570         VALID_CTXT();
6571         VALID_ERROR2("Expecting no namespace for element %s\n",
6572                     define->name);
6573         return(0);
6574     } else if ((elem->ns != NULL) && (define->name != NULL)) {
6575         VALID_CTXT();
6576         VALID_ERROR2("Expecting no namespace for element %s\n",
6577                     define->name);
6578         return(0);
6579     }
6580
6581     if (define->nameClass == NULL)
6582         return(1);
6583
6584     define = define->nameClass;
6585     if (define->type == XML_RELAXNG_EXCEPT) {
6586         xmlRelaxNGDefinePtr list;
6587         oldflags = ctxt->flags;
6588         ctxt->flags |= FLAGS_IGNORABLE;
6589
6590         list = define->content;
6591         while (list != NULL) {
6592             ret = xmlRelaxNGElementMatch(ctxt, list, elem);
6593             if (ret == 1) {
6594                 ctxt->flags = oldflags;
6595                 return(0);
6596             }
6597             if (ret < 0) {
6598                 ctxt->flags = oldflags;
6599                 return(ret);
6600             }
6601             list = list->next;
6602         }
6603         ret = 1;
6604         ctxt->flags = oldflags;
6605     } else if (define->type == XML_RELAXNG_CHOICE) {
6606         xmlRelaxNGDefinePtr list;
6607         oldflags = ctxt->flags;
6608         ctxt->flags |= FLAGS_IGNORABLE;
6609
6610         list = define->nameClass;
6611         while (list != NULL) {
6612             ret = xmlRelaxNGElementMatch(ctxt, list, elem);
6613             if (ret == 1) {
6614                 ctxt->flags = oldflags;
6615                 return(1);
6616             }
6617             if (ret < 0) {
6618                 ctxt->flags = oldflags;
6619                 return(ret);
6620             }
6621             list = list->next;
6622         }
6623         ret = 0;
6624         ctxt->flags = oldflags;
6625     } else {
6626         TODO
6627         ret = -1;
6628     }
6629     return(ret);
6630 }
6631
6632 /**
6633  * xmlRelaxNGValidateDefinition:
6634  * @ctxt:  a Relax-NG validation context
6635  * @define:  the definition to verify
6636  *
6637  * Validate the current node against the definition
6638  *
6639  * Returns 0 if the validation succeeded or an error code.
6640  */
6641 static int
6642 xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt, 
6643                              xmlRelaxNGDefinePtr define) {
6644     xmlNodePtr node;
6645     int ret = 0, i, tmp, oldflags;
6646     xmlRelaxNGValidStatePtr oldstate, state;
6647
6648     if (define == NULL) {
6649         VALID_CTXT();
6650         VALID_ERROR("internal error: define == NULL\n");
6651         return(-1);
6652     }
6653     if (ctxt->state != NULL) {
6654         node = ctxt->state->seq;
6655     } else {
6656         node = NULL;
6657     }
6658 #ifdef DEBUG
6659     for (i = 0;i < ctxt->depth;i++)
6660         xmlGenericError(xmlGenericErrorContext, " ");
6661     xmlGenericError(xmlGenericErrorContext,
6662             "Start validating %s ", xmlRelaxNGDefName(define));
6663     if (define->name != NULL)
6664         xmlGenericError(xmlGenericErrorContext, "%s ", define->name);
6665     if ((node != NULL) && (node->name != NULL))
6666         xmlGenericError(xmlGenericErrorContext, "on %s\n", node->name);
6667     else
6668         xmlGenericError(xmlGenericErrorContext, "\n");
6669 #endif
6670     ctxt->depth++;
6671     switch (define->type) {
6672         case XML_RELAXNG_EMPTY:
6673             node = xmlRelaxNGSkipIgnored(ctxt, node);
6674             if (node != NULL) {
6675                 VALID_CTXT();
6676                 VALID_ERROR("Expecting an empty element\n");
6677                 ret = -1;
6678                 break;
6679             }
6680             ret = 0;
6681             break;
6682         case XML_RELAXNG_NOT_ALLOWED:
6683             ret = -1;
6684             break;
6685         case XML_RELAXNG_TEXT:
6686 #if 0
6687             if (node == NULL) {
6688                 ret = 0;
6689                 break;
6690             }
6691 #endif
6692             while ((node != NULL) &&
6693                    ((node->type == XML_TEXT_NODE) ||
6694                     (node->type == XML_COMMENT_NODE) ||
6695                     (node->type == XML_PI_NODE) ||
6696                     (node->type == XML_CDATA_SECTION_NODE)))
6697                 node = node->next;
6698 #if 0
6699             if (node == ctxt->state->seq) {
6700                 VALID_CTXT();
6701                 VALID_ERROR("Expecting text content\n");
6702                 ret = -1;
6703             }
6704 #endif
6705             ctxt->state->seq = node;
6706             break;
6707         case XML_RELAXNG_ELEMENT:
6708             node = xmlRelaxNGSkipIgnored(ctxt, node);
6709             if (node == NULL) {
6710                 VALID_CTXT();
6711                 VALID_ERROR("Expecting an element, got empty\n");
6712                 ret = -1;
6713                 break;
6714             }
6715             if (node->type != XML_ELEMENT_NODE) {
6716                 VALID_CTXT();
6717                 VALID_ERROR2("Expecting an element got %d type\n", node->type);
6718                 ret = -1;
6719                 break;
6720             }
6721             /*
6722              * This node was already validated successfully against
6723              * this definition.
6724              */
6725             if (node->_private == define) {
6726                 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt, node->next);
6727                 break;
6728             }
6729
6730             ret = xmlRelaxNGElementMatch(ctxt, define, node);
6731             if (ret <= 0) {
6732                 ret = -1;
6733                 break;
6734             }
6735             ret = 0;
6736             
6737             state = xmlRelaxNGNewValidState(ctxt, node);
6738             if (state == NULL) {
6739                 ret = -1;
6740                 break;
6741             }
6742
6743             oldstate = ctxt->state;
6744             ctxt->state = state;
6745             if (define->attrs != NULL) {
6746                 tmp = xmlRelaxNGValidateAttributeList(ctxt, define->attrs);
6747                 if (tmp != 0) {
6748                     ret = -1;
6749 #ifdef DEBUG
6750                     xmlGenericError(xmlGenericErrorContext,
6751                         "E: Element %s failed to validate attributes\n",
6752                             node->name);
6753 #endif
6754                 }
6755             }
6756             if (define->content != NULL) {
6757                 tmp = xmlRelaxNGValidateElementContent(ctxt, define->content);
6758                 if (tmp != 0) {
6759                     ret = -1;
6760 #ifdef DEBUG
6761                     xmlGenericError(xmlGenericErrorContext,
6762                         "E: Element %s failed to validate element content\n",
6763                             node->name);
6764 #endif
6765                 }
6766             }
6767             state = ctxt->state;
6768             if (state->seq != NULL) {
6769                 state->seq = xmlRelaxNGSkipIgnored(ctxt, state->seq);
6770                 if (state->seq != NULL) {
6771                     VALID_CTXT();
6772                     VALID_ERROR3("Extra content for element %s: %s\n",
6773                                 node->name, state->seq->name);
6774                     ret = -1;
6775 #ifdef DEBUG
6776                     xmlGenericError(xmlGenericErrorContext,
6777                         "E: Element %s has extra content: %s\n",
6778                             node->name, state->seq->name);
6779 #endif
6780                 }
6781             }
6782             for (i = 0;i < state->nbAttrs;i++) {
6783                 if (state->attrs[i] != NULL) {
6784                     VALID_CTXT();
6785                     VALID_ERROR3("Invalid attribute %s for element %s\n",
6786                                 state->attrs[i]->name, node->name);
6787                     ret = -1;
6788                 }
6789             }
6790             ctxt->state = oldstate;
6791             xmlRelaxNGFreeValidState(state);
6792             if (oldstate != NULL)
6793                 oldstate->seq = xmlRelaxNGSkipIgnored(ctxt, node->next);
6794             if (ret == 0)
6795                 node->_private = define;
6796
6797
6798 #ifdef DEBUG
6799             xmlGenericError(xmlGenericErrorContext,
6800                     "xmlRelaxNGValidateDefinition(): validated %s : %d",
6801                             node->name, ret);
6802             if (oldstate == NULL)
6803                 xmlGenericError(xmlGenericErrorContext, ": no state\n");
6804             else if (oldstate->seq == NULL)
6805                 xmlGenericError(xmlGenericErrorContext, ": done\n");
6806             else if (oldstate->seq->type == XML_ELEMENT_NODE)
6807                 xmlGenericError(xmlGenericErrorContext, ": next elem %s\n",
6808                         oldstate->seq->name);
6809             else
6810                 xmlGenericError(xmlGenericErrorContext, ": next %s %d\n",
6811                         oldstate->seq->name, oldstate->seq->type);
6812 #endif
6813             break;
6814         case XML_RELAXNG_OPTIONAL:
6815             oldflags = ctxt->flags;
6816             ctxt->flags |= FLAGS_IGNORABLE;
6817             oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state);
6818             ret = xmlRelaxNGValidateDefinition(ctxt, define->content);
6819             if (ret != 0) {
6820                 xmlRelaxNGFreeValidState(ctxt->state);
6821                 ctxt->state = oldstate;
6822                 ret = 0;
6823                 break;
6824             }
6825             xmlRelaxNGFreeValidState(oldstate);
6826             ctxt->flags = oldflags;
6827             ret = 0;
6828             break;
6829         case XML_RELAXNG_ONEORMORE:
6830             ret = xmlRelaxNGValidateDefinition(ctxt, define->content);
6831             if (ret != 0) {
6832                 break;
6833             }
6834             /* no break on purpose */
6835         case XML_RELAXNG_ZEROORMORE: {
6836             oldflags = ctxt->flags;
6837             ctxt->flags |= FLAGS_IGNORABLE;
6838             while (ctxt->state->nbAttrLeft != 0) {
6839                 oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state);
6840                 ret = xmlRelaxNGValidateDefinition(ctxt, define->content);
6841                 if (ret != 0) {
6842                     xmlRelaxNGFreeValidState(ctxt->state);
6843                     ctxt->state = oldstate;
6844                     break;
6845                 }
6846                 xmlRelaxNGFreeValidState(oldstate);
6847             }
6848             if (ret == 0) {
6849                 /*
6850                  * There is no attribute left to be consumed,
6851                  * we can check the closure by looking at ctxt->state->seq
6852                  */
6853                 xmlNodePtr cur, temp;
6854
6855                 cur = ctxt->state->seq;
6856                 temp = NULL;
6857                 while ((cur != NULL) && (temp != cur)) {
6858                     temp = cur;
6859                     oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state);
6860                     ret = xmlRelaxNGValidateDefinition(ctxt, define->content);
6861                     if (ret != 0) {
6862                         xmlRelaxNGFreeValidState(ctxt->state);
6863                         ctxt->state = oldstate;
6864                         break;
6865                     }
6866                     xmlRelaxNGFreeValidState(oldstate);
6867                     cur = ctxt->state->seq;
6868                 }
6869             }
6870             ctxt->flags = oldflags;
6871             ret = 0;
6872             break;
6873         }
6874         case XML_RELAXNG_CHOICE: {
6875             xmlRelaxNGDefinePtr list = define->content;
6876             int success = 0;
6877
6878             oldflags = ctxt->flags;
6879             ctxt->flags |= FLAGS_IGNORABLE;
6880
6881             while (list != NULL) {
6882                 oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state);
6883                 ret = xmlRelaxNGValidateDefinition(ctxt, list);
6884                 if (ret == 0) {
6885                     if (xmlRelaxNGEqualValidState(ctxt, ctxt->state, oldstate)){
6886                         /*
6887                          * if that pattern was nullable flag it but try 
6888                          * to make more progresses
6889                          */
6890                         success = 1;
6891                     } else {
6892                         xmlRelaxNGFreeValidState(oldstate);
6893                         break;
6894                     }
6895                 }
6896                 xmlRelaxNGFreeValidState(ctxt->state);
6897                 ctxt->state = oldstate;
6898                 list = list->next;
6899             }
6900             ctxt->flags = oldflags;
6901             if (success == 1)
6902                 ret = 0;
6903             break;
6904         }
6905         case XML_RELAXNG_DEF:
6906         case XML_RELAXNG_GROUP: {
6907             xmlRelaxNGDefinePtr list = define->content;
6908
6909             while (list != NULL) {
6910                 ret = xmlRelaxNGValidateDefinition(ctxt, list);
6911                 if (ret != 0)
6912                     break;
6913                 list = list->next;
6914             }
6915             break;
6916         }
6917         case XML_RELAXNG_INTERLEAVE:
6918             ret = xmlRelaxNGValidateInterleave(ctxt, define);
6919             break;
6920         case XML_RELAXNG_ATTRIBUTE:
6921             ret = xmlRelaxNGValidateAttribute(ctxt, define);
6922             break;
6923         case XML_RELAXNG_NOOP:
6924         case XML_RELAXNG_REF:
6925         case XML_RELAXNG_PARENTREF:
6926         case XML_RELAXNG_EXTERNALREF:
6927             ret = xmlRelaxNGValidateDefinition(ctxt, define->content);
6928             break;
6929         case XML_RELAXNG_DATATYPE: {
6930             xmlNodePtr child;
6931             xmlChar *content = NULL;
6932
6933             child = node;
6934             while (child != NULL) {
6935                 if (child->type == XML_ELEMENT_NODE) {
6936                     VALID_CTXT();
6937                     VALID_ERROR2("Element %s has child elements\n",
6938                                  node->parent->name);
6939                     ret = -1;
6940                     break;
6941                 } else if ((child->type == XML_TEXT_NODE) ||
6942                            (child->type == XML_CDATA_SECTION_NODE)) {
6943                     content = xmlStrcat(content, child->content);
6944                 }
6945                 /* TODO: handle entities ... */
6946                 child = child->next;
6947             }
6948             if (ret == -1) {
6949                 if (content != NULL)
6950                     xmlFree(content);
6951                 break;
6952             }
6953             if (content == NULL) {
6954                 content = xmlStrdup(BAD_CAST "");
6955                 if (content == NULL) {
6956                     VALID_CTXT();
6957                     VALID_ERROR("Allocation failure\n");
6958                     ret = -1;
6959                     break;
6960                 }
6961             }
6962             ret = xmlRelaxNGValidateDatatype(ctxt, content, define);
6963             if (ret == -1) {
6964                 VALID_CTXT();
6965                 VALID_ERROR2("internal error validating %s\n", define->name);
6966             } else if (ret == 0) {
6967                 ctxt->state->seq = NULL;
6968             }
6969             if (content != NULL)
6970                 xmlFree(content);
6971             break;
6972         }
6973         case XML_RELAXNG_VALUE: {
6974             xmlChar *content = NULL;
6975             xmlChar *oldvalue;
6976             xmlNodePtr child;
6977
6978             child = node;
6979             while (child != NULL) {
6980                 if (child->type == XML_ELEMENT_NODE) {
6981                     VALID_CTXT();
6982                     VALID_ERROR2("Element %s has child elements\n",
6983                                  node->parent->name);
6984                     ret = -1;
6985                     break;
6986                 } else if ((child->type == XML_TEXT_NODE) ||
6987                            (child->type == XML_CDATA_SECTION_NODE)) {
6988                     content = xmlStrcat(content, child->content);
6989                 }
6990                 /* TODO: handle entities ... */
6991                 child = child->next;
6992             }
6993             if (ret == -1) {
6994                 if (content != NULL)
6995                     xmlFree(content);
6996                 break;
6997             }
6998             if (content == NULL) {
6999                 content = xmlStrdup(BAD_CAST "");
7000                 if (content == NULL) {
7001                     VALID_CTXT();
7002                     VALID_ERROR("Allocation failure\n");
7003                     ret = -1;
7004                     break;
7005                 }
7006             }
7007             oldvalue = ctxt->state->value;
7008             ctxt->state->value = content;
7009             ret = xmlRelaxNGValidateValue(ctxt, define);
7010             ctxt->state->value = oldvalue;
7011             if (ret == -1) {
7012                 VALID_CTXT();
7013                 if (define->name != NULL) {
7014                     VALID_ERROR2("error validating value %s\n", define->name);
7015                 } else {
7016                     VALID_ERROR("error validating value\n");
7017                 }
7018             } else if (ret == 0) {
7019                 ctxt->state->seq = NULL;
7020             }
7021             if (content != NULL)
7022                 xmlFree(content);
7023             break;
7024         }
7025         case XML_RELAXNG_LIST: {
7026             xmlChar *content;
7027             xmlNodePtr child;
7028             xmlChar *oldvalue, *oldendvalue;
7029             int len;
7030
7031             /*
7032              * Make sure it's only text nodes
7033              */
7034             
7035             content = NULL;
7036             child = node;
7037             while (child != NULL) {
7038                 if (child->type == XML_ELEMENT_NODE) {
7039                     VALID_CTXT();
7040                     VALID_ERROR2("Element %s has child elements\n",
7041                                  node->parent->name);
7042                     ret = -1;
7043                     break;
7044                 } else if ((child->type == XML_TEXT_NODE) ||
7045                            (child->type == XML_CDATA_SECTION_NODE)) {
7046                     content = xmlStrcat(content, child->content);
7047                 }
7048                 /* TODO: handle entities ... */
7049                 child = child->next;
7050             }
7051             if (ret == -1) {
7052                 if (content != NULL)
7053                     xmlFree(content);
7054                 break;
7055             }
7056             if (content == NULL) {
7057                 content = xmlStrdup(BAD_CAST "");
7058                 if (content == NULL) {
7059                     VALID_CTXT();
7060                     VALID_ERROR("Allocation failure\n");
7061                     ret = -1;
7062                     break;
7063                 }
7064             }
7065             len = xmlStrlen(content);
7066             oldvalue = ctxt->state->value;
7067             oldendvalue = ctxt->state->endvalue;
7068             ctxt->state->value = content;
7069             ctxt->state->endvalue = content + len;
7070             ret = xmlRelaxNGValidateValue(ctxt, define);
7071             ctxt->state->value = oldvalue;
7072             ctxt->state->endvalue = oldendvalue;
7073             if (ret == -1) {
7074                 VALID_CTXT();
7075                 VALID_ERROR("error validating list\n");
7076             } else if ((ret == 0) && (node != NULL)) {
7077                 ctxt->state->seq = node->next;
7078             }
7079             if (content != NULL)
7080                 xmlFree(content);
7081             break;
7082         }
7083         case XML_RELAXNG_START:
7084         case XML_RELAXNG_EXCEPT:
7085         case XML_RELAXNG_PARAM:
7086             TODO
7087             ret = -1;
7088             break;
7089     }
7090     ctxt->depth--;
7091 #ifdef DEBUG
7092     for (i = 0;i < ctxt->depth;i++)
7093         xmlGenericError(xmlGenericErrorContext, " ");
7094     xmlGenericError(xmlGenericErrorContext,
7095             "Validating %s ", xmlRelaxNGDefName(define));
7096     if (define->name != NULL)
7097         xmlGenericError(xmlGenericErrorContext, "%s ", define->name);
7098     if (ret == 0)
7099         xmlGenericError(xmlGenericErrorContext, "suceeded\n");
7100     else
7101         xmlGenericError(xmlGenericErrorContext, "failed\n");
7102 #endif
7103     return(ret);
7104 }
7105
7106 /**
7107  * xmlRelaxNGValidateDocument:
7108  * @ctxt:  a Relax-NG validation context
7109  * @doc:  the document
7110  *
7111  * Validate the given document
7112  *
7113  * Returns 0 if the validation succeeded or an error code.
7114  */
7115 static int
7116 xmlRelaxNGValidateDocument(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc) {
7117     int ret;
7118     xmlRelaxNGPtr schema;
7119     xmlRelaxNGGrammarPtr grammar;
7120     xmlRelaxNGValidStatePtr state;
7121
7122     if ((ctxt == NULL) || (ctxt->schema == NULL) || (doc == NULL))
7123         return(-1);
7124
7125     schema = ctxt->schema;
7126     grammar = schema->topgrammar;
7127     if (grammar == NULL) {
7128         VALID_CTXT();
7129         VALID_ERROR("No top grammar defined\n");
7130         return(-1);
7131     }
7132     state = xmlRelaxNGNewValidState(ctxt, NULL);
7133     ctxt->state = state;
7134     ret = xmlRelaxNGValidateDefinition(ctxt, grammar->start);
7135     state = ctxt->state;
7136     if ((state != NULL) && (state->seq != NULL)) {
7137         xmlNodePtr node;
7138
7139         node = state->seq;
7140         node = xmlRelaxNGSkipIgnored(ctxt, node);
7141         if (node != NULL) {
7142             VALID_CTXT();
7143             VALID_ERROR("extra data on the document\n");
7144             ret = -1;
7145         }
7146     }
7147     xmlRelaxNGFreeValidState(state);
7148
7149     return(ret);
7150 }
7151
7152 /************************************************************************
7153  *                                                                      *
7154  *                      Validation interfaces                           *
7155  *                                                                      *
7156  ************************************************************************/
7157 /**
7158  * xmlRelaxNGNewValidCtxt:
7159  * @schema:  a precompiled XML RelaxNGs
7160  *
7161  * Create an XML RelaxNGs validation context based on the given schema
7162  *
7163  * Returns the validation context or NULL in case of error
7164  */
7165 xmlRelaxNGValidCtxtPtr
7166 xmlRelaxNGNewValidCtxt(xmlRelaxNGPtr schema) {
7167     xmlRelaxNGValidCtxtPtr ret;
7168
7169     ret = (xmlRelaxNGValidCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGValidCtxt));
7170     if (ret == NULL) {
7171         xmlGenericError(xmlGenericErrorContext,
7172                 "Failed to allocate new schama validation context\n");
7173         return (NULL);
7174     }
7175     memset(ret, 0, sizeof(xmlRelaxNGValidCtxt));
7176     ret->schema = schema;
7177     ret->error = xmlGenericError;
7178     ret->userData = xmlGenericErrorContext;
7179     return (ret);
7180 }
7181
7182 /**
7183  * xmlRelaxNGFreeValidCtxt:
7184  * @ctxt:  the schema validation context
7185  *
7186  * Free the resources associated to the schema validation context
7187  */
7188 void
7189 xmlRelaxNGFreeValidCtxt(xmlRelaxNGValidCtxtPtr ctxt) {
7190     if (ctxt == NULL)
7191         return;
7192     xmlFree(ctxt);
7193 }
7194
7195 /**
7196  * xmlRelaxNGSetValidErrors:
7197  * @ctxt:  a Relax-NG validation context
7198  * @err:  the error function
7199  * @warn: the warning function
7200  * @ctx: the functions context
7201  *
7202  * Set the error and warning callback informations
7203  */
7204 void
7205 xmlRelaxNGSetValidErrors(xmlRelaxNGValidCtxtPtr ctxt,
7206         xmlRelaxNGValidityErrorFunc err,
7207         xmlRelaxNGValidityWarningFunc warn, void *ctx) {
7208     if (ctxt == NULL)
7209         return;
7210     ctxt->error = err;
7211     ctxt->warning = warn;
7212     ctxt->userData = ctx;
7213 }
7214
7215 /**
7216  * xmlRelaxNGValidateDoc:
7217  * @ctxt:  a Relax-NG validation context
7218  * @doc:  a parsed document tree
7219  *
7220  * Validate a document tree in memory.
7221  *
7222  * Returns 0 if the document is valid, a positive error code
7223  *     number otherwise and -1 in case of internal or API error.
7224  */
7225 int
7226 xmlRelaxNGValidateDoc(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc) {
7227     int ret;
7228
7229     if ((ctxt == NULL) || (doc == NULL))
7230         return(-1);
7231
7232     ctxt->doc = doc;
7233
7234     ret = xmlRelaxNGValidateDocument(ctxt, doc);
7235     /*
7236      * TODO: build error codes
7237      */
7238     if (ret == -1)
7239         return(1);
7240     return(ret);
7241 }
7242
7243 #endif /* LIBXML_SCHEMAS_ENABLED */
7244