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