Skip to content
Snippets Groups Projects
rngparser.c 46.5 KiB
Newer Older
  • Learn to ignore specific revisions
  • /**
     * rngparser.c: parser for the Relax-NG compact syntax.
     *
    
     * Based on:
     *   RELAX NG Compact Syntax
     *   Committee Specification 21 November 2002
     *   http://www.oasis-open.org/committees/relax-ng/compact-20021121.html
     *
    
     * See Copyright for the status of this software.
     *
     * Daniel Veillard <veillard@redhat.com>
     */
    
    #include <string.h>
    
    #include <libxml/parser.h>
    #include <libxml/parserInternals.h>
    #include <libxml/relaxng.h>
    #include <libxml/dict.h>
    
    
    #define TODO								\
    
        xmlGenericError(xmlGenericErrorContext,				\
    	    "Unimplemented block at %s:%d\n",				\
                __FILE__, __LINE__);
    
    #define MAX_TOKEN 10
    
    typedef enum {
        CRNG_NONE = 0,
        CRNG_OP = 1,
        CRNG_KEYWORD,
        CRNG_IDENTIFIER,
        CRNG_LITERAL_SEGMENT,
        CRNG_CNAME,
        CRNG_QNAME,
        CRNG_NSNAME,
        CRNG_DOCUMENTATION
    } xmlCRNGTokType;
    
    typedef enum {
        CRNG_OKAY = 0,
        CRNG_MEMORY_ERROR,
        CRNG_INVALID_CHAR_ERROR,
        CRNG_END_ERROR,
        CRNG_ENCODING_ERROR
    } xmlCRNGError;
    
    typedef enum {
        XML_CRNG_ERROR = -1,
        XML_CRNG_OK = 0,
        XML_CRNG_EOF = 1
    } xmlCRelaxNGParserState;
    
    typedef struct _token _token;
    typedef _token *tokenPtr;
    struct _token {
        xmlCRNGTokType toktype;
        int toklen;
        const xmlChar *token;
        const xmlChar *prefix;
    };
    
    typedef struct _xmlCRelaxNGParserCtxt xmlCRelaxNGParserCtxt;
    typedef xmlCRelaxNGParserCtxt *xmlCRelaxNGParserCtxtPtr;
    struct _xmlCRelaxNGParserCtxt {
        void *userData;			/* user specific data block */
        xmlRelaxNGValidityErrorFunc error;	/* the callback in case of errors */
        xmlRelaxNGValidityWarningFunc warning;/* the callback in case of warning */
        xmlRelaxNGValidErr err;
    
        const xmlChar *compact;
        const xmlChar *end;
        const xmlChar *cur;
        int isElem;
        int lineno;
        const xmlChar *linestart;
        const char *filename;
    
        int  nbTokens;
        int  firstToken;
        _token tokens[MAX_TOKEN];
        int  totalToken;
    
        xmlCRelaxNGParserState state;
    
        int            nbErrors;
    
        xmlDocPtr      res;			/* the result */
        xmlNodePtr     ins;			/* the current insertion node */
    
        xmlNsPtr       nsDef;
        tokenPtr token;
    
        xmlHashTablePtr namespaces;
        xmlHashTablePtr datatypes;
    
        /*
    
         * dictionary and keywords
    
         */
        xmlDictPtr     dict;
        const xmlChar *key_attribute;
        const xmlChar *key_default;
        const xmlChar *key_datatypes;
        const xmlChar *key_div;
        const xmlChar *key_element;
        const xmlChar *key_empty;
        const xmlChar *key_external;
        const xmlChar *key_grammar;
        const xmlChar *key_include;
        const xmlChar *key_inherit;
        const xmlChar *key_list;
        const xmlChar *key_mixed;
        const xmlChar *key_namespace;
        const xmlChar *key_notAllowed;
        const xmlChar *key_parent;
        const xmlChar *key_start;
        const xmlChar *key_string;
        const xmlChar *key_text;
        const xmlChar *key_token;
        const xmlChar *key_equal;
        const xmlChar *key_orequal;
        const xmlChar *key_andequal;
        const xmlChar *key_combine;
        const xmlChar *key_or;
        const xmlChar *key_comma;
        const xmlChar *key_and;
        const xmlChar *key_choice;
        const xmlChar *key_group;
        const xmlChar *key_interleave;
        const xmlChar *key_ref;
        const xmlChar *key_define;
    
        /* results */
        xmlDocPtr doc;	/* the resulting doc */
        xmlNodePtr insert;	/* the insertion point */
        xmlAttrPtr attrs;   /* pending attributes */
    };
    
    static const xmlChar *xmlCRelaxNGInherit = BAD_CAST "Inherit string";
    static const xmlChar *xmlCRelaxNGDefault = BAD_CAST "Default string";
    
    #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
    /**
     * IS_BLANK:
     * @c:  an UNICODE value (int)
     *
     * Macro to check the following production in the XML spec:
     *
     * [3] S ::= (#x20 | #x9 | #xD | #xA)+
     */
    #ifndef IS_BLANK
    #define IS_BLANK(c) (((c) == 0x20) || ((c) == 0x09) || ((c) == 0xA) ||	\
                         ((c) == 0x0D))
    #endif
    #define IS_SEPARATOR(c) (((c) == 0x20) || ((c) == 0x09) || ((c) == 0xA) || \
                         ((c) == 0x0D) || (c == '#'))
    
    #define CRNG_ERROR0(X)							\
        { xmlCRNGErr(ctxt, X, NULL); return(0); }
    #define CRNG_ERROR(X)							\
        { xmlCRNGErr(ctxt, X, NULL); }
    
    #define CRNG_MEM_ERROR0()						\
        { xmlCRNGErr(ctxt, CRNG_MEMORY_ERROR, NULL); return(0); }
    #define CRNG_MEM_ERROR()						\
        { xmlCRNGErr(ctxt, CRNG_MEMORY_ERROR, NULL); }
    
    #define ERROR(str) xmlCRNGErr(ctxt, 0, str);
    
    static void
    xmlCRNGErr(xmlCRelaxNGParserCtxtPtr ctxt, int err_no, const char *err_msg) {
        const xmlChar *cur;
        xmlChar buffer[150];
        int i, l;
    
        if (ctxt != NULL) {
            if (ctxt->filename != NULL)
    	    fprintf(stderr, "%s:%d ", ctxt->filename, ctxt->lineno);
        }
        if (err_msg != NULL) {
    	fprintf(stderr, "error: %s\n", err_msg);
        } else if (err_no != 0)
    	fprintf(stderr, "error %d\n", err_no);
        cur = ctxt->cur;
        while ((*cur != '\n') && (*cur != '\r') && (ctxt->cur - cur < 80)) cur--;
        l = ctxt->cur - cur;
        cur++;
        for (i = 0; i < 100;i++) {
            if ((*cur == '\n') || (*cur == '\r')) break;
            buffer[i] = *cur++;
        }
        buffer[i] = 0;
        fprintf(stderr, "%s\n", buffer);
        for (i = 0; i < l;i++) buffer[i] = ' ';
        buffer[i++] = '^';
        buffer[i++] = 0;
        fprintf(stderr, "%s\n", buffer);
    }
    
    /**
     * IS_OP
     * @c:  an UNICODE value (int)
     *
     * Macro to check for operator value
     */
    #ifndef IS_OP
    #define IS_OP(c) (((c) == ',') || ((c) == '&') || ((c) == '|') ||	\
    		  ((c) == '?') || ((c) == '-') || ((c) == '*') ||	\
    		  ((c) == '{') || ((c) == '}') || ((c) == '(') ||	\
    		  ((c) == ')') || ((c) == '+') || ((c) == '=') ||	\
    		  ((c) == ':'))
    #endif
    
    static int
    xmlCRNGIsKeyword(xmlCRelaxNGParserCtxtPtr ctxt, const xmlChar *str) {
        if ((str == ctxt->key_attribute) ||
            (str == ctxt->key_default) ||
            (str == ctxt->key_datatypes) ||
            (str == ctxt->key_div) ||
            (str == ctxt->key_element) ||
            (str == ctxt->key_empty) ||
            (str == ctxt->key_external) ||
            (str == ctxt->key_grammar) ||
            (str == ctxt->key_include) ||
            (str == ctxt->key_inherit) ||
            (str == ctxt->key_list) ||
            (str == ctxt->key_mixed) ||
            (str == ctxt->key_namespace) ||
            (str == ctxt->key_notAllowed) ||
            (str == ctxt->key_parent) ||
            (str == ctxt->key_start) ||
            (str == ctxt->key_string) ||
            (str == ctxt->key_text) ||
            (str == ctxt->key_token))
    	return(1);
        return(0);
    
    }
    
    /*
     * xmlCRNGNextToken:
     * ctxt:  a compact RNG parser context
     *
     * Scan the schema to get the next token
     *
     * Return 0 if success and -1 in case of error
     */
    
    static int
    xmlCRNGNextToken(xmlCRelaxNGParserCtxtPtr ctxt) {
        const xmlChar *cur;
        tokenPtr token;
    
        if (ctxt == NULL) return(-1);
        if (ctxt->nbTokens >= MAX_TOKEN) return(-1);
        token = &(ctxt->tokens[(ctxt->firstToken + ctxt->nbTokens) % MAX_TOKEN]);
        token->toktype = CRNG_NONE;
    
        if (ctxt->cur == NULL) {
            ctxt->cur = ctxt->compact;
        }
    retry:
        if (ctxt->cur >= ctxt->end) {
    	ctxt->state = XML_CRNG_EOF;
    	return(-1);
        }
        while ((ctxt->cur < ctxt->end) &&
               (IS_BLANK(*ctxt->cur))) ctxt->cur++;
        if (ctxt->cur >= ctxt->end) {
    	ctxt->state = XML_CRNG_EOF;
    	return(-1);
        }
        if (*ctxt->cur == '#') {
            cur = ctxt->cur;
    	cur++;
    	while ((cur < ctxt->end) && (*cur != '\n') && (*cur != '\r'))
    	    cur++;
            ctxt->cur = cur;
    	goto retry;
        } else if (*ctxt->cur == '"') {
            /* string, check for '"""' */
    	ctxt->cur++;
    	if (ctxt->cur >= ctxt->end) goto eof;
    	cur = ctxt->cur;
    
            if ((ctxt->end - ctxt->end > 2) &&
    
    	    (*cur == '"') && (cur[1] == '"')) {
    	    TODO
    	} else {
    	    while ((cur < ctxt->end) && (*cur != '"')) cur++;
    	    if (cur >= ctxt->end) goto eof;
    	    token->toklen = cur - ctxt->cur;
    	    token->token = xmlDictLookup(ctxt->dict, ctxt->cur, token->toklen);
    	    token->toktype = CRNG_LITERAL_SEGMENT;
    	    token->prefix = NULL;
    	    cur++;
    	    ctxt->cur = cur;
    	}
        } else if (*ctxt->cur == '\'') {
            /* string, check for "'''" */
    	TODO
        } else if ((IS_OP(*ctxt->cur)) || (*ctxt->cur == ':')) {
            cur = ctxt->cur;
    	cur++;
    	if ((cur < ctxt->end) &&
    	    (((*cur == '=') &&
    	      ((*ctxt->cur == '|') || (*ctxt->cur == '&'))) ||
    	     ((*cur == '*') && (*ctxt->cur == ':')))) {
    	    token->toklen = 2;
    	} else {
    	    token->toklen = 1;
    	}
    	token->token = xmlDictLookup(ctxt->dict, ctxt->cur, token->toklen);
    	token->toktype = CRNG_OP;
    	token->prefix = NULL;
    	ctxt->cur += token->toklen;
        } else {
            int escape = 0;
    
            cur = ctxt->cur;
            if (*cur == '\\') {
    	    escape = 1;
    	    cur++;
    	    ctxt->cur++;
    	}
    	while ((cur < ctxt->end) &&
    	       (!(IS_SEPARATOR(*cur))) && (!(IS_OP(*cur)))) cur++;
    
    	token->toklen = cur - ctxt->cur;
    	token->token = xmlDictLookup(ctxt->dict, ctxt->cur, token->toklen);
    	token->prefix = NULL;
    	ctxt->cur = cur;
    	if ((escape == 0) && (xmlCRNGIsKeyword(ctxt, token->token)))
    	    token->toktype = CRNG_KEYWORD;
    	else {
    	    token->toktype = CRNG_IDENTIFIER;
    	}
    	if (*ctxt->cur == ':') {
    	    ctxt->cur++;
    	    if (*ctxt->cur == '*') {
    		ctxt->cur++;
    		token->toktype = CRNG_NSNAME;
    	    } else {
    	        cur = ctxt->cur;
    		while ((cur < ctxt->end) &&
    		       (!(IS_SEPARATOR(*cur))) && (!(IS_OP(*cur)))) cur++;
    		token->prefix = token->token;
    		token->toklen = cur - ctxt->cur;
    		token->token = xmlDictLookup(ctxt->dict, ctxt->cur,
    		                             token->toklen);
    		ctxt->cur = cur;
    		if (xmlValidateNCName(token->token, 0) == 0)
    		    token->toktype = CRNG_QNAME;
    		else {
    		    TODO /* sounds like an error ! */
    		    token->toktype = CRNG_IDENTIFIER;
    		}
    	    }
    	}
        }
        ctxt->nbTokens++;
        return(0);
    eof:
        ctxt->state = XML_CRNG_EOF;
        CRNG_ERROR(CRNG_END_ERROR);
        return(-1);
    }
    
    /**
     * xmlParseCRNGGetToken:
     * @ctxt: a compact RNG parser context
     * @no: the number of the token from 1 for the first one
     *      and 2, 3 ... for read-ahead
     *
     * Token reading interface
     *
     * returns a pointer to the new token, or NULL in case of error or EOF
     */
    static tokenPtr
    xmlParseCRNGGetToken(xmlCRelaxNGParserCtxtPtr ctxt, int no) {
        tokenPtr ret;
        int res;
    
        if ((no <= 0) || (no >= MAX_TOKEN)) return(NULL);
        no--;
        while (ctxt->nbTokens <= no) {
            res = xmlCRNGNextToken(ctxt);
    	if (res < 0)
    	    return(NULL);
        }
        ret = &(ctxt->tokens[(ctxt->firstToken + no) % MAX_TOKEN]);
        return(ret);
    }
    
    /**
     * xmlParseCRNGDropTokens:
     * @ctxt: a compact RNG parser context
     * @nr: the number of token marked as read
    
     * mark a number of token as read and consumed.
     *
     * Returns -1 in case of error and 0 otherwise
     */
    static int
    xmlParseCRNGDropTokens(xmlCRelaxNGParserCtxtPtr ctxt, int nr) {
        if ((nr <= 0) || (nr >= MAX_TOKEN)) return(-1);
        while ((ctxt->nbTokens >0) && (nr > 0)) {
            ctxt->firstToken++;
    	nr--;
    	ctxt->nbTokens--;
    	ctxt->totalToken++;
    
    	if (ctxt->totalToken == 384)
    
    	    fprintf(stderr, "found\n");
        }
        ctxt->firstToken = ctxt->firstToken % MAX_TOKEN;
        return(0);
    }
    
    static void
    xmlParseCRNGTokenize(xmlCRelaxNGParserCtxtPtr ctxt) {
        tokenPtr token;
    
        token = xmlParseCRNGGetToken(ctxt, 1);
        while (token != NULL) {
            switch (token->toktype) {
                case CRNG_NONE: printf("none"); break;
                case CRNG_OP: printf("op"); break;
                case CRNG_KEYWORD: printf("keyword"); break;
                case CRNG_IDENTIFIER: printf("identifier"); break;
                case CRNG_LITERAL_SEGMENT: printf("literal"); break;
                case CRNG_CNAME: printf("cname"); break;
                case CRNG_QNAME: printf("qname"); break;
                case CRNG_NSNAME: printf("nsname"); break;
                case CRNG_DOCUMENTATION: printf("doc"); break;
    	}
            printf(":%s\n", token->token);
    	xmlParseCRNGDropTokens(ctxt, 1);
    	token = xmlParseCRNGGetToken(ctxt, 1);
        }
    }
    
    /**
     * xmlParseCRNG_attribute:
     * @ctxt: a compact RNG parser context
     * @name: the attribute name
     * @ns: the attribute namespace
     * @value: the attribute value
     *
     * implements attribute of the RELAX NG Compact Syntax Appendix A
     *
     * Returns 0 in case of success and -1 in case of error
     */
    static int
    
    xmlParseCRNG_attribute(xmlCRelaxNGParserCtxtPtr ctxt,
    
                           const xmlChar *name,
                           xmlNsPtr ns,
    		       const xmlChar *value)
    {
        xmlAttrPtr attr;
    
        attr = xmlNewNsPropEatName(NULL, ns, (xmlChar *) name, value);
        if (attr == NULL) CRNG_MEM_ERROR0();
        attr->next = ctxt->attrs;
        if (ctxt->attrs != NULL)
            ctxt->attrs->prev = attr;
        ctxt->attrs = attr;
        return(0);
    }
    
    /**
     * xmlParseCRNG_bindPrefix:
     * @ctxt: a compact RNG parser context
     * @prefix: the namespace prefix or NULL
     * @namespace: the namespace name
     *
     * implements bindPrefix of the RELAX NG Compact Syntax Appendix A
     *
     * Returns 0 in case of success and -1 in case of error
     */
    static int
    
    xmlParseCRNG_bindPrefix(xmlCRelaxNGParserCtxtPtr ctxt,
    
                            const xmlChar *prefix,
    			const xmlChar *namespace)
    {
        int ret;
    
        if ((prefix != NULL) && (xmlStrEqual(prefix, BAD_CAST "xml"))  &&
            (!xmlStrEqual(namespace, XML_XML_NAMESPACE))) {
    	ERROR("The \"xml\" prefix must be bound to \"http://www.w3.org/XML/1998/namespace\"");
    	return(-1);
        } else if ((xmlStrEqual(namespace, XML_XML_NAMESPACE)) &&
                   (!xmlStrEqual(prefix, BAD_CAST "xml"))) {
    	ERROR("The \"http://www.w3.org/XML/1998/namespace\" name must be bound to \"xml\" prefix");
    	return(-1);
        }
        if (ctxt->namespaces == NULL)
            ctxt->namespaces = xmlHashCreate(10);
        if (ctxt->namespaces == NULL) {
            ERROR("Failed to create namespace hash table");
    	return(-1);
        }
        if (prefix == NULL)
            ret = xmlHashAddEntry(ctxt->namespaces, xmlCRelaxNGDefault,
    	                      (void *) namespace);
        else
    
            ret = xmlHashAddEntry(ctxt->namespaces, prefix,
    
    	                      (void *) namespace);
        if (ret < 0) {
            if (prefix == NULL) {
    	    ERROR("Redefinition of default namespace");
    	} else {
    	    ERROR("Redefinition of namespace");
    	}
    	return(-1);
        }
    
        return(0);
    }
    
    /**
     * xmlParseCRNG_bindDatatypePrefix:
     * @ctxt: a compact RNG parser context
     * @prefix: the datatype prefix
     * @namespace: the datatype identifier
     *
     * implements bindDatatypePrefix of the RELAX NG Compact Syntax Appendix A
     *
     * Returns 0 in case of success and -1 in case of error
     */
    static int
    
    xmlParseCRNG_bindDatatypePrefix(xmlCRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
    
                                    const xmlChar *prefix,
    			        const xmlChar *namespace)
    {
        int ret;
    
        if ((prefix != NULL) && (xmlStrEqual(prefix, BAD_CAST "xsd"))  &&
    
            (!xmlStrEqual(namespace,
    
    		  BAD_CAST "http://www.w3.org/2001/XMLSchema-datatypes"))) {
    	ERROR("The \"xsd\" prefix must be bound to \"http://www.w3.org/2001/XMLSchema-datatypes\"");
    	return(-1);
        }
        if (ctxt->datatypes == NULL)
            ctxt->datatypes = xmlHashCreate(10);
        if (ctxt->datatypes == NULL) {
            ERROR("Failed to create namespace hash table");
    	return(-1);
        }
    
        ret = xmlHashAddEntry(ctxt->datatypes, prefix,
    
                              (void *) namespace);
        if (ret < 0) {
    	ERROR("Redefinition of datatype");
    	return(-1);
        }
        return(0);
    }
    
    /**
     * xmlParseCRNG_lookupPrefix:
     * @ctxt: a compact RNG parser context
     * @prefix: the namespace prefix or NULL
     *
     * implements lookupPrefix of the RELAX NG Compact Syntax Appendix A
     *
     * Returns the prefix in case of success or NULL in case of error
     */
    static const xmlChar *
    
    xmlParseCRNG_lookupPrefix(xmlCRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
    
                            const xmlChar *prefix)
    {
        const xmlChar *ret;
    
        if (prefix == NULL)
            ret = xmlHashLookup(ctxt->namespaces, xmlCRelaxNGDefault);
        else
            ret = xmlHashLookup(ctxt->namespaces, prefix);
        return(ret);
    }
    
    /**
     * xmlParseCRNG_lookupDatatypePrefix:
     * @ctxt: a compact RNG parser context
     * @prefix: the namespace prefix or NULL
     *
     * implements lookupDatatypePrefix of the RELAX NG Compact Syntax Appendix A
     *
     * Returns the prefix in case of success or NULL in case of error
     */
    static const xmlChar *
    
    xmlParseCRNG_lookupDatatypePrefix(xmlCRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
    
                            const xmlChar *prefix)
    {
        const xmlChar *ret;
        ret = xmlHashLookup(ctxt->datatypes, prefix);
        return(ret);
    }
    
    /**
     * xmlParseCRNG_datatypeAttributes:
     * @ctxt: a compact RNG parser context
     * @prefix: the namespace prefix or NULL
     *
     * implements lookupPrefix of the RELAX NG Compact Syntax Appendix A
     *
     * Returns the prefix in case of success or NULL in case of error
     */
    static xmlAttrPtr
    
    xmlParseCRNG_datatypeAttributes(xmlCRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
    
                            const xmlChar *library, const xmlChar *type)
    {
        xmlAttrPtr lib, typ;
    
        lib = xmlNewNsProp(NULL, NULL, BAD_CAST "datatypeLibrary", library);
        if (lib == NULL) {
            CRNG_MEM_ERROR();
    	return(NULL);
        }
        typ = xmlNewNsProp(NULL, NULL, BAD_CAST "type", type);
        if (typ == NULL) {
            CRNG_MEM_ERROR();
    	return(lib);
        }
        lib->next = typ;
    
        return(lib);
    }
    
    /**
     * xmlParseCRNG_XXX:
     * @ctxt: a compact RNG parser context
     *
     * Parse XXX of the RELAX NG Compact Syntax Appendix A
     *
     * Returns 0 in case of success and -1 in case of error
     */
    static int
    xmlParseCRNG_XXX(xmlCRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED)
    {
        return(0);
    }
    
    static int xmlParseCRNG_pattern(xmlCRelaxNGParserCtxtPtr ctxt);
    static int xmlParseCRNG_nameClass(xmlCRelaxNGParserCtxtPtr ctxt);
    
    /**
     * xmlParseCRNG_params:
     * @ctxt: a compact RNG parser context
     *
     * Parse params of the RELAX NG Compact Syntax Appendix A
     *
     * Returns 0 in case of success and -1 in case of error
     */
    static int
    xmlParseCRNG_params(xmlCRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED)
    {
        TODO
        return(0);
    }
    
    /**
     * xmlParseCRNG_exceptNameClass:
     * @ctxt: a compact RNG parser context
     *
     * Parse exceptNameClass of the RELAX NG Compact Syntax Appendix A
     *
     * Returns 0 in case of success and -1 in case of error
     */
    static int
    xmlParseCRNG_exceptNameClass(xmlCRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED)
    {
        tokenPtr token;
        xmlNodePtr insert = ctxt->insert, cur;
    
        token = xmlParseCRNGGetToken(ctxt, 1);
        if ((token->toktype == CRNG_OP) &&
            (token->token[0] == '-') && (token->token[1] == 0)) {
    	xmlParseCRNGDropTokens(ctxt, 1);
    	cur = xmlNewNode(NULL, BAD_CAST "except");
    	if (cur == NULL) CRNG_MEM_ERROR0();
    	if (ctxt->insert != NULL)
    	    xmlAddChild(ctxt->insert, cur);
    	ctxt->insert = cur;
    	xmlParseCRNG_nameClass(ctxt);
        }
        ctxt->insert = insert;
        return(0);
    }
    
    /**
     * xmlParseCRNG_innerNameClass:
     * @ctxt: a compact RNG parser context
     *
     * Parse innerNameClass of the RELAX NG Compact Syntax Appendix A
     *
     * Returns 0 in case of success and -1 in case of error
     */
    static int
    xmlParseCRNG_innerNameClass(xmlCRelaxNGParserCtxtPtr ctxt)
    {
        tokenPtr token;
        xmlNodePtr cur;
    
        token = xmlParseCRNGGetToken(ctxt, 1);
        if (token->toktype == CRNG_OP) {
            if ((token->token[0] == '(') && (token->token[1] == 0)) {
    	    xmlParseCRNGDropTokens(ctxt, 1);
    	    xmlParseCRNG_nameClass(ctxt);
    	    token = xmlParseCRNGGetToken(ctxt, 1);
    	    if ((token->toktype != CRNG_OP) ||
    	        (token->token[0] != ')') || (token->token[1] != 0)) {
    		ERROR("Expecting \")\" here");
    	    }
    	    xmlParseCRNGDropTokens(ctxt, 1);
    	} else if ((token->token[0] == '*') && (token->token[1] == 0)) {
    	    xmlParseCRNGDropTokens(ctxt, 1);
    	    cur = xmlNewNode(NULL, BAD_CAST "anyName");
    	    if (cur == NULL) CRNG_MEM_ERROR0();
    	    if (ctxt->insert != NULL)
    		xmlAddChild(ctxt->insert, cur);
    	    ctxt->insert = cur;
    	    xmlParseCRNG_exceptNameClass(ctxt);
    	} else {
    	    TODO
    	}
        } else if ((token->toktype == CRNG_IDENTIFIER) ||
                   (token->toktype == CRNG_KEYWORD)) {
    	cur = xmlNewNode(NULL, BAD_CAST "name");
    	if (cur == NULL) CRNG_MEM_ERROR0();
    	if (ctxt->isElem) {
    	    xmlSetProp(cur, BAD_CAST "ns",
    
    	               xmlParseCRNG_lookupPrefix(ctxt, NULL));
    
    	    xmlSetProp(cur, BAD_CAST "ns", BAD_CAST "");
    
    	}
    	xmlNodeAddContent(cur, token->token);
    	if (ctxt->insert != NULL)
    	    xmlAddChild(ctxt->insert, cur);
    	ctxt->insert = cur;
    	xmlParseCRNGDropTokens(ctxt, 1);
        } else if (token->toktype == CRNG_CNAME) {
            TODO
        } else if (token->toktype == CRNG_NSNAME) {
    	cur = xmlNewNode(NULL, BAD_CAST "nsName");
    	if (cur == NULL) CRNG_MEM_ERROR0();
            xmlSetProp(cur, BAD_CAST "ns",
    
    	           xmlParseCRNG_lookupPrefix(ctxt, token->token));
    
    	if (ctxt->insert != NULL)
    	    xmlAddChild(ctxt->insert, cur);
    	ctxt->insert = cur;
    	xmlParseCRNGDropTokens(ctxt, 1);
    	xmlParseCRNG_exceptNameClass(ctxt);
        } else {
            TODO /* probably an error */
        }
    
        return(0);
    }
    
    /**
     * xmlParseCRNG_nameClass:
     * @ctxt: a compact RNG parser context
     *
     * Parse nameClass of the RELAX NG Compact Syntax Appendix A
     *
     * Returns 0 in case of success and -1 in case of error
     */
    static int
    xmlParseCRNG_nameClass(xmlCRelaxNGParserCtxtPtr ctxt)
    {
        tokenPtr token;
        xmlNodePtr insert = ctxt->insert, last, choice;
    
        ctxt->insert = NULL;
        xmlParseCRNG_innerNameClass(ctxt);
        last = ctxt->insert;
        token = xmlParseCRNGGetToken(ctxt, 1);
        while ((token->toktype == CRNG_OP) &&
            (token->token[0] == '|') && (token->token[1] == 0)) {
    	choice = xmlNewNodeEatName(NULL, (xmlChar *) ctxt->key_choice);
    	xmlParseCRNGDropTokens(ctxt, 1);
    	if (choice == NULL) CRNG_MEM_ERROR0();
    	ctxt->insert = NULL;
    	xmlParseCRNG_innerNameClass(ctxt);
    	xmlAddChild(choice, last);
    	xmlAddChild(choice, ctxt->insert);
    	last = choice;
    	token = xmlParseCRNGGetToken(ctxt, 1);
        }
        xmlAddChild(insert, last);
    
        ctxt->insert = insert;
        return(0);
    }
    
    /**
     * xmlParseCRNG_patternBlock:
     * @ctxt: a compact RNG parser context
     *
     * Parse a pattern block of the RELAX NG Compact Syntax Appendix A
     *
     * Returns 0 in case of success and -1 in case of error
     */
    static int
    xmlParseCRNG_patternBlock(xmlCRelaxNGParserCtxtPtr ctxt)
    {
        tokenPtr token;
    
        token = xmlParseCRNGGetToken(ctxt, 1);
        if ((token->toktype != CRNG_OP) ||
    	(token->token[0] != '{') || (token->token[1] != 0)) {
    	ERROR("Expecting \"{\" here");
        }
        xmlParseCRNGDropTokens(ctxt, 1);
        xmlParseCRNG_pattern(ctxt);
        token = xmlParseCRNGGetToken(ctxt, 1);
        if ((token->toktype != CRNG_OP) ||
    	(token->token[0] != '}') || (token->token[1] != 0)) {
    	ERROR("Expecting \"}\" here");
        }
        xmlParseCRNGDropTokens(ctxt, 1);
        return(0);
    }
    
    /**
     * xmlParseCRNG_datatype:
     * @ctxt: a compact RNG parser context
     *
     * Parse datatype of the RELAX NG Compact Syntax Appendix A
     *
     * Returns 0 in case of success and -1 in case of error
     */
    static int
    xmlParseCRNG_datatype(xmlCRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED)
    {
        tokenPtr token;
        xmlAttrPtr attrs = NULL;
    
        token = xmlParseCRNGGetToken(ctxt, 1);
        if (token->toktype == CRNG_KEYWORD) {
    	if (token->token == ctxt->key_string) {
    
    	    attrs = xmlParseCRNG_datatypeAttributes(ctxt, BAD_CAST "",
    
    	                                            token->token);
    	    xmlParseCRNGDropTokens(ctxt, 1);
    	} else if (token->token == ctxt->key_token) {
    
    	    attrs = xmlParseCRNG_datatypeAttributes(ctxt, BAD_CAST "",
    
    	                                            token->token);
    	    xmlParseCRNGDropTokens(ctxt, 1);
    	} else {
    	    TODO /* probably an error */
    	}
        } else if (token->toktype == CRNG_LITERAL_SEGMENT) {
    	ctxt->insert = xmlNewNode(NULL, BAD_CAST "value");
    	xmlParseCRNGDropTokens(ctxt, 1);
    	if (ctxt->insert == NULL) CRNG_MEM_ERROR0();
    	xmlNodeAddContent(ctxt->insert, token->token);
        } else if (token->toktype == CRNG_QNAME) {
    
    	attrs = xmlParseCRNG_datatypeAttributes(ctxt,
    
    	            xmlParseCRNG_lookupDatatypePrefix(ctxt, token->prefix),
    		    token->token);
        } else {
            TODO
        }
        if (attrs != NULL) {
    	token = xmlParseCRNGGetToken(ctxt, 1);
    	if (token->toktype == CRNG_LITERAL_SEGMENT) {
    	    ctxt->insert = xmlNewNode(NULL, BAD_CAST "value");
    	    xmlParseCRNGDropTokens(ctxt, 1);
    	    if (ctxt->insert == NULL) {
    	        xmlFreePropList(attrs);
    		CRNG_MEM_ERROR0();
    	    }
    	    ctxt->insert->properties = attrs;
    	    xmlNodeAddContent(ctxt->insert, token->token);
    	} else if ((token->toktype == CRNG_OP) &&
    	           (token->token[0] == '{') && (token->token[0] == 0)) {
    	    ctxt->insert = xmlNewNode(NULL, BAD_CAST "data");
    	    xmlParseCRNGDropTokens(ctxt, 1);
    	    if (ctxt->insert == NULL) {
    	        xmlFreePropList(attrs);
    		CRNG_MEM_ERROR0();
    	    }
    	    ctxt->insert->properties = attrs;
    	    xmlParseCRNG_params(ctxt);
            } else {
    	    ctxt->insert = xmlNewNode(NULL, BAD_CAST "data");
    	    xmlParseCRNGDropTokens(ctxt, 1);
    	    if (ctxt->insert == NULL) {
    	        xmlFreePropList(attrs);
    		CRNG_MEM_ERROR0();
    	    }
    	    ctxt->insert->properties = attrs;
    	    xmlNodeAddContent(ctxt->insert, token->token);
    	}
        }
        return(0);
    }
    
    /**
     * xmlParseCRNG_primary:
     * @ctxt: a compact RNG parser context
     *
     * Parse primary of the RELAX NG Compact Syntax Appendix A
     *
     * Returns 0 in case of success and -1 in case of error
     */
    static int
    xmlParseCRNG_primary(xmlCRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED)
    {
        tokenPtr token;
    
        token = xmlParseCRNGGetToken(ctxt, 1);
        if (token == NULL)
            return(0);
        if (token->toktype == CRNG_KEYWORD) {
            if (token->token == ctxt->key_element) {
    	    ctxt->insert = xmlNewNodeEatName(NULL, (xmlChar *) token->token);
    	    xmlParseCRNGDropTokens(ctxt, 1);
    	    if (ctxt->insert == NULL) CRNG_MEM_ERROR0();
    	    ctxt->isElem = 1;
    	    xmlParseCRNG_nameClass(ctxt);
    	    xmlParseCRNG_patternBlock(ctxt);
    	} else if (token->token == ctxt->key_attribute) {
    	    ctxt->insert = xmlNewNodeEatName(NULL, (xmlChar *) token->token);
    	    xmlParseCRNGDropTokens(ctxt, 1);
    	    if (ctxt->insert == NULL) CRNG_MEM_ERROR0();
    	    ctxt->isElem = 0;
    	    xmlParseCRNG_nameClass(ctxt);
    	    xmlParseCRNG_patternBlock(ctxt);
    	} else if (token->token == ctxt->key_mixed) {
    	    ctxt->insert = xmlNewNodeEatName(NULL, (xmlChar *) token->token);
    	    xmlParseCRNGDropTokens(ctxt, 1);
    	    if (ctxt->insert == NULL) CRNG_MEM_ERROR0();
    	    xmlParseCRNG_patternBlock(ctxt);
    	} else if (token->token == ctxt->key_list) {
    	    ctxt->insert = xmlNewNodeEatName(NULL, (xmlChar *) token->token);
    	    xmlParseCRNGDropTokens(ctxt, 1);
    	    if (ctxt->insert == NULL) CRNG_MEM_ERROR0();
    	    xmlParseCRNG_patternBlock(ctxt);
    	} else if (token->token == ctxt->key_empty) {
    	    ctxt->insert = xmlNewNodeEatName(NULL, (xmlChar *) token->token);
    	    xmlParseCRNGDropTokens(ctxt, 1);
    	    if (ctxt->insert == NULL) CRNG_MEM_ERROR0();
    	} else if (token->token == ctxt->key_notAllowed) {
    	    ctxt->insert = xmlNewNodeEatName(NULL, (xmlChar *) token->token);
    	    xmlParseCRNGDropTokens(ctxt, 1);
    	    if (ctxt->insert == NULL) CRNG_MEM_ERROR0();
    	} else if (token->token == ctxt->key_text) {
    	    ctxt->insert = xmlNewNodeEatName(NULL, (xmlChar *) token->token);
    	    xmlParseCRNGDropTokens(ctxt, 1);
    	    if (ctxt->insert == NULL) CRNG_MEM_ERROR0();
    	} else if (token->token == ctxt->key_parent) {
    	    ctxt->insert = xmlNewNodeEatName(NULL, (xmlChar *) token->token);
    	    xmlParseCRNGDropTokens(ctxt, 1);
    	    if (ctxt->insert == NULL) CRNG_MEM_ERROR0();
    	    TODO
    	} else if (token->token == ctxt->key_grammar) {
    	    ctxt->insert = xmlNewNodeEatName(NULL, (xmlChar *) token->token);
    	    xmlParseCRNGDropTokens(ctxt, 1);
    	    if (ctxt->insert == NULL) CRNG_MEM_ERROR0();
    	    TODO
    	} else if (token->token == ctxt->key_external) {
    	    ctxt->insert = xmlNewNode(NULL, BAD_CAST "externalRef");
    	    xmlParseCRNGDropTokens(ctxt, 1);
    	    if (ctxt->insert == NULL) CRNG_MEM_ERROR0();
    	    TODO
    	} else {
    	   TODO
    	}
        } else if (token->toktype == CRNG_IDENTIFIER) {
    	ctxt->insert = xmlNewNodeEatName(NULL, (xmlChar *) ctxt->key_ref);
    	if (ctxt->insert == NULL) CRNG_MEM_ERROR0();
    	xmlSetProp(ctxt->insert, BAD_CAST "name", token->token);
    	xmlParseCRNGDropTokens(ctxt, 1);
        } else if (token->toktype == CRNG_QNAME) {
            xmlParseCRNG_datatype(ctxt);
        } else if (token->toktype == CRNG_LITERAL_SEGMENT) {
            xmlParseCRNG_datatype(ctxt);
        } else if ((token->toktype == CRNG_OP) &&
                   (token->token[0] == '(') && (token->token[1] == 0)) {
    	xmlParseCRNGDropTokens(ctxt, 1);
    	xmlParseCRNG_pattern(ctxt);
    	token = xmlParseCRNGGetToken(ctxt, 1);
    	if ((token->toktype != CRNG_OP) ||
    	    (token->token[0] != ')') || (token->token[1] != 0)) {
    	    ERROR("Expecting \")\" here");
    	}
    	xmlParseCRNGDropTokens(ctxt, 1);
        }
        return(0);
    }
    
    /**
     * xmlParseCRNG_particle:
     * @ctxt: a compact RNG parser context
     *
     * Parse particle of the RELAX NG Compact Syntax Appendix A
     *
     * Returns 0 in case of success and -1 in case of error
     */
    static int
    xmlParseCRNG_particle(xmlCRelaxNGParserCtxtPtr ctxt)