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