| /* | 
 |  * relaxng.c : implementation of the Relax-NG handling and validity checking | 
 |  * | 
 |  * See Copyright for the status of this software. | 
 |  * | 
 |  * Daniel Veillard <veillard@redhat.com> | 
 |  */ | 
 |  | 
 | /** | 
 |  * TODO: | 
 |  * - add support for DTD compatibility spec | 
 |  *   http://www.oasis-open.org/committees/relax-ng/compatibility-20011203.html | 
 |  * - report better mem allocations pbms at runtime and abort immediately. | 
 |  */ | 
 |  | 
 | #define IN_LIBXML | 
 | #include "libxml.h" | 
 |  | 
 | #ifdef LIBXML_SCHEMAS_ENABLED | 
 |  | 
 | #include <string.h> | 
 | #include <stdio.h> | 
 | #include <libxml/xmlmemory.h> | 
 | #include <libxml/parser.h> | 
 | #include <libxml/parserInternals.h> | 
 | #include <libxml/hash.h> | 
 | #include <libxml/uri.h> | 
 |  | 
 | #include <libxml/relaxng.h> | 
 |  | 
 | #include <libxml/xmlschemastypes.h> | 
 | #include <libxml/xmlautomata.h> | 
 | #include <libxml/xmlregexp.h> | 
 | #include <libxml/xmlschemastypes.h> | 
 |  | 
 | /* | 
 |  * The Relax-NG namespace | 
 |  */ | 
 | static const xmlChar *xmlRelaxNGNs = (const xmlChar *) | 
 |     "http://relaxng.org/ns/structure/1.0"; | 
 |  | 
 | #define IS_RELAXNG(node, type)						\ | 
 |    ((node != NULL) && (node->ns != NULL) &&				\ | 
 |     (xmlStrEqual(node->name, (const xmlChar *) type)) &&		\ | 
 |     (xmlStrEqual(node->ns->href, xmlRelaxNGNs))) | 
 |  | 
 |  | 
 | #if 0 | 
 | #define DEBUG 1 | 
 |  | 
 | #define DEBUG_GRAMMAR 1 | 
 |  | 
 | #define DEBUG_CONTENT 1 | 
 |  | 
 | #define DEBUG_TYPE 1 | 
 |  | 
 | #define DEBUG_VALID 1 | 
 |  | 
 | #define DEBUG_INTERLEAVE 1 | 
 |  | 
 | #define DEBUG_LIST 1 | 
 |  | 
 | #define DEBUG_INCLUDE 1  | 
 |  | 
 | #define DEBUG_ERROR 1 | 
 |  | 
 | #define DEBUG_COMPILE 1 | 
 |  | 
 | #define DEBUG_PROGRESSIVE 1 | 
 | #endif | 
 |  | 
 | #define MAX_ERROR 5 | 
 |  | 
 | #define TODO 								\ | 
 |     xmlGenericError(xmlGenericErrorContext,				\ | 
 | 	    "Unimplemented block at %s:%d\n",				\ | 
 |             __FILE__, __LINE__); | 
 |  | 
 | typedef struct _xmlRelaxNGSchema xmlRelaxNGSchema; | 
 | typedef xmlRelaxNGSchema *xmlRelaxNGSchemaPtr; | 
 |  | 
 | typedef struct _xmlRelaxNGDefine xmlRelaxNGDefine; | 
 | typedef xmlRelaxNGDefine *xmlRelaxNGDefinePtr; | 
 |  | 
 | typedef struct _xmlRelaxNGDocument xmlRelaxNGDocument; | 
 | typedef xmlRelaxNGDocument *xmlRelaxNGDocumentPtr; | 
 |  | 
 | typedef struct _xmlRelaxNGInclude xmlRelaxNGInclude; | 
 | typedef xmlRelaxNGInclude *xmlRelaxNGIncludePtr; | 
 |  | 
 | typedef enum { | 
 |     XML_RELAXNG_COMBINE_UNDEFINED = 0,  /* undefined */ | 
 |     XML_RELAXNG_COMBINE_CHOICE, /* choice */ | 
 |     XML_RELAXNG_COMBINE_INTERLEAVE      /* interleave */ | 
 | } xmlRelaxNGCombine; | 
 |  | 
 | typedef enum { | 
 |     XML_RELAXNG_CONTENT_ERROR = -1, | 
 |     XML_RELAXNG_CONTENT_EMPTY = 0, | 
 |     XML_RELAXNG_CONTENT_SIMPLE, | 
 |     XML_RELAXNG_CONTENT_COMPLEX | 
 | } xmlRelaxNGContentType; | 
 |  | 
 | typedef struct _xmlRelaxNGGrammar xmlRelaxNGGrammar; | 
 | typedef xmlRelaxNGGrammar *xmlRelaxNGGrammarPtr; | 
 |  | 
 | struct _xmlRelaxNGGrammar { | 
 |     xmlRelaxNGGrammarPtr parent;        /* the parent grammar if any */ | 
 |     xmlRelaxNGGrammarPtr children;      /* the children grammar if any */ | 
 |     xmlRelaxNGGrammarPtr next;  /* the next grammar if any */ | 
 |     xmlRelaxNGDefinePtr start;  /* <start> content */ | 
 |     xmlRelaxNGCombine combine;  /* the default combine value */ | 
 |     xmlRelaxNGDefinePtr startList;      /* list of <start> definitions */ | 
 |     xmlHashTablePtr defs;       /* define* */ | 
 |     xmlHashTablePtr refs;       /* references */ | 
 | }; | 
 |  | 
 |  | 
 | typedef enum { | 
 |     XML_RELAXNG_NOOP = -1,      /* a no operation from simplification  */ | 
 |     XML_RELAXNG_EMPTY = 0,      /* an empty pattern */ | 
 |     XML_RELAXNG_NOT_ALLOWED,    /* not allowed top */ | 
 |     XML_RELAXNG_EXCEPT,         /* except present in nameclass defs */ | 
 |     XML_RELAXNG_TEXT,           /* textual content */ | 
 |     XML_RELAXNG_ELEMENT,        /* an element */ | 
 |     XML_RELAXNG_DATATYPE,       /* extenal data type definition */ | 
 |     XML_RELAXNG_PARAM,          /* extenal data type parameter */ | 
 |     XML_RELAXNG_VALUE,          /* value from an extenal data type definition */ | 
 |     XML_RELAXNG_LIST,           /* a list of patterns */ | 
 |     XML_RELAXNG_ATTRIBUTE,      /* an attrbute following a pattern */ | 
 |     XML_RELAXNG_DEF,            /* a definition */ | 
 |     XML_RELAXNG_REF,            /* reference to a definition */ | 
 |     XML_RELAXNG_EXTERNALREF,    /* reference to an external def */ | 
 |     XML_RELAXNG_PARENTREF,      /* reference to a def in the parent grammar */ | 
 |     XML_RELAXNG_OPTIONAL,       /* optional patterns */ | 
 |     XML_RELAXNG_ZEROORMORE,     /* zero or more non empty patterns */ | 
 |     XML_RELAXNG_ONEORMORE,      /* one or more non empty patterns */ | 
 |     XML_RELAXNG_CHOICE,         /* a choice between non empty patterns */ | 
 |     XML_RELAXNG_GROUP,          /* a pair/group of non empty patterns */ | 
 |     XML_RELAXNG_INTERLEAVE,     /* interleaving choice of non-empty patterns */ | 
 |     XML_RELAXNG_START           /* Used to keep track of starts on grammars */ | 
 | } xmlRelaxNGType; | 
 |  | 
 | #define IS_NULLABLE		(1 << 0) | 
 | #define IS_NOT_NULLABLE		(1 << 1) | 
 | #define IS_INDETERMINIST	(1 << 2) | 
 | #define IS_MIXED		(1 << 3) | 
 | #define IS_TRIABLE		(1 << 4) | 
 | #define IS_PROCESSED		(1 << 5) | 
 | #define IS_COMPILABLE		(1 << 6) | 
 | #define IS_NOT_COMPILABLE	(1 << 7) | 
 | #define IS_EXTERNAL_REF	        (1 << 8) | 
 |  | 
 | struct _xmlRelaxNGDefine { | 
 |     xmlRelaxNGType type;        /* the type of definition */ | 
 |     xmlNodePtr node;            /* the node in the source */ | 
 |     xmlChar *name;              /* the element local name if present */ | 
 |     xmlChar *ns;                /* the namespace local name if present */ | 
 |     xmlChar *value;             /* value when available */ | 
 |     void *data;                 /* data lib or specific pointer */ | 
 |     xmlRelaxNGDefinePtr content;        /* the expected content */ | 
 |     xmlRelaxNGDefinePtr parent; /* the parent definition, if any */ | 
 |     xmlRelaxNGDefinePtr next;   /* list within grouping sequences */ | 
 |     xmlRelaxNGDefinePtr attrs;  /* list of attributes for elements */ | 
 |     xmlRelaxNGDefinePtr nameClass;      /* the nameClass definition if any */ | 
 |     xmlRelaxNGDefinePtr nextHash;       /* next define in defs/refs hash tables */ | 
 |     short depth;                /* used for the cycle detection */ | 
 |     short dflags;               /* define related flags */ | 
 |     xmlRegexpPtr contModel;     /* a compiled content model if available */ | 
 | }; | 
 |  | 
 | /** | 
 |  * _xmlRelaxNG: | 
 |  * | 
 |  * A RelaxNGs definition | 
 |  */ | 
 | struct _xmlRelaxNG { | 
 |     void *_private;             /* unused by the library for users or bindings */ | 
 |     xmlRelaxNGGrammarPtr topgrammar; | 
 |     xmlDocPtr doc; | 
 |  | 
 |     int idref;                  /* requires idref checking */ | 
 |  | 
 |     xmlHashTablePtr defs;       /* define */ | 
 |     xmlHashTablePtr refs;       /* references */ | 
 |     xmlRelaxNGDocumentPtr documents;    /* all the documents loaded */ | 
 |     xmlRelaxNGIncludePtr includes;      /* all the includes loaded */ | 
 |     int defNr;                  /* number of defines used */ | 
 |     xmlRelaxNGDefinePtr *defTab;        /* pointer to the allocated definitions */ | 
 |  | 
 | }; | 
 |  | 
 | #define XML_RELAXNG_IN_ATTRIBUTE	(1 << 0) | 
 | #define XML_RELAXNG_IN_ONEORMORE	(1 << 1) | 
 | #define XML_RELAXNG_IN_LIST		(1 << 2) | 
 | #define XML_RELAXNG_IN_DATAEXCEPT	(1 << 3) | 
 | #define XML_RELAXNG_IN_START		(1 << 4) | 
 | #define XML_RELAXNG_IN_OOMGROUP		(1 << 5) | 
 | #define XML_RELAXNG_IN_OOMINTERLEAVE	(1 << 6) | 
 | #define XML_RELAXNG_IN_EXTERNALREF	(1 << 7) | 
 | #define XML_RELAXNG_IN_ANYEXCEPT	(1 << 8) | 
 | #define XML_RELAXNG_IN_NSEXCEPT		(1 << 9) | 
 |  | 
 | struct _xmlRelaxNGParserCtxt { | 
 |     void *userData;             /* user specific data block */ | 
 |     xmlRelaxNGValidityErrorFunc error;  /* the callback in case of errors */ | 
 |     xmlRelaxNGValidityWarningFunc warning;      /* the callback in case of warning */ | 
 |     xmlStructuredErrorFunc serror; | 
 |     xmlRelaxNGValidErr err; | 
 |  | 
 |     xmlRelaxNGPtr schema;       /* The schema in use */ | 
 |     xmlRelaxNGGrammarPtr grammar;       /* the current grammar */ | 
 |     xmlRelaxNGGrammarPtr parentgrammar; /* the parent grammar */ | 
 |     int flags;                  /* parser flags */ | 
 |     int nbErrors;               /* number of errors at parse time */ | 
 |     int nbWarnings;             /* number of warnings at parse time */ | 
 |     const xmlChar *define;      /* the current define scope */ | 
 |     xmlRelaxNGDefinePtr def;    /* the current define */ | 
 |  | 
 |     int nbInterleaves; | 
 |     xmlHashTablePtr interleaves;        /* keep track of all the interleaves */ | 
 |  | 
 |     xmlRelaxNGDocumentPtr documents;    /* all the documents loaded */ | 
 |     xmlRelaxNGIncludePtr includes;      /* all the includes loaded */ | 
 |     xmlChar *URL; | 
 |     xmlDocPtr document; | 
 |  | 
 |     int defNr;                  /* number of defines used */ | 
 |     int defMax;                 /* number of defines aloocated */ | 
 |     xmlRelaxNGDefinePtr *defTab;        /* pointer to the allocated definitions */ | 
 |  | 
 |     const char *buffer; | 
 |     int size; | 
 |  | 
 |     /* the document stack */ | 
 |     xmlRelaxNGDocumentPtr doc;  /* Current parsed external ref */ | 
 |     int docNr;                  /* Depth of the parsing stack */ | 
 |     int docMax;                 /* Max depth of the parsing stack */ | 
 |     xmlRelaxNGDocumentPtr *docTab;      /* array of docs */ | 
 |  | 
 |     /* the include stack */ | 
 |     xmlRelaxNGIncludePtr inc;   /* Current parsed include */ | 
 |     int incNr;                  /* Depth of the include parsing stack */ | 
 |     int incMax;                 /* Max depth of the parsing stack */ | 
 |     xmlRelaxNGIncludePtr *incTab;       /* array of incs */ | 
 |  | 
 |     int idref;                  /* requires idref checking */ | 
 |  | 
 |     /* used to compile content models */ | 
 |     xmlAutomataPtr am;          /* the automata */ | 
 |     xmlAutomataStatePtr state;  /* used to build the automata */ | 
 |  | 
 |     int crng;			/* compact syntax and other flags */ | 
 |     int freedoc;		/* need to free the document */ | 
 | }; | 
 |  | 
 | #define FLAGS_IGNORABLE		1 | 
 | #define FLAGS_NEGATIVE		2 | 
 | #define FLAGS_MIXED_CONTENT	4 | 
 | #define FLAGS_NOERROR		8 | 
 |  | 
 | /** | 
 |  * xmlRelaxNGInterleaveGroup: | 
 |  * | 
 |  * A RelaxNGs partition set associated to lists of definitions | 
 |  */ | 
 | typedef struct _xmlRelaxNGInterleaveGroup xmlRelaxNGInterleaveGroup; | 
 | typedef xmlRelaxNGInterleaveGroup *xmlRelaxNGInterleaveGroupPtr; | 
 | struct _xmlRelaxNGInterleaveGroup { | 
 |     xmlRelaxNGDefinePtr rule;   /* the rule to satisfy */ | 
 |     xmlRelaxNGDefinePtr *defs;  /* the array of element definitions */ | 
 |     xmlRelaxNGDefinePtr *attrs; /* the array of attributes definitions */ | 
 | }; | 
 |  | 
 | #define IS_DETERMINIST		1 | 
 | #define IS_NEEDCHECK		2 | 
 |  | 
 | /** | 
 |  * xmlRelaxNGPartitions: | 
 |  * | 
 |  * A RelaxNGs partition associated to an interleave group | 
 |  */ | 
 | typedef struct _xmlRelaxNGPartition xmlRelaxNGPartition; | 
 | typedef xmlRelaxNGPartition *xmlRelaxNGPartitionPtr; | 
 | struct _xmlRelaxNGPartition { | 
 |     int nbgroups;               /* number of groups in the partitions */ | 
 |     xmlHashTablePtr triage;     /* hash table used to direct nodes to the | 
 |                                  * right group when possible */ | 
 |     int flags;                  /* determinist ? */ | 
 |     xmlRelaxNGInterleaveGroupPtr *groups; | 
 | }; | 
 |  | 
 | /** | 
 |  * xmlRelaxNGValidState: | 
 |  * | 
 |  * A RelaxNGs validation state | 
 |  */ | 
 | #define MAX_ATTR 20 | 
 | typedef struct _xmlRelaxNGValidState xmlRelaxNGValidState; | 
 | typedef xmlRelaxNGValidState *xmlRelaxNGValidStatePtr; | 
 | struct _xmlRelaxNGValidState { | 
 |     xmlNodePtr node;            /* the current node */ | 
 |     xmlNodePtr seq;             /* the sequence of children left to validate */ | 
 |     int nbAttrs;                /* the number of attributes */ | 
 |     int maxAttrs;               /* the size of attrs */ | 
 |     int nbAttrLeft;             /* the number of attributes left to validate */ | 
 |     xmlChar *value;             /* the value when operating on string */ | 
 |     xmlChar *endvalue;          /* the end value when operating on string */ | 
 |     xmlAttrPtr *attrs;          /* the array of attributes */ | 
 | }; | 
 |  | 
 | /** | 
 |  * xmlRelaxNGStates: | 
 |  * | 
 |  * A RelaxNGs container for validation state | 
 |  */ | 
 | typedef struct _xmlRelaxNGStates xmlRelaxNGStates; | 
 | typedef xmlRelaxNGStates *xmlRelaxNGStatesPtr; | 
 | struct _xmlRelaxNGStates { | 
 |     int nbState;                /* the number of states */ | 
 |     int maxState;               /* the size of the array */ | 
 |     xmlRelaxNGValidStatePtr *tabState; | 
 | }; | 
 |  | 
 | #define ERROR_IS_DUP	1 | 
 |  | 
 | /** | 
 |  * xmlRelaxNGValidError: | 
 |  * | 
 |  * A RelaxNGs validation error | 
 |  */ | 
 | typedef struct _xmlRelaxNGValidError xmlRelaxNGValidError; | 
 | typedef xmlRelaxNGValidError *xmlRelaxNGValidErrorPtr; | 
 | struct _xmlRelaxNGValidError { | 
 |     xmlRelaxNGValidErr err;     /* the error number */ | 
 |     int flags;                  /* flags */ | 
 |     xmlNodePtr node;            /* the current node */ | 
 |     xmlNodePtr seq;             /* the current child */ | 
 |     const xmlChar *arg1;        /* first arg */ | 
 |     const xmlChar *arg2;        /* second arg */ | 
 | }; | 
 |  | 
 | /** | 
 |  * xmlRelaxNGValidCtxt: | 
 |  * | 
 |  * A RelaxNGs validation context | 
 |  */ | 
 |  | 
 | struct _xmlRelaxNGValidCtxt { | 
 |     void *userData;             /* user specific data block */ | 
 |     xmlRelaxNGValidityErrorFunc error;  /* the callback in case of errors */ | 
 |     xmlRelaxNGValidityWarningFunc warning;      /* the callback in case of warning */ | 
 |     xmlStructuredErrorFunc serror; | 
 |     int nbErrors;               /* number of errors in validation */ | 
 |  | 
 |     xmlRelaxNGPtr schema;       /* The schema in use */ | 
 |     xmlDocPtr doc;              /* the document being validated */ | 
 |     int flags;                  /* validation flags */ | 
 |     int depth;                  /* validation depth */ | 
 |     int idref;                  /* requires idref checking */ | 
 |     int errNo;                  /* the first error found */ | 
 |  | 
 |     /* | 
 |      * Errors accumulated in branches may have to be stacked to be | 
 |      * provided back when it's sure they affect validation. | 
 |      */ | 
 |     xmlRelaxNGValidErrorPtr err;        /* Last error */ | 
 |     int errNr;                  /* Depth of the error stack */ | 
 |     int errMax;                 /* Max depth of the error stack */ | 
 |     xmlRelaxNGValidErrorPtr errTab;     /* stack of errors */ | 
 |  | 
 |     xmlRelaxNGValidStatePtr state;      /* the current validation state */ | 
 |     xmlRelaxNGStatesPtr states; /* the accumulated state list */ | 
 |  | 
 |     xmlRelaxNGStatesPtr freeState;      /* the pool of free valid states */ | 
 |     int freeStatesNr; | 
 |     int freeStatesMax; | 
 |     xmlRelaxNGStatesPtr *freeStates;    /* the pool of free state groups */ | 
 |  | 
 |     /* | 
 |      * This is used for "progressive" validation | 
 |      */ | 
 |     xmlRegExecCtxtPtr elem;     /* the current element regexp */ | 
 |     int elemNr;                 /* the number of element validated */ | 
 |     int elemMax;                /* the max depth of elements */ | 
 |     xmlRegExecCtxtPtr *elemTab; /* the stack of regexp runtime */ | 
 |     int pstate;                 /* progressive state */ | 
 |     xmlNodePtr pnode;           /* the current node */ | 
 |     xmlRelaxNGDefinePtr pdef;   /* the non-streamable definition */ | 
 |     int perr;                   /* signal error in content model | 
 |                                  * outside the regexp */ | 
 | }; | 
 |  | 
 | /** | 
 |  * xmlRelaxNGInclude: | 
 |  * | 
 |  * Structure associated to a RelaxNGs document element | 
 |  */ | 
 | struct _xmlRelaxNGInclude { | 
 |     xmlRelaxNGIncludePtr next;  /* keep a chain of includes */ | 
 |     xmlChar *href;              /* the normalized href value */ | 
 |     xmlDocPtr doc;              /* the associated XML document */ | 
 |     xmlRelaxNGDefinePtr content;        /* the definitions */ | 
 |     xmlRelaxNGPtr schema;       /* the schema */ | 
 | }; | 
 |  | 
 | /** | 
 |  * xmlRelaxNGDocument: | 
 |  * | 
 |  * Structure associated to a RelaxNGs document element | 
 |  */ | 
 | struct _xmlRelaxNGDocument { | 
 |     xmlRelaxNGDocumentPtr next; /* keep a chain of documents */ | 
 |     xmlChar *href;              /* the normalized href value */ | 
 |     xmlDocPtr doc;              /* the associated XML document */ | 
 |     xmlRelaxNGDefinePtr content;        /* the definitions */ | 
 |     xmlRelaxNGPtr schema;       /* the schema */ | 
 |     int externalRef;            /* 1 if an external ref */ | 
 | }; | 
 |  | 
 |  | 
 | /************************************************************************ | 
 |  *									* | 
 |  * 		Some factorized error routines				* | 
 |  *									* | 
 |  ************************************************************************/ | 
 |  | 
 | /** | 
 |  * xmlRngPErrMemory: | 
 |  * @ctxt:  an Relax-NG parser context | 
 |  * @extra:  extra informations | 
 |  * | 
 |  * Handle a redefinition of attribute error | 
 |  */ | 
 | static void | 
 | xmlRngPErrMemory(xmlRelaxNGParserCtxtPtr ctxt, const char *extra) | 
 | { | 
 |     xmlStructuredErrorFunc schannel = NULL; | 
 |     xmlGenericErrorFunc channel = NULL; | 
 |     void *data = NULL; | 
 |  | 
 |     if (ctxt != NULL) { | 
 |         if (ctxt->serror != NULL) | 
 | 	    schannel = ctxt->serror; | 
 | 	else | 
 | 	    channel = ctxt->error; | 
 |         data = ctxt->userData; | 
 |         ctxt->nbErrors++; | 
 |     } | 
 |     if (extra) | 
 |         __xmlRaiseError(schannel, channel, data, | 
 |                         NULL, NULL, XML_FROM_RELAXNGP, | 
 |                         XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, extra, | 
 |                         NULL, NULL, 0, 0, | 
 |                         "Memory allocation failed : %s\n", extra); | 
 |     else | 
 |         __xmlRaiseError(schannel, channel, data, | 
 |                         NULL, NULL, XML_FROM_RELAXNGP, | 
 |                         XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, NULL, | 
 |                         NULL, NULL, 0, 0, "Memory allocation failed\n"); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRngVErrMemory: | 
 |  * @ctxt:  a Relax-NG validation context | 
 |  * @extra:  extra informations | 
 |  * | 
 |  * Handle a redefinition of attribute error | 
 |  */ | 
 | static void | 
 | xmlRngVErrMemory(xmlRelaxNGValidCtxtPtr ctxt, const char *extra) | 
 | { | 
 |     xmlStructuredErrorFunc schannel = NULL; | 
 |     xmlGenericErrorFunc channel = NULL; | 
 |     void *data = NULL; | 
 |  | 
 |     if (ctxt != NULL) { | 
 |         if (ctxt->serror != NULL) | 
 | 	    schannel = ctxt->serror; | 
 | 	else | 
 | 	    channel = ctxt->error; | 
 |         data = ctxt->userData; | 
 |         ctxt->nbErrors++; | 
 |     } | 
 |     if (extra) | 
 |         __xmlRaiseError(schannel, channel, data, | 
 |                         NULL, NULL, XML_FROM_RELAXNGV, | 
 |                         XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, extra, | 
 |                         NULL, NULL, 0, 0, | 
 |                         "Memory allocation failed : %s\n", extra); | 
 |     else | 
 |         __xmlRaiseError(schannel, channel, data, | 
 |                         NULL, NULL, XML_FROM_RELAXNGV, | 
 |                         XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, NULL, | 
 |                         NULL, NULL, 0, 0, "Memory allocation failed\n"); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRngPErr: | 
 |  * @ctxt:  a Relax-NG parser context | 
 |  * @node:  the node raising the error | 
 |  * @error:  the error code | 
 |  * @msg:  message | 
 |  * @str1:  extra info | 
 |  * @str2:  extra info | 
 |  * | 
 |  * Handle a Relax NG Parsing error | 
 |  */ | 
 | static void | 
 | xmlRngPErr(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node, int error, | 
 |            const char *msg, const xmlChar * str1, const xmlChar * str2) | 
 | { | 
 |     xmlStructuredErrorFunc schannel = NULL; | 
 |     xmlGenericErrorFunc channel = NULL; | 
 |     void *data = NULL; | 
 |  | 
 |     if (ctxt != NULL) { | 
 |         if (ctxt->serror != NULL) | 
 | 	    schannel = ctxt->serror; | 
 | 	else | 
 | 	    channel = ctxt->error; | 
 |         data = ctxt->userData; | 
 |         ctxt->nbErrors++; | 
 |     } | 
 |     __xmlRaiseError(schannel, channel, data, | 
 |                     NULL, node, XML_FROM_RELAXNGP, | 
 |                     error, XML_ERR_ERROR, NULL, 0, | 
 |                     (const char *) str1, (const char *) str2, NULL, 0, 0, | 
 |                     msg, str1, str2); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRngVErr: | 
 |  * @ctxt:  a Relax-NG validation context | 
 |  * @node:  the node raising the error | 
 |  * @error:  the error code | 
 |  * @msg:  message | 
 |  * @str1:  extra info | 
 |  * @str2:  extra info | 
 |  * | 
 |  * Handle a Relax NG Validation error | 
 |  */ | 
 | static void | 
 | xmlRngVErr(xmlRelaxNGValidCtxtPtr ctxt, xmlNodePtr node, int error, | 
 |            const char *msg, const xmlChar * str1, const xmlChar * str2) | 
 | { | 
 |     xmlStructuredErrorFunc schannel = NULL; | 
 |     xmlGenericErrorFunc channel = NULL; | 
 |     void *data = NULL; | 
 |  | 
 |     if (ctxt != NULL) { | 
 |         if (ctxt->serror != NULL) | 
 | 	    schannel = ctxt->serror; | 
 | 	else | 
 | 	    channel = ctxt->error; | 
 |         data = ctxt->userData; | 
 |         ctxt->nbErrors++; | 
 |     } | 
 |     __xmlRaiseError(schannel, channel, data, | 
 |                     NULL, node, XML_FROM_RELAXNGV, | 
 |                     error, XML_ERR_ERROR, NULL, 0, | 
 |                     (const char *) str1, (const char *) str2, NULL, 0, 0, | 
 |                     msg, str1, str2); | 
 | } | 
 |  | 
 | /************************************************************************ | 
 |  * 									* | 
 |  * 		Preliminary type checking interfaces			* | 
 |  * 									* | 
 |  ************************************************************************/ | 
 |  | 
 | /** | 
 |  * xmlRelaxNGTypeHave: | 
 |  * @data:  data needed for the library | 
 |  * @type:  the type name | 
 |  * @value:  the value to check | 
 |  * | 
 |  * Function provided by a type library to check if a type is exported | 
 |  * | 
 |  * Returns 1 if yes, 0 if no and -1 in case of error. | 
 |  */ | 
 | typedef int (*xmlRelaxNGTypeHave) (void *data, const xmlChar * type); | 
 |  | 
 | /** | 
 |  * xmlRelaxNGTypeCheck: | 
 |  * @data:  data needed for the library | 
 |  * @type:  the type name | 
 |  * @value:  the value to check | 
 |  * @result:  place to store the result if needed | 
 |  * | 
 |  * Function provided by a type library to check if a value match a type | 
 |  * | 
 |  * Returns 1 if yes, 0 if no and -1 in case of error. | 
 |  */ | 
 | typedef int (*xmlRelaxNGTypeCheck) (void *data, const xmlChar * type, | 
 |                                     const xmlChar * value, void **result, | 
 |                                     xmlNodePtr node); | 
 |  | 
 | /** | 
 |  * xmlRelaxNGFacetCheck: | 
 |  * @data:  data needed for the library | 
 |  * @type:  the type name | 
 |  * @facet:  the facet name | 
 |  * @val:  the facet value | 
 |  * @strval:  the string value | 
 |  * @value:  the value to check | 
 |  * | 
 |  * Function provided by a type library to check a value facet | 
 |  * | 
 |  * Returns 1 if yes, 0 if no and -1 in case of error. | 
 |  */ | 
 | typedef int (*xmlRelaxNGFacetCheck) (void *data, const xmlChar * type, | 
 |                                      const xmlChar * facet, | 
 |                                      const xmlChar * val, | 
 |                                      const xmlChar * strval, void *value); | 
 |  | 
 | /** | 
 |  * xmlRelaxNGTypeFree: | 
 |  * @data:  data needed for the library | 
 |  * @result:  the value to free | 
 |  * | 
 |  * Function provided by a type library to free a returned result | 
 |  */ | 
 | typedef void (*xmlRelaxNGTypeFree) (void *data, void *result); | 
 |  | 
 | /** | 
 |  * xmlRelaxNGTypeCompare: | 
 |  * @data:  data needed for the library | 
 |  * @type:  the type name | 
 |  * @value1:  the first value | 
 |  * @value2:  the second value | 
 |  * | 
 |  * Function provided by a type library to compare two values accordingly | 
 |  * to a type. | 
 |  * | 
 |  * Returns 1 if yes, 0 if no and -1 in case of error. | 
 |  */ | 
 | typedef int (*xmlRelaxNGTypeCompare) (void *data, const xmlChar * type, | 
 |                                       const xmlChar * value1, | 
 |                                       xmlNodePtr ctxt1, | 
 |                                       void *comp1, | 
 |                                       const xmlChar * value2, | 
 |                                       xmlNodePtr ctxt2); | 
 | typedef struct _xmlRelaxNGTypeLibrary xmlRelaxNGTypeLibrary; | 
 | typedef xmlRelaxNGTypeLibrary *xmlRelaxNGTypeLibraryPtr; | 
 | struct _xmlRelaxNGTypeLibrary { | 
 |     const xmlChar *namespace;   /* the datatypeLibrary value */ | 
 |     void *data;                 /* data needed for the library */ | 
 |     xmlRelaxNGTypeHave have;    /* the export function */ | 
 |     xmlRelaxNGTypeCheck check;  /* the checking function */ | 
 |     xmlRelaxNGTypeCompare comp; /* the compare function */ | 
 |     xmlRelaxNGFacetCheck facet; /* the facet check function */ | 
 |     xmlRelaxNGTypeFree freef;   /* the freeing function */ | 
 | }; | 
 |  | 
 | /************************************************************************ | 
 |  * 									* | 
 |  * 			Allocation functions				* | 
 |  * 									* | 
 |  ************************************************************************/ | 
 | static void xmlRelaxNGFreeGrammar(xmlRelaxNGGrammarPtr grammar); | 
 | static void xmlRelaxNGFreeDefine(xmlRelaxNGDefinePtr define); | 
 | static void xmlRelaxNGNormExtSpace(xmlChar * value); | 
 | static void xmlRelaxNGFreeInnerSchema(xmlRelaxNGPtr schema); | 
 | static int xmlRelaxNGEqualValidState(xmlRelaxNGValidCtxtPtr ctxt | 
 |                                      ATTRIBUTE_UNUSED, | 
 |                                      xmlRelaxNGValidStatePtr state1, | 
 |                                      xmlRelaxNGValidStatePtr state2); | 
 | static void xmlRelaxNGFreeValidState(xmlRelaxNGValidCtxtPtr ctxt, | 
 |                                      xmlRelaxNGValidStatePtr state); | 
 |  | 
 | /** | 
 |  * xmlRelaxNGFreeDocument: | 
 |  * @docu:  a document structure | 
 |  * | 
 |  * Deallocate a RelaxNG document structure. | 
 |  */ | 
 | static void | 
 | xmlRelaxNGFreeDocument(xmlRelaxNGDocumentPtr docu) | 
 | { | 
 |     if (docu == NULL) | 
 |         return; | 
 |  | 
 |     if (docu->href != NULL) | 
 |         xmlFree(docu->href); | 
 |     if (docu->doc != NULL) | 
 |         xmlFreeDoc(docu->doc); | 
 |     if (docu->schema != NULL) | 
 |         xmlRelaxNGFreeInnerSchema(docu->schema); | 
 |     xmlFree(docu); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGFreeDocumentList: | 
 |  * @docu:  a list of  document structure | 
 |  * | 
 |  * Deallocate a RelaxNG document structures. | 
 |  */ | 
 | static void | 
 | xmlRelaxNGFreeDocumentList(xmlRelaxNGDocumentPtr docu) | 
 | { | 
 |     xmlRelaxNGDocumentPtr next; | 
 |  | 
 |     while (docu != NULL) { | 
 |         next = docu->next; | 
 |         xmlRelaxNGFreeDocument(docu); | 
 |         docu = next; | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGFreeInclude: | 
 |  * @incl:  a include structure | 
 |  * | 
 |  * Deallocate a RelaxNG include structure. | 
 |  */ | 
 | static void | 
 | xmlRelaxNGFreeInclude(xmlRelaxNGIncludePtr incl) | 
 | { | 
 |     if (incl == NULL) | 
 |         return; | 
 |  | 
 |     if (incl->href != NULL) | 
 |         xmlFree(incl->href); | 
 |     if (incl->doc != NULL) | 
 |         xmlFreeDoc(incl->doc); | 
 |     if (incl->schema != NULL) | 
 |         xmlRelaxNGFree(incl->schema); | 
 |     xmlFree(incl); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGFreeIncludeList: | 
 |  * @incl:  a include structure list | 
 |  * | 
 |  * Deallocate a RelaxNG include structure. | 
 |  */ | 
 | static void | 
 | xmlRelaxNGFreeIncludeList(xmlRelaxNGIncludePtr incl) | 
 | { | 
 |     xmlRelaxNGIncludePtr next; | 
 |  | 
 |     while (incl != NULL) { | 
 |         next = incl->next; | 
 |         xmlRelaxNGFreeInclude(incl); | 
 |         incl = next; | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGNewRelaxNG: | 
 |  * @ctxt:  a Relax-NG validation context (optional) | 
 |  * | 
 |  * Allocate a new RelaxNG structure. | 
 |  * | 
 |  * Returns the newly allocated structure or NULL in case or error | 
 |  */ | 
 | static xmlRelaxNGPtr | 
 | xmlRelaxNGNewRelaxNG(xmlRelaxNGParserCtxtPtr ctxt) | 
 | { | 
 |     xmlRelaxNGPtr ret; | 
 |  | 
 |     ret = (xmlRelaxNGPtr) xmlMalloc(sizeof(xmlRelaxNG)); | 
 |     if (ret == NULL) { | 
 |         xmlRngPErrMemory(ctxt, NULL); | 
 |         return (NULL); | 
 |     } | 
 |     memset(ret, 0, sizeof(xmlRelaxNG)); | 
 |  | 
 |     return (ret); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGFreeInnerSchema: | 
 |  * @schema:  a schema structure | 
 |  * | 
 |  * Deallocate a RelaxNG schema structure. | 
 |  */ | 
 | static void | 
 | xmlRelaxNGFreeInnerSchema(xmlRelaxNGPtr schema) | 
 | { | 
 |     if (schema == NULL) | 
 |         return; | 
 |  | 
 |     if (schema->doc != NULL) | 
 |         xmlFreeDoc(schema->doc); | 
 |     if (schema->defTab != NULL) { | 
 |         int i; | 
 |  | 
 |         for (i = 0; i < schema->defNr; i++) | 
 |             xmlRelaxNGFreeDefine(schema->defTab[i]); | 
 |         xmlFree(schema->defTab); | 
 |     } | 
 |  | 
 |     xmlFree(schema); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGFree: | 
 |  * @schema:  a schema structure | 
 |  * | 
 |  * Deallocate a RelaxNG structure. | 
 |  */ | 
 | void | 
 | xmlRelaxNGFree(xmlRelaxNGPtr schema) | 
 | { | 
 |     if (schema == NULL) | 
 |         return; | 
 |  | 
 |     if (schema->topgrammar != NULL) | 
 |         xmlRelaxNGFreeGrammar(schema->topgrammar); | 
 |     if (schema->doc != NULL) | 
 |         xmlFreeDoc(schema->doc); | 
 |     if (schema->documents != NULL) | 
 |         xmlRelaxNGFreeDocumentList(schema->documents); | 
 |     if (schema->includes != NULL) | 
 |         xmlRelaxNGFreeIncludeList(schema->includes); | 
 |     if (schema->defTab != NULL) { | 
 |         int i; | 
 |  | 
 |         for (i = 0; i < schema->defNr; i++) | 
 |             xmlRelaxNGFreeDefine(schema->defTab[i]); | 
 |         xmlFree(schema->defTab); | 
 |     } | 
 |  | 
 |     xmlFree(schema); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGNewGrammar: | 
 |  * @ctxt:  a Relax-NG validation context (optional) | 
 |  * | 
 |  * Allocate a new RelaxNG grammar. | 
 |  * | 
 |  * Returns the newly allocated structure or NULL in case or error | 
 |  */ | 
 | static xmlRelaxNGGrammarPtr | 
 | xmlRelaxNGNewGrammar(xmlRelaxNGParserCtxtPtr ctxt) | 
 | { | 
 |     xmlRelaxNGGrammarPtr ret; | 
 |  | 
 |     ret = (xmlRelaxNGGrammarPtr) xmlMalloc(sizeof(xmlRelaxNGGrammar)); | 
 |     if (ret == NULL) { | 
 |         xmlRngPErrMemory(ctxt, NULL); | 
 |         return (NULL); | 
 |     } | 
 |     memset(ret, 0, sizeof(xmlRelaxNGGrammar)); | 
 |  | 
 |     return (ret); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGFreeGrammar: | 
 |  * @grammar:  a grammar structure | 
 |  * | 
 |  * Deallocate a RelaxNG grammar structure. | 
 |  */ | 
 | static void | 
 | xmlRelaxNGFreeGrammar(xmlRelaxNGGrammarPtr grammar) | 
 | { | 
 |     if (grammar == NULL) | 
 |         return; | 
 |  | 
 |     if (grammar->children != NULL) { | 
 |         xmlRelaxNGFreeGrammar(grammar->children); | 
 |     } | 
 |     if (grammar->next != NULL) { | 
 |         xmlRelaxNGFreeGrammar(grammar->next); | 
 |     } | 
 |     if (grammar->refs != NULL) { | 
 |         xmlHashFree(grammar->refs, NULL); | 
 |     } | 
 |     if (grammar->defs != NULL) { | 
 |         xmlHashFree(grammar->defs, NULL); | 
 |     } | 
 |  | 
 |     xmlFree(grammar); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGNewDefine: | 
 |  * @ctxt:  a Relax-NG validation context | 
 |  * @node:  the node in the input document. | 
 |  * | 
 |  * Allocate a new RelaxNG define. | 
 |  * | 
 |  * Returns the newly allocated structure or NULL in case or error | 
 |  */ | 
 | static xmlRelaxNGDefinePtr | 
 | xmlRelaxNGNewDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) | 
 | { | 
 |     xmlRelaxNGDefinePtr ret; | 
 |  | 
 |     if (ctxt->defMax == 0) { | 
 |         ctxt->defMax = 16; | 
 |         ctxt->defNr = 0; | 
 |         ctxt->defTab = (xmlRelaxNGDefinePtr *) | 
 |             xmlMalloc(ctxt->defMax * sizeof(xmlRelaxNGDefinePtr)); | 
 |         if (ctxt->defTab == NULL) { | 
 |             xmlRngPErrMemory(ctxt, "allocating define\n"); | 
 |             return (NULL); | 
 |         } | 
 |     } else if (ctxt->defMax <= ctxt->defNr) { | 
 |         xmlRelaxNGDefinePtr *tmp; | 
 |  | 
 |         ctxt->defMax *= 2; | 
 |         tmp = (xmlRelaxNGDefinePtr *) xmlRealloc(ctxt->defTab, | 
 |                                                  ctxt->defMax * | 
 |                                                  sizeof | 
 |                                                  (xmlRelaxNGDefinePtr)); | 
 |         if (tmp == NULL) { | 
 |             xmlRngPErrMemory(ctxt, "allocating define\n"); | 
 |             return (NULL); | 
 |         } | 
 |         ctxt->defTab = tmp; | 
 |     } | 
 |     ret = (xmlRelaxNGDefinePtr) xmlMalloc(sizeof(xmlRelaxNGDefine)); | 
 |     if (ret == NULL) { | 
 |         xmlRngPErrMemory(ctxt, "allocating define\n"); | 
 |         return (NULL); | 
 |     } | 
 |     memset(ret, 0, sizeof(xmlRelaxNGDefine)); | 
 |     ctxt->defTab[ctxt->defNr++] = ret; | 
 |     ret->node = node; | 
 |     ret->depth = -1; | 
 |     return (ret); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGFreePartition: | 
 |  * @partitions:  a partition set structure | 
 |  * | 
 |  * Deallocate RelaxNG partition set structures. | 
 |  */ | 
 | static void | 
 | xmlRelaxNGFreePartition(xmlRelaxNGPartitionPtr partitions) | 
 | { | 
 |     xmlRelaxNGInterleaveGroupPtr group; | 
 |     int j; | 
 |  | 
 |     if (partitions != NULL) { | 
 |         if (partitions->groups != NULL) { | 
 |             for (j = 0; j < partitions->nbgroups; j++) { | 
 |                 group = partitions->groups[j]; | 
 |                 if (group != NULL) { | 
 |                     if (group->defs != NULL) | 
 |                         xmlFree(group->defs); | 
 |                     if (group->attrs != NULL) | 
 |                         xmlFree(group->attrs); | 
 |                     xmlFree(group); | 
 |                 } | 
 |             } | 
 |             xmlFree(partitions->groups); | 
 |         } | 
 |         if (partitions->triage != NULL) { | 
 |             xmlHashFree(partitions->triage, NULL); | 
 |         } | 
 |         xmlFree(partitions); | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGFreeDefine: | 
 |  * @define:  a define structure | 
 |  * | 
 |  * Deallocate a RelaxNG define structure. | 
 |  */ | 
 | static void | 
 | xmlRelaxNGFreeDefine(xmlRelaxNGDefinePtr define) | 
 | { | 
 |     if (define == NULL) | 
 |         return; | 
 |  | 
 |     if ((define->type == XML_RELAXNG_VALUE) && (define->attrs != NULL)) { | 
 |         xmlRelaxNGTypeLibraryPtr lib; | 
 |  | 
 |         lib = (xmlRelaxNGTypeLibraryPtr) define->data; | 
 |         if ((lib != NULL) && (lib->freef != NULL)) | 
 |             lib->freef(lib->data, (void *) define->attrs); | 
 |     } | 
 |     if ((define->data != NULL) && (define->type == XML_RELAXNG_INTERLEAVE)) | 
 |         xmlRelaxNGFreePartition((xmlRelaxNGPartitionPtr) define->data); | 
 |     if ((define->data != NULL) && (define->type == XML_RELAXNG_CHOICE)) | 
 |         xmlHashFree((xmlHashTablePtr) define->data, NULL); | 
 |     if (define->name != NULL) | 
 |         xmlFree(define->name); | 
 |     if (define->ns != NULL) | 
 |         xmlFree(define->ns); | 
 |     if (define->value != NULL) | 
 |         xmlFree(define->value); | 
 |     if (define->contModel != NULL) | 
 |         xmlRegFreeRegexp(define->contModel); | 
 |     xmlFree(define); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGNewStates: | 
 |  * @ctxt:  a Relax-NG validation context | 
 |  * @size:  the default size for the container | 
 |  * | 
 |  * Allocate a new RelaxNG validation state container | 
 |  * | 
 |  * Returns the newly allocated structure or NULL in case or error | 
 |  */ | 
 | static xmlRelaxNGStatesPtr | 
 | xmlRelaxNGNewStates(xmlRelaxNGValidCtxtPtr ctxt, int size) | 
 | { | 
 |     xmlRelaxNGStatesPtr ret; | 
 |  | 
 |     if ((ctxt != NULL) && | 
 |         (ctxt->freeStates != NULL) && (ctxt->freeStatesNr > 0)) { | 
 |         ctxt->freeStatesNr--; | 
 |         ret = ctxt->freeStates[ctxt->freeStatesNr]; | 
 |         ret->nbState = 0; | 
 |         return (ret); | 
 |     } | 
 |     if (size < 16) | 
 |         size = 16; | 
 |  | 
 |     ret = (xmlRelaxNGStatesPtr) xmlMalloc(sizeof(xmlRelaxNGStates) + | 
 |                                           (size - | 
 |                                            1) * | 
 |                                           sizeof(xmlRelaxNGValidStatePtr)); | 
 |     if (ret == NULL) { | 
 |         xmlRngVErrMemory(ctxt, "allocating states\n"); | 
 |         return (NULL); | 
 |     } | 
 |     ret->nbState = 0; | 
 |     ret->maxState = size; | 
 |     ret->tabState = (xmlRelaxNGValidStatePtr *) xmlMalloc((size) * | 
 |                                                           sizeof | 
 |                                                           (xmlRelaxNGValidStatePtr)); | 
 |     if (ret->tabState == NULL) { | 
 |         xmlRngVErrMemory(ctxt, "allocating states\n"); | 
 |         xmlFree(ret); | 
 |         return (NULL); | 
 |     } | 
 |     return (ret); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGAddStateUniq: | 
 |  * @ctxt:  a Relax-NG validation context | 
 |  * @states:  the states container | 
 |  * @state:  the validation state | 
 |  * | 
 |  * Add a RelaxNG validation state to the container without checking | 
 |  * for unicity. | 
 |  * | 
 |  * Return 1 in case of success and 0 if this is a duplicate and -1 on error | 
 |  */ | 
 | static int | 
 | xmlRelaxNGAddStatesUniq(xmlRelaxNGValidCtxtPtr ctxt, | 
 |                         xmlRelaxNGStatesPtr states, | 
 |                         xmlRelaxNGValidStatePtr state) | 
 | { | 
 |     if (state == NULL) { | 
 |         return (-1); | 
 |     } | 
 |     if (states->nbState >= states->maxState) { | 
 |         xmlRelaxNGValidStatePtr *tmp; | 
 |         int size; | 
 |  | 
 |         size = states->maxState * 2; | 
 |         tmp = (xmlRelaxNGValidStatePtr *) xmlRealloc(states->tabState, | 
 |                                                      (size) * | 
 |                                                      sizeof | 
 |                                                      (xmlRelaxNGValidStatePtr)); | 
 |         if (tmp == NULL) { | 
 |             xmlRngVErrMemory(ctxt, "adding states\n"); | 
 |             return (-1); | 
 |         } | 
 |         states->tabState = tmp; | 
 |         states->maxState = size; | 
 |     } | 
 |     states->tabState[states->nbState++] = state; | 
 |     return (1); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGAddState: | 
 |  * @ctxt:  a Relax-NG validation context | 
 |  * @states:  the states container | 
 |  * @state:  the validation state | 
 |  * | 
 |  * Add a RelaxNG validation state to the container | 
 |  * | 
 |  * Return 1 in case of success and 0 if this is a duplicate and -1 on error | 
 |  */ | 
 | static int | 
 | xmlRelaxNGAddStates(xmlRelaxNGValidCtxtPtr ctxt, | 
 |                     xmlRelaxNGStatesPtr states, | 
 |                     xmlRelaxNGValidStatePtr state) | 
 | { | 
 |     int i; | 
 |  | 
 |     if (state == NULL) { | 
 |         return (-1); | 
 |     } | 
 |     if (states->nbState >= states->maxState) { | 
 |         xmlRelaxNGValidStatePtr *tmp; | 
 |         int size; | 
 |  | 
 |         size = states->maxState * 2; | 
 |         tmp = (xmlRelaxNGValidStatePtr *) xmlRealloc(states->tabState, | 
 |                                                      (size) * | 
 |                                                      sizeof | 
 |                                                      (xmlRelaxNGValidStatePtr)); | 
 |         if (tmp == NULL) { | 
 |             xmlRngVErrMemory(ctxt, "adding states\n"); | 
 |             return (-1); | 
 |         } | 
 |         states->tabState = tmp; | 
 |         states->maxState = size; | 
 |     } | 
 |     for (i = 0; i < states->nbState; i++) { | 
 |         if (xmlRelaxNGEqualValidState(ctxt, state, states->tabState[i])) { | 
 |             xmlRelaxNGFreeValidState(ctxt, state); | 
 |             return (0); | 
 |         } | 
 |     } | 
 |     states->tabState[states->nbState++] = state; | 
 |     return (1); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGFreeStates: | 
 |  * @ctxt:  a Relax-NG validation context | 
 |  * @states:  teh container | 
 |  * | 
 |  * Free a RelaxNG validation state container | 
 |  */ | 
 | static void | 
 | xmlRelaxNGFreeStates(xmlRelaxNGValidCtxtPtr ctxt, | 
 |                      xmlRelaxNGStatesPtr states) | 
 | { | 
 |     if (states == NULL) | 
 |         return; | 
 |     if ((ctxt != NULL) && (ctxt->freeStates == NULL)) { | 
 |         ctxt->freeStatesMax = 40; | 
 |         ctxt->freeStatesNr = 0; | 
 |         ctxt->freeStates = (xmlRelaxNGStatesPtr *) | 
 |             xmlMalloc(ctxt->freeStatesMax * sizeof(xmlRelaxNGStatesPtr)); | 
 |         if (ctxt->freeStates == NULL) { | 
 |             xmlRngVErrMemory(ctxt, "storing states\n"); | 
 |         } | 
 |     } else if ((ctxt != NULL) | 
 |                && (ctxt->freeStatesNr >= ctxt->freeStatesMax)) { | 
 |         xmlRelaxNGStatesPtr *tmp; | 
 |  | 
 |         tmp = (xmlRelaxNGStatesPtr *) xmlRealloc(ctxt->freeStates, | 
 |                                                  2 * ctxt->freeStatesMax * | 
 |                                                  sizeof | 
 |                                                  (xmlRelaxNGStatesPtr)); | 
 |         if (tmp == NULL) { | 
 |             xmlRngVErrMemory(ctxt, "storing states\n"); | 
 |             xmlFree(states->tabState); | 
 |             xmlFree(states); | 
 |             return; | 
 |         } | 
 |         ctxt->freeStates = tmp; | 
 |         ctxt->freeStatesMax *= 2; | 
 |     } | 
 |     if ((ctxt == NULL) || (ctxt->freeStates == NULL)) { | 
 |         xmlFree(states->tabState); | 
 |         xmlFree(states); | 
 |     } else { | 
 |         ctxt->freeStates[ctxt->freeStatesNr++] = states; | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGNewValidState: | 
 |  * @ctxt:  a Relax-NG validation context | 
 |  * @node:  the current node or NULL for the document | 
 |  * | 
 |  * Allocate a new RelaxNG validation state | 
 |  * | 
 |  * Returns the newly allocated structure or NULL in case or error | 
 |  */ | 
 | static xmlRelaxNGValidStatePtr | 
 | xmlRelaxNGNewValidState(xmlRelaxNGValidCtxtPtr ctxt, xmlNodePtr node) | 
 | { | 
 |     xmlRelaxNGValidStatePtr ret; | 
 |     xmlAttrPtr attr; | 
 |     xmlAttrPtr attrs[MAX_ATTR]; | 
 |     int nbAttrs = 0; | 
 |     xmlNodePtr root = NULL; | 
 |  | 
 |     if (node == NULL) { | 
 |         root = xmlDocGetRootElement(ctxt->doc); | 
 |         if (root == NULL) | 
 |             return (NULL); | 
 |     } else { | 
 |         attr = node->properties; | 
 |         while (attr != NULL) { | 
 |             if (nbAttrs < MAX_ATTR) | 
 |                 attrs[nbAttrs++] = attr; | 
 |             else | 
 |                 nbAttrs++; | 
 |             attr = attr->next; | 
 |         } | 
 |     } | 
 |     if ((ctxt->freeState != NULL) && (ctxt->freeState->nbState > 0)) { | 
 |         ctxt->freeState->nbState--; | 
 |         ret = ctxt->freeState->tabState[ctxt->freeState->nbState]; | 
 |     } else { | 
 |         ret = | 
 |             (xmlRelaxNGValidStatePtr) | 
 |             xmlMalloc(sizeof(xmlRelaxNGValidState)); | 
 |         if (ret == NULL) { | 
 |             xmlRngVErrMemory(ctxt, "allocating states\n"); | 
 |             return (NULL); | 
 |         } | 
 |         memset(ret, 0, sizeof(xmlRelaxNGValidState)); | 
 |     } | 
 |     ret->value = NULL; | 
 |     ret->endvalue = NULL; | 
 |     if (node == NULL) { | 
 |         ret->node = (xmlNodePtr) ctxt->doc; | 
 |         ret->seq = root; | 
 |     } else { | 
 |         ret->node = node; | 
 |         ret->seq = node->children; | 
 |     } | 
 |     ret->nbAttrs = 0; | 
 |     if (nbAttrs > 0) { | 
 |         if (ret->attrs == NULL) { | 
 |             if (nbAttrs < 4) | 
 |                 ret->maxAttrs = 4; | 
 |             else | 
 |                 ret->maxAttrs = nbAttrs; | 
 |             ret->attrs = (xmlAttrPtr *) xmlMalloc(ret->maxAttrs * | 
 |                                                   sizeof(xmlAttrPtr)); | 
 |             if (ret->attrs == NULL) { | 
 |                 xmlRngVErrMemory(ctxt, "allocating states\n"); | 
 |                 return (ret); | 
 |             } | 
 |         } else if (ret->maxAttrs < nbAttrs) { | 
 |             xmlAttrPtr *tmp; | 
 |  | 
 |             tmp = (xmlAttrPtr *) xmlRealloc(ret->attrs, nbAttrs * | 
 |                                             sizeof(xmlAttrPtr)); | 
 |             if (tmp == NULL) { | 
 |                 xmlRngVErrMemory(ctxt, "allocating states\n"); | 
 |                 return (ret); | 
 |             } | 
 |             ret->attrs = tmp; | 
 |             ret->maxAttrs = nbAttrs; | 
 |         } | 
 |         ret->nbAttrs = nbAttrs; | 
 |         if (nbAttrs < MAX_ATTR) { | 
 |             memcpy(ret->attrs, attrs, sizeof(xmlAttrPtr) * nbAttrs); | 
 |         } else { | 
 |             attr = node->properties; | 
 |             nbAttrs = 0; | 
 |             while (attr != NULL) { | 
 |                 ret->attrs[nbAttrs++] = attr; | 
 |                 attr = attr->next; | 
 |             } | 
 |         } | 
 |     } | 
 |     ret->nbAttrLeft = ret->nbAttrs; | 
 |     return (ret); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGCopyValidState: | 
 |  * @ctxt:  a Relax-NG validation context | 
 |  * @state:  a validation state | 
 |  * | 
 |  * Copy the validation state | 
 |  * | 
 |  * Returns the newly allocated structure or NULL in case or error | 
 |  */ | 
 | static xmlRelaxNGValidStatePtr | 
 | xmlRelaxNGCopyValidState(xmlRelaxNGValidCtxtPtr ctxt, | 
 |                          xmlRelaxNGValidStatePtr state) | 
 | { | 
 |     xmlRelaxNGValidStatePtr ret; | 
 |     unsigned int maxAttrs; | 
 |     xmlAttrPtr *attrs; | 
 |  | 
 |     if (state == NULL) | 
 |         return (NULL); | 
 |     if ((ctxt->freeState != NULL) && (ctxt->freeState->nbState > 0)) { | 
 |         ctxt->freeState->nbState--; | 
 |         ret = ctxt->freeState->tabState[ctxt->freeState->nbState]; | 
 |     } else { | 
 |         ret = | 
 |             (xmlRelaxNGValidStatePtr) | 
 |             xmlMalloc(sizeof(xmlRelaxNGValidState)); | 
 |         if (ret == NULL) { | 
 |             xmlRngVErrMemory(ctxt, "allocating states\n"); | 
 |             return (NULL); | 
 |         } | 
 |         memset(ret, 0, sizeof(xmlRelaxNGValidState)); | 
 |     } | 
 |     attrs = ret->attrs; | 
 |     maxAttrs = ret->maxAttrs; | 
 |     memcpy(ret, state, sizeof(xmlRelaxNGValidState)); | 
 |     ret->attrs = attrs; | 
 |     ret->maxAttrs = maxAttrs; | 
 |     if (state->nbAttrs > 0) { | 
 |         if (ret->attrs == NULL) { | 
 |             ret->maxAttrs = state->maxAttrs; | 
 |             ret->attrs = (xmlAttrPtr *) xmlMalloc(ret->maxAttrs * | 
 |                                                   sizeof(xmlAttrPtr)); | 
 |             if (ret->attrs == NULL) { | 
 |                 xmlRngVErrMemory(ctxt, "allocating states\n"); | 
 |                 ret->nbAttrs = 0; | 
 |                 return (ret); | 
 |             } | 
 |         } else if (ret->maxAttrs < state->nbAttrs) { | 
 |             xmlAttrPtr *tmp; | 
 |  | 
 |             tmp = (xmlAttrPtr *) xmlRealloc(ret->attrs, state->maxAttrs * | 
 |                                             sizeof(xmlAttrPtr)); | 
 |             if (tmp == NULL) { | 
 |                 xmlRngVErrMemory(ctxt, "allocating states\n"); | 
 |                 ret->nbAttrs = 0; | 
 |                 return (ret); | 
 |             } | 
 |             ret->maxAttrs = state->maxAttrs; | 
 |             ret->attrs = tmp; | 
 |         } | 
 |         memcpy(ret->attrs, state->attrs, | 
 |                state->nbAttrs * sizeof(xmlAttrPtr)); | 
 |     } | 
 |     return (ret); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGEqualValidState: | 
 |  * @ctxt:  a Relax-NG validation context | 
 |  * @state1:  a validation state | 
 |  * @state2:  a validation state | 
 |  * | 
 |  * Compare the validation states for equality | 
 |  * | 
 |  * Returns 1 if equald, 0 otherwise | 
 |  */ | 
 | static int | 
 | xmlRelaxNGEqualValidState(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED, | 
 |                           xmlRelaxNGValidStatePtr state1, | 
 |                           xmlRelaxNGValidStatePtr state2) | 
 | { | 
 |     int i; | 
 |  | 
 |     if ((state1 == NULL) || (state2 == NULL)) | 
 |         return (0); | 
 |     if (state1 == state2) | 
 |         return (1); | 
 |     if (state1->node != state2->node) | 
 |         return (0); | 
 |     if (state1->seq != state2->seq) | 
 |         return (0); | 
 |     if (state1->nbAttrLeft != state2->nbAttrLeft) | 
 |         return (0); | 
 |     if (state1->nbAttrs != state2->nbAttrs) | 
 |         return (0); | 
 |     if (state1->endvalue != state2->endvalue) | 
 |         return (0); | 
 |     if ((state1->value != state2->value) && | 
 |         (!xmlStrEqual(state1->value, state2->value))) | 
 |         return (0); | 
 |     for (i = 0; i < state1->nbAttrs; i++) { | 
 |         if (state1->attrs[i] != state2->attrs[i]) | 
 |             return (0); | 
 |     } | 
 |     return (1); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGFreeValidState: | 
 |  * @state:  a validation state structure | 
 |  * | 
 |  * Deallocate a RelaxNG validation state structure. | 
 |  */ | 
 | static void | 
 | xmlRelaxNGFreeValidState(xmlRelaxNGValidCtxtPtr ctxt, | 
 |                          xmlRelaxNGValidStatePtr state) | 
 | { | 
 |     if (state == NULL) | 
 |         return; | 
 |  | 
 |     if ((ctxt != NULL) && (ctxt->freeState == NULL)) { | 
 |         ctxt->freeState = xmlRelaxNGNewStates(ctxt, 40); | 
 |     } | 
 |     if ((ctxt == NULL) || (ctxt->freeState == NULL)) { | 
 |         if (state->attrs != NULL) | 
 |             xmlFree(state->attrs); | 
 |         xmlFree(state); | 
 |     } else { | 
 |         xmlRelaxNGAddStatesUniq(ctxt, ctxt->freeState, state); | 
 |     } | 
 | } | 
 |  | 
 | /************************************************************************ | 
 |  * 									* | 
 |  * 			Semi internal functions				* | 
 |  * 									* | 
 |  ************************************************************************/ | 
 |  | 
 | /** | 
 |  * xmlRelaxParserSetFlag: | 
 |  * @ctxt: a RelaxNG parser context | 
 |  * @flags: a set of flags values | 
 |  * | 
 |  * Semi private function used to pass informations to a parser context | 
 |  * which are a combination of xmlRelaxNGParserFlag . | 
 |  * | 
 |  * Returns 0 if success and -1 in case of error | 
 |  */ | 
 | int | 
 | xmlRelaxParserSetFlag(xmlRelaxNGParserCtxtPtr ctxt, int flags) | 
 | { | 
 |     if (ctxt == NULL) return(-1); | 
 |     if (flags & XML_RELAXNGP_FREE_DOC) { | 
 |         ctxt->crng |= XML_RELAXNGP_FREE_DOC; | 
 | 	flags -= XML_RELAXNGP_FREE_DOC; | 
 |     } | 
 |     if (flags & XML_RELAXNGP_CRNG) { | 
 |         ctxt->crng |= XML_RELAXNGP_CRNG; | 
 | 	flags -= XML_RELAXNGP_CRNG; | 
 |     } | 
 |     if (flags != 0) return(-1); | 
 |     return(0); | 
 | } | 
 |  | 
 | /************************************************************************ | 
 |  * 									* | 
 |  * 			Document functions				* | 
 |  * 									* | 
 |  ************************************************************************/ | 
 | static xmlDocPtr xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt, | 
 |                                       xmlDocPtr doc); | 
 |  | 
 | /** | 
 |  * xmlRelaxNGIncludePush: | 
 |  * @ctxt:  the parser context | 
 |  * @value:  the element doc | 
 |  * | 
 |  * Pushes a new include on top of the include stack | 
 |  * | 
 |  * Returns 0 in case of error, the index in the stack otherwise | 
 |  */ | 
 | static int | 
 | xmlRelaxNGIncludePush(xmlRelaxNGParserCtxtPtr ctxt, | 
 |                       xmlRelaxNGIncludePtr value) | 
 | { | 
 |     if (ctxt->incTab == NULL) { | 
 |         ctxt->incMax = 4; | 
 |         ctxt->incNr = 0; | 
 |         ctxt->incTab = | 
 |             (xmlRelaxNGIncludePtr *) xmlMalloc(ctxt->incMax * | 
 |                                                sizeof(ctxt->incTab[0])); | 
 |         if (ctxt->incTab == NULL) { | 
 |             xmlRngPErrMemory(ctxt, "allocating include\n"); | 
 |             return (0); | 
 |         } | 
 |     } | 
 |     if (ctxt->incNr >= ctxt->incMax) { | 
 |         ctxt->incMax *= 2; | 
 |         ctxt->incTab = | 
 |             (xmlRelaxNGIncludePtr *) xmlRealloc(ctxt->incTab, | 
 |                                                 ctxt->incMax * | 
 |                                                 sizeof(ctxt->incTab[0])); | 
 |         if (ctxt->incTab == NULL) { | 
 |             xmlRngPErrMemory(ctxt, "allocating include\n"); | 
 |             return (0); | 
 |         } | 
 |     } | 
 |     ctxt->incTab[ctxt->incNr] = value; | 
 |     ctxt->inc = value; | 
 |     return (ctxt->incNr++); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGIncludePop: | 
 |  * @ctxt: the parser context | 
 |  * | 
 |  * Pops the top include from the include stack | 
 |  * | 
 |  * Returns the include just removed | 
 |  */ | 
 | static xmlRelaxNGIncludePtr | 
 | xmlRelaxNGIncludePop(xmlRelaxNGParserCtxtPtr ctxt) | 
 | { | 
 |     xmlRelaxNGIncludePtr ret; | 
 |  | 
 |     if (ctxt->incNr <= 0) | 
 |         return (NULL); | 
 |     ctxt->incNr--; | 
 |     if (ctxt->incNr > 0) | 
 |         ctxt->inc = ctxt->incTab[ctxt->incNr - 1]; | 
 |     else | 
 |         ctxt->inc = NULL; | 
 |     ret = ctxt->incTab[ctxt->incNr]; | 
 |     ctxt->incTab[ctxt->incNr] = NULL; | 
 |     return (ret); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGRemoveRedefine: | 
 |  * @ctxt: the parser context | 
 |  * @URL:  the normalized URL | 
 |  * @target:  the included target | 
 |  * @name:  the define name to eliminate | 
 |  * | 
 |  * Applies the elimination algorithm of 4.7 | 
 |  * | 
 |  * Returns 0 in case of error, 1 in case of success. | 
 |  */ | 
 | static int | 
 | xmlRelaxNGRemoveRedefine(xmlRelaxNGParserCtxtPtr ctxt, | 
 |                          const xmlChar * URL ATTRIBUTE_UNUSED, | 
 |                          xmlNodePtr target, const xmlChar * name) | 
 | { | 
 |     int found = 0; | 
 |     xmlNodePtr tmp, tmp2; | 
 |     xmlChar *name2; | 
 |  | 
 | #ifdef DEBUG_INCLUDE | 
 |     if (name == NULL) | 
 |         xmlGenericError(xmlGenericErrorContext, | 
 |                         "Elimination of <include> start from %s\n", URL); | 
 |     else | 
 |         xmlGenericError(xmlGenericErrorContext, | 
 |                         "Elimination of <include> define %s from %s\n", | 
 |                         name, URL); | 
 | #endif | 
 |     tmp = target; | 
 |     while (tmp != NULL) { | 
 |         tmp2 = tmp->next; | 
 |         if ((name == NULL) && (IS_RELAXNG(tmp, "start"))) { | 
 |             found = 1; | 
 |             xmlUnlinkNode(tmp); | 
 |             xmlFreeNode(tmp); | 
 |         } else if ((name != NULL) && (IS_RELAXNG(tmp, "define"))) { | 
 |             name2 = xmlGetProp(tmp, BAD_CAST "name"); | 
 |             xmlRelaxNGNormExtSpace(name2); | 
 |             if (name2 != NULL) { | 
 |                 if (xmlStrEqual(name, name2)) { | 
 |                     found = 1; | 
 |                     xmlUnlinkNode(tmp); | 
 |                     xmlFreeNode(tmp); | 
 |                 } | 
 |                 xmlFree(name2); | 
 |             } | 
 |         } else if (IS_RELAXNG(tmp, "include")) { | 
 |             xmlChar *href = NULL; | 
 |             xmlRelaxNGDocumentPtr inc = tmp->psvi; | 
 |  | 
 |             if ((inc != NULL) && (inc->doc != NULL) && | 
 |                 (inc->doc->children != NULL)) { | 
 |  | 
 |                 if (xmlStrEqual | 
 |                     (inc->doc->children->name, BAD_CAST "grammar")) { | 
 | #ifdef DEBUG_INCLUDE | 
 |                     href = xmlGetProp(tmp, BAD_CAST "href"); | 
 | #endif | 
 |                     if (xmlRelaxNGRemoveRedefine(ctxt, href, | 
 |                                                  inc->doc->children-> | 
 |                                                  children, name) == 1) { | 
 |                         found = 1; | 
 |                     } | 
 | #ifdef DEBUG_INCLUDE | 
 |                     if (href != NULL) | 
 |                         xmlFree(href); | 
 | #endif | 
 |                 } | 
 |             } | 
 |         } | 
 |         tmp = tmp2; | 
 |     } | 
 |     return (found); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGLoadInclude: | 
 |  * @ctxt: the parser context | 
 |  * @URL:  the normalized URL | 
 |  * @node: the include node. | 
 |  * @ns:  the namespace passed from the context. | 
 |  * | 
 |  * First lookup if the document is already loaded into the parser context, | 
 |  * check against recursion. If not found the resource is loaded and | 
 |  * the content is preprocessed before being returned back to the caller. | 
 |  * | 
 |  * Returns the xmlRelaxNGIncludePtr or NULL in case of error | 
 |  */ | 
 | static xmlRelaxNGIncludePtr | 
 | xmlRelaxNGLoadInclude(xmlRelaxNGParserCtxtPtr ctxt, const xmlChar * URL, | 
 |                       xmlNodePtr node, const xmlChar * ns) | 
 | { | 
 |     xmlRelaxNGIncludePtr ret = NULL; | 
 |     xmlDocPtr doc; | 
 |     int i; | 
 |     xmlNodePtr root, cur; | 
 |  | 
 | #ifdef DEBUG_INCLUDE | 
 |     xmlGenericError(xmlGenericErrorContext, | 
 |                     "xmlRelaxNGLoadInclude(%s)\n", URL); | 
 | #endif | 
 |  | 
 |     /* | 
 |      * check against recursion in the stack | 
 |      */ | 
 |     for (i = 0; i < ctxt->incNr; i++) { | 
 |         if (xmlStrEqual(ctxt->incTab[i]->href, URL)) { | 
 |             xmlRngPErr(ctxt, NULL, XML_RNGP_INCLUDE_RECURSE, | 
 |                        "Detected an Include recursion for %s\n", URL, | 
 |                        NULL); | 
 |             return (NULL); | 
 |         } | 
 |     } | 
 |  | 
 |     /* | 
 |      * load the document | 
 |      */ | 
 |     doc = xmlReadFile((const char *) URL,NULL,0); | 
 |     if (doc == NULL) { | 
 |         xmlRngPErr(ctxt, node, XML_RNGP_PARSE_ERROR, | 
 |                    "xmlRelaxNG: could not load %s\n", URL, NULL); | 
 |         return (NULL); | 
 |     } | 
 | #ifdef DEBUG_INCLUDE | 
 |     xmlGenericError(xmlGenericErrorContext, "Parsed %s Okay\n", URL); | 
 | #endif | 
 |  | 
 |     /* | 
 |      * Allocate the document structures and register it first. | 
 |      */ | 
 |     ret = (xmlRelaxNGIncludePtr) xmlMalloc(sizeof(xmlRelaxNGInclude)); | 
 |     if (ret == NULL) { | 
 |         xmlRngPErrMemory(ctxt, "allocating include\n"); | 
 |         xmlFreeDoc(doc); | 
 |         return (NULL); | 
 |     } | 
 |     memset(ret, 0, sizeof(xmlRelaxNGInclude)); | 
 |     ret->doc = doc; | 
 |     ret->href = xmlStrdup(URL); | 
 |     ret->next = ctxt->includes; | 
 |     ctxt->includes = ret; | 
 |  | 
 |     /* | 
 |      * transmit the ns if needed | 
 |      */ | 
 |     if (ns != NULL) { | 
 |         root = xmlDocGetRootElement(doc); | 
 |         if (root != NULL) { | 
 |             if (xmlHasProp(root, BAD_CAST "ns") == NULL) { | 
 |                 xmlSetProp(root, BAD_CAST "ns", ns); | 
 |             } | 
 |         } | 
 |     } | 
 |  | 
 |     /* | 
 |      * push it on the stack | 
 |      */ | 
 |     xmlRelaxNGIncludePush(ctxt, ret); | 
 |  | 
 |     /* | 
 |      * Some preprocessing of the document content, this include recursing | 
 |      * in the include stack. | 
 |      */ | 
 | #ifdef DEBUG_INCLUDE | 
 |     xmlGenericError(xmlGenericErrorContext, "cleanup of %s\n", URL); | 
 | #endif | 
 |  | 
 |     doc = xmlRelaxNGCleanupDoc(ctxt, doc); | 
 |     if (doc == NULL) { | 
 |         ctxt->inc = NULL; | 
 |         return (NULL); | 
 |     } | 
 |  | 
 |     /* | 
 |      * Pop up the include from the stack | 
 |      */ | 
 |     xmlRelaxNGIncludePop(ctxt); | 
 |  | 
 | #ifdef DEBUG_INCLUDE | 
 |     xmlGenericError(xmlGenericErrorContext, "Checking of %s\n", URL); | 
 | #endif | 
 |     /* | 
 |      * Check that the top element is a grammar | 
 |      */ | 
 |     root = xmlDocGetRootElement(doc); | 
 |     if (root == NULL) { | 
 |         xmlRngPErr(ctxt, node, XML_RNGP_EMPTY, | 
 |                    "xmlRelaxNG: included document is empty %s\n", URL, | 
 |                    NULL); | 
 |         return (NULL); | 
 |     } | 
 |     if (!IS_RELAXNG(root, "grammar")) { | 
 |         xmlRngPErr(ctxt, node, XML_RNGP_GRAMMAR_MISSING, | 
 |                    "xmlRelaxNG: included document %s root is not a grammar\n", | 
 |                    URL, NULL); | 
 |         return (NULL); | 
 |     } | 
 |  | 
 |     /* | 
 |      * Elimination of redefined rules in the include. | 
 |      */ | 
 |     cur = node->children; | 
 |     while (cur != NULL) { | 
 |         if (IS_RELAXNG(cur, "start")) { | 
 |             int found = 0; | 
 |  | 
 |             found = | 
 |                 xmlRelaxNGRemoveRedefine(ctxt, URL, root->children, NULL); | 
 |             if (!found) { | 
 |                 xmlRngPErr(ctxt, node, XML_RNGP_START_MISSING, | 
 |                            "xmlRelaxNG: include %s has a start but not the included grammar\n", | 
 |                            URL, NULL); | 
 |             } | 
 |         } else if (IS_RELAXNG(cur, "define")) { | 
 |             xmlChar *name; | 
 |  | 
 |             name = xmlGetProp(cur, BAD_CAST "name"); | 
 |             if (name == NULL) { | 
 |                 xmlRngPErr(ctxt, node, XML_RNGP_NAME_MISSING, | 
 |                            "xmlRelaxNG: include %s has define without name\n", | 
 |                            URL, NULL); | 
 |             } else { | 
 |                 int found; | 
 |  | 
 |                 xmlRelaxNGNormExtSpace(name); | 
 |                 found = xmlRelaxNGRemoveRedefine(ctxt, URL, | 
 |                                                  root->children, name); | 
 |                 if (!found) { | 
 |                     xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_MISSING, | 
 |                                "xmlRelaxNG: include %s has a define %s but not the included grammar\n", | 
 |                                URL, name); | 
 |                 } | 
 |                 xmlFree(name); | 
 |             } | 
 |         } | 
 |         cur = cur->next; | 
 |     } | 
 |  | 
 |  | 
 |     return (ret); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGValidErrorPush: | 
 |  * @ctxt:  the validation context | 
 |  * @err:  the error code | 
 |  * @arg1:  the first string argument | 
 |  * @arg2:  the second string argument | 
 |  * @dup:  arg need to be duplicated | 
 |  * | 
 |  * Pushes a new error on top of the error stack | 
 |  * | 
 |  * Returns 0 in case of error, the index in the stack otherwise | 
 |  */ | 
 | static int | 
 | xmlRelaxNGValidErrorPush(xmlRelaxNGValidCtxtPtr ctxt, | 
 |                          xmlRelaxNGValidErr err, const xmlChar * arg1, | 
 |                          const xmlChar * arg2, int dup) | 
 | { | 
 |     xmlRelaxNGValidErrorPtr cur; | 
 |  | 
 | #ifdef DEBUG_ERROR | 
 |     xmlGenericError(xmlGenericErrorContext, | 
 |                     "Pushing error %d at %d on stack\n", err, ctxt->errNr); | 
 | #endif | 
 |     if (ctxt->errTab == NULL) { | 
 |         ctxt->errMax = 8; | 
 |         ctxt->errNr = 0; | 
 |         ctxt->errTab = | 
 |             (xmlRelaxNGValidErrorPtr) xmlMalloc(ctxt->errMax * | 
 |                                                 sizeof | 
 |                                                 (xmlRelaxNGValidError)); | 
 |         if (ctxt->errTab == NULL) { | 
 |             xmlRngVErrMemory(ctxt, "pushing error\n"); | 
 |             return (0); | 
 |         } | 
 |         ctxt->err = NULL; | 
 |     } | 
 |     if (ctxt->errNr >= ctxt->errMax) { | 
 |         ctxt->errMax *= 2; | 
 |         ctxt->errTab = | 
 |             (xmlRelaxNGValidErrorPtr) xmlRealloc(ctxt->errTab, | 
 |                                                  ctxt->errMax * | 
 |                                                  sizeof | 
 |                                                  (xmlRelaxNGValidError)); | 
 |         if (ctxt->errTab == NULL) { | 
 |             xmlRngVErrMemory(ctxt, "pushing error\n"); | 
 |             return (0); | 
 |         } | 
 |         ctxt->err = &ctxt->errTab[ctxt->errNr - 1]; | 
 |     } | 
 |     if ((ctxt->err != NULL) && (ctxt->state != NULL) && | 
 |         (ctxt->err->node == ctxt->state->node) && (ctxt->err->err == err)) | 
 |         return (ctxt->errNr); | 
 |     cur = &ctxt->errTab[ctxt->errNr]; | 
 |     cur->err = err; | 
 |     if (dup) { | 
 |         cur->arg1 = xmlStrdup(arg1); | 
 |         cur->arg2 = xmlStrdup(arg2); | 
 |         cur->flags = ERROR_IS_DUP; | 
 |     } else { | 
 |         cur->arg1 = arg1; | 
 |         cur->arg2 = arg2; | 
 |         cur->flags = 0; | 
 |     } | 
 |     if (ctxt->state != NULL) { | 
 |         cur->node = ctxt->state->node; | 
 |         cur->seq = ctxt->state->seq; | 
 |     } else { | 
 |         cur->node = NULL; | 
 |         cur->seq = NULL; | 
 |     } | 
 |     ctxt->err = cur; | 
 |     return (ctxt->errNr++); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGValidErrorPop: | 
 |  * @ctxt: the validation context | 
 |  * | 
 |  * Pops the top error from the error stack | 
 |  */ | 
 | static void | 
 | xmlRelaxNGValidErrorPop(xmlRelaxNGValidCtxtPtr ctxt) | 
 | { | 
 |     xmlRelaxNGValidErrorPtr cur; | 
 |  | 
 |     if (ctxt->errNr <= 0) { | 
 |         ctxt->err = NULL; | 
 |         return; | 
 |     } | 
 |     ctxt->errNr--; | 
 |     if (ctxt->errNr > 0) | 
 |         ctxt->err = &ctxt->errTab[ctxt->errNr - 1]; | 
 |     else | 
 |         ctxt->err = NULL; | 
 |     cur = &ctxt->errTab[ctxt->errNr]; | 
 |     if (cur->flags & ERROR_IS_DUP) { | 
 |         if (cur->arg1 != NULL) | 
 |             xmlFree((xmlChar *) cur->arg1); | 
 |         cur->arg1 = NULL; | 
 |         if (cur->arg2 != NULL) | 
 |             xmlFree((xmlChar *) cur->arg2); | 
 |         cur->arg2 = NULL; | 
 |         cur->flags = 0; | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGDocumentPush: | 
 |  * @ctxt:  the parser context | 
 |  * @value:  the element doc | 
 |  * | 
 |  * Pushes a new doc on top of the doc stack | 
 |  * | 
 |  * Returns 0 in case of error, the index in the stack otherwise | 
 |  */ | 
 | static int | 
 | xmlRelaxNGDocumentPush(xmlRelaxNGParserCtxtPtr ctxt, | 
 |                        xmlRelaxNGDocumentPtr value) | 
 | { | 
 |     if (ctxt->docTab == NULL) { | 
 |         ctxt->docMax = 4; | 
 |         ctxt->docNr = 0; | 
 |         ctxt->docTab = | 
 |             (xmlRelaxNGDocumentPtr *) xmlMalloc(ctxt->docMax * | 
 |                                                 sizeof(ctxt->docTab[0])); | 
 |         if (ctxt->docTab == NULL) { | 
 |             xmlRngPErrMemory(ctxt, "adding document\n"); | 
 |             return (0); | 
 |         } | 
 |     } | 
 |     if (ctxt->docNr >= ctxt->docMax) { | 
 |         ctxt->docMax *= 2; | 
 |         ctxt->docTab = | 
 |             (xmlRelaxNGDocumentPtr *) xmlRealloc(ctxt->docTab, | 
 |                                                  ctxt->docMax * | 
 |                                                  sizeof(ctxt->docTab[0])); | 
 |         if (ctxt->docTab == NULL) { | 
 |             xmlRngPErrMemory(ctxt, "adding document\n"); | 
 |             return (0); | 
 |         } | 
 |     } | 
 |     ctxt->docTab[ctxt->docNr] = value; | 
 |     ctxt->doc = value; | 
 |     return (ctxt->docNr++); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGDocumentPop: | 
 |  * @ctxt: the parser context | 
 |  * | 
 |  * Pops the top doc from the doc stack | 
 |  * | 
 |  * Returns the doc just removed | 
 |  */ | 
 | static xmlRelaxNGDocumentPtr | 
 | xmlRelaxNGDocumentPop(xmlRelaxNGParserCtxtPtr ctxt) | 
 | { | 
 |     xmlRelaxNGDocumentPtr ret; | 
 |  | 
 |     if (ctxt->docNr <= 0) | 
 |         return (NULL); | 
 |     ctxt->docNr--; | 
 |     if (ctxt->docNr > 0) | 
 |         ctxt->doc = ctxt->docTab[ctxt->docNr - 1]; | 
 |     else | 
 |         ctxt->doc = NULL; | 
 |     ret = ctxt->docTab[ctxt->docNr]; | 
 |     ctxt->docTab[ctxt->docNr] = NULL; | 
 |     return (ret); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGLoadExternalRef: | 
 |  * @ctxt: the parser context | 
 |  * @URL:  the normalized URL | 
 |  * @ns:  the inherited ns if any | 
 |  * | 
 |  * First lookup if the document is already loaded into the parser context, | 
 |  * check against recursion. If not found the resource is loaded and | 
 |  * the content is preprocessed before being returned back to the caller. | 
 |  * | 
 |  * Returns the xmlRelaxNGDocumentPtr or NULL in case of error | 
 |  */ | 
 | static xmlRelaxNGDocumentPtr | 
 | xmlRelaxNGLoadExternalRef(xmlRelaxNGParserCtxtPtr ctxt, | 
 |                           const xmlChar * URL, const xmlChar * ns) | 
 | { | 
 |     xmlRelaxNGDocumentPtr ret = NULL; | 
 |     xmlDocPtr doc; | 
 |     xmlNodePtr root; | 
 |     int i; | 
 |  | 
 |     /* | 
 |      * check against recursion in the stack | 
 |      */ | 
 |     for (i = 0; i < ctxt->docNr; i++) { | 
 |         if (xmlStrEqual(ctxt->docTab[i]->href, URL)) { | 
 |             xmlRngPErr(ctxt, NULL, XML_RNGP_EXTERNALREF_RECURSE, | 
 |                        "Detected an externalRef recursion for %s\n", URL, | 
 |                        NULL); | 
 |             return (NULL); | 
 |         } | 
 |     } | 
 |  | 
 |     /* | 
 |      * load the document | 
 |      */ | 
 |     doc = xmlReadFile((const char *) URL,NULL,0); | 
 |     if (doc == NULL) { | 
 |         xmlRngPErr(ctxt, NULL, XML_RNGP_PARSE_ERROR, | 
 |                    "xmlRelaxNG: could not load %s\n", URL, NULL); | 
 |         return (NULL); | 
 |     } | 
 |  | 
 |     /* | 
 |      * Allocate the document structures and register it first. | 
 |      */ | 
 |     ret = (xmlRelaxNGDocumentPtr) xmlMalloc(sizeof(xmlRelaxNGDocument)); | 
 |     if (ret == NULL) { | 
 |         xmlRngPErr(ctxt, (xmlNodePtr) doc, XML_ERR_NO_MEMORY, | 
 |                    "xmlRelaxNG: allocate memory for doc %s\n", URL, NULL); | 
 |         xmlFreeDoc(doc); | 
 |         return (NULL); | 
 |     } | 
 |     memset(ret, 0, sizeof(xmlRelaxNGDocument)); | 
 |     ret->doc = doc; | 
 |     ret->href = xmlStrdup(URL); | 
 |     ret->next = ctxt->documents; | 
 |     ret->externalRef = 1; | 
 |     ctxt->documents = ret; | 
 |  | 
 |     /* | 
 |      * transmit the ns if needed | 
 |      */ | 
 |     if (ns != NULL) { | 
 |         root = xmlDocGetRootElement(doc); | 
 |         if (root != NULL) { | 
 |             if (xmlHasProp(root, BAD_CAST "ns") == NULL) { | 
 |                 xmlSetProp(root, BAD_CAST "ns", ns); | 
 |             } | 
 |         } | 
 |     } | 
 |  | 
 |     /* | 
 |      * push it on the stack and register it in the hash table | 
 |      */ | 
 |     xmlRelaxNGDocumentPush(ctxt, ret); | 
 |  | 
 |     /* | 
 |      * Some preprocessing of the document content | 
 |      */ | 
 |     doc = xmlRelaxNGCleanupDoc(ctxt, doc); | 
 |     if (doc == NULL) { | 
 |         ctxt->doc = NULL; | 
 |         return (NULL); | 
 |     } | 
 |  | 
 |     xmlRelaxNGDocumentPop(ctxt); | 
 |  | 
 |     return (ret); | 
 | } | 
 |  | 
 | /************************************************************************ | 
 |  * 									* | 
 |  * 			Error functions					* | 
 |  * 									* | 
 |  ************************************************************************/ | 
 |  | 
 | #define VALID_ERR(a) xmlRelaxNGAddValidError(ctxt, a, NULL, NULL, 0); | 
 | #define VALID_ERR2(a, b) xmlRelaxNGAddValidError(ctxt, a, b, NULL, 0); | 
 | #define VALID_ERR3(a, b, c) xmlRelaxNGAddValidError(ctxt, a, b, c, 0); | 
 | #define VALID_ERR2P(a, b) xmlRelaxNGAddValidError(ctxt, a, b, NULL, 1); | 
 | #define VALID_ERR3P(a, b, c) xmlRelaxNGAddValidError(ctxt, a, b, c, 1); | 
 |  | 
 | static const char * | 
 | xmlRelaxNGDefName(xmlRelaxNGDefinePtr def) | 
 | { | 
 |     if (def == NULL) | 
 |         return ("none"); | 
 |     switch (def->type) { | 
 |         case XML_RELAXNG_EMPTY: | 
 |             return ("empty"); | 
 |         case XML_RELAXNG_NOT_ALLOWED: | 
 |             return ("notAllowed"); | 
 |         case XML_RELAXNG_EXCEPT: | 
 |             return ("except"); | 
 |         case XML_RELAXNG_TEXT: | 
 |             return ("text"); | 
 |         case XML_RELAXNG_ELEMENT: | 
 |             return ("element"); | 
 |         case XML_RELAXNG_DATATYPE: | 
 |             return ("datatype"); | 
 |         case XML_RELAXNG_VALUE: | 
 |             return ("value"); | 
 |         case XML_RELAXNG_LIST: | 
 |             return ("list"); | 
 |         case XML_RELAXNG_ATTRIBUTE: | 
 |             return ("attribute"); | 
 |         case XML_RELAXNG_DEF: | 
 |             return ("def"); | 
 |         case XML_RELAXNG_REF: | 
 |             return ("ref"); | 
 |         case XML_RELAXNG_EXTERNALREF: | 
 |             return ("externalRef"); | 
 |         case XML_RELAXNG_PARENTREF: | 
 |             return ("parentRef"); | 
 |         case XML_RELAXNG_OPTIONAL: | 
 |             return ("optional"); | 
 |         case XML_RELAXNG_ZEROORMORE: | 
 |             return ("zeroOrMore"); | 
 |         case XML_RELAXNG_ONEORMORE: | 
 |             return ("oneOrMore"); | 
 |         case XML_RELAXNG_CHOICE: | 
 |             return ("choice"); | 
 |         case XML_RELAXNG_GROUP: | 
 |             return ("group"); | 
 |         case XML_RELAXNG_INTERLEAVE: | 
 |             return ("interleave"); | 
 |         case XML_RELAXNG_START: | 
 |             return ("start"); | 
 |         case XML_RELAXNG_NOOP: | 
 |             return ("noop"); | 
 |         case XML_RELAXNG_PARAM: | 
 |             return ("param"); | 
 |     } | 
 |     return ("unknown"); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGGetErrorString: | 
 |  * @err:  the error code | 
 |  * @arg1:  the first string argument | 
 |  * @arg2:  the second string argument | 
 |  * | 
 |  * computes a formatted error string for the given error code and args | 
 |  * | 
 |  * Returns the error string, it must be deallocated by the caller | 
 |  */ | 
 | static xmlChar * | 
 | xmlRelaxNGGetErrorString(xmlRelaxNGValidErr err, const xmlChar * arg1, | 
 |                          const xmlChar * arg2) | 
 | { | 
 |     char msg[1000]; | 
 |  | 
 |     if (arg1 == NULL) | 
 |         arg1 = BAD_CAST ""; | 
 |     if (arg2 == NULL) | 
 |         arg2 = BAD_CAST ""; | 
 |  | 
 |     msg[0] = 0; | 
 |     switch (err) { | 
 |         case XML_RELAXNG_OK: | 
 |             return (NULL); | 
 |         case XML_RELAXNG_ERR_MEMORY: | 
 |             return (xmlCharStrdup("out of memory\n")); | 
 |         case XML_RELAXNG_ERR_TYPE: | 
 |             snprintf(msg, 1000, "failed to validate type %s\n", arg1); | 
 |             break; | 
 |         case XML_RELAXNG_ERR_TYPEVAL: | 
 |             snprintf(msg, 1000, "Type %s doesn't allow value '%s'\n", arg1, | 
 |                      arg2); | 
 |             break; | 
 |         case XML_RELAXNG_ERR_DUPID: | 
 |             snprintf(msg, 1000, "ID %s redefined\n", arg1); | 
 |             break; | 
 |         case XML_RELAXNG_ERR_TYPECMP: | 
 |             snprintf(msg, 1000, "failed to compare type %s\n", arg1); | 
 |             break; | 
 |         case XML_RELAXNG_ERR_NOSTATE: | 
 |             return (xmlCharStrdup("Internal error: no state\n")); | 
 |         case XML_RELAXNG_ERR_NODEFINE: | 
 |             return (xmlCharStrdup("Internal error: no define\n")); | 
 |         case XML_RELAXNG_ERR_INTERNAL: | 
 |             snprintf(msg, 1000, "Internal error: %s\n", arg1); | 
 |             break; | 
 |         case XML_RELAXNG_ERR_LISTEXTRA: | 
 |             snprintf(msg, 1000, "Extra data in list: %s\n", arg1); | 
 |             break; | 
 |         case XML_RELAXNG_ERR_INTERNODATA: | 
 |             return (xmlCharStrdup | 
 |                     ("Internal: interleave block has no data\n")); | 
 |         case XML_RELAXNG_ERR_INTERSEQ: | 
 |             return (xmlCharStrdup("Invalid sequence in interleave\n")); | 
 |         case XML_RELAXNG_ERR_INTEREXTRA: | 
 |             snprintf(msg, 1000, "Extra element %s in interleave\n", arg1); | 
 |             break; | 
 |         case XML_RELAXNG_ERR_ELEMNAME: | 
 |             snprintf(msg, 1000, "Expecting element %s, got %s\n", arg1, | 
 |                      arg2); | 
 |             break; | 
 |         case XML_RELAXNG_ERR_ELEMNONS: | 
 |             snprintf(msg, 1000, "Expecting a namespace for element %s\n", | 
 |                      arg1); | 
 |             break; | 
 |         case XML_RELAXNG_ERR_ELEMWRONGNS: | 
 |             snprintf(msg, 1000, | 
 |                      "Element %s has wrong namespace: expecting %s\n", arg1, | 
 |                      arg2); | 
 |             break; | 
 |         case XML_RELAXNG_ERR_ELEMWRONG: | 
 |             snprintf(msg, 1000, "Did not expect element %s there\n", arg1); | 
 |             break; | 
 |         case XML_RELAXNG_ERR_TEXTWRONG: | 
 |             snprintf(msg, 1000, | 
 |                      "Did not expect text in element %s content\n", arg1); | 
 |             break; | 
 |         case XML_RELAXNG_ERR_ELEMEXTRANS: | 
 |             snprintf(msg, 1000, "Expecting no namespace for element %s\n", | 
 |                      arg1); | 
 |             break; | 
 |         case XML_RELAXNG_ERR_ELEMNOTEMPTY: | 
 |             snprintf(msg, 1000, "Expecting element %s to be empty\n", arg1); | 
 |             break; | 
 |         case XML_RELAXNG_ERR_NOELEM: | 
 |             snprintf(msg, 1000, "Expecting an element %s, got nothing\n", | 
 |                      arg1); | 
 |             break; | 
 |         case XML_RELAXNG_ERR_NOTELEM: | 
 |             return (xmlCharStrdup("Expecting an element got text\n")); | 
 |         case XML_RELAXNG_ERR_ATTRVALID: | 
 |             snprintf(msg, 1000, "Element %s failed to validate attributes\n", | 
 |                      arg1); | 
 |             break; | 
 |         case XML_RELAXNG_ERR_CONTENTVALID: | 
 |             snprintf(msg, 1000, "Element %s failed to validate content\n", | 
 |                      arg1); | 
 |             break; | 
 |         case XML_RELAXNG_ERR_EXTRACONTENT: | 
 |             snprintf(msg, 1000, "Element %s has extra content: %s\n", | 
 |                      arg1, arg2); | 
 |             break; | 
 |         case XML_RELAXNG_ERR_INVALIDATTR: | 
 |             snprintf(msg, 1000, "Invalid attribute %s for element %s\n", | 
 |                      arg1, arg2); | 
 |             break; | 
 |         case XML_RELAXNG_ERR_LACKDATA: | 
 |             snprintf(msg, 1000, "Datatype element %s contains no data\n", | 
 |                      arg1); | 
 |             break; | 
 |         case XML_RELAXNG_ERR_DATAELEM: | 
 |             snprintf(msg, 1000, "Datatype element %s has child elements\n", | 
 |                      arg1); | 
 |             break; | 
 |         case XML_RELAXNG_ERR_VALELEM: | 
 |             snprintf(msg, 1000, "Value element %s has child elements\n", | 
 |                      arg1); | 
 |             break; | 
 |         case XML_RELAXNG_ERR_LISTELEM: | 
 |             snprintf(msg, 1000, "List element %s has child elements\n", | 
 |                      arg1); | 
 |             break; | 
 |         case XML_RELAXNG_ERR_DATATYPE: | 
 |             snprintf(msg, 1000, "Error validating datatype %s\n", arg1); | 
 |             break; | 
 |         case XML_RELAXNG_ERR_VALUE: | 
 |             snprintf(msg, 1000, "Error validating value %s\n", arg1); | 
 |             break; | 
 |         case XML_RELAXNG_ERR_LIST: | 
 |             return (xmlCharStrdup("Error validating list\n")); | 
 |         case XML_RELAXNG_ERR_NOGRAMMAR: | 
 |             return (xmlCharStrdup("No top grammar defined\n")); | 
 |         case XML_RELAXNG_ERR_EXTRADATA: | 
 |             return (xmlCharStrdup("Extra data in the document\n")); | 
 |         default: | 
 |             return (xmlCharStrdup("Unknown error !\n")); | 
 |     } | 
 |     if (msg[0] == 0) { | 
 |         snprintf(msg, 1000, "Unknown error code %d\n", err); | 
 |     } | 
 |     msg[1000 - 1] = 0; | 
 |     return (xmlStrdup((xmlChar *) msg)); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGShowValidError: | 
 |  * @ctxt:  the validation context | 
 |  * @err:  the error number | 
 |  * @node:  the node | 
 |  * @child:  the node child generating the problem. | 
 |  * @arg1:  the first argument | 
 |  * @arg2:  the second argument | 
 |  * | 
 |  * Show a validation error. | 
 |  */ | 
 | static void | 
 | xmlRelaxNGShowValidError(xmlRelaxNGValidCtxtPtr ctxt, | 
 |                          xmlRelaxNGValidErr err, xmlNodePtr node, | 
 |                          xmlNodePtr child, const xmlChar * arg1, | 
 |                          const xmlChar * arg2) | 
 | { | 
 |     xmlChar *msg; | 
 |  | 
 |     if (ctxt->flags & FLAGS_NOERROR) | 
 |         return; | 
 |  | 
 | #ifdef DEBUG_ERROR | 
 |     xmlGenericError(xmlGenericErrorContext, "Show error %d\n", err); | 
 | #endif | 
 |     msg = xmlRelaxNGGetErrorString(err, arg1, arg2); | 
 |     if (msg == NULL) | 
 |         return; | 
 |  | 
 |     if (ctxt->errNo == XML_RELAXNG_OK) | 
 |         ctxt->errNo = err; | 
 |     xmlRngVErr(ctxt, (child == NULL ? node : child), err, | 
 |                (const char *) msg, arg1, arg2); | 
 |     xmlFree(msg); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGPopErrors: | 
 |  * @ctxt:  the validation context | 
 |  * @level:  the error level in the stack | 
 |  * | 
 |  * pop and discard all errors until the given level is reached | 
 |  */ | 
 | static void | 
 | xmlRelaxNGPopErrors(xmlRelaxNGValidCtxtPtr ctxt, int level) | 
 | { | 
 |     int i; | 
 |     xmlRelaxNGValidErrorPtr err; | 
 |  | 
 | #ifdef DEBUG_ERROR | 
 |     xmlGenericError(xmlGenericErrorContext, | 
 |                     "Pop errors till level %d\n", level); | 
 | #endif | 
 |     for (i = level; i < ctxt->errNr; i++) { | 
 |         err = &ctxt->errTab[i]; | 
 |         if (err->flags & ERROR_IS_DUP) { | 
 |             if (err->arg1 != NULL) | 
 |                 xmlFree((xmlChar *) err->arg1); | 
 |             err->arg1 = NULL; | 
 |             if (err->arg2 != NULL) | 
 |                 xmlFree((xmlChar *) err->arg2); | 
 |             err->arg2 = NULL; | 
 |             err->flags = 0; | 
 |         } | 
 |     } | 
 |     ctxt->errNr = level; | 
 |     if (ctxt->errNr <= 0) | 
 |         ctxt->err = NULL; | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGDumpValidError: | 
 |  * @ctxt:  the validation context | 
 |  * | 
 |  * Show all validation error over a given index. | 
 |  */ | 
 | static void | 
 | xmlRelaxNGDumpValidError(xmlRelaxNGValidCtxtPtr ctxt) | 
 | { | 
 |     int i, j, k; | 
 |     xmlRelaxNGValidErrorPtr err, dup; | 
 |  | 
 | #ifdef DEBUG_ERROR | 
 |     xmlGenericError(xmlGenericErrorContext, | 
 |                     "Dumping error stack %d errors\n", ctxt->errNr); | 
 | #endif | 
 |     for (i = 0, k = 0; i < ctxt->errNr; i++) { | 
 |         err = &ctxt->errTab[i]; | 
 |         if (k < MAX_ERROR) { | 
 |             for (j = 0; j < i; j++) { | 
 |                 dup = &ctxt->errTab[j]; | 
 |                 if ((err->err == dup->err) && (err->node == dup->node) && | 
 |                     (xmlStrEqual(err->arg1, dup->arg1)) && | 
 |                     (xmlStrEqual(err->arg2, dup->arg2))) { | 
 |                     goto skip; | 
 |                 } | 
 |             } | 
 |             xmlRelaxNGShowValidError(ctxt, err->err, err->node, err->seq, | 
 |                                      err->arg1, err->arg2); | 
 |             k++; | 
 |         } | 
 |       skip: | 
 |         if (err->flags & ERROR_IS_DUP) { | 
 |             if (err->arg1 != NULL) | 
 |                 xmlFree((xmlChar *) err->arg1); | 
 |             err->arg1 = NULL; | 
 |             if (err->arg2 != NULL) | 
 |                 xmlFree((xmlChar *) err->arg2); | 
 |             err->arg2 = NULL; | 
 |             err->flags = 0; | 
 |         } | 
 |     } | 
 |     ctxt->errNr = 0; | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGAddValidError: | 
 |  * @ctxt:  the validation context | 
 |  * @err:  the error number | 
 |  * @arg1:  the first argument | 
 |  * @arg2:  the second argument | 
 |  * @dup:  need to dup the args | 
 |  * | 
 |  * Register a validation error, either generating it if it's sure | 
 |  * or stacking it for later handling if unsure. | 
 |  */ | 
 | static void | 
 | xmlRelaxNGAddValidError(xmlRelaxNGValidCtxtPtr ctxt, | 
 |                         xmlRelaxNGValidErr err, const xmlChar * arg1, | 
 |                         const xmlChar * arg2, int dup) | 
 | { | 
 |     if (ctxt == NULL) | 
 |         return; | 
 |     if (ctxt->flags & FLAGS_NOERROR) | 
 |         return; | 
 |  | 
 | #ifdef DEBUG_ERROR | 
 |     xmlGenericError(xmlGenericErrorContext, "Adding error %d\n", err); | 
 | #endif | 
 |     /* | 
 |      * generate the error directly | 
 |      */ | 
 |     if (((ctxt->flags & FLAGS_IGNORABLE) == 0) || | 
 |     	 (ctxt->flags & FLAGS_NEGATIVE)) { | 
 |         xmlNodePtr node, seq; | 
 |  | 
 |         /* | 
 |          * Flush first any stacked error which might be the | 
 |          * real cause of the problem. | 
 |          */ | 
 |         if (ctxt->errNr != 0) | 
 |             xmlRelaxNGDumpValidError(ctxt); | 
 |         if (ctxt->state != NULL) { | 
 |             node = ctxt->state->node; | 
 |             seq = ctxt->state->seq; | 
 |         } else { | 
 |             node = seq = NULL; | 
 |         } | 
 |         if ((node == NULL) && (seq == NULL)) { | 
 |             node = ctxt->pnode; | 
 |         } | 
 |         xmlRelaxNGShowValidError(ctxt, err, node, seq, arg1, arg2); | 
 |     } | 
 |     /* | 
 |      * Stack the error for later processing if needed | 
 |      */ | 
 |     else { | 
 |         xmlRelaxNGValidErrorPush(ctxt, err, arg1, arg2, dup); | 
 |     } | 
 | } | 
 |  | 
 |  | 
 | /************************************************************************ | 
 |  * 									* | 
 |  * 			Type library hooks				* | 
 |  * 									* | 
 |  ************************************************************************/ | 
 | static xmlChar *xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt, | 
 |                                     const xmlChar * str); | 
 |  | 
 | /** | 
 |  * xmlRelaxNGSchemaTypeHave: | 
 |  * @data:  data needed for the library | 
 |  * @type:  the type name | 
 |  * | 
 |  * Check if the given type is provided by | 
 |  * the W3C XMLSchema Datatype library. | 
 |  * | 
 |  * Returns 1 if yes, 0 if no and -1 in case of error. | 
 |  */ | 
 | static int | 
 | xmlRelaxNGSchemaTypeHave(void *data ATTRIBUTE_UNUSED, const xmlChar * type) | 
 | { | 
 |     xmlSchemaTypePtr typ; | 
 |  | 
 |     if (type == NULL) | 
 |         return (-1); | 
 |     typ = xmlSchemaGetPredefinedType(type, | 
 |                                      BAD_CAST | 
 |                                      "http://www.w3.org/2001/XMLSchema"); | 
 |     if (typ == NULL) | 
 |         return (0); | 
 |     return (1); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGSchemaTypeCheck: | 
 |  * @data:  data needed for the library | 
 |  * @type:  the type name | 
 |  * @value:  the value to check | 
 |  * @node:  the node | 
 |  * | 
 |  * Check if the given type and value are validated by | 
 |  * the W3C XMLSchema Datatype library. | 
 |  * | 
 |  * Returns 1 if yes, 0 if no and -1 in case of error. | 
 |  */ | 
 | static int | 
 | xmlRelaxNGSchemaTypeCheck(void *data ATTRIBUTE_UNUSED, | 
 |                           const xmlChar * type, | 
 |                           const xmlChar * value, | 
 |                           void **result, xmlNodePtr node) | 
 | { | 
 |     xmlSchemaTypePtr typ; | 
 |     int ret; | 
 |  | 
 |     if ((type == NULL) || (value == NULL)) | 
 |         return (-1); | 
 |     typ = xmlSchemaGetPredefinedType(type, | 
 |                                      BAD_CAST | 
 |                                      "http://www.w3.org/2001/XMLSchema"); | 
 |     if (typ == NULL) | 
 |         return (-1); | 
 |     ret = xmlSchemaValPredefTypeNode(typ, value, | 
 |                                      (xmlSchemaValPtr *) result, node); | 
 |     if (ret == 2)               /* special ID error code */ | 
 |         return (2); | 
 |     if (ret == 0) | 
 |         return (1); | 
 |     if (ret > 0) | 
 |         return (0); | 
 |     return (-1); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGSchemaFacetCheck: | 
 |  * @data:  data needed for the library | 
 |  * @type:  the type name | 
 |  * @facet:  the facet name | 
 |  * @val:  the facet value | 
 |  * @strval:  the string value | 
 |  * @value:  the value to check | 
 |  * | 
 |  * Function provided by a type library to check a value facet | 
 |  * | 
 |  * Returns 1 if yes, 0 if no and -1 in case of error. | 
 |  */ | 
 | static int | 
 | xmlRelaxNGSchemaFacetCheck(void *data ATTRIBUTE_UNUSED, | 
 |                            const xmlChar * type, const xmlChar * facetname, | 
 |                            const xmlChar * val, const xmlChar * strval, | 
 |                            void *value) | 
 | { | 
 |     xmlSchemaFacetPtr facet; | 
 |     xmlSchemaTypePtr typ; | 
 |     int ret; | 
 |  | 
 |     if ((type == NULL) || (strval == NULL)) | 
 |         return (-1); | 
 |     typ = xmlSchemaGetPredefinedType(type, | 
 |                                      BAD_CAST | 
 |                                      "http://www.w3.org/2001/XMLSchema"); | 
 |     if (typ == NULL) | 
 |         return (-1); | 
 |  | 
 |     facet = xmlSchemaNewFacet(); | 
 |     if (facet == NULL) | 
 |         return (-1); | 
 |  | 
 |     if (xmlStrEqual(facetname, BAD_CAST "minInclusive")) { | 
 |         facet->type = XML_SCHEMA_FACET_MININCLUSIVE; | 
 |     } else if (xmlStrEqual(facetname, BAD_CAST "minExclusive")) { | 
 |         facet->type = XML_SCHEMA_FACET_MINEXCLUSIVE; | 
 |     } else if (xmlStrEqual(facetname, BAD_CAST "maxInclusive")) { | 
 |         facet->type = XML_SCHEMA_FACET_MAXINCLUSIVE; | 
 |     } else if (xmlStrEqual(facetname, BAD_CAST "maxExclusive")) { | 
 |         facet->type = XML_SCHEMA_FACET_MAXEXCLUSIVE; | 
 |     } else if (xmlStrEqual(facetname, BAD_CAST "totalDigits")) { | 
 |         facet->type = XML_SCHEMA_FACET_TOTALDIGITS; | 
 |     } else if (xmlStrEqual(facetname, BAD_CAST "fractionDigits")) { | 
 |         facet->type = XML_SCHEMA_FACET_FRACTIONDIGITS; | 
 |     } else if (xmlStrEqual(facetname, BAD_CAST "pattern")) { | 
 |         facet->type = XML_SCHEMA_FACET_PATTERN; | 
 |     } else if (xmlStrEqual(facetname, BAD_CAST "enumeration")) { | 
 |         facet->type = XML_SCHEMA_FACET_ENUMERATION; | 
 |     } else if (xmlStrEqual(facetname, BAD_CAST "whiteSpace")) { | 
 |         facet->type = XML_SCHEMA_FACET_WHITESPACE; | 
 |     } else if (xmlStrEqual(facetname, BAD_CAST "length")) { | 
 |         facet->type = XML_SCHEMA_FACET_LENGTH; | 
 |     } else if (xmlStrEqual(facetname, BAD_CAST "maxLength")) { | 
 |         facet->type = XML_SCHEMA_FACET_MAXLENGTH; | 
 |     } else if (xmlStrEqual(facetname, BAD_CAST "minLength")) { | 
 |         facet->type = XML_SCHEMA_FACET_MINLENGTH; | 
 |     } else { | 
 |         xmlSchemaFreeFacet(facet); | 
 |         return (-1); | 
 |     } | 
 |     facet->value = val; | 
 |     ret = xmlSchemaCheckFacet(facet, typ, NULL, type); | 
 |     if (ret != 0) { | 
 |         xmlSchemaFreeFacet(facet); | 
 |         return (-1); | 
 |     } | 
 |     ret = xmlSchemaValidateFacet(typ, facet, strval, value); | 
 |     xmlSchemaFreeFacet(facet); | 
 |     if (ret != 0) | 
 |         return (-1); | 
 |     return (0); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGSchemaFreeValue: | 
 |  * @data:  data needed for the library | 
 |  * @value:  the value to free | 
 |  * | 
 |  * Function provided by a type library to free a Schemas value | 
 |  * | 
 |  * Returns 1 if yes, 0 if no and -1 in case of error. | 
 |  */ | 
 | static void | 
 | xmlRelaxNGSchemaFreeValue(void *data ATTRIBUTE_UNUSED, void *value) | 
 | { | 
 |     xmlSchemaFreeValue(value); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGSchemaTypeCompare: | 
 |  * @data:  data needed for the library | 
 |  * @type:  the type name | 
 |  * @value1:  the first value | 
 |  * @value2:  the second value | 
 |  * | 
 |  * Compare two values for equality accordingly a type from the W3C XMLSchema | 
 |  * Datatype library. | 
 |  * | 
 |  * Returns 1 if equal, 0 if no and -1 in case of error. | 
 |  */ | 
 | static int | 
 | xmlRelaxNGSchemaTypeCompare(void *data ATTRIBUTE_UNUSED, | 
 |                             const xmlChar * type, | 
 |                             const xmlChar * value1, | 
 |                             xmlNodePtr ctxt1, | 
 |                             void *comp1, | 
 |                             const xmlChar * value2, xmlNodePtr ctxt2) | 
 | { | 
 |     int ret; | 
 |     xmlSchemaTypePtr typ; | 
 |     xmlSchemaValPtr res1 = NULL, res2 = NULL; | 
 |  | 
 |     if ((type == NULL) || (value1 == NULL) || (value2 == NULL)) | 
 |         return (-1); | 
 |     typ = xmlSchemaGetPredefinedType(type, | 
 |                                      BAD_CAST | 
 |                                      "http://www.w3.org/2001/XMLSchema"); | 
 |     if (typ == NULL) | 
 |         return (-1); | 
 |     if (comp1 == NULL) { | 
 |         ret = xmlSchemaValPredefTypeNode(typ, value1, &res1, ctxt1); | 
 |         if (ret != 0) | 
 |             return (-1); | 
 |         if (res1 == NULL) | 
 |             return (-1); | 
 |     } else { | 
 |         res1 = (xmlSchemaValPtr) comp1; | 
 |     } | 
 |     ret = xmlSchemaValPredefTypeNode(typ, value2, &res2, ctxt2); | 
 |     if (ret != 0) { | 
 | 	if ((comp1 == NULL) && (res1 != NULL)) | 
 | 	    xmlSchemaFreeValue(res1); | 
 |         return (-1); | 
 |     } | 
 |     if (res1 == NULL) { | 
 |         return (-1); | 
 |     } | 
 |     ret = xmlSchemaCompareValues(res1, res2); | 
 |     if (res1 != (xmlSchemaValPtr) comp1) | 
 |         xmlSchemaFreeValue(res1); | 
 |     xmlSchemaFreeValue(res2); | 
 |     if (ret == -2) | 
 |         return (-1); | 
 |     if (ret == 0) | 
 |         return (1); | 
 |     return (0); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGDefaultTypeHave: | 
 |  * @data:  data needed for the library | 
 |  * @type:  the type name | 
 |  * | 
 |  * Check if the given type is provided by | 
 |  * the default datatype library. | 
 |  * | 
 |  * Returns 1 if yes, 0 if no and -1 in case of error. | 
 |  */ | 
 | static int | 
 | xmlRelaxNGDefaultTypeHave(void *data ATTRIBUTE_UNUSED, | 
 |                           const xmlChar * type) | 
 | { | 
 |     if (type == NULL) | 
 |         return (-1); | 
 |     if (xmlStrEqual(type, BAD_CAST "string")) | 
 |         return (1); | 
 |     if (xmlStrEqual(type, BAD_CAST "token")) | 
 |         return (1); | 
 |     return (0); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGDefaultTypeCheck: | 
 |  * @data:  data needed for the library | 
 |  * @type:  the type name | 
 |  * @value:  the value to check | 
 |  * @node:  the node | 
 |  * | 
 |  * Check if the given type and value are validated by | 
 |  * the default datatype library. | 
 |  * | 
 |  * Returns 1 if yes, 0 if no and -1 in case of error. | 
 |  */ | 
 | static int | 
 | xmlRelaxNGDefaultTypeCheck(void *data ATTRIBUTE_UNUSED, | 
 |                            const xmlChar * type ATTRIBUTE_UNUSED, | 
 |                            const xmlChar * value ATTRIBUTE_UNUSED, | 
 |                            void **result ATTRIBUTE_UNUSED, | 
 |                            xmlNodePtr node ATTRIBUTE_UNUSED) | 
 | { | 
 |     if (value == NULL) | 
 |         return (-1); | 
 |     if (xmlStrEqual(type, BAD_CAST "string")) | 
 |         return (1); | 
 |     if (xmlStrEqual(type, BAD_CAST "token")) { | 
 |         return (1); | 
 |     } | 
 |  | 
 |     return (0); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGDefaultTypeCompare: | 
 |  * @data:  data needed for the library | 
 |  * @type:  the type name | 
 |  * @value1:  the first value | 
 |  * @value2:  the second value | 
 |  * | 
 |  * Compare two values accordingly a type from the default | 
 |  * datatype library. | 
 |  * | 
 |  * Returns 1 if yes, 0 if no and -1 in case of error. | 
 |  */ | 
 | static int | 
 | xmlRelaxNGDefaultTypeCompare(void *data ATTRIBUTE_UNUSED, | 
 |                              const xmlChar * type, | 
 |                              const xmlChar * value1, | 
 |                              xmlNodePtr ctxt1 ATTRIBUTE_UNUSED, | 
 |                              void *comp1 ATTRIBUTE_UNUSED, | 
 |                              const xmlChar * value2, | 
 |                              xmlNodePtr ctxt2 ATTRIBUTE_UNUSED) | 
 | { | 
 |     int ret = -1; | 
 |  | 
 |     if (xmlStrEqual(type, BAD_CAST "string")) { | 
 |         ret = xmlStrEqual(value1, value2); | 
 |     } else if (xmlStrEqual(type, BAD_CAST "token")) { | 
 |         if (!xmlStrEqual(value1, value2)) { | 
 |             xmlChar *nval, *nvalue; | 
 |  | 
 |             /* | 
 |              * TODO: trivial optimizations are possible by | 
 |              * computing at compile-time | 
 |              */ | 
 |             nval = xmlRelaxNGNormalize(NULL, value1); | 
 |             nvalue = xmlRelaxNGNormalize(NULL, value2); | 
 |  | 
 |             if ((nval == NULL) || (nvalue == NULL)) | 
 |                 ret = -1; | 
 |             else if (xmlStrEqual(nval, nvalue)) | 
 |                 ret = 1; | 
 |             else | 
 |                 ret = 0; | 
 |             if (nval != NULL) | 
 |                 xmlFree(nval); | 
 |             if (nvalue != NULL) | 
 |                 xmlFree(nvalue); | 
 |         } else | 
 |             ret = 1; | 
 |     } | 
 |     return (ret); | 
 | } | 
 |  | 
 | static int xmlRelaxNGTypeInitialized = 0; | 
 | static xmlHashTablePtr xmlRelaxNGRegisteredTypes = NULL; | 
 |  | 
 | /** | 
 |  * xmlRelaxNGFreeTypeLibrary: | 
 |  * @lib:  the type library structure | 
 |  * @namespace:  the URI bound to the library | 
 |  * | 
 |  * Free the structure associated to the type library | 
 |  */ | 
 | static void | 
 | xmlRelaxNGFreeTypeLibrary(xmlRelaxNGTypeLibraryPtr lib, | 
 |                           const xmlChar * namespace ATTRIBUTE_UNUSED) | 
 | { | 
 |     if (lib == NULL) | 
 |         return; | 
 |     if (lib->namespace != NULL) | 
 |         xmlFree((xmlChar *) lib->namespace); | 
 |     xmlFree(lib); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGRegisterTypeLibrary: | 
 |  * @namespace:  the URI bound to the library | 
 |  * @data:  data associated to the library | 
 |  * @have:  the provide function | 
 |  * @check:  the checking function | 
 |  * @comp:  the comparison function | 
 |  * | 
 |  * Register a new type library | 
 |  * | 
 |  * Returns 0 in case of success and -1 in case of error. | 
 |  */ | 
 | static int | 
 | xmlRelaxNGRegisterTypeLibrary(const xmlChar * namespace, void *data, | 
 |                               xmlRelaxNGTypeHave have, | 
 |                               xmlRelaxNGTypeCheck check, | 
 |                               xmlRelaxNGTypeCompare comp, | 
 |                               xmlRelaxNGFacetCheck facet, | 
 |                               xmlRelaxNGTypeFree freef) | 
 | { | 
 |     xmlRelaxNGTypeLibraryPtr lib; | 
 |     int ret; | 
 |  | 
 |     if ((xmlRelaxNGRegisteredTypes == NULL) || (namespace == NULL) || | 
 |         (check == NULL) || (comp == NULL)) | 
 |         return (-1); | 
 |     if (xmlHashLookup(xmlRelaxNGRegisteredTypes, namespace) != NULL) { | 
 |         xmlGenericError(xmlGenericErrorContext, | 
 |                         "Relax-NG types library '%s' already registered\n", | 
 |                         namespace); | 
 |         return (-1); | 
 |     } | 
 |     lib = | 
 |         (xmlRelaxNGTypeLibraryPtr) | 
 |         xmlMalloc(sizeof(xmlRelaxNGTypeLibrary)); | 
 |     if (lib == NULL) { | 
 |         xmlRngVErrMemory(NULL, "adding types library\n"); | 
 |         return (-1); | 
 |     } | 
 |     memset(lib, 0, sizeof(xmlRelaxNGTypeLibrary)); | 
 |     lib->namespace = xmlStrdup(namespace); | 
 |     lib->data = data; | 
 |     lib->have = have; | 
 |     lib->comp = comp; | 
 |     lib->check = check; | 
 |     lib->facet = facet; | 
 |     lib->freef = freef; | 
 |     ret = xmlHashAddEntry(xmlRelaxNGRegisteredTypes, namespace, lib); | 
 |     if (ret < 0) { | 
 |         xmlGenericError(xmlGenericErrorContext, | 
 |                         "Relax-NG types library failed to register '%s'\n", | 
 |                         namespace); | 
 |         xmlRelaxNGFreeTypeLibrary(lib, namespace); | 
 |         return (-1); | 
 |     } | 
 |     return (0); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGInitTypes: | 
 |  * | 
 |  * Initilize the default type libraries. | 
 |  * | 
 |  * Returns 0 in case of success and -1 in case of error. | 
 |  */ | 
 | int | 
 | xmlRelaxNGInitTypes(void) | 
 | { | 
 |     if (xmlRelaxNGTypeInitialized != 0) | 
 |         return (0); | 
 |     xmlRelaxNGRegisteredTypes = xmlHashCreate(10); | 
 |     if (xmlRelaxNGRegisteredTypes == NULL) { | 
 |         xmlGenericError(xmlGenericErrorContext, | 
 |                         "Failed to allocate sh table for Relax-NG types\n"); | 
 |         return (-1); | 
 |     } | 
 |     xmlRelaxNGRegisterTypeLibrary(BAD_CAST | 
 |                                   "http://www.w3.org/2001/XMLSchema-datatypes", | 
 |                                   NULL, xmlRelaxNGSchemaTypeHave, | 
 |                                   xmlRelaxNGSchemaTypeCheck, | 
 |                                   xmlRelaxNGSchemaTypeCompare, | 
 |                                   xmlRelaxNGSchemaFacetCheck, | 
 |                                   xmlRelaxNGSchemaFreeValue); | 
 |     xmlRelaxNGRegisterTypeLibrary(xmlRelaxNGNs, NULL, | 
 |                                   xmlRelaxNGDefaultTypeHave, | 
 |                                   xmlRelaxNGDefaultTypeCheck, | 
 |                                   xmlRelaxNGDefaultTypeCompare, NULL, | 
 |                                   NULL); | 
 |     xmlRelaxNGTypeInitialized = 1; | 
 |     return (0); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGCleanupTypes: | 
 |  * | 
 |  * Cleanup the default Schemas type library associated to RelaxNG | 
 |  */ | 
 | void | 
 | xmlRelaxNGCleanupTypes(void) | 
 | { | 
 |     xmlSchemaCleanupTypes(); | 
 |     if (xmlRelaxNGTypeInitialized == 0) | 
 |         return; | 
 |     xmlHashFree(xmlRelaxNGRegisteredTypes, (xmlHashDeallocator) | 
 |                 xmlRelaxNGFreeTypeLibrary); | 
 |     xmlRelaxNGTypeInitialized = 0; | 
 | } | 
 |  | 
 | /************************************************************************ | 
 |  * 									* | 
 |  * 		Compiling element content into regexp			* | 
 |  * 									* | 
 |  * Sometime the element content can be compiled into a pure regexp,	* | 
 |  * This allows a faster execution and streamability at that level	* | 
 |  * 									* | 
 |  ************************************************************************/ | 
 |  | 
 | /* from automata.c but not exported */ | 
 | void xmlAutomataSetFlags(xmlAutomataPtr am, int flags); | 
 |  | 
 |  | 
 | static int xmlRelaxNGTryCompile(xmlRelaxNGParserCtxtPtr ctxt, | 
 |                                 xmlRelaxNGDefinePtr def); | 
 |  | 
 | /** | 
 |  * xmlRelaxNGIsCompileable: | 
 |  * @define:  the definition to check | 
 |  * | 
 |  * Check if a definition is nullable. | 
 |  * | 
 |  * Returns 1 if yes, 0 if no and -1 in case of error | 
 |  */ | 
 | static int | 
 | xmlRelaxNGIsCompileable(xmlRelaxNGDefinePtr def) | 
 | { | 
 |     int ret = -1; | 
 |  | 
 |     if (def == NULL) { | 
 |         return (-1); | 
 |     } | 
 |     if ((def->type != XML_RELAXNG_ELEMENT) && | 
 |         (def->dflags & IS_COMPILABLE)) | 
 |         return (1); | 
 |     if ((def->type != XML_RELAXNG_ELEMENT) && | 
 |         (def->dflags & IS_NOT_COMPILABLE)) | 
 |         return (0); | 
 |     switch (def->type) { | 
 |         case XML_RELAXNG_NOOP: | 
 |             ret = xmlRelaxNGIsCompileable(def->content); | 
 |             break; | 
 |         case XML_RELAXNG_TEXT: | 
 |         case XML_RELAXNG_EMPTY: | 
 |             ret = 1; | 
 |             break; | 
 |         case XML_RELAXNG_ELEMENT: | 
 |             /* | 
 |              * Check if the element content is compileable | 
 |              */ | 
 |             if (((def->dflags & IS_NOT_COMPILABLE) == 0) && | 
 |                 ((def->dflags & IS_COMPILABLE) == 0)) { | 
 |                 xmlRelaxNGDefinePtr list; | 
 |  | 
 |                 list = def->content; | 
 |                 while (list != NULL) { | 
 |                     ret = xmlRelaxNGIsCompileable(list); | 
 |                     if (ret != 1) | 
 |                         break; | 
 |                     list = list->next; | 
 |                 } | 
 | 		/* | 
 | 		 * Because the routine is recursive, we must guard against | 
 | 		 * discovering both COMPILABLE and NOT_COMPILABLE | 
 | 		 */ | 
 |                 if (ret == 0) { | 
 | 		    def->dflags &= ~IS_COMPILABLE; | 
 |                     def->dflags |= IS_NOT_COMPILABLE; | 
 | 		} | 
 |                 if ((ret == 1) && !(def->dflags &= IS_NOT_COMPILABLE)) | 
 |                     def->dflags |= IS_COMPILABLE; | 
 | #ifdef DEBUG_COMPILE | 
 |                 if (ret == 1) { | 
 |                     xmlGenericError(xmlGenericErrorContext, | 
 |                                     "element content for %s is compilable\n", | 
 |                                     def->name); | 
 |                 } else if (ret == 0) { | 
 |                     xmlGenericError(xmlGenericErrorContext, | 
 |                                     "element content for %s is not compilable\n", | 
 |                                     def->name); | 
 |                 } else { | 
 |                     xmlGenericError(xmlGenericErrorContext, | 
 |                                     "Problem in RelaxNGIsCompileable for element %s\n", | 
 |                                     def->name); | 
 |                 } | 
 | #endif | 
 |             } | 
 |             /* | 
 |              * All elements return a compileable status unless they | 
 |              * are generic like anyName | 
 |              */ | 
 |             if ((def->nameClass != NULL) || (def->name == NULL)) | 
 |                 ret = 0; | 
 |             else | 
 |                 ret = 1; | 
 |             return (ret); | 
 |         case XML_RELAXNG_REF: | 
 |         case XML_RELAXNG_EXTERNALREF: | 
 |         case XML_RELAXNG_PARENTREF: | 
 |             if (def->depth == -20) { | 
 |                 return (1); | 
 |             } else { | 
 |                 xmlRelaxNGDefinePtr list; | 
 |  | 
 |                 def->depth = -20; | 
 |                 list = def->content; | 
 |                 while (list != NULL) { | 
 |                     ret = xmlRelaxNGIsCompileable(list); | 
 |                     if (ret != 1) | 
 |                         break; | 
 |                     list = list->next; | 
 |                 } | 
 |             } | 
 |             break; | 
 |         case XML_RELAXNG_START: | 
 |         case XML_RELAXNG_OPTIONAL: | 
 |         case XML_RELAXNG_ZEROORMORE: | 
 |         case XML_RELAXNG_ONEORMORE: | 
 |         case XML_RELAXNG_CHOICE: | 
 |         case XML_RELAXNG_GROUP: | 
 |         case XML_RELAXNG_DEF:{ | 
 |                 xmlRelaxNGDefinePtr list; | 
 |  | 
 |                 list = def->content; | 
 |                 while (list != NULL) { | 
 |                     ret = xmlRelaxNGIsCompileable(list); | 
 |                     if (ret != 1) | 
 |                         break; | 
 |                     list = list->next; | 
 |                 } | 
 |                 break; | 
 |             } | 
 |         case XML_RELAXNG_EXCEPT: | 
 |         case XML_RELAXNG_ATTRIBUTE: | 
 |         case XML_RELAXNG_INTERLEAVE: | 
 |         case XML_RELAXNG_DATATYPE: | 
 |         case XML_RELAXNG_LIST: | 
 |         case XML_RELAXNG_PARAM: | 
 |         case XML_RELAXNG_VALUE: | 
 |         case XML_RELAXNG_NOT_ALLOWED: | 
 |             ret = 0; | 
 |             break; | 
 |     } | 
 |     if (ret == 0) | 
 |         def->dflags |= IS_NOT_COMPILABLE; | 
 |     if (ret == 1) | 
 |         def->dflags |= IS_COMPILABLE; | 
 | #ifdef DEBUG_COMPILE | 
 |     if (ret == 1) { | 
 |         xmlGenericError(xmlGenericErrorContext, | 
 |                         "RelaxNGIsCompileable %s : true\n", | 
 |                         xmlRelaxNGDefName(def)); | 
 |     } else if (ret == 0) { | 
 |         xmlGenericError(xmlGenericErrorContext, | 
 |                         "RelaxNGIsCompileable %s : false\n", | 
 |                         xmlRelaxNGDefName(def)); | 
 |     } else { | 
 |         xmlGenericError(xmlGenericErrorContext, | 
 |                         "Problem in RelaxNGIsCompileable %s\n", | 
 |                         xmlRelaxNGDefName(def)); | 
 |     } | 
 | #endif | 
 |     return (ret); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGCompile: | 
 |  * ctxt:  the RelaxNG parser context | 
 |  * @define:  the definition tree to compile | 
 |  * | 
 |  * Compile the set of definitions, it works recursively, till the | 
 |  * element boundaries, where it tries to compile the content if possible | 
 |  * | 
 |  * Returns 0 if success and -1 in case of error | 
 |  */ | 
 | static int | 
 | xmlRelaxNGCompile(xmlRelaxNGParserCtxtPtr ctxt, xmlRelaxNGDefinePtr def) | 
 | { | 
 |     int ret = 0; | 
 |     xmlRelaxNGDefinePtr list; | 
 |  | 
 |     if ((ctxt == NULL) || (def == NULL)) | 
 |         return (-1); | 
 |  | 
 |     switch (def->type) { | 
 |         case XML_RELAXNG_START: | 
 |             if ((xmlRelaxNGIsCompileable(def) == 1) && (def->depth != -25)) { | 
 |                 xmlAutomataPtr oldam = ctxt->am; | 
 |                 xmlAutomataStatePtr oldstate = ctxt->state; | 
 |  | 
 |                 def->depth = -25; | 
 |  | 
 |                 list = def->content; | 
 |                 ctxt->am = xmlNewAutomata(); | 
 |                 if (ctxt->am == NULL) | 
 |                     return (-1); | 
 |  | 
 |                 /* | 
 |                  * assume identical strings but not same pointer are different | 
 |                  * atoms, needed for non-determinism detection | 
 |                  * That way if 2 elements with the same name are in a choice | 
 |                  * branch the automata is found non-deterministic and | 
 |                  * we fallback to the normal validation which does the right | 
 |                  * thing of exploring both choices. | 
 |                  */ | 
 |                 xmlAutomataSetFlags(ctxt->am, 1); | 
 |  | 
 |                 ctxt->state = xmlAutomataGetInitState(ctxt->am); | 
 |                 while (list != NULL) { | 
 |                     xmlRelaxNGCompile(ctxt, list); | 
 |                     list = list->next; | 
 |                 } | 
 |                 xmlAutomataSetFinalState(ctxt->am, ctxt->state); | 
 |                 def->contModel = xmlAutomataCompile(ctxt->am); | 
 |                 xmlRegexpIsDeterminist(def->contModel); | 
 |  | 
 |                 xmlFreeAutomata(ctxt->am); | 
 |                 ctxt->state = oldstate; | 
 |                 ctxt->am = oldam; | 
 |             } | 
 |             break; | 
 |         case XML_RELAXNG_ELEMENT: | 
 |             if ((ctxt->am != NULL) && (def->name != NULL)) { | 
 |                 ctxt->state = xmlAutomataNewTransition2(ctxt->am, | 
 |                                                         ctxt->state, NULL, | 
 |                                                         def->name, def->ns, | 
 |                                                         def); | 
 |             } | 
 |             if ((def->dflags & IS_COMPILABLE) && (def->depth != -25)) { | 
 |                 xmlAutomataPtr oldam = ctxt->am; | 
 |                 xmlAutomataStatePtr oldstate = ctxt->state; | 
 |  | 
 |                 def->depth = -25; | 
 |  | 
 |                 list = def->content; | 
 |                 ctxt->am = xmlNewAutomata(); | 
 |                 if (ctxt->am == NULL) | 
 |                     return (-1); | 
 |                 xmlAutomataSetFlags(ctxt->am, 1); | 
 |                 ctxt->state = xmlAutomataGetInitState(ctxt->am); | 
 |                 while (list != NULL) { | 
 |                     xmlRelaxNGCompile(ctxt, list); | 
 |                     list = list->next; | 
 |                 } | 
 |                 xmlAutomataSetFinalState(ctxt->am, ctxt->state); | 
 |                 def->contModel = xmlAutomataCompile(ctxt->am); | 
 |                 if (!xmlRegexpIsDeterminist(def->contModel)) { | 
 | #ifdef DEBUG_COMPILE | 
 |                     xmlGenericError(xmlGenericErrorContext, | 
 |                         "Content model not determinist %s\n", | 
 |                                     def->name); | 
 | #endif | 
 |                     /* | 
 |                      * we can only use the automata if it is determinist | 
 |                      */ | 
 |                     xmlRegFreeRegexp(def->contModel); | 
 |                     def->contModel = NULL; | 
 |                 } | 
 |                 xmlFreeAutomata(ctxt->am); | 
 |                 ctxt->state = oldstate; | 
 |                 ctxt->am = oldam; | 
 |             } else { | 
 |                 xmlAutomataPtr oldam = ctxt->am; | 
 |  | 
 |                 /* | 
 |                  * we can't build the content model for this element content | 
 |                  * but it still might be possible to build it for some of its | 
 |                  * children, recurse. | 
 |                  */ | 
 |                 ret = xmlRelaxNGTryCompile(ctxt, def); | 
 |                 ctxt->am = oldam; | 
 |             } | 
 |             break; | 
 |         case XML_RELAXNG_NOOP: | 
 |             ret = xmlRelaxNGCompile(ctxt, def->content); | 
 |             break; | 
 |         case XML_RELAXNG_OPTIONAL:{ | 
 |                 xmlAutomataStatePtr oldstate = ctxt->state; | 
 |  | 
 |                 list = def->content; | 
 |                 while (list != NULL) { | 
 |                     xmlRelaxNGCompile(ctxt, list); | 
 |                     list = list->next; | 
 |                 } | 
 |                 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state); | 
 |                 break; | 
 |             } | 
 |         case XML_RELAXNG_ZEROORMORE:{ | 
 |                 xmlAutomataStatePtr oldstate; | 
 |  | 
 |                 ctxt->state = | 
 |                     xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL); | 
 |                 oldstate = ctxt->state; | 
 |                 list = def->content; | 
 |                 while (list != NULL) { | 
 |                     xmlRelaxNGCompile(ctxt, list); | 
 |                     list = list->next; | 
 |                 } | 
 |                 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldstate); | 
 |                 ctxt->state = | 
 |                     xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL); | 
 |                 break; | 
 |             } | 
 |         case XML_RELAXNG_ONEORMORE:{ | 
 |                 xmlAutomataStatePtr oldstate; | 
 |  | 
 |                 list = def->content; | 
 |                 while (list != NULL) { | 
 |                     xmlRelaxNGCompile(ctxt, list); | 
 |                     list = list->next; | 
 |                 } | 
 |                 oldstate = ctxt->state; | 
 |                 list = def->content; | 
 |                 while (list != NULL) { | 
 |                     xmlRelaxNGCompile(ctxt, list); | 
 |                     list = list->next; | 
 |                 } | 
 |                 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldstate); | 
 |                 ctxt->state = | 
 |                     xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL); | 
 |                 break; | 
 |             } | 
 |         case XML_RELAXNG_CHOICE:{ | 
 |                 xmlAutomataStatePtr target = NULL; | 
 |                 xmlAutomataStatePtr oldstate = ctxt->state; | 
 |  | 
 |                 list = def->content; | 
 |                 while (list != NULL) { | 
 |                     ctxt->state = oldstate; | 
 |                     ret = xmlRelaxNGCompile(ctxt, list); | 
 |                     if (ret != 0) | 
 |                         break; | 
 |                     if (target == NULL) | 
 |                         target = ctxt->state; | 
 |                     else { | 
 |                         xmlAutomataNewEpsilon(ctxt->am, ctxt->state, | 
 |                                               target); | 
 |                     } | 
 |                     list = list->next; | 
 |                 } | 
 |                 ctxt->state = target; | 
 |  | 
 |                 break; | 
 |             } | 
 |         case XML_RELAXNG_REF: | 
 |         case XML_RELAXNG_EXTERNALREF: | 
 |         case XML_RELAXNG_PARENTREF: | 
 |         case XML_RELAXNG_GROUP: | 
 |         case XML_RELAXNG_DEF: | 
 |             list = def->content; | 
 |             while (list != NULL) { | 
 |                 ret = xmlRelaxNGCompile(ctxt, list); | 
 |                 if (ret != 0) | 
 |                     break; | 
 |                 list = list->next; | 
 |             } | 
 |             break; | 
 |         case XML_RELAXNG_TEXT:{ | 
 |                 xmlAutomataStatePtr oldstate; | 
 |  | 
 |                 ctxt->state = | 
 |                     xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL); | 
 |                 oldstate = ctxt->state; | 
 |                 xmlRelaxNGCompile(ctxt, def->content); | 
 |                 xmlAutomataNewTransition(ctxt->am, ctxt->state, | 
 |                                          ctxt->state, BAD_CAST "#text", | 
 |                                          NULL); | 
 |                 ctxt->state = | 
 |                     xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL); | 
 |                 break; | 
 |             } | 
 |         case XML_RELAXNG_EMPTY: | 
 |             ctxt->state = | 
 |                 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL); | 
 |             break; | 
 |         case XML_RELAXNG_EXCEPT: | 
 |         case XML_RELAXNG_ATTRIBUTE: | 
 |         case XML_RELAXNG_INTERLEAVE: | 
 |         case XML_RELAXNG_NOT_ALLOWED: | 
 |         case XML_RELAXNG_DATATYPE: | 
 |         case XML_RELAXNG_LIST: | 
 |         case XML_RELAXNG_PARAM: | 
 |         case XML_RELAXNG_VALUE: | 
 |             /* This should not happen and generate an internal error */ | 
 |             fprintf(stderr, "RNG internal error trying to compile %s\n", | 
 |                     xmlRelaxNGDefName(def)); | 
 |             break; | 
 |     } | 
 |     return (ret); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGTryCompile: | 
 |  * ctxt:  the RelaxNG parser context | 
 |  * @define:  the definition tree to compile | 
 |  * | 
 |  * Try to compile the set of definitions, it works recursively, | 
 |  * possibly ignoring parts which cannot be compiled. | 
 |  * | 
 |  * Returns 0 if success and -1 in case of error | 
 |  */ | 
 | static int | 
 | xmlRelaxNGTryCompile(xmlRelaxNGParserCtxtPtr ctxt, xmlRelaxNGDefinePtr def) | 
 | { | 
 |     int ret = 0; | 
 |     xmlRelaxNGDefinePtr list; | 
 |  | 
 |     if ((ctxt == NULL) || (def == NULL)) | 
 |         return (-1); | 
 |  | 
 |     if ((def->type == XML_RELAXNG_START) || | 
 |         (def->type == XML_RELAXNG_ELEMENT)) { | 
 |         ret = xmlRelaxNGIsCompileable(def); | 
 |         if ((def->dflags & IS_COMPILABLE) && (def->depth != -25)) { | 
 |             ctxt->am = NULL; | 
 |             ret = xmlRelaxNGCompile(ctxt, def); | 
 | #ifdef DEBUG_PROGRESSIVE | 
 |             if (ret == 0) { | 
 |                 if (def->type == XML_RELAXNG_START) | 
 |                     xmlGenericError(xmlGenericErrorContext, | 
 |                                     "compiled the start\n"); | 
 |                 else | 
 |                     xmlGenericError(xmlGenericErrorContext, | 
 |                                     "compiled element %s\n", def->name); | 
 |             } else { | 
 |                 if (def->type == XML_RELAXNG_START) | 
 |                     xmlGenericError(xmlGenericErrorContext, | 
 |                                     "failed to compile the start\n"); | 
 |                 else | 
 |                     xmlGenericError(xmlGenericErrorContext, | 
 |                                     "failed to compile element %s\n", | 
 |                                     def->name); | 
 |             } | 
 | #endif | 
 |             return (ret); | 
 |         } | 
 |     } | 
 |     switch (def->type) { | 
 |         case XML_RELAXNG_NOOP: | 
 |             ret = xmlRelaxNGTryCompile(ctxt, def->content); | 
 |             break; | 
 |         case XML_RELAXNG_TEXT: | 
 |         case XML_RELAXNG_DATATYPE: | 
 |         case XML_RELAXNG_LIST: | 
 |         case XML_RELAXNG_PARAM: | 
 |         case XML_RELAXNG_VALUE: | 
 |         case XML_RELAXNG_EMPTY: | 
 |         case XML_RELAXNG_ELEMENT: | 
 |             ret = 0; | 
 |             break; | 
 |         case XML_RELAXNG_OPTIONAL: | 
 |         case XML_RELAXNG_ZEROORMORE: | 
 |         case XML_RELAXNG_ONEORMORE: | 
 |         case XML_RELAXNG_CHOICE: | 
 |         case XML_RELAXNG_GROUP: | 
 |         case XML_RELAXNG_DEF: | 
 |         case XML_RELAXNG_START: | 
 |         case XML_RELAXNG_REF: | 
 |         case XML_RELAXNG_EXTERNALREF: | 
 |         case XML_RELAXNG_PARENTREF: | 
 |             list = def->content; | 
 |             while (list != NULL) { | 
 |                 ret = xmlRelaxNGTryCompile(ctxt, list); | 
 |                 if (ret != 0) | 
 |                     break; | 
 |                 list = list->next; | 
 |             } | 
 |             break; | 
 |         case XML_RELAXNG_EXCEPT: | 
 |         case XML_RELAXNG_ATTRIBUTE: | 
 |         case XML_RELAXNG_INTERLEAVE: | 
 |         case XML_RELAXNG_NOT_ALLOWED: | 
 |             ret = 0; | 
 |             break; | 
 |     } | 
 |     return (ret); | 
 | } | 
 |  | 
 | /************************************************************************ | 
 |  * 									* | 
 |  * 			Parsing functions				* | 
 |  * 									* | 
 |  ************************************************************************/ | 
 |  | 
 | static xmlRelaxNGDefinePtr xmlRelaxNGParseAttribute(xmlRelaxNGParserCtxtPtr | 
 |                                                     ctxt, xmlNodePtr node); | 
 | static xmlRelaxNGDefinePtr xmlRelaxNGParseElement(xmlRelaxNGParserCtxtPtr | 
 |                                                   ctxt, xmlNodePtr node); | 
 | static xmlRelaxNGDefinePtr xmlRelaxNGParsePatterns(xmlRelaxNGParserCtxtPtr | 
 |                                                    ctxt, xmlNodePtr nodes, | 
 |                                                    int group); | 
 | static xmlRelaxNGDefinePtr xmlRelaxNGParsePattern(xmlRelaxNGParserCtxtPtr | 
 |                                                   ctxt, xmlNodePtr node); | 
 | static xmlRelaxNGPtr xmlRelaxNGParseDocument(xmlRelaxNGParserCtxtPtr ctxt, | 
 |                                              xmlNodePtr node); | 
 | static int xmlRelaxNGParseGrammarContent(xmlRelaxNGParserCtxtPtr ctxt, | 
 |                                          xmlNodePtr nodes); | 
 | static xmlRelaxNGDefinePtr xmlRelaxNGParseNameClass(xmlRelaxNGParserCtxtPtr | 
 |                                                     ctxt, xmlNodePtr node, | 
 |                                                     xmlRelaxNGDefinePtr | 
 |                                                     def); | 
 | static xmlRelaxNGGrammarPtr xmlRelaxNGParseGrammar(xmlRelaxNGParserCtxtPtr | 
 |                                                    ctxt, xmlNodePtr nodes); | 
 | static int xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt, | 
 |                                   xmlRelaxNGDefinePtr define, | 
 |                                   xmlNodePtr elem); | 
 |  | 
 |  | 
 | #define IS_BLANK_NODE(n) (xmlRelaxNGIsBlank((n)->content)) | 
 |  | 
 | /** | 
 |  * xmlRelaxNGIsNullable: | 
 |  * @define:  the definition to verify | 
 |  * | 
 |  * Check if a definition is nullable. | 
 |  * | 
 |  * Returns 1 if yes, 0 if no and -1 in case of error | 
 |  */ | 
 | static int | 
 | xmlRelaxNGIsNullable(xmlRelaxNGDefinePtr define) | 
 | { | 
 |     int ret; | 
 |  | 
 |     if (define == NULL) | 
 |         return (-1); | 
 |  | 
 |     if (define->dflags & IS_NULLABLE) | 
 |         return (1); | 
 |     if (define->dflags & IS_NOT_NULLABLE) | 
 |         return (0); | 
 |     switch (define->type) { | 
 |         case XML_RELAXNG_EMPTY: | 
 |         case XML_RELAXNG_TEXT: | 
 |             ret = 1; | 
 |             break; | 
 |         case XML_RELAXNG_NOOP: | 
 |         case XML_RELAXNG_DEF: | 
 |         case XML_RELAXNG_REF: | 
 |         case XML_RELAXNG_EXTERNALREF: | 
 |         case XML_RELAXNG_PARENTREF: | 
 |         case XML_RELAXNG_ONEORMORE: | 
 |             ret = xmlRelaxNGIsNullable(define->content); | 
 |             break; | 
 |         case XML_RELAXNG_EXCEPT: | 
 |         case XML_RELAXNG_NOT_ALLOWED: | 
 |         case XML_RELAXNG_ELEMENT: | 
 |         case XML_RELAXNG_DATATYPE: | 
 |         case XML_RELAXNG_PARAM: | 
 |         case XML_RELAXNG_VALUE: | 
 |         case XML_RELAXNG_LIST: | 
 |         case XML_RELAXNG_ATTRIBUTE: | 
 |             ret = 0; | 
 |             break; | 
 |         case XML_RELAXNG_CHOICE:{ | 
 |                 xmlRelaxNGDefinePtr list = define->content; | 
 |  | 
 |                 while (list != NULL) { | 
 |                     ret = xmlRelaxNGIsNullable(list); | 
 |                     if (ret != 0) | 
 |                         goto done; | 
 |                     list = list->next; | 
 |                 } | 
 |                 ret = 0; | 
 |                 break; | 
 |             } | 
 |         case XML_RELAXNG_START: | 
 |         case XML_RELAXNG_INTERLEAVE: | 
 |         case XML_RELAXNG_GROUP:{ | 
 |                 xmlRelaxNGDefinePtr list = define->content; | 
 |  | 
 |                 while (list != NULL) { | 
 |                     ret = xmlRelaxNGIsNullable(list); | 
 |                     if (ret != 1) | 
 |                         goto done; | 
 |                     list = list->next; | 
 |                 } | 
 |                 return (1); | 
 |             } | 
 |         default: | 
 |             return (-1); | 
 |     } | 
 |   done: | 
 |     if (ret == 0) | 
 |         define->dflags |= IS_NOT_NULLABLE; | 
 |     if (ret == 1) | 
 |         define->dflags |= IS_NULLABLE; | 
 |     return (ret); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGIsBlank: | 
 |  * @str:  a string | 
 |  * | 
 |  * Check if a string is ignorable c.f. 4.2. Whitespace | 
 |  * | 
 |  * Returns 1 if the string is NULL or made of blanks chars, 0 otherwise | 
 |  */ | 
 | static int | 
 | xmlRelaxNGIsBlank(xmlChar * str) | 
 | { | 
 |     if (str == NULL) | 
 |         return (1); | 
 |     while (*str != 0) { | 
 |         if (!(IS_BLANK_CH(*str))) | 
 |             return (0); | 
 |         str++; | 
 |     } | 
 |     return (1); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGGetDataTypeLibrary: | 
 |  * @ctxt:  a Relax-NG parser context | 
 |  * @node:  the current data or value element | 
 |  * | 
 |  * Applies algorithm from 4.3. datatypeLibrary attribute | 
 |  * | 
 |  * Returns the datatypeLibary value or NULL if not found | 
 |  */ | 
 | static xmlChar * | 
 | xmlRelaxNGGetDataTypeLibrary(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED, | 
 |                              xmlNodePtr node) | 
 | { | 
 |     xmlChar *ret, *escape; | 
 |  | 
 |     if (node == NULL) | 
 |         return(NULL); | 
 |  | 
 |     if ((IS_RELAXNG(node, "data")) || (IS_RELAXNG(node, "value"))) { | 
 |         ret = xmlGetProp(node, BAD_CAST "datatypeLibrary"); | 
 |         if (ret != NULL) { | 
 |             if (ret[0] == 0) { | 
 |                 xmlFree(ret); | 
 |                 return (NULL); | 
 |             } | 
 |             escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?"); | 
 |             if (escape == NULL) { | 
 |                 return (ret); | 
 |             } | 
 |             xmlFree(ret); | 
 |             return (escape); | 
 |         } | 
 |     } | 
 |     node = node->parent; | 
 |     while ((node != NULL) && (node->type == XML_ELEMENT_NODE)) { | 
 |         ret = xmlGetProp(node, BAD_CAST "datatypeLibrary"); | 
 |         if (ret != NULL) { | 
 |             if (ret[0] == 0) { | 
 |                 xmlFree(ret); | 
 |                 return (NULL); | 
 |             } | 
 |             escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?"); | 
 |             if (escape == NULL) { | 
 |                 return (ret); | 
 |             } | 
 |             xmlFree(ret); | 
 |             return (escape); | 
 |         } | 
 |         node = node->parent; | 
 |     } | 
 |     return (NULL); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGParseValue: | 
 |  * @ctxt:  a Relax-NG parser context | 
 |  * @node:  the data node. | 
 |  * | 
 |  * parse the content of a RelaxNG value node. | 
 |  * | 
 |  * Returns the definition pointer or NULL in case of error | 
 |  */ | 
 | static xmlRelaxNGDefinePtr | 
 | xmlRelaxNGParseValue(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) | 
 | { | 
 |     xmlRelaxNGDefinePtr def = NULL; | 
 |     xmlRelaxNGTypeLibraryPtr lib = NULL; | 
 |     xmlChar *type; | 
 |     xmlChar *library; | 
 |     int success = 0; | 
 |  | 
 |     def = xmlRelaxNGNewDefine(ctxt, node); | 
 |     if (def == NULL) | 
 |         return (NULL); | 
 |     def->type = XML_RELAXNG_VALUE; | 
 |  | 
 |     type = xmlGetProp(node, BAD_CAST "type"); | 
 |     if (type != NULL) { | 
 |         xmlRelaxNGNormExtSpace(type); | 
 |         if (xmlValidateNCName(type, 0)) { | 
 |             xmlRngPErr(ctxt, node, XML_RNGP_TYPE_VALUE, | 
 |                        "value type '%s' is not an NCName\n", type, NULL); | 
 |         } | 
 |         library = xmlRelaxNGGetDataTypeLibrary(ctxt, node); | 
 |         if (library == NULL) | 
 |             library = | 
 |                 xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0"); | 
 |  | 
 |         def->name = type; | 
 |         def->ns = library; | 
 |  | 
 |         lib = (xmlRelaxNGTypeLibraryPtr) | 
 |             xmlHashLookup(xmlRelaxNGRegisteredTypes, library); | 
 |         if (lib == NULL) { | 
 |             xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_TYPE_LIB, | 
 |                        "Use of unregistered type library '%s'\n", library, | 
 |                        NULL); | 
 |             def->data = NULL; | 
 |         } else { | 
 |             def->data = lib; | 
 |             if (lib->have == NULL) { | 
 |                 xmlRngPErr(ctxt, node, XML_RNGP_ERROR_TYPE_LIB, | 
 |                            "Internal error with type library '%s': no 'have'\n", | 
 |                            library, NULL); | 
 |             } else { | 
 |                 success = lib->have(lib->data, def->name); | 
 |                 if (success != 1) { | 
 |                     xmlRngPErr(ctxt, node, XML_RNGP_TYPE_NOT_FOUND, | 
 |                                "Error type '%s' is not exported by type library '%s'\n", | 
 |                                def->name, library); | 
 |                 } | 
 |             } | 
 |         } | 
 |     } | 
 |     if (node->children == NULL) { | 
 |         def->value = xmlStrdup(BAD_CAST ""); | 
 |     } else if (((node->children->type != XML_TEXT_NODE) && | 
 |                 (node->children->type != XML_CDATA_SECTION_NODE)) || | 
 |                (node->children->next != NULL)) { | 
 |         xmlRngPErr(ctxt, node, XML_RNGP_TEXT_EXPECTED, | 
 |                    "Expecting a single text value for <value>content\n", | 
 |                    NULL, NULL); | 
 |     } else if (def != NULL) { | 
 |         def->value = xmlNodeGetContent(node); | 
 |         if (def->value == NULL) { | 
 |             xmlRngPErr(ctxt, node, XML_RNGP_VALUE_NO_CONTENT, | 
 |                        "Element <value> has no content\n", NULL, NULL); | 
 |         } else if ((lib != NULL) && (lib->check != NULL) && (success == 1)) { | 
 |             void *val = NULL; | 
 |  | 
 |             success = | 
 |                 lib->check(lib->data, def->name, def->value, &val, node); | 
 |             if (success != 1) { | 
 |                 xmlRngPErr(ctxt, node, XML_RNGP_INVALID_VALUE, | 
 |                            "Value '%s' is not acceptable for type '%s'\n", | 
 |                            def->value, def->name); | 
 |             } else { | 
 |                 if (val != NULL) | 
 |                     def->attrs = val; | 
 |             } | 
 |         } | 
 |     } | 
 |     return (def); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGParseData: | 
 |  * @ctxt:  a Relax-NG parser context | 
 |  * @node:  the data node. | 
 |  * | 
 |  * parse the content of a RelaxNG data node. | 
 |  * | 
 |  * Returns the definition pointer or NULL in case of error | 
 |  */ | 
 | static xmlRelaxNGDefinePtr | 
 | xmlRelaxNGParseData(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) | 
 | { | 
 |     xmlRelaxNGDefinePtr def = NULL, except; | 
 |     xmlRelaxNGDefinePtr param, lastparam = NULL; | 
 |     xmlRelaxNGTypeLibraryPtr lib; | 
 |     xmlChar *type; | 
 |     xmlChar *library; | 
 |     xmlNodePtr content; | 
 |     int tmp; | 
 |  | 
 |     type = xmlGetProp(node, BAD_CAST "type"); | 
 |     if (type == NULL) { | 
 |         xmlRngPErr(ctxt, node, XML_RNGP_TYPE_MISSING, "data has no type\n", NULL, | 
 |                    NULL); | 
 |         return (NULL); | 
 |     } | 
 |     xmlRelaxNGNormExtSpace(type); | 
 |     if (xmlValidateNCName(type, 0)) { | 
 |         xmlRngPErr(ctxt, node, XML_RNGP_TYPE_VALUE, | 
 |                    "data type '%s' is not an NCName\n", type, NULL); | 
 |     } | 
 |     library = xmlRelaxNGGetDataTypeLibrary(ctxt, node); | 
 |     if (library == NULL) | 
 |         library = | 
 |             xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0"); | 
 |  | 
 |     def = xmlRelaxNGNewDefine(ctxt, node); | 
 |     if (def == NULL) { | 
 |         xmlFree(type); | 
 |         return (NULL); | 
 |     } | 
 |     def->type = XML_RELAXNG_DATATYPE; | 
 |     def->name = type; | 
 |     def->ns = library; | 
 |  | 
 |     lib = (xmlRelaxNGTypeLibraryPtr) | 
 |         xmlHashLookup(xmlRelaxNGRegisteredTypes, library); | 
 |     if (lib == NULL) { | 
 |         xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_TYPE_LIB, | 
 |                    "Use of unregistered type library '%s'\n", library, | 
 |                    NULL); | 
 |         def->data = NULL; | 
 |     } else { | 
 |         def->data = lib; | 
 |         if (lib->have == NULL) { | 
 |             xmlRngPErr(ctxt, node, XML_RNGP_ERROR_TYPE_LIB, | 
 |                        "Internal error with type library '%s': no 'have'\n", | 
 |                        library, NULL); | 
 |         } else { | 
 |             tmp = lib->have(lib->data, def->name); | 
 |             if (tmp != 1) { | 
 |                 xmlRngPErr(ctxt, node, XML_RNGP_TYPE_NOT_FOUND, | 
 |                            "Error type '%s' is not exported by type library '%s'\n", | 
 |                            def->name, library); | 
 |             } else | 
 |                 if ((xmlStrEqual | 
 |                      (library, | 
 |                       BAD_CAST | 
 |                       "http://www.w3.org/2001/XMLSchema-datatypes")) | 
 |                     && ((xmlStrEqual(def->name, BAD_CAST "IDREF")) | 
 |                         || (xmlStrEqual(def->name, BAD_CAST "IDREFS")))) { | 
 |                 ctxt->idref = 1; | 
 |             } | 
 |         } | 
 |     } | 
 |     content = node->children; | 
 |  | 
 |     /* | 
 |      * Handle optional params | 
 |      */ | 
 |     while (content != NULL) { | 
 |         if (!xmlStrEqual(content->name, BAD_CAST "param")) | 
 |             break; | 
 |         if (xmlStrEqual(library, | 
 |                         BAD_CAST "http://relaxng.org/ns/structure/1.0")) { | 
 |             xmlRngPErr(ctxt, node, XML_RNGP_PARAM_FORBIDDEN, | 
 |                        "Type library '%s' does not allow type parameters\n", | 
 |                        library, NULL); | 
 |             content = content->next; | 
 |             while ((content != NULL) && | 
 |                    (xmlStrEqual(content->name, BAD_CAST "param"))) | 
 |                 content = content->next; | 
 |         } else { | 
 |             param = xmlRelaxNGNewDefine(ctxt, node); | 
 |             if (param != NULL) { | 
 |                 param->type = XML_RELAXNG_PARAM; | 
 |                 param->name = xmlGetProp(content, BAD_CAST "name"); | 
 |                 if (param->name == NULL) { | 
 |                     xmlRngPErr(ctxt, node, XML_RNGP_PARAM_NAME_MISSING, | 
 |                                "param has no name\n", NULL, NULL); | 
 |                 } | 
 |                 param->value = xmlNodeGetContent(content); | 
 |                 if (lastparam == NULL) { | 
 |                     def->attrs = lastparam = param; | 
 |                 } else { | 
 |                     lastparam->next = param; | 
 |                     lastparam = param; | 
 |                 } | 
 |                 if (lib != NULL) { | 
 |                 } | 
 |             } | 
 |             content = content->next; | 
 |         } | 
 |     } | 
 |     /* | 
 |      * Handle optional except | 
 |      */ | 
 |     if ((content != NULL) | 
 |         && (xmlStrEqual(content->name, BAD_CAST "except"))) { | 
 |         xmlNodePtr child; | 
 |         xmlRelaxNGDefinePtr tmp2, last = NULL; | 
 |  | 
 |         except = xmlRelaxNGNewDefine(ctxt, node); | 
 |         if (except == NULL) { | 
 |             return (def); | 
 |         } | 
 |         except->type = XML_RELAXNG_EXCEPT; | 
 |         child = content->children; | 
 | 	def->content = except; | 
 |         if (child == NULL) { | 
 |             xmlRngPErr(ctxt, content, XML_RNGP_EXCEPT_NO_CONTENT, | 
 |                        "except has no content\n", NULL, NULL); | 
 |         } | 
 |         while (child != NULL) { | 
 |             tmp2 = xmlRelaxNGParsePattern(ctxt, child); | 
 |             if (tmp2 != NULL) { | 
 |                 if (last == NULL) { | 
 |                     except->content = last = tmp2; | 
 |                 } else { | 
 |                     last->next = tmp2; | 
 |                     last = tmp2; | 
 |                 } | 
 |             } | 
 |             child = child->next; | 
 |         } | 
 |         content = content->next; | 
 |     } | 
 |     /* | 
 |      * Check there is no unhandled data | 
 |      */ | 
 |     if (content != NULL) { | 
 |         xmlRngPErr(ctxt, content, XML_RNGP_DATA_CONTENT, | 
 |                    "Element data has unexpected content %s\n", | 
 |                    content->name, NULL); | 
 |     } | 
 |  | 
 |     return (def); | 
 | } | 
 |  | 
 | static const xmlChar *invalidName = BAD_CAST "\1"; | 
 |  | 
 | /** | 
 |  * xmlRelaxNGCompareNameClasses: | 
 |  * @defs1:  the first element/attribute defs | 
 |  * @defs2:  the second element/attribute defs | 
 |  * @name:  the restriction on the name | 
 |  * @ns:  the restriction on the namespace | 
 |  * | 
 |  * Compare the 2 lists of element definitions. The comparison is | 
 |  * that if both lists do not accept the same QNames, it returns 1 | 
 |  * If the 2 lists can accept the same QName the comparison returns 0 | 
 |  * | 
 |  * Returns 1 disttinct, 0 if equal | 
 |  */ | 
 | static int | 
 | xmlRelaxNGCompareNameClasses(xmlRelaxNGDefinePtr def1, | 
 |                              xmlRelaxNGDefinePtr def2) | 
 | { | 
 |     int ret = 1; | 
 |     xmlNode node; | 
 |     xmlNs ns; | 
 |     xmlRelaxNGValidCtxt ctxt; | 
 |  | 
 |     memset(&ctxt, 0, sizeof(xmlRelaxNGValidCtxt)); | 
 |  | 
 |     ctxt.flags = FLAGS_IGNORABLE | FLAGS_NOERROR; | 
 |  | 
 |     if ((def1->type == XML_RELAXNG_ELEMENT) || | 
 |         (def1->type == XML_RELAXNG_ATTRIBUTE)) { | 
 |         if (def2->type == XML_RELAXNG_TEXT) | 
 |             return (1); | 
 |         if (def1->name != NULL) { | 
 |             node.name = def1->name; | 
 |         } else { | 
 |             node.name = invalidName; | 
 |         } | 
 |         if (def1->ns != NULL) { | 
 |             if (def1->ns[0] == 0) { | 
 |                 node.ns = NULL; | 
 |             } else { | 
 | 	        node.ns = &ns; | 
 |                 ns.href = def1->ns; | 
 |             } | 
 |         } else { | 
 |             node.ns = NULL; | 
 |         } | 
 |         if (xmlRelaxNGElementMatch(&ctxt, def2, &node)) { | 
 |             if (def1->nameClass != NULL) { | 
 |                 ret = xmlRelaxNGCompareNameClasses(def1->nameClass, def2); | 
 |             } else { | 
 |                 ret = 0; | 
 |             } | 
 |         } else { | 
 |             ret = 1; | 
 |         } | 
 |     } else if (def1->type == XML_RELAXNG_TEXT) { | 
 |         if (def2->type == XML_RELAXNG_TEXT) | 
 |             return (0); | 
 |         return (1); | 
 |     } else if (def1->type == XML_RELAXNG_EXCEPT) { | 
 |         TODO ret = 0; | 
 |     } else { | 
 |         TODO ret = 0; | 
 |     } | 
 |     if (ret == 0) | 
 |         return (ret); | 
 |     if ((def2->type == XML_RELAXNG_ELEMENT) || | 
 |         (def2->type == XML_RELAXNG_ATTRIBUTE)) { | 
 |         if (def2->name != NULL) { | 
 |             node.name = def2->name; | 
 |         } else { | 
 |             node.name = invalidName; | 
 |         } | 
 |         node.ns = &ns; | 
 |         if (def2->ns != NULL) { | 
 |             if (def2->ns[0] == 0) { | 
 |                 node.ns = NULL; | 
 |             } else { | 
 |                 ns.href = def2->ns; | 
 |             } | 
 |         } else { | 
 |             ns.href = invalidName; | 
 |         } | 
 |         if (xmlRelaxNGElementMatch(&ctxt, def1, &node)) { | 
 |             if (def2->nameClass != NULL) { | 
 |                 ret = xmlRelaxNGCompareNameClasses(def2->nameClass, def1); | 
 |             } else { | 
 |                 ret = 0; | 
 |             } | 
 |         } else { | 
 |             ret = 1; | 
 |         } | 
 |     } else { | 
 |         TODO ret = 0; | 
 |     } | 
 |  | 
 |     return (ret); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGCompareElemDefLists: | 
 |  * @ctxt:  a Relax-NG parser context | 
 |  * @defs1:  the first list of element/attribute defs | 
 |  * @defs2:  the second list of element/attribute defs | 
 |  * | 
 |  * Compare the 2 lists of element or attribute definitions. The comparison | 
 |  * is that if both lists do not accept the same QNames, it returns 1 | 
 |  * If the 2 lists can accept the same QName the comparison returns 0 | 
 |  * | 
 |  * Returns 1 disttinct, 0 if equal | 
 |  */ | 
 | static int | 
 | xmlRelaxNGCompareElemDefLists(xmlRelaxNGParserCtxtPtr ctxt | 
 |                               ATTRIBUTE_UNUSED, xmlRelaxNGDefinePtr * def1, | 
 |                               xmlRelaxNGDefinePtr * def2) | 
 | { | 
 |     xmlRelaxNGDefinePtr *basedef2 = def2; | 
 |  | 
 |     if ((def1 == NULL) || (def2 == NULL)) | 
 |         return (1); | 
 |     if ((*def1 == NULL) || (*def2 == NULL)) | 
 |         return (1); | 
 |     while (*def1 != NULL) { | 
 |         while ((*def2) != NULL) { | 
 |             if (xmlRelaxNGCompareNameClasses(*def1, *def2) == 0) | 
 |                 return (0); | 
 |             def2++; | 
 |         } | 
 |         def2 = basedef2; | 
 |         def1++; | 
 |     } | 
 |     return (1); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGGenerateAttributes: | 
 |  * @ctxt:  a Relax-NG parser context | 
 |  * @def:  the definition definition | 
 |  * | 
 |  * Check if the definition can only generate attributes | 
 |  * | 
 |  * Returns 1 if yes, 0 if no and -1 in case of error. | 
 |  */ | 
 | static int | 
 | xmlRelaxNGGenerateAttributes(xmlRelaxNGParserCtxtPtr ctxt, | 
 |                              xmlRelaxNGDefinePtr def) | 
 | { | 
 |     xmlRelaxNGDefinePtr parent, cur, tmp; | 
 |  | 
 |     /* | 
 |      * Don't run that check in case of error. Infinite recursion | 
 |      * becomes possible. | 
 |      */ | 
 |     if (ctxt->nbErrors != 0) | 
 |         return (-1); | 
 |  | 
 |     parent = NULL; | 
 |     cur = def; | 
 |     while (cur != NULL) { | 
 |         if ((cur->type == XML_RELAXNG_ELEMENT) || | 
 |             (cur->type == XML_RELAXNG_TEXT) || | 
 |             (cur->type == XML_RELAXNG_DATATYPE) || | 
 |             (cur->type == XML_RELAXNG_PARAM) || | 
 |             (cur->type == XML_RELAXNG_LIST) || | 
 |             (cur->type == XML_RELAXNG_VALUE) || | 
 |             (cur->type == XML_RELAXNG_EMPTY)) | 
 |             return (0); | 
 |         if ((cur->type == XML_RELAXNG_CHOICE) || | 
 |             (cur->type == XML_RELAXNG_INTERLEAVE) || | 
 |             (cur->type == XML_RELAXNG_GROUP) || | 
 |             (cur->type == XML_RELAXNG_ONEORMORE) || | 
 |             (cur->type == XML_RELAXNG_ZEROORMORE) || | 
 |             (cur->type == XML_RELAXNG_OPTIONAL) || | 
 |             (cur->type == XML_RELAXNG_PARENTREF) || | 
 |             (cur->type == XML_RELAXNG_EXTERNALREF) || | 
 |             (cur->type == XML_RELAXNG_REF) || | 
 |             (cur->type == XML_RELAXNG_DEF)) { | 
 |             if (cur->content != NULL) { | 
 |                 parent = cur; | 
 |                 cur = cur->content; | 
 |                 tmp = cur; | 
 |                 while (tmp != NULL) { | 
 |                     tmp->parent = parent; | 
 |                     tmp = tmp->next; | 
 |                 } | 
 |                 continue; | 
 |             } | 
 |         } | 
 |         if (cur == def) | 
 |             break; | 
 |         if (cur->next != NULL) { | 
 |             cur = cur->next; | 
 |             continue; | 
 |         } | 
 |         do { | 
 |             cur = cur->parent; | 
 |             if (cur == NULL) | 
 |                 break; | 
 |             if (cur == def) | 
 |                 return (1); | 
 |             if (cur->next != NULL) { | 
 |                 cur = cur->next; | 
 |                 break; | 
 |             } | 
 |         } while (cur != NULL); | 
 |     } | 
 |     return (1); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGGetElements: | 
 |  * @ctxt:  a Relax-NG parser context | 
 |  * @def:  the definition definition | 
 |  * @eora:  gather elements (0) or attributes (1) | 
 |  * | 
 |  * Compute the list of top elements a definition can generate | 
 |  * | 
 |  * Returns a list of elements or NULL if none was found. | 
 |  */ | 
 | static xmlRelaxNGDefinePtr * | 
 | xmlRelaxNGGetElements(xmlRelaxNGParserCtxtPtr ctxt, | 
 |                       xmlRelaxNGDefinePtr def, int eora) | 
 | { | 
 |     xmlRelaxNGDefinePtr *ret = NULL, parent, cur, tmp; | 
 |     int len = 0; | 
 |     int max = 0; | 
 |  | 
 |     /* | 
 |      * Don't run that check in case of error. Infinite recursion | 
 |      * becomes possible. | 
 |      */ | 
 |     if (ctxt->nbErrors != 0) | 
 |         return (NULL); | 
 |  | 
 |     parent = NULL; | 
 |     cur = def; | 
 |     while (cur != NULL) { | 
 |         if (((eora == 0) && ((cur->type == XML_RELAXNG_ELEMENT) || | 
 |                              (cur->type == XML_RELAXNG_TEXT))) || | 
 |             ((eora == 1) && (cur->type == XML_RELAXNG_ATTRIBUTE))) { | 
 |             if (ret == NULL) { | 
 |                 max = 10; | 
 |                 ret = (xmlRelaxNGDefinePtr *) | 
 |                     xmlMalloc((max + 1) * sizeof(xmlRelaxNGDefinePtr)); | 
 |                 if (ret == NULL) { | 
 |                     xmlRngPErrMemory(ctxt, "getting element list\n"); | 
 |                     return (NULL); | 
 |                 } | 
 |             } else if (max <= len) { | 
 | 	        xmlRelaxNGDefinePtr *temp; | 
 |  | 
 |                 max *= 2; | 
 |                 temp = xmlRealloc(ret, | 
 |                                (max + 1) * sizeof(xmlRelaxNGDefinePtr)); | 
 |                 if (temp == NULL) { | 
 |                     xmlRngPErrMemory(ctxt, "getting element list\n"); | 
 | 		    xmlFree(ret); | 
 |                     return (NULL); | 
 |                 } | 
 | 		ret = temp; | 
 |             } | 
 |             ret[len++] = cur; | 
 |             ret[len] = NULL; | 
 |         } else if ((cur->type == XML_RELAXNG_CHOICE) || | 
 |                    (cur->type == XML_RELAXNG_INTERLEAVE) || | 
 |                    (cur->type == XML_RELAXNG_GROUP) || | 
 |                    (cur->type == XML_RELAXNG_ONEORMORE) || | 
 |                    (cur->type == XML_RELAXNG_ZEROORMORE) || | 
 |                    (cur->type == XML_RELAXNG_OPTIONAL) || | 
 |                    (cur->type == XML_RELAXNG_PARENTREF) || | 
 |                    (cur->type == XML_RELAXNG_REF) || | 
 |                    (cur->type == XML_RELAXNG_DEF) || | 
 | 		   (cur->type == XML_RELAXNG_EXTERNALREF)) { | 
 |             /* | 
 |              * Don't go within elements or attributes or string values. | 
 |              * Just gather the element top list | 
 |              */ | 
 |             if (cur->content != NULL) { | 
 |                 parent = cur; | 
 |                 cur = cur->content; | 
 |                 tmp = cur; | 
 |                 while (tmp != NULL) { | 
 |                     tmp->parent = parent; | 
 |                     tmp = tmp->next; | 
 |                 } | 
 |                 continue; | 
 |             } | 
 |         } | 
 |         if (cur == def) | 
 |             break; | 
 |         if (cur->next != NULL) { | 
 |             cur = cur->next; | 
 |             continue; | 
 |         } | 
 |         do { | 
 |             cur = cur->parent; | 
 |             if (cur == NULL) | 
 |                 break; | 
 |             if (cur == def) | 
 |                 return (ret); | 
 |             if (cur->next != NULL) { | 
 |                 cur = cur->next; | 
 |                 break; | 
 |             } | 
 |         } while (cur != NULL); | 
 |     } | 
 |     return (ret); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGCheckChoiceDeterminism: | 
 |  * @ctxt:  a Relax-NG parser context | 
 |  * @def:  the choice definition | 
 |  * | 
 |  * Also used to find indeterministic pattern in choice | 
 |  */ | 
 | static void | 
 | xmlRelaxNGCheckChoiceDeterminism(xmlRelaxNGParserCtxtPtr ctxt, | 
 |                                  xmlRelaxNGDefinePtr def) | 
 | { | 
 |     xmlRelaxNGDefinePtr **list; | 
 |     xmlRelaxNGDefinePtr cur; | 
 |     int nbchild = 0, i, j, ret; | 
 |     int is_nullable = 0; | 
 |     int is_indeterminist = 0; | 
 |     xmlHashTablePtr triage = NULL; | 
 |     int is_triable = 1; | 
 |  | 
 |     if ((def == NULL) || (def->type != XML_RELAXNG_CHOICE)) | 
 |         return; | 
 |  | 
 |     if (def->dflags & IS_PROCESSED) | 
 |         return; | 
 |  | 
 |     /* | 
 |      * Don't run that check in case of error. Infinite recursion | 
 |      * becomes possible. | 
 |      */ | 
 |     if (ctxt->nbErrors != 0) | 
 |         return; | 
 |  | 
 |     is_nullable = xmlRelaxNGIsNullable(def); | 
 |  | 
 |     cur = def->content; | 
 |     while (cur != NULL) { | 
 |         nbchild++; | 
 |         cur = cur->next; | 
 |     } | 
 |  | 
 |     list = (xmlRelaxNGDefinePtr **) xmlMalloc(nbchild * | 
 |                                               sizeof(xmlRelaxNGDefinePtr | 
 |                                                      *)); | 
 |     if (list == NULL) { | 
 |         xmlRngPErrMemory(ctxt, "building choice\n"); | 
 |         return; | 
 |     } | 
 |     i = 0; | 
 |     /* | 
 |      * a bit strong but safe | 
 |      */ | 
 |     if (is_nullable == 0) { | 
 |         triage = xmlHashCreate(10); | 
 |     } else { | 
 |         is_triable = 0; | 
 |     } | 
 |     cur = def->content; | 
 |     while (cur != NULL) { | 
 |         list[i] = xmlRelaxNGGetElements(ctxt, cur, 0); | 
 |         if ((list[i] == NULL) || (list[i][0] == NULL)) { | 
 |             is_triable = 0; | 
 |         } else if (is_triable == 1) { | 
 |             xmlRelaxNGDefinePtr *tmp; | 
 |             int res; | 
 |  | 
 |             tmp = list[i]; | 
 |             while ((*tmp != NULL) && (is_triable == 1)) { | 
 |                 if ((*tmp)->type == XML_RELAXNG_TEXT) { | 
 |                     res = xmlHashAddEntry2(triage, | 
 |                                            BAD_CAST "#text", NULL, | 
 |                                            (void *) cur); | 
 |                     if (res != 0) | 
 |                         is_triable = -1; | 
 |                 } else if (((*tmp)->type == XML_RELAXNG_ELEMENT) && | 
 |                            ((*tmp)->name != NULL)) { | 
 |                     if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0)) | 
 |                         res = xmlHashAddEntry2(triage, | 
 |                                                (*tmp)->name, NULL, | 
 |                                                (void *) cur); | 
 |                     else | 
 |                         res = xmlHashAddEntry2(triage, | 
 |                                                (*tmp)->name, (*tmp)->ns, | 
 |                                                (void *) cur); | 
 |                     if (res != 0) | 
 |                         is_triable = -1; | 
 |                 } else if ((*tmp)->type == XML_RELAXNG_ELEMENT) { | 
 |                     if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0)) | 
 |                         res = xmlHashAddEntry2(triage, | 
 |                                                BAD_CAST "#any", NULL, | 
 |                                                (void *) cur); | 
 |                     else | 
 |                         res = xmlHashAddEntry2(triage, | 
 |                                                BAD_CAST "#any", (*tmp)->ns, | 
 |                                                (void *) cur); | 
 |                     if (res != 0) | 
 |                         is_triable = -1; | 
 |                 } else { | 
 |                     is_triable = -1; | 
 |                 } | 
 |                 tmp++; | 
 |             } | 
 |         } | 
 |         i++; | 
 |         cur = cur->next; | 
 |     } | 
 |  | 
 |     for (i = 0; i < nbchild; i++) { | 
 |         if (list[i] == NULL) | 
 |             continue; | 
 |         for (j = 0; j < i; j++) { | 
 |             if (list[j] == NULL) | 
 |                 continue; | 
 |             ret = xmlRelaxNGCompareElemDefLists(ctxt, list[i], list[j]); | 
 |             if (ret == 0) { | 
 |                 is_indeterminist = 1; | 
 |             } | 
 |         } | 
 |     } | 
 |     for (i = 0; i < nbchild; i++) { | 
 |         if (list[i] != NULL) | 
 |             xmlFree(list[i]); | 
 |     } | 
 |  | 
 |     xmlFree(list); | 
 |     if (is_indeterminist) { | 
 |         def->dflags |= IS_INDETERMINIST; | 
 |     } | 
 |     if (is_triable == 1) { | 
 |         def->dflags |= IS_TRIABLE; | 
 |         def->data = triage; | 
 |     } else if (triage != NULL) { | 
 |         xmlHashFree(triage, NULL); | 
 |     } | 
 |     def->dflags |= IS_PROCESSED; | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGCheckGroupAttrs: | 
 |  * @ctxt:  a Relax-NG parser context | 
 |  * @def:  the group definition | 
 |  * | 
 |  * Detects violations of rule 7.3 | 
 |  */ | 
 | static void | 
 | xmlRelaxNGCheckGroupAttrs(xmlRelaxNGParserCtxtPtr ctxt, | 
 |                           xmlRelaxNGDefinePtr def) | 
 | { | 
 |     xmlRelaxNGDefinePtr **list; | 
 |     xmlRelaxNGDefinePtr cur; | 
 |     int nbchild = 0, i, j, ret; | 
 |  | 
 |     if ((def == NULL) || | 
 |         ((def->type != XML_RELAXNG_GROUP) && | 
 |          (def->type != XML_RELAXNG_ELEMENT))) | 
 |         return; | 
 |  | 
 |     if (def->dflags & IS_PROCESSED) | 
 |         return; | 
 |  | 
 |     /* | 
 |      * Don't run that check in case of error. Infinite recursion | 
 |      * becomes possible. | 
 |      */ | 
 |     if (ctxt->nbErrors != 0) | 
 |         return; | 
 |  | 
 |     cur = def->attrs; | 
 |     while (cur != NULL) { | 
 |         nbchild++; | 
 |         cur = cur->next; | 
 |     } | 
 |     cur = def->content; | 
 |     while (cur != NULL) { | 
 |         nbchild++; | 
 |         cur = cur->next; | 
 |     } | 
 |  | 
 |     list = (xmlRelaxNGDefinePtr **) xmlMalloc(nbchild * | 
 |                                               sizeof(xmlRelaxNGDefinePtr | 
 |                                                      *)); | 
 |     if (list == NULL) { | 
 |         xmlRngPErrMemory(ctxt, "building group\n"); | 
 |         return; | 
 |     } | 
 |     i = 0; | 
 |     cur = def->attrs; | 
 |     while (cur != NULL) { | 
 |         list[i] = xmlRelaxNGGetElements(ctxt, cur, 1); | 
 |         i++; | 
 |         cur = cur->next; | 
 |     } | 
 |     cur = def->content; | 
 |     while (cur != NULL) { | 
 |         list[i] = xmlRelaxNGGetElements(ctxt, cur, 1); | 
 |         i++; | 
 |         cur = cur->next; | 
 |     } | 
 |  | 
 |     for (i = 0; i < nbchild; i++) { | 
 |         if (list[i] == NULL) | 
 |             continue; | 
 |         for (j = 0; j < i; j++) { | 
 |             if (list[j] == NULL) | 
 |                 continue; | 
 |             ret = xmlRelaxNGCompareElemDefLists(ctxt, list[i], list[j]); | 
 |             if (ret == 0) { | 
 |                 xmlRngPErr(ctxt, def->node, XML_RNGP_GROUP_ATTR_CONFLICT, | 
 |                            "Attributes conflicts in group\n", NULL, NULL); | 
 |             } | 
 |         } | 
 |     } | 
 |     for (i = 0; i < nbchild; i++) { | 
 |         if (list[i] != NULL) | 
 |             xmlFree(list[i]); | 
 |     } | 
 |  | 
 |     xmlFree(list); | 
 |     def->dflags |= IS_PROCESSED; | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGComputeInterleaves: | 
 |  * @def:  the interleave definition | 
 |  * @ctxt:  a Relax-NG parser context | 
 |  * @name:  the definition name | 
 |  * | 
 |  * A lot of work for preprocessing interleave definitions | 
 |  * is potentially needed to get a decent execution speed at runtime | 
 |  *   - trying to get a total order on the element nodes generated | 
 |  *     by the interleaves, order the list of interleave definitions | 
 |  *     following that order. | 
 |  *   - if <text/> is used to handle mixed content, it is better to | 
 |  *     flag this in the define and simplify the runtime checking | 
 |  *     algorithm | 
 |  */ | 
 | static void | 
 | xmlRelaxNGComputeInterleaves(xmlRelaxNGDefinePtr def, | 
 |                              xmlRelaxNGParserCtxtPtr ctxt, | 
 |                              xmlChar * name ATTRIBUTE_UNUSED) | 
 | { | 
 |     xmlRelaxNGDefinePtr cur, *tmp; | 
 |  | 
 |     xmlRelaxNGPartitionPtr partitions = NULL; | 
 |     xmlRelaxNGInterleaveGroupPtr *groups = NULL; | 
 |     xmlRelaxNGInterleaveGroupPtr group; | 
 |     int i, j, ret, res; | 
 |     int nbgroups = 0; | 
 |     int nbchild = 0; | 
 |     int is_mixed = 0; | 
 |     int is_determinist = 1; | 
 |  | 
 |     /* | 
 |      * Don't run that check in case of error. Infinite recursion | 
 |      * becomes possible. | 
 |      */ | 
 |     if (ctxt->nbErrors != 0) | 
 |         return; | 
 |  | 
 | #ifdef DEBUG_INTERLEAVE | 
 |     xmlGenericError(xmlGenericErrorContext, | 
 |                     "xmlRelaxNGComputeInterleaves(%s)\n", name); | 
 | #endif | 
 |     cur = def->content; | 
 |     while (cur != NULL) { | 
 |         nbchild++; | 
 |         cur = cur->next; | 
 |     } | 
 |  | 
 | #ifdef DEBUG_INTERLEAVE | 
 |     xmlGenericError(xmlGenericErrorContext, "  %d child\n", nbchild); | 
 | #endif | 
 |     groups = (xmlRelaxNGInterleaveGroupPtr *) | 
 |         xmlMalloc(nbchild * sizeof(xmlRelaxNGInterleaveGroupPtr)); | 
 |     if (groups == NULL) | 
 |         goto error; | 
 |     cur = def->content; | 
 |     while (cur != NULL) { | 
 |         groups[nbgroups] = (xmlRelaxNGInterleaveGroupPtr) | 
 |             xmlMalloc(sizeof(xmlRelaxNGInterleaveGroup)); | 
 |         if (groups[nbgroups] == NULL) | 
 |             goto error; | 
 |         if (cur->type == XML_RELAXNG_TEXT) | 
 |             is_mixed++; | 
 |         groups[nbgroups]->rule = cur; | 
 |         groups[nbgroups]->defs = xmlRelaxNGGetElements(ctxt, cur, 0); | 
 |         groups[nbgroups]->attrs = xmlRelaxNGGetElements(ctxt, cur, 1); | 
 |         nbgroups++; | 
 |         cur = cur->next; | 
 |     } | 
 | #ifdef DEBUG_INTERLEAVE | 
 |     xmlGenericError(xmlGenericErrorContext, "  %d groups\n", nbgroups); | 
 | #endif | 
 |  | 
 |     /* | 
 |      * Let's check that all rules makes a partitions according to 7.4 | 
 |      */ | 
 |     partitions = (xmlRelaxNGPartitionPtr) | 
 |         xmlMalloc(sizeof(xmlRelaxNGPartition)); | 
 |     if (partitions == NULL) | 
 |         goto error; | 
 |     memset(partitions, 0, sizeof(xmlRelaxNGPartition)); | 
 |     partitions->nbgroups = nbgroups; | 
 |     partitions->triage = xmlHashCreate(nbgroups); | 
 |     for (i = 0; i < nbgroups; i++) { | 
 |         group = groups[i]; | 
 |         for (j = i + 1; j < nbgroups; j++) { | 
 |             if (groups[j] == NULL) | 
 |                 continue; | 
 |  | 
 |             ret = xmlRelaxNGCompareElemDefLists(ctxt, group->defs, | 
 |                                                 groups[j]->defs); | 
 |             if (ret == 0) { | 
 |                 xmlRngPErr(ctxt, def->node, XML_RNGP_ELEM_TEXT_CONFLICT, | 
 |                            "Element or text conflicts in interleave\n", | 
 |                            NULL, NULL); | 
 |             } | 
 |             ret = xmlRelaxNGCompareElemDefLists(ctxt, group->attrs, | 
 |                                                 groups[j]->attrs); | 
 |             if (ret == 0) { | 
 |                 xmlRngPErr(ctxt, def->node, XML_RNGP_ATTR_CONFLICT, | 
 |                            "Attributes conflicts in interleave\n", NULL, | 
 |                            NULL); | 
 |             } | 
 |         } | 
 |         tmp = group->defs; | 
 |         if ((tmp != NULL) && (*tmp != NULL)) { | 
 |             while (*tmp != NULL) { | 
 |                 if ((*tmp)->type == XML_RELAXNG_TEXT) { | 
 |                     res = xmlHashAddEntry2(partitions->triage, | 
 |                                            BAD_CAST "#text", NULL, | 
 |                                            (void *) (long) (i + 1)); | 
 |                     if (res != 0) | 
 |                         is_determinist = -1; | 
 |                 } else if (((*tmp)->type == XML_RELAXNG_ELEMENT) && | 
 |                            ((*tmp)->name != NULL)) { | 
 |                     if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0)) | 
 |                         res = xmlHashAddEntry2(partitions->triage, | 
 |                                                (*tmp)->name, NULL, | 
 |                                                (void *) (long) (i + 1)); | 
 |                     else | 
 |                         res = xmlHashAddEntry2(partitions->triage, | 
 |                                                (*tmp)->name, (*tmp)->ns, | 
 |                                                (void *) (long) (i + 1)); | 
 |                     if (res != 0) | 
 |                         is_determinist = -1; | 
 |                 } else if ((*tmp)->type == XML_RELAXNG_ELEMENT) { | 
 |                     if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0)) | 
 |                         res = xmlHashAddEntry2(partitions->triage, | 
 |                                                BAD_CAST "#any", NULL, | 
 |                                                (void *) (long) (i + 1)); | 
 |                     else | 
 |                         res = xmlHashAddEntry2(partitions->triage, | 
 |                                                BAD_CAST "#any", (*tmp)->ns, | 
 |                                                (void *) (long) (i + 1)); | 
 |                     if ((*tmp)->nameClass != NULL) | 
 |                         is_determinist = 2; | 
 |                     if (res != 0) | 
 |                         is_determinist = -1; | 
 |                 } else { | 
 |                     is_determinist = -1; | 
 |                 } | 
 |                 tmp++; | 
 |             } | 
 |         } else { | 
 |             is_determinist = 0; | 
 |         } | 
 |     } | 
 |     partitions->groups = groups; | 
 |  | 
 |     /* | 
 |      * and save the partition list back in the def | 
 |      */ | 
 |     def->data = partitions; | 
 |     if (is_mixed != 0) | 
 |         def->dflags |= IS_MIXED; | 
 |     if (is_determinist == 1) | 
 |         partitions->flags = IS_DETERMINIST; | 
 |     if (is_determinist == 2) | 
 |         partitions->flags = IS_DETERMINIST | IS_NEEDCHECK; | 
 |     return; | 
 |  | 
 |   error: | 
 |     xmlRngPErrMemory(ctxt, "in interleave computation\n"); | 
 |     if (groups != NULL) { | 
 |         for (i = 0; i < nbgroups; i++) | 
 |             if (groups[i] != NULL) { | 
 |                 if (groups[i]->defs != NULL) | 
 |                     xmlFree(groups[i]->defs); | 
 |                 xmlFree(groups[i]); | 
 |             } | 
 |         xmlFree(groups); | 
 |     } | 
 |     xmlRelaxNGFreePartition(partitions); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGParseInterleave: | 
 |  * @ctxt:  a Relax-NG parser context | 
 |  * @node:  the data node. | 
 |  * | 
 |  * parse the content of a RelaxNG interleave node. | 
 |  * | 
 |  * Returns the definition pointer or NULL in case of error | 
 |  */ | 
 | static xmlRelaxNGDefinePtr | 
 | xmlRelaxNGParseInterleave(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) | 
 | { | 
 |     xmlRelaxNGDefinePtr def = NULL; | 
 |     xmlRelaxNGDefinePtr last = NULL, cur; | 
 |     xmlNodePtr child; | 
 |  | 
 |     def = xmlRelaxNGNewDefine(ctxt, node); | 
 |     if (def == NULL) { | 
 |         return (NULL); | 
 |     } | 
 |     def->type = XML_RELAXNG_INTERLEAVE; | 
 |  | 
 |     if (ctxt->interleaves == NULL) | 
 |         ctxt->interleaves = xmlHashCreate(10); | 
 |     if (ctxt->interleaves == NULL) { | 
 |         xmlRngPErrMemory(ctxt, "create interleaves\n"); | 
 |     } else { | 
 |         char name[32]; | 
 |  | 
 |         snprintf(name, 32, "interleave%d", ctxt->nbInterleaves++); | 
 |         if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST name, def) < 0) { | 
 |             xmlRngPErr(ctxt, node, XML_RNGP_INTERLEAVE_ADD, | 
 |                        "Failed to add %s to hash table\n", | 
 | 		       (const xmlChar *) name, NULL); | 
 |         } | 
 |     } | 
 |     child = node->children; | 
 |     if (child == NULL) { | 
 |         xmlRngPErr(ctxt, node, XML_RNGP_INTERLEAVE_NO_CONTENT, | 
 |                    "Element interleave is empty\n", NULL, NULL); | 
 |     } | 
 |     while (child != NULL) { | 
 |         if (IS_RELAXNG(child, "element")) { | 
 |             cur = xmlRelaxNGParseElement(ctxt, child); | 
 |         } else { | 
 |             cur = xmlRelaxNGParsePattern(ctxt, child); | 
 |         } | 
 |         if (cur != NULL) { | 
 |             cur->parent = def; | 
 |             if (last == NULL) { | 
 |                 def->content = last = cur; | 
 |             } else { | 
 |                 last->next = cur; | 
 |                 last = cur; | 
 |             } | 
 |         } | 
 |         child = child->next; | 
 |     } | 
 |  | 
 |     return (def); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGParseInclude: | 
 |  * @ctxt:  a Relax-NG parser context | 
 |  * @node:  the include node | 
 |  * | 
 |  * Integrate the content of an include node in the current grammar | 
 |  * | 
 |  * Returns 0 in case of success or -1 in case of error | 
 |  */ | 
 | static int | 
 | xmlRelaxNGParseInclude(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) | 
 | { | 
 |     xmlRelaxNGIncludePtr incl; | 
 |     xmlNodePtr root; | 
 |     int ret = 0, tmp; | 
 |  | 
 |     incl = node->psvi; | 
 |     if (incl == NULL) { | 
 |         xmlRngPErr(ctxt, node, XML_RNGP_INCLUDE_EMPTY, | 
 |                    "Include node has no data\n", NULL, NULL); | 
 |         return (-1); | 
 |     } | 
 |     root = xmlDocGetRootElement(incl->doc); | 
 |     if (root == NULL) { | 
 |         xmlRngPErr(ctxt, node, XML_RNGP_EMPTY, "Include document is empty\n", | 
 |                    NULL, NULL); | 
 |         return (-1); | 
 |     } | 
 |     if (!xmlStrEqual(root->name, BAD_CAST "grammar")) { | 
 |         xmlRngPErr(ctxt, node, XML_RNGP_GRAMMAR_MISSING, | 
 |                    "Include document root is not a grammar\n", NULL, NULL); | 
 |         return (-1); | 
 |     } | 
 |  | 
 |     /* | 
 |      * Merge the definition from both the include and the internal list | 
 |      */ | 
 |     if (root->children != NULL) { | 
 |         tmp = xmlRelaxNGParseGrammarContent(ctxt, root->children); | 
 |         if (tmp != 0) | 
 |             ret = -1; | 
 |     } | 
 |     if (node->children != NULL) { | 
 |         tmp = xmlRelaxNGParseGrammarContent(ctxt, node->children); | 
 |         if (tmp != 0) | 
 |             ret = -1; | 
 |     } | 
 |     return (ret); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGParseDefine: | 
 |  * @ctxt:  a Relax-NG parser context | 
 |  * @node:  the define node | 
 |  * | 
 |  * parse the content of a RelaxNG define element node. | 
 |  * | 
 |  * Returns 0 in case of success or -1 in case of error | 
 |  */ | 
 | static int | 
 | xmlRelaxNGParseDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) | 
 | { | 
 |     xmlChar *name; | 
 |     int ret = 0, tmp; | 
 |     xmlRelaxNGDefinePtr def; | 
 |     const xmlChar *olddefine; | 
 |  | 
 |     name = xmlGetProp(node, BAD_CAST "name"); | 
 |     if (name == NULL) { | 
 |         xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_NAME_MISSING, | 
 |                    "define has no name\n", NULL, NULL); | 
 |     } else { | 
 |         xmlRelaxNGNormExtSpace(name); | 
 |         if (xmlValidateNCName(name, 0)) { | 
 |             xmlRngPErr(ctxt, node, XML_RNGP_INVALID_DEFINE_NAME, | 
 |                        "define name '%s' is not an NCName\n", name, NULL); | 
 |         } | 
 |         def = xmlRelaxNGNewDefine(ctxt, node); | 
 |         if (def == NULL) { | 
 |             xmlFree(name); | 
 |             return (-1); | 
 |         } | 
 |         def->type = XML_RELAXNG_DEF; | 
 |         def->name = name; | 
 |         if (node->children == NULL) { | 
 |             xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_EMPTY, | 
 |                        "define has no children\n", NULL, NULL); | 
 |         } else { | 
 |             olddefine = ctxt->define; | 
 |             ctxt->define = name; | 
 |             def->content = | 
 |                 xmlRelaxNGParsePatterns(ctxt, node->children, 0); | 
 |             ctxt->define = olddefine; | 
 |         } | 
 |         if (ctxt->grammar->defs == NULL) | 
 |             ctxt->grammar->defs = xmlHashCreate(10); | 
 |         if (ctxt->grammar->defs == NULL) { | 
 |             xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_CREATE_FAILED, | 
 |                        "Could not create definition hash\n", NULL, NULL); | 
 |             ret = -1; | 
 |         } else { | 
 |             tmp = xmlHashAddEntry(ctxt->grammar->defs, name, def); | 
 |             if (tmp < 0) { | 
 |                 xmlRelaxNGDefinePtr prev; | 
 |  | 
 |                 prev = xmlHashLookup(ctxt->grammar->defs, name); | 
 |                 if (prev == NULL) { | 
 |                     xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_CREATE_FAILED, | 
 |                                "Internal error on define aggregation of %s\n", | 
 |                                name, NULL); | 
 |                     ret = -1; | 
 |                 } else { | 
 |                     while (prev->nextHash != NULL) | 
 |                         prev = prev->nextHash; | 
 |                     prev->nextHash = def; | 
 |                 } | 
 |             } | 
 |         } | 
 |     } | 
 |     return (ret); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGParseImportRef: | 
 |  * @payload: the parser context | 
 |  * @data: the current grammar | 
 |  * @name: the reference name | 
 |  * | 
 |  * Import import one references into the current grammar | 
 |  */ | 
 | static void | 
 | xmlRelaxNGParseImportRef(void *payload, void *data, xmlChar *name) { | 
 |     xmlRelaxNGParserCtxtPtr ctxt = (xmlRelaxNGParserCtxtPtr) data; | 
 |     xmlRelaxNGDefinePtr def = (xmlRelaxNGDefinePtr) payload; | 
 |     int tmp; | 
 |  | 
 |     def->dflags |= IS_EXTERNAL_REF; | 
 |  | 
 |     tmp = xmlHashAddEntry(ctxt->grammar->refs, name, def); | 
 |     if (tmp < 0) { | 
 |         xmlRelaxNGDefinePtr prev; | 
 |  | 
 |         prev = (xmlRelaxNGDefinePtr) | 
 |             xmlHashLookup(ctxt->grammar->refs, def->name); | 
 |         if (prev == NULL) { | 
 |             if (def->name != NULL) { | 
 |                 xmlRngPErr(ctxt, NULL, XML_RNGP_REF_CREATE_FAILED, | 
 |                            "Error refs definitions '%s'\n", | 
 |                            def->name, NULL); | 
 |             } else { | 
 |                 xmlRngPErr(ctxt, NULL, XML_RNGP_REF_CREATE_FAILED, | 
 |                            "Error refs definitions\n", | 
 |                            NULL, NULL); | 
 |             } | 
 |         } else { | 
 |             def->nextHash = prev->nextHash; | 
 |             prev->nextHash = def; | 
 |         } | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGParseImportRefs: | 
 |  * @ctxt: the parser context | 
 |  * @grammar: the sub grammar | 
 |  * | 
 |  * Import references from the subgrammar into the current grammar | 
 |  * | 
 |  * Returns 0 in case of success, -1 in case of failure | 
 |  */ | 
 | static int | 
 | xmlRelaxNGParseImportRefs(xmlRelaxNGParserCtxtPtr ctxt, | 
 |                           xmlRelaxNGGrammarPtr grammar) { | 
 |     if ((ctxt == NULL) || (grammar == NULL) || (ctxt->grammar == NULL)) | 
 |         return(-1); | 
 |     if (grammar->refs == NULL) | 
 |         return(0); | 
 |     if (ctxt->grammar->refs == NULL) | 
 |         ctxt->grammar->refs = xmlHashCreate(10); | 
 |     if (ctxt->grammar->refs == NULL) { | 
 |         xmlRngPErr(ctxt, NULL, XML_RNGP_REF_CREATE_FAILED, | 
 |                    "Could not create references hash\n", NULL, NULL); | 
 |         return(-1); | 
 |     } | 
 |     xmlHashScan(grammar->refs, xmlRelaxNGParseImportRef, ctxt); | 
 |     return(0); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGProcessExternalRef: | 
 |  * @ctxt: the parser context | 
 |  * @node:  the externlRef node | 
 |  * | 
 |  * Process and compile an externlRef node | 
 |  * | 
 |  * Returns the xmlRelaxNGDefinePtr or NULL in case of error | 
 |  */ | 
 | static xmlRelaxNGDefinePtr | 
 | xmlRelaxNGProcessExternalRef(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) | 
 | { | 
 |     xmlRelaxNGDocumentPtr docu; | 
 |     xmlNodePtr root, tmp; | 
 |     xmlChar *ns; | 
 |     int newNs = 0, oldflags; | 
 |     xmlRelaxNGDefinePtr def; | 
 |  | 
 |     docu = node->psvi; | 
 |     if (docu != NULL) { | 
 |         def = xmlRelaxNGNewDefine(ctxt, node); | 
 |         if (def == NULL) | 
 |             return (NULL); | 
 |         def->type = XML_RELAXNG_EXTERNALREF; | 
 |  | 
 |         if (docu->content == NULL) { | 
 |             /* | 
 |              * Then do the parsing for good | 
 |              */ | 
 |             root = xmlDocGetRootElement(docu->doc); | 
 |             if (root == NULL) { | 
 |                 xmlRngPErr(ctxt, node, XML_RNGP_EXTERNALREF_EMTPY, | 
 |                            "xmlRelaxNGParse: %s is empty\n", ctxt->URL, | 
 |                            NULL); | 
 |                 return (NULL); | 
 |             } | 
 |             /* | 
 |              * ns transmission rules | 
 |              */ | 
 |             ns = xmlGetProp(root, BAD_CAST "ns"); | 
 |             if (ns == NULL) { | 
 |                 tmp = node; | 
 |                 while ((tmp != NULL) && (tmp->type == XML_ELEMENT_NODE)) { | 
 |                     ns = xmlGetProp(tmp, BAD_CAST "ns"); | 
 |                     if (ns != NULL) { | 
 |                         break; | 
 |                     } | 
 |                     tmp = tmp->parent; | 
 |                 } | 
 |                 if (ns != NULL) { | 
 |                     xmlSetProp(root, BAD_CAST "ns", ns); | 
 |                     newNs = 1; | 
 |                     xmlFree(ns); | 
 |                 } | 
 |             } else { | 
 |                 xmlFree(ns); | 
 |             } | 
 |  | 
 |             /* | 
 |              * Parsing to get a precompiled schemas. | 
 |              */ | 
 |             oldflags = ctxt->flags; | 
 |             ctxt->flags |= XML_RELAXNG_IN_EXTERNALREF; | 
 |             docu->schema = xmlRelaxNGParseDocument(ctxt, root); | 
 |             ctxt->flags = oldflags; | 
 |             if ((docu->schema != NULL) && | 
 |                 (docu->schema->topgrammar != NULL)) { | 
 |                 docu->content = docu->schema->topgrammar->start; | 
 |                 if (docu->schema->topgrammar->refs) | 
 |                     xmlRelaxNGParseImportRefs(ctxt, docu->schema->topgrammar); | 
 |             } | 
 |  | 
 |             /* | 
 |              * the externalRef may be reused in a different ns context | 
 |              */ | 
 |             if (newNs == 1) { | 
 |                 xmlUnsetProp(root, BAD_CAST "ns"); | 
 |             } | 
 |         } | 
 |         def->content = docu->content; | 
 |     } else { | 
 |         def = NULL; | 
 |     } | 
 |     return (def); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGParsePattern: | 
 |  * @ctxt:  a Relax-NG parser context | 
 |  * @node:  the pattern node. | 
 |  * | 
 |  * parse the content of a RelaxNG pattern node. | 
 |  * | 
 |  * Returns the definition pointer or NULL in case of error or if no | 
 |  *     pattern is generated. | 
 |  */ | 
 | static xmlRelaxNGDefinePtr | 
 | xmlRelaxNGParsePattern(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) | 
 | { | 
 |     xmlRelaxNGDefinePtr def = NULL; | 
 |  | 
 |     if (node == NULL) { | 
 |         return (NULL); | 
 |     } | 
 |     if (IS_RELAXNG(node, "element")) { | 
 |         def = xmlRelaxNGParseElement(ctxt, node); | 
 |     } else if (IS_RELAXNG(node, "attribute")) { | 
 |         def = xmlRelaxNGParseAttribute(ctxt, node); | 
 |     } else if (IS_RELAXNG(node, "empty")) { | 
 |         def = xmlRelaxNGNewDefine(ctxt, node); | 
 |         if (def == NULL) | 
 |             return (NULL); | 
 |         def->type = XML_RELAXNG_EMPTY; | 
 |         if (node->children != NULL) { | 
 |             xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_NOT_EMPTY, | 
 |                        "empty: had a child node\n", NULL, NULL); | 
 |         } | 
 |     } else if (IS_RELAXNG(node, "text")) { | 
 |         def = xmlRelaxNGNewDefine(ctxt, node); | 
 |         if (def == NULL) | 
 |             return (NULL); | 
 |         def->type = XML_RELAXNG_TEXT; | 
 |         if (node->children != NULL) { | 
 |             xmlRngPErr(ctxt, node, XML_RNGP_TEXT_HAS_CHILD, | 
 |                        "text: had a child node\n", NULL, NULL); | 
 |         } | 
 |     } else if (IS_RELAXNG(node, "zeroOrMore")) { | 
 |         def = xmlRelaxNGNewDefine(ctxt, node); | 
 |         if (def == NULL) | 
 |             return (NULL); | 
 |         def->type = XML_RELAXNG_ZEROORMORE; | 
 |         if (node->children == NULL) { | 
 |             xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT, | 
 |                        "Element %s is empty\n", node->name, NULL); | 
 |         } else { | 
 |             def->content = | 
 |                 xmlRelaxNGParsePatterns(ctxt, node->children, 1); | 
 |         } | 
 |     } else if (IS_RELAXNG(node, "oneOrMore")) { | 
 |         def = xmlRelaxNGNewDefine(ctxt, node); | 
 |         if (def == NULL) | 
 |             return (NULL); | 
 |         def->type = XML_RELAXNG_ONEORMORE; | 
 |         if (node->children == NULL) { | 
 |             xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT, | 
 |                        "Element %s is empty\n", node->name, NULL); | 
 |         } else { | 
 |             def->content = | 
 |                 xmlRelaxNGParsePatterns(ctxt, node->children, 1); | 
 |         } | 
 |     } else if (IS_RELAXNG(node, "optional")) { | 
 |         def = xmlRelaxNGNewDefine(ctxt, node); | 
 |         if (def == NULL) | 
 |             return (NULL); | 
 |         def->type = XML_RELAXNG_OPTIONAL; | 
 |         if (node->children == NULL) { | 
 |             xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT, | 
 |                        "Element %s is empty\n", node->name, NULL); | 
 |         } else { | 
 |             def->content = | 
 |                 xmlRelaxNGParsePatterns(ctxt, node->children, 1); | 
 |         } | 
 |     } else if (IS_RELAXNG(node, "choice")) { | 
 |         def = xmlRelaxNGNewDefine(ctxt, node); | 
 |         if (def == NULL) | 
 |             return (NULL); | 
 |         def->type = XML_RELAXNG_CHOICE; | 
 |         if (node->children == NULL) { | 
 |             xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT, | 
 |                        "Element %s is empty\n", node->name, NULL); | 
 |         } else { | 
 |             def->content = | 
 |                 xmlRelaxNGParsePatterns(ctxt, node->children, 0); | 
 |         } | 
 |     } else if (IS_RELAXNG(node, "group")) { | 
 |         def = xmlRelaxNGNewDefine(ctxt, node); | 
 |         if (def == NULL) | 
 |             return (NULL); | 
 |         def->type = XML_RELAXNG_GROUP; | 
 |         if (node->children == NULL) { | 
 |             xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT, | 
 |                        "Element %s is empty\n", node->name, NULL); | 
 |         } else { | 
 |             def->content = | 
 |                 xmlRelaxNGParsePatterns(ctxt, node->children, 0); | 
 |         } | 
 |     } else if (IS_RELAXNG(node, "ref")) { | 
 |         def = xmlRelaxNGNewDefine(ctxt, node); | 
 |         if (def == NULL) | 
 |             return (NULL); | 
 |         def->type = XML_RELAXNG_REF; | 
 |         def->name = xmlGetProp(node, BAD_CAST "name"); | 
 |         if (def->name == NULL) { | 
 |             xmlRngPErr(ctxt, node, XML_RNGP_REF_NO_NAME, "ref has no name\n", | 
 |                        NULL, NULL); | 
 |         } else { | 
 |             xmlRelaxNGNormExtSpace(def->name); | 
 |             if (xmlValidateNCName(def->name, 0)) { | 
 |                 xmlRngPErr(ctxt, node, XML_RNGP_REF_NAME_INVALID, | 
 |                            "ref name '%s' is not an NCName\n", def->name, | 
 |                            NULL); | 
 |             } | 
 |         } | 
 |         if (node->children != NULL) { | 
 |             xmlRngPErr(ctxt, node, XML_RNGP_REF_NOT_EMPTY, "ref is not empty\n", | 
 |                        NULL, NULL); | 
 |         } | 
 |         if (ctxt->grammar->refs == NULL) | 
 |             ctxt->grammar->refs = xmlHashCreate(10); | 
 |         if (ctxt->grammar->refs == NULL) { | 
 |             xmlRngPErr(ctxt, node, XML_RNGP_REF_CREATE_FAILED, | 
 |                        "Could not create references hash\n", NULL, NULL); | 
 |             def = NULL; | 
 |         } else { | 
 |             int tmp; | 
 |  | 
 |             tmp = xmlHashAddEntry(ctxt->grammar->refs, def->name, def); | 
 |             if (tmp < 0) { | 
 |                 xmlRelaxNGDefinePtr prev; | 
 |  | 
 |                 prev = (xmlRelaxNGDefinePtr) | 
 |                     xmlHashLookup(ctxt->grammar->refs, def->name); | 
 |                 if (prev == NULL) { | 
 |                     if (def->name != NULL) { | 
 | 		        xmlRngPErr(ctxt, node, XML_RNGP_REF_CREATE_FAILED, | 
 | 				   "Error refs definitions '%s'\n", | 
 | 				   def->name, NULL); | 
 |                     } else { | 
 | 		        xmlRngPErr(ctxt, node, XML_RNGP_REF_CREATE_FAILED, | 
 | 				   "Error refs definitions\n", | 
 | 				   NULL, NULL); | 
 |                     } | 
 |                     def = NULL; | 
 |                 } else { | 
 |                     def->nextHash = prev->nextHash; | 
 |                     prev->nextHash = def; | 
 |                 } | 
 |             } | 
 |         } | 
 |     } else if (IS_RELAXNG(node, "data")) { | 
 |         def = xmlRelaxNGParseData(ctxt, node); | 
 |     } else if (IS_RELAXNG(node, "value")) { | 
 |         def = xmlRelaxNGParseValue(ctxt, node); | 
 |     } else if (IS_RELAXNG(node, "list")) { | 
 |         def = xmlRelaxNGNewDefine(ctxt, node); | 
 |         if (def == NULL) | 
 |             return (NULL); | 
 |         def->type = XML_RELAXNG_LIST; | 
 |         if (node->children == NULL) { | 
 |             xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT, | 
 |                        "Element %s is empty\n", node->name, NULL); | 
 |         } else { | 
 |             def->content = | 
 |                 xmlRelaxNGParsePatterns(ctxt, node->children, 0); | 
 |         } | 
 |     } else if (IS_RELAXNG(node, "interleave")) { | 
 |         def = xmlRelaxNGParseInterleave(ctxt, node); | 
 |     } else if (IS_RELAXNG(node, "externalRef")) { | 
 |         def = xmlRelaxNGProcessExternalRef(ctxt, node); | 
 |     } else if (IS_RELAXNG(node, "notAllowed")) { | 
 |         def = xmlRelaxNGNewDefine(ctxt, node); | 
 |         if (def == NULL) | 
 |             return (NULL); | 
 |         def->type = XML_RELAXNG_NOT_ALLOWED; | 
 |         if (node->children != NULL) { | 
 |             xmlRngPErr(ctxt, node, XML_RNGP_NOTALLOWED_NOT_EMPTY, | 
 |                        "xmlRelaxNGParse: notAllowed element is not empty\n", | 
 |                        NULL, NULL); | 
 |         } | 
 |     } else if (IS_RELAXNG(node, "grammar")) { | 
 |         xmlRelaxNGGrammarPtr grammar, old; | 
 |         xmlRelaxNGGrammarPtr oldparent; | 
 |  | 
 | #ifdef DEBUG_GRAMMAR | 
 |         xmlGenericError(xmlGenericErrorContext, | 
 |                         "Found <grammar> pattern\n"); | 
 | #endif | 
 |  | 
 |         oldparent = ctxt->parentgrammar; | 
 |         old = ctxt->grammar; | 
 |         ctxt->parentgrammar = old; | 
 |         grammar = xmlRelaxNGParseGrammar(ctxt, node->children); | 
 |         if (old != NULL) { | 
 |             ctxt->grammar = old; | 
 |             ctxt->parentgrammar = oldparent; | 
 | #if 0 | 
 |             if (grammar != NULL) { | 
 |                 grammar->next = old->next; | 
 |                 old->next = grammar; | 
 |             } | 
 | #endif | 
 |         } | 
 |         if (grammar != NULL) | 
 |             def = grammar->start; | 
 |         else | 
 |             def = NULL; | 
 |     } else if (IS_RELAXNG(node, "parentRef")) { | 
 |         if (ctxt->parentgrammar == NULL) { | 
 |             xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NO_PARENT, | 
 |                        "Use of parentRef without a parent grammar\n", NULL, | 
 |                        NULL); | 
 |             return (NULL); | 
 |         } | 
 |         def = xmlRelaxNGNewDefine(ctxt, node); | 
 |         if (def == NULL) | 
 |             return (NULL); | 
 |         def->type = XML_RELAXNG_PARENTREF; | 
 |         def->name = xmlGetProp(node, BAD_CAST "name"); | 
 |         if (def->name == NULL) { | 
 |             xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NO_NAME, | 
 |                        "parentRef has no name\n", NULL, NULL); | 
 |         } else { | 
 |             xmlRelaxNGNormExtSpace(def->name); | 
 |             if (xmlValidateNCName(def->name, 0)) { | 
 |                 xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NAME_INVALID, | 
 |                            "parentRef name '%s' is not an NCName\n", | 
 |                            def->name, NULL); | 
 |             } | 
 |         } | 
 |         if (node->children != NULL) { | 
 |             xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NOT_EMPTY, | 
 |                        "parentRef is not empty\n", NULL, NULL); | 
 |         } | 
 |         if (ctxt->parentgrammar->refs == NULL) | 
 |             ctxt->parentgrammar->refs = xmlHashCreate(10); | 
 |         if (ctxt->parentgrammar->refs == NULL) { | 
 |             xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_CREATE_FAILED, | 
 |                        "Could not create references hash\n", NULL, NULL); | 
 |             def = NULL; | 
 |         } else if (def->name != NULL) { | 
 |             int tmp; | 
 |  | 
 |             tmp = | 
 |                 xmlHashAddEntry(ctxt->parentgrammar->refs, def->name, def); | 
 |             if (tmp < 0) { | 
 |                 xmlRelaxNGDefinePtr prev; | 
 |  | 
 |                 prev = (xmlRelaxNGDefinePtr) | 
 |                     xmlHashLookup(ctxt->parentgrammar->refs, def->name); | 
 |                 if (prev == NULL) { | 
 |                     xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_CREATE_FAILED, | 
 |                                "Internal error parentRef definitions '%s'\n", | 
 |                                def->name, NULL); | 
 |                     def = NULL; | 
 |                 } else { | 
 |                     def->nextHash = prev->nextHash; | 
 |                     prev->nextHash = def; | 
 |                 } | 
 |             } | 
 |         } | 
 |     } else if (IS_RELAXNG(node, "mixed")) { | 
 |         if (node->children == NULL) { | 
 |             xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT, "Mixed is empty\n", | 
 |                        NULL, NULL); | 
 |             def = NULL; | 
 |         } else { | 
 |             def = xmlRelaxNGParseInterleave(ctxt, node); | 
 |             if (def != NULL) { | 
 |                 xmlRelaxNGDefinePtr tmp; | 
 |  | 
 |                 if ((def->content != NULL) && (def->content->next != NULL)) { | 
 |                     tmp = xmlRelaxNGNewDefine(ctxt, node); | 
 |                     if (tmp != NULL) { | 
 |                         tmp->type = XML_RELAXNG_GROUP; | 
 |                         tmp->content = def->content; | 
 |                         def->content = tmp; | 
 |                     } | 
 |                 } | 
 |  | 
 |                 tmp = xmlRelaxNGNewDefine(ctxt, node); | 
 |                 if (tmp == NULL) | 
 |                     return (def); | 
 |                 tmp->type = XML_RELAXNG_TEXT; | 
 |                 tmp->next = def->content; | 
 |                 def->content = tmp; | 
 |             } | 
 |         } | 
 |     } else { | 
 |         xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_CONSTRUCT, | 
 |                    "Unexpected node %s is not a pattern\n", node->name, | 
 |                    NULL); | 
 |         def = NULL; | 
 |     } | 
 |     return (def); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGParseAttribute: | 
 |  * @ctxt:  a Relax-NG parser context | 
 |  * @node:  the element node | 
 |  * | 
 |  * parse the content of a RelaxNG attribute node. | 
 |  * | 
 |  * Returns the definition pointer or NULL in case of error. | 
 |  */ | 
 | static xmlRelaxNGDefinePtr | 
 | xmlRelaxNGParseAttribute(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) | 
 | { | 
 |     xmlRelaxNGDefinePtr ret, cur; | 
 |     xmlNodePtr child; | 
 |     int old_flags; | 
 |  | 
 |     ret = xmlRelaxNGNewDefine(ctxt, node); | 
 |     if (ret == NULL) | 
 |         return (NULL); | 
 |     ret->type = XML_RELAXNG_ATTRIBUTE; | 
 |     ret->parent = ctxt->def; | 
 |     child = node->children; | 
 |     if (child == NULL) { | 
 |         xmlRngPErr(ctxt, node, XML_RNGP_ATTRIBUTE_EMPTY, | 
 |                    "xmlRelaxNGParseattribute: attribute has no children\n", | 
 |                    NULL, NULL); | 
 |         return (ret); | 
 |     } | 
 |     old_flags = ctxt->flags; | 
 |     ctxt->flags |= XML_RELAXNG_IN_ATTRIBUTE; | 
 |     cur = xmlRelaxNGParseNameClass(ctxt, child, ret); | 
 |     if (cur != NULL) | 
 |         child = child->next; | 
 |  | 
 |     if (child != NULL) { | 
 |         cur = xmlRelaxNGParsePattern(ctxt, child); | 
 |         if (cur != NULL) { | 
 |             switch (cur->type) { | 
 |                 case XML_RELAXNG_EMPTY: | 
 |                 case XML_RELAXNG_NOT_ALLOWED: | 
 |                 case XML_RELAXNG_TEXT: | 
 |                 case XML_RELAXNG_ELEMENT: | 
 |                 case XML_RELAXNG_DATATYPE: | 
 |                 case XML_RELAXNG_VALUE: | 
 |                 case XML_RELAXNG_LIST: | 
 |                 case XML_RELAXNG_REF: | 
 |                 case XML_RELAXNG_PARENTREF: | 
 |                 case XML_RELAXNG_EXTERNALREF: | 
 |                 case XML_RELAXNG_DEF: | 
 |                 case XML_RELAXNG_ONEORMORE: | 
 |                 case XML_RELAXNG_ZEROORMORE: | 
 |                 case XML_RELAXNG_OPTIONAL: | 
 |                 case XML_RELAXNG_CHOICE: | 
 |                 case XML_RELAXNG_GROUP: | 
 |                 case XML_RELAXNG_INTERLEAVE: | 
 |                 case XML_RELAXNG_ATTRIBUTE: | 
 |                     ret->content = cur; | 
 |                     cur->parent = ret; | 
 |                     break; | 
 |                 case XML_RELAXNG_START: | 
 |                 case XML_RELAXNG_PARAM: | 
 |                 case XML_RELAXNG_EXCEPT: | 
 |                     xmlRngPErr(ctxt, node, XML_RNGP_ATTRIBUTE_CONTENT, | 
 |                                "attribute has invalid content\n", NULL, | 
 |                                NULL); | 
 |                     break; | 
 |                 case XML_RELAXNG_NOOP: | 
 |                     xmlRngPErr(ctxt, node, XML_RNGP_ATTRIBUTE_NOOP, | 
 |                                "RNG Internal error, noop found in attribute\n", | 
 |                                NULL, NULL); | 
 |                     break; | 
 |             } | 
 |         } | 
 |         child = child->next; | 
 |     } | 
 |     if (child != NULL) { | 
 |         xmlRngPErr(ctxt, node, XML_RNGP_ATTRIBUTE_CHILDREN, | 
 |                    "attribute has multiple children\n", NULL, NULL); | 
 |     } | 
 |     ctxt->flags = old_flags; | 
 |     return (ret); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGParseExceptNameClass: | 
 |  * @ctxt:  a Relax-NG parser context | 
 |  * @node:  the except node | 
 |  * @attr:  1 if within an attribute, 0 if within an element | 
 |  * | 
 |  * parse the content of a RelaxNG nameClass node. | 
 |  * | 
 |  * Returns the definition pointer or NULL in case of error. | 
 |  */ | 
 | static xmlRelaxNGDefinePtr | 
 | xmlRelaxNGParseExceptNameClass(xmlRelaxNGParserCtxtPtr ctxt, | 
 |                                xmlNodePtr node, int attr) | 
 | { | 
 |     xmlRelaxNGDefinePtr ret, cur, last = NULL; | 
 |     xmlNodePtr child; | 
 |  | 
 |     if (!IS_RELAXNG(node, "except")) { | 
 |         xmlRngPErr(ctxt, node, XML_RNGP_EXCEPT_MISSING, | 
 |                    "Expecting an except node\n", NULL, NULL); | 
 |         return (NULL); | 
 |     } | 
 |     if (node->next != NULL) { | 
 |         xmlRngPErr(ctxt, node, XML_RNGP_EXCEPT_MULTIPLE, | 
 |                    "exceptNameClass allows only a single except node\n", | 
 |                    NULL, NULL); | 
 |     } | 
 |     if (node->children == NULL) { | 
 |         xmlRngPErr(ctxt, node, XML_RNGP_EXCEPT_EMPTY, "except has no content\n", | 
 |                    NULL, NULL); | 
 |         return (NULL); | 
 |     } | 
 |  | 
 |     ret = xmlRelaxNGNewDefine(ctxt, node); | 
 |     if (ret == NULL) | 
 |         return (NULL); | 
 |     ret->type = XML_RELAXNG_EXCEPT; | 
 |     child = node->children; | 
 |     while (child != NULL) { | 
 |         cur = xmlRelaxNGNewDefine(ctxt, child); | 
 |         if (cur == NULL) | 
 |             break; | 
 |         if (attr) | 
 |             cur->type = XML_RELAXNG_ATTRIBUTE; | 
 |         else | 
 |             cur->type = XML_RELAXNG_ELEMENT; | 
 |  | 
 |         if (xmlRelaxNGParseNameClass(ctxt, child, cur) != NULL) { | 
 |             if (last == NULL) { | 
 |                 ret->content = cur; | 
 |             } else { | 
 |                 last->next = cur; | 
 |             } | 
 |             last = cur; | 
 |         } | 
 |         child = child->next; | 
 |     } | 
 |  | 
 |     return (ret); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGParseNameClass: | 
 |  * @ctxt:  a Relax-NG parser context | 
 |  * @node:  the nameClass node | 
 |  * @def:  the current definition | 
 |  * | 
 |  * parse the content of a RelaxNG nameClass node. | 
 |  * | 
 |  * Returns the definition pointer or NULL in case of error. | 
 |  */ | 
 | static xmlRelaxNGDefinePtr | 
 | xmlRelaxNGParseNameClass(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node, | 
 |                          xmlRelaxNGDefinePtr def) | 
 | { | 
 |     xmlRelaxNGDefinePtr ret, tmp; | 
 |     xmlChar *val; | 
 |  | 
 |     ret = def; | 
 |     if ((IS_RELAXNG(node, "name")) || (IS_RELAXNG(node, "anyName")) || | 
 |         (IS_RELAXNG(node, "nsName"))) { | 
 |         if ((def->type != XML_RELAXNG_ELEMENT) && | 
 |             (def->type != XML_RELAXNG_ATTRIBUTE)) { | 
 |             ret = xmlRelaxNGNewDefine(ctxt, node); | 
 |             if (ret == NULL) | 
 |                 return (NULL); | 
 |             ret->parent = def; | 
 |             if (ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) | 
 |                 ret->type = XML_RELAXNG_ATTRIBUTE; | 
 |             else | 
 |                 ret->type = XML_RELAXNG_ELEMENT; | 
 |         } | 
 |     } | 
 |     if (IS_RELAXNG(node, "name")) { | 
 |         val = xmlNodeGetContent(node); | 
 |         xmlRelaxNGNormExtSpace(val); | 
 |         if (xmlValidateNCName(val, 0)) { | 
 | 	    if (node->parent != NULL) | 
 | 		xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_NAME, | 
 | 			   "Element %s name '%s' is not an NCName\n", | 
 | 			   node->parent->name, val); | 
 | 	    else | 
 | 		xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_NAME, | 
 | 			   "name '%s' is not an NCName\n", | 
 | 			   val, NULL); | 
 |         } | 
 |         ret->name = val; | 
 |         val = xmlGetProp(node, BAD_CAST "ns"); | 
 |         ret->ns = val; | 
 |         if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) && | 
 |             (val != NULL) && | 
 |             (xmlStrEqual(val, BAD_CAST "http://www.w3.org/2000/xmlns"))) { | 
 | 	    xmlRngPErr(ctxt, node, XML_RNGP_XML_NS, | 
 |                         "Attribute with namespace '%s' is not allowed\n", | 
 |                         val, NULL); | 
 |         } | 
 |         if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) && | 
 |             (val != NULL) && | 
 |             (val[0] == 0) && (xmlStrEqual(ret->name, BAD_CAST "xmlns"))) { | 
 | 	    xmlRngPErr(ctxt, node, XML_RNGP_XMLNS_NAME, | 
 |                        "Attribute with QName 'xmlns' is not allowed\n", | 
 |                        val, NULL); | 
 |         } | 
 |     } else if (IS_RELAXNG(node, "anyName")) { | 
 |         ret->name = NULL; | 
 |         ret->ns = NULL; | 
 |         if (node->children != NULL) { | 
 |             ret->nameClass = | 
 |                 xmlRelaxNGParseExceptNameClass(ctxt, node->children, | 
 |                                                (def->type == | 
 |                                                 XML_RELAXNG_ATTRIBUTE)); | 
 |         } | 
 |     } else if (IS_RELAXNG(node, "nsName")) { | 
 |         ret->name = NULL; | 
 |         ret->ns = xmlGetProp(node, BAD_CAST "ns"); | 
 |         if (ret->ns == NULL) { | 
 |             xmlRngPErr(ctxt, node, XML_RNGP_NSNAME_NO_NS, | 
 |                        "nsName has no ns attribute\n", NULL, NULL); | 
 |         } | 
 |         if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) && | 
 |             (ret->ns != NULL) && | 
 |             (xmlStrEqual | 
 |              (ret->ns, BAD_CAST "http://www.w3.org/2000/xmlns"))) { | 
 |             xmlRngPErr(ctxt, node, XML_RNGP_XML_NS, | 
 |                        "Attribute with namespace '%s' is not allowed\n", | 
 |                        ret->ns, NULL); | 
 |         } | 
 |         if (node->children != NULL) { | 
 |             ret->nameClass = | 
 |                 xmlRelaxNGParseExceptNameClass(ctxt, node->children, | 
 |                                                (def->type == | 
 |                                                 XML_RELAXNG_ATTRIBUTE)); | 
 |         } | 
 |     } else if (IS_RELAXNG(node, "choice")) { | 
 |         xmlNodePtr child; | 
 |         xmlRelaxNGDefinePtr last = NULL; | 
 |  | 
 |         ret = xmlRelaxNGNewDefine(ctxt, node); | 
 |         if (ret == NULL) | 
 |             return (NULL); | 
 |         ret->parent = def; | 
 |         ret->type = XML_RELAXNG_CHOICE; | 
 |  | 
 |         if (node->children == NULL) { | 
 |             xmlRngPErr(ctxt, node, XML_RNGP_CHOICE_EMPTY, | 
 |                        "Element choice is empty\n", NULL, NULL); | 
 |         } else { | 
 |  | 
 |             child = node->children; | 
 |             while (child != NULL) { | 
 |                 tmp = xmlRelaxNGParseNameClass(ctxt, child, ret); | 
 |                 if (tmp != NULL) { | 
 |                     if (last == NULL) { | 
 |                         last = ret->nameClass = tmp; | 
 |                     } else { | 
 |                         last->next = tmp; | 
 |                         last = tmp; | 
 |                     } | 
 |                 } | 
 |                 child = child->next; | 
 |             } | 
 |         } | 
 |     } else { | 
 |         xmlRngPErr(ctxt, node, XML_RNGP_CHOICE_CONTENT, | 
 |                    "expecting name, anyName, nsName or choice : got %s\n", | 
 |                    (node == NULL ? (const xmlChar *) "nothing" : node->name), | 
 | 		   NULL); | 
 |         return (NULL); | 
 |     } | 
 |     if (ret != def) { | 
 |         if (def->nameClass == NULL) { | 
 |             def->nameClass = ret; | 
 |         } else { | 
 |             tmp = def->nameClass; | 
 |             while (tmp->next != NULL) { | 
 |                 tmp = tmp->next; | 
 |             } | 
 |             tmp->next = ret; | 
 |         } | 
 |     } | 
 |     return (ret); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGParseElement: | 
 |  * @ctxt:  a Relax-NG parser context | 
 |  * @node:  the element node | 
 |  * | 
 |  * parse the content of a RelaxNG element node. | 
 |  * | 
 |  * Returns the definition pointer or NULL in case of error. | 
 |  */ | 
 | static xmlRelaxNGDefinePtr | 
 | xmlRelaxNGParseElement(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) | 
 | { | 
 |     xmlRelaxNGDefinePtr ret, cur, last; | 
 |     xmlNodePtr child; | 
 |     const xmlChar *olddefine; | 
 |  | 
 |     ret = xmlRelaxNGNewDefine(ctxt, node); | 
 |     if (ret == NULL) | 
 |         return (NULL); | 
 |     ret->type = XML_RELAXNG_ELEMENT; | 
 |     ret->parent = ctxt->def; | 
 |     child = node->children; | 
 |     if (child == NULL) { | 
 |         xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_EMPTY, | 
 |                    "xmlRelaxNGParseElement: element has no children\n", | 
 |                    NULL, NULL); | 
 |         return (ret); | 
 |     } | 
 |     cur = xmlRelaxNGParseNameClass(ctxt, child, ret); | 
 |     if (cur != NULL) | 
 |         child = child->next; | 
 |  | 
 |     if (child == NULL) { | 
 |         xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_NO_CONTENT, | 
 |                    "xmlRelaxNGParseElement: element has no content\n", | 
 |                    NULL, NULL); | 
 |         return (ret); | 
 |     } | 
 |     olddefine = ctxt->define; | 
 |     ctxt->define = NULL; | 
 |     last = NULL; | 
 |     while (child != NULL) { | 
 |         cur = xmlRelaxNGParsePattern(ctxt, child); | 
 |         if (cur != NULL) { | 
 |             cur->parent = ret; | 
 |             switch (cur->type) { | 
 |                 case XML_RELAXNG_EMPTY: | 
 |                 case XML_RELAXNG_NOT_ALLOWED: | 
 |                 case XML_RELAXNG_TEXT: | 
 |                 case XML_RELAXNG_ELEMENT: | 
 |                 case XML_RELAXNG_DATATYPE: | 
 |                 case XML_RELAXNG_VALUE: | 
 |                 case XML_RELAXNG_LIST: | 
 |                 case XML_RELAXNG_REF: | 
 |                 case XML_RELAXNG_PARENTREF: | 
 |                 case XML_RELAXNG_EXTERNALREF: | 
 |                 case XML_RELAXNG_DEF: | 
 |                 case XML_RELAXNG_ZEROORMORE: | 
 |                 case XML_RELAXNG_ONEORMORE: | 
 |                 case XML_RELAXNG_OPTIONAL: | 
 |                 case XML_RELAXNG_CHOICE: | 
 |                 case XML_RELAXNG_GROUP: | 
 |                 case XML_RELAXNG_INTERLEAVE: | 
 |                     if (last == NULL) { | 
 |                         ret->content = last = cur; | 
 |                     } else { | 
 |                         if ((last->type == XML_RELAXNG_ELEMENT) && | 
 |                             (ret->content == last)) { | 
 |                             ret->content = xmlRelaxNGNewDefine(ctxt, node); | 
 |                             if (ret->content != NULL) { | 
 |                                 ret->content->type = XML_RELAXNG_GROUP; | 
 |                                 ret->content->content = last; | 
 |                             } else { | 
 |                                 ret->content = last; | 
 |                             } | 
 |                         } | 
 |                         last->next = cur; | 
 |                         last = cur; | 
 |                     } | 
 |                     break; | 
 |                 case XML_RELAXNG_ATTRIBUTE: | 
 |                     cur->next = ret->attrs; | 
 |                     ret->attrs = cur; | 
 |                     break; | 
 |                 case XML_RELAXNG_START: | 
 |                     xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_CONTENT, | 
 |                                "RNG Internal error, start found in element\n", | 
 |                                NULL, NULL); | 
 |                     break; | 
 |                 case XML_RELAXNG_PARAM: | 
 |                     xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_CONTENT, | 
 |                                "RNG Internal error, param found in element\n", | 
 |                                NULL, NULL); | 
 |                     break; | 
 |                 case XML_RELAXNG_EXCEPT: | 
 |                     xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_CONTENT, | 
 |                                "RNG Internal error, except found in element\n", | 
 |                                NULL, NULL); | 
 |                     break; | 
 |                 case XML_RELAXNG_NOOP: | 
 |                     xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_CONTENT, | 
 |                                "RNG Internal error, noop found in element\n", | 
 |                                NULL, NULL); | 
 |                     break; | 
 |             } | 
 |         } | 
 |         child = child->next; | 
 |     } | 
 |     ctxt->define = olddefine; | 
 |     return (ret); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGParsePatterns: | 
 |  * @ctxt:  a Relax-NG parser context | 
 |  * @nodes:  list of nodes | 
 |  * @group:  use an implicit <group> for elements | 
 |  * | 
 |  * parse the content of a RelaxNG start node. | 
 |  * | 
 |  * Returns the definition pointer or NULL in case of error. | 
 |  */ | 
 | static xmlRelaxNGDefinePtr | 
 | xmlRelaxNGParsePatterns(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes, | 
 |                         int group) | 
 | { | 
 |     xmlRelaxNGDefinePtr def = NULL, last = NULL, cur, parent; | 
 |  | 
 |     parent = ctxt->def; | 
 |     while (nodes != NULL) { | 
 |         if (IS_RELAXNG(nodes, "element")) { | 
 |             cur = xmlRelaxNGParseElement(ctxt, nodes); | 
 |             if (def == NULL) { | 
 |                 def = last = cur; | 
 |             } else { | 
 |                 if ((group == 1) && (def->type == XML_RELAXNG_ELEMENT) && | 
 |                     (def == last)) { | 
 |                     def = xmlRelaxNGNewDefine(ctxt, nodes); | 
 |                     def->type = XML_RELAXNG_GROUP; | 
 |                     def->content = last; | 
 |                 } | 
 |                 last->next = cur; | 
 |                 last = cur; | 
 |             } | 
 |             cur->parent = parent; | 
 |         } else { | 
 |             cur = xmlRelaxNGParsePattern(ctxt, nodes); | 
 |             if (cur != NULL) { | 
 |                 if (def == NULL) { | 
 |                     def = last = cur; | 
 |                 } else { | 
 |                     last->next = cur; | 
 |                     last = cur; | 
 |                 } | 
 |             } | 
 |         } | 
 |         nodes = nodes->next; | 
 |     } | 
 |     return (def); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGParseStart: | 
 |  * @ctxt:  a Relax-NG parser context | 
 |  * @nodes:  start children nodes | 
 |  * | 
 |  * parse the content of a RelaxNG start node. | 
 |  * | 
 |  * Returns 0 in case of success, -1 in case of error | 
 |  */ | 
 | static int | 
 | xmlRelaxNGParseStart(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes) | 
 | { | 
 |     int ret = 0; | 
 |     xmlRelaxNGDefinePtr def = NULL, last; | 
 |  | 
 |     if (nodes == NULL) { | 
 |         xmlRngPErr(ctxt, nodes, XML_RNGP_START_EMPTY, "start has no children\n", | 
 |                    NULL, NULL); | 
 |         return (-1); | 
 |     } | 
 |     if (IS_RELAXNG(nodes, "empty")) { | 
 |         def = xmlRelaxNGNewDefine(ctxt, nodes); | 
 |         if (def == NULL) | 
 |             return (-1); | 
 |         def->type = XML_RELAXNG_EMPTY; | 
 |         if (nodes->children != NULL) { | 
 |             xmlRngPErr(ctxt, nodes, XML_RNGP_EMPTY_CONTENT, | 
 |                        "element empty is not empty\n", NULL, NULL); | 
 |         } | 
 |     } else if (IS_RELAXNG(nodes, "notAllowed")) { | 
 |         def = xmlRelaxNGNewDefine(ctxt, nodes); | 
 |         if (def == NULL) | 
 |             return (-1); | 
 |         def->type = XML_RELAXNG_NOT_ALLOWED; | 
 |         if (nodes->children != NULL) { | 
 |             xmlRngPErr(ctxt, nodes, XML_RNGP_NOTALLOWED_NOT_EMPTY, | 
 |                        "element notAllowed is not empty\n", NULL, NULL); | 
 |         } | 
 |     } else { | 
 |         def = xmlRelaxNGParsePatterns(ctxt, nodes, 1); | 
 |     } | 
 |     if (ctxt->grammar->start != NULL) { | 
 |         last = ctxt->grammar->start; | 
 |         while (last->next != NULL) | 
 |             last = last->next; | 
 |         last->next = def; | 
 |     } else { | 
 |         ctxt->grammar->start = def; | 
 |     } | 
 |     nodes = nodes->next; | 
 |     if (nodes != NULL) { | 
 |         xmlRngPErr(ctxt, nodes, XML_RNGP_START_CONTENT, | 
 |                    "start more than one children\n", NULL, NULL); | 
 |         return (-1); | 
 |     } | 
 |     return (ret); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGParseGrammarContent: | 
 |  * @ctxt:  a Relax-NG parser context | 
 |  * @nodes:  grammar children nodes | 
 |  * | 
 |  * parse the content of a RelaxNG grammar node. | 
 |  * | 
 |  * Returns 0 in case of success, -1 in case of error | 
 |  */ | 
 | static int | 
 | xmlRelaxNGParseGrammarContent(xmlRelaxNGParserCtxtPtr ctxt, | 
 |                               xmlNodePtr nodes) | 
 | { | 
 |     int ret = 0, tmp; | 
 |  | 
 |     if (nodes == NULL) { | 
 |         xmlRngPErr(ctxt, nodes, XML_RNGP_GRAMMAR_EMPTY, | 
 |                    "grammar has no children\n", NULL, NULL); | 
 |         return (-1); | 
 |     } | 
 |     while (nodes != NULL) { | 
 |         if (IS_RELAXNG(nodes, "start")) { | 
 |             if (nodes->children == NULL) { | 
 |                 xmlRngPErr(ctxt, nodes, XML_RNGP_START_EMPTY, | 
 |                            "start has no children\n", NULL, NULL); | 
 |             } else { | 
 |                 tmp = xmlRelaxNGParseStart(ctxt, nodes->children); | 
 |                 if (tmp != 0) | 
 |                     ret = -1; | 
 |             } | 
 |         } else if (IS_RELAXNG(nodes, "define")) { | 
 |             tmp = xmlRelaxNGParseDefine(ctxt, nodes); | 
 |             if (tmp != 0) | 
 |                 ret = -1; | 
 |         } else if (IS_RELAXNG(nodes, "include")) { | 
 |             tmp = xmlRelaxNGParseInclude(ctxt, nodes); | 
 |             if (tmp != 0) | 
 |                 ret = -1; | 
 |         } else { | 
 |             xmlRngPErr(ctxt, nodes, XML_RNGP_GRAMMAR_CONTENT, | 
 |                        "grammar has unexpected child %s\n", nodes->name, | 
 |                        NULL); | 
 |             ret = -1; | 
 |         } | 
 |         nodes = nodes->next; | 
 |     } | 
 |     return (ret); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGCheckReference: | 
 |  * @ref:  the ref | 
 |  * @ctxt:  a Relax-NG parser context | 
 |  * @name:  the name associated to the defines | 
 |  * | 
 |  * Applies the 4.17. combine attribute rule for all the define | 
 |  * element of a given grammar using the same name. | 
 |  */ | 
 | static void | 
 | xmlRelaxNGCheckReference(xmlRelaxNGDefinePtr ref, | 
 |                          xmlRelaxNGParserCtxtPtr ctxt, | 
 |                          const xmlChar * name) | 
 | { | 
 |     xmlRelaxNGGrammarPtr grammar; | 
 |     xmlRelaxNGDefinePtr def, cur; | 
 |  | 
 |     /* | 
 |      * Those rules don't apply to imported ref from xmlRelaxNGParseImportRef | 
 |      */ | 
 |     if (ref->dflags & IS_EXTERNAL_REF) | 
 |         return; | 
 |  | 
 |     grammar = ctxt->grammar; | 
 |     if (grammar == NULL) { | 
 |         xmlRngPErr(ctxt, ref->node, XML_ERR_INTERNAL_ERROR, | 
 |                    "Internal error: no grammar in CheckReference %s\n", | 
 |                    name, NULL); | 
 |         return; | 
 |     } | 
 |     if (ref->content != NULL) { | 
 |         xmlRngPErr(ctxt, ref->node, XML_ERR_INTERNAL_ERROR, | 
 |                    "Internal error: reference has content in CheckReference %s\n", | 
 |                    name, NULL); | 
 |         return; | 
 |     } | 
 |     if (grammar->defs != NULL) { | 
 |         def = xmlHashLookup(grammar->defs, name); | 
 |         if (def != NULL) { | 
 |             cur = ref; | 
 |             while (cur != NULL) { | 
 |                 cur->content = def; | 
 |                 cur = cur->nextHash; | 
 |             } | 
 |         } else { | 
 |             xmlRngPErr(ctxt, ref->node, XML_RNGP_REF_NO_DEF, | 
 |                        "Reference %s has no matching definition\n", name, | 
 |                        NULL); | 
 |         } | 
 |     } else { | 
 |         xmlRngPErr(ctxt, ref->node, XML_RNGP_REF_NO_DEF, | 
 |                    "Reference %s has no matching definition\n", name, | 
 |                    NULL); | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGCheckCombine: | 
 |  * @define:  the define(s) list | 
 |  * @ctxt:  a Relax-NG parser context | 
 |  * @name:  the name associated to the defines | 
 |  * | 
 |  * Applies the 4.17. combine attribute rule for all the define | 
 |  * element of a given grammar using the same name. | 
 |  */ | 
 | static void | 
 | xmlRelaxNGCheckCombine(xmlRelaxNGDefinePtr define, | 
 |                        xmlRelaxNGParserCtxtPtr ctxt, const xmlChar * name) | 
 | { | 
 |     xmlChar *combine; | 
 |     int choiceOrInterleave = -1; | 
 |     int missing = 0; | 
 |     xmlRelaxNGDefinePtr cur, last, tmp, tmp2; | 
 |  | 
 |     if (define->nextHash == NULL) | 
 |         return; | 
 |     cur = define; | 
 |     while (cur != NULL) { | 
 |         combine = xmlGetProp(cur->node, BAD_CAST "combine"); | 
 |         if (combine != NULL) { | 
 |             if (xmlStrEqual(combine, BAD_CAST "choice")) { | 
 |                 if (choiceOrInterleave == -1) | 
 |                     choiceOrInterleave = 1; | 
 |                 else if (choiceOrInterleave == 0) { | 
 |                     xmlRngPErr(ctxt, define->node, XML_RNGP_DEF_CHOICE_AND_INTERLEAVE, | 
 |                                "Defines for %s use both 'choice' and 'interleave'\n", | 
 |                                name, NULL); | 
 |                 } | 
 |             } else if (xmlStrEqual(combine, BAD_CAST "interleave")) { | 
 |                 if (choiceOrInterleave == -1) | 
 |                     choiceOrInterleave = 0; | 
 |                 else if (choiceOrInterleave == 1) { | 
 |                     xmlRngPErr(ctxt, define->node, XML_RNGP_DEF_CHOICE_AND_INTERLEAVE, | 
 |                                "Defines for %s use both 'choice' and 'interleave'\n", | 
 |                                name, NULL); | 
 |                 } | 
 |             } else { | 
 |                 xmlRngPErr(ctxt, define->node, XML_RNGP_UNKNOWN_COMBINE, | 
 |                            "Defines for %s use unknown combine value '%s''\n", | 
 |                            name, combine); | 
 |             } | 
 |             xmlFree(combine); | 
 |         } else { | 
 |             if (missing == 0) | 
 |                 missing = 1; | 
 |             else { | 
 |                 xmlRngPErr(ctxt, define->node, XML_RNGP_NEED_COMBINE, | 
 |                            "Some defines for %s needs the combine attribute\n", | 
 |                            name, NULL); | 
 |             } | 
 |         } | 
 |  | 
 |         cur = cur->nextHash; | 
 |     } | 
 | #ifdef DEBUG | 
 |     xmlGenericError(xmlGenericErrorContext, | 
 |                     "xmlRelaxNGCheckCombine(): merging %s defines: %d\n", | 
 |                     name, choiceOrInterleave); | 
 | #endif | 
 |     if (choiceOrInterleave == -1) | 
 |         choiceOrInterleave = 0; | 
 |     cur = xmlRelaxNGNewDefine(ctxt, define->node); | 
 |     if (cur == NULL) | 
 |         return; | 
 |     if (choiceOrInterleave == 0) | 
 |         cur->type = XML_RELAXNG_INTERLEAVE; | 
 |     else | 
 |         cur->type = XML_RELAXNG_CHOICE; | 
 |     tmp = define; | 
 |     last = NULL; | 
 |     while (tmp != NULL) { | 
 |         if (tmp->content != NULL) { | 
 |             if (tmp->content->next != NULL) { | 
 |                 /* | 
 |                  * we need first to create a wrapper. | 
 |                  */ | 
 |                 tmp2 = xmlRelaxNGNewDefine(ctxt, tmp->content->node); | 
 |                 if (tmp2 == NULL) | 
 |                     break; | 
 |                 tmp2->type = XML_RELAXNG_GROUP; | 
 |                 tmp2->content = tmp->content; | 
 |             } else { | 
 |                 tmp2 = tmp->content; | 
 |             } | 
 |             if (last == NULL) { | 
 |                 cur->content = tmp2; | 
 |             } else { | 
 |                 last->next = tmp2; | 
 |             } | 
 |             last = tmp2; | 
 |         } | 
 |         tmp->content = cur; | 
 |         tmp = tmp->nextHash; | 
 |     } | 
 |     define->content = cur; | 
 |     if (choiceOrInterleave == 0) { | 
 |         if (ctxt->interleaves == NULL) | 
 |             ctxt->interleaves = xmlHashCreate(10); | 
 |         if (ctxt->interleaves == NULL) { | 
 |             xmlRngPErr(ctxt, define->node, XML_RNGP_INTERLEAVE_CREATE_FAILED, | 
 |                        "Failed to create interleaves hash table\n", NULL, | 
 |                        NULL); | 
 |         } else { | 
 |             char tmpname[32]; | 
 |  | 
 |             snprintf(tmpname, 32, "interleave%d", ctxt->nbInterleaves++); | 
 |             if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST tmpname, cur) < | 
 |                 0) { | 
 |                 xmlRngPErr(ctxt, define->node, XML_RNGP_INTERLEAVE_CREATE_FAILED, | 
 |                            "Failed to add %s to hash table\n", | 
 | 			   (const xmlChar *) tmpname, NULL); | 
 |             } | 
 |         } | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGCombineStart: | 
 |  * @ctxt:  a Relax-NG parser context | 
 |  * @grammar:  the grammar | 
 |  * | 
 |  * Applies the 4.17. combine rule for all the start | 
 |  * element of a given grammar. | 
 |  */ | 
 | static void | 
 | xmlRelaxNGCombineStart(xmlRelaxNGParserCtxtPtr ctxt, | 
 |                        xmlRelaxNGGrammarPtr grammar) | 
 | { | 
 |     xmlRelaxNGDefinePtr starts; | 
 |     xmlChar *combine; | 
 |     int choiceOrInterleave = -1; | 
 |     int missing = 0; | 
 |     xmlRelaxNGDefinePtr cur; | 
 |  | 
 |     starts = grammar->start; | 
 |     if ((starts == NULL) || (starts->next == NULL)) | 
 |         return; | 
 |     cur = starts; | 
 |     while (cur != NULL) { | 
 |         if ((cur->node == NULL) || (cur->node->parent == NULL) || | 
 |             (!xmlStrEqual(cur->node->parent->name, BAD_CAST "start"))) { | 
 |             combine = NULL; | 
 |             xmlRngPErr(ctxt, cur->node, XML_RNGP_START_MISSING, | 
 |                        "Internal error: start element not found\n", NULL, | 
 |                        NULL); | 
 |         } else { | 
 |             combine = xmlGetProp(cur->node->parent, BAD_CAST "combine"); | 
 |         } | 
 |  | 
 |         if (combine != NULL) { | 
 |             if (xmlStrEqual(combine, BAD_CAST "choice")) { | 
 |                 if (choiceOrInterleave == -1) | 
 |                     choiceOrInterleave = 1; | 
 |                 else if (choiceOrInterleave == 0) { | 
 |                     xmlRngPErr(ctxt, cur->node, XML_RNGP_START_CHOICE_AND_INTERLEAVE, | 
 |                                "<start> use both 'choice' and 'interleave'\n", | 
 |                                NULL, NULL); | 
 |                 } | 
 |             } else if (xmlStrEqual(combine, BAD_CAST "interleave")) { | 
 |                 if (choiceOrInterleave == -1) | 
 |                     choiceOrInterleave = 0; | 
 |                 else if (choiceOrInterleave == 1) { | 
 |                     xmlRngPErr(ctxt, cur->node, XML_RNGP_START_CHOICE_AND_INTERLEAVE, | 
 |                                "<start> use both 'choice' and 'interleave'\n", | 
 |                                NULL, NULL); | 
 |                 } | 
 |             } else { | 
 |                 xmlRngPErr(ctxt, cur->node, XML_RNGP_UNKNOWN_COMBINE, | 
 |                            "<start> uses unknown combine value '%s''\n", | 
 |                            combine, NULL); | 
 |             } | 
 |             xmlFree(combine); | 
 |         } else { | 
 |             if (missing == 0) | 
 |                 missing = 1; | 
 |             else { | 
 |                 xmlRngPErr(ctxt, cur->node, XML_RNGP_NEED_COMBINE, | 
 |                            "Some <start> element miss the combine attribute\n", | 
 |                            NULL, NULL); | 
 |             } | 
 |         } | 
 |  | 
 |         cur = cur->next; | 
 |     } | 
 | #ifdef DEBUG | 
 |     xmlGenericError(xmlGenericErrorContext, | 
 |                     "xmlRelaxNGCombineStart(): merging <start>: %d\n", | 
 |                     choiceOrInterleave); | 
 | #endif | 
 |     if (choiceOrInterleave == -1) | 
 |         choiceOrInterleave = 0; | 
 |     cur = xmlRelaxNGNewDefine(ctxt, starts->node); | 
 |     if (cur == NULL) | 
 |         return; | 
 |     if (choiceOrInterleave == 0) | 
 |         cur->type = XML_RELAXNG_INTERLEAVE; | 
 |     else | 
 |         cur->type = XML_RELAXNG_CHOICE; | 
 |     cur->content = grammar->start; | 
 |     grammar->start = cur; | 
 |     if (choiceOrInterleave == 0) { | 
 |         if (ctxt->interleaves == NULL) | 
 |             ctxt->interleaves = xmlHashCreate(10); | 
 |         if (ctxt->interleaves == NULL) { | 
 |             xmlRngPErr(ctxt, cur->node, XML_RNGP_INTERLEAVE_CREATE_FAILED, | 
 |                        "Failed to create interleaves hash table\n", NULL, | 
 |                        NULL); | 
 |         } else { | 
 |             char tmpname[32]; | 
 |  | 
 |             snprintf(tmpname, 32, "interleave%d", ctxt->nbInterleaves++); | 
 |             if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST tmpname, cur) < | 
 |                 0) { | 
 |                 xmlRngPErr(ctxt, cur->node, XML_RNGP_INTERLEAVE_CREATE_FAILED, | 
 |                            "Failed to add %s to hash table\n", | 
 | 			   (const xmlChar *) tmpname, NULL); | 
 |             } | 
 |         } | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGCheckCycles: | 
 |  * @ctxt:  a Relax-NG parser context | 
 |  * @nodes:  grammar children nodes | 
 |  * @depth:  the counter | 
 |  * | 
 |  * Check for cycles. | 
 |  * | 
 |  * Returns 0 if check passed, and -1 in case of error | 
 |  */ | 
 | static int | 
 | xmlRelaxNGCheckCycles(xmlRelaxNGParserCtxtPtr ctxt, | 
 |                       xmlRelaxNGDefinePtr cur, int depth) | 
 | { | 
 |     int ret = 0; | 
 |  | 
 |     while ((ret == 0) && (cur != NULL)) { | 
 |         if ((cur->type == XML_RELAXNG_REF) || | 
 |             (cur->type == XML_RELAXNG_PARENTREF)) { | 
 |             if (cur->depth == -1) { | 
 |                 cur->depth = depth; | 
 |                 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth); | 
 |                 cur->depth = -2; | 
 |             } else if (depth == cur->depth) { | 
 |                 xmlRngPErr(ctxt, cur->node, XML_RNGP_REF_CYCLE, | 
 |                            "Detected a cycle in %s references\n", | 
 |                            cur->name, NULL); | 
 |                 return (-1); | 
 |             } | 
 |         } else if (cur->type == XML_RELAXNG_ELEMENT) { | 
 |             ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth + 1); | 
 |         } else { | 
 |             ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth); | 
 |         } | 
 |         cur = cur->next; | 
 |     } | 
 |     return (ret); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGTryUnlink: | 
 |  * @ctxt:  a Relax-NG parser context | 
 |  * @cur:  the definition to unlink | 
 |  * @parent:  the parent definition | 
 |  * @prev:  the previous sibling definition | 
 |  * | 
 |  * Try to unlink a definition. If not possble make it a NOOP | 
 |  * | 
 |  * Returns the new prev definition | 
 |  */ | 
 | static xmlRelaxNGDefinePtr | 
 | xmlRelaxNGTryUnlink(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED, | 
 |                     xmlRelaxNGDefinePtr cur, | 
 |                     xmlRelaxNGDefinePtr parent, xmlRelaxNGDefinePtr prev) | 
 | { | 
 |     if (prev != NULL) { | 
 |         prev->next = cur->next; | 
 |     } else { | 
 |         if (parent != NULL) { | 
 |             if (parent->content == cur) | 
 |                 parent->content = cur->next; | 
 |             else if (parent->attrs == cur) | 
 |                 parent->attrs = cur->next; | 
 |             else if (parent->nameClass == cur) | 
 |                 parent->nameClass = cur->next; | 
 |         } else { | 
 |             cur->type = XML_RELAXNG_NOOP; | 
 |             prev = cur; | 
 |         } | 
 |     } | 
 |     return (prev); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGSimplify: | 
 |  * @ctxt:  a Relax-NG parser context | 
 |  * @nodes:  grammar children nodes | 
 |  * | 
 |  * Check for simplification of empty and notAllowed | 
 |  */ | 
 | static void | 
 | xmlRelaxNGSimplify(xmlRelaxNGParserCtxtPtr ctxt, | 
 |                    xmlRelaxNGDefinePtr cur, xmlRelaxNGDefinePtr parent) | 
 | { | 
 |     xmlRelaxNGDefinePtr prev = NULL; | 
 |  | 
 |     while (cur != NULL) { | 
 |         if ((cur->type == XML_RELAXNG_REF) || | 
 |             (cur->type == XML_RELAXNG_PARENTREF)) { | 
 |             if (cur->depth != -3) { | 
 |                 cur->depth = -3; | 
 |                 xmlRelaxNGSimplify(ctxt, cur->content, cur); | 
 |             } | 
 |         } else if (cur->type == XML_RELAXNG_NOT_ALLOWED) { | 
 |             cur->parent = parent; | 
 |             if ((parent != NULL) && | 
 |                 ((parent->type == XML_RELAXNG_ATTRIBUTE) || | 
 |                  (parent->type == XML_RELAXNG_LIST) || | 
 |                  (parent->type == XML_RELAXNG_GROUP) || | 
 |                  (parent->type == XML_RELAXNG_INTERLEAVE) || | 
 |                  (parent->type == XML_RELAXNG_ONEORMORE) || | 
 |                  (parent->type == XML_RELAXNG_ZEROORMORE))) { | 
 |                 parent->type = XML_RELAXNG_NOT_ALLOWED; | 
 |                 break; | 
 |             } | 
 |             if ((parent != NULL) && (parent->type == XML_RELAXNG_CHOICE)) { | 
 |                 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev); | 
 |             } else | 
 |                 prev = cur; | 
 |         } else if (cur->type == XML_RELAXNG_EMPTY) { | 
 |             cur->parent = parent; | 
 |             if ((parent != NULL) && | 
 |                 ((parent->type == XML_RELAXNG_ONEORMORE) || | 
 |                  (parent->type == XML_RELAXNG_ZEROORMORE))) { | 
 |                 parent->type = XML_RELAXNG_EMPTY; | 
 |                 break; | 
 |             } | 
 |             if ((parent != NULL) && | 
 |                 ((parent->type == XML_RELAXNG_GROUP) || | 
 |                  (parent->type == XML_RELAXNG_INTERLEAVE))) { | 
 |                 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev); | 
 |             } else | 
 |                 prev = cur; | 
 |         } else { | 
 |             cur->parent = parent; | 
 |             if (cur->content != NULL) | 
 |                 xmlRelaxNGSimplify(ctxt, cur->content, cur); | 
 |             if ((cur->type != XML_RELAXNG_VALUE) && (cur->attrs != NULL)) | 
 |                 xmlRelaxNGSimplify(ctxt, cur->attrs, cur); | 
 |             if (cur->nameClass != NULL) | 
 |                 xmlRelaxNGSimplify(ctxt, cur->nameClass, cur); | 
 |             /* | 
 |              * On Elements, try to move attribute only generating rules on | 
 |              * the attrs rules. | 
 |              */ | 
 |             if (cur->type == XML_RELAXNG_ELEMENT) { | 
 |                 int attronly; | 
 |                 xmlRelaxNGDefinePtr tmp, pre; | 
 |  | 
 |                 while (cur->content != NULL) { | 
 |                     attronly = | 
 |                         xmlRelaxNGGenerateAttributes(ctxt, cur->content); | 
 |                     if (attronly == 1) { | 
 |                         /* | 
 |                          * migrate cur->content to attrs | 
 |                          */ | 
 |                         tmp = cur->content; | 
 |                         cur->content = tmp->next; | 
 |                         tmp->next = cur->attrs; | 
 |                         cur->attrs = tmp; | 
 |                     } else { | 
 |                         /* | 
 |                          * cur->content can generate elements or text | 
 |                          */ | 
 |                         break; | 
 |                     } | 
 |                 } | 
 |                 pre = cur->content; | 
 |                 while ((pre != NULL) && (pre->next != NULL)) { | 
 |                     tmp = pre->next; | 
 |                     attronly = xmlRelaxNGGenerateAttributes(ctxt, tmp); | 
 |                     if (attronly == 1) { | 
 |                         /* | 
 |                          * migrate tmp to attrs | 
 |                          */ | 
 |                         pre->next = tmp->next; | 
 |                         tmp->next = cur->attrs; | 
 |                         cur->attrs = tmp; | 
 |                     } else { | 
 |                         pre = tmp; | 
 |                     } | 
 |                 } | 
 |             } | 
 |             /* | 
 |              * This may result in a simplification | 
 |              */ | 
 |             if ((cur->type == XML_RELAXNG_GROUP) || | 
 |                 (cur->type == XML_RELAXNG_INTERLEAVE)) { | 
 |                 if (cur->content == NULL) | 
 |                     cur->type = XML_RELAXNG_EMPTY; | 
 |                 else if (cur->content->next == NULL) { | 
 |                     if ((parent == NULL) && (prev == NULL)) { | 
 |                         cur->type = XML_RELAXNG_NOOP; | 
 |                     } else if (prev == NULL) { | 
 |                         parent->content = cur->content; | 
 |                         cur->content->next = cur->next; | 
 |                         cur = cur->content; | 
 |                     } else { | 
 |                         cur->content->next = cur->next; | 
 |                         prev->next = cur->content; | 
 |                         cur = cur->content; | 
 |                     } | 
 |                 } | 
 |             } | 
 |             /* | 
 |              * the current node may have been transformed back | 
 |              */ | 
 |             if ((cur->type == XML_RELAXNG_EXCEPT) && | 
 |                 (cur->content != NULL) && | 
 |                 (cur->content->type == XML_RELAXNG_NOT_ALLOWED)) { | 
 |                 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev); | 
 |             } else if (cur->type == XML_RELAXNG_NOT_ALLOWED) { | 
 |                 if ((parent != NULL) && | 
 |                     ((parent->type == XML_RELAXNG_ATTRIBUTE) || | 
 |                      (parent->type == XML_RELAXNG_LIST) || | 
 |                      (parent->type == XML_RELAXNG_GROUP) || | 
 |                      (parent->type == XML_RELAXNG_INTERLEAVE) || | 
 |                      (parent->type == XML_RELAXNG_ONEORMORE) || | 
 |                      (parent->type == XML_RELAXNG_ZEROORMORE))) { | 
 |                     parent->type = XML_RELAXNG_NOT_ALLOWED; | 
 |                     break; | 
 |                 } | 
 |                 if ((parent != NULL) && | 
 |                     (parent->type == XML_RELAXNG_CHOICE)) { | 
 |                     prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev); | 
 |                 } else | 
 |                     prev = cur; | 
 |             } else if (cur->type == XML_RELAXNG_EMPTY) { | 
 |                 if ((parent != NULL) && | 
 |                     ((parent->type == XML_RELAXNG_ONEORMORE) || | 
 |                      (parent->type == XML_RELAXNG_ZEROORMORE))) { | 
 |                     parent->type = XML_RELAXNG_EMPTY; | 
 |                     break; | 
 |                 } | 
 |                 if ((parent != NULL) && | 
 |                     ((parent->type == XML_RELAXNG_GROUP) || | 
 |                      (parent->type == XML_RELAXNG_INTERLEAVE) || | 
 |                      (parent->type == XML_RELAXNG_CHOICE))) { | 
 |                     prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev); | 
 |                 } else | 
 |                     prev = cur; | 
 |             } else { | 
 |                 prev = cur; | 
 |             } | 
 |         } | 
 |         cur = cur->next; | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGGroupContentType: | 
 |  * @ct1:  the first content type | 
 |  * @ct2:  the second content type | 
 |  * | 
 |  * Try to group 2 content types | 
 |  * | 
 |  * Returns the content type | 
 |  */ | 
 | static xmlRelaxNGContentType | 
 | xmlRelaxNGGroupContentType(xmlRelaxNGContentType ct1, | 
 |                            xmlRelaxNGContentType ct2) | 
 | { | 
 |     if ((ct1 == XML_RELAXNG_CONTENT_ERROR) || | 
 |         (ct2 == XML_RELAXNG_CONTENT_ERROR)) | 
 |         return (XML_RELAXNG_CONTENT_ERROR); | 
 |     if (ct1 == XML_RELAXNG_CONTENT_EMPTY) | 
 |         return (ct2); | 
 |     if (ct2 == XML_RELAXNG_CONTENT_EMPTY) | 
 |         return (ct1); | 
 |     if ((ct1 == XML_RELAXNG_CONTENT_COMPLEX) && | 
 |         (ct2 == XML_RELAXNG_CONTENT_COMPLEX)) | 
 |         return (XML_RELAXNG_CONTENT_COMPLEX); | 
 |     return (XML_RELAXNG_CONTENT_ERROR); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGMaxContentType: | 
 |  * @ct1:  the first content type | 
 |  * @ct2:  the second content type | 
 |  * | 
 |  * Compute the max content-type | 
 |  * | 
 |  * Returns the content type | 
 |  */ | 
 | static xmlRelaxNGContentType | 
 | xmlRelaxNGMaxContentType(xmlRelaxNGContentType ct1, | 
 |                          xmlRelaxNGContentType ct2) | 
 | { | 
 |     if ((ct1 == XML_RELAXNG_CONTENT_ERROR) || | 
 |         (ct2 == XML_RELAXNG_CONTENT_ERROR)) | 
 |         return (XML_RELAXNG_CONTENT_ERROR); | 
 |     if ((ct1 == XML_RELAXNG_CONTENT_SIMPLE) || | 
 |         (ct2 == XML_RELAXNG_CONTENT_SIMPLE)) | 
 |         return (XML_RELAXNG_CONTENT_SIMPLE); | 
 |     if ((ct1 == XML_RELAXNG_CONTENT_COMPLEX) || | 
 |         (ct2 == XML_RELAXNG_CONTENT_COMPLEX)) | 
 |         return (XML_RELAXNG_CONTENT_COMPLEX); | 
 |     return (XML_RELAXNG_CONTENT_EMPTY); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGCheckRules: | 
 |  * @ctxt:  a Relax-NG parser context | 
 |  * @cur:  the current definition | 
 |  * @flags:  some accumulated flags | 
 |  * @ptype:  the parent type | 
 |  * | 
 |  * Check for rules in section 7.1 and 7.2 | 
 |  * | 
 |  * Returns the content type of @cur | 
 |  */ | 
 | static xmlRelaxNGContentType | 
 | xmlRelaxNGCheckRules(xmlRelaxNGParserCtxtPtr ctxt, | 
 |                      xmlRelaxNGDefinePtr cur, int flags, | 
 |                      xmlRelaxNGType ptype) | 
 | { | 
 |     int nflags; | 
 |     xmlRelaxNGContentType ret, tmp, val = XML_RELAXNG_CONTENT_EMPTY; | 
 |  | 
 |     while (cur != NULL) { | 
 |         ret = XML_RELAXNG_CONTENT_EMPTY; | 
 |         if ((cur->type == XML_RELAXNG_REF) || | 
 |             (cur->type == XML_RELAXNG_PARENTREF)) { | 
 |            /* | 
 |             * This should actually be caught by list//element(ref) at the | 
 |             * element boundaries, c.f. Bug #159968 local refs are dropped | 
 |             * in step 4.19. | 
 |             */ | 
 | #if 0 | 
 |             if (flags & XML_RELAXNG_IN_LIST) { | 
 |                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_REF, | 
 |                            "Found forbidden pattern list//ref\n", NULL, | 
 |                            NULL); | 
 |             } | 
 | #endif | 
 |             if (flags & XML_RELAXNG_IN_DATAEXCEPT) { | 
 |                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_REF, | 
 |                            "Found forbidden pattern data/except//ref\n", | 
 |                            NULL, NULL); | 
 |             } | 
 |             if (cur->content == NULL) { | 
 |                 if (cur->type == XML_RELAXNG_PARENTREF) | 
 |                     xmlRngPErr(ctxt, cur->node, XML_RNGP_REF_NO_DEF, | 
 |                                "Internal found no define for parent refs\n", | 
 |                                NULL, NULL); | 
 |                 else | 
 |                     xmlRngPErr(ctxt, cur->node, XML_RNGP_REF_NO_DEF, | 
 |                                "Internal found no define for ref %s\n", | 
 |                                (cur->name ? cur->name: BAD_CAST "null"), NULL); | 
 |             } | 
 |             if (cur->depth > -4) { | 
 |                 cur->depth = -4; | 
 |                 ret = xmlRelaxNGCheckRules(ctxt, cur->content, | 
 |                                            flags, cur->type); | 
 |                 cur->depth = ret - 15; | 
 |             } else if (cur->depth == -4) { | 
 |                 ret = XML_RELAXNG_CONTENT_COMPLEX; | 
 |             } else { | 
 |                 ret = (xmlRelaxNGContentType) (cur->depth + 15); | 
 |             } | 
 |         } else if (cur->type == XML_RELAXNG_ELEMENT) { | 
 |             /* | 
 |              * The 7.3 Attribute derivation rule for groups is plugged there | 
 |              */ | 
 |             xmlRelaxNGCheckGroupAttrs(ctxt, cur); | 
 |             if (flags & XML_RELAXNG_IN_DATAEXCEPT) { | 
 |                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_ELEM, | 
 |                            "Found forbidden pattern data/except//element(ref)\n", | 
 |                            NULL, NULL); | 
 |             } | 
 |             if (flags & XML_RELAXNG_IN_LIST) { | 
 |                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_ELEM, | 
 |                            "Found forbidden pattern list//element(ref)\n", | 
 |                            NULL, NULL); | 
 |             } | 
 |             if (flags & XML_RELAXNG_IN_ATTRIBUTE) { | 
 |                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ATTR_ELEM, | 
 |                            "Found forbidden pattern attribute//element(ref)\n", | 
 |                            NULL, NULL); | 
 |             } | 
 |             if (flags & XML_RELAXNG_IN_ATTRIBUTE) { | 
 |                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ATTR_ELEM, | 
 |                            "Found forbidden pattern attribute//element(ref)\n", | 
 |                            NULL, NULL); | 
 |             } | 
 |             /* | 
 |              * reset since in the simple form elements are only child | 
 |              * of grammar/define | 
 |              */ | 
 |             nflags = 0; | 
 |             ret = | 
 |                 xmlRelaxNGCheckRules(ctxt, cur->attrs, nflags, cur->type); | 
 |             if (ret != XML_RELAXNG_CONTENT_EMPTY) { | 
 |                 xmlRngPErr(ctxt, cur->node, XML_RNGP_ELEM_CONTENT_EMPTY, | 
 |                            "Element %s attributes have a content type error\n", | 
 |                            cur->name, NULL); | 
 |             } | 
 |             ret = | 
 |                 xmlRelaxNGCheckRules(ctxt, cur->content, nflags, | 
 |                                      cur->type); | 
 |             if (ret == XML_RELAXNG_CONTENT_ERROR) { | 
 |                 xmlRngPErr(ctxt, cur->node, XML_RNGP_ELEM_CONTENT_ERROR, | 
 |                            "Element %s has a content type error\n", | 
 |                            cur->name, NULL); | 
 |             } else { | 
 |                 ret = XML_RELAXNG_CONTENT_COMPLEX; | 
 |             } | 
 |         } else if (cur->type == XML_RELAXNG_ATTRIBUTE) { | 
 |             if (flags & XML_RELAXNG_IN_ATTRIBUTE) { | 
 |                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ATTR_ATTR, | 
 |                            "Found forbidden pattern attribute//attribute\n", | 
 |                            NULL, NULL); | 
 |             } | 
 |             if (flags & XML_RELAXNG_IN_LIST) { | 
 |                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_ATTR, | 
 |                            "Found forbidden pattern list//attribute\n", | 
 |                            NULL, NULL); | 
 |             } | 
 |             if (flags & XML_RELAXNG_IN_OOMGROUP) { | 
 |                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ONEMORE_GROUP_ATTR, | 
 |                            "Found forbidden pattern oneOrMore//group//attribute\n", | 
 |                            NULL, NULL); | 
 |             } | 
 |             if (flags & XML_RELAXNG_IN_OOMINTERLEAVE) { | 
 |                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ONEMORE_INTERLEAVE_ATTR, | 
 |                            "Found forbidden pattern oneOrMore//interleave//attribute\n", | 
 |                            NULL, NULL); | 
 |             } | 
 |             if (flags & XML_RELAXNG_IN_DATAEXCEPT) { | 
 |                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_ATTR, | 
 |                            "Found forbidden pattern data/except//attribute\n", | 
 |                            NULL, NULL); | 
 |             } | 
 |             if (flags & XML_RELAXNG_IN_START) { | 
 |                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_ATTR, | 
 |                            "Found forbidden pattern start//attribute\n", | 
 |                            NULL, NULL); | 
 |             } | 
 |             if ((!(flags & XML_RELAXNG_IN_ONEORMORE)) | 
 |                 && (cur->name == NULL)) { | 
 |                 if (cur->ns == NULL) { | 
 |                     xmlRngPErr(ctxt, cur->node, XML_RNGP_ANYNAME_ATTR_ANCESTOR, | 
 |                                "Found anyName attribute without oneOrMore ancestor\n", | 
 |                                NULL, NULL); | 
 |                 } else { | 
 |                     xmlRngPErr(ctxt, cur->node, XML_RNGP_NSNAME_ATTR_ANCESTOR, | 
 |                                "Found nsName attribute without oneOrMore ancestor\n", | 
 |                                NULL, NULL); | 
 |                 } | 
 |             } | 
 |             nflags = flags | XML_RELAXNG_IN_ATTRIBUTE; | 
 |             xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type); | 
 |             ret = XML_RELAXNG_CONTENT_EMPTY; | 
 |         } else if ((cur->type == XML_RELAXNG_ONEORMORE) || | 
 |                    (cur->type == XML_RELAXNG_ZEROORMORE)) { | 
 |             if (flags & XML_RELAXNG_IN_DATAEXCEPT) { | 
 |                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_ONEMORE, | 
 |                            "Found forbidden pattern data/except//oneOrMore\n", | 
 |                            NULL, NULL); | 
 |             } | 
 |             if (flags & XML_RELAXNG_IN_START) { | 
 |                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_ONEMORE, | 
 |                            "Found forbidden pattern start//oneOrMore\n", | 
 |                            NULL, NULL); | 
 |             } | 
 |             nflags = flags | XML_RELAXNG_IN_ONEORMORE; | 
 |             ret = | 
 |                 xmlRelaxNGCheckRules(ctxt, cur->content, nflags, | 
 |                                      cur->type); | 
 |             ret = xmlRelaxNGGroupContentType(ret, ret); | 
 |         } else if (cur->type == XML_RELAXNG_LIST) { | 
 |             if (flags & XML_RELAXNG_IN_LIST) { | 
 |                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_LIST, | 
 |                            "Found forbidden pattern list//list\n", NULL, | 
 |                            NULL); | 
 |             } | 
 |             if (flags & XML_RELAXNG_IN_DATAEXCEPT) { | 
 |                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_LIST, | 
 |                            "Found forbidden pattern data/except//list\n", | 
 |                            NULL, NULL); | 
 |             } | 
 |             if (flags & XML_RELAXNG_IN_START) { | 
 |                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_LIST, | 
 |                            "Found forbidden pattern start//list\n", NULL, | 
 |                            NULL); | 
 |             } | 
 |             nflags = flags | XML_RELAXNG_IN_LIST; | 
 |             ret = | 
 |                 xmlRelaxNGCheckRules(ctxt, cur->content, nflags, | 
 |                                      cur->type); | 
 |         } else if (cur->type == XML_RELAXNG_GROUP) { | 
 |             if (flags & XML_RELAXNG_IN_DATAEXCEPT) { | 
 |                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_GROUP, | 
 |                            "Found forbidden pattern data/except//group\n", | 
 |                            NULL, NULL); | 
 |             } | 
 |             if (flags & XML_RELAXNG_IN_START) { | 
 |                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_GROUP, | 
 |                            "Found forbidden pattern start//group\n", NULL, | 
 |                            NULL); | 
 |             } | 
 |             if (flags & XML_RELAXNG_IN_ONEORMORE) | 
 |                 nflags = flags | XML_RELAXNG_IN_OOMGROUP; | 
 |             else | 
 |                 nflags = flags; | 
 |             ret = | 
 |                 xmlRelaxNGCheckRules(ctxt, cur->content, nflags, | 
 |                                      cur->type); | 
 |             /* | 
 |              * The 7.3 Attribute derivation rule for groups is plugged there | 
 |              */ | 
 |             xmlRelaxNGCheckGroupAttrs(ctxt, cur); | 
 |         } else if (cur->type == XML_RELAXNG_INTERLEAVE) { | 
 |             if (flags & XML_RELAXNG_IN_LIST) { | 
 |                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_INTERLEAVE, | 
 |                            "Found forbidden pattern list//interleave\n", | 
 |                            NULL, NULL); | 
 |             } | 
 |             if (flags & XML_RELAXNG_IN_DATAEXCEPT) { | 
 |                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_INTERLEAVE, | 
 |                            "Found forbidden pattern data/except//interleave\n", | 
 |                            NULL, NULL); | 
 |             } | 
 |             if (flags & XML_RELAXNG_IN_START) { | 
 |                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_INTERLEAVE, | 
 |                            "Found forbidden pattern start//interleave\n", | 
 |                            NULL, NULL); | 
 |             } | 
 |             if (flags & XML_RELAXNG_IN_ONEORMORE) | 
 |                 nflags = flags | XML_RELAXNG_IN_OOMINTERLEAVE; | 
 |             else | 
 |                 nflags = flags; | 
 |             ret = | 
 |                 xmlRelaxNGCheckRules(ctxt, cur->content, nflags, | 
 |                                      cur->type); | 
 |         } else if (cur->type == XML_RELAXNG_EXCEPT) { | 
 |             if ((cur->parent != NULL) && | 
 |                 (cur->parent->type == XML_RELAXNG_DATATYPE)) | 
 |                 nflags = flags | XML_RELAXNG_IN_DATAEXCEPT; | 
 |             else | 
 |                 nflags = flags; | 
 |             ret = | 
 |                 xmlRelaxNGCheckRules(ctxt, cur->content, nflags, | 
 |                                      cur->type); | 
 |         } else if (cur->type == XML_RELAXNG_DATATYPE) { | 
 |             if (flags & XML_RELAXNG_IN_START) { | 
 |                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_DATA, | 
 |                            "Found forbidden pattern start//data\n", NULL, | 
 |                            NULL); | 
 |             } | 
 |             xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type); | 
 |             ret = XML_RELAXNG_CONTENT_SIMPLE; | 
 |         } else if (cur->type == XML_RELAXNG_VALUE) { | 
 |             if (flags & XML_RELAXNG_IN_START) { | 
 |                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_VALUE, | 
 |                            "Found forbidden pattern start//value\n", NULL, | 
 |                            NULL); | 
 |             } | 
 |             xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type); | 
 |             ret = XML_RELAXNG_CONTENT_SIMPLE; | 
 |         } else if (cur->type == XML_RELAXNG_TEXT) { | 
 |             if (flags & XML_RELAXNG_IN_LIST) { | 
 |                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_TEXT, | 
 |                            "Found forbidden pattern list//text\n", NULL, | 
 |                            NULL); | 
 |             } | 
 |             if (flags & XML_RELAXNG_IN_DATAEXCEPT) { | 
 |                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_TEXT, | 
 |                            "Found forbidden pattern data/except//text\n", | 
 |                            NULL, NULL); | 
 |             } | 
 |             if (flags & XML_RELAXNG_IN_START) { | 
 |                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_TEXT, | 
 |                            "Found forbidden pattern start//text\n", NULL, | 
 |                            NULL); | 
 |             } | 
 |             ret = XML_RELAXNG_CONTENT_COMPLEX; | 
 |         } else if (cur->type == XML_RELAXNG_EMPTY) { | 
 |             if (flags & XML_RELAXNG_IN_DATAEXCEPT) { | 
 |                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_EMPTY, | 
 |                            "Found forbidden pattern data/except//empty\n", | 
 |                            NULL, NULL); | 
 |             } | 
 |             if (flags & XML_RELAXNG_IN_START) { | 
 |                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_EMPTY, | 
 |                            "Found forbidden pattern start//empty\n", NULL, | 
 |                            NULL); | 
 |             } | 
 |             ret = XML_RELAXNG_CONTENT_EMPTY; | 
 |         } else if (cur->type == XML_RELAXNG_CHOICE) { | 
 |             xmlRelaxNGCheckChoiceDeterminism(ctxt, cur); | 
 |             ret = | 
 |                 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type); | 
 |         } else { | 
 |             ret = | 
 |                 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type); | 
 |         } | 
 |         cur = cur->next; | 
 |         if (ptype == XML_RELAXNG_GROUP) { | 
 |             val = xmlRelaxNGGroupContentType(val, ret); | 
 |         } else if (ptype == XML_RELAXNG_INTERLEAVE) { | 
 |             /* | 
 |              * TODO: scan complain that tmp is never used, seems on purpose | 
 |              *       need double-checking | 
 |              */ | 
 |             tmp = xmlRelaxNGGroupContentType(val, ret); | 
 |             if (tmp != XML_RELAXNG_CONTENT_ERROR) | 
 |                 tmp = xmlRelaxNGMaxContentType(val, ret); | 
 |         } else if (ptype == XML_RELAXNG_CHOICE) { | 
 |             val = xmlRelaxNGMaxContentType(val, ret); | 
 |         } else if (ptype == XML_RELAXNG_LIST) { | 
 |             val = XML_RELAXNG_CONTENT_SIMPLE; | 
 |         } else if (ptype == XML_RELAXNG_EXCEPT) { | 
 |             if (ret == XML_RELAXNG_CONTENT_ERROR) | 
 |                 val = XML_RELAXNG_CONTENT_ERROR; | 
 |             else | 
 |                 val = XML_RELAXNG_CONTENT_SIMPLE; | 
 |         } else { | 
 |             val = xmlRelaxNGGroupContentType(val, ret); | 
 |         } | 
 |  | 
 |     } | 
 |     return (val); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGParseGrammar: | 
 |  * @ctxt:  a Relax-NG parser context | 
 |  * @nodes:  grammar children nodes | 
 |  * | 
 |  * parse a Relax-NG <grammar> node | 
 |  * | 
 |  * Returns the internal xmlRelaxNGGrammarPtr built or | 
 |  *         NULL in case of error | 
 |  */ | 
 | static xmlRelaxNGGrammarPtr | 
 | xmlRelaxNGParseGrammar(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes) | 
 | { | 
 |     xmlRelaxNGGrammarPtr ret, tmp, old; | 
 |  | 
 | #ifdef DEBUG_GRAMMAR | 
 |     xmlGenericError(xmlGenericErrorContext, "Parsing a new grammar\n"); | 
 | #endif | 
 |  | 
 |     ret = xmlRelaxNGNewGrammar(ctxt); | 
 |     if (ret == NULL) | 
 |         return (NULL); | 
 |  | 
 |     /* | 
 |      * Link the new grammar in the tree | 
 |      */ | 
 |     ret->parent = ctxt->grammar; | 
 |     if (ctxt->grammar != NULL) { | 
 |         tmp = ctxt->grammar->children; | 
 |         if (tmp == NULL) { | 
 |             ctxt->grammar->children = ret; | 
 |         } else { | 
 |             while (tmp->next != NULL) | 
 |                 tmp = tmp->next; | 
 |             tmp->next = ret; | 
 |         } | 
 |     } | 
 |  | 
 |     old = ctxt->grammar; | 
 |     ctxt->grammar = ret; | 
 |     xmlRelaxNGParseGrammarContent(ctxt, nodes); | 
 |     ctxt->grammar = ret; | 
 |     if (ctxt->grammar == NULL) { | 
 |         xmlRngPErr(ctxt, nodes, XML_RNGP_GRAMMAR_CONTENT, | 
 |                    "Failed to parse <grammar> content\n", NULL, NULL); | 
 |     } else if (ctxt->grammar->start == NULL) { | 
 |         xmlRngPErr(ctxt, nodes, XML_RNGP_GRAMMAR_NO_START, | 
 |                    "Element <grammar> has no <start>\n", NULL, NULL); | 
 |     } | 
 |  | 
 |     /* | 
 |      * Apply 4.17 mergingd rules to defines and starts | 
 |      */ | 
 |     xmlRelaxNGCombineStart(ctxt, ret); | 
 |     if (ret->defs != NULL) { | 
 |         xmlHashScan(ret->defs, (xmlHashScanner) xmlRelaxNGCheckCombine, | 
 |                     ctxt); | 
 |     } | 
 |  | 
 |     /* | 
 |      * link together defines and refs in this grammar | 
 |      */ | 
 |     if (ret->refs != NULL) { | 
 |         xmlHashScan(ret->refs, (xmlHashScanner) xmlRelaxNGCheckReference, | 
 |                     ctxt); | 
 |     } | 
 |  | 
 |  | 
 |     /* @@@@ */ | 
 |  | 
 |     ctxt->grammar = old; | 
 |     return (ret); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGParseDocument: | 
 |  * @ctxt:  a Relax-NG parser context | 
 |  * @node:  the root node of the RelaxNG schema | 
 |  * | 
 |  * parse a Relax-NG definition resource and build an internal | 
 |  * xmlRelaxNG struture which can be used to validate instances. | 
 |  * | 
 |  * Returns the internal XML RelaxNG structure built or | 
 |  *         NULL in case of error | 
 |  */ | 
 | static xmlRelaxNGPtr | 
 | xmlRelaxNGParseDocument(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) | 
 | { | 
 |     xmlRelaxNGPtr schema = NULL; | 
 |     const xmlChar *olddefine; | 
 |     xmlRelaxNGGrammarPtr old; | 
 |  | 
 |     if ((ctxt == NULL) || (node == NULL)) | 
 |         return (NULL); | 
 |  | 
 |     schema = xmlRelaxNGNewRelaxNG(ctxt); | 
 |     if (schema == NULL) | 
 |         return (NULL); | 
 |  | 
 |     olddefine = ctxt->define; | 
 |     ctxt->define = NULL; | 
 |     if (IS_RELAXNG(node, "grammar")) { | 
 |         schema->topgrammar = xmlRelaxNGParseGrammar(ctxt, node->children); | 
 |     } else { | 
 |         xmlRelaxNGGrammarPtr tmp, ret; | 
 |  | 
 |         schema->topgrammar = ret = xmlRelaxNGNewGrammar(ctxt); | 
 |         if (schema->topgrammar == NULL) { | 
 |             return (schema); | 
 |         } | 
 |         /* | 
 |          * Link the new grammar in the tree | 
 |          */ | 
 |         ret->parent = ctxt->grammar; | 
 |         if (ctxt->grammar != NULL) { | 
 |             tmp = ctxt->grammar->children; | 
 |             if (tmp == NULL) { | 
 |                 ctxt->grammar->children = ret; | 
 |             } else { | 
 |                 while (tmp->next != NULL) | 
 |                     tmp = tmp->next; | 
 |                 tmp->next = ret; | 
 |             } | 
 |         } | 
 |         old = ctxt->grammar; | 
 |         ctxt->grammar = ret; | 
 |         xmlRelaxNGParseStart(ctxt, node); | 
 |         if (old != NULL) | 
 |             ctxt->grammar = old; | 
 |     } | 
 |     ctxt->define = olddefine; | 
 |     if (schema->topgrammar->start != NULL) { | 
 |         xmlRelaxNGCheckCycles(ctxt, schema->topgrammar->start, 0); | 
 |         if ((ctxt->flags & XML_RELAXNG_IN_EXTERNALREF) == 0) { | 
 |             xmlRelaxNGSimplify(ctxt, schema->topgrammar->start, NULL); | 
 |             while ((schema->topgrammar->start != NULL) && | 
 |                    (schema->topgrammar->start->type == XML_RELAXNG_NOOP) && | 
 |                    (schema->topgrammar->start->next != NULL)) | 
 |                 schema->topgrammar->start = | 
 |                     schema->topgrammar->start->content; | 
 |             xmlRelaxNGCheckRules(ctxt, schema->topgrammar->start, | 
 |                                  XML_RELAXNG_IN_START, XML_RELAXNG_NOOP); | 
 |         } | 
 |     } | 
 | #ifdef DEBUG | 
 |     if (schema == NULL) | 
 |         xmlGenericError(xmlGenericErrorContext, | 
 |                         "xmlRelaxNGParseDocument() failed\n"); | 
 | #endif | 
 |  | 
 |     return (schema); | 
 | } | 
 |  | 
 | /************************************************************************ | 
 |  * 									* | 
 |  * 			Reading RelaxNGs				* | 
 |  * 									* | 
 |  ************************************************************************/ | 
 |  | 
 | /** | 
 |  * xmlRelaxNGNewParserCtxt: | 
 |  * @URL:  the location of the schema | 
 |  * | 
 |  * Create an XML RelaxNGs parse context for that file/resource expected | 
 |  * to contain an XML RelaxNGs file. | 
 |  * | 
 |  * Returns the parser context or NULL in case of error | 
 |  */ | 
 | xmlRelaxNGParserCtxtPtr | 
 | xmlRelaxNGNewParserCtxt(const char *URL) | 
 | { | 
 |     xmlRelaxNGParserCtxtPtr ret; | 
 |  | 
 |     if (URL == NULL) | 
 |         return (NULL); | 
 |  | 
 |     ret = | 
 |         (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt)); | 
 |     if (ret == NULL) { | 
 |         xmlRngPErrMemory(NULL, "building parser\n"); | 
 |         return (NULL); | 
 |     } | 
 |     memset(ret, 0, sizeof(xmlRelaxNGParserCtxt)); | 
 |     ret->URL = xmlStrdup((const xmlChar *) URL); | 
 |     ret->error = xmlGenericError; | 
 |     ret->userData = xmlGenericErrorContext; | 
 |     return (ret); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGNewMemParserCtxt: | 
 |  * @buffer:  a pointer to a char array containing the schemas | 
 |  * @size:  the size of the array | 
 |  * | 
 |  * Create an XML RelaxNGs parse context for that memory buffer expected | 
 |  * to contain an XML RelaxNGs file. | 
 |  * | 
 |  * Returns the parser context or NULL in case of error | 
 |  */ | 
 | xmlRelaxNGParserCtxtPtr | 
 | xmlRelaxNGNewMemParserCtxt(const char *buffer, int size) | 
 | { | 
 |     xmlRelaxNGParserCtxtPtr ret; | 
 |  | 
 |     if ((buffer == NULL) || (size <= 0)) | 
 |         return (NULL); | 
 |  | 
 |     ret = | 
 |         (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt)); | 
 |     if (ret == NULL) { | 
 |         xmlRngPErrMemory(NULL, "building parser\n"); | 
 |         return (NULL); | 
 |     } | 
 |     memset(ret, 0, sizeof(xmlRelaxNGParserCtxt)); | 
 |     ret->buffer = buffer; | 
 |     ret->size = size; | 
 |     ret->error = xmlGenericError; | 
 |     ret->userData = xmlGenericErrorContext; | 
 |     return (ret); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGNewDocParserCtxt: | 
 |  * @doc:  a preparsed document tree | 
 |  * | 
 |  * Create an XML RelaxNGs parser context for that document. | 
 |  * Note: since the process of compiling a RelaxNG schemas modifies the | 
 |  *       document, the @doc parameter is duplicated internally. | 
 |  * | 
 |  * Returns the parser context or NULL in case of error | 
 |  */ | 
 | xmlRelaxNGParserCtxtPtr | 
 | xmlRelaxNGNewDocParserCtxt(xmlDocPtr doc) | 
 | { | 
 |     xmlRelaxNGParserCtxtPtr ret; | 
 |     xmlDocPtr copy; | 
 |  | 
 |     if (doc == NULL) | 
 |         return (NULL); | 
 |     copy = xmlCopyDoc(doc, 1); | 
 |     if (copy == NULL) | 
 |         return (NULL); | 
 |  | 
 |     ret = | 
 |         (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt)); | 
 |     if (ret == NULL) { | 
 |         xmlRngPErrMemory(NULL, "building parser\n"); | 
 |         return (NULL); | 
 |     } | 
 |     memset(ret, 0, sizeof(xmlRelaxNGParserCtxt)); | 
 |     ret->document = copy; | 
 |     ret->freedoc = 1; | 
 |     ret->userData = xmlGenericErrorContext; | 
 |     return (ret); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGFreeParserCtxt: | 
 |  * @ctxt:  the schema parser context | 
 |  * | 
 |  * Free the resources associated to the schema parser context | 
 |  */ | 
 | void | 
 | xmlRelaxNGFreeParserCtxt(xmlRelaxNGParserCtxtPtr ctxt) | 
 | { | 
 |     if (ctxt == NULL) | 
 |         return; | 
 |     if (ctxt->URL != NULL) | 
 |         xmlFree(ctxt->URL); | 
 |     if (ctxt->doc != NULL) | 
 |         xmlRelaxNGFreeDocument(ctxt->doc); | 
 |     if (ctxt->interleaves != NULL) | 
 |         xmlHashFree(ctxt->interleaves, NULL); | 
 |     if (ctxt->documents != NULL) | 
 |         xmlRelaxNGFreeDocumentList(ctxt->documents); | 
 |     if (ctxt->includes != NULL) | 
 |         xmlRelaxNGFreeIncludeList(ctxt->includes); | 
 |     if (ctxt->docTab != NULL) | 
 |         xmlFree(ctxt->docTab); | 
 |     if (ctxt->incTab != NULL) | 
 |         xmlFree(ctxt->incTab); | 
 |     if (ctxt->defTab != NULL) { | 
 |         int i; | 
 |  | 
 |         for (i = 0; i < ctxt->defNr; i++) | 
 |             xmlRelaxNGFreeDefine(ctxt->defTab[i]); | 
 |         xmlFree(ctxt->defTab); | 
 |     } | 
 |     if ((ctxt->document != NULL) && (ctxt->freedoc)) | 
 |         xmlFreeDoc(ctxt->document); | 
 |     xmlFree(ctxt); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGNormExtSpace: | 
 |  * @value:  a value | 
 |  * | 
 |  * Removes the leading and ending spaces of the value | 
 |  * The string is modified "in situ" | 
 |  */ | 
 | static void | 
 | xmlRelaxNGNormExtSpace(xmlChar * value) | 
 | { | 
 |     xmlChar *start = value; | 
 |     xmlChar *cur = value; | 
 |  | 
 |     if (value == NULL) | 
 |         return; | 
 |  | 
 |     while (IS_BLANK_CH(*cur)) | 
 |         cur++; | 
 |     if (cur == start) { | 
 |         do { | 
 |             while ((*cur != 0) && (!IS_BLANK_CH(*cur))) | 
 |                 cur++; | 
 |             if (*cur == 0) | 
 |                 return; | 
 |             start = cur; | 
 |             while (IS_BLANK_CH(*cur)) | 
 |                 cur++; | 
 |             if (*cur == 0) { | 
 |                 *start = 0; | 
 |                 return; | 
 |             } | 
 |         } while (1); | 
 |     } else { | 
 |         do { | 
 |             while ((*cur != 0) && (!IS_BLANK_CH(*cur))) | 
 |                 *start++ = *cur++; | 
 |             if (*cur == 0) { | 
 |                 *start = 0; | 
 |                 return; | 
 |             } | 
 |             /* don't try to normalize the inner spaces */ | 
 |             while (IS_BLANK_CH(*cur)) | 
 |                 cur++; | 
 |             if (*cur == 0) { | 
 |                 *start = 0; | 
 |                 return; | 
 |             } | 
 |             *start++ = *cur++; | 
 |         } while (1); | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGCleanupAttributes: | 
 |  * @ctxt:  a Relax-NG parser context | 
 |  * @node:  a Relax-NG node | 
 |  * | 
 |  * Check all the attributes on the given node | 
 |  */ | 
 | static void | 
 | xmlRelaxNGCleanupAttributes(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) | 
 | { | 
 |     xmlAttrPtr cur, next; | 
 |  | 
 |     cur = node->properties; | 
 |     while (cur != NULL) { | 
 |         next = cur->next; | 
 |         if ((cur->ns == NULL) || | 
 |             (xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) { | 
 |             if (xmlStrEqual(cur->name, BAD_CAST "name")) { | 
 |                 if ((!xmlStrEqual(node->name, BAD_CAST "element")) && | 
 |                     (!xmlStrEqual(node->name, BAD_CAST "attribute")) && | 
 |                     (!xmlStrEqual(node->name, BAD_CAST "ref")) && | 
 |                     (!xmlStrEqual(node->name, BAD_CAST "parentRef")) && | 
 |                     (!xmlStrEqual(node->name, BAD_CAST "param")) && | 
 |                     (!xmlStrEqual(node->name, BAD_CAST "define"))) { | 
 |                     xmlRngPErr(ctxt, node, XML_RNGP_FORBIDDEN_ATTRIBUTE, | 
 |                                "Attribute %s is not allowed on %s\n", | 
 |                                cur->name, node->name); | 
 |                 } | 
 |             } else if (xmlStrEqual(cur->name, BAD_CAST "type")) { | 
 |                 if ((!xmlStrEqual(node->name, BAD_CAST "value")) && | 
 |                     (!xmlStrEqual(node->name, BAD_CAST "data"))) { | 
 |                     xmlRngPErr(ctxt, node, XML_RNGP_FORBIDDEN_ATTRIBUTE, | 
 |                                "Attribute %s is not allowed on %s\n", | 
 |                                cur->name, node->name); | 
 |                 } | 
 |             } else if (xmlStrEqual(cur->name, BAD_CAST "href")) { | 
 |                 if ((!xmlStrEqual(node->name, BAD_CAST "externalRef")) && | 
 |                     (!xmlStrEqual(node->name, BAD_CAST "include"))) { | 
 |                     xmlRngPErr(ctxt, node, XML_RNGP_FORBIDDEN_ATTRIBUTE, | 
 |                                "Attribute %s is not allowed on %s\n", | 
 |                                cur->name, node->name); | 
 |                 } | 
 |             } else if (xmlStrEqual(cur->name, BAD_CAST "combine")) { | 
 |                 if ((!xmlStrEqual(node->name, BAD_CAST "start")) && | 
 |                     (!xmlStrEqual(node->name, BAD_CAST "define"))) { | 
 |                     xmlRngPErr(ctxt, node, XML_RNGP_FORBIDDEN_ATTRIBUTE, | 
 |                                "Attribute %s is not allowed on %s\n", | 
 |                                cur->name, node->name); | 
 |                 } | 
 |             } else if (xmlStrEqual(cur->name, BAD_CAST "datatypeLibrary")) { | 
 |                 xmlChar *val; | 
 |                 xmlURIPtr uri; | 
 |  | 
 |                 val = xmlNodeListGetString(node->doc, cur->children, 1); | 
 |                 if (val != NULL) { | 
 |                     if (val[0] != 0) { | 
 |                         uri = xmlParseURI((const char *) val); | 
 |                         if (uri == NULL) { | 
 |                             xmlRngPErr(ctxt, node, XML_RNGP_INVALID_URI, | 
 |                                        "Attribute %s contains invalid URI %s\n", | 
 |                                        cur->name, val); | 
 |                         } else { | 
 |                             if (uri->scheme == NULL) { | 
 |                                 xmlRngPErr(ctxt, node, XML_RNGP_URI_NOT_ABSOLUTE, | 
 |                                            "Attribute %s URI %s is not absolute\n", | 
 |                                            cur->name, val); | 
 |                             } | 
 |                             if (uri->fragment != NULL) { | 
 |                                 xmlRngPErr(ctxt, node, XML_RNGP_URI_FRAGMENT, | 
 |                                            "Attribute %s URI %s has a fragment ID\n", | 
 |                                            cur->name, val); | 
 |                             } | 
 |                             xmlFreeURI(uri); | 
 |                         } | 
 |                     } | 
 |                     xmlFree(val); | 
 |                 } | 
 |             } else if (!xmlStrEqual(cur->name, BAD_CAST "ns")) { | 
 |                 xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_ATTRIBUTE, | 
 |                            "Unknown attribute %s on %s\n", cur->name, | 
 |                            node->name); | 
 |             } | 
 |         } | 
 |         cur = next; | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGCleanupTree: | 
 |  * @ctxt:  a Relax-NG parser context | 
 |  * @root:  an xmlNodePtr subtree | 
 |  * | 
 |  * Cleanup the subtree from unwanted nodes for parsing, resolve | 
 |  * Include and externalRef lookups. | 
 |  */ | 
 | static void | 
 | xmlRelaxNGCleanupTree(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr root) | 
 | { | 
 |     xmlNodePtr cur, delete; | 
 |  | 
 |     delete = NULL; | 
 |     cur = root; | 
 |     while (cur != NULL) { | 
 |         if (delete != NULL) { | 
 |             xmlUnlinkNode(delete); | 
 |             xmlFreeNode(delete); | 
 |             delete = NULL; | 
 |         } | 
 |         if (cur->type == XML_ELEMENT_NODE) { | 
 |             /* | 
 |              * Simplification 4.1. Annotations | 
 |              */ | 
 |             if ((cur->ns == NULL) || | 
 |                 (!xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) { | 
 |                 if ((cur->parent != NULL) && | 
 |                     (cur->parent->type == XML_ELEMENT_NODE) && | 
 |                     ((xmlStrEqual(cur->parent->name, BAD_CAST "name")) || | 
 |                      (xmlStrEqual(cur->parent->name, BAD_CAST "value")) || | 
 |                      (xmlStrEqual(cur->parent->name, BAD_CAST "param")))) { | 
 |                     xmlRngPErr(ctxt, cur, XML_RNGP_FOREIGN_ELEMENT, | 
 |                                "element %s doesn't allow foreign elements\n", | 
 |                                cur->parent->name, NULL); | 
 |                 } | 
 |                 delete = cur; | 
 |                 goto skip_children; | 
 |             } else { | 
 |                 xmlRelaxNGCleanupAttributes(ctxt, cur); | 
 |                 if (xmlStrEqual(cur->name, BAD_CAST "externalRef")) { | 
 |                     xmlChar *href, *ns, *base, *URL; | 
 |                     xmlRelaxNGDocumentPtr docu; | 
 |                     xmlNodePtr tmp; | 
 | 		    xmlURIPtr uri; | 
 |  | 
 |                     ns = xmlGetProp(cur, BAD_CAST "ns"); | 
 |                     if (ns == NULL) { | 
 |                         tmp = cur->parent; | 
 |                         while ((tmp != NULL) && | 
 |                                (tmp->type == XML_ELEMENT_NODE)) { | 
 |                             ns = xmlGetProp(tmp, BAD_CAST "ns"); | 
 |                             if (ns != NULL) | 
 |                                 break; | 
 |                             tmp = tmp->parent; | 
 |                         } | 
 |                     } | 
 |                     href = xmlGetProp(cur, BAD_CAST "href"); | 
 |                     if (href == NULL) { | 
 |                         xmlRngPErr(ctxt, cur, XML_RNGP_MISSING_HREF, | 
 |                                    "xmlRelaxNGParse: externalRef has no href attribute\n", | 
 |                                    NULL, NULL); | 
 |                         if (ns != NULL) | 
 |                             xmlFree(ns); | 
 |                         delete = cur; | 
 |                         goto skip_children; | 
 |                     } | 
 | 		    uri = xmlParseURI((const char *) href); | 
 | 		    if (uri == NULL) { | 
 |                         xmlRngPErr(ctxt, cur, XML_RNGP_HREF_ERROR, | 
 |                                    "Incorrect URI for externalRef %s\n", | 
 |                                    href, NULL); | 
 |                         if (ns != NULL) | 
 |                             xmlFree(ns); | 
 |                         if (href != NULL) | 
 |                             xmlFree(href); | 
 |                         delete = cur; | 
 |                         goto skip_children; | 
 | 		    } | 
 | 		    if (uri->fragment != NULL) { | 
 |                         xmlRngPErr(ctxt, cur, XML_RNGP_HREF_ERROR, | 
 | 			       "Fragment forbidden in URI for externalRef %s\n", | 
 |                                    href, NULL); | 
 |                         if (ns != NULL) | 
 |                             xmlFree(ns); | 
 | 		        xmlFreeURI(uri); | 
 |                         if (href != NULL) | 
 |                             xmlFree(href); | 
 |                         delete = cur; | 
 |                         goto skip_children; | 
 | 		    } | 
 | 		    xmlFreeURI(uri); | 
 |                     base = xmlNodeGetBase(cur->doc, cur); | 
 |                     URL = xmlBuildURI(href, base); | 
 |                     if (URL == NULL) { | 
 |                         xmlRngPErr(ctxt, cur, XML_RNGP_HREF_ERROR, | 
 |                                    "Failed to compute URL for externalRef %s\n", | 
 |                                    href, NULL); | 
 |                         if (ns != NULL) | 
 |                             xmlFree(ns); | 
 |                         if (href != NULL) | 
 |                             xmlFree(href); | 
 |                         if (base != NULL) | 
 |                             xmlFree(base); | 
 |                         delete = cur; | 
 |                         goto skip_children; | 
 |                     } | 
 |                     if (href != NULL) | 
 |                         xmlFree(href); | 
 |                     if (base != NULL) | 
 |                         xmlFree(base); | 
 |                     docu = xmlRelaxNGLoadExternalRef(ctxt, URL, ns); | 
 |                     if (docu == NULL) { | 
 |                         xmlRngPErr(ctxt, cur, XML_RNGP_EXTERNAL_REF_FAILURE, | 
 |                                    "Failed to load externalRef %s\n", URL, | 
 |                                    NULL); | 
 |                         if (ns != NULL) | 
 |                             xmlFree(ns); | 
 |                         xmlFree(URL); | 
 |                         delete = cur; | 
 |                         goto skip_children; | 
 |                     } | 
 |                     if (ns != NULL) | 
 |                         xmlFree(ns); | 
 |                     xmlFree(URL); | 
 |                     cur->psvi = docu; | 
 |                 } else if (xmlStrEqual(cur->name, BAD_CAST "include")) { | 
 |                     xmlChar *href, *ns, *base, *URL; | 
 |                     xmlRelaxNGIncludePtr incl; | 
 |                     xmlNodePtr tmp; | 
 |  | 
 |                     href = xmlGetProp(cur, BAD_CAST "href"); | 
 |                     if (href == NULL) { | 
 |                         xmlRngPErr(ctxt, cur, XML_RNGP_MISSING_HREF, | 
 |                                    "xmlRelaxNGParse: include has no href attribute\n", | 
 |                                    NULL, NULL); | 
 |                         delete = cur; | 
 |                         goto skip_children; | 
 |                     } | 
 |                     base = xmlNodeGetBase(cur->doc, cur); | 
 |                     URL = xmlBuildURI(href, base); | 
 |                     if (URL == NULL) { | 
 |                         xmlRngPErr(ctxt, cur, XML_RNGP_HREF_ERROR, | 
 |                                    "Failed to compute URL for include %s\n", | 
 |                                    href, NULL); | 
 |                         if (href != NULL) | 
 |                             xmlFree(href); | 
 |                         if (base != NULL) | 
 |                             xmlFree(base); | 
 |                         delete = cur; | 
 |                         goto skip_children; | 
 |                     } | 
 |                     if (href != NULL) | 
 |                         xmlFree(href); | 
 |                     if (base != NULL) | 
 |                         xmlFree(base); | 
 |                     ns = xmlGetProp(cur, BAD_CAST "ns"); | 
 |                     if (ns == NULL) { | 
 |                         tmp = cur->parent; | 
 |                         while ((tmp != NULL) && | 
 |                                (tmp->type == XML_ELEMENT_NODE)) { | 
 |                             ns = xmlGetProp(tmp, BAD_CAST "ns"); | 
 |                             if (ns != NULL) | 
 |                                 break; | 
 |                             tmp = tmp->parent; | 
 |                         } | 
 |                     } | 
 |                     incl = xmlRelaxNGLoadInclude(ctxt, URL, cur, ns); | 
 |                     if (ns != NULL) | 
 |                         xmlFree(ns); | 
 |                     if (incl == NULL) { | 
 |                         xmlRngPErr(ctxt, cur, XML_RNGP_INCLUDE_FAILURE, | 
 |                                    "Failed to load include %s\n", URL, | 
 |                                    NULL); | 
 |                         xmlFree(URL); | 
 |                         delete = cur; | 
 |                         goto skip_children; | 
 |                     } | 
 |                     xmlFree(URL); | 
 |                     cur->psvi = incl; | 
 |                 } else if ((xmlStrEqual(cur->name, BAD_CAST "element")) || | 
 |                            (xmlStrEqual(cur->name, BAD_CAST "attribute"))) | 
 |                 { | 
 |                     xmlChar *name, *ns; | 
 |                     xmlNodePtr text = NULL; | 
 |  | 
 |                     /* | 
 |                      * Simplification 4.8. name attribute of element | 
 |                      * and attribute elements | 
 |                      */ | 
 |                     name = xmlGetProp(cur, BAD_CAST "name"); | 
 |                     if (name != NULL) { | 
 |                         if (cur->children == NULL) { | 
 |                             text = | 
 |                                 xmlNewChild(cur, cur->ns, BAD_CAST "name", | 
 |                                             name); | 
 |                         } else { | 
 |                             xmlNodePtr node; | 
 |  | 
 |                             node = xmlNewDocNode(cur->doc, cur->ns, | 
 | 			                         BAD_CAST "name", NULL); | 
 |                             if (node != NULL) { | 
 |                                 xmlAddPrevSibling(cur->children, node); | 
 |                                 text = xmlNewText(name); | 
 |                                 xmlAddChild(node, text); | 
 |                                 text = node; | 
 |                             } | 
 |                         } | 
 |                         if (text == NULL) { | 
 |                             xmlRngPErr(ctxt, cur, XML_RNGP_CREATE_FAILURE, | 
 |                                        "Failed to create a name %s element\n", | 
 |                                        name, NULL); | 
 |                         } | 
 |                         xmlUnsetProp(cur, BAD_CAST "name"); | 
 |                         xmlFree(name); | 
 |                         ns = xmlGetProp(cur, BAD_CAST "ns"); | 
 |                         if (ns != NULL) { | 
 |                             if (text != NULL) { | 
 |                                 xmlSetProp(text, BAD_CAST "ns", ns); | 
 |                                 /* xmlUnsetProp(cur, BAD_CAST "ns"); */ | 
 |                             } | 
 |                             xmlFree(ns); | 
 |                         } else if (xmlStrEqual(cur->name, | 
 |                                                BAD_CAST "attribute")) { | 
 |                             xmlSetProp(text, BAD_CAST "ns", BAD_CAST ""); | 
 |                         } | 
 |                     } | 
 |                 } else if ((xmlStrEqual(cur->name, BAD_CAST "name")) || | 
 |                            (xmlStrEqual(cur->name, BAD_CAST "nsName")) || | 
 |                            (xmlStrEqual(cur->name, BAD_CAST "value"))) { | 
 |                     /* | 
 |                      * Simplification 4.8. name attribute of element | 
 |                      * and attribute elements | 
 |                      */ | 
 |                     if (xmlHasProp(cur, BAD_CAST "ns") == NULL) { | 
 |                         xmlNodePtr node; | 
 |                         xmlChar *ns = NULL; | 
 |  | 
 |                         node = cur->parent; | 
 |                         while ((node != NULL) && | 
 |                                (node->type == XML_ELEMENT_NODE)) { | 
 |                             ns = xmlGetProp(node, BAD_CAST "ns"); | 
 |                             if (ns != NULL) { | 
 |                                 break; | 
 |                             } | 
 |                             node = node->parent; | 
 |                         } | 
 |                         if (ns == NULL) { | 
 |                             xmlSetProp(cur, BAD_CAST "ns", BAD_CAST ""); | 
 |                         } else { | 
 |                             xmlSetProp(cur, BAD_CAST "ns", ns); | 
 |                             xmlFree(ns); | 
 |                         } | 
 |                     } | 
 |                     if (xmlStrEqual(cur->name, BAD_CAST "name")) { | 
 |                         xmlChar *name, *local, *prefix; | 
 |  | 
 |                         /* | 
 |                          * Simplification: 4.10. QNames | 
 |                          */ | 
 |                         name = xmlNodeGetContent(cur); | 
 |                         if (name != NULL) { | 
 |                             local = xmlSplitQName2(name, &prefix); | 
 |                             if (local != NULL) { | 
 |                                 xmlNsPtr ns; | 
 |  | 
 |                                 ns = xmlSearchNs(cur->doc, cur, prefix); | 
 |                                 if (ns == NULL) { | 
 |                                     xmlRngPErr(ctxt, cur, | 
 |                                                XML_RNGP_PREFIX_UNDEFINED, | 
 |                                                "xmlRelaxNGParse: no namespace for prefix %s\n", | 
 |                                                prefix, NULL); | 
 |                                 } else { | 
 |                                     xmlSetProp(cur, BAD_CAST "ns", | 
 |                                                ns->href); | 
 |                                     xmlNodeSetContent(cur, local); | 
 |                                 } | 
 |                                 xmlFree(local); | 
 |                                 xmlFree(prefix); | 
 |                             } | 
 |                             xmlFree(name); | 
 |                         } | 
 |                     } | 
 |                     /* | 
 |                      * 4.16 | 
 |                      */ | 
 |                     if (xmlStrEqual(cur->name, BAD_CAST "nsName")) { | 
 |                         if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) { | 
 |                             xmlRngPErr(ctxt, cur, | 
 |                                        XML_RNGP_PAT_NSNAME_EXCEPT_NSNAME, | 
 |                                        "Found nsName/except//nsName forbidden construct\n", | 
 |                                        NULL, NULL); | 
 |                         } | 
 |                     } | 
 |                 } else if ((xmlStrEqual(cur->name, BAD_CAST "except")) && | 
 |                            (cur != root)) { | 
 |                     int oldflags = ctxt->flags; | 
 |  | 
 |                     /* | 
 |                      * 4.16 | 
 |                      */ | 
 |                     if ((cur->parent != NULL) && | 
 |                         (xmlStrEqual | 
 |                          (cur->parent->name, BAD_CAST "anyName"))) { | 
 |                         ctxt->flags |= XML_RELAXNG_IN_ANYEXCEPT; | 
 |                         xmlRelaxNGCleanupTree(ctxt, cur); | 
 |                         ctxt->flags = oldflags; | 
 |                         goto skip_children; | 
 |                     } else if ((cur->parent != NULL) && | 
 |                                (xmlStrEqual | 
 |                                 (cur->parent->name, BAD_CAST "nsName"))) { | 
 |                         ctxt->flags |= XML_RELAXNG_IN_NSEXCEPT; | 
 |                         xmlRelaxNGCleanupTree(ctxt, cur); | 
 |                         ctxt->flags = oldflags; | 
 |                         goto skip_children; | 
 |                     } | 
 |                 } else if (xmlStrEqual(cur->name, BAD_CAST "anyName")) { | 
 |                     /* | 
 |                      * 4.16 | 
 |                      */ | 
 |                     if (ctxt->flags & XML_RELAXNG_IN_ANYEXCEPT) { | 
 |                         xmlRngPErr(ctxt, cur, | 
 |                                    XML_RNGP_PAT_ANYNAME_EXCEPT_ANYNAME, | 
 |                                    "Found anyName/except//anyName forbidden construct\n", | 
 |                                    NULL, NULL); | 
 |                     } else if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) { | 
 |                         xmlRngPErr(ctxt, cur, | 
 |                                    XML_RNGP_PAT_NSNAME_EXCEPT_ANYNAME, | 
 |                                    "Found nsName/except//anyName forbidden construct\n", | 
 |                                    NULL, NULL); | 
 |                     } | 
 |                 } | 
 |                 /* | 
 |                  * Thisd is not an else since "include" is transformed | 
 |                  * into a div | 
 |                  */ | 
 |                 if (xmlStrEqual(cur->name, BAD_CAST "div")) { | 
 |                     xmlChar *ns; | 
 |                     xmlNodePtr child, ins, tmp; | 
 |  | 
 |                     /* | 
 |                      * implements rule 4.11 | 
 |                      */ | 
 |  | 
 |                     ns = xmlGetProp(cur, BAD_CAST "ns"); | 
 |  | 
 |                     child = cur->children; | 
 |                     ins = cur; | 
 |                     while (child != NULL) { | 
 |                         if (ns != NULL) { | 
 |                             if (!xmlHasProp(child, BAD_CAST "ns")) { | 
 |                                 xmlSetProp(child, BAD_CAST "ns", ns); | 
 |                             } | 
 |                         } | 
 |                         tmp = child->next; | 
 |                         xmlUnlinkNode(child); | 
 |                         ins = xmlAddNextSibling(ins, child); | 
 |                         child = tmp; | 
 |                     } | 
 |                     if (ns != NULL) | 
 |                         xmlFree(ns); | 
 | 		    /* | 
 | 		     * Since we are about to delete cur, if it's nsDef is non-NULL we | 
 | 		     * need to preserve it (it contains the ns definitions for the | 
 | 		     * children we just moved).  We'll just stick it on to the end | 
 | 		     * of cur->parent's list, since it's never going to be re-serialized | 
 | 		     * (bug 143738). | 
 | 		     */ | 
 | 		    if (cur->nsDef != NULL) { | 
 | 			xmlNsPtr parDef = (xmlNsPtr)&cur->parent->nsDef; | 
 | 			while (parDef->next != NULL) | 
 | 			    parDef = parDef->next; | 
 | 			parDef->next = cur->nsDef; | 
 | 			cur->nsDef = NULL; | 
 | 		    } | 
 |                     delete = cur; | 
 |                     goto skip_children; | 
 |                 } | 
 |             } | 
 |         } | 
 |         /* | 
 |          * Simplification 4.2 whitespaces | 
 |          */ | 
 |         else if ((cur->type == XML_TEXT_NODE) || | 
 |                  (cur->type == XML_CDATA_SECTION_NODE)) { | 
 |             if (IS_BLANK_NODE(cur)) { | 
 |                 if (cur->parent->type == XML_ELEMENT_NODE) { | 
 |                     if ((!xmlStrEqual(cur->parent->name, BAD_CAST "value")) | 
 |                         && | 
 |                         (!xmlStrEqual | 
 |                          (cur->parent->name, BAD_CAST "param"))) | 
 |                         delete = cur; | 
 |                 } else { | 
 |                     delete = cur; | 
 |                     goto skip_children; | 
 |                 } | 
 |             } | 
 |         } else { | 
 |             delete = cur; | 
 |             goto skip_children; | 
 |         } | 
 |  | 
 |         /* | 
 |          * Skip to next node | 
 |          */ | 
 |         if (cur->children != NULL) { | 
 |             if ((cur->children->type != XML_ENTITY_DECL) && | 
 |                 (cur->children->type != XML_ENTITY_REF_NODE) && | 
 |                 (cur->children->type != XML_ENTITY_NODE)) { | 
 |                 cur = cur->children; | 
 |                 continue; | 
 |             } | 
 |         } | 
 |       skip_children: | 
 |         if (cur->next != NULL) { | 
 |             cur = cur->next; | 
 |             continue; | 
 |         } | 
 |  | 
 |         do { | 
 |             cur = cur->parent; | 
 |             if (cur == NULL) | 
 |                 break; | 
 |             if (cur == root) { | 
 |                 cur = NULL; | 
 |                 break; | 
 |             } | 
 |             if (cur->next != NULL) { | 
 |                 cur = cur->next; | 
 |                 break; | 
 |             } | 
 |         } while (cur != NULL); | 
 |     } | 
 |     if (delete != NULL) { | 
 |         xmlUnlinkNode(delete); | 
 |         xmlFreeNode(delete); | 
 |         delete = NULL; | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGCleanupDoc: | 
 |  * @ctxt:  a Relax-NG parser context | 
 |  * @doc:  an xmldocPtr document pointer | 
 |  * | 
 |  * Cleanup the document from unwanted nodes for parsing, resolve | 
 |  * Include and externalRef lookups. | 
 |  * | 
 |  * Returns the cleaned up document or NULL in case of error | 
 |  */ | 
 | static xmlDocPtr | 
 | xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt, xmlDocPtr doc) | 
 | { | 
 |     xmlNodePtr root; | 
 |  | 
 |     /* | 
 |      * Extract the root | 
 |      */ | 
 |     root = xmlDocGetRootElement(doc); | 
 |     if (root == NULL) { | 
 |         xmlRngPErr(ctxt, (xmlNodePtr) doc, XML_RNGP_EMPTY, "xmlRelaxNGParse: %s is empty\n", | 
 |                    ctxt->URL, NULL); | 
 |         return (NULL); | 
 |     } | 
 |     xmlRelaxNGCleanupTree(ctxt, root); | 
 |     return (doc); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGParse: | 
 |  * @ctxt:  a Relax-NG parser context | 
 |  * | 
 |  * parse a schema definition resource and build an internal | 
 |  * XML Shema struture which can be used to validate instances. | 
 |  * | 
 |  * Returns the internal XML RelaxNG structure built from the resource or | 
 |  *         NULL in case of error | 
 |  */ | 
 | xmlRelaxNGPtr | 
 | xmlRelaxNGParse(xmlRelaxNGParserCtxtPtr ctxt) | 
 | { | 
 |     xmlRelaxNGPtr ret = NULL; | 
 |     xmlDocPtr doc; | 
 |     xmlNodePtr root; | 
 |  | 
 |     xmlRelaxNGInitTypes(); | 
 |  | 
 |     if (ctxt == NULL) | 
 |         return (NULL); | 
 |  | 
 |     /* | 
 |      * First step is to parse the input document into an DOM/Infoset | 
 |      */ | 
 |     if (ctxt->URL != NULL) { | 
 |         doc = xmlReadFile((const char *) ctxt->URL,NULL,0); | 
 |         if (doc == NULL) { | 
 |             xmlRngPErr(ctxt, NULL, XML_RNGP_PARSE_ERROR, | 
 |                        "xmlRelaxNGParse: could not load %s\n", ctxt->URL, | 
 |                        NULL); | 
 |             return (NULL); | 
 |         } | 
 |     } else if (ctxt->buffer != NULL) { | 
 |         doc = xmlReadMemory(ctxt->buffer, ctxt->size,NULL,NULL,0); | 
 |         if (doc == NULL) { | 
 |             xmlRngPErr(ctxt, NULL, XML_RNGP_PARSE_ERROR, | 
 |                        "xmlRelaxNGParse: could not parse schemas\n", NULL, | 
 |                        NULL); | 
 |             return (NULL); | 
 |         } | 
 |         doc->URL = xmlStrdup(BAD_CAST "in_memory_buffer"); | 
 |         ctxt->URL = xmlStrdup(BAD_CAST "in_memory_buffer"); | 
 |     } else if (ctxt->document != NULL) { | 
 |         doc = ctxt->document; | 
 |     } else { | 
 |         xmlRngPErr(ctxt, NULL, XML_RNGP_EMPTY, | 
 |                    "xmlRelaxNGParse: nothing to parse\n", NULL, NULL); | 
 |         return (NULL); | 
 |     } | 
 |     ctxt->document = doc; | 
 |  | 
 |     /* | 
 |      * Some preprocessing of the document content | 
 |      */ | 
 |     doc = xmlRelaxNGCleanupDoc(ctxt, doc); | 
 |     if (doc == NULL) { | 
 |         xmlFreeDoc(ctxt->document); | 
 |         ctxt->document = NULL; | 
 |         return (NULL); | 
 |     } | 
 |  | 
 |     /* | 
 |      * Then do the parsing for good | 
 |      */ | 
 |     root = xmlDocGetRootElement(doc); | 
 |     if (root == NULL) { | 
 |         xmlRngPErr(ctxt, (xmlNodePtr) doc, | 
 | 	           XML_RNGP_EMPTY, "xmlRelaxNGParse: %s is empty\n", | 
 |                    (ctxt->URL ? ctxt->URL : BAD_CAST "schemas"), NULL); | 
 | 	 | 
 |         xmlFreeDoc(ctxt->document); | 
 |         ctxt->document = NULL; | 
 |         return (NULL); | 
 |     } | 
 |     ret = xmlRelaxNGParseDocument(ctxt, root); | 
 |     if (ret == NULL) { | 
 |         xmlFreeDoc(ctxt->document); | 
 |         ctxt->document = NULL; | 
 |         return (NULL); | 
 |     } | 
 |  | 
 |     /* | 
 |      * Check the ref/defines links | 
 |      */ | 
 |     /* | 
 |      * try to preprocess interleaves | 
 |      */ | 
 |     if (ctxt->interleaves != NULL) { | 
 |         xmlHashScan(ctxt->interleaves, | 
 |                     (xmlHashScanner) xmlRelaxNGComputeInterleaves, ctxt); | 
 |     } | 
 |  | 
 |     /* | 
 |      * if there was a parsing error return NULL | 
 |      */ | 
 |     if (ctxt->nbErrors > 0) { | 
 |         xmlRelaxNGFree(ret); | 
 |         ctxt->document = NULL; | 
 |         xmlFreeDoc(doc); | 
 |         return (NULL); | 
 |     } | 
 |  | 
 |     /* | 
 |      * try to compile (parts of) the schemas | 
 |      */ | 
 |     if ((ret->topgrammar != NULL) && (ret->topgrammar->start != NULL)) { | 
 |         if (ret->topgrammar->start->type != XML_RELAXNG_START) { | 
 |             xmlRelaxNGDefinePtr def; | 
 |  | 
 |             def = xmlRelaxNGNewDefine(ctxt, NULL); | 
 |             if (def != NULL) { | 
 |                 def->type = XML_RELAXNG_START; | 
 |                 def->content = ret->topgrammar->start; | 
 |                 ret->topgrammar->start = def; | 
 |             } | 
 |         } | 
 |         xmlRelaxNGTryCompile(ctxt, ret->topgrammar->start); | 
 |     } | 
 |  | 
 |     /* | 
 |      * Transfer the pointer for cleanup at the schema level. | 
 |      */ | 
 |     ret->doc = doc; | 
 |     ctxt->document = NULL; | 
 |     ret->documents = ctxt->documents; | 
 |     ctxt->documents = NULL; | 
 |  | 
 |     ret->includes = ctxt->includes; | 
 |     ctxt->includes = NULL; | 
 |     ret->defNr = ctxt->defNr; | 
 |     ret->defTab = ctxt->defTab; | 
 |     ctxt->defTab = NULL; | 
 |     if (ctxt->idref == 1) | 
 |         ret->idref = 1; | 
 |  | 
 |     return (ret); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGSetParserErrors: | 
 |  * @ctxt:  a Relax-NG validation context | 
 |  * @err:  the error callback | 
 |  * @warn:  the warning callback | 
 |  * @ctx:  contextual data for the callbacks | 
 |  * | 
 |  * Set the callback functions used to handle errors for a validation context | 
 |  */ | 
 | void | 
 | xmlRelaxNGSetParserErrors(xmlRelaxNGParserCtxtPtr ctxt, | 
 |                           xmlRelaxNGValidityErrorFunc err, | 
 |                           xmlRelaxNGValidityWarningFunc warn, void *ctx) | 
 | { | 
 |     if (ctxt == NULL) | 
 |         return; | 
 |     ctxt->error = err; | 
 |     ctxt->warning = warn; | 
 |     ctxt->serror = NULL; | 
 |     ctxt->userData = ctx; | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGGetParserErrors: | 
 |  * @ctxt:  a Relax-NG validation context | 
 |  * @err:  the error callback result | 
 |  * @warn:  the warning callback result | 
 |  * @ctx:  contextual data for the callbacks result | 
 |  * | 
 |  * Get the callback information used to handle errors for a validation context | 
 |  * | 
 |  * Returns -1 in case of failure, 0 otherwise. | 
 |  */ | 
 | int | 
 | xmlRelaxNGGetParserErrors(xmlRelaxNGParserCtxtPtr ctxt, | 
 |                           xmlRelaxNGValidityErrorFunc * err, | 
 |                           xmlRelaxNGValidityWarningFunc * warn, void **ctx) | 
 | { | 
 |     if (ctxt == NULL) | 
 |         return (-1); | 
 |     if (err != NULL) | 
 |         *err = ctxt->error; | 
 |     if (warn != NULL) | 
 |         *warn = ctxt->warning; | 
 |     if (ctx != NULL) | 
 |         *ctx = ctxt->userData; | 
 |     return (0); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGSetParserStructuredErrors: | 
 |  * @ctxt:  a Relax-NG parser context | 
 |  * @serror:  the error callback | 
 |  * @ctx:  contextual data for the callbacks | 
 |  * | 
 |  * Set the callback functions used to handle errors for a parsing context | 
 |  */ | 
 | void | 
 | xmlRelaxNGSetParserStructuredErrors(xmlRelaxNGParserCtxtPtr ctxt, | 
 | 				    xmlStructuredErrorFunc serror, | 
 | 				    void *ctx) | 
 | { | 
 |     if (ctxt == NULL) | 
 |         return; | 
 |     ctxt->serror = serror; | 
 |     ctxt->error = NULL; | 
 |     ctxt->warning = NULL; | 
 |     ctxt->userData = ctx; | 
 | } | 
 |  | 
 | #ifdef LIBXML_OUTPUT_ENABLED | 
 |  | 
 | /************************************************************************ | 
 |  * 									* | 
 |  * 			Dump back a compiled form			* | 
 |  * 									* | 
 |  ************************************************************************/ | 
 | static void xmlRelaxNGDumpDefine(FILE * output, | 
 |                                  xmlRelaxNGDefinePtr define); | 
 |  | 
 | /** | 
 |  * xmlRelaxNGDumpDefines: | 
 |  * @output:  the file output | 
 |  * @defines:  a list of define structures | 
 |  * | 
 |  * Dump a RelaxNG structure back | 
 |  */ | 
 | static void | 
 | xmlRelaxNGDumpDefines(FILE * output, xmlRelaxNGDefinePtr defines) | 
 | { | 
 |     while (defines != NULL) { | 
 |         xmlRelaxNGDumpDefine(output, defines); | 
 |         defines = defines->next; | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGDumpDefine: | 
 |  * @output:  the file output | 
 |  * @define:  a define structure | 
 |  * | 
 |  * Dump a RelaxNG structure back | 
 |  */ | 
 | static void | 
 | xmlRelaxNGDumpDefine(FILE * output, xmlRelaxNGDefinePtr define) | 
 | { | 
 |     if (define == NULL) | 
 |         return; | 
 |     switch (define->type) { | 
 |         case XML_RELAXNG_EMPTY: | 
 |             fprintf(output, "<empty/>\n"); | 
 |             break; | 
 |         case XML_RELAXNG_NOT_ALLOWED: | 
 |             fprintf(output, "<notAllowed/>\n"); | 
 |             break; | 
 |         case XML_RELAXNG_TEXT: | 
 |             fprintf(output, "<text/>\n"); | 
 |             break; | 
 |         case XML_RELAXNG_ELEMENT: | 
 |             fprintf(output, "<element>\n"); | 
 |             if (define->name != NULL) { | 
 |                 fprintf(output, "<name"); | 
 |                 if (define->ns != NULL) | 
 |                     fprintf(output, " ns=\"%s\"", define->ns); | 
 |                 fprintf(output, ">%s</name>\n", define->name); | 
 |             } | 
 |             xmlRelaxNGDumpDefines(output, define->attrs); | 
 |             xmlRelaxNGDumpDefines(output, define->content); | 
 |             fprintf(output, "</element>\n"); | 
 |             break; | 
 |         case XML_RELAXNG_LIST: | 
 |             fprintf(output, "<list>\n"); | 
 |             xmlRelaxNGDumpDefines(output, define->content); | 
 |             fprintf(output, "</list>\n"); | 
 |             break; | 
 |         case XML_RELAXNG_ONEORMORE: | 
 |             fprintf(output, "<oneOrMore>\n"); | 
 |             xmlRelaxNGDumpDefines(output, define->content); | 
 |             fprintf(output, "</oneOrMore>\n"); | 
 |             break; | 
 |         case XML_RELAXNG_ZEROORMORE: | 
 |             fprintf(output, "<zeroOrMore>\n"); | 
 |             xmlRelaxNGDumpDefines(output, define->content); | 
 |             fprintf(output, "</zeroOrMore>\n"); | 
 |             break; | 
 |         case XML_RELAXNG_CHOICE: | 
 |             fprintf(output, "<choice>\n"); | 
 |             xmlRelaxNGDumpDefines(output, define->content); | 
 |             fprintf(output, "</choice>\n"); | 
 |             break; | 
 |         case XML_RELAXNG_GROUP: | 
 |             fprintf(output, "<group>\n"); | 
 |             xmlRelaxNGDumpDefines(output, define->content); | 
 |             fprintf(output, "</group>\n"); | 
 |             break; | 
 |         case XML_RELAXNG_INTERLEAVE: | 
 |             fprintf(output, "<interleave>\n"); | 
 |             xmlRelaxNGDumpDefines(output, define->content); | 
 |             fprintf(output, "</interleave>\n"); | 
 |             break; | 
 |         case XML_RELAXNG_OPTIONAL: | 
 |             fprintf(output, "<optional>\n"); | 
 |             xmlRelaxNGDumpDefines(output, define->content); | 
 |             fprintf(output, "</optional>\n"); | 
 |             break; | 
 |         case XML_RELAXNG_ATTRIBUTE: | 
 |             fprintf(output, "<attribute>\n"); | 
 |             xmlRelaxNGDumpDefines(output, define->content); | 
 |             fprintf(output, "</attribute>\n"); | 
 |             break; | 
 |         case XML_RELAXNG_DEF: | 
 |             fprintf(output, "<define"); | 
 |             if (define->name != NULL) | 
 |                 fprintf(output, " name=\"%s\"", define->name); | 
 |             fprintf(output, ">\n"); | 
 |             xmlRelaxNGDumpDefines(output, define->content); | 
 |             fprintf(output, "</define>\n"); | 
 |             break; | 
 |         case XML_RELAXNG_REF: | 
 |             fprintf(output, "<ref"); | 
 |             if (define->name != NULL) | 
 |                 fprintf(output, " name=\"%s\"", define->name); | 
 |             fprintf(output, ">\n"); | 
 |             xmlRelaxNGDumpDefines(output, define->content); | 
 |             fprintf(output, "</ref>\n"); | 
 |             break; | 
 |         case XML_RELAXNG_PARENTREF: | 
 |             fprintf(output, "<parentRef"); | 
 |             if (define->name != NULL) | 
 |                 fprintf(output, " name=\"%s\"", define->name); | 
 |             fprintf(output, ">\n"); | 
 |             xmlRelaxNGDumpDefines(output, define->content); | 
 |             fprintf(output, "</parentRef>\n"); | 
 |             break; | 
 |         case XML_RELAXNG_EXTERNALREF: | 
 |             fprintf(output, "<externalRef>"); | 
 |             xmlRelaxNGDumpDefines(output, define->content); | 
 |             fprintf(output, "</externalRef>\n"); | 
 |             break; | 
 |         case XML_RELAXNG_DATATYPE: | 
 |         case XML_RELAXNG_VALUE: | 
 |             TODO break; | 
 |         case XML_RELAXNG_START: | 
 |         case XML_RELAXNG_EXCEPT: | 
 |         case XML_RELAXNG_PARAM: | 
 |             TODO break; | 
 |         case XML_RELAXNG_NOOP: | 
 |             xmlRelaxNGDumpDefines(output, define->content); | 
 |             break; | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGDumpGrammar: | 
 |  * @output:  the file output | 
 |  * @grammar:  a grammar structure | 
 |  * @top:  is this a top grammar  | 
 |  * | 
 |  * Dump a RelaxNG structure back | 
 |  */ | 
 | static void | 
 | xmlRelaxNGDumpGrammar(FILE * output, xmlRelaxNGGrammarPtr grammar, int top) | 
 | { | 
 |     if (grammar == NULL) | 
 |         return; | 
 |  | 
 |     fprintf(output, "<grammar"); | 
 |     if (top) | 
 |         fprintf(output, " xmlns=\"http://relaxng.org/ns/structure/1.0\""); | 
 |     switch (grammar->combine) { | 
 |         case XML_RELAXNG_COMBINE_UNDEFINED: | 
 |             break; | 
 |         case XML_RELAXNG_COMBINE_CHOICE: | 
 |             fprintf(output, " combine=\"choice\""); | 
 |             break; | 
 |         case XML_RELAXNG_COMBINE_INTERLEAVE: | 
 |             fprintf(output, " combine=\"interleave\""); | 
 |             break; | 
 |         default: | 
 |             fprintf(output, " <!-- invalid combine value -->"); | 
 |     } | 
 |     fprintf(output, ">\n"); | 
 |     if (grammar->start == NULL) { | 
 |         fprintf(output, " <!-- grammar had no start -->"); | 
 |     } else { | 
 |         fprintf(output, "<start>\n"); | 
 |         xmlRelaxNGDumpDefine(output, grammar->start); | 
 |         fprintf(output, "</start>\n"); | 
 |     } | 
 |     /* TODO ? Dump the defines ? */ | 
 |     fprintf(output, "</grammar>\n"); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGDump: | 
 |  * @output:  the file output | 
 |  * @schema:  a schema structure | 
 |  * | 
 |  * Dump a RelaxNG structure back | 
 |  */ | 
 | void | 
 | xmlRelaxNGDump(FILE * output, xmlRelaxNGPtr schema) | 
 | { | 
 |     if (output == NULL) | 
 |         return; | 
 |     if (schema == NULL) { | 
 |         fprintf(output, "RelaxNG empty or failed to compile\n"); | 
 |         return; | 
 |     } | 
 |     fprintf(output, "RelaxNG: "); | 
 |     if (schema->doc == NULL) { | 
 |         fprintf(output, "no document\n"); | 
 |     } else if (schema->doc->URL != NULL) { | 
 |         fprintf(output, "%s\n", schema->doc->URL); | 
 |     } else { | 
 |         fprintf(output, "\n"); | 
 |     } | 
 |     if (schema->topgrammar == NULL) { | 
 |         fprintf(output, "RelaxNG has no top grammar\n"); | 
 |         return; | 
 |     } | 
 |     xmlRelaxNGDumpGrammar(output, schema->topgrammar, 1); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGDumpTree: | 
 |  * @output:  the file output | 
 |  * @schema:  a schema structure | 
 |  * | 
 |  * Dump the transformed RelaxNG tree. | 
 |  */ | 
 | void | 
 | xmlRelaxNGDumpTree(FILE * output, xmlRelaxNGPtr schema) | 
 | { | 
 |     if (output == NULL) | 
 |         return; | 
 |     if (schema == NULL) { | 
 |         fprintf(output, "RelaxNG empty or failed to compile\n"); | 
 |         return; | 
 |     } | 
 |     if (schema->doc == NULL) { | 
 |         fprintf(output, "no document\n"); | 
 |     } else { | 
 |         xmlDocDump(output, schema->doc); | 
 |     } | 
 | } | 
 | #endif /* LIBXML_OUTPUT_ENABLED */ | 
 |  | 
 | /************************************************************************ | 
 |  * 									* | 
 |  * 		Validation of compiled content				* | 
 |  * 									* | 
 |  ************************************************************************/ | 
 | static int xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt, | 
 |                                         xmlRelaxNGDefinePtr define); | 
 |  | 
 | /** | 
 |  * xmlRelaxNGValidateCompiledCallback: | 
 |  * @exec:  the regular expression instance | 
 |  * @token:  the token which matched | 
 |  * @transdata:  callback data, the define for the subelement if available | 
 |  @ @inputdata:  callback data, the Relax NG validation context | 
 |  * | 
 |  * Handle the callback and if needed validate the element children. | 
 |  */ | 
 | static void | 
 | xmlRelaxNGValidateCompiledCallback(xmlRegExecCtxtPtr exec ATTRIBUTE_UNUSED, | 
 |                                    const xmlChar * token, | 
 |                                    void *transdata, void *inputdata) | 
 | { | 
 |     xmlRelaxNGValidCtxtPtr ctxt = (xmlRelaxNGValidCtxtPtr) inputdata; | 
 |     xmlRelaxNGDefinePtr define = (xmlRelaxNGDefinePtr) transdata; | 
 |     int ret; | 
 |  | 
 | #ifdef DEBUG_COMPILE | 
 |     xmlGenericError(xmlGenericErrorContext, | 
 |                     "Compiled callback for: '%s'\n", token); | 
 | #endif | 
 |     if (ctxt == NULL) { | 
 |         fprintf(stderr, "callback on %s missing context\n", token); | 
 |         return; | 
 |     } | 
 |     if (define == NULL) { | 
 |         if (token[0] == '#') | 
 |             return; | 
 |         fprintf(stderr, "callback on %s missing define\n", token); | 
 |         if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK)) | 
 |             ctxt->errNo = XML_RELAXNG_ERR_INTERNAL; | 
 |         return; | 
 |     } | 
 |     if ((ctxt == NULL) || (define == NULL)) { | 
 |         fprintf(stderr, "callback on %s missing info\n", token); | 
 |         if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK)) | 
 |             ctxt->errNo = XML_RELAXNG_ERR_INTERNAL; | 
 |         return; | 
 |     } else if (define->type != XML_RELAXNG_ELEMENT) { | 
 |         fprintf(stderr, "callback on %s define is not element\n", token); | 
 |         if (ctxt->errNo == XML_RELAXNG_OK) | 
 |             ctxt->errNo = XML_RELAXNG_ERR_INTERNAL; | 
 |         return; | 
 |     } | 
 |     ret = xmlRelaxNGValidateDefinition(ctxt, define); | 
 |     if (ret != 0) | 
 |         ctxt->perr = ret; | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGValidateCompiledContent: | 
 |  * @ctxt:  the RelaxNG validation context | 
 |  * @regexp:  the regular expression as compiled | 
 |  * @content:  list of children to test against the regexp | 
 |  * | 
 |  * Validate the content model of an element or start using the regexp | 
 |  * | 
 |  * Returns 0 in case of success, -1 in case of error. | 
 |  */ | 
 | static int | 
 | xmlRelaxNGValidateCompiledContent(xmlRelaxNGValidCtxtPtr ctxt, | 
 |                                   xmlRegexpPtr regexp, xmlNodePtr content) | 
 | { | 
 |     xmlRegExecCtxtPtr exec; | 
 |     xmlNodePtr cur; | 
 |     int ret = 0; | 
 |     int oldperr; | 
 |  | 
 |     if ((ctxt == NULL) || (regexp == NULL)) | 
 |         return (-1); | 
 |     oldperr = ctxt->perr; | 
 |     exec = xmlRegNewExecCtxt(regexp, | 
 |                              xmlRelaxNGValidateCompiledCallback, ctxt); | 
 |     ctxt->perr = 0; | 
 |     cur = content; | 
 |     while (cur != NULL) { | 
 |         ctxt->state->seq = cur; | 
 |         switch (cur->type) { | 
 |             case XML_TEXT_NODE: | 
 |             case XML_CDATA_SECTION_NODE: | 
 |                 if (xmlIsBlankNode(cur)) | 
 |                     break; | 
 |                 ret = xmlRegExecPushString(exec, BAD_CAST "#text", ctxt); | 
 |                 if (ret < 0) { | 
 |                     VALID_ERR2(XML_RELAXNG_ERR_TEXTWRONG, | 
 |                                cur->parent->name); | 
 |                 } | 
 |                 break; | 
 |             case XML_ELEMENT_NODE: | 
 |                 if (cur->ns != NULL) { | 
 |                     ret = xmlRegExecPushString2(exec, cur->name, | 
 |                                                 cur->ns->href, ctxt); | 
 |                 } else { | 
 |                     ret = xmlRegExecPushString(exec, cur->name, ctxt); | 
 |                 } | 
 |                 if (ret < 0) { | 
 |                     VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG, cur->name); | 
 |                 } | 
 |                 break; | 
 |             default: | 
 |                 break; | 
 |         } | 
 |         if (ret < 0) | 
 |             break; | 
 |         /* | 
 |          * Switch to next element | 
 |          */ | 
 |         cur = cur->next; | 
 |     } | 
 |     ret = xmlRegExecPushString(exec, NULL, NULL); | 
 |     if (ret == 1) { | 
 |         ret = 0; | 
 |         ctxt->state->seq = NULL; | 
 |     } else if (ret == 0) { | 
 |         /* | 
 |          * TODO: get some of the names needed to exit the current state of exec | 
 |          */ | 
 |         VALID_ERR2(XML_RELAXNG_ERR_NOELEM, BAD_CAST ""); | 
 |         ret = -1; | 
 |         if ((ctxt->flags & FLAGS_IGNORABLE) == 0) | 
 |             xmlRelaxNGDumpValidError(ctxt); | 
 |     } else { | 
 |         ret = -1; | 
 |     } | 
 |     xmlRegFreeExecCtxt(exec); | 
 |     /* | 
 |      * There might be content model errors outside of the pure | 
 |      * regexp validation, e.g. for attribute values. | 
 |      */ | 
 |     if ((ret == 0) && (ctxt->perr != 0)) { | 
 |         ret = ctxt->perr; | 
 |     } | 
 |     ctxt->perr = oldperr; | 
 |     return (ret); | 
 | } | 
 |  | 
 | /************************************************************************ | 
 |  * 									* | 
 |  * 		Progressive validation of when possible			* | 
 |  * 									* | 
 |  ************************************************************************/ | 
 | static int xmlRelaxNGValidateAttributeList(xmlRelaxNGValidCtxtPtr ctxt, | 
 |                                            xmlRelaxNGDefinePtr defines); | 
 | static int xmlRelaxNGValidateElementEnd(xmlRelaxNGValidCtxtPtr ctxt, | 
 |                                         int dolog); | 
 | static void xmlRelaxNGLogBestError(xmlRelaxNGValidCtxtPtr ctxt); | 
 |  | 
 | /** | 
 |  * xmlRelaxNGElemPush: | 
 |  * @ctxt:  the validation context | 
 |  * @exec:  the regexp runtime for the new content model | 
 |  * | 
 |  * Push a new regexp for the current node content model on the stack | 
 |  * | 
 |  * Returns 0 in case of success and -1 in case of error. | 
 |  */ | 
 | static int | 
 | xmlRelaxNGElemPush(xmlRelaxNGValidCtxtPtr ctxt, xmlRegExecCtxtPtr exec) | 
 | { | 
 |     if (ctxt->elemTab == NULL) { | 
 |         ctxt->elemMax = 10; | 
 |         ctxt->elemTab = (xmlRegExecCtxtPtr *) xmlMalloc(ctxt->elemMax * | 
 |                                                         sizeof | 
 |                                                         (xmlRegExecCtxtPtr)); | 
 |         if (ctxt->elemTab == NULL) { | 
 |             xmlRngVErrMemory(ctxt, "validating\n"); | 
 |             return (-1); | 
 |         } | 
 |     } | 
 |     if (ctxt->elemNr >= ctxt->elemMax) { | 
 |         ctxt->elemMax *= 2; | 
 |         ctxt->elemTab = (xmlRegExecCtxtPtr *) xmlRealloc(ctxt->elemTab, | 
 |                                                          ctxt->elemMax * | 
 |                                                          sizeof | 
 |                                                          (xmlRegExecCtxtPtr)); | 
 |         if (ctxt->elemTab == NULL) { | 
 |             xmlRngVErrMemory(ctxt, "validating\n"); | 
 |             return (-1); | 
 |         } | 
 |     } | 
 |     ctxt->elemTab[ctxt->elemNr++] = exec; | 
 |     ctxt->elem = exec; | 
 |     return (0); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGElemPop: | 
 |  * @ctxt:  the validation context | 
 |  * | 
 |  * Pop the regexp of the current node content model from the stack | 
 |  * | 
 |  * Returns the exec or NULL if empty | 
 |  */ | 
 | static xmlRegExecCtxtPtr | 
 | xmlRelaxNGElemPop(xmlRelaxNGValidCtxtPtr ctxt) | 
 | { | 
 |     xmlRegExecCtxtPtr ret; | 
 |  | 
 |     if (ctxt->elemNr <= 0) | 
 |         return (NULL); | 
 |     ctxt->elemNr--; | 
 |     ret = ctxt->elemTab[ctxt->elemNr]; | 
 |     ctxt->elemTab[ctxt->elemNr] = NULL; | 
 |     if (ctxt->elemNr > 0) | 
 |         ctxt->elem = ctxt->elemTab[ctxt->elemNr - 1]; | 
 |     else | 
 |         ctxt->elem = NULL; | 
 |     return (ret); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGValidateProgressiveCallback: | 
 |  * @exec:  the regular expression instance | 
 |  * @token:  the token which matched | 
 |  * @transdata:  callback data, the define for the subelement if available | 
 |  @ @inputdata:  callback data, the Relax NG validation context | 
 |  * | 
 |  * Handle the callback and if needed validate the element children. | 
 |  * some of the in/out informations are passed via the context in @inputdata. | 
 |  */ | 
 | static void | 
 | xmlRelaxNGValidateProgressiveCallback(xmlRegExecCtxtPtr exec | 
 |                                       ATTRIBUTE_UNUSED, | 
 |                                       const xmlChar * token, | 
 |                                       void *transdata, void *inputdata) | 
 | { | 
 |     xmlRelaxNGValidCtxtPtr ctxt = (xmlRelaxNGValidCtxtPtr) inputdata; | 
 |     xmlRelaxNGDefinePtr define = (xmlRelaxNGDefinePtr) transdata; | 
 |     xmlRelaxNGValidStatePtr state, oldstate; | 
 |     xmlNodePtr node; | 
 |     int ret = 0, oldflags; | 
 |  | 
 | #ifdef DEBUG_PROGRESSIVE | 
 |     xmlGenericError(xmlGenericErrorContext, | 
 |                     "Progressive callback for: '%s'\n", token); | 
 | #endif | 
 |     if (ctxt == NULL) { | 
 |         fprintf(stderr, "callback on %s missing context\n", token); | 
 |         return; | 
 |     } | 
 |     node = ctxt->pnode; | 
 |     ctxt->pstate = 1; | 
 |     if (define == NULL) { | 
 |         if (token[0] == '#') | 
 |             return; | 
 |         fprintf(stderr, "callback on %s missing define\n", token); | 
 |         if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK)) | 
 |             ctxt->errNo = XML_RELAXNG_ERR_INTERNAL; | 
 |         ctxt->pstate = -1; | 
 |         return; | 
 |     } | 
 |     if ((ctxt == NULL) || (define == NULL)) { | 
 |         fprintf(stderr, "callback on %s missing info\n", token); | 
 |         if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK)) | 
 |             ctxt->errNo = XML_RELAXNG_ERR_INTERNAL; | 
 |         ctxt->pstate = -1; | 
 |         return; | 
 |     } else if (define->type != XML_RELAXNG_ELEMENT) { | 
 |         fprintf(stderr, "callback on %s define is not element\n", token); | 
 |         if (ctxt->errNo == XML_RELAXNG_OK) | 
 |             ctxt->errNo = XML_RELAXNG_ERR_INTERNAL; | 
 |         ctxt->pstate = -1; | 
 |         return; | 
 |     } | 
 |     if (node->type != XML_ELEMENT_NODE) { | 
 |         VALID_ERR(XML_RELAXNG_ERR_NOTELEM); | 
 |         if ((ctxt->flags & FLAGS_IGNORABLE) == 0) | 
 |             xmlRelaxNGDumpValidError(ctxt); | 
 |         ctxt->pstate = -1; | 
 |         return; | 
 |     } | 
 |     if (define->contModel == NULL) { | 
 |         /* | 
 |          * this node cannot be validated in a streamable fashion | 
 |          */ | 
 | #ifdef DEBUG_PROGRESSIVE | 
 |         xmlGenericError(xmlGenericErrorContext, | 
 |                         "Element '%s' validation is not streamable\n", | 
 |                         token); | 
 | #endif | 
 |         ctxt->pstate = 0; | 
 |         ctxt->pdef = define; | 
 |         return; | 
 |     } | 
 |     exec = xmlRegNewExecCtxt(define->contModel, | 
 |                              xmlRelaxNGValidateProgressiveCallback, ctxt); | 
 |     if (exec == NULL) { | 
 |         ctxt->pstate = -1; | 
 |         return; | 
 |     } | 
 |     xmlRelaxNGElemPush(ctxt, exec); | 
 |  | 
 |     /* | 
 |      * Validate the attributes part of the content. | 
 |      */ | 
 |     state = xmlRelaxNGNewValidState(ctxt, node); | 
 |     if (state == NULL) { | 
 |         ctxt->pstate = -1; | 
 |         return; | 
 |     } | 
 |     oldstate = ctxt->state; | 
 |     ctxt->state = state; | 
 |     if (define->attrs != NULL) { | 
 |         ret = xmlRelaxNGValidateAttributeList(ctxt, define->attrs); | 
 |         if (ret != 0) { | 
 |             ctxt->pstate = -1; | 
 |             VALID_ERR2(XML_RELAXNG_ERR_ATTRVALID, node->name); | 
 |         } | 
 |     } | 
 |     if (ctxt->state != NULL) { | 
 |         ctxt->state->seq = NULL; | 
 |         ret = xmlRelaxNGValidateElementEnd(ctxt, 1); | 
 |         if (ret != 0) { | 
 |             ctxt->pstate = -1; | 
 |         } | 
 |         xmlRelaxNGFreeValidState(ctxt, ctxt->state); | 
 |     } else if (ctxt->states != NULL) { | 
 |         int tmp = -1, i; | 
 |  | 
 |         oldflags = ctxt->flags; | 
 |  | 
 |         for (i = 0; i < ctxt->states->nbState; i++) { | 
 |             state = ctxt->states->tabState[i]; | 
 |             ctxt->state = state; | 
 |             ctxt->state->seq = NULL; | 
 |  | 
 |             if (xmlRelaxNGValidateElementEnd(ctxt, 0) == 0) { | 
 |                 tmp = 0; | 
 |                 break; | 
 |             } | 
 |         } | 
 |         if (tmp != 0) { | 
 |             /* | 
 |              * validation error, log the message for the "best" one | 
 |              */ | 
 |             ctxt->flags |= FLAGS_IGNORABLE; | 
 |             xmlRelaxNGLogBestError(ctxt); | 
 |         } | 
 |         for (i = 0; i < ctxt->states->nbState; i++) { | 
 |             xmlRelaxNGFreeValidState(ctxt, ctxt->states->tabState[i]); | 
 |         } | 
 |         xmlRelaxNGFreeStates(ctxt, ctxt->states); | 
 |         ctxt->states = NULL; | 
 |         if ((ret == 0) && (tmp == -1)) | 
 |             ctxt->pstate = -1; | 
 |         ctxt->flags = oldflags; | 
 |     } | 
 |     if (ctxt->pstate == -1) { | 
 |         if ((ctxt->flags & FLAGS_IGNORABLE) == 0) { | 
 |             xmlRelaxNGDumpValidError(ctxt); | 
 |         } | 
 |     } | 
 |     ctxt->state = oldstate; | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGValidatePushElement: | 
 |  * @ctxt:  the validation context | 
 |  * @doc:  a document instance | 
 |  * @elem:  an element instance | 
 |  * | 
 |  * Push a new element start on the RelaxNG validation stack. | 
 |  * | 
 |  * returns 1 if no validation problem was found or 0 if validating the | 
 |  *         element requires a full node, and -1 in case of error. | 
 |  */ | 
 | int | 
 | xmlRelaxNGValidatePushElement(xmlRelaxNGValidCtxtPtr ctxt, | 
 |                               xmlDocPtr doc ATTRIBUTE_UNUSED, | 
 |                               xmlNodePtr elem) | 
 | { | 
 |     int ret = 1; | 
 |  | 
 |     if ((ctxt == NULL) || (elem == NULL)) | 
 |         return (-1); | 
 |  | 
 | #ifdef DEBUG_PROGRESSIVE | 
 |     xmlGenericError(xmlGenericErrorContext, "PushElem %s\n", elem->name); | 
 | #endif | 
 |     if (ctxt->elem == 0) { | 
 |         xmlRelaxNGPtr schema; | 
 |         xmlRelaxNGGrammarPtr grammar; | 
 |         xmlRegExecCtxtPtr exec; | 
 |         xmlRelaxNGDefinePtr define; | 
 |  | 
 |         schema = ctxt->schema; | 
 |         if (schema == NULL) { | 
 |             VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR); | 
 |             return (-1); | 
 |         } | 
 |         grammar = schema->topgrammar; | 
 |         if ((grammar == NULL) || (grammar->start == NULL)) { | 
 |             VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR); | 
 |             return (-1); | 
 |         } | 
 |         define = grammar->start; | 
 |         if (define->contModel == NULL) { | 
 |             ctxt->pdef = define; | 
 |             return (0); | 
 |         } | 
 |         exec = xmlRegNewExecCtxt(define->contModel, | 
 |                                  xmlRelaxNGValidateProgressiveCallback, | 
 |                                  ctxt); | 
 |         if (exec == NULL) { | 
 |             return (-1); | 
 |         } | 
 |         xmlRelaxNGElemPush(ctxt, exec); | 
 |     } | 
 |     ctxt->pnode = elem; | 
 |     ctxt->pstate = 0; | 
 |     if (elem->ns != NULL) { | 
 |         ret = | 
 |             xmlRegExecPushString2(ctxt->elem, elem->name, elem->ns->href, | 
 |                                   ctxt); | 
 |     } else { | 
 |         ret = xmlRegExecPushString(ctxt->elem, elem->name, ctxt); | 
 |     } | 
 |     if (ret < 0) { | 
 |         VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG, elem->name); | 
 |     } else { | 
 |         if (ctxt->pstate == 0) | 
 |             ret = 0; | 
 |         else if (ctxt->pstate < 0) | 
 |             ret = -1; | 
 |         else | 
 |             ret = 1; | 
 |     } | 
 | #ifdef DEBUG_PROGRESSIVE | 
 |     if (ret < 0) | 
 |         xmlGenericError(xmlGenericErrorContext, "PushElem %s failed\n", | 
 |                         elem->name); | 
 | #endif | 
 |     return (ret); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGValidatePushCData: | 
 |  * @ctxt:  the RelaxNG validation context | 
 |  * @data:  some character data read | 
 |  * @len:  the lenght of the data | 
 |  * | 
 |  * check the CData parsed for validation in the current stack | 
 |  * | 
 |  * returns 1 if no validation problem was found or -1 otherwise | 
 |  */ | 
 | int | 
 | xmlRelaxNGValidatePushCData(xmlRelaxNGValidCtxtPtr ctxt, | 
 |                             const xmlChar * data, int len ATTRIBUTE_UNUSED) | 
 | { | 
 |     int ret = 1; | 
 |  | 
 |     if ((ctxt == NULL) || (ctxt->elem == NULL) || (data == NULL)) | 
 |         return (-1); | 
 |  | 
 | #ifdef DEBUG_PROGRESSIVE | 
 |     xmlGenericError(xmlGenericErrorContext, "CDATA %s %d\n", data, len); | 
 | #endif | 
 |  | 
 |     while (*data != 0) { | 
 |         if (!IS_BLANK_CH(*data)) | 
 |             break; | 
 |         data++; | 
 |     } | 
 |     if (*data == 0) | 
 |         return (1); | 
 |  | 
 |     ret = xmlRegExecPushString(ctxt->elem, BAD_CAST "#text", ctxt); | 
 |     if (ret < 0) { | 
 |         VALID_ERR2(XML_RELAXNG_ERR_TEXTWRONG, BAD_CAST " TODO "); | 
 | #ifdef DEBUG_PROGRESSIVE | 
 |         xmlGenericError(xmlGenericErrorContext, "CDATA failed\n"); | 
 | #endif | 
 |  | 
 |         return (-1); | 
 |     } | 
 |     return (1); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGValidatePopElement: | 
 |  * @ctxt:  the RelaxNG validation context | 
 |  * @doc:  a document instance | 
 |  * @elem:  an element instance | 
 |  * | 
 |  * Pop the element end from the RelaxNG validation stack. | 
 |  * | 
 |  * returns 1 if no validation problem was found or 0 otherwise | 
 |  */ | 
 | int | 
 | xmlRelaxNGValidatePopElement(xmlRelaxNGValidCtxtPtr ctxt, | 
 |                              xmlDocPtr doc ATTRIBUTE_UNUSED, | 
 |                              xmlNodePtr elem) | 
 | { | 
 |     int ret; | 
 |     xmlRegExecCtxtPtr exec; | 
 |  | 
 |     if ((ctxt == NULL) || (ctxt->elem == NULL) || (elem == NULL)) | 
 |         return (-1); | 
 | #ifdef DEBUG_PROGRESSIVE | 
 |     xmlGenericError(xmlGenericErrorContext, "PopElem %s\n", elem->name); | 
 | #endif | 
 |     /* | 
 |      * verify that we reached a terminal state of the content model. | 
 |      */ | 
 |     exec = xmlRelaxNGElemPop(ctxt); | 
 |     ret = xmlRegExecPushString(exec, NULL, NULL); | 
 |     if (ret == 0) { | 
 |         /* | 
 |          * TODO: get some of the names needed to exit the current state of exec | 
 |          */ | 
 |         VALID_ERR2(XML_RELAXNG_ERR_NOELEM, BAD_CAST ""); | 
 |         ret = -1; | 
 |     } else if (ret < 0) { | 
 |         ret = -1; | 
 |     } else { | 
 |         ret = 1; | 
 |     } | 
 |     xmlRegFreeExecCtxt(exec); | 
 | #ifdef DEBUG_PROGRESSIVE | 
 |     if (ret < 0) | 
 |         xmlGenericError(xmlGenericErrorContext, "PopElem %s failed\n", | 
 |                         elem->name); | 
 | #endif | 
 |     return (ret); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGValidateFullElement: | 
 |  * @ctxt:  the validation context | 
 |  * @doc:  a document instance | 
 |  * @elem:  an element instance | 
 |  * | 
 |  * Validate a full subtree when xmlRelaxNGValidatePushElement() returned | 
 |  * 0 and the content of the node has been expanded. | 
 |  * | 
 |  * returns 1 if no validation problem was found or -1 in case of error. | 
 |  */ | 
 | int | 
 | xmlRelaxNGValidateFullElement(xmlRelaxNGValidCtxtPtr ctxt, | 
 |                               xmlDocPtr doc ATTRIBUTE_UNUSED, | 
 |                               xmlNodePtr elem) | 
 | { | 
 |     int ret; | 
 |     xmlRelaxNGValidStatePtr state; | 
 |  | 
 |     if ((ctxt == NULL) || (ctxt->pdef == NULL) || (elem == NULL)) | 
 |         return (-1); | 
 | #ifdef DEBUG_PROGRESSIVE | 
 |     xmlGenericError(xmlGenericErrorContext, "FullElem %s\n", elem->name); | 
 | #endif | 
 |     state = xmlRelaxNGNewValidState(ctxt, elem->parent); | 
 |     if (state == NULL) { | 
 |         return (-1); | 
 |     } | 
 |     state->seq = elem; | 
 |     ctxt->state = state; | 
 |     ctxt->errNo = XML_RELAXNG_OK; | 
 |     ret = xmlRelaxNGValidateDefinition(ctxt, ctxt->pdef); | 
 |     if ((ret != 0) || (ctxt->errNo != XML_RELAXNG_OK)) | 
 |         ret = -1; | 
 |     else | 
 |         ret = 1; | 
 |     xmlRelaxNGFreeValidState(ctxt, ctxt->state); | 
 |     ctxt->state = NULL; | 
 | #ifdef DEBUG_PROGRESSIVE | 
 |     if (ret < 0) | 
 |         xmlGenericError(xmlGenericErrorContext, "FullElem %s failed\n", | 
 |                         elem->name); | 
 | #endif | 
 |     return (ret); | 
 | } | 
 |  | 
 | /************************************************************************ | 
 |  * 									* | 
 |  * 		Generic interpreted validation implementation		* | 
 |  * 									* | 
 |  ************************************************************************/ | 
 | static int xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt, | 
 |                                    xmlRelaxNGDefinePtr define); | 
 |  | 
 | /** | 
 |  * xmlRelaxNGSkipIgnored: | 
 |  * @ctxt:  a schema validation context | 
 |  * @node:  the top node. | 
 |  * | 
 |  * Skip ignorable nodes in that context | 
 |  * | 
 |  * Returns the new sibling or NULL in case of error. | 
 |  */ | 
 | static xmlNodePtr | 
 | xmlRelaxNGSkipIgnored(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED, | 
 |                       xmlNodePtr node) | 
 | { | 
 |     /* | 
 |      * TODO complete and handle entities | 
 |      */ | 
 |     while ((node != NULL) && | 
 |            ((node->type == XML_COMMENT_NODE) || | 
 |             (node->type == XML_PI_NODE) || | 
 | 	    (node->type == XML_XINCLUDE_START) || | 
 | 	    (node->type == XML_XINCLUDE_END) || | 
 |             (((node->type == XML_TEXT_NODE) || | 
 |               (node->type == XML_CDATA_SECTION_NODE)) && | 
 |              ((ctxt->flags & FLAGS_MIXED_CONTENT) || | 
 |               (IS_BLANK_NODE(node)))))) { | 
 |         node = node->next; | 
 |     } | 
 |     return (node); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGNormalize: | 
 |  * @ctxt:  a schema validation context | 
 |  * @str:  the string to normalize | 
 |  * | 
 |  * Implements the  normalizeWhiteSpace( s ) function from | 
 |  * section 6.2.9 of the spec | 
 |  * | 
 |  * Returns the new string or NULL in case of error. | 
 |  */ | 
 | static xmlChar * | 
 | xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt, const xmlChar * str) | 
 | { | 
 |     xmlChar *ret, *p; | 
 |     const xmlChar *tmp; | 
 |     int len; | 
 |  | 
 |     if (str == NULL) | 
 |         return (NULL); | 
 |     tmp = str; | 
 |     while (*tmp != 0) | 
 |         tmp++; | 
 |     len = tmp - str; | 
 |  | 
 |     ret = (xmlChar *) xmlMallocAtomic((len + 1) * sizeof(xmlChar)); | 
 |     if (ret == NULL) { | 
 |         xmlRngVErrMemory(ctxt, "validating\n"); | 
 |         return (NULL); | 
 |     } | 
 |     p = ret; | 
 |     while (IS_BLANK_CH(*str)) | 
 |         str++; | 
 |     while (*str != 0) { | 
 |         if (IS_BLANK_CH(*str)) { | 
 |             while (IS_BLANK_CH(*str)) | 
 |                 str++; | 
 |             if (*str == 0) | 
 |                 break; | 
 |             *p++ = ' '; | 
 |         } else | 
 |             *p++ = *str++; | 
 |     } | 
 |     *p = 0; | 
 |     return (ret); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGValidateDatatype: | 
 |  * @ctxt:  a Relax-NG validation context | 
 |  * @value:  the string value | 
 |  * @type:  the datatype definition | 
 |  * @node:  the node | 
 |  * | 
 |  * Validate the given value against the dataype | 
 |  * | 
 |  * Returns 0 if the validation succeeded or an error code. | 
 |  */ | 
 | static int | 
 | xmlRelaxNGValidateDatatype(xmlRelaxNGValidCtxtPtr ctxt, | 
 |                            const xmlChar * value, | 
 |                            xmlRelaxNGDefinePtr define, xmlNodePtr node) | 
 | { | 
 |     int ret, tmp; | 
 |     xmlRelaxNGTypeLibraryPtr lib; | 
 |     void *result = NULL; | 
 |     xmlRelaxNGDefinePtr cur; | 
 |  | 
 |     if ((define == NULL) || (define->data == NULL)) { | 
 |         return (-1); | 
 |     } | 
 |     lib = (xmlRelaxNGTypeLibraryPtr) define->data; | 
 |     if (lib->check != NULL) { | 
 |         if ((define->attrs != NULL) && | 
 |             (define->attrs->type == XML_RELAXNG_PARAM)) { | 
 |             ret = | 
 |                 lib->check(lib->data, define->name, value, &result, node); | 
 |         } else { | 
 |             ret = lib->check(lib->data, define->name, value, NULL, node); | 
 |         } | 
 |     } else | 
 |         ret = -1; | 
 |     if (ret < 0) { | 
 |         VALID_ERR2(XML_RELAXNG_ERR_TYPE, define->name); | 
 |         if ((result != NULL) && (lib != NULL) && (lib->freef != NULL)) | 
 |             lib->freef(lib->data, result); | 
 |         return (-1); | 
 |     } else if (ret == 1) { | 
 |         ret = 0; | 
 |     } else if (ret == 2) { | 
 |         VALID_ERR2P(XML_RELAXNG_ERR_DUPID, value); | 
 |     } else { | 
 |         VALID_ERR3P(XML_RELAXNG_ERR_TYPEVAL, define->name, value); | 
 |         ret = -1; | 
 |     } | 
 |     cur = define->attrs; | 
 |     while ((ret == 0) && (cur != NULL) && (cur->type == XML_RELAXNG_PARAM)) { | 
 |         if (lib->facet != NULL) { | 
 |             tmp = lib->facet(lib->data, define->name, cur->name, | 
 |                              cur->value, value, result); | 
 |             if (tmp != 0) | 
 |                 ret = -1; | 
 |         } | 
 |         cur = cur->next; | 
 |     } | 
 |     if ((ret == 0) && (define->content != NULL)) { | 
 |         const xmlChar *oldvalue, *oldendvalue; | 
 |  | 
 |         oldvalue = ctxt->state->value; | 
 |         oldendvalue = ctxt->state->endvalue; | 
 |         ctxt->state->value = (xmlChar *) value; | 
 |         ctxt->state->endvalue = NULL; | 
 |         ret = xmlRelaxNGValidateValue(ctxt, define->content); | 
 |         ctxt->state->value = (xmlChar *) oldvalue; | 
 |         ctxt->state->endvalue = (xmlChar *) oldendvalue; | 
 |     } | 
 |     if ((result != NULL) && (lib != NULL) && (lib->freef != NULL)) | 
 |         lib->freef(lib->data, result); | 
 |     return (ret); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGNextValue: | 
 |  * @ctxt:  a Relax-NG validation context | 
 |  * | 
 |  * Skip to the next value when validating within a list | 
 |  * | 
 |  * Returns 0 if the operation succeeded or an error code. | 
 |  */ | 
 | static int | 
 | xmlRelaxNGNextValue(xmlRelaxNGValidCtxtPtr ctxt) | 
 | { | 
 |     xmlChar *cur; | 
 |  | 
 |     cur = ctxt->state->value; | 
 |     if ((cur == NULL) || (ctxt->state->endvalue == NULL)) { | 
 |         ctxt->state->value = NULL; | 
 |         ctxt->state->endvalue = NULL; | 
 |         return (0); | 
 |     } | 
 |     while (*cur != 0) | 
 |         cur++; | 
 |     while ((cur != ctxt->state->endvalue) && (*cur == 0)) | 
 |         cur++; | 
 |     if (cur == ctxt->state->endvalue) | 
 |         ctxt->state->value = NULL; | 
 |     else | 
 |         ctxt->state->value = cur; | 
 |     return (0); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGValidateValueList: | 
 |  * @ctxt:  a Relax-NG validation context | 
 |  * @defines:  the list of definitions to verify | 
 |  * | 
 |  * Validate the given set of definitions for the current value | 
 |  * | 
 |  * Returns 0 if the validation succeeded or an error code. | 
 |  */ | 
 | static int | 
 | xmlRelaxNGValidateValueList(xmlRelaxNGValidCtxtPtr ctxt, | 
 |                             xmlRelaxNGDefinePtr defines) | 
 | { | 
 |     int ret = 0; | 
 |  | 
 |     while (defines != NULL) { | 
 |         ret = xmlRelaxNGValidateValue(ctxt, defines); | 
 |         if (ret != 0) | 
 |             break; | 
 |         defines = defines->next; | 
 |     } | 
 |     return (ret); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGValidateValue: | 
 |  * @ctxt:  a Relax-NG validation context | 
 |  * @define:  the definition to verify | 
 |  * | 
 |  * Validate the given definition for the current value | 
 |  * | 
 |  * Returns 0 if the validation succeeded or an error code. | 
 |  */ | 
 | static int | 
 | xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt, | 
 |                         xmlRelaxNGDefinePtr define) | 
 | { | 
 |     int ret = 0, oldflags; | 
 |     xmlChar *value; | 
 |  | 
 |     value = ctxt->state->value; | 
 |     switch (define->type) { | 
 |         case XML_RELAXNG_EMPTY:{ | 
 |                 if ((value != NULL) && (value[0] != 0)) { | 
 |                     int idx = 0; | 
 |  | 
 |                     while (IS_BLANK_CH(value[idx])) | 
 |                         idx++; | 
 |                     if (value[idx] != 0) | 
 |                         ret = -1; | 
 |                 } | 
 |                 break; | 
 |             } | 
 |         case XML_RELAXNG_TEXT: | 
 |             break; | 
 |         case XML_RELAXNG_VALUE:{ | 
 |                 if (!xmlStrEqual(value, define->value)) { | 
 |                     if (define->name != NULL) { | 
 |                         xmlRelaxNGTypeLibraryPtr lib; | 
 |  | 
 |                         lib = (xmlRelaxNGTypeLibraryPtr) define->data; | 
 |                         if ((lib != NULL) && (lib->comp != NULL)) { | 
 |                             ret = lib->comp(lib->data, define->name, | 
 |                                             define->value, define->node, | 
 |                                             (void *) define->attrs, | 
 |                                             value, ctxt->state->node); | 
 |                         } else | 
 |                             ret = -1; | 
 |                         if (ret < 0) { | 
 |                             VALID_ERR2(XML_RELAXNG_ERR_TYPECMP, | 
 |                                        define->name); | 
 |                             return (-1); | 
 |                         } else if (ret == 1) { | 
 |                             ret = 0; | 
 |                         } else { | 
 |                             ret = -1; | 
 |                         } | 
 |                     } else { | 
 |                         xmlChar *nval, *nvalue; | 
 |  | 
 |                         /* | 
 |                          * TODO: trivial optimizations are possible by | 
 |                          * computing at compile-time | 
 |                          */ | 
 |                         nval = xmlRelaxNGNormalize(ctxt, define->value); | 
 |                         nvalue = xmlRelaxNGNormalize(ctxt, value); | 
 |  | 
 |                         if ((nval == NULL) || (nvalue == NULL) || | 
 |                             (!xmlStrEqual(nval, nvalue))) | 
 |                             ret = -1; | 
 |                         if (nval != NULL) | 
 |                             xmlFree(nval); | 
 |                         if (nvalue != NULL) | 
 |                             xmlFree(nvalue); | 
 |                     } | 
 |                 } | 
 |                 if (ret == 0) | 
 |                     xmlRelaxNGNextValue(ctxt); | 
 |                 break; | 
 |             } | 
 |         case XML_RELAXNG_DATATYPE:{ | 
 |                 ret = xmlRelaxNGValidateDatatype(ctxt, value, define, | 
 |                                                  ctxt->state->seq); | 
 |                 if (ret == 0) | 
 |                     xmlRelaxNGNextValue(ctxt); | 
 |  | 
 |                 break; | 
 |             } | 
 |         case XML_RELAXNG_CHOICE:{ | 
 |                 xmlRelaxNGDefinePtr list = define->content; | 
 |                 xmlChar *oldvalue; | 
 |  | 
 |                 oldflags = ctxt->flags; | 
 |                 ctxt->flags |= FLAGS_IGNORABLE; | 
 |  | 
 |                 oldvalue = ctxt->state->value; | 
 |                 while (list != NULL) { | 
 |                     ret = xmlRelaxNGValidateValue(ctxt, list); | 
 |                     if (ret == 0) { | 
 |                         break; | 
 |                     } | 
 |                     ctxt->state->value = oldvalue; | 
 |                     list = list->next; | 
 |                 } | 
 |                 ctxt->flags = oldflags; | 
 |                 if (ret != 0) { | 
 |                     if ((ctxt->flags & FLAGS_IGNORABLE) == 0) | 
 |                         xmlRelaxNGDumpValidError(ctxt); | 
 |                 } else { | 
 |                     if (ctxt->errNr > 0) | 
 |                         xmlRelaxNGPopErrors(ctxt, 0); | 
 |                 } | 
 |                 break; | 
 |             } | 
 |         case XML_RELAXNG_LIST:{ | 
 |                 xmlRelaxNGDefinePtr list = define->content; | 
 |                 xmlChar *oldvalue, *oldend, *val, *cur; | 
 |  | 
 | #ifdef DEBUG_LIST | 
 |                 int nb_values = 0; | 
 | #endif | 
 |  | 
 |                 oldvalue = ctxt->state->value; | 
 |                 oldend = ctxt->state->endvalue; | 
 |  | 
 |                 val = xmlStrdup(oldvalue); | 
 |                 if (val == NULL) { | 
 |                     val = xmlStrdup(BAD_CAST ""); | 
 |                 } | 
 |                 if (val == NULL) { | 
 |                     VALID_ERR(XML_RELAXNG_ERR_NOSTATE); | 
 |                     return (-1); | 
 |                 } | 
 |                 cur = val; | 
 |                 while (*cur != 0) { | 
 |                     if (IS_BLANK_CH(*cur)) { | 
 |                         *cur = 0; | 
 |                         cur++; | 
 | #ifdef DEBUG_LIST | 
 |                         nb_values++; | 
 | #endif | 
 |                         while (IS_BLANK_CH(*cur)) | 
 |                             *cur++ = 0; | 
 |                     } else | 
 |                         cur++; | 
 |                 } | 
 | #ifdef DEBUG_LIST | 
 |                 xmlGenericError(xmlGenericErrorContext, | 
 |                                 "list value: '%s' found %d items\n", | 
 |                                 oldvalue, nb_values); | 
 |                 nb_values = 0; | 
 | #endif | 
 |                 ctxt->state->endvalue = cur; | 
 |                 cur = val; | 
 |                 while ((*cur == 0) && (cur != ctxt->state->endvalue)) | 
 |                     cur++; | 
 |  | 
 |                 ctxt->state->value = cur; | 
 |  | 
 |                 while (list != NULL) { | 
 |                     if (ctxt->state->value == ctxt->state->endvalue) | 
 |                         ctxt->state->value = NULL; | 
 |                     ret = xmlRelaxNGValidateValue(ctxt, list); | 
 |                     if (ret != 0) { | 
 | #ifdef DEBUG_LIST | 
 |                         xmlGenericError(xmlGenericErrorContext, | 
 |                                         "Failed to validate value: '%s' with %d rule\n", | 
 |                                         ctxt->state->value, nb_values); | 
 | #endif | 
 |                         break; | 
 |                     } | 
 | #ifdef DEBUG_LIST | 
 |                     nb_values++; | 
 | #endif | 
 |                     list = list->next; | 
 |                 } | 
 |  | 
 |                 if ((ret == 0) && (ctxt->state->value != NULL) && | 
 |                     (ctxt->state->value != ctxt->state->endvalue)) { | 
 |                     VALID_ERR2(XML_RELAXNG_ERR_LISTEXTRA, | 
 |                                ctxt->state->value); | 
 |                     ret = -1; | 
 |                 } | 
 |                 xmlFree(val); | 
 |                 ctxt->state->value = oldvalue; | 
 |                 ctxt->state->endvalue = oldend; | 
 |                 break; | 
 |             } | 
 |         case XML_RELAXNG_ONEORMORE: | 
 |             ret = xmlRelaxNGValidateValueList(ctxt, define->content); | 
 |             if (ret != 0) { | 
 |                 break; | 
 |             } | 
 |             /* no break on purpose */ | 
 |         case XML_RELAXNG_ZEROORMORE:{ | 
 |                 xmlChar *cur, *temp; | 
 |  | 
 |                 oldflags = ctxt->flags; | 
 |                 ctxt->flags |= FLAGS_IGNORABLE; | 
 |                 cur = ctxt->state->value; | 
 |                 temp = NULL; | 
 |                 while ((cur != NULL) && (cur != ctxt->state->endvalue) && | 
 |                        (temp != cur)) { | 
 |                     temp = cur; | 
 |                     ret = | 
 |                         xmlRelaxNGValidateValueList(ctxt, define->content); | 
 |                     if (ret != 0) { | 
 |                         ctxt->state->value = temp; | 
 |                         ret = 0; | 
 |                         break; | 
 |                     } | 
 |                     cur = ctxt->state->value; | 
 |                 } | 
 |                 ctxt->flags = oldflags; | 
 | 		if (ctxt->errNr > 0) | 
 | 		    xmlRelaxNGPopErrors(ctxt, 0); | 
 |                 break; | 
 |             } | 
 |         case XML_RELAXNG_EXCEPT:{ | 
 |                 xmlRelaxNGDefinePtr list; | 
 |  | 
 |                 list = define->content; | 
 |                 while (list != NULL) { | 
 |                     ret = xmlRelaxNGValidateValue(ctxt, list); | 
 |                     if (ret == 0) { | 
 |                         ret = -1; | 
 |                         break; | 
 |                     } else | 
 |                         ret = 0; | 
 |                     list = list->next; | 
 |                 } | 
 |                 break; | 
 |             } | 
 |         case XML_RELAXNG_DEF: | 
 |         case XML_RELAXNG_GROUP:{ | 
 |                 xmlRelaxNGDefinePtr list; | 
 |  | 
 |                 list = define->content; | 
 |                 while (list != NULL) { | 
 |                     ret = xmlRelaxNGValidateValue(ctxt, list); | 
 |                     if (ret != 0) { | 
 |                         ret = -1; | 
 |                         break; | 
 |                     } else | 
 |                         ret = 0; | 
 |                     list = list->next; | 
 |                 } | 
 |                 break; | 
 |             } | 
 |         case XML_RELAXNG_REF: | 
 |         case XML_RELAXNG_PARENTREF: | 
 | 	    if (define->content == NULL) { | 
 |                 VALID_ERR(XML_RELAXNG_ERR_NODEFINE); | 
 |                 ret = -1; | 
 | 	    } else { | 
 |                 ret = xmlRelaxNGValidateValue(ctxt, define->content); | 
 |             } | 
 |             break; | 
 |         default: | 
 |             TODO ret = -1; | 
 |     } | 
 |     return (ret); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGValidateValueContent: | 
 |  * @ctxt:  a Relax-NG validation context | 
 |  * @defines:  the list of definitions to verify | 
 |  * | 
 |  * Validate the given definitions for the current value | 
 |  * | 
 |  * Returns 0 if the validation succeeded or an error code. | 
 |  */ | 
 | static int | 
 | xmlRelaxNGValidateValueContent(xmlRelaxNGValidCtxtPtr ctxt, | 
 |                                xmlRelaxNGDefinePtr defines) | 
 | { | 
 |     int ret = 0; | 
 |  | 
 |     while (defines != NULL) { | 
 |         ret = xmlRelaxNGValidateValue(ctxt, defines); | 
 |         if (ret != 0) | 
 |             break; | 
 |         defines = defines->next; | 
 |     } | 
 |     return (ret); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGAttributeMatch: | 
 |  * @ctxt:  a Relax-NG validation context | 
 |  * @define:  the definition to check | 
 |  * @prop:  the attribute | 
 |  * | 
 |  * Check if the attribute matches the definition nameClass | 
 |  * | 
 |  * Returns 1 if the attribute matches, 0 if no, or -1 in case of error | 
 |  */ | 
 | static int | 
 | xmlRelaxNGAttributeMatch(xmlRelaxNGValidCtxtPtr ctxt, | 
 |                          xmlRelaxNGDefinePtr define, xmlAttrPtr prop) | 
 | { | 
 |     int ret; | 
 |  | 
 |     if (define->name != NULL) { | 
 |         if (!xmlStrEqual(define->name, prop->name)) | 
 |             return (0); | 
 |     } | 
 |     if (define->ns != NULL) { | 
 |         if (define->ns[0] == 0) { | 
 |             if (prop->ns != NULL) | 
 |                 return (0); | 
 |         } else { | 
 |             if ((prop->ns == NULL) || | 
 |                 (!xmlStrEqual(define->ns, prop->ns->href))) | 
 |                 return (0); | 
 |         } | 
 |     } | 
 |     if (define->nameClass == NULL) | 
 |         return (1); | 
 |     define = define->nameClass; | 
 |     if (define->type == XML_RELAXNG_EXCEPT) { | 
 |         xmlRelaxNGDefinePtr list; | 
 |  | 
 |         list = define->content; | 
 |         while (list != NULL) { | 
 |             ret = xmlRelaxNGAttributeMatch(ctxt, list, prop); | 
 |             if (ret == 1) | 
 |                 return (0); | 
 |             if (ret < 0) | 
 |                 return (ret); | 
 |             list = list->next; | 
 |         } | 
 |     } else { | 
 |     TODO} | 
 |     return (1); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGValidateAttribute: | 
 |  * @ctxt:  a Relax-NG validation context | 
 |  * @define:  the definition to verify | 
 |  * | 
 |  * Validate the given attribute definition for that node | 
 |  * | 
 |  * Returns 0 if the validation succeeded or an error code. | 
 |  */ | 
 | static int | 
 | xmlRelaxNGValidateAttribute(xmlRelaxNGValidCtxtPtr ctxt, | 
 |                             xmlRelaxNGDefinePtr define) | 
 | { | 
 |     int ret = 0, i; | 
 |     xmlChar *value, *oldvalue; | 
 |     xmlAttrPtr prop = NULL, tmp; | 
 |     xmlNodePtr oldseq; | 
 |  | 
 |     if (ctxt->state->nbAttrLeft <= 0) | 
 |         return (-1); | 
 |     if (define->name != NULL) { | 
 |         for (i = 0; i < ctxt->state->nbAttrs; i++) { | 
 |             tmp = ctxt->state->attrs[i]; | 
 |             if ((tmp != NULL) && (xmlStrEqual(define->name, tmp->name))) { | 
 |                 if ((((define->ns == NULL) || (define->ns[0] == 0)) && | 
 |                      (tmp->ns == NULL)) || | 
 |                     ((tmp->ns != NULL) && | 
 |                      (xmlStrEqual(define->ns, tmp->ns->href)))) { | 
 |                     prop = tmp; | 
 |                     break; | 
 |                 } | 
 |             } | 
 |         } | 
 |         if (prop != NULL) { | 
 |             value = xmlNodeListGetString(prop->doc, prop->children, 1); | 
 |             oldvalue = ctxt->state->value; | 
 |             oldseq = ctxt->state->seq; | 
 |             ctxt->state->seq = (xmlNodePtr) prop; | 
 |             ctxt->state->value = value; | 
 |             ctxt->state->endvalue = NULL; | 
 |             ret = xmlRelaxNGValidateValueContent(ctxt, define->content); | 
 |             if (ctxt->state->value != NULL) | 
 |                 value = ctxt->state->value; | 
 |             if (value != NULL) | 
 |                 xmlFree(value); | 
 |             ctxt->state->value = oldvalue; | 
 |             ctxt->state->seq = oldseq; | 
 |             if (ret == 0) { | 
 |                 /* | 
 |                  * flag the attribute as processed | 
 |                  */ | 
 |                 ctxt->state->attrs[i] = NULL; | 
 |                 ctxt->state->nbAttrLeft--; | 
 |             } | 
 |         } else { | 
 |             ret = -1; | 
 |         } | 
 | #ifdef DEBUG | 
 |         xmlGenericError(xmlGenericErrorContext, | 
 |                         "xmlRelaxNGValidateAttribute(%s): %d\n", | 
 |                         define->name, ret); | 
 | #endif | 
 |     } else { | 
 |         for (i = 0; i < ctxt->state->nbAttrs; i++) { | 
 |             tmp = ctxt->state->attrs[i]; | 
 |             if ((tmp != NULL) && | 
 |                 (xmlRelaxNGAttributeMatch(ctxt, define, tmp) == 1)) { | 
 |                 prop = tmp; | 
 |                 break; | 
 |             } | 
 |         } | 
 |         if (prop != NULL) { | 
 |             value = xmlNodeListGetString(prop->doc, prop->children, 1); | 
 |             oldvalue = ctxt->state->value; | 
 |             oldseq = ctxt->state->seq; | 
 |             ctxt->state->seq = (xmlNodePtr) prop; | 
 |             ctxt->state->value = value; | 
 |             ret = xmlRelaxNGValidateValueContent(ctxt, define->content); | 
 |             if (ctxt->state->value != NULL) | 
 |                 value = ctxt->state->value; | 
 |             if (value != NULL) | 
 |                 xmlFree(value); | 
 |             ctxt->state->value = oldvalue; | 
 |             ctxt->state->seq = oldseq; | 
 |             if (ret == 0) { | 
 |                 /* | 
 |                  * flag the attribute as processed | 
 |                  */ | 
 |                 ctxt->state->attrs[i] = NULL; | 
 |                 ctxt->state->nbAttrLeft--; | 
 |             } | 
 |         } else { | 
 |             ret = -1; | 
 |         } | 
 | #ifdef DEBUG | 
 |         if (define->ns != NULL) { | 
 |             xmlGenericError(xmlGenericErrorContext, | 
 |                             "xmlRelaxNGValidateAttribute(nsName ns = %s): %d\n", | 
 |                             define->ns, ret); | 
 |         } else { | 
 |             xmlGenericError(xmlGenericErrorContext, | 
 |                             "xmlRelaxNGValidateAttribute(anyName): %d\n", | 
 |                             ret); | 
 |         } | 
 | #endif | 
 |     } | 
 |  | 
 |     return (ret); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGValidateAttributeList: | 
 |  * @ctxt:  a Relax-NG validation context | 
 |  * @define:  the list of definition to verify | 
 |  * | 
 |  * Validate the given node against the list of attribute definitions | 
 |  * | 
 |  * Returns 0 if the validation succeeded or an error code. | 
 |  */ | 
 | static int | 
 | xmlRelaxNGValidateAttributeList(xmlRelaxNGValidCtxtPtr ctxt, | 
 |                                 xmlRelaxNGDefinePtr defines) | 
 | { | 
 |     int ret = 0, res; | 
 |     int needmore = 0; | 
 |     xmlRelaxNGDefinePtr cur; | 
 |  | 
 |     cur = defines; | 
 |     while (cur != NULL) { | 
 |         if (cur->type == XML_RELAXNG_ATTRIBUTE) { | 
 |             if (xmlRelaxNGValidateAttribute(ctxt, cur) != 0) | 
 |                 ret = -1; | 
 |         } else | 
 |             needmore = 1; | 
 |         cur = cur->next; | 
 |     } | 
 |     if (!needmore) | 
 |         return (ret); | 
 |     cur = defines; | 
 |     while (cur != NULL) { | 
 |         if (cur->type != XML_RELAXNG_ATTRIBUTE) { | 
 |             if ((ctxt->state != NULL) || (ctxt->states != NULL)) { | 
 |                 res = xmlRelaxNGValidateDefinition(ctxt, cur); | 
 |                 if (res < 0) | 
 |                     ret = -1; | 
 |             } else { | 
 |                 VALID_ERR(XML_RELAXNG_ERR_NOSTATE); | 
 |                 return (-1); | 
 |             } | 
 |             if (res == -1)      /* continues on -2 */ | 
 |                 break; | 
 |         } | 
 |         cur = cur->next; | 
 |     } | 
 |  | 
 |     return (ret); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGNodeMatchesList: | 
 |  * @node:  the node | 
 |  * @list:  a NULL terminated array of definitions | 
 |  * | 
 |  * Check if a node can be matched by one of the definitions | 
 |  * | 
 |  * Returns 1 if matches 0 otherwise | 
 |  */ | 
 | static int | 
 | xmlRelaxNGNodeMatchesList(xmlNodePtr node, xmlRelaxNGDefinePtr * list) | 
 | { | 
 |     xmlRelaxNGDefinePtr cur; | 
 |     int i = 0, tmp; | 
 |  | 
 |     if ((node == NULL) || (list == NULL)) | 
 |         return (0); | 
 |  | 
 |     cur = list[i++]; | 
 |     while (cur != NULL) { | 
 |         if ((node->type == XML_ELEMENT_NODE) && | 
 |             (cur->type == XML_RELAXNG_ELEMENT)) { | 
 |             tmp = xmlRelaxNGElementMatch(NULL, cur, node); | 
 |             if (tmp == 1) | 
 |                 return (1); | 
 |         } else if (((node->type == XML_TEXT_NODE) || | 
 |                     (node->type == XML_CDATA_SECTION_NODE)) && | 
 |                    (cur->type == XML_RELAXNG_TEXT)) { | 
 |             return (1); | 
 |         } | 
 |         cur = list[i++]; | 
 |     } | 
 |     return (0); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGValidateInterleave: | 
 |  * @ctxt:  a Relax-NG validation context | 
 |  * @define:  the definition to verify | 
 |  * | 
 |  * Validate an interleave definition for a node. | 
 |  * | 
 |  * Returns 0 if the validation succeeded or an error code. | 
 |  */ | 
 | static int | 
 | xmlRelaxNGValidateInterleave(xmlRelaxNGValidCtxtPtr ctxt, | 
 |                              xmlRelaxNGDefinePtr define) | 
 | { | 
 |     int ret = 0, i, nbgroups; | 
 |     int errNr = ctxt->errNr; | 
 |     int oldflags; | 
 |  | 
 |     xmlRelaxNGValidStatePtr oldstate; | 
 |     xmlRelaxNGPartitionPtr partitions; | 
 |     xmlRelaxNGInterleaveGroupPtr group = NULL; | 
 |     xmlNodePtr cur, start, last = NULL, lastchg = NULL, lastelem; | 
 |     xmlNodePtr *list = NULL, *lasts = NULL; | 
 |  | 
 |     if (define->data != NULL) { | 
 |         partitions = (xmlRelaxNGPartitionPtr) define->data; | 
 |         nbgroups = partitions->nbgroups; | 
 |     } else { | 
 |         VALID_ERR(XML_RELAXNG_ERR_INTERNODATA); | 
 |         return (-1); | 
 |     } | 
 |     /* | 
 |      * Optimizations for MIXED | 
 |      */ | 
 |     oldflags = ctxt->flags; | 
 |     if (define->dflags & IS_MIXED) { | 
 |         ctxt->flags |= FLAGS_MIXED_CONTENT; | 
 |         if (nbgroups == 2) { | 
 |             /* | 
 |              * this is a pure <mixed> case | 
 |              */ | 
 |             if (ctxt->state != NULL) | 
 |                 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt, | 
 |                                                          ctxt->state->seq); | 
 |             if (partitions->groups[0]->rule->type == XML_RELAXNG_TEXT) | 
 |                 ret = xmlRelaxNGValidateDefinition(ctxt, | 
 |                                                    partitions->groups[1]-> | 
 |                                                    rule); | 
 |             else | 
 |                 ret = xmlRelaxNGValidateDefinition(ctxt, | 
 |                                                    partitions->groups[0]-> | 
 |                                                    rule); | 
 |             if (ret == 0) { | 
 |                 if (ctxt->state != NULL) | 
 |                     ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt, | 
 |                                                              ctxt->state-> | 
 |                                                              seq); | 
 |             } | 
 |             ctxt->flags = oldflags; | 
 |             return (ret); | 
 |         } | 
 |     } | 
 |  | 
 |     /* | 
 |      * Build arrays to store the first and last node of the chain | 
 |      * pertaining to each group | 
 |      */ | 
 |     list = (xmlNodePtr *) xmlMalloc(nbgroups * sizeof(xmlNodePtr)); | 
 |     if (list == NULL) { | 
 |         xmlRngVErrMemory(ctxt, "validating\n"); | 
 |         return (-1); | 
 |     } | 
 |     memset(list, 0, nbgroups * sizeof(xmlNodePtr)); | 
 |     lasts = (xmlNodePtr *) xmlMalloc(nbgroups * sizeof(xmlNodePtr)); | 
 |     if (lasts == NULL) { | 
 |         xmlRngVErrMemory(ctxt, "validating\n"); | 
 |         return (-1); | 
 |     } | 
 |     memset(lasts, 0, nbgroups * sizeof(xmlNodePtr)); | 
 |  | 
 |     /* | 
 |      * Walk the sequence of children finding the right group and | 
 |      * sorting them in sequences. | 
 |      */ | 
 |     cur = ctxt->state->seq; | 
 |     cur = xmlRelaxNGSkipIgnored(ctxt, cur); | 
 |     start = cur; | 
 |     while (cur != NULL) { | 
 |         ctxt->state->seq = cur; | 
 |         if ((partitions->triage != NULL) && | 
 |             (partitions->flags & IS_DETERMINIST)) { | 
 |             void *tmp = NULL; | 
 |  | 
 |             if ((cur->type == XML_TEXT_NODE) || | 
 |                 (cur->type == XML_CDATA_SECTION_NODE)) { | 
 |                 tmp = xmlHashLookup2(partitions->triage, BAD_CAST "#text", | 
 |                                      NULL); | 
 |             } else if (cur->type == XML_ELEMENT_NODE) { | 
 |                 if (cur->ns != NULL) { | 
 |                     tmp = xmlHashLookup2(partitions->triage, cur->name, | 
 |                                          cur->ns->href); | 
 |                     if (tmp == NULL) | 
 |                         tmp = xmlHashLookup2(partitions->triage, | 
 |                                              BAD_CAST "#any", | 
 |                                              cur->ns->href); | 
 |                 } else | 
 |                     tmp = | 
 |                         xmlHashLookup2(partitions->triage, cur->name, | 
 |                                        NULL); | 
 |                 if (tmp == NULL) | 
 |                     tmp = | 
 |                         xmlHashLookup2(partitions->triage, BAD_CAST "#any", | 
 |                                        NULL); | 
 |             } | 
 |  | 
 |             if (tmp == NULL) { | 
 |                 i = nbgroups; | 
 |             } else { | 
 |                 i = ((long) tmp) - 1; | 
 |                 if (partitions->flags & IS_NEEDCHECK) { | 
 |                     group = partitions->groups[i]; | 
 |                     if (!xmlRelaxNGNodeMatchesList(cur, group->defs)) | 
 |                         i = nbgroups; | 
 |                 } | 
 |             } | 
 |         } else { | 
 |             for (i = 0; i < nbgroups; i++) { | 
 |                 group = partitions->groups[i]; | 
 |                 if (group == NULL) | 
 |                     continue; | 
 |                 if (xmlRelaxNGNodeMatchesList(cur, group->defs)) | 
 |                     break; | 
 |             } | 
 |         } | 
 |         /* | 
 |          * We break as soon as an element not matched is found | 
 |          */ | 
 |         if (i >= nbgroups) { | 
 |             break; | 
 |         } | 
 |         if (lasts[i] != NULL) { | 
 |             lasts[i]->next = cur; | 
 |             lasts[i] = cur; | 
 |         } else { | 
 |             list[i] = cur; | 
 |             lasts[i] = cur; | 
 |         } | 
 |         if (cur->next != NULL) | 
 |             lastchg = cur->next; | 
 |         else | 
 |             lastchg = cur; | 
 |         cur = xmlRelaxNGSkipIgnored(ctxt, cur->next); | 
 |     } | 
 |     if (ret != 0) { | 
 |         VALID_ERR(XML_RELAXNG_ERR_INTERSEQ); | 
 |         ret = -1; | 
 |         goto done; | 
 |     } | 
 |     lastelem = cur; | 
 |     oldstate = ctxt->state; | 
 |     for (i = 0; i < nbgroups; i++) { | 
 |         ctxt->state = xmlRelaxNGCopyValidState(ctxt, oldstate); | 
 |         group = partitions->groups[i]; | 
 |         if (lasts[i] != NULL) { | 
 |             last = lasts[i]->next; | 
 |             lasts[i]->next = NULL; | 
 |         } | 
 |         ctxt->state->seq = list[i]; | 
 |         ret = xmlRelaxNGValidateDefinition(ctxt, group->rule); | 
 |         if (ret != 0) | 
 |             break; | 
 |         if (ctxt->state != NULL) { | 
 |             cur = ctxt->state->seq; | 
 |             cur = xmlRelaxNGSkipIgnored(ctxt, cur); | 
 |             xmlRelaxNGFreeValidState(ctxt, oldstate); | 
 |             oldstate = ctxt->state; | 
 |             ctxt->state = NULL; | 
 |             if (cur != NULL) { | 
 |                 VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA, cur->name); | 
 |                 ret = -1; | 
 |                 ctxt->state = oldstate; | 
 |                 goto done; | 
 |             } | 
 |         } else if (ctxt->states != NULL) { | 
 |             int j; | 
 |             int found = 0; | 
 | 	    int best = -1; | 
 | 	    int lowattr = -1; | 
 |  | 
 | 	    /* | 
 | 	     * PBM: what happen if there is attributes checks in the interleaves | 
 | 	     */ | 
 |  | 
 |             for (j = 0; j < ctxt->states->nbState; j++) { | 
 |                 cur = ctxt->states->tabState[j]->seq; | 
 |                 cur = xmlRelaxNGSkipIgnored(ctxt, cur); | 
 |                 if (cur == NULL) { | 
 | 		    if (found == 0) { | 
 | 		        lowattr = ctxt->states->tabState[j]->nbAttrLeft; | 
 | 			best = j; | 
 | 		    } | 
 |                     found = 1; | 
 | 		    if (ctxt->states->tabState[j]->nbAttrLeft <= lowattr) { | 
 | 		        /* try  to keep the latest one to mach old heuristic */ | 
 | 		        lowattr = ctxt->states->tabState[j]->nbAttrLeft; | 
 | 			best = j; | 
 | 		    } | 
 |                     if (lowattr == 0) | 
 | 		        break; | 
 |                 } else if (found == 0) { | 
 |                     if (lowattr == -1) { | 
 | 		        lowattr = ctxt->states->tabState[j]->nbAttrLeft; | 
 | 			best = j; | 
 | 		    } else | 
 | 		    if (ctxt->states->tabState[j]->nbAttrLeft <= lowattr)  { | 
 | 		        /* try  to keep the latest one to mach old heuristic */ | 
 | 		        lowattr = ctxt->states->tabState[j]->nbAttrLeft; | 
 | 			best = j; | 
 | 		    } | 
 | 		} | 
 |             } | 
 | 	    /* | 
 | 	     * BIG PBM: here we pick only one restarting point :-( | 
 | 	     */ | 
 |             if (ctxt->states->nbState > 0) { | 
 |                 xmlRelaxNGFreeValidState(ctxt, oldstate); | 
 | 		if (best != -1) { | 
 | 		    oldstate = ctxt->states->tabState[best]; | 
 | 		    ctxt->states->tabState[best] = NULL; | 
 | 		} else { | 
 | 		    oldstate = | 
 | 			ctxt->states->tabState[ctxt->states->nbState - 1]; | 
 |                     ctxt->states->tabState[ctxt->states->nbState - 1] = NULL; | 
 |                     ctxt->states->nbState--; | 
 | 		} | 
 |             } | 
 |             for (j = 0; j < ctxt->states->nbState ; j++) { | 
 |                 xmlRelaxNGFreeValidState(ctxt, ctxt->states->tabState[j]); | 
 |             } | 
 |             xmlRelaxNGFreeStates(ctxt, ctxt->states); | 
 |             ctxt->states = NULL; | 
 |             if (found == 0) { | 
 |                 if (cur == NULL) { | 
 | 		    VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA, | 
 | 			       (const xmlChar *) "noname"); | 
 |                 } else { | 
 |                     VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA, cur->name); | 
 |                 } | 
 |                 ret = -1; | 
 |                 ctxt->state = oldstate; | 
 |                 goto done; | 
 |             } | 
 |         } else { | 
 |             ret = -1; | 
 |             break; | 
 |         } | 
 |         if (lasts[i] != NULL) { | 
 |             lasts[i]->next = last; | 
 |         } | 
 |     } | 
 |     if (ctxt->state != NULL) | 
 |         xmlRelaxNGFreeValidState(ctxt, ctxt->state); | 
 |     ctxt->state = oldstate; | 
 |     ctxt->state->seq = lastelem; | 
 |     if (ret != 0) { | 
 |         VALID_ERR(XML_RELAXNG_ERR_INTERSEQ); | 
 |         ret = -1; | 
 |         goto done; | 
 |     } | 
 |  | 
 |   done: | 
 |     ctxt->flags = oldflags; | 
 |     /* | 
 |      * builds the next links chain from the prev one | 
 |      */ | 
 |     cur = lastchg; | 
 |     while (cur != NULL) { | 
 |         if ((cur == start) || (cur->prev == NULL)) | 
 |             break; | 
 |         cur->prev->next = cur; | 
 |         cur = cur->prev; | 
 |     } | 
 |     if (ret == 0) { | 
 |         if (ctxt->errNr > errNr) | 
 |             xmlRelaxNGPopErrors(ctxt, errNr); | 
 |     } | 
 |  | 
 |     xmlFree(list); | 
 |     xmlFree(lasts); | 
 |     return (ret); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGValidateDefinitionList: | 
 |  * @ctxt:  a Relax-NG validation context | 
 |  * @define:  the list of definition to verify | 
 |  * | 
 |  * Validate the given node content against the (list) of definitions | 
 |  * | 
 |  * Returns 0 if the validation succeeded or an error code. | 
 |  */ | 
 | static int | 
 | xmlRelaxNGValidateDefinitionList(xmlRelaxNGValidCtxtPtr ctxt, | 
 |                                  xmlRelaxNGDefinePtr defines) | 
 | { | 
 |     int ret = 0, res; | 
 |  | 
 |  | 
 |     if (defines == NULL) { | 
 |         VALID_ERR2(XML_RELAXNG_ERR_INTERNAL, | 
 |                    BAD_CAST "NULL definition list"); | 
 |         return (-1); | 
 |     } | 
 |     while (defines != NULL) { | 
 |         if ((ctxt->state != NULL) || (ctxt->states != NULL)) { | 
 |             res = xmlRelaxNGValidateDefinition(ctxt, defines); | 
 |             if (res < 0) | 
 |                 ret = -1; | 
 |         } else { | 
 |             VALID_ERR(XML_RELAXNG_ERR_NOSTATE); | 
 |             return (-1); | 
 |         } | 
 |         if (res == -1)          /* continues on -2 */ | 
 |             break; | 
 |         defines = defines->next; | 
 |     } | 
 |  | 
 |     return (ret); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGElementMatch: | 
 |  * @ctxt:  a Relax-NG validation context | 
 |  * @define:  the definition to check | 
 |  * @elem:  the element | 
 |  * | 
 |  * Check if the element matches the definition nameClass | 
 |  * | 
 |  * Returns 1 if the element matches, 0 if no, or -1 in case of error | 
 |  */ | 
 | static int | 
 | xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt, | 
 |                        xmlRelaxNGDefinePtr define, xmlNodePtr elem) | 
 | { | 
 |     int ret = 0, oldflags = 0; | 
 |  | 
 |     if (define->name != NULL) { | 
 |         if (!xmlStrEqual(elem->name, define->name)) { | 
 |             VALID_ERR3(XML_RELAXNG_ERR_ELEMNAME, define->name, elem->name); | 
 |             return (0); | 
 |         } | 
 |     } | 
 |     if ((define->ns != NULL) && (define->ns[0] != 0)) { | 
 |         if (elem->ns == NULL) { | 
 |             VALID_ERR2(XML_RELAXNG_ERR_ELEMNONS, elem->name); | 
 |             return (0); | 
 |         } else if (!xmlStrEqual(elem->ns->href, define->ns)) { | 
 |             VALID_ERR3(XML_RELAXNG_ERR_ELEMWRONGNS, | 
 |                        elem->name, define->ns); | 
 |             return (0); | 
 |         } | 
 |     } else if ((elem->ns != NULL) && (define->ns != NULL) && | 
 |                (define->name == NULL)) { | 
 |         VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS, elem->name); | 
 |         return (0); | 
 |     } else if ((elem->ns != NULL) && (define->name != NULL)) { | 
 |         VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS, define->name); | 
 |         return (0); | 
 |     } | 
 |  | 
 |     if (define->nameClass == NULL) | 
 |         return (1); | 
 |  | 
 |     define = define->nameClass; | 
 |     if (define->type == XML_RELAXNG_EXCEPT) { | 
 |         xmlRelaxNGDefinePtr list; | 
 |  | 
 |         if (ctxt != NULL) { | 
 |             oldflags = ctxt->flags; | 
 |             ctxt->flags |= FLAGS_IGNORABLE; | 
 |         } | 
 |  | 
 |         list = define->content; | 
 |         while (list != NULL) { | 
 |             ret = xmlRelaxNGElementMatch(ctxt, list, elem); | 
 |             if (ret == 1) { | 
 |                 if (ctxt != NULL) | 
 |                     ctxt->flags = oldflags; | 
 |                 return (0); | 
 |             } | 
 |             if (ret < 0) { | 
 |                 if (ctxt != NULL) | 
 |                     ctxt->flags = oldflags; | 
 |                 return (ret); | 
 |             } | 
 |             list = list->next; | 
 |         } | 
 |         ret = 1; | 
 |         if (ctxt != NULL) { | 
 |             ctxt->flags = oldflags; | 
 |         } | 
 |     } else if (define->type == XML_RELAXNG_CHOICE) { | 
 |         xmlRelaxNGDefinePtr list; | 
 |  | 
 |         if (ctxt != NULL) { | 
 |             oldflags = ctxt->flags; | 
 |             ctxt->flags |= FLAGS_IGNORABLE; | 
 |         } | 
 |  | 
 |         list = define->nameClass; | 
 |         while (list != NULL) { | 
 |             ret = xmlRelaxNGElementMatch(ctxt, list, elem); | 
 |             if (ret == 1) { | 
 |                 if (ctxt != NULL) | 
 |                     ctxt->flags = oldflags; | 
 |                 return (1); | 
 |             } | 
 |             if (ret < 0) { | 
 |                 if (ctxt != NULL) | 
 |                     ctxt->flags = oldflags; | 
 |                 return (ret); | 
 |             } | 
 |             list = list->next; | 
 |         } | 
 |         if (ctxt != NULL) { | 
 |             if (ret != 0) { | 
 |                 if ((ctxt->flags & FLAGS_IGNORABLE) == 0) | 
 |                     xmlRelaxNGDumpValidError(ctxt); | 
 |             } else { | 
 |                 if (ctxt->errNr > 0) | 
 |                     xmlRelaxNGPopErrors(ctxt, 0); | 
 |             } | 
 |         } | 
 |         ret = 0; | 
 |         if (ctxt != NULL) { | 
 |             ctxt->flags = oldflags; | 
 |         } | 
 |     } else { | 
 |         TODO ret = -1; | 
 |     } | 
 |     return (ret); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGBestState: | 
 |  * @ctxt:  a Relax-NG validation context | 
 |  * | 
 |  * Find the "best" state in the ctxt->states list of states to report | 
 |  * errors about. I.e. a state with no element left in the child list | 
 |  * or the one with the less attributes left. | 
 |  * This is called only if a falidation error was detected | 
 |  * | 
 |  * Returns the index of the "best" state or -1 in case of error | 
 |  */ | 
 | static int | 
 | xmlRelaxNGBestState(xmlRelaxNGValidCtxtPtr ctxt) | 
 | { | 
 |     xmlRelaxNGValidStatePtr state; | 
 |     int i, tmp; | 
 |     int best = -1; | 
 |     int value = 1000000; | 
 |  | 
 |     if ((ctxt == NULL) || (ctxt->states == NULL) || | 
 |         (ctxt->states->nbState <= 0)) | 
 |         return (-1); | 
 |  | 
 |     for (i = 0; i < ctxt->states->nbState; i++) { | 
 |         state = ctxt->states->tabState[i]; | 
 |         if (state == NULL) | 
 |             continue; | 
 |         if (state->seq != NULL) { | 
 |             if ((best == -1) || (value > 100000)) { | 
 |                 value = 100000; | 
 |                 best = i; | 
 |             } | 
 |         } else { | 
 |             tmp = state->nbAttrLeft; | 
 |             if ((best == -1) || (value > tmp)) { | 
 |                 value = tmp; | 
 |                 best = i; | 
 |             } | 
 |         } | 
 |     } | 
 |     return (best); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGLogBestError: | 
 |  * @ctxt:  a Relax-NG validation context | 
 |  * | 
 |  * Find the "best" state in the ctxt->states list of states to report | 
 |  * errors about and log it. | 
 |  */ | 
 | static void | 
 | xmlRelaxNGLogBestError(xmlRelaxNGValidCtxtPtr ctxt) | 
 | { | 
 |     int best; | 
 |  | 
 |     if ((ctxt == NULL) || (ctxt->states == NULL) || | 
 |         (ctxt->states->nbState <= 0)) | 
 |         return; | 
 |  | 
 |     best = xmlRelaxNGBestState(ctxt); | 
 |     if ((best >= 0) && (best < ctxt->states->nbState)) { | 
 |         ctxt->state = ctxt->states->tabState[best]; | 
 |  | 
 |         xmlRelaxNGValidateElementEnd(ctxt, 1); | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGValidateElementEnd: | 
 |  * @ctxt:  a Relax-NG validation context | 
 |  * @dolog:  indicate that error logging should be done | 
 |  * | 
 |  * Validate the end of the element, implements check that | 
 |  * there is nothing left not consumed in the element content | 
 |  * or in the attribute list. | 
 |  * | 
 |  * Returns 0 if the validation succeeded or an error code. | 
 |  */ | 
 | static int | 
 | xmlRelaxNGValidateElementEnd(xmlRelaxNGValidCtxtPtr ctxt, int dolog) | 
 | { | 
 |     int i; | 
 |     xmlRelaxNGValidStatePtr state; | 
 |  | 
 |     state = ctxt->state; | 
 |     if (state->seq != NULL) { | 
 |         state->seq = xmlRelaxNGSkipIgnored(ctxt, state->seq); | 
 |         if (state->seq != NULL) { | 
 |             if (dolog) { | 
 |                 VALID_ERR3(XML_RELAXNG_ERR_EXTRACONTENT, | 
 |                            state->node->name, state->seq->name); | 
 |             } | 
 |             return (-1); | 
 |         } | 
 |     } | 
 |     for (i = 0; i < state->nbAttrs; i++) { | 
 |         if (state->attrs[i] != NULL) { | 
 |             if (dolog) { | 
 |                 VALID_ERR3(XML_RELAXNG_ERR_INVALIDATTR, | 
 |                            state->attrs[i]->name, state->node->name); | 
 |             } | 
 |             return (-1 - i); | 
 |         } | 
 |     } | 
 |     return (0); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGValidateState: | 
 |  * @ctxt:  a Relax-NG validation context | 
 |  * @define:  the definition to verify | 
 |  * | 
 |  * Validate the current state against the definition | 
 |  * | 
 |  * Returns 0 if the validation succeeded or an error code. | 
 |  */ | 
 | static int | 
 | xmlRelaxNGValidateState(xmlRelaxNGValidCtxtPtr ctxt, | 
 |                         xmlRelaxNGDefinePtr define) | 
 | { | 
 |     xmlNodePtr node; | 
 |     int ret = 0, i, tmp, oldflags, errNr; | 
 |     xmlRelaxNGValidStatePtr oldstate = NULL, state; | 
 |  | 
 |     if (define == NULL) { | 
 |         VALID_ERR(XML_RELAXNG_ERR_NODEFINE); | 
 |         return (-1); | 
 |     } | 
 |  | 
 |     if (ctxt->state != NULL) { | 
 |         node = ctxt->state->seq; | 
 |     } else { | 
 |         node = NULL; | 
 |     } | 
 | #ifdef DEBUG | 
 |     for (i = 0; i < ctxt->depth; i++) | 
 |         xmlGenericError(xmlGenericErrorContext, " "); | 
 |     xmlGenericError(xmlGenericErrorContext, | 
 |                     "Start validating %s ", xmlRelaxNGDefName(define)); | 
 |     if (define->name != NULL) | 
 |         xmlGenericError(xmlGenericErrorContext, "%s ", define->name); | 
 |     if ((node != NULL) && (node->name != NULL)) | 
 |         xmlGenericError(xmlGenericErrorContext, "on %s\n", node->name); | 
 |     else | 
 |         xmlGenericError(xmlGenericErrorContext, "\n"); | 
 | #endif | 
 |     ctxt->depth++; | 
 |     switch (define->type) { | 
 |         case XML_RELAXNG_EMPTY: | 
 |             node = xmlRelaxNGSkipIgnored(ctxt, node); | 
 |             ret = 0; | 
 |             break; | 
 |         case XML_RELAXNG_NOT_ALLOWED: | 
 |             ret = -1; | 
 |             break; | 
 |         case XML_RELAXNG_TEXT: | 
 |             while ((node != NULL) && | 
 |                    ((node->type == XML_TEXT_NODE) || | 
 |                     (node->type == XML_COMMENT_NODE) || | 
 |                     (node->type == XML_PI_NODE) || | 
 |                     (node->type == XML_CDATA_SECTION_NODE))) | 
 |                 node = node->next; | 
 |             ctxt->state->seq = node; | 
 |             break; | 
 |         case XML_RELAXNG_ELEMENT: | 
 |             errNr = ctxt->errNr; | 
 |             node = xmlRelaxNGSkipIgnored(ctxt, node); | 
 |             if (node == NULL) { | 
 |                 VALID_ERR2(XML_RELAXNG_ERR_NOELEM, define->name); | 
 |                 ret = -1; | 
 |                 if ((ctxt->flags & FLAGS_IGNORABLE) == 0) | 
 |                     xmlRelaxNGDumpValidError(ctxt); | 
 |                 break; | 
 |             } | 
 |             if (node->type != XML_ELEMENT_NODE) { | 
 |                 VALID_ERR(XML_RELAXNG_ERR_NOTELEM); | 
 |                 ret = -1; | 
 |                 if ((ctxt->flags & FLAGS_IGNORABLE) == 0) | 
 |                     xmlRelaxNGDumpValidError(ctxt); | 
 |                 break; | 
 |             } | 
 |             /* | 
 |              * This node was already validated successfully against | 
 |              * this definition. | 
 |              */ | 
 |             if (node->psvi == define) { | 
 |                 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt, node->next); | 
 |                 if (ctxt->errNr > errNr) | 
 |                     xmlRelaxNGPopErrors(ctxt, errNr); | 
 |                 if (ctxt->errNr != 0) { | 
 |                     while ((ctxt->err != NULL) && | 
 |                            (((ctxt->err->err == XML_RELAXNG_ERR_ELEMNAME) | 
 |                              && (xmlStrEqual(ctxt->err->arg2, node->name))) | 
 |                             || | 
 |                             ((ctxt->err->err == | 
 |                               XML_RELAXNG_ERR_ELEMEXTRANS) | 
 |                              && (xmlStrEqual(ctxt->err->arg1, node->name))) | 
 |                             || (ctxt->err->err == XML_RELAXNG_ERR_NOELEM) | 
 |                             || (ctxt->err->err == | 
 |                                 XML_RELAXNG_ERR_NOTELEM))) | 
 |                         xmlRelaxNGValidErrorPop(ctxt); | 
 |                 } | 
 |                 break; | 
 |             } | 
 |  | 
 |             ret = xmlRelaxNGElementMatch(ctxt, define, node); | 
 |             if (ret <= 0) { | 
 |                 ret = -1; | 
 |                 if ((ctxt->flags & FLAGS_IGNORABLE) == 0) | 
 |                     xmlRelaxNGDumpValidError(ctxt); | 
 |                 break; | 
 |             } | 
 |             ret = 0; | 
 |             if (ctxt->errNr != 0) { | 
 |                 if (ctxt->errNr > errNr) | 
 |                     xmlRelaxNGPopErrors(ctxt, errNr); | 
 |                 while ((ctxt->err != NULL) && | 
 |                        (((ctxt->err->err == XML_RELAXNG_ERR_ELEMNAME) && | 
 |                          (xmlStrEqual(ctxt->err->arg2, node->name))) || | 
 |                         ((ctxt->err->err == XML_RELAXNG_ERR_ELEMEXTRANS) && | 
 |                          (xmlStrEqual(ctxt->err->arg1, node->name))) || | 
 |                         (ctxt->err->err == XML_RELAXNG_ERR_NOELEM) || | 
 |                         (ctxt->err->err == XML_RELAXNG_ERR_NOTELEM))) | 
 |                     xmlRelaxNGValidErrorPop(ctxt); | 
 |             } | 
 |             errNr = ctxt->errNr; | 
 |  | 
 |             oldflags = ctxt->flags; | 
 |             if (ctxt->flags & FLAGS_MIXED_CONTENT) { | 
 |                 ctxt->flags -= FLAGS_MIXED_CONTENT; | 
 |             } | 
 |             state = xmlRelaxNGNewValidState(ctxt, node); | 
 |             if (state == NULL) { | 
 |                 ret = -1; | 
 |                 if ((ctxt->flags & FLAGS_IGNORABLE) == 0) | 
 |                     xmlRelaxNGDumpValidError(ctxt); | 
 |                 break; | 
 |             } | 
 |  | 
 |             oldstate = ctxt->state; | 
 |             ctxt->state = state; | 
 |             if (define->attrs != NULL) { | 
 |                 tmp = xmlRelaxNGValidateAttributeList(ctxt, define->attrs); | 
 |                 if (tmp != 0) { | 
 |                     ret = -1; | 
 |                     VALID_ERR2(XML_RELAXNG_ERR_ATTRVALID, node->name); | 
 |                 } | 
 |             } | 
 |             if (define->contModel != NULL) { | 
 |                 xmlRelaxNGValidStatePtr nstate, tmpstate = ctxt->state; | 
 |                 xmlRelaxNGStatesPtr tmpstates = ctxt->states; | 
 |                 xmlNodePtr nseq; | 
 |  | 
 |                 nstate = xmlRelaxNGNewValidState(ctxt, node); | 
 |                 ctxt->state = nstate; | 
 |                 ctxt->states = NULL; | 
 |  | 
 |                 tmp = xmlRelaxNGValidateCompiledContent(ctxt, | 
 |                                                         define->contModel, | 
 |                                                         ctxt->state->seq); | 
 |                 nseq = ctxt->state->seq; | 
 |                 ctxt->state = tmpstate; | 
 |                 ctxt->states = tmpstates; | 
 |                 xmlRelaxNGFreeValidState(ctxt, nstate); | 
 |  | 
 | #ifdef DEBUG_COMPILE | 
 |                 xmlGenericError(xmlGenericErrorContext, | 
 |                                 "Validating content of '%s' : %d\n", | 
 |                                 define->name, tmp); | 
 | #endif | 
 |                 if (tmp != 0) | 
 |                     ret = -1; | 
 |  | 
 |                 if (ctxt->states != NULL) { | 
 |                     tmp = -1; | 
 |  | 
 |                     for (i = 0; i < ctxt->states->nbState; i++) { | 
 |                         state = ctxt->states->tabState[i]; | 
 |                         ctxt->state = state; | 
 |                         ctxt->state->seq = nseq; | 
 |  | 
 |                         if (xmlRelaxNGValidateElementEnd(ctxt, 0) == 0) { | 
 |                             tmp = 0; | 
 |                             break; | 
 |                         } | 
 |                     } | 
 |                     if (tmp != 0) { | 
 |                         /* | 
 |                          * validation error, log the message for the "best" one | 
 |                          */ | 
 |                         ctxt->flags |= FLAGS_IGNORABLE; | 
 |                         xmlRelaxNGLogBestError(ctxt); | 
 |                     } | 
 |                     for (i = 0; i < ctxt->states->nbState; i++) { | 
 |                         xmlRelaxNGFreeValidState(ctxt, | 
 |                                                  ctxt->states-> | 
 |                                                  tabState[i]); | 
 |                     } | 
 |                     xmlRelaxNGFreeStates(ctxt, ctxt->states); | 
 |                     ctxt->flags = oldflags; | 
 |                     ctxt->states = NULL; | 
 |                     if ((ret == 0) && (tmp == -1)) | 
 |                         ret = -1; | 
 |                 } else { | 
 |                     state = ctxt->state; | 
 | 		    if (ctxt->state != NULL) | 
 | 			ctxt->state->seq = nseq; | 
 |                     if (ret == 0) | 
 |                         ret = xmlRelaxNGValidateElementEnd(ctxt, 1); | 
 |                     xmlRelaxNGFreeValidState(ctxt, state); | 
 |                 } | 
 |             } else { | 
 |                 if (define->content != NULL) { | 
 |                     tmp = xmlRelaxNGValidateDefinitionList(ctxt, | 
 |                                                            define-> | 
 |                                                            content); | 
 |                     if (tmp != 0) { | 
 |                         ret = -1; | 
 |                         if (ctxt->state == NULL) { | 
 |                             ctxt->state = oldstate; | 
 |                             VALID_ERR2(XML_RELAXNG_ERR_CONTENTVALID, | 
 |                                        node->name); | 
 |                             ctxt->state = NULL; | 
 |                         } else { | 
 |                             VALID_ERR2(XML_RELAXNG_ERR_CONTENTVALID, | 
 |                                        node->name); | 
 |                         } | 
 |  | 
 |                     } | 
 |                 } | 
 |                 if (ctxt->states != NULL) { | 
 |                     tmp = -1; | 
 |  | 
 |                     for (i = 0; i < ctxt->states->nbState; i++) { | 
 |                         state = ctxt->states->tabState[i]; | 
 |                         ctxt->state = state; | 
 |  | 
 |                         if (xmlRelaxNGValidateElementEnd(ctxt, 0) == 0) { | 
 |                             tmp = 0; | 
 |                             break; | 
 |                         } | 
 |                     } | 
 |                     if (tmp != 0) { | 
 |                         /* | 
 |                          * validation error, log the message for the "best" one | 
 |                          */ | 
 |                         ctxt->flags |= FLAGS_IGNORABLE; | 
 |                         xmlRelaxNGLogBestError(ctxt); | 
 |                     } | 
 |                     for (i = 0; i < ctxt->states->nbState; i++) { | 
 |                         xmlRelaxNGFreeValidState(ctxt, | 
 |                                                  ctxt->states->tabState[i]); | 
 |                         ctxt->states->tabState[i] = NULL; | 
 |                     } | 
 |                     xmlRelaxNGFreeStates(ctxt, ctxt->states); | 
 |                     ctxt->flags = oldflags; | 
 |                     ctxt->states = NULL; | 
 |                     if ((ret == 0) && (tmp == -1)) | 
 |                         ret = -1; | 
 |                 } else { | 
 |                     state = ctxt->state; | 
 |                     if (ret == 0) | 
 |                         ret = xmlRelaxNGValidateElementEnd(ctxt, 1); | 
 |                     xmlRelaxNGFreeValidState(ctxt, state); | 
 |                 } | 
 |             } | 
 |             if (ret == 0) { | 
 |                 node->psvi = define; | 
 |             } | 
 |             ctxt->flags = oldflags; | 
 |             ctxt->state = oldstate; | 
 |             if (oldstate != NULL) | 
 |                 oldstate->seq = xmlRelaxNGSkipIgnored(ctxt, node->next); | 
 |             if (ret != 0) { | 
 |                 if ((ctxt->flags & FLAGS_IGNORABLE) == 0) { | 
 |                     xmlRelaxNGDumpValidError(ctxt); | 
 |                     ret = 0; | 
 | #if 0 | 
 |                 } else { | 
 |                     ret = -2; | 
 | #endif | 
 |                 } | 
 |             } else { | 
 |                 if (ctxt->errNr > errNr) | 
 |                     xmlRelaxNGPopErrors(ctxt, errNr); | 
 |             } | 
 |  | 
 | #ifdef DEBUG | 
 |             xmlGenericError(xmlGenericErrorContext, | 
 |                             "xmlRelaxNGValidateDefinition(): validated %s : %d", | 
 |                             node->name, ret); | 
 |             if (oldstate == NULL) | 
 |                 xmlGenericError(xmlGenericErrorContext, ": no state\n"); | 
 |             else if (oldstate->seq == NULL) | 
 |                 xmlGenericError(xmlGenericErrorContext, ": done\n"); | 
 |             else if (oldstate->seq->type == XML_ELEMENT_NODE) | 
 |                 xmlGenericError(xmlGenericErrorContext, ": next elem %s\n", | 
 |                                 oldstate->seq->name); | 
 |             else | 
 |                 xmlGenericError(xmlGenericErrorContext, ": next %s %d\n", | 
 |                                 oldstate->seq->name, oldstate->seq->type); | 
 | #endif | 
 |             break; | 
 |         case XML_RELAXNG_OPTIONAL:{ | 
 |                 errNr = ctxt->errNr; | 
 |                 oldflags = ctxt->flags; | 
 |                 ctxt->flags |= FLAGS_IGNORABLE; | 
 |                 oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state); | 
 |                 ret = | 
 |                     xmlRelaxNGValidateDefinitionList(ctxt, | 
 |                                                      define->content); | 
 |                 if (ret != 0) { | 
 |                     if (ctxt->state != NULL) | 
 |                         xmlRelaxNGFreeValidState(ctxt, ctxt->state); | 
 |                     ctxt->state = oldstate; | 
 |                     ctxt->flags = oldflags; | 
 |                     ret = 0; | 
 |                     if (ctxt->errNr > errNr) | 
 |                         xmlRelaxNGPopErrors(ctxt, errNr); | 
 |                     break; | 
 |                 } | 
 |                 if (ctxt->states != NULL) { | 
 |                     xmlRelaxNGAddStates(ctxt, ctxt->states, oldstate); | 
 |                 } else { | 
 |                     ctxt->states = xmlRelaxNGNewStates(ctxt, 1); | 
 |                     if (ctxt->states == NULL) { | 
 |                         xmlRelaxNGFreeValidState(ctxt, oldstate); | 
 |                         ctxt->flags = oldflags; | 
 |                         ret = -1; | 
 |                         if (ctxt->errNr > errNr) | 
 |                             xmlRelaxNGPopErrors(ctxt, errNr); | 
 |                         break; | 
 |                     } | 
 |                     xmlRelaxNGAddStates(ctxt, ctxt->states, oldstate); | 
 |                     xmlRelaxNGAddStates(ctxt, ctxt->states, ctxt->state); | 
 |                     ctxt->state = NULL; | 
 |                 } | 
 |                 ctxt->flags = oldflags; | 
 |                 ret = 0; | 
 |                 if (ctxt->errNr > errNr) | 
 |                     xmlRelaxNGPopErrors(ctxt, errNr); | 
 |                 break; | 
 |             } | 
 |         case XML_RELAXNG_ONEORMORE: | 
 |             errNr = ctxt->errNr; | 
 |             ret = xmlRelaxNGValidateDefinitionList(ctxt, define->content); | 
 |             if (ret != 0) { | 
 |                 break; | 
 |             } | 
 |             if (ctxt->errNr > errNr) | 
 |                 xmlRelaxNGPopErrors(ctxt, errNr); | 
 |             /* no break on purpose */ | 
 |         case XML_RELAXNG_ZEROORMORE:{ | 
 |                 int progress; | 
 |                 xmlRelaxNGStatesPtr states = NULL, res = NULL; | 
 |                 int base, j; | 
 |  | 
 |                 errNr = ctxt->errNr; | 
 |                 res = xmlRelaxNGNewStates(ctxt, 1); | 
 |                 if (res == NULL) { | 
 |                     ret = -1; | 
 |                     break; | 
 |                 } | 
 |                 /* | 
 |                  * All the input states are also exit states | 
 |                  */ | 
 |                 if (ctxt->state != NULL) { | 
 |                     xmlRelaxNGAddStates(ctxt, res, | 
 |                                         xmlRelaxNGCopyValidState(ctxt, | 
 |                                                                  ctxt-> | 
 |                                                                  state)); | 
 |                 } else { | 
 |                     for (j = 0; j < ctxt->states->nbState; j++) { | 
 |                         xmlRelaxNGAddStates(ctxt, res, | 
 |                             xmlRelaxNGCopyValidState(ctxt, | 
 |                                             ctxt->states->tabState[j])); | 
 |                     } | 
 |                 } | 
 |                 oldflags = ctxt->flags; | 
 |                 ctxt->flags |= FLAGS_IGNORABLE; | 
 |                 do { | 
 |                     progress = 0; | 
 |                     base = res->nbState; | 
 |  | 
 |                     if (ctxt->states != NULL) { | 
 |                         states = ctxt->states; | 
 |                         for (i = 0; i < states->nbState; i++) { | 
 |                             ctxt->state = states->tabState[i]; | 
 |                             ctxt->states = NULL; | 
 |                             ret = xmlRelaxNGValidateDefinitionList(ctxt, | 
 |                                                                    define-> | 
 |                                                                    content); | 
 |                             if (ret == 0) { | 
 |                                 if (ctxt->state != NULL) { | 
 |                                     tmp = xmlRelaxNGAddStates(ctxt, res, | 
 |                                                               ctxt->state); | 
 |                                     ctxt->state = NULL; | 
 |                                     if (tmp == 1) | 
 |                                         progress = 1; | 
 |                                 } else if (ctxt->states != NULL) { | 
 |                                     for (j = 0; j < ctxt->states->nbState; | 
 |                                          j++) { | 
 |                                         tmp = | 
 |                                             xmlRelaxNGAddStates(ctxt, res, | 
 |                                                    ctxt->states->tabState[j]); | 
 |                                         if (tmp == 1) | 
 |                                             progress = 1; | 
 |                                     } | 
 |                                     xmlRelaxNGFreeStates(ctxt, | 
 |                                                          ctxt->states); | 
 |                                     ctxt->states = NULL; | 
 |                                 } | 
 |                             } else { | 
 |                                 if (ctxt->state != NULL) { | 
 |                                     xmlRelaxNGFreeValidState(ctxt, | 
 |                                                              ctxt->state); | 
 |                                     ctxt->state = NULL; | 
 |                                 } | 
 |                             } | 
 |                         } | 
 |                     } else { | 
 |                         ret = xmlRelaxNGValidateDefinitionList(ctxt, | 
 |                                                                define-> | 
 |                                                                content); | 
 |                         if (ret != 0) { | 
 |                             xmlRelaxNGFreeValidState(ctxt, ctxt->state); | 
 |                             ctxt->state = NULL; | 
 |                         } else { | 
 |                             base = res->nbState; | 
 |                             if (ctxt->state != NULL) { | 
 |                                 tmp = xmlRelaxNGAddStates(ctxt, res, | 
 |                                                           ctxt->state); | 
 |                                 ctxt->state = NULL; | 
 |                                 if (tmp == 1) | 
 |                                     progress = 1; | 
 |                             } else if (ctxt->states != NULL) { | 
 |                                 for (j = 0; j < ctxt->states->nbState; j++) { | 
 |                                     tmp = xmlRelaxNGAddStates(ctxt, res, | 
 |                                                ctxt->states->tabState[j]); | 
 |                                     if (tmp == 1) | 
 |                                         progress = 1; | 
 |                                 } | 
 |                                 if (states == NULL) { | 
 |                                     states = ctxt->states; | 
 |                                 } else { | 
 |                                     xmlRelaxNGFreeStates(ctxt, | 
 |                                                          ctxt->states); | 
 |                                 } | 
 |                                 ctxt->states = NULL; | 
 |                             } | 
 |                         } | 
 |                     } | 
 |                     if (progress) { | 
 |                         /* | 
 |                          * Collect all the new nodes added at that step | 
 |                          * and make them the new node set | 
 |                          */ | 
 |                         if (res->nbState - base == 1) { | 
 |                             ctxt->state = xmlRelaxNGCopyValidState(ctxt, | 
 |                                                                    res-> | 
 |                                                                    tabState | 
 |                                                                    [base]); | 
 |                         } else { | 
 |                             if (states == NULL) { | 
 |                                 xmlRelaxNGNewStates(ctxt, | 
 |                                                     res->nbState - base); | 
 | 			        states = ctxt->states; | 
 | 				if (states == NULL) { | 
 | 				    progress = 0; | 
 | 				    break; | 
 | 				} | 
 |                             } | 
 |                             states->nbState = 0; | 
 |                             for (i = base; i < res->nbState; i++) | 
 |                                 xmlRelaxNGAddStates(ctxt, states, | 
 |                                                     xmlRelaxNGCopyValidState | 
 |                                                     (ctxt, res->tabState[i])); | 
 |                             ctxt->states = states; | 
 |                         } | 
 |                     } | 
 |                 } while (progress == 1); | 
 |                 if (states != NULL) { | 
 |                     xmlRelaxNGFreeStates(ctxt, states); | 
 |                 } | 
 |                 ctxt->states = res; | 
 |                 ctxt->flags = oldflags; | 
 | #if 0 | 
 |                 /* | 
 |                  * errors may have to be propagated back... | 
 |                  */ | 
 |                 if (ctxt->errNr > errNr) | 
 |                     xmlRelaxNGPopErrors(ctxt, errNr); | 
 | #endif | 
 |                 ret = 0; | 
 |                 break; | 
 |             } | 
 |         case XML_RELAXNG_CHOICE:{ | 
 |                 xmlRelaxNGDefinePtr list = NULL; | 
 |                 xmlRelaxNGStatesPtr states = NULL; | 
 |  | 
 |                 node = xmlRelaxNGSkipIgnored(ctxt, node); | 
 |  | 
 |                 errNr = ctxt->errNr; | 
 |                 if ((define->dflags & IS_TRIABLE) && (define->data != NULL) && | 
 | 		    (node != NULL)) { | 
 | 		    /* | 
 | 		     * node == NULL can't be optimized since IS_TRIABLE | 
 | 		     * doesn't account for choice which may lead to | 
 | 		     * only attributes. | 
 | 		     */ | 
 |                     xmlHashTablePtr triage = | 
 |                         (xmlHashTablePtr) define->data; | 
 |  | 
 |                     /* | 
 |                      * Something we can optimize cleanly there is only one | 
 |                      * possble branch out ! | 
 |                      */ | 
 |                     if ((node->type == XML_TEXT_NODE) || | 
 |                         (node->type == XML_CDATA_SECTION_NODE)) { | 
 |                         list = | 
 |                             xmlHashLookup2(triage, BAD_CAST "#text", NULL); | 
 |                     } else if (node->type == XML_ELEMENT_NODE) { | 
 |                         if (node->ns != NULL) { | 
 |                             list = xmlHashLookup2(triage, node->name, | 
 |                                                   node->ns->href); | 
 |                             if (list == NULL) | 
 |                                 list = | 
 |                                     xmlHashLookup2(triage, BAD_CAST "#any", | 
 |                                                    node->ns->href); | 
 |                         } else | 
 |                             list = | 
 |                                 xmlHashLookup2(triage, node->name, NULL); | 
 |                         if (list == NULL) | 
 |                             list = | 
 |                                 xmlHashLookup2(triage, BAD_CAST "#any", | 
 |                                                NULL); | 
 |                     } | 
 |                     if (list == NULL) { | 
 |                         ret = -1; | 
 | 			VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG, node->name); | 
 |                         break; | 
 |                     } | 
 |                     ret = xmlRelaxNGValidateDefinition(ctxt, list); | 
 |                     if (ret == 0) { | 
 |                     } | 
 |                     break; | 
 |                 } | 
 |  | 
 |                 list = define->content; | 
 |                 oldflags = ctxt->flags; | 
 |                 ctxt->flags |= FLAGS_IGNORABLE; | 
 |  | 
 |                 while (list != NULL) { | 
 |                     oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state); | 
 |                     ret = xmlRelaxNGValidateDefinition(ctxt, list); | 
 |                     if (ret == 0) { | 
 |                         if (states == NULL) { | 
 |                             states = xmlRelaxNGNewStates(ctxt, 1); | 
 |                         } | 
 |                         if (ctxt->state != NULL) { | 
 |                             xmlRelaxNGAddStates(ctxt, states, ctxt->state); | 
 |                         } else if (ctxt->states != NULL) { | 
 |                             for (i = 0; i < ctxt->states->nbState; i++) { | 
 |                                 xmlRelaxNGAddStates(ctxt, states, | 
 |                                                     ctxt->states-> | 
 |                                                     tabState[i]); | 
 |                             } | 
 |                             xmlRelaxNGFreeStates(ctxt, ctxt->states); | 
 |                             ctxt->states = NULL; | 
 |                         } | 
 |                     } else { | 
 |                         xmlRelaxNGFreeValidState(ctxt, ctxt->state); | 
 |                     } | 
 |                     ctxt->state = oldstate; | 
 |                     list = list->next; | 
 |                 } | 
 |                 if (states != NULL) { | 
 |                     xmlRelaxNGFreeValidState(ctxt, oldstate); | 
 |                     ctxt->states = states; | 
 |                     ctxt->state = NULL; | 
 |                     ret = 0; | 
 |                 } else { | 
 |                     ctxt->states = NULL; | 
 |                 } | 
 |                 ctxt->flags = oldflags; | 
 |                 if (ret != 0) { | 
 |                     if ((ctxt->flags & FLAGS_IGNORABLE) == 0) { | 
 |                         xmlRelaxNGDumpValidError(ctxt); | 
 |                     } | 
 |                 } else { | 
 |                     if (ctxt->errNr > errNr) | 
 |                         xmlRelaxNGPopErrors(ctxt, errNr); | 
 |                 } | 
 |                 break; | 
 |             } | 
 |         case XML_RELAXNG_DEF: | 
 |         case XML_RELAXNG_GROUP: | 
 |             ret = xmlRelaxNGValidateDefinitionList(ctxt, define->content); | 
 |             break; | 
 |         case XML_RELAXNG_INTERLEAVE: | 
 |             ret = xmlRelaxNGValidateInterleave(ctxt, define); | 
 |             break; | 
 |         case XML_RELAXNG_ATTRIBUTE: | 
 |             ret = xmlRelaxNGValidateAttribute(ctxt, define); | 
 |             break; | 
 |         case XML_RELAXNG_START: | 
 |         case XML_RELAXNG_NOOP: | 
 |         case XML_RELAXNG_REF: | 
 |         case XML_RELAXNG_EXTERNALREF: | 
 |         case XML_RELAXNG_PARENTREF: | 
 |             ret = xmlRelaxNGValidateDefinition(ctxt, define->content); | 
 |             break; | 
 |         case XML_RELAXNG_DATATYPE:{ | 
 |                 xmlNodePtr child; | 
 |                 xmlChar *content = NULL; | 
 |  | 
 |                 child = node; | 
 |                 while (child != NULL) { | 
 |                     if (child->type == XML_ELEMENT_NODE) { | 
 |                         VALID_ERR2(XML_RELAXNG_ERR_DATAELEM, | 
 |                                    node->parent->name); | 
 |                         ret = -1; | 
 |                         break; | 
 |                     } else if ((child->type == XML_TEXT_NODE) || | 
 |                                (child->type == XML_CDATA_SECTION_NODE)) { | 
 |                         content = xmlStrcat(content, child->content); | 
 |                     } | 
 |                     /* TODO: handle entities ... */ | 
 |                     child = child->next; | 
 |                 } | 
 |                 if (ret == -1) { | 
 |                     if (content != NULL) | 
 |                         xmlFree(content); | 
 |                     break; | 
 |                 } | 
 |                 if (content == NULL) { | 
 |                     content = xmlStrdup(BAD_CAST ""); | 
 |                     if (content == NULL) { | 
 |                         xmlRngVErrMemory(ctxt, "validating\n"); | 
 |                         ret = -1; | 
 |                         break; | 
 |                     } | 
 |                 } | 
 |                 ret = xmlRelaxNGValidateDatatype(ctxt, content, define, | 
 |                                                  ctxt->state->seq); | 
 |                 if (ret == -1) { | 
 |                     VALID_ERR2(XML_RELAXNG_ERR_DATATYPE, define->name); | 
 |                 } else if (ret == 0) { | 
 |                     ctxt->state->seq = NULL; | 
 |                 } | 
 |                 if (content != NULL) | 
 |                     xmlFree(content); | 
 |                 break; | 
 |             } | 
 |         case XML_RELAXNG_VALUE:{ | 
 |                 xmlChar *content = NULL; | 
 |                 xmlChar *oldvalue; | 
 |                 xmlNodePtr child; | 
 |  | 
 |                 child = node; | 
 |                 while (child != NULL) { | 
 |                     if (child->type == XML_ELEMENT_NODE) { | 
 |                         VALID_ERR2(XML_RELAXNG_ERR_VALELEM, | 
 |                                    node->parent->name); | 
 |                         ret = -1; | 
 |                         break; | 
 |                     } else if ((child->type == XML_TEXT_NODE) || | 
 |                                (child->type == XML_CDATA_SECTION_NODE)) { | 
 |                         content = xmlStrcat(content, child->content); | 
 |                     } | 
 |                     /* TODO: handle entities ... */ | 
 |                     child = child->next; | 
 |                 } | 
 |                 if (ret == -1) { | 
 |                     if (content != NULL) | 
 |                         xmlFree(content); | 
 |                     break; | 
 |                 } | 
 |                 if (content == NULL) { | 
 |                     content = xmlStrdup(BAD_CAST ""); | 
 |                     if (content == NULL) { | 
 |                         xmlRngVErrMemory(ctxt, "validating\n"); | 
 |                         ret = -1; | 
 |                         break; | 
 |                     } | 
 |                 } | 
 |                 oldvalue = ctxt->state->value; | 
 |                 ctxt->state->value = content; | 
 |                 ret = xmlRelaxNGValidateValue(ctxt, define); | 
 |                 ctxt->state->value = oldvalue; | 
 |                 if (ret == -1) { | 
 |                     VALID_ERR2(XML_RELAXNG_ERR_VALUE, define->name); | 
 |                 } else if (ret == 0) { | 
 |                     ctxt->state->seq = NULL; | 
 |                 } | 
 |                 if (content != NULL) | 
 |                     xmlFree(content); | 
 |                 break; | 
 |             } | 
 |         case XML_RELAXNG_LIST:{ | 
 |                 xmlChar *content; | 
 |                 xmlNodePtr child; | 
 |                 xmlChar *oldvalue, *oldendvalue; | 
 |                 int len; | 
 |  | 
 |                 /* | 
 |                  * Make sure it's only text nodes | 
 |                  */ | 
 |  | 
 |                 content = NULL; | 
 |                 child = node; | 
 |                 while (child != NULL) { | 
 |                     if (child->type == XML_ELEMENT_NODE) { | 
 |                         VALID_ERR2(XML_RELAXNG_ERR_LISTELEM, | 
 |                                    node->parent->name); | 
 |                         ret = -1; | 
 |                         break; | 
 |                     } else if ((child->type == XML_TEXT_NODE) || | 
 |                                (child->type == XML_CDATA_SECTION_NODE)) { | 
 |                         content = xmlStrcat(content, child->content); | 
 |                     } | 
 |                     /* TODO: handle entities ... */ | 
 |                     child = child->next; | 
 |                 } | 
 |                 if (ret == -1) { | 
 |                     if (content != NULL) | 
 |                         xmlFree(content); | 
 |                     break; | 
 |                 } | 
 |                 if (content == NULL) { | 
 |                     content = xmlStrdup(BAD_CAST ""); | 
 |                     if (content == NULL) { | 
 |                         xmlRngVErrMemory(ctxt, "validating\n"); | 
 |                         ret = -1; | 
 |                         break; | 
 |                     } | 
 |                 } | 
 |                 len = xmlStrlen(content); | 
 |                 oldvalue = ctxt->state->value; | 
 |                 oldendvalue = ctxt->state->endvalue; | 
 |                 ctxt->state->value = content; | 
 |                 ctxt->state->endvalue = content + len; | 
 |                 ret = xmlRelaxNGValidateValue(ctxt, define); | 
 |                 ctxt->state->value = oldvalue; | 
 |                 ctxt->state->endvalue = oldendvalue; | 
 |                 if (ret == -1) { | 
 |                     VALID_ERR(XML_RELAXNG_ERR_LIST); | 
 |                 } else if ((ret == 0) && (node != NULL)) { | 
 |                     ctxt->state->seq = node->next; | 
 |                 } | 
 |                 if (content != NULL) | 
 |                     xmlFree(content); | 
 |                 break; | 
 |             } | 
 |         case XML_RELAXNG_EXCEPT: | 
 |         case XML_RELAXNG_PARAM: | 
 |             TODO ret = -1; | 
 |             break; | 
 |     } | 
 |     ctxt->depth--; | 
 | #ifdef DEBUG | 
 |     for (i = 0; i < ctxt->depth; i++) | 
 |         xmlGenericError(xmlGenericErrorContext, " "); | 
 |     xmlGenericError(xmlGenericErrorContext, | 
 |                     "Validating %s ", xmlRelaxNGDefName(define)); | 
 |     if (define->name != NULL) | 
 |         xmlGenericError(xmlGenericErrorContext, "%s ", define->name); | 
 |     if (ret == 0) | 
 |         xmlGenericError(xmlGenericErrorContext, "suceeded\n"); | 
 |     else | 
 |         xmlGenericError(xmlGenericErrorContext, "failed\n"); | 
 | #endif | 
 |     return (ret); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGValidateDefinition: | 
 |  * @ctxt:  a Relax-NG validation context | 
 |  * @define:  the definition to verify | 
 |  * | 
 |  * Validate the current node lists against the definition | 
 |  * | 
 |  * Returns 0 if the validation succeeded or an error code. | 
 |  */ | 
 | static int | 
 | xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt, | 
 |                              xmlRelaxNGDefinePtr define) | 
 | { | 
 |     xmlRelaxNGStatesPtr states, res; | 
 |     int i, j, k, ret, oldflags; | 
 |  | 
 |     /* | 
 |      * We should NOT have both ctxt->state and ctxt->states | 
 |      */ | 
 |     if ((ctxt->state != NULL) && (ctxt->states != NULL)) { | 
 |         TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state); | 
 |         ctxt->state = NULL; | 
 |     } | 
 |  | 
 |     if ((ctxt->states == NULL) || (ctxt->states->nbState == 1)) { | 
 |         if (ctxt->states != NULL) { | 
 |             ctxt->state = ctxt->states->tabState[0]; | 
 |             xmlRelaxNGFreeStates(ctxt, ctxt->states); | 
 |             ctxt->states = NULL; | 
 |         } | 
 |         ret = xmlRelaxNGValidateState(ctxt, define); | 
 |         if ((ctxt->state != NULL) && (ctxt->states != NULL)) { | 
 |             TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state); | 
 |             ctxt->state = NULL; | 
 |         } | 
 |         if ((ctxt->states != NULL) && (ctxt->states->nbState == 1)) { | 
 |             ctxt->state = ctxt->states->tabState[0]; | 
 |             xmlRelaxNGFreeStates(ctxt, ctxt->states); | 
 |             ctxt->states = NULL; | 
 |         } | 
 |         return (ret); | 
 |     } | 
 |  | 
 |     states = ctxt->states; | 
 |     ctxt->states = NULL; | 
 |     res = NULL; | 
 |     j = 0; | 
 |     oldflags = ctxt->flags; | 
 |     ctxt->flags |= FLAGS_IGNORABLE; | 
 |     for (i = 0; i < states->nbState; i++) { | 
 |         ctxt->state = states->tabState[i]; | 
 |         ctxt->states = NULL; | 
 |         ret = xmlRelaxNGValidateState(ctxt, define); | 
 |         /* | 
 |          * We should NOT have both ctxt->state and ctxt->states | 
 |          */ | 
 |         if ((ctxt->state != NULL) && (ctxt->states != NULL)) { | 
 |             TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state); | 
 |             ctxt->state = NULL; | 
 |         } | 
 |         if (ret == 0) { | 
 |             if (ctxt->states == NULL) { | 
 |                 if (res != NULL) { | 
 |                     /* add the state to the container */ | 
 |                     xmlRelaxNGAddStates(ctxt, res, ctxt->state); | 
 |                     ctxt->state = NULL; | 
 |                 } else { | 
 |                     /* add the state directly in states */ | 
 |                     states->tabState[j++] = ctxt->state; | 
 |                     ctxt->state = NULL; | 
 |                 } | 
 |             } else { | 
 |                 if (res == NULL) { | 
 |                     /* make it the new container and copy other results */ | 
 |                     res = ctxt->states; | 
 |                     ctxt->states = NULL; | 
 |                     for (k = 0; k < j; k++) | 
 |                         xmlRelaxNGAddStates(ctxt, res, | 
 |                                             states->tabState[k]); | 
 |                 } else { | 
 |                     /* add all the new results to res and reff the container */ | 
 |                     for (k = 0; k < ctxt->states->nbState; k++) | 
 |                         xmlRelaxNGAddStates(ctxt, res, | 
 |                                             ctxt->states->tabState[k]); | 
 |                     xmlRelaxNGFreeStates(ctxt, ctxt->states); | 
 |                     ctxt->states = NULL; | 
 |                 } | 
 |             } | 
 |         } else { | 
 |             if (ctxt->state != NULL) { | 
 |                 xmlRelaxNGFreeValidState(ctxt, ctxt->state); | 
 |                 ctxt->state = NULL; | 
 |             } else if (ctxt->states != NULL) { | 
 |                 for (k = 0; k < ctxt->states->nbState; k++) | 
 |                     xmlRelaxNGFreeValidState(ctxt, | 
 |                                              ctxt->states->tabState[k]); | 
 |                 xmlRelaxNGFreeStates(ctxt, ctxt->states); | 
 |                 ctxt->states = NULL; | 
 |             } | 
 |         } | 
 |     } | 
 |     ctxt->flags = oldflags; | 
 |     if (res != NULL) { | 
 |         xmlRelaxNGFreeStates(ctxt, states); | 
 |         ctxt->states = res; | 
 |         ret = 0; | 
 |     } else if (j > 1) { | 
 |         states->nbState = j; | 
 |         ctxt->states = states; | 
 |         ret = 0; | 
 |     } else if (j == 1) { | 
 |         ctxt->state = states->tabState[0]; | 
 |         xmlRelaxNGFreeStates(ctxt, states); | 
 |         ret = 0; | 
 |     } else { | 
 |         ret = -1; | 
 |         xmlRelaxNGFreeStates(ctxt, states); | 
 |         if (ctxt->states != NULL) { | 
 |             xmlRelaxNGFreeStates(ctxt, ctxt->states); | 
 |             ctxt->states = NULL; | 
 |         } | 
 |     } | 
 |     if ((ctxt->state != NULL) && (ctxt->states != NULL)) { | 
 |         TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state); | 
 |         ctxt->state = NULL; | 
 |     } | 
 |     return (ret); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGValidateDocument: | 
 |  * @ctxt:  a Relax-NG validation context | 
 |  * @doc:  the document | 
 |  * | 
 |  * Validate the given document | 
 |  * | 
 |  * Returns 0 if the validation succeeded or an error code. | 
 |  */ | 
 | static int | 
 | xmlRelaxNGValidateDocument(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc) | 
 | { | 
 |     int ret; | 
 |     xmlRelaxNGPtr schema; | 
 |     xmlRelaxNGGrammarPtr grammar; | 
 |     xmlRelaxNGValidStatePtr state; | 
 |     xmlNodePtr node; | 
 |  | 
 |     if ((ctxt == NULL) || (ctxt->schema == NULL) || (doc == NULL)) | 
 |         return (-1); | 
 |  | 
 |     ctxt->errNo = XML_RELAXNG_OK; | 
 |     schema = ctxt->schema; | 
 |     grammar = schema->topgrammar; | 
 |     if (grammar == NULL) { | 
 |         VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR); | 
 |         return (-1); | 
 |     } | 
 |     state = xmlRelaxNGNewValidState(ctxt, NULL); | 
 |     ctxt->state = state; | 
 |     ret = xmlRelaxNGValidateDefinition(ctxt, grammar->start); | 
 |     if ((ctxt->state != NULL) && (state->seq != NULL)) { | 
 |         state = ctxt->state; | 
 |         node = state->seq; | 
 |         node = xmlRelaxNGSkipIgnored(ctxt, node); | 
 |         if (node != NULL) { | 
 |             if (ret != -1) { | 
 |                 VALID_ERR(XML_RELAXNG_ERR_EXTRADATA); | 
 |                 ret = -1; | 
 |             } | 
 |         } | 
 |     } else if (ctxt->states != NULL) { | 
 |         int i; | 
 |         int tmp = -1; | 
 |  | 
 |         for (i = 0; i < ctxt->states->nbState; i++) { | 
 |             state = ctxt->states->tabState[i]; | 
 |             node = state->seq; | 
 |             node = xmlRelaxNGSkipIgnored(ctxt, node); | 
 |             if (node == NULL) | 
 |                 tmp = 0; | 
 |             xmlRelaxNGFreeValidState(ctxt, state); | 
 |         } | 
 |         if (tmp == -1) { | 
 |             if (ret != -1) { | 
 |                 VALID_ERR(XML_RELAXNG_ERR_EXTRADATA); | 
 |                 ret = -1; | 
 |             } | 
 |         } | 
 |     } | 
 |     if (ctxt->state != NULL) { | 
 |         xmlRelaxNGFreeValidState(ctxt, ctxt->state); | 
 |         ctxt->state = NULL; | 
 |     } | 
 |     if (ret != 0) | 
 |         xmlRelaxNGDumpValidError(ctxt); | 
 | #ifdef DEBUG | 
 |     else if (ctxt->errNr != 0) { | 
 |         ctxt->error(ctxt->userData, | 
 |                     "%d Extra error messages left on stack !\n", | 
 |                     ctxt->errNr); | 
 |         xmlRelaxNGDumpValidError(ctxt); | 
 |     } | 
 | #endif | 
 | #ifdef LIBXML_VALID_ENABLED | 
 |     if (ctxt->idref == 1) { | 
 |         xmlValidCtxt vctxt; | 
 |  | 
 |         memset(&vctxt, 0, sizeof(xmlValidCtxt)); | 
 |         vctxt.valid = 1; | 
 |         vctxt.error = ctxt->error; | 
 |         vctxt.warning = ctxt->warning; | 
 |         vctxt.userData = ctxt->userData; | 
 |  | 
 |         if (xmlValidateDocumentFinal(&vctxt, doc) != 1) | 
 |             ret = -1; | 
 |     } | 
 | #endif /* LIBXML_VALID_ENABLED */ | 
 |     if ((ret == 0) && (ctxt->errNo != XML_RELAXNG_OK)) | 
 |         ret = -1; | 
 |  | 
 |     return (ret); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGCleanPSVI: | 
 |  * @node:  an input element or document | 
 |  * | 
 |  * Call this routine to speed up XPath computation on static documents. | 
 |  * This stamps all the element nodes with the document order | 
 |  * Like for line information, the order is kept in the element->content | 
 |  * field, the value stored is actually - the node number (starting at -1) | 
 |  * to be able to differentiate from line numbers. | 
 |  * | 
 |  * Returns the number of elements found in the document or -1 in case | 
 |  *    of error. | 
 |  */ | 
 | static void | 
 | xmlRelaxNGCleanPSVI(xmlNodePtr node) { | 
 |     xmlNodePtr cur; | 
 |  | 
 |     if ((node == NULL) || | 
 |         ((node->type != XML_ELEMENT_NODE) && | 
 |          (node->type != XML_DOCUMENT_NODE) && | 
 |          (node->type != XML_HTML_DOCUMENT_NODE))) | 
 | 	return; | 
 |     if (node->type == XML_ELEMENT_NODE) | 
 |         node->psvi = NULL; | 
 |  | 
 |     cur = node->children; | 
 |     while (cur != NULL) { | 
 | 	if (cur->type == XML_ELEMENT_NODE) { | 
 | 	    cur->psvi = NULL; | 
 | 	    if (cur->children != NULL) { | 
 | 		cur = cur->children; | 
 | 		continue; | 
 | 	    } | 
 | 	} | 
 | 	if (cur->next != NULL) { | 
 | 	    cur = cur->next; | 
 | 	    continue; | 
 | 	} | 
 | 	do { | 
 | 	    cur = cur->parent; | 
 | 	    if (cur == NULL) | 
 | 		break; | 
 | 	    if (cur == node) { | 
 | 		cur = NULL; | 
 | 		break; | 
 | 	    } | 
 | 	    if (cur->next != NULL) { | 
 | 		cur = cur->next; | 
 | 		break; | 
 | 	    } | 
 | 	} while (cur != NULL); | 
 |     } | 
 |     return; | 
 | } | 
 | /************************************************************************ | 
 |  * 									* | 
 |  * 			Validation interfaces				* | 
 |  * 									* | 
 |  ************************************************************************/ | 
 |  | 
 | /** | 
 |  * xmlRelaxNGNewValidCtxt: | 
 |  * @schema:  a precompiled XML RelaxNGs | 
 |  * | 
 |  * Create an XML RelaxNGs validation context based on the given schema | 
 |  * | 
 |  * Returns the validation context or NULL in case of error | 
 |  */ | 
 | xmlRelaxNGValidCtxtPtr | 
 | xmlRelaxNGNewValidCtxt(xmlRelaxNGPtr schema) | 
 | { | 
 |     xmlRelaxNGValidCtxtPtr ret; | 
 |  | 
 |     ret = (xmlRelaxNGValidCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGValidCtxt)); | 
 |     if (ret == NULL) { | 
 |         xmlRngVErrMemory(NULL, "building context\n"); | 
 |         return (NULL); | 
 |     } | 
 |     memset(ret, 0, sizeof(xmlRelaxNGValidCtxt)); | 
 |     ret->schema = schema; | 
 |     ret->error = xmlGenericError; | 
 |     ret->userData = xmlGenericErrorContext; | 
 |     ret->errNr = 0; | 
 |     ret->errMax = 0; | 
 |     ret->err = NULL; | 
 |     ret->errTab = NULL; | 
 |     if (schema != NULL) | 
 | 	ret->idref = schema->idref; | 
 |     ret->states = NULL; | 
 |     ret->freeState = NULL; | 
 |     ret->freeStates = NULL; | 
 |     ret->errNo = XML_RELAXNG_OK; | 
 |     return (ret); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGFreeValidCtxt: | 
 |  * @ctxt:  the schema validation context | 
 |  * | 
 |  * Free the resources associated to the schema validation context | 
 |  */ | 
 | void | 
 | xmlRelaxNGFreeValidCtxt(xmlRelaxNGValidCtxtPtr ctxt) | 
 | { | 
 |     int k; | 
 |  | 
 |     if (ctxt == NULL) | 
 |         return; | 
 |     if (ctxt->states != NULL) | 
 |         xmlRelaxNGFreeStates(NULL, ctxt->states); | 
 |     if (ctxt->freeState != NULL) { | 
 |         for (k = 0; k < ctxt->freeState->nbState; k++) { | 
 |             xmlRelaxNGFreeValidState(NULL, ctxt->freeState->tabState[k]); | 
 |         } | 
 |         xmlRelaxNGFreeStates(NULL, ctxt->freeState); | 
 |     } | 
 |     if (ctxt->freeStates != NULL) { | 
 |         for (k = 0; k < ctxt->freeStatesNr; k++) { | 
 |             xmlRelaxNGFreeStates(NULL, ctxt->freeStates[k]); | 
 |         } | 
 |         xmlFree(ctxt->freeStates); | 
 |     } | 
 |     if (ctxt->errTab != NULL) | 
 |         xmlFree(ctxt->errTab); | 
 |     if (ctxt->elemTab != NULL) { | 
 |         xmlRegExecCtxtPtr exec; | 
 |  | 
 |         exec = xmlRelaxNGElemPop(ctxt); | 
 |         while (exec != NULL) { | 
 |             xmlRegFreeExecCtxt(exec); | 
 |             exec = xmlRelaxNGElemPop(ctxt); | 
 |         } | 
 |         xmlFree(ctxt->elemTab); | 
 |     } | 
 |     xmlFree(ctxt); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGSetValidErrors: | 
 |  * @ctxt:  a Relax-NG validation context | 
 |  * @err:  the error function | 
 |  * @warn: the warning function | 
 |  * @ctx: the functions context | 
 |  * | 
 |  * Set the error and warning callback informations | 
 |  */ | 
 | void | 
 | xmlRelaxNGSetValidErrors(xmlRelaxNGValidCtxtPtr ctxt, | 
 |                          xmlRelaxNGValidityErrorFunc err, | 
 |                          xmlRelaxNGValidityWarningFunc warn, void *ctx) | 
 | { | 
 |     if (ctxt == NULL) | 
 |         return; | 
 |     ctxt->error = err; | 
 |     ctxt->warning = warn; | 
 |     ctxt->userData = ctx; | 
 |     ctxt->serror = NULL; | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGSetValidStructuredErrors: | 
 |  * @ctxt:  a Relax-NG validation context | 
 |  * @serror:  the structured error function | 
 |  * @ctx: the functions context | 
 |  * | 
 |  * Set the structured error callback | 
 |  */ | 
 | void | 
 | xmlRelaxNGSetValidStructuredErrors(xmlRelaxNGValidCtxtPtr ctxt, | 
 |                                    xmlStructuredErrorFunc serror, void *ctx) | 
 | { | 
 |     if (ctxt == NULL) | 
 |         return; | 
 |     ctxt->serror = serror; | 
 |     ctxt->error = NULL; | 
 |     ctxt->warning = NULL; | 
 |     ctxt->userData = ctx; | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGGetValidErrors: | 
 |  * @ctxt:  a Relax-NG validation context | 
 |  * @err:  the error function result | 
 |  * @warn: the warning function result | 
 |  * @ctx: the functions context result | 
 |  * | 
 |  * Get the error and warning callback informations | 
 |  * | 
 |  * Returns -1 in case of error and 0 otherwise | 
 |  */ | 
 | int | 
 | xmlRelaxNGGetValidErrors(xmlRelaxNGValidCtxtPtr ctxt, | 
 |                          xmlRelaxNGValidityErrorFunc * err, | 
 |                          xmlRelaxNGValidityWarningFunc * warn, void **ctx) | 
 | { | 
 |     if (ctxt == NULL) | 
 |         return (-1); | 
 |     if (err != NULL) | 
 |         *err = ctxt->error; | 
 |     if (warn != NULL) | 
 |         *warn = ctxt->warning; | 
 |     if (ctx != NULL) | 
 |         *ctx = ctxt->userData; | 
 |     return (0); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlRelaxNGValidateDoc: | 
 |  * @ctxt:  a Relax-NG validation context | 
 |  * @doc:  a parsed document tree | 
 |  * | 
 |  * Validate a document tree in memory. | 
 |  * | 
 |  * Returns 0 if the document is valid, a positive error code | 
 |  *     number otherwise and -1 in case of internal or API error. | 
 |  */ | 
 | int | 
 | xmlRelaxNGValidateDoc(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc) | 
 | { | 
 |     int ret; | 
 |  | 
 |     if ((ctxt == NULL) || (doc == NULL)) | 
 |         return (-1); | 
 |  | 
 |     ctxt->doc = doc; | 
 |  | 
 |     ret = xmlRelaxNGValidateDocument(ctxt, doc); | 
 |     /* | 
 |      * Remove all left PSVI | 
 |      */ | 
 |     xmlRelaxNGCleanPSVI((xmlNodePtr) doc); | 
 |  | 
 |     /* | 
 |      * TODO: build error codes | 
 |      */ | 
 |     if (ret == -1) | 
 |         return (1); | 
 |     return (ret); | 
 | } | 
 |  | 
 | #define bottom_relaxng | 
 | #include "elfgcchack.h" | 
 | #endif /* LIBXML_SCHEMAS_ENABLED */ |