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 
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      * 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 
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
xmlCRNGErr(xmlCRelaxNGParserCtxtPtr ctxt,int err_no,const char * err_msg)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
xmlCRNGIsKeyword(xmlCRelaxNGParserCtxtPtr ctxt,const xmlChar * str)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
xmlCRNGNextToken(xmlCRelaxNGParserCtxtPtr ctxt)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
xmlParseCRNGGetToken(xmlCRelaxNGParserCtxtPtr ctxt,int no)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
xmlParseCRNGDropTokens(xmlCRelaxNGParserCtxtPtr ctxt,int nr)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
xmlParseCRNGTokenize(xmlCRelaxNGParserCtxtPtr ctxt)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
xmlParseCRNG_attribute(xmlCRelaxNGParserCtxtPtr ctxt,const xmlChar * name,xmlNsPtr ns,const xmlChar * value)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
xmlParseCRNG_bindPrefix(xmlCRelaxNGParserCtxtPtr ctxt,const xmlChar * prefix,const xmlChar * namespace)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
xmlParseCRNG_bindDatatypePrefix(xmlCRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,const xmlChar * prefix,const xmlChar * namespace)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 *
xmlParseCRNG_lookupPrefix(xmlCRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,const xmlChar * prefix)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 *
xmlParseCRNG_lookupDatatypePrefix(xmlCRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,const xmlChar * prefix)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
xmlParseCRNG_datatypeAttributes(xmlCRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,const xmlChar * library,const xmlChar * type)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
xmlParseCRNG_XXX(xmlCRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED)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
xmlParseCRNG_params(xmlCRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED)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
xmlParseCRNG_exceptNameClass(xmlCRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED)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
xmlParseCRNG_innerNameClass(xmlCRelaxNGParserCtxtPtr ctxt)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
xmlParseCRNG_nameClass(xmlCRelaxNGParserCtxtPtr ctxt)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
xmlParseCRNG_patternBlock(xmlCRelaxNGParserCtxtPtr ctxt)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
xmlParseCRNG_datatype(xmlCRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED)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
xmlParseCRNG_primary(xmlCRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED)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
xmlParseCRNG_particle(xmlCRelaxNGParserCtxtPtr ctxt)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
xmlParseCRNG_pattern(xmlCRelaxNGParserCtxtPtr ctxt)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
xmlParseCRNG_component(xmlCRelaxNGParserCtxtPtr ctxt)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
xmlParseCRNG_grammar(xmlCRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED)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
xmlParseCRNG_topLevelBody(xmlCRelaxNGParserCtxtPtr ctxt)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 *
xmlParseCRNG_namespacePrefix(xmlCRelaxNGParserCtxtPtr ctxt)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
xmlParseCRNG_decl(xmlCRelaxNGParserCtxtPtr ctxt)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
xmlParseCRNG_preamble(xmlCRelaxNGParserCtxtPtr ctxt)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
xmlParseCRNG_topLevel(xmlCRelaxNGParserCtxtPtr ctxt)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
xmlConvertCRNG(const char * schemas,int len,const char * encoding)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
xmlConvertCRNGFile(const char * URL,const char * encoding)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 
main(int argc ATTRIBUTE_UNUSED,char ** argv ATTRIBUTE_UNUSED)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