Home | History | Annotate | Download | only in libxml2
      1 /**
      2  * rngparser.c: parser for the Relax-NG compact syntax.
      3  *
      4  * Based on:
      5  *   RELAX NG Compact Syntax
      6  *   Committee Specification 21 November 2002
      7  *   http://www.oasis-open.org/committees/relax-ng/compact-20021121.html
      8  *
      9  * See Copyright for the status of this software.
     10  *
     11  * Daniel Veillard <veillard (at) redhat.com>
     12  */
     13 
     14 #include <string.h>
     15 
     16 #include <libxml/parser.h>
     17 #include <libxml/parserInternals.h>
     18 #include <libxml/relaxng.h>
     19 #include <libxml/dict.h>
     20 
     21 #define TODO								\
     22     xmlGenericError(xmlGenericErrorContext,				\
     23 	    "Unimplemented block at %s:%d\n",				\
     24             __FILE__, __LINE__);
     25 
     26 #define MAX_TOKEN 10
     27 
     28 typedef enum {
     29     CRNG_NONE = 0,
     30     CRNG_OP = 1,
     31     CRNG_KEYWORD,
     32     CRNG_IDENTIFIER,
     33     CRNG_LITERAL_SEGMENT,
     34     CRNG_CNAME,
     35     CRNG_QNAME,
     36     CRNG_NSNAME,
     37     CRNG_DOCUMENTATION
     38 } xmlCRNGTokType;
     39 
     40 typedef enum {
     41     CRNG_OKAY = 0,
     42     CRNG_MEMORY_ERROR,
     43     CRNG_INVALID_CHAR_ERROR,
     44     CRNG_END_ERROR,
     45     CRNG_ENCODING_ERROR
     46 } xmlCRNGError;
     47 
     48 typedef enum {
     49     XML_CRNG_ERROR = -1,
     50     XML_CRNG_OK = 0,
     51     XML_CRNG_EOF = 1
     52 } xmlCRelaxNGParserState;
     53 
     54 typedef struct _token _token;
     55 typedef _token *tokenPtr;
     56 struct _token {
     57     xmlCRNGTokType toktype;
     58     int toklen;
     59     const xmlChar *token;
     60     const xmlChar *prefix;
     61 };
     62 
     63 typedef struct _xmlCRelaxNGParserCtxt xmlCRelaxNGParserCtxt;
     64 typedef xmlCRelaxNGParserCtxt *xmlCRelaxNGParserCtxtPtr;
     65 struct _xmlCRelaxNGParserCtxt {
     66     void *userData;			/* user specific data block */
     67     xmlRelaxNGValidityErrorFunc error;	/* the callback in case of errors */
     68     xmlRelaxNGValidityWarningFunc warning;/* the callback in case of warning */
     69     xmlRelaxNGValidErr err;
     70 
     71     const xmlChar *compact;
     72     const xmlChar *end;
     73     const xmlChar *cur;
     74     int isElem;
     75     int lineno;
     76     const xmlChar *linestart;
     77     const char *filename;
     78 
     79     int  nbTokens;
     80     int  firstToken;
     81     _token tokens[MAX_TOKEN];
     82     int  totalToken;
     83 
     84     xmlCRelaxNGParserState state;
     85 
     86     int            nbErrors;
     87 
     88     xmlDocPtr      res;			/* the result */
     89     xmlNodePtr     ins;			/* the current insertion node */
     90 
     91     xmlNsPtr       nsDef;
     92     tokenPtr token;
     93 
     94     xmlHashTablePtr namespaces;
     95     xmlHashTablePtr datatypes;
     96 
     97     /*
     98      * dictionary and keywords
     99      */
    100     xmlDictPtr     dict;
    101     const xmlChar *key_attribute;
    102     const xmlChar *key_default;
    103     const xmlChar *key_datatypes;
    104     const xmlChar *key_div;
    105     const xmlChar *key_element;
    106     const xmlChar *key_empty;
    107     const xmlChar *key_external;
    108     const xmlChar *key_grammar;
    109     const xmlChar *key_include;
    110     const xmlChar *key_inherit;
    111     const xmlChar *key_list;
    112     const xmlChar *key_mixed;
    113     const xmlChar *key_namespace;
    114     const xmlChar *key_notAllowed;
    115     const xmlChar *key_parent;
    116     const xmlChar *key_start;
    117     const xmlChar *key_string;
    118     const xmlChar *key_text;
    119     const xmlChar *key_token;
    120     const xmlChar *key_equal;
    121     const xmlChar *key_orequal;
    122     const xmlChar *key_andequal;
    123     const xmlChar *key_combine;
    124     const xmlChar *key_or;
    125     const xmlChar *key_comma;
    126     const xmlChar *key_and;
    127     const xmlChar *key_choice;
    128     const xmlChar *key_group;
    129     const xmlChar *key_interleave;
    130     const xmlChar *key_ref;
    131     const xmlChar *key_define;
    132 
    133     /* results */
    134     xmlDocPtr doc;	/* the resulting doc */
    135     xmlNodePtr insert;	/* the insertion point */
    136     xmlAttrPtr attrs;   /* pending attributes */
    137 };
    138 
    139 static const xmlChar *xmlCRelaxNGInherit = BAD_CAST "Inherit string";
    140 static const xmlChar *xmlCRelaxNGDefault = BAD_CAST "Default string";
    141 
    142 #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
    143 /**
    144  * IS_BLANK:
    145  * @c:  an UNICODE value (int)
    146  *
    147  * Macro to check the following production in the XML spec:
    148  *
    149  * [3] S ::= (#x20 | #x9 | #xD | #xA)+
    150  */
    151 #ifndef IS_BLANK
    152 #define IS_BLANK(c) (((c) == 0x20) || ((c) == 0x09) || ((c) == 0xA) ||	\
    153                      ((c) == 0x0D))
    154 #endif
    155 #define IS_SEPARATOR(c) (((c) == 0x20) || ((c) == 0x09) || ((c) == 0xA) || \
    156                      ((c) == 0x0D) || (c == '#'))
    157 
    158 #define CRNG_ERROR0(X)							\
    159     { xmlCRNGErr(ctxt, X, NULL); return(0); }
    160 #define CRNG_ERROR(X)							\
    161     { xmlCRNGErr(ctxt, X, NULL); }
    162 
    163 #define CRNG_MEM_ERROR0()						\
    164     { xmlCRNGErr(ctxt, CRNG_MEMORY_ERROR, NULL); return(0); }
    165 #define CRNG_MEM_ERROR()						\
    166     { xmlCRNGErr(ctxt, CRNG_MEMORY_ERROR, NULL); }
    167 
    168 #define ERROR(str) xmlCRNGErr(ctxt, 0, str);
    169 
    170 static void
    171 xmlCRNGErr(xmlCRelaxNGParserCtxtPtr ctxt, int err_no, const char *err_msg) {
    172     const xmlChar *cur;
    173     xmlChar buffer[150];
    174     int i, l;
    175 
    176     if (ctxt != NULL) {
    177         if (ctxt->filename != NULL)
    178 	    fprintf(stderr, "%s:%d ", ctxt->filename, ctxt->lineno);
    179     }
    180     if (err_msg != NULL) {
    181 	fprintf(stderr, "error: %s\n", err_msg);
    182     } else if (err_no != 0)
    183 	fprintf(stderr, "error %d\n", err_no);
    184     cur = ctxt->cur;
    185     while ((*cur != '\n') && (*cur != '\r') && (ctxt->cur - cur < 80)) cur--;
    186     l = ctxt->cur - cur;
    187     cur++;
    188     for (i = 0; i < 100;i++) {
    189         if ((*cur == '\n') || (*cur == '\r')) break;
    190         buffer[i] = *cur++;
    191     }
    192     buffer[i] = 0;
    193     fprintf(stderr, "%s\n", buffer);
    194     for (i = 0; i < l;i++) buffer[i] = ' ';
    195     buffer[i++] = '^';
    196     buffer[i++] = 0;
    197     fprintf(stderr, "%s\n", buffer);
    198 }
    199 
    200 /**
    201  * IS_OP
    202  * @c:  an UNICODE value (int)
    203  *
    204  * Macro to check for operator value
    205  */
    206 #ifndef IS_OP
    207 #define IS_OP(c) (((c) == ',') || ((c) == '&') || ((c) == '|') ||	\
    208 		  ((c) == '?') || ((c) == '-') || ((c) == '*') ||	\
    209 		  ((c) == '{') || ((c) == '}') || ((c) == '(') ||	\
    210 		  ((c) == ')') || ((c) == '+') || ((c) == '=') ||	\
    211 		  ((c) == ':'))
    212 #endif
    213 
    214 static int
    215 xmlCRNGIsKeyword(xmlCRelaxNGParserCtxtPtr ctxt, const xmlChar *str) {
    216     if ((str == ctxt->key_attribute) ||
    217         (str == ctxt->key_default) ||
    218         (str == ctxt->key_datatypes) ||
    219         (str == ctxt->key_div) ||
    220         (str == ctxt->key_element) ||
    221         (str == ctxt->key_empty) ||
    222         (str == ctxt->key_external) ||
    223         (str == ctxt->key_grammar) ||
    224         (str == ctxt->key_include) ||
    225         (str == ctxt->key_inherit) ||
    226         (str == ctxt->key_list) ||
    227         (str == ctxt->key_mixed) ||
    228         (str == ctxt->key_namespace) ||
    229         (str == ctxt->key_notAllowed) ||
    230         (str == ctxt->key_parent) ||
    231         (str == ctxt->key_start) ||
    232         (str == ctxt->key_string) ||
    233         (str == ctxt->key_text) ||
    234         (str == ctxt->key_token))
    235 	return(1);
    236     return(0);
    237 
    238 }
    239 
    240 /*
    241  * xmlCRNGNextToken:
    242  * ctxt:  a compact RNG parser context
    243  *
    244  * Scan the schema to get the next token
    245  *
    246  * Return 0 if success and -1 in case of error
    247  */
    248 
    249 static int
    250 xmlCRNGNextToken(xmlCRelaxNGParserCtxtPtr ctxt) {
    251     const xmlChar *cur;
    252     tokenPtr token;
    253 
    254     if (ctxt == NULL) return(-1);
    255     if (ctxt->nbTokens >= MAX_TOKEN) return(-1);
    256     token = &(ctxt->tokens[(ctxt->firstToken + ctxt->nbTokens) % MAX_TOKEN]);
    257     token->toktype = CRNG_NONE;
    258 
    259     if (ctxt->cur == NULL) {
    260         ctxt->cur = ctxt->compact;
    261     }
    262 retry:
    263     if (ctxt->cur >= ctxt->end) {
    264 	ctxt->state = XML_CRNG_EOF;
    265 	return(-1);
    266     }
    267     while ((ctxt->cur < ctxt->end) &&
    268            (IS_BLANK(*ctxt->cur))) ctxt->cur++;
    269     if (ctxt->cur >= ctxt->end) {
    270 	ctxt->state = XML_CRNG_EOF;
    271 	return(-1);
    272     }
    273     if (*ctxt->cur == '#') {
    274         cur = ctxt->cur;
    275 	cur++;
    276 	while ((cur < ctxt->end) && (*cur != '\n') && (*cur != '\r'))
    277 	    cur++;
    278         ctxt->cur = cur;
    279 	goto retry;
    280     } else if (*ctxt->cur == '"') {
    281         /* string, check for '"""' */
    282 	ctxt->cur++;
    283 	if (ctxt->cur >= ctxt->end) goto eof;
    284 	cur = ctxt->cur;
    285         if ((ctxt->end - ctxt->end > 2) &&
    286 	    (*cur == '"') && (cur[1] == '"')) {
    287 	    TODO
    288 	} else {
    289 	    while ((cur < ctxt->end) && (*cur != '"')) cur++;
    290 	    if (cur >= ctxt->end) goto eof;
    291 	    token->toklen = cur - ctxt->cur;
    292 	    token->token = xmlDictLookup(ctxt->dict, ctxt->cur, token->toklen);
    293 	    token->toktype = CRNG_LITERAL_SEGMENT;
    294 	    token->prefix = NULL;
    295 	    cur++;
    296 	    ctxt->cur = cur;
    297 	}
    298     } else if (*ctxt->cur == '\'') {
    299         /* string, check for "'''" */
    300 	TODO
    301     } else if ((IS_OP(*ctxt->cur)) || (*ctxt->cur == ':')) {
    302         cur = ctxt->cur;
    303 	cur++;
    304 	if ((cur < ctxt->end) &&
    305 	    (((*cur == '=') &&
    306 	      ((*ctxt->cur == '|') || (*ctxt->cur == '&'))) ||
    307 	     ((*cur == '*') && (*ctxt->cur == ':')))) {
    308 	    token->toklen = 2;
    309 	} else {
    310 	    token->toklen = 1;
    311 	}
    312 	token->token = xmlDictLookup(ctxt->dict, ctxt->cur, token->toklen);
    313 	token->toktype = CRNG_OP;
    314 	token->prefix = NULL;
    315 	ctxt->cur += token->toklen;
    316     } else {
    317         int escape = 0;
    318 
    319         cur = ctxt->cur;
    320         if (*cur == '\\') {
    321 	    escape = 1;
    322 	    cur++;
    323 	    ctxt->cur++;
    324 	}
    325 	while ((cur < ctxt->end) &&
    326 	       (!(IS_SEPARATOR(*cur))) && (!(IS_OP(*cur)))) cur++;
    327 
    328 	token->toklen = cur - ctxt->cur;
    329 	token->token = xmlDictLookup(ctxt->dict, ctxt->cur, token->toklen);
    330 	token->prefix = NULL;
    331 	ctxt->cur = cur;
    332 	if ((escape == 0) && (xmlCRNGIsKeyword(ctxt, token->token)))
    333 	    token->toktype = CRNG_KEYWORD;
    334 	else {
    335 	    token->toktype = CRNG_IDENTIFIER;
    336 	}
    337 	if (*ctxt->cur == ':') {
    338 	    ctxt->cur++;
    339 	    if (*ctxt->cur == '*') {
    340 		ctxt->cur++;
    341 		token->toktype = CRNG_NSNAME;
    342 	    } else {
    343 	        cur = ctxt->cur;
    344 		while ((cur < ctxt->end) &&
    345 		       (!(IS_SEPARATOR(*cur))) && (!(IS_OP(*cur)))) cur++;
    346 		token->prefix = token->token;
    347 		token->toklen = cur - ctxt->cur;
    348 		token->token = xmlDictLookup(ctxt->dict, ctxt->cur,
    349 		                             token->toklen);
    350 		ctxt->cur = cur;
    351 		if (xmlValidateNCName(token->token, 0) == 0)
    352 		    token->toktype = CRNG_QNAME;
    353 		else {
    354 		    TODO /* sounds like an error ! */
    355 		    token->toktype = CRNG_IDENTIFIER;
    356 		}
    357 	    }
    358 	}
    359     }
    360     ctxt->nbTokens++;
    361     return(0);
    362 eof:
    363     ctxt->state = XML_CRNG_EOF;
    364     CRNG_ERROR(CRNG_END_ERROR);
    365     return(-1);
    366 }
    367 
    368 /**
    369  * xmlParseCRNGGetToken:
    370  * @ctxt: a compact RNG parser context
    371  * @no: the number of the token from 1 for the first one
    372  *      and 2, 3 ... for read-ahead
    373  *
    374  * Token reading interface
    375  *
    376  * returns a pointer to the new token, or NULL in case of error or EOF
    377  */
    378 static tokenPtr
    379 xmlParseCRNGGetToken(xmlCRelaxNGParserCtxtPtr ctxt, int no) {
    380     tokenPtr ret;
    381     int res;
    382 
    383     if ((no <= 0) || (no >= MAX_TOKEN)) return(NULL);
    384     no--;
    385     while (ctxt->nbTokens <= no) {
    386         res = xmlCRNGNextToken(ctxt);
    387 	if (res < 0)
    388 	    return(NULL);
    389     }
    390     ret = &(ctxt->tokens[(ctxt->firstToken + no) % MAX_TOKEN]);
    391     return(ret);
    392 }
    393 
    394 /**
    395  * xmlParseCRNGDropTokens:
    396  * @ctxt: a compact RNG parser context
    397  * @nr: the number of token marked as read
    398  *
    399  * mark a number of token as read and consumed.
    400  *
    401  * Returns -1 in case of error and 0 otherwise
    402  */
    403 static int
    404 xmlParseCRNGDropTokens(xmlCRelaxNGParserCtxtPtr ctxt, int nr) {
    405     if ((nr <= 0) || (nr >= MAX_TOKEN)) return(-1);
    406     while ((ctxt->nbTokens >0) && (nr > 0)) {
    407         ctxt->firstToken++;
    408 	nr--;
    409 	ctxt->nbTokens--;
    410 	ctxt->totalToken++;
    411 	if (ctxt->totalToken == 384)
    412 	    fprintf(stderr, "found\n");
    413     }
    414     ctxt->firstToken = ctxt->firstToken % MAX_TOKEN;
    415     return(0);
    416 }
    417 
    418 static void
    419 xmlParseCRNGTokenize(xmlCRelaxNGParserCtxtPtr ctxt) {
    420     tokenPtr token;
    421 
    422     token = xmlParseCRNGGetToken(ctxt, 1);
    423     while (token != NULL) {
    424         switch (token->toktype) {
    425             case CRNG_NONE: printf("none"); break;
    426             case CRNG_OP: printf("op"); break;
    427             case CRNG_KEYWORD: printf("keyword"); break;
    428             case CRNG_IDENTIFIER: printf("identifier"); break;
    429             case CRNG_LITERAL_SEGMENT: printf("literal"); break;
    430             case CRNG_CNAME: printf("cname"); break;
    431             case CRNG_QNAME: printf("qname"); break;
    432             case CRNG_NSNAME: printf("nsname"); break;
    433             case CRNG_DOCUMENTATION: printf("doc"); break;
    434 	}
    435         printf(":%s\n", token->token);
    436 	xmlParseCRNGDropTokens(ctxt, 1);
    437 	token = xmlParseCRNGGetToken(ctxt, 1);
    438     }
    439 }
    440 
    441 /**
    442  * xmlParseCRNG_attribute:
    443  * @ctxt: a compact RNG parser context
    444  * @name: the attribute name
    445  * @ns: the attribute namespace
    446  * @value: the attribute value
    447  *
    448  * implements attribute of the RELAX NG Compact Syntax Appendix A
    449  *
    450  * Returns 0 in case of success and -1 in case of error
    451  */
    452 static int
    453 xmlParseCRNG_attribute(xmlCRelaxNGParserCtxtPtr ctxt,
    454                        const xmlChar *name,
    455                        xmlNsPtr ns,
    456 		       const xmlChar *value)
    457 {
    458     xmlAttrPtr attr;
    459 
    460     attr = xmlNewNsPropEatName(NULL, ns, (xmlChar *) name, value);
    461     if (attr == NULL) CRNG_MEM_ERROR0();
    462     attr->next = ctxt->attrs;
    463     if (ctxt->attrs != NULL)
    464         ctxt->attrs->prev = attr;
    465     ctxt->attrs = attr;
    466     return(0);
    467 }
    468 
    469 /**
    470  * xmlParseCRNG_bindPrefix:
    471  * @ctxt: a compact RNG parser context
    472  * @prefix: the namespace prefix or NULL
    473  * @namespace: the namespace name
    474  *
    475  * implements bindPrefix of the RELAX NG Compact Syntax Appendix A
    476  *
    477  * Returns 0 in case of success and -1 in case of error
    478  */
    479 static int
    480 xmlParseCRNG_bindPrefix(xmlCRelaxNGParserCtxtPtr ctxt,
    481                         const xmlChar *prefix,
    482 			const xmlChar *namespace)
    483 {
    484     int ret;
    485 
    486     if ((prefix != NULL) && (xmlStrEqual(prefix, BAD_CAST "xml"))  &&
    487         (!xmlStrEqual(namespace, XML_XML_NAMESPACE))) {
    488 	ERROR("The \"xml\" prefix must be bound to \"http://www.w3.org/XML/1998/namespace\"");
    489 	return(-1);
    490     } else if ((xmlStrEqual(namespace, XML_XML_NAMESPACE)) &&
    491                (!xmlStrEqual(prefix, BAD_CAST "xml"))) {
    492 	ERROR("The \"http://www.w3.org/XML/1998/namespace\" name must be bound to \"xml\" prefix");
    493 	return(-1);
    494     }
    495     if (ctxt->namespaces == NULL)
    496         ctxt->namespaces = xmlHashCreate(10);
    497     if (ctxt->namespaces == NULL) {
    498         ERROR("Failed to create namespace hash table");
    499 	return(-1);
    500     }
    501     if (prefix == NULL)
    502         ret = xmlHashAddEntry(ctxt->namespaces, xmlCRelaxNGDefault,
    503 	                      (void *) namespace);
    504     else
    505         ret = xmlHashAddEntry(ctxt->namespaces, prefix,
    506 	                      (void *) namespace);
    507     if (ret < 0) {
    508         if (prefix == NULL) {
    509 	    ERROR("Redefinition of default namespace");
    510 	} else {
    511 	    ERROR("Redefinition of namespace");
    512 	}
    513 	return(-1);
    514     }
    515 
    516     return(0);
    517 }
    518 
    519 /**
    520  * xmlParseCRNG_bindDatatypePrefix:
    521  * @ctxt: a compact RNG parser context
    522  * @prefix: the datatype prefix
    523  * @namespace: the datatype identifier
    524  *
    525  * implements bindDatatypePrefix of the RELAX NG Compact Syntax Appendix A
    526  *
    527  * Returns 0 in case of success and -1 in case of error
    528  */
    529 static int
    530 xmlParseCRNG_bindDatatypePrefix(xmlCRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
    531                                 const xmlChar *prefix,
    532 			        const xmlChar *namespace)
    533 {
    534     int ret;
    535 
    536     if ((prefix != NULL) && (xmlStrEqual(prefix, BAD_CAST "xsd"))  &&
    537         (!xmlStrEqual(namespace,
    538 		  BAD_CAST "http://www.w3.org/2001/XMLSchema-datatypes"))) {
    539 	ERROR("The \"xsd\" prefix must be bound to \"http://www.w3.org/2001/XMLSchema-datatypes\"");
    540 	return(-1);
    541     }
    542     if (ctxt->datatypes == NULL)
    543         ctxt->datatypes = xmlHashCreate(10);
    544     if (ctxt->datatypes == NULL) {
    545         ERROR("Failed to create namespace hash table");
    546 	return(-1);
    547     }
    548     ret = xmlHashAddEntry(ctxt->datatypes, prefix,
    549                           (void *) namespace);
    550     if (ret < 0) {
    551 	ERROR("Redefinition of datatype");
    552 	return(-1);
    553     }
    554     return(0);
    555 }
    556 
    557 /**
    558  * xmlParseCRNG_lookupPrefix:
    559  * @ctxt: a compact RNG parser context
    560  * @prefix: the namespace prefix or NULL
    561  *
    562  * implements lookupPrefix of the RELAX NG Compact Syntax Appendix A
    563  *
    564  * Returns the prefix in case of success or NULL in case of error
    565  */
    566 static const xmlChar *
    567 xmlParseCRNG_lookupPrefix(xmlCRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
    568                         const xmlChar *prefix)
    569 {
    570     const xmlChar *ret;
    571 
    572     if (prefix == NULL)
    573         ret = xmlHashLookup(ctxt->namespaces, xmlCRelaxNGDefault);
    574     else
    575         ret = xmlHashLookup(ctxt->namespaces, prefix);
    576     return(ret);
    577 }
    578 
    579 /**
    580  * xmlParseCRNG_lookupDatatypePrefix:
    581  * @ctxt: a compact RNG parser context
    582  * @prefix: the namespace prefix or NULL
    583  *
    584  * implements lookupDatatypePrefix of the RELAX NG Compact Syntax Appendix A
    585  *
    586  * Returns the prefix in case of success or NULL in case of error
    587  */
    588 static const xmlChar *
    589 xmlParseCRNG_lookupDatatypePrefix(xmlCRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
    590                         const xmlChar *prefix)
    591 {
    592     const xmlChar *ret;
    593     ret = xmlHashLookup(ctxt->datatypes, prefix);
    594     return(ret);
    595 }
    596 
    597 /**
    598  * xmlParseCRNG_datatypeAttributes:
    599  * @ctxt: a compact RNG parser context
    600  * @prefix: the namespace prefix or NULL
    601  *
    602  * implements lookupPrefix of the RELAX NG Compact Syntax Appendix A
    603  *
    604  * Returns the prefix in case of success or NULL in case of error
    605  */
    606 static xmlAttrPtr
    607 xmlParseCRNG_datatypeAttributes(xmlCRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
    608                         const xmlChar *library, const xmlChar *type)
    609 {
    610     xmlAttrPtr lib, typ;
    611 
    612     lib = xmlNewNsProp(NULL, NULL, BAD_CAST "datatypeLibrary", library);
    613     if (lib == NULL) {
    614         CRNG_MEM_ERROR();
    615 	return(NULL);
    616     }
    617     typ = xmlNewNsProp(NULL, NULL, BAD_CAST "type", type);
    618     if (typ == NULL) {
    619         CRNG_MEM_ERROR();
    620 	return(lib);
    621     }
    622     lib->next = typ;
    623 
    624     return(lib);
    625 }
    626 
    627 /**
    628  * xmlParseCRNG_XXX:
    629  * @ctxt: a compact RNG parser context
    630  *
    631  * Parse XXX of the RELAX NG Compact Syntax Appendix A
    632  *
    633  * Returns 0 in case of success and -1 in case of error
    634  */
    635 static int
    636 xmlParseCRNG_XXX(xmlCRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED)
    637 {
    638     return(0);
    639 }
    640 
    641 static int xmlParseCRNG_pattern(xmlCRelaxNGParserCtxtPtr ctxt);
    642 static int xmlParseCRNG_nameClass(xmlCRelaxNGParserCtxtPtr ctxt);
    643 
    644 /**
    645  * xmlParseCRNG_params:
    646  * @ctxt: a compact RNG parser context
    647  *
    648  * Parse params of the RELAX NG Compact Syntax Appendix A
    649  *
    650  * Returns 0 in case of success and -1 in case of error
    651  */
    652 static int
    653 xmlParseCRNG_params(xmlCRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED)
    654 {
    655     TODO
    656     return(0);
    657 }
    658 
    659 /**
    660  * xmlParseCRNG_exceptNameClass:
    661  * @ctxt: a compact RNG parser context
    662  *
    663  * Parse exceptNameClass of the RELAX NG Compact Syntax Appendix A
    664  *
    665  * Returns 0 in case of success and -1 in case of error
    666  */
    667 static int
    668 xmlParseCRNG_exceptNameClass(xmlCRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED)
    669 {
    670     tokenPtr token;
    671     xmlNodePtr insert = ctxt->insert, cur;
    672 
    673     token = xmlParseCRNGGetToken(ctxt, 1);
    674     if ((token->toktype == CRNG_OP) &&
    675         (token->token[0] == '-') && (token->token[1] == 0)) {
    676 	xmlParseCRNGDropTokens(ctxt, 1);
    677 	cur = xmlNewNode(NULL, BAD_CAST "except");
    678 	if (cur == NULL) CRNG_MEM_ERROR0();
    679 	if (ctxt->insert != NULL)
    680 	    xmlAddChild(ctxt->insert, cur);
    681 	ctxt->insert = cur;
    682 	xmlParseCRNG_nameClass(ctxt);
    683     }
    684     ctxt->insert = insert;
    685     return(0);
    686 }
    687 
    688 /**
    689  * xmlParseCRNG_innerNameClass:
    690  * @ctxt: a compact RNG parser context
    691  *
    692  * Parse innerNameClass of the RELAX NG Compact Syntax Appendix A
    693  *
    694  * Returns 0 in case of success and -1 in case of error
    695  */
    696 static int
    697 xmlParseCRNG_innerNameClass(xmlCRelaxNGParserCtxtPtr ctxt)
    698 {
    699     tokenPtr token;
    700     xmlNodePtr cur;
    701 
    702     token = xmlParseCRNGGetToken(ctxt, 1);
    703     if (token->toktype == CRNG_OP) {
    704         if ((token->token[0] == '(') && (token->token[1] == 0)) {
    705 	    xmlParseCRNGDropTokens(ctxt, 1);
    706 	    xmlParseCRNG_nameClass(ctxt);
    707 	    token = xmlParseCRNGGetToken(ctxt, 1);
    708 	    if ((token->toktype != CRNG_OP) ||
    709 	        (token->token[0] != ')') || (token->token[1] != 0)) {
    710 		ERROR("Expecting \")\" here");
    711 	    }
    712 	    xmlParseCRNGDropTokens(ctxt, 1);
    713 	} else if ((token->token[0] == '*') && (token->token[1] == 0)) {
    714 	    xmlParseCRNGDropTokens(ctxt, 1);
    715 	    cur = xmlNewNode(NULL, BAD_CAST "anyName");
    716 	    if (cur == NULL) CRNG_MEM_ERROR0();
    717 	    if (ctxt->insert != NULL)
    718 		xmlAddChild(ctxt->insert, cur);
    719 	    ctxt->insert = cur;
    720 	    xmlParseCRNG_exceptNameClass(ctxt);
    721 	} else {
    722 	    TODO
    723 	}
    724     } else if ((token->toktype == CRNG_IDENTIFIER) ||
    725                (token->toktype == CRNG_KEYWORD)) {
    726 	cur = xmlNewNode(NULL, BAD_CAST "name");
    727 	if (cur == NULL) CRNG_MEM_ERROR0();
    728 	if (ctxt->isElem) {
    729 	    xmlSetProp(cur, BAD_CAST "ns",
    730 	               xmlParseCRNG_lookupPrefix(ctxt, NULL));
    731 	} else {
    732 	    xmlSetProp(cur, BAD_CAST "ns", BAD_CAST "");
    733 	}
    734 	xmlNodeAddContent(cur, token->token);
    735 	if (ctxt->insert != NULL)
    736 	    xmlAddChild(ctxt->insert, cur);
    737 	ctxt->insert = cur;
    738 	xmlParseCRNGDropTokens(ctxt, 1);
    739     } else if (token->toktype == CRNG_CNAME) {
    740         TODO
    741     } else if (token->toktype == CRNG_NSNAME) {
    742 	cur = xmlNewNode(NULL, BAD_CAST "nsName");
    743 	if (cur == NULL) CRNG_MEM_ERROR0();
    744         xmlSetProp(cur, BAD_CAST "ns",
    745 	           xmlParseCRNG_lookupPrefix(ctxt, token->token));
    746 	if (ctxt->insert != NULL)
    747 	    xmlAddChild(ctxt->insert, cur);
    748 	ctxt->insert = cur;
    749 	xmlParseCRNGDropTokens(ctxt, 1);
    750 	xmlParseCRNG_exceptNameClass(ctxt);
    751     } else {
    752         TODO /* probably an error */
    753     }
    754 
    755     return(0);
    756 }
    757 
    758 /**
    759  * xmlParseCRNG_nameClass:
    760  * @ctxt: a compact RNG parser context
    761  *
    762  * Parse nameClass of the RELAX NG Compact Syntax Appendix A
    763  *
    764  * Returns 0 in case of success and -1 in case of error
    765  */
    766 static int
    767 xmlParseCRNG_nameClass(xmlCRelaxNGParserCtxtPtr ctxt)
    768 {
    769     tokenPtr token;
    770     xmlNodePtr insert = ctxt->insert, last, choice;
    771 
    772     ctxt->insert = NULL;
    773     xmlParseCRNG_innerNameClass(ctxt);
    774     last = ctxt->insert;
    775     token = xmlParseCRNGGetToken(ctxt, 1);
    776     while ((token->toktype == CRNG_OP) &&
    777         (token->token[0] == '|') && (token->token[1] == 0)) {
    778 	choice = xmlNewNodeEatName(NULL, (xmlChar *) ctxt->key_choice);
    779 	xmlParseCRNGDropTokens(ctxt, 1);
    780 	if (choice == NULL) CRNG_MEM_ERROR0();
    781 	ctxt->insert = NULL;
    782 	xmlParseCRNG_innerNameClass(ctxt);
    783 	xmlAddChild(choice, last);
    784 	xmlAddChild(choice, ctxt->insert);
    785 	last = choice;
    786 	token = xmlParseCRNGGetToken(ctxt, 1);
    787     }
    788     xmlAddChild(insert, last);
    789 
    790     ctxt->insert = insert;
    791     return(0);
    792 }
    793 
    794 /**
    795  * xmlParseCRNG_patternBlock:
    796  * @ctxt: a compact RNG parser context
    797  *
    798  * Parse a pattern block of the RELAX NG Compact Syntax Appendix A
    799  *
    800  * Returns 0 in case of success and -1 in case of error
    801  */
    802 static int
    803 xmlParseCRNG_patternBlock(xmlCRelaxNGParserCtxtPtr ctxt)
    804 {
    805     tokenPtr token;
    806 
    807     token = xmlParseCRNGGetToken(ctxt, 1);
    808     if ((token->toktype != CRNG_OP) ||
    809 	(token->token[0] != '{') || (token->token[1] != 0)) {
    810 	ERROR("Expecting \"{\" here");
    811     }
    812     xmlParseCRNGDropTokens(ctxt, 1);
    813     xmlParseCRNG_pattern(ctxt);
    814     token = xmlParseCRNGGetToken(ctxt, 1);
    815     if ((token->toktype != CRNG_OP) ||
    816 	(token->token[0] != '}') || (token->token[1] != 0)) {
    817 	ERROR("Expecting \"}\" here");
    818     }
    819     xmlParseCRNGDropTokens(ctxt, 1);
    820     return(0);
    821 }
    822 
    823 /**
    824  * xmlParseCRNG_datatype:
    825  * @ctxt: a compact RNG parser context
    826  *
    827  * Parse datatype of the RELAX NG Compact Syntax Appendix A
    828  *
    829  * Returns 0 in case of success and -1 in case of error
    830  */
    831 static int
    832 xmlParseCRNG_datatype(xmlCRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED)
    833 {
    834     tokenPtr token;
    835     xmlAttrPtr attrs = NULL;
    836 
    837     token = xmlParseCRNGGetToken(ctxt, 1);
    838     if (token->toktype == CRNG_KEYWORD) {
    839 	if (token->token == ctxt->key_string) {
    840 	    attrs = xmlParseCRNG_datatypeAttributes(ctxt, BAD_CAST "",
    841 	                                            token->token);
    842 	    xmlParseCRNGDropTokens(ctxt, 1);
    843 	} else if (token->token == ctxt->key_token) {
    844 	    attrs = xmlParseCRNG_datatypeAttributes(ctxt, BAD_CAST "",
    845 	                                            token->token);
    846 	    xmlParseCRNGDropTokens(ctxt, 1);
    847 	} else {
    848 	    TODO /* probably an error */
    849 	}
    850     } else if (token->toktype == CRNG_LITERAL_SEGMENT) {
    851 	ctxt->insert = xmlNewNode(NULL, BAD_CAST "value");
    852 	xmlParseCRNGDropTokens(ctxt, 1);
    853 	if (ctxt->insert == NULL) CRNG_MEM_ERROR0();
    854 	xmlNodeAddContent(ctxt->insert, token->token);
    855     } else if (token->toktype == CRNG_QNAME) {
    856 	attrs = xmlParseCRNG_datatypeAttributes(ctxt,
    857 	            xmlParseCRNG_lookupDatatypePrefix(ctxt, token->prefix),
    858 		    token->token);
    859     } else {
    860         TODO
    861     }
    862     if (attrs != NULL) {
    863 	token = xmlParseCRNGGetToken(ctxt, 1);
    864 	if (token->toktype == CRNG_LITERAL_SEGMENT) {
    865 	    ctxt->insert = xmlNewNode(NULL, BAD_CAST "value");
    866 	    xmlParseCRNGDropTokens(ctxt, 1);
    867 	    if (ctxt->insert == NULL) {
    868 	        xmlFreePropList(attrs);
    869 		CRNG_MEM_ERROR0();
    870 	    }
    871 	    ctxt->insert->properties = attrs;
    872 	    xmlNodeAddContent(ctxt->insert, token->token);
    873 	} else if ((token->toktype == CRNG_OP) &&
    874 	           (token->token[0] == '{') && (token->token[0] == 0)) {
    875 	    ctxt->insert = xmlNewNode(NULL, BAD_CAST "data");
    876 	    xmlParseCRNGDropTokens(ctxt, 1);
    877 	    if (ctxt->insert == NULL) {
    878 	        xmlFreePropList(attrs);
    879 		CRNG_MEM_ERROR0();
    880 	    }
    881 	    ctxt->insert->properties = attrs;
    882 	    xmlParseCRNG_params(ctxt);
    883         } else {
    884 	    ctxt->insert = xmlNewNode(NULL, BAD_CAST "data");
    885 	    xmlParseCRNGDropTokens(ctxt, 1);
    886 	    if (ctxt->insert == NULL) {
    887 	        xmlFreePropList(attrs);
    888 		CRNG_MEM_ERROR0();
    889 	    }
    890 	    ctxt->insert->properties = attrs;
    891 	    xmlNodeAddContent(ctxt->insert, token->token);
    892 	}
    893     }
    894     return(0);
    895 }
    896 
    897 /**
    898  * xmlParseCRNG_primary:
    899  * @ctxt: a compact RNG parser context
    900  *
    901  * Parse primary of the RELAX NG Compact Syntax Appendix A
    902  *
    903  * Returns 0 in case of success and -1 in case of error
    904  */
    905 static int
    906 xmlParseCRNG_primary(xmlCRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED)
    907 {
    908     tokenPtr token;
    909 
    910     token = xmlParseCRNGGetToken(ctxt, 1);
    911     if (token == NULL)
    912         return(0);
    913     if (token->toktype == CRNG_KEYWORD) {
    914         if (token->token == ctxt->key_element) {
    915 	    ctxt->insert = xmlNewNodeEatName(NULL, (xmlChar *) token->token);
    916 	    xmlParseCRNGDropTokens(ctxt, 1);
    917 	    if (ctxt->insert == NULL) CRNG_MEM_ERROR0();
    918 	    ctxt->isElem = 1;
    919 	    xmlParseCRNG_nameClass(ctxt);
    920 	    xmlParseCRNG_patternBlock(ctxt);
    921 	} else if (token->token == ctxt->key_attribute) {
    922 	    ctxt->insert = xmlNewNodeEatName(NULL, (xmlChar *) token->token);
    923 	    xmlParseCRNGDropTokens(ctxt, 1);
    924 	    if (ctxt->insert == NULL) CRNG_MEM_ERROR0();
    925 	    ctxt->isElem = 0;
    926 	    xmlParseCRNG_nameClass(ctxt);
    927 	    xmlParseCRNG_patternBlock(ctxt);
    928 	} else if (token->token == ctxt->key_mixed) {
    929 	    ctxt->insert = xmlNewNodeEatName(NULL, (xmlChar *) token->token);
    930 	    xmlParseCRNGDropTokens(ctxt, 1);
    931 	    if (ctxt->insert == NULL) CRNG_MEM_ERROR0();
    932 	    xmlParseCRNG_patternBlock(ctxt);
    933 	} else if (token->token == ctxt->key_list) {
    934 	    ctxt->insert = xmlNewNodeEatName(NULL, (xmlChar *) token->token);
    935 	    xmlParseCRNGDropTokens(ctxt, 1);
    936 	    if (ctxt->insert == NULL) CRNG_MEM_ERROR0();
    937 	    xmlParseCRNG_patternBlock(ctxt);
    938 	} else if (token->token == ctxt->key_empty) {
    939 	    ctxt->insert = xmlNewNodeEatName(NULL, (xmlChar *) token->token);
    940 	    xmlParseCRNGDropTokens(ctxt, 1);
    941 	    if (ctxt->insert == NULL) CRNG_MEM_ERROR0();
    942 	} else if (token->token == ctxt->key_notAllowed) {
    943 	    ctxt->insert = xmlNewNodeEatName(NULL, (xmlChar *) token->token);
    944 	    xmlParseCRNGDropTokens(ctxt, 1);
    945 	    if (ctxt->insert == NULL) CRNG_MEM_ERROR0();
    946 	} else if (token->token == ctxt->key_text) {
    947 	    ctxt->insert = xmlNewNodeEatName(NULL, (xmlChar *) token->token);
    948 	    xmlParseCRNGDropTokens(ctxt, 1);
    949 	    if (ctxt->insert == NULL) CRNG_MEM_ERROR0();
    950 	} else if (token->token == ctxt->key_parent) {
    951 	    ctxt->insert = xmlNewNodeEatName(NULL, (xmlChar *) token->token);
    952 	    xmlParseCRNGDropTokens(ctxt, 1);
    953 	    if (ctxt->insert == NULL) CRNG_MEM_ERROR0();
    954 	    TODO
    955 	} else if (token->token == ctxt->key_grammar) {
    956 	    ctxt->insert = xmlNewNodeEatName(NULL, (xmlChar *) token->token);
    957 	    xmlParseCRNGDropTokens(ctxt, 1);
    958 	    if (ctxt->insert == NULL) CRNG_MEM_ERROR0();
    959 	    TODO
    960 	} else if (token->token == ctxt->key_external) {
    961 	    ctxt->insert = xmlNewNode(NULL, BAD_CAST "externalRef");
    962 	    xmlParseCRNGDropTokens(ctxt, 1);
    963 	    if (ctxt->insert == NULL) CRNG_MEM_ERROR0();
    964 	    TODO
    965 	} else {
    966 	   TODO
    967 	}
    968     } else if (token->toktype == CRNG_IDENTIFIER) {
    969 	ctxt->insert = xmlNewNodeEatName(NULL, (xmlChar *) ctxt->key_ref);
    970 	if (ctxt->insert == NULL) CRNG_MEM_ERROR0();
    971 	xmlSetProp(ctxt->insert, BAD_CAST "name", token->token);
    972 	xmlParseCRNGDropTokens(ctxt, 1);
    973     } else if (token->toktype == CRNG_QNAME) {
    974         xmlParseCRNG_datatype(ctxt);
    975     } else if (token->toktype == CRNG_LITERAL_SEGMENT) {
    976         xmlParseCRNG_datatype(ctxt);
    977     } else if ((token->toktype == CRNG_OP) &&
    978                (token->token[0] == '(') && (token->token[1] == 0)) {
    979 	xmlParseCRNGDropTokens(ctxt, 1);
    980 	xmlParseCRNG_pattern(ctxt);
    981 	token = xmlParseCRNGGetToken(ctxt, 1);
    982 	if ((token->toktype != CRNG_OP) ||
    983 	    (token->token[0] != ')') || (token->token[1] != 0)) {
    984 	    ERROR("Expecting \")\" here");
    985 	}
    986 	xmlParseCRNGDropTokens(ctxt, 1);
    987     }
    988     return(0);
    989 }
    990 
    991 /**
    992  * xmlParseCRNG_particle:
    993  * @ctxt: a compact RNG parser context
    994  *
    995  * Parse particle of the RELAX NG Compact Syntax Appendix A
    996  *
    997  * Returns 0 in case of success and -1 in case of error
    998  */
    999 static int
   1000 xmlParseCRNG_particle(xmlCRelaxNGParserCtxtPtr ctxt)
   1001 {
   1002     tokenPtr token;
   1003     xmlNodePtr insert = ctxt->insert, res, tmp = NULL;
   1004 
   1005     ctxt->insert = NULL;
   1006     xmlParseCRNG_primary(ctxt);
   1007     res = ctxt->insert;
   1008     token = xmlParseCRNGGetToken(ctxt, 1);
   1009     if ((token != NULL) && (token->toktype == CRNG_OP)) {
   1010         if ((token->token[0] == '*') && (token->token[1] == 0)) {
   1011 	    tmp = xmlNewNode(NULL, BAD_CAST "zeroOrMore");
   1012 	    if (tmp == NULL) CRNG_MEM_ERROR0();
   1013 	} else if ((token->token[0] == '+') && (token->token[1] == 0)) {
   1014 	    tmp = xmlNewNode(NULL, BAD_CAST "oneOrMore");
   1015 	    if (tmp == NULL) CRNG_MEM_ERROR0();
   1016 	} else if ((token->token[0] == '?') && (token->token[1] == 0)) {
   1017 	    tmp = xmlNewNode(NULL, BAD_CAST "optional");
   1018 	    if (tmp == NULL) CRNG_MEM_ERROR0();
   1019 	}
   1020 	if (tmp != NULL) {
   1021 	    xmlAddChild(tmp, res);
   1022 	    res = tmp;
   1023 	    xmlParseCRNGDropTokens(ctxt, 1);
   1024 	}
   1025     }
   1026     if (insert != NULL) {
   1027         xmlAddChild(insert, res);
   1028 	ctxt->insert = insert;
   1029     } else
   1030         ctxt->insert = res;
   1031     return(0);
   1032 }
   1033 
   1034 /**
   1035  * xmlParseCRNG_pattern:
   1036  * @ctxt: a compact RNG parser context
   1037  *
   1038  * Parse pattern of the RELAX NG Compact Syntax Appendix A
   1039  *
   1040  * Returns 0 in case of success and -1 in case of error
   1041  */
   1042 static int
   1043 xmlParseCRNG_pattern(xmlCRelaxNGParserCtxtPtr ctxt)
   1044 {
   1045     tokenPtr token;
   1046     xmlNodePtr insert = ctxt->insert, prev, grp;
   1047 
   1048     ctxt->insert = NULL;
   1049     xmlParseCRNG_particle(ctxt);
   1050     prev = ctxt->insert;
   1051     token = xmlParseCRNGGetToken(ctxt, 1);
   1052     while ((prev != NULL) && (token != NULL) && (token->toktype == CRNG_OP)) {
   1053         if (token->token == ctxt->key_or) {
   1054 	    grp = xmlNewNodeEatName(NULL, (xmlChar *) ctxt->key_choice);
   1055 	    if (grp == NULL) CRNG_MEM_ERROR0();
   1056 	} else if (token->token == ctxt->key_and) {
   1057 	    grp = xmlNewNodeEatName(NULL, (xmlChar *) ctxt->key_interleave);
   1058 	    if (grp == NULL) CRNG_MEM_ERROR0();
   1059 	} else if (token->token == ctxt->key_comma) {
   1060 	    grp = xmlNewNodeEatName(NULL, (xmlChar *) ctxt->key_group);
   1061 	    if (grp == NULL) CRNG_MEM_ERROR0();
   1062 	} else
   1063 	   break;
   1064 	xmlParseCRNGDropTokens(ctxt, 1);
   1065         ctxt->insert = NULL;
   1066 	xmlParseCRNG_particle(ctxt);
   1067 	xmlAddChild(grp, prev);
   1068 	xmlAddChild(grp, ctxt->insert);
   1069 	prev = grp;
   1070 	token = xmlParseCRNGGetToken(ctxt, 1);
   1071     }
   1072     if (insert != NULL) {
   1073 	xmlAddChild(insert, prev);
   1074 	ctxt->insert = insert;
   1075     } else {
   1076 	ctxt->insert = prev;
   1077     }
   1078 
   1079     return(0);
   1080 }
   1081 
   1082 /**
   1083  * xmlParseCRNG_component:
   1084  * @ctxt: a compact RNG parser context
   1085  *
   1086  * Parse component of the RELAX NG Compact Syntax Appendix A
   1087  *
   1088  * Returns 0 in case of success and -1 in case of error
   1089  */
   1090 static int
   1091 xmlParseCRNG_component(xmlCRelaxNGParserCtxtPtr ctxt)
   1092 {
   1093     tokenPtr token, tok2;
   1094     xmlNodePtr insert = ctxt->insert;
   1095 
   1096     token = xmlParseCRNGGetToken(ctxt, 1);
   1097     if (token == NULL)
   1098         return(0);
   1099     if (token->toktype == CRNG_KEYWORD) {
   1100         if (token->token == ctxt->key_start) {
   1101 	    xmlNodePtr start;
   1102 
   1103 	    start = xmlNewNodeEatName(NULL, (xmlChar *) ctxt->key_start);
   1104 	    if (start == NULL) CRNG_MEM_ERROR0();
   1105 	    if (ctxt->insert != NULL)
   1106 	        xmlAddChild(ctxt->insert, start);
   1107 	    ctxt->insert = start;
   1108             xmlParseCRNGDropTokens(ctxt, 1);
   1109 	    token = xmlParseCRNGGetToken(ctxt, 1);
   1110 
   1111             if ((token->toktype == CRNG_OP) &&
   1112 	        (token->token == ctxt->key_equal)) {
   1113 	    } else if ((token->toktype == CRNG_OP) &&
   1114 	               (token->token == ctxt->key_orequal)) {
   1115 		xmlParseCRNG_attribute(ctxt, ctxt->key_combine, NULL,
   1116 		                       BAD_CAST "choice");
   1117 	    } else if ((token->toktype == CRNG_OP) &&
   1118 	               (token->token == ctxt->key_andequal)) {
   1119 		xmlParseCRNG_attribute(ctxt, ctxt->key_combine, NULL,
   1120 		                       BAD_CAST "interleave");
   1121 	    } else {
   1122 	        ERROR("expecting \"=\" or \"&=\" or \"|=\" here")
   1123 		return(-1);
   1124 	    }
   1125 	    start->properties = ctxt->attrs;
   1126 	    ctxt->attrs = NULL;
   1127             xmlParseCRNGDropTokens(ctxt, 1);
   1128 	    xmlParseCRNG_pattern(ctxt);
   1129 
   1130 	} else if (token->token == ctxt->key_include) {
   1131 	    TODO
   1132 	} else if (token->token == ctxt->key_div) {
   1133 	    TODO
   1134 	} else {
   1135 	    return(-1);
   1136 	}
   1137     } else if (token->toktype == CRNG_IDENTIFIER) {
   1138         xmlNodePtr define;
   1139 	const xmlChar *identifier;
   1140 
   1141         identifier = token->token;
   1142 	tok2 = xmlParseCRNGGetToken(ctxt, 2);
   1143 	if ((tok2->toktype == CRNG_OP) &&
   1144 	    (tok2->token == ctxt->key_equal)) {
   1145 	} else if ((tok2->toktype == CRNG_OP) &&
   1146 		   (tok2->token == ctxt->key_orequal)) {
   1147 	    xmlParseCRNG_attribute(ctxt, ctxt->key_combine, NULL,
   1148 				   BAD_CAST "choice");
   1149 	} else if ((tok2->toktype == CRNG_OP) &&
   1150 		   (tok2->token == ctxt->key_andequal)) {
   1151 	    xmlParseCRNG_attribute(ctxt, ctxt->key_combine, NULL,
   1152 				   BAD_CAST "interleave");
   1153 	} else {
   1154 	    ERROR("expecting \"=\" or \"&=\" or \"|=\" here")
   1155 	    return(-1);
   1156 	}
   1157 	xmlParseCRNGDropTokens(ctxt, 2);
   1158 
   1159 	define = xmlNewNodeEatName(NULL, (xmlChar *) ctxt->key_define);
   1160 	if (define == NULL) CRNG_MEM_ERROR0();
   1161 	define->properties = ctxt->attrs;
   1162 	ctxt->attrs = NULL;
   1163 	xmlSetProp(define, BAD_CAST "name", identifier);
   1164 	if (ctxt->insert != NULL)
   1165 	    xmlAddChild(ctxt->insert, define);
   1166 	ctxt->insert = define;
   1167 	xmlParseCRNG_pattern(ctxt);
   1168     } else {
   1169 	return(-1);
   1170     }
   1171     ctxt->insert = insert;
   1172     return(0);
   1173 }
   1174 
   1175 /**
   1176  * xmlParseCRNG_grammar:
   1177  * @ctxt: a compact RNG parser context
   1178  *
   1179  * Parse grammar of the RELAX NG Compact Syntax Appendix A
   1180  *
   1181  * Returns 0 in case of success and -1 in case of error
   1182  */
   1183 static int
   1184 xmlParseCRNG_grammar(xmlCRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED)
   1185 {
   1186     tokenPtr token;
   1187     int ret;
   1188 
   1189     token = xmlParseCRNGGetToken(ctxt, 1);
   1190     while (token != NULL) {
   1191         ret = xmlParseCRNG_component(ctxt);
   1192 	if (ret != 0)
   1193 	    break;
   1194 	token = xmlParseCRNGGetToken(ctxt, 1);
   1195     }
   1196     return(0);
   1197 }
   1198 
   1199 /**
   1200  * xmlParseCRNG_topLevelBody:
   1201  * @ctxt: a compact RNG parser context
   1202  *
   1203  * Parse topLevelBody of the RELAX NG Compact Syntax Appendix A
   1204  *
   1205  * Returns 0 in case of success and -1 in case of error
   1206  */
   1207 static int
   1208 xmlParseCRNG_topLevelBody(xmlCRelaxNGParserCtxtPtr ctxt)
   1209 {
   1210     tokenPtr token, tok2;
   1211 
   1212     token = xmlParseCRNGGetToken(ctxt, 1);
   1213     if (token->toktype == CRNG_KEYWORD) {
   1214         if ((token->token == ctxt->key_start) ||
   1215 	    (token->token == ctxt->key_include) ||
   1216 	    (token->token == ctxt->key_div)) {
   1217 	    xmlNodePtr grammar;
   1218 
   1219 	    grammar = xmlNewNodeEatName(NULL, (xmlChar *) ctxt->key_grammar);
   1220 	    if (grammar == NULL) CRNG_MEM_ERROR0();
   1221 	    xmlDocSetRootElement(ctxt->doc, grammar);
   1222 	    ctxt->insert = grammar;
   1223 
   1224 	    xmlParseCRNG_grammar(ctxt);
   1225 	} else {
   1226 	    xmlParseCRNG_pattern(ctxt);
   1227 	}
   1228     } else {
   1229         tok2 = xmlParseCRNGGetToken(ctxt, 2);
   1230 	if ((tok2->toktype == CRNG_OP) &&
   1231 	    ((tok2->token == ctxt->key_equal) ||
   1232 	     (tok2->token == ctxt->key_orequal) ||
   1233 	     (tok2->token == ctxt->key_andequal))) {
   1234 	    xmlNodePtr grammar;
   1235 
   1236 	    grammar = xmlNewNodeEatName(NULL, (xmlChar *) ctxt->key_grammar);
   1237 	    if (grammar == NULL) CRNG_MEM_ERROR0();
   1238 	    xmlDocSetRootElement(ctxt->doc, grammar);
   1239 	    ctxt->insert = grammar;
   1240 
   1241 	    xmlParseCRNG_grammar(ctxt);
   1242 	} else {
   1243 	    xmlParseCRNG_pattern(ctxt);
   1244 	}
   1245     }
   1246     return(0);
   1247 }
   1248 
   1249 /**
   1250  * xmlParseCRNG_namespacePrefix:
   1251  * @ctxt: a compact RNG parser context
   1252  *
   1253  * Parse namespacePrefix of the RELAX NG Compact Syntax Appendix A
   1254  *
   1255  * Returns the prefix or NULL in case of error
   1256  */
   1257 static const xmlChar *
   1258 xmlParseCRNG_namespacePrefix(xmlCRelaxNGParserCtxtPtr ctxt)
   1259 {
   1260     tokenPtr token;
   1261     const xmlChar *prefix = NULL;
   1262 
   1263     token = xmlParseCRNGGetToken(ctxt, 1);
   1264     if (token->toktype == CRNG_IDENTIFIER) {
   1265         prefix = token->token;
   1266     } else if (token->toktype == CRNG_OP) {
   1267 	if ((token->token[0] == '=') && (token->token[1] == 0))
   1268 	    return(NULL);
   1269         prefix = token->token;
   1270     } else {
   1271 	ERROR("Expecting a namespace prefix");
   1272 	return(NULL);
   1273     }
   1274     xmlParseCRNGDropTokens(ctxt, 1);
   1275 
   1276     if (xmlStrEqual(prefix, BAD_CAST "xmlns")) {
   1277 	ERROR("Namespace prefix \"xmlns\" is forbidden");
   1278     }
   1279     return(prefix);
   1280 }
   1281 
   1282 /**
   1283  * xmlParseCRNG_decl:
   1284  * @ctxt: a compact RNG parser context
   1285  *
   1286  * Parse decl of the RELAX NG Compact Syntax Appendix A
   1287  *
   1288  * Returns 0 in case of success and -1 in case of error
   1289  */
   1290 static int
   1291 xmlParseCRNG_decl(xmlCRelaxNGParserCtxtPtr ctxt)
   1292 {
   1293     const xmlChar *prefix = NULL;
   1294     const xmlChar *namespace = NULL;
   1295     tokenPtr token;
   1296 
   1297     token = xmlParseCRNGGetToken(ctxt, 1);
   1298     if (token->toktype != CRNG_KEYWORD) return(-1);
   1299     if (token->token == ctxt->key_default) {
   1300         xmlParseCRNGDropTokens(ctxt, 1);
   1301         token = xmlParseCRNGGetToken(ctxt, 1);
   1302         if ((token->toktype != CRNG_KEYWORD) ||
   1303 	    (token->token != ctxt->key_namespace)) {
   1304 	    ERROR("Expecting keyword \"namespace\" after \"default\"");
   1305 	}
   1306         xmlParseCRNGDropTokens(ctxt, 1);
   1307 	prefix = xmlParseCRNG_namespacePrefix(ctxt);
   1308         token = xmlParseCRNGGetToken(ctxt, 1);
   1309         if ((token->toktype != CRNG_OP) ||
   1310 	    (token->token[0] != '=') || (token->token[1] != 0)) {
   1311 	    ERROR("Expecting keyword \"=\" here");
   1312 	}
   1313         xmlParseCRNGDropTokens(ctxt, 1);
   1314         token = xmlParseCRNGGetToken(ctxt, 1);
   1315         if ((token->toktype == CRNG_KEYWORD) &&
   1316 	    (token->token == ctxt->key_inherit)) {
   1317 	    namespace = xmlCRelaxNGInherit;
   1318 	} else if (token->toktype == CRNG_LITERAL_SEGMENT) {
   1319 	    namespace = token->token;
   1320 	} else {
   1321 	    ERROR("Expecting an URI or \"inherit\" value");
   1322 	}
   1323         xmlParseCRNGDropTokens(ctxt, 1);
   1324         if (namespace != NULL) {
   1325 	    if (prefix != NULL)
   1326 		xmlParseCRNG_bindPrefix(ctxt, prefix, namespace);
   1327             xmlParseCRNG_bindPrefix(ctxt, NULL, namespace);
   1328 	}
   1329     } else if (token->token == ctxt->key_namespace) {
   1330         xmlParseCRNGDropTokens(ctxt, 1);
   1331 	prefix = xmlParseCRNG_namespacePrefix(ctxt);
   1332         token = xmlParseCRNGGetToken(ctxt, 1);
   1333         if ((token->toktype != CRNG_OP) ||
   1334 	    (token->token[0] != '=') || (token->token[1] != 0)) {
   1335 	    ERROR("Expecting keyword \"=\" here");
   1336 	}
   1337         xmlParseCRNGDropTokens(ctxt, 1);
   1338         token = xmlParseCRNGGetToken(ctxt, 1);
   1339         if ((token->toktype == CRNG_KEYWORD) &&
   1340 	    (token->token == ctxt->key_inherit)) {
   1341 	    namespace = xmlCRelaxNGInherit;
   1342 	} else if (token->toktype == CRNG_LITERAL_SEGMENT) {
   1343 	    namespace = token->token;
   1344 	} else {
   1345 	    ERROR("Expecting an URI or \"inherit\" value");
   1346 	}
   1347         xmlParseCRNGDropTokens(ctxt, 1);
   1348         if (namespace != NULL)
   1349 	    xmlParseCRNG_bindPrefix(ctxt, prefix, namespace);
   1350     } else if (token->token == ctxt->key_datatypes) {
   1351         xmlParseCRNGDropTokens(ctxt, 1);
   1352 
   1353         token = xmlParseCRNGGetToken(ctxt, 1);
   1354 	if ((token->toktype != CRNG_KEYWORD) &&
   1355 	    (token->toktype != CRNG_IDENTIFIER)) {
   1356 	    ERROR("Expecting a datatype prefix identifier here");
   1357 	} else
   1358 	    prefix = token->token;
   1359         xmlParseCRNGDropTokens(ctxt, 1);
   1360         token = xmlParseCRNGGetToken(ctxt, 1);
   1361         if ((token->toktype != CRNG_OP) ||
   1362 	    (token->token[0] != '=') || (token->token[1] != 0)) {
   1363 	    ERROR("Expecting keyword \"=\" here");
   1364 	}
   1365         xmlParseCRNGDropTokens(ctxt, 1);
   1366         token = xmlParseCRNGGetToken(ctxt, 1);
   1367 	if (token->toktype == CRNG_LITERAL_SEGMENT) {
   1368 	    namespace = token->token;
   1369 	} else {
   1370 	    ERROR("Expecting a literal value for the datatype identifier");
   1371 	}
   1372         xmlParseCRNGDropTokens(ctxt, 1);
   1373         if ((namespace != NULL) && (prefix != NULL))
   1374 	    xmlParseCRNG_bindDatatypePrefix(ctxt, prefix, namespace);
   1375     }
   1376 
   1377     return(0);
   1378 }
   1379 
   1380 /**
   1381  * xmlParseCRNG_preamble:
   1382  * @ctxt: a compact RNG parser context
   1383  *
   1384  * Parse preamble of the RELAX NG Compact Syntax Appendix A
   1385  *
   1386  * Returns 0 in case of success and -1 in case of error
   1387  */
   1388 static int
   1389 xmlParseCRNG_preamble(xmlCRelaxNGParserCtxtPtr ctxt)
   1390 {
   1391     tokenPtr token;
   1392 
   1393     token = xmlParseCRNGGetToken(ctxt, 1);
   1394     while (token != NULL) {
   1395 	if (token == NULL) return(-1);
   1396 	if ((token->toktype == CRNG_KEYWORD) &&
   1397 	    ((token->token == ctxt->key_default) ||
   1398 	     (token->token == ctxt->key_namespace) ||
   1399 	     (token->token == ctxt->key_datatypes))) {
   1400 	    xmlParseCRNG_decl(ctxt);
   1401 	} else
   1402 	    break;
   1403 	token = xmlParseCRNGGetToken(ctxt, 1);
   1404     }
   1405     return(0);
   1406 }
   1407 
   1408 /**
   1409  * xmlParseCRNG_topLevel:
   1410  * @ctxt: a compact RNG parser context
   1411  *
   1412  * Parse topLevel of the RELAX NG Compact Syntax Appendix A
   1413  *
   1414  * Returns 0 in case of success and -1 in case of error
   1415  */
   1416 static int
   1417 xmlParseCRNG_topLevel(xmlCRelaxNGParserCtxtPtr ctxt)
   1418 {
   1419     xmlParseCRNG_preamble(ctxt);
   1420     xmlParseCRNG_topLevelBody(ctxt);
   1421     return(0);
   1422 }
   1423 
   1424 /**
   1425  * xmlConvertCRNG:
   1426  * @schemas:  pointer to the text of the compact schemas
   1427  * @len:  length of the schemas in bytes (or 0)
   1428  * @encoding:  encoding indicated by the context or NULL
   1429  *
   1430  * Compiles the schemas into the equivalent Relax-NG XML structure
   1431  *
   1432  * Returns the xmlDocPtr resulting from the compilation or
   1433  *         NULL in case of error
   1434  */
   1435 xmlDocPtr
   1436 xmlConvertCRNG(const char *schemas, int len, const char *encoding) {
   1437     struct _xmlCRelaxNGParserCtxt ctxt;
   1438     xmlDocPtr ret = NULL;
   1439 
   1440     if (schemas == NULL) return(NULL);
   1441     if (len <= 5) len = xmlStrlen((const unsigned char *) schemas);
   1442     if (len <= 0) return(NULL);
   1443 
   1444     memset(&ctxt, 0, sizeof(ctxt));
   1445     ctxt.compact = (const unsigned char *) schemas;
   1446     ctxt.cur = (const unsigned char *) schemas;
   1447     ctxt.end = (const unsigned char *) &schemas[len];
   1448     ctxt.dict = xmlDictCreate();
   1449     if (ctxt.dict == NULL)
   1450         return(NULL);
   1451     ctxt.doc = xmlNewDoc(NULL);
   1452     if (ctxt.doc == NULL) {
   1453 	xmlDictFree(ctxt.dict);
   1454 	return(NULL);
   1455     }
   1456     ctxt.doc->dict = ctxt.dict;
   1457     xmlDictReference(ctxt.dict);
   1458 
   1459     ctxt.nbTokens = 0;
   1460     ctxt.firstToken = 0;
   1461     ctxt.key_attribute = xmlDictLookup(ctxt.dict, BAD_CAST "attribute", -1);
   1462     ctxt.key_default = xmlDictLookup(ctxt.dict, BAD_CAST "default", -1);
   1463     ctxt.key_datatypes = xmlDictLookup(ctxt.dict, BAD_CAST "datatypes", -1);
   1464     ctxt.key_div = xmlDictLookup(ctxt.dict, BAD_CAST "div", -1);
   1465     ctxt.key_element = xmlDictLookup(ctxt.dict, BAD_CAST "element", -1);
   1466     ctxt.key_empty = xmlDictLookup(ctxt.dict, BAD_CAST "empty", -1);
   1467     ctxt.key_external = xmlDictLookup(ctxt.dict, BAD_CAST "external", -1);
   1468     ctxt.key_grammar = xmlDictLookup(ctxt.dict, BAD_CAST "grammar", -1);
   1469     ctxt.key_include = xmlDictLookup(ctxt.dict, BAD_CAST "include", -1);
   1470     ctxt.key_inherit = xmlDictLookup(ctxt.dict, BAD_CAST "inherit", -1);
   1471     ctxt.key_list = xmlDictLookup(ctxt.dict, BAD_CAST "list", -1);
   1472     ctxt.key_mixed = xmlDictLookup(ctxt.dict, BAD_CAST "mixed", -1);
   1473     ctxt.key_namespace = xmlDictLookup(ctxt.dict, BAD_CAST "namespace", -1);
   1474     ctxt.key_notAllowed = xmlDictLookup(ctxt.dict, BAD_CAST "notAllowed", -1);
   1475     ctxt.key_parent = xmlDictLookup(ctxt.dict, BAD_CAST "parent", -1);
   1476     ctxt.key_start = xmlDictLookup(ctxt.dict, BAD_CAST "start", -1);
   1477     ctxt.key_string = xmlDictLookup(ctxt.dict, BAD_CAST "string", -1);
   1478     ctxt.key_text = xmlDictLookup(ctxt.dict, BAD_CAST "text", -1);
   1479     ctxt.key_token = xmlDictLookup(ctxt.dict, BAD_CAST "token", -1);
   1480     ctxt.key_equal = xmlDictLookup(ctxt.dict, BAD_CAST "=", 1);
   1481     ctxt.key_orequal = xmlDictLookup(ctxt.dict, BAD_CAST "|=", 2);
   1482     ctxt.key_andequal = xmlDictLookup(ctxt.dict, BAD_CAST "&=", 2);
   1483     ctxt.key_combine = xmlDictLookup(ctxt.dict, BAD_CAST "&=", 2);
   1484     ctxt.key_or = xmlDictLookup(ctxt.dict, BAD_CAST "|", 1);
   1485     ctxt.key_comma = xmlDictLookup(ctxt.dict, BAD_CAST ",", 1);
   1486     ctxt.key_and = xmlDictLookup(ctxt.dict, BAD_CAST "&", 1);
   1487     ctxt.key_choice = xmlDictLookup(ctxt.dict, BAD_CAST "choice", -1);
   1488     ctxt.key_group = xmlDictLookup(ctxt.dict, BAD_CAST "group", -1);
   1489     ctxt.key_interleave = xmlDictLookup(ctxt.dict, BAD_CAST "interleave", -1);
   1490     ctxt.key_ref = xmlDictLookup(ctxt.dict, BAD_CAST "ref", 3);
   1491     ctxt.key_define = xmlDictLookup(ctxt.dict, BAD_CAST "define", 6);
   1492 
   1493     /* xmlConvertCRNGTokenize(&ctxt); */
   1494     xmlConvertCRNG_topLevel(&ctxt);
   1495 
   1496     xmlDictFree(ctxt.dict);
   1497 
   1498     ret = ctxt.doc;
   1499     return(ret);
   1500 }
   1501 
   1502 /**
   1503  * xmlConvertCRNGFile:
   1504  * @URL: URL or filename for the resource
   1505  * @encoding:  encoding indicated by the context or NULL
   1506  *
   1507  * Compiles the schemas into the equivalent Relax-NG XML structure
   1508  *
   1509  * Returns the xmlDocPtr resulting from the compilation or
   1510  *         NULL in case of error
   1511  */
   1512 xmlDocPtr
   1513 xmlConvertCRNGFile(const char *URL, const char *encoding) {
   1514 }
   1515 
   1516 #ifdef STANDALONE
   1517 const xmlChar *schemas =
   1518 "# RELAX NG XML syntax specified in compact syntax.\n\
   1519 \n\
   1520 default namespace rng = \"http://relaxng.org/ns/structure/1.0\"\n\
   1521 namespace local = \"\"\n\
   1522 datatypes xsd = \"http://www.w3.org/2001/XMLSchema-datatypes\"\n\
   1523 \n\
   1524 start = pattern\n\
   1525 \n\
   1526 pattern =\n\
   1527   element element { (nameQName | nameClass), (common & pattern+) }\n\
   1528   | element attribute { (nameQName | nameClass), (common & pattern?) }\n\
   1529   | element group|interleave|choice|optional\n\
   1530             |zeroOrMore|oneOrMore|list|mixed { common & pattern+ }\n\
   1531   | element ref|parentRef { nameNCName, common }\n\
   1532   | element empty|notAllowed|text { common }\n\
   1533   | element data { type, param*, (common & exceptPattern?) }\n\
   1534   | element value { commonAttributes, type?, xsd:string }\n\
   1535   | element externalRef { href, common }\n\
   1536   | element grammar { common & grammarContent* }\n\
   1537 \n\
   1538 param = element param { commonAttributes, nameNCName, xsd:string }\n\
   1539 \n\
   1540 exceptPattern = element except { common & pattern+ }\n\
   1541 \n\
   1542 grammarContent =\n\
   1543   definition\n\
   1544   | element div { common & grammarContent* }\n\
   1545   | element include { href, (common & includeContent*) }\n\
   1546 \n\
   1547 includeContent =\n\
   1548   definition\n\
   1549   | element div { common & includeContent* }\n\
   1550 \n\
   1551 definition =\n\
   1552   element start { combine?, (common & pattern+) }\n\
   1553   | element define { nameNCName, combine?, (common & pattern+) }\n\
   1554 \n\
   1555 combine = attribute combine { \"choice\" | \"interleave\" }\n\
   1556 \n\
   1557 nameClass =\n\
   1558   element name { commonAttributes, xsd:QName }\n\
   1559   | element anyName { common & exceptNameClass? }\n\
   1560   | element nsName { common & exceptNameClass? }\n\
   1561   | element choice { common & nameClass+ }\n\
   1562 \n\
   1563 exceptNameClass = element except { common & nameClass+ }\n\
   1564 \n\
   1565 nameQName = attribute name { xsd:QName }\n\
   1566 nameNCName = attribute name { xsd:NCName }\n\
   1567 href = attribute href { xsd:anyURI }\n\
   1568 type = attribute type { xsd:NCName }\n\
   1569 \n\
   1570 common = commonAttributes, foreignElement*\n\
   1571 \n\
   1572 commonAttributes =\n\
   1573   attribute ns { xsd:string }?,\n\
   1574   attribute datatypeLibrary { xsd:anyURI }?,\n\
   1575   foreignAttribute*\n\
   1576 \n\
   1577 foreignElement = element * - rng:* { (anyAttribute | text | anyElement)* }\n\
   1578 foreignAttribute = attribute * - (rng:*|local:*) { text }\n\
   1579 anyElement = element * { (anyAttribute | text | anyElement)* }\n\
   1580 anyAttribute = attribute * { text }\n\
   1581 ";
   1582 
   1583 int main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) {
   1584     xmlDocPtr res;
   1585 
   1586     res = xmlConvertCRNG(schemas, -1);
   1587     if (res != NULL) {
   1588         xmlDocFormatDump(stdout, res, 1);
   1589 	xmlFreeDoc(res);
   1590     }
   1591     return(0);
   1592 }
   1593 #endif
   1594 #define bottom_rngparser
   1595 #include "elfgcchack.h"
   1596