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