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@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
28typedef 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
40typedef 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
48typedef enum {
49    XML_CRNG_ERROR = -1,
50    XML_CRNG_OK = 0,
51    XML_CRNG_EOF = 1
52} xmlCRelaxNGParserState;
53
54typedef struct _token _token;
55typedef _token *tokenPtr;
56struct _token {
57    xmlCRNGTokType toktype;
58    int toklen;
59    const xmlChar *token;
60    const xmlChar *prefix;
61};
62
63typedef struct _xmlCRelaxNGParserCtxt xmlCRelaxNGParserCtxt;
64typedef xmlCRelaxNGParserCtxt *xmlCRelaxNGParserCtxtPtr;
65struct _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     * dictionnary 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
139static const xmlChar *xmlCRelaxNGInherit = BAD_CAST "Inherit string";
140static 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
170static void
171xmlCRNGErr(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
214static int
215xmlCRNGIsKeyword(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
249static int
250xmlCRNGNextToken(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    }
262retry:
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);
362eof:
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 */
378static tokenPtr
379xmlParseCRNGGetToken(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 */
403static int
404xmlParseCRNGDropTokens(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
418static void
419xmlParseCRNGTokenize(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 */
452static int
453xmlParseCRNG_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 */
479static int
480xmlParseCRNG_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 */
529static int
530xmlParseCRNG_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 */
566static const xmlChar *
567xmlParseCRNG_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 */
588static const xmlChar *
589xmlParseCRNG_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 */
606static xmlAttrPtr
607xmlParseCRNG_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 */
635static int
636xmlParseCRNG_XXX(xmlCRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED)
637{
638    return(0);
639}
640
641static int xmlParseCRNG_pattern(xmlCRelaxNGParserCtxtPtr ctxt);
642static 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 */
652static int
653xmlParseCRNG_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 */
667static int
668xmlParseCRNG_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 */
696static int
697xmlParseCRNG_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 */
766static int
767xmlParseCRNG_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 */
802static int
803xmlParseCRNG_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 */
831static int
832xmlParseCRNG_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 */
905static int
906xmlParseCRNG_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 */
999static int
1000xmlParseCRNG_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 */
1042static int
1043xmlParseCRNG_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 */
1090static int
1091xmlParseCRNG_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 */
1183static int
1184xmlParseCRNG_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 */
1207static int
1208xmlParseCRNG_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 */
1257static const xmlChar *
1258xmlParseCRNG_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 */
1290static int
1291xmlParseCRNG_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 */
1388static int
1389xmlParseCRNG_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 */
1416static int
1417xmlParseCRNG_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 */
1435xmlDocPtr
1436xmlConvertCRNG(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 */
1512xmlDocPtr
1513xmlConvertCRNGFile(const char *URL, const char *encoding) {
1514}
1515
1516#ifdef STANDALONE
1517const xmlChar *schemas =
1518"# RELAX NG XML syntax specified in compact syntax.\n\
1519\n\
1520default namespace rng = \"http://relaxng.org/ns/structure/1.0\"\n\
1521namespace local = \"\"\n\
1522datatypes xsd = \"http://www.w3.org/2001/XMLSchema-datatypes\"\n\
1523\n\
1524start = pattern\n\
1525\n\
1526pattern =\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\
1538param = element param { commonAttributes, nameNCName, xsd:string }\n\
1539\n\
1540exceptPattern = element except { common & pattern+ }\n\
1541\n\
1542grammarContent =\n\
1543  definition\n\
1544  | element div { common & grammarContent* }\n\
1545  | element include { href, (common & includeContent*) }\n\
1546\n\
1547includeContent =\n\
1548  definition\n\
1549  | element div { common & includeContent* }\n\
1550\n\
1551definition =\n\
1552  element start { combine?, (common & pattern+) }\n\
1553  | element define { nameNCName, combine?, (common & pattern+) }\n\
1554\n\
1555combine = attribute combine { \"choice\" | \"interleave\" }\n\
1556\n\
1557nameClass =\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\
1563exceptNameClass = element except { common & nameClass+ }\n\
1564\n\
1565nameQName = attribute name { xsd:QName }\n\
1566nameNCName = attribute name { xsd:NCName }\n\
1567href = attribute href { xsd:anyURI }\n\
1568type = attribute type { xsd:NCName }\n\
1569\n\
1570common = commonAttributes, foreignElement*\n\
1571\n\
1572commonAttributes =\n\
1573  attribute ns { xsd:string }?,\n\
1574  attribute datatypeLibrary { xsd:anyURI }?,\n\
1575  foreignAttribute*\n\
1576\n\
1577foreignElement = element * - rng:* { (anyAttribute | text | anyElement)* }\n\
1578foreignAttribute = attribute * - (rng:*|local:*) { text }\n\
1579anyElement = element * { (anyAttribute | text | anyElement)* }\n\
1580anyAttribute = attribute * { text }\n\
1581";
1582
1583int 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