commiting the compact relax ng parser. It's not completely finished, it's
* rngparser.c: commiting the compact relax ng parser. It's not
completely finished, it's not integrated but I want to save the
current state
Daniel
diff --git a/ChangeLog b/ChangeLog
index fdd84c7..3f7e51f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+Tue Jan 6 00:10:33 CET 2004 Daniel Veillard <daniel@veillard.com>
+
+ * rngparser.c: commiting the compact relax ng parser. It's not
+ completely finished, it's not integrated but I want to save the
+ current state
+
Mon Jan 5 22:22:48 HKT 2004 William Brack <wbrack@mmm.com.hk>
* doc/apibuild.py, doc/APIconstructors.html, doc/libxml2-refs.xml,
diff --git a/rngparser.c b/rngparser.c
new file mode 100644
index 0000000..67a25b7
--- /dev/null
+++ b/rngparser.c
@@ -0,0 +1,1571 @@
+/**
+ * rngparser.c: parser for the Relax-NG compact syntax.
+ *
+ * See Copyright for the status of this software.
+ *
+ * Daniel Veillard <veillard@redhat.com>
+ */
+
+#include <string.h>
+
+#include <libxml/parser.h>
+#include <libxml/parserInternals.h>
+#include <libxml/relaxng.h>
+#include <libxml/dict.h>
+
+#define TODO \
+ xmlGenericError(xmlGenericErrorContext, \
+ "Unimplemented block at %s:%d\n", \
+ __FILE__, __LINE__);
+
+#define MAX_TOKEN 10
+
+typedef enum {
+ CRNG_NONE = 0,
+ CRNG_OP = 1,
+ CRNG_KEYWORD,
+ CRNG_IDENTIFIER,
+ CRNG_LITERAL_SEGMENT,
+ CRNG_CNAME,
+ CRNG_QNAME,
+ CRNG_NSNAME,
+ CRNG_DOCUMENTATION
+} xmlCRNGTokType;
+
+typedef enum {
+ CRNG_OKAY = 0,
+ CRNG_MEMORY_ERROR,
+ CRNG_INVALID_CHAR_ERROR,
+ CRNG_END_ERROR,
+ CRNG_ENCODING_ERROR
+} xmlCRNGError;
+
+typedef enum {
+ XML_CRNG_ERROR = -1,
+ XML_CRNG_OK = 0,
+ XML_CRNG_EOF = 1
+} xmlCRelaxNGParserState;
+
+typedef struct _token _token;
+typedef _token *tokenPtr;
+struct _token {
+ xmlCRNGTokType toktype;
+ int toklen;
+ const xmlChar *token;
+ const xmlChar *prefix;
+};
+
+typedef struct _xmlCRelaxNGParserCtxt xmlCRelaxNGParserCtxt;
+typedef xmlCRelaxNGParserCtxt *xmlCRelaxNGParserCtxtPtr;
+struct _xmlCRelaxNGParserCtxt {
+ void *userData; /* user specific data block */
+ xmlRelaxNGValidityErrorFunc error; /* the callback in case of errors */
+ xmlRelaxNGValidityWarningFunc warning;/* the callback in case of warning */
+ xmlRelaxNGValidErr err;
+
+ const xmlChar *compact;
+ const xmlChar *end;
+ const xmlChar *cur;
+ int isElem;
+ int lineno;
+ const xmlChar *linestart;
+ const char *filename;
+
+ int nbTokens;
+ int firstToken;
+ _token tokens[MAX_TOKEN];
+ int totalToken;
+
+ xmlCRelaxNGParserState state;
+
+ int nbErrors;
+
+ xmlDocPtr res; /* the result */
+ xmlNodePtr ins; /* the current insertion node */
+
+ xmlNsPtr nsDef;
+ tokenPtr token;
+
+ xmlHashTablePtr namespaces;
+ xmlHashTablePtr datatypes;
+
+ /*
+ * dictionnary and keywords
+ */
+ xmlDictPtr dict;
+ const xmlChar *key_attribute;
+ const xmlChar *key_default;
+ const xmlChar *key_datatypes;
+ const xmlChar *key_div;
+ const xmlChar *key_element;
+ const xmlChar *key_empty;
+ const xmlChar *key_external;
+ const xmlChar *key_grammar;
+ const xmlChar *key_include;
+ const xmlChar *key_inherit;
+ const xmlChar *key_list;
+ const xmlChar *key_mixed;
+ const xmlChar *key_namespace;
+ const xmlChar *key_notAllowed;
+ const xmlChar *key_parent;
+ const xmlChar *key_start;
+ const xmlChar *key_string;
+ const xmlChar *key_text;
+ const xmlChar *key_token;
+ const xmlChar *key_equal;
+ const xmlChar *key_orequal;
+ const xmlChar *key_andequal;
+ const xmlChar *key_combine;
+ const xmlChar *key_or;
+ const xmlChar *key_comma;
+ const xmlChar *key_and;
+ const xmlChar *key_choice;
+ const xmlChar *key_group;
+ const xmlChar *key_interleave;
+ const xmlChar *key_ref;
+ const xmlChar *key_define;
+
+ /* results */
+ xmlDocPtr doc; /* the resulting doc */
+ xmlNodePtr insert; /* the insertion point */
+ xmlAttrPtr attrs; /* pending attributes */
+};
+
+static const xmlChar *xmlCRelaxNGInherit = BAD_CAST "Inherit string";
+static const xmlChar *xmlCRelaxNGDefault = BAD_CAST "Default string";
+
+#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
+/**
+ * IS_BLANK:
+ * @c: an UNICODE value (int)
+ *
+ * Macro to check the following production in the XML spec:
+ *
+ * [3] S ::= (#x20 | #x9 | #xD | #xA)+
+ */
+#ifndef IS_BLANK
+#define IS_BLANK(c) (((c) == 0x20) || ((c) == 0x09) || ((c) == 0xA) || \
+ ((c) == 0x0D))
+#endif
+#define IS_SEPARATOR(c) (((c) == 0x20) || ((c) == 0x09) || ((c) == 0xA) || \
+ ((c) == 0x0D) || (c == '#'))
+
+#define CRNG_ERROR0(X) \
+ { xmlCRNGErr(ctxt, X, NULL); return(0); }
+#define CRNG_ERROR(X) \
+ { xmlCRNGErr(ctxt, X, NULL); }
+
+#define CRNG_MEM_ERROR0() \
+ { xmlCRNGErr(ctxt, CRNG_MEMORY_ERROR, NULL); return(0); }
+#define CRNG_MEM_ERROR() \
+ { xmlCRNGErr(ctxt, CRNG_MEMORY_ERROR, NULL); }
+
+#define ERROR(str) xmlCRNGErr(ctxt, 0, str);
+
+static void
+xmlCRNGErr(xmlCRelaxNGParserCtxtPtr ctxt, int err_no, const char *err_msg) {
+ const xmlChar *cur;
+ xmlChar buffer[150];
+ int i, l;
+
+ if (ctxt != NULL) {
+ if (ctxt->filename != NULL)
+ fprintf(stderr, "%s:%d ", ctxt->filename, ctxt->lineno);
+ }
+ if (err_msg != NULL) {
+ fprintf(stderr, "error: %s\n", err_msg);
+ } else if (err_no != 0)
+ fprintf(stderr, "error %d\n", err_no);
+ cur = ctxt->cur;
+ while ((*cur != '\n') && (*cur != '\r') && (ctxt->cur - cur < 80)) cur--;
+ l = ctxt->cur - cur;
+ cur++;
+ for (i = 0; i < 100;i++) {
+ if ((*cur == '\n') || (*cur == '\r')) break;
+ buffer[i] = *cur++;
+ }
+ buffer[i] = 0;
+ fprintf(stderr, "%s\n", buffer);
+ for (i = 0; i < l;i++) buffer[i] = ' ';
+ buffer[i++] = '^';
+ buffer[i++] = 0;
+ fprintf(stderr, "%s\n", buffer);
+}
+
+/**
+ * IS_OP
+ * @c: an UNICODE value (int)
+ *
+ * Macro to check for operator value
+ */
+#ifndef IS_OP
+#define IS_OP(c) (((c) == ',') || ((c) == '&') || ((c) == '|') || \
+ ((c) == '?') || ((c) == '-') || ((c) == '*') || \
+ ((c) == '{') || ((c) == '}') || ((c) == '(') || \
+ ((c) == ')') || ((c) == '+') || ((c) == '=') || \
+ ((c) == ':'))
+#endif
+
+static int
+xmlCRNGIsKeyword(xmlCRelaxNGParserCtxtPtr ctxt, const xmlChar *str) {
+ if ((str == ctxt->key_attribute) ||
+ (str == ctxt->key_default) ||
+ (str == ctxt->key_datatypes) ||
+ (str == ctxt->key_div) ||
+ (str == ctxt->key_element) ||
+ (str == ctxt->key_empty) ||
+ (str == ctxt->key_external) ||
+ (str == ctxt->key_grammar) ||
+ (str == ctxt->key_include) ||
+ (str == ctxt->key_inherit) ||
+ (str == ctxt->key_list) ||
+ (str == ctxt->key_mixed) ||
+ (str == ctxt->key_namespace) ||
+ (str == ctxt->key_notAllowed) ||
+ (str == ctxt->key_parent) ||
+ (str == ctxt->key_start) ||
+ (str == ctxt->key_string) ||
+ (str == ctxt->key_text) ||
+ (str == ctxt->key_token))
+ return(1);
+ return(0);
+
+}
+
+/*
+ * xmlCRNGNextToken:
+ * ctxt: a compact RNG parser context
+ *
+ * Scan the schema to get the next token
+ *
+ * Return 0 if success and -1 in case of error
+ */
+
+static int
+xmlCRNGNextToken(xmlCRelaxNGParserCtxtPtr ctxt) {
+ const xmlChar *cur;
+ tokenPtr token;
+
+ if (ctxt == NULL) return(-1);
+ if (ctxt->nbTokens >= MAX_TOKEN) return(-1);
+ token = &(ctxt->tokens[(ctxt->firstToken + ctxt->nbTokens) % MAX_TOKEN]);
+ token->toktype = CRNG_NONE;
+
+ if (ctxt->cur == NULL) {
+ ctxt->cur = ctxt->compact;
+ }
+retry:
+ if (ctxt->cur >= ctxt->end) {
+ ctxt->state = XML_CRNG_EOF;
+ return(-1);
+ }
+ while ((ctxt->cur < ctxt->end) &&
+ (IS_BLANK(*ctxt->cur))) ctxt->cur++;
+ if (ctxt->cur >= ctxt->end) {
+ ctxt->state = XML_CRNG_EOF;
+ return(-1);
+ }
+ if (*ctxt->cur == '#') {
+ cur = ctxt->cur;
+ cur++;
+ while ((cur < ctxt->end) && (*cur != '\n') && (*cur != '\r'))
+ cur++;
+ ctxt->cur = cur;
+ goto retry;
+ } else if (*ctxt->cur == '"') {
+ /* string, check for '"""' */
+ ctxt->cur++;
+ if (ctxt->cur >= ctxt->end) goto eof;
+ cur = ctxt->cur;
+ if ((ctxt->end - ctxt->end > 2) &&
+ (*cur == '"') && (cur[1] == '"')) {
+ TODO
+ } else {
+ while ((cur < ctxt->end) && (*cur != '"')) cur++;
+ if (cur >= ctxt->end) goto eof;
+ token->toklen = cur - ctxt->cur;
+ token->token = xmlDictLookup(ctxt->dict, ctxt->cur, token->toklen);
+ token->toktype = CRNG_LITERAL_SEGMENT;
+ token->prefix = NULL;
+ cur++;
+ ctxt->cur = cur;
+ }
+ } else if (*ctxt->cur == '\'') {
+ /* string, check for "'''" */
+ TODO
+ } else if ((IS_OP(*ctxt->cur)) || (*ctxt->cur == ':')) {
+ cur = ctxt->cur;
+ cur++;
+ if ((cur < ctxt->end) &&
+ (((*cur == '=') &&
+ ((*ctxt->cur == '|') || (*ctxt->cur == '&'))) ||
+ ((*cur == '*') && (*ctxt->cur == ':')))) {
+ token->toklen = 2;
+ } else {
+ token->toklen = 1;
+ }
+ token->token = xmlDictLookup(ctxt->dict, ctxt->cur, token->toklen);
+ token->toktype = CRNG_OP;
+ token->prefix = NULL;
+ ctxt->cur += token->toklen;
+ } else {
+ int escape = 0;
+
+ cur = ctxt->cur;
+ if (*cur == '\\') {
+ escape = 1;
+ cur++;
+ ctxt->cur++;
+ }
+ while ((cur < ctxt->end) &&
+ (!(IS_SEPARATOR(*cur))) && (!(IS_OP(*cur)))) cur++;
+
+ token->toklen = cur - ctxt->cur;
+ token->token = xmlDictLookup(ctxt->dict, ctxt->cur, token->toklen);
+ token->prefix = NULL;
+ ctxt->cur = cur;
+ if ((escape == 0) && (xmlCRNGIsKeyword(ctxt, token->token)))
+ token->toktype = CRNG_KEYWORD;
+ else {
+ token->toktype = CRNG_IDENTIFIER;
+ }
+ if (*ctxt->cur == ':') {
+ ctxt->cur++;
+ if (*ctxt->cur == '*') {
+ ctxt->cur++;
+ token->toktype = CRNG_NSNAME;
+ } else {
+ cur = ctxt->cur;
+ while ((cur < ctxt->end) &&
+ (!(IS_SEPARATOR(*cur))) && (!(IS_OP(*cur)))) cur++;
+ token->prefix = token->token;
+ token->toklen = cur - ctxt->cur;
+ token->token = xmlDictLookup(ctxt->dict, ctxt->cur,
+ token->toklen);
+ ctxt->cur = cur;
+ if (xmlValidateNCName(token->token, 0) == 0)
+ token->toktype = CRNG_QNAME;
+ else {
+ TODO /* sounds like an error ! */
+ token->toktype = CRNG_IDENTIFIER;
+ }
+ }
+ }
+ }
+ ctxt->nbTokens++;
+ return(0);
+eof:
+ ctxt->state = XML_CRNG_EOF;
+ CRNG_ERROR(CRNG_END_ERROR);
+ return(-1);
+}
+
+/**
+ * xmlParseCRNGGetToken:
+ * @ctxt: a compact RNG parser context
+ * @no: the number of the token from 1 for the first one
+ * and 2, 3 ... for read-ahead
+ *
+ * Token reading interface
+ *
+ * returns a pointer to the new token, or NULL in case of error or EOF
+ */
+static tokenPtr
+xmlParseCRNGGetToken(xmlCRelaxNGParserCtxtPtr ctxt, int no) {
+ tokenPtr ret;
+ int res;
+
+ if ((no <= 0) || (no >= MAX_TOKEN)) return(NULL);
+ no--;
+ while (ctxt->nbTokens <= no) {
+ res = xmlCRNGNextToken(ctxt);
+ if (res < 0)
+ return(NULL);
+ }
+ ret = &(ctxt->tokens[(ctxt->firstToken + no) % MAX_TOKEN]);
+ return(ret);
+}
+
+/**
+ * xmlParseCRNGDropTokens:
+ * @ctxt: a compact RNG parser context
+ * @nr: the number of token marked as read
+ *
+ * mark a number of token as read and consumed.
+ *
+ * Returns -1 in case of error and 0 otherwise
+ */
+static int
+xmlParseCRNGDropTokens(xmlCRelaxNGParserCtxtPtr ctxt, int nr) {
+ if ((nr <= 0) || (nr >= MAX_TOKEN)) return(-1);
+ while ((ctxt->nbTokens >0) && (nr > 0)) {
+ ctxt->firstToken++;
+ nr--;
+ ctxt->nbTokens--;
+ ctxt->totalToken++;
+ if (ctxt->totalToken == 384)
+ fprintf(stderr, "found\n");
+ }
+ ctxt->firstToken = ctxt->firstToken % MAX_TOKEN;
+ return(0);
+}
+
+static void
+xmlParseCRNGTokenize(xmlCRelaxNGParserCtxtPtr ctxt) {
+ tokenPtr token;
+
+ token = xmlParseCRNGGetToken(ctxt, 1);
+ while (token != NULL) {
+ switch (token->toktype) {
+ case CRNG_NONE: printf("none"); break;
+ case CRNG_OP: printf("op"); break;
+ case CRNG_KEYWORD: printf("keyword"); break;
+ case CRNG_IDENTIFIER: printf("identifier"); break;
+ case CRNG_LITERAL_SEGMENT: printf("literal"); break;
+ case CRNG_CNAME: printf("cname"); break;
+ case CRNG_QNAME: printf("qname"); break;
+ case CRNG_NSNAME: printf("nsname"); break;
+ case CRNG_DOCUMENTATION: printf("doc"); break;
+ }
+ printf(":%s\n", token->token);
+ xmlParseCRNGDropTokens(ctxt, 1);
+ token = xmlParseCRNGGetToken(ctxt, 1);
+ }
+}
+
+/**
+ * xmlParseCRNG_attribute:
+ * @ctxt: a compact RNG parser context
+ * @name: the attribute name
+ * @ns: the attribute namespace
+ * @value: the attribute value
+ *
+ * implements attribute of the RELAX NG Compact Syntax Appendix A
+ *
+ * Returns 0 in case of success and -1 in case of error
+ */
+static int
+xmlParseCRNG_attribute(xmlCRelaxNGParserCtxtPtr ctxt,
+ const xmlChar *name,
+ xmlNsPtr ns,
+ const xmlChar *value)
+{
+ xmlAttrPtr attr;
+
+ attr = xmlNewNsPropEatName(NULL, ns, (xmlChar *) name, value);
+ if (attr == NULL) CRNG_MEM_ERROR0();
+ attr->next = ctxt->attrs;
+ if (ctxt->attrs != NULL)
+ ctxt->attrs->prev = attr;
+ ctxt->attrs = attr;
+ return(0);
+}
+
+/**
+ * xmlParseCRNG_bindPrefix:
+ * @ctxt: a compact RNG parser context
+ * @prefix: the namespace prefix or NULL
+ * @namespace: the namespace name
+ *
+ * implements bindPrefix of the RELAX NG Compact Syntax Appendix A
+ *
+ * Returns 0 in case of success and -1 in case of error
+ */
+static int
+xmlParseCRNG_bindPrefix(xmlCRelaxNGParserCtxtPtr ctxt,
+ const xmlChar *prefix,
+ const xmlChar *namespace)
+{
+ int ret;
+
+ if ((prefix != NULL) && (xmlStrEqual(prefix, BAD_CAST "xml")) &&
+ (!xmlStrEqual(namespace, XML_XML_NAMESPACE))) {
+ ERROR("The \"xml\" prefix must be bound to \"http://www.w3.org/XML/1998/namespace\"");
+ return(-1);
+ } else if ((xmlStrEqual(namespace, XML_XML_NAMESPACE)) &&
+ (!xmlStrEqual(prefix, BAD_CAST "xml"))) {
+ ERROR("The \"http://www.w3.org/XML/1998/namespace\" name must be bound to \"xml\" prefix");
+ return(-1);
+ }
+ if (ctxt->namespaces == NULL)
+ ctxt->namespaces = xmlHashCreate(10);
+ if (ctxt->namespaces == NULL) {
+ ERROR("Failed to create namespace hash table");
+ return(-1);
+ }
+ if (prefix == NULL)
+ ret = xmlHashAddEntry(ctxt->namespaces, xmlCRelaxNGDefault,
+ (void *) namespace);
+ else
+ ret = xmlHashAddEntry(ctxt->namespaces, prefix,
+ (void *) namespace);
+ if (ret < 0) {
+ if (prefix == NULL) {
+ ERROR("Redefinition of default namespace");
+ } else {
+ ERROR("Redefinition of namespace");
+ }
+ return(-1);
+ }
+
+ return(0);
+}
+
+/**
+ * xmlParseCRNG_bindDatatypePrefix:
+ * @ctxt: a compact RNG parser context
+ * @prefix: the datatype prefix
+ * @namespace: the datatype identifier
+ *
+ * implements bindDatatypePrefix of the RELAX NG Compact Syntax Appendix A
+ *
+ * Returns 0 in case of success and -1 in case of error
+ */
+static int
+xmlParseCRNG_bindDatatypePrefix(xmlCRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
+ const xmlChar *prefix,
+ const xmlChar *namespace)
+{
+ int ret;
+
+ if ((prefix != NULL) && (xmlStrEqual(prefix, BAD_CAST "xsd")) &&
+ (!xmlStrEqual(namespace,
+ BAD_CAST "http://www.w3.org/2001/XMLSchema-datatypes"))) {
+ ERROR("The \"xsd\" prefix must be bound to \"http://www.w3.org/2001/XMLSchema-datatypes\"");
+ return(-1);
+ }
+ if (ctxt->datatypes == NULL)
+ ctxt->datatypes = xmlHashCreate(10);
+ if (ctxt->datatypes == NULL) {
+ ERROR("Failed to create namespace hash table");
+ return(-1);
+ }
+ ret = xmlHashAddEntry(ctxt->datatypes, prefix,
+ (void *) namespace);
+ if (ret < 0) {
+ ERROR("Redefinition of datatype");
+ return(-1);
+ }
+ return(0);
+}
+
+/**
+ * xmlParseCRNG_lookupPrefix:
+ * @ctxt: a compact RNG parser context
+ * @prefix: the namespace prefix or NULL
+ *
+ * implements lookupPrefix of the RELAX NG Compact Syntax Appendix A
+ *
+ * Returns the prefix in case of success or NULL in case of error
+ */
+static const xmlChar *
+xmlParseCRNG_lookupPrefix(xmlCRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
+ const xmlChar *prefix)
+{
+ const xmlChar *ret;
+
+ if (prefix == NULL)
+ ret = xmlHashLookup(ctxt->namespaces, xmlCRelaxNGDefault);
+ else
+ ret = xmlHashLookup(ctxt->namespaces, prefix);
+ return(ret);
+}
+
+/**
+ * xmlParseCRNG_lookupDatatypePrefix:
+ * @ctxt: a compact RNG parser context
+ * @prefix: the namespace prefix or NULL
+ *
+ * implements lookupDatatypePrefix of the RELAX NG Compact Syntax Appendix A
+ *
+ * Returns the prefix in case of success or NULL in case of error
+ */
+static const xmlChar *
+xmlParseCRNG_lookupDatatypePrefix(xmlCRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
+ const xmlChar *prefix)
+{
+ const xmlChar *ret;
+ ret = xmlHashLookup(ctxt->datatypes, prefix);
+ return(ret);
+}
+
+/**
+ * xmlParseCRNG_datatypeAttributes:
+ * @ctxt: a compact RNG parser context
+ * @prefix: the namespace prefix or NULL
+ *
+ * implements lookupPrefix of the RELAX NG Compact Syntax Appendix A
+ *
+ * Returns the prefix in case of success or NULL in case of error
+ */
+static xmlAttrPtr
+xmlParseCRNG_datatypeAttributes(xmlCRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
+ const xmlChar *library, const xmlChar *type)
+{
+ xmlAttrPtr lib, typ;
+
+ lib = xmlNewNsProp(NULL, NULL, BAD_CAST "datatypeLibrary", library);
+ if (lib == NULL) {
+ CRNG_MEM_ERROR();
+ return(NULL);
+ }
+ typ = xmlNewNsProp(NULL, NULL, BAD_CAST "type", type);
+ if (typ == NULL) {
+ CRNG_MEM_ERROR();
+ return(lib);
+ }
+ lib->next = typ;
+
+ return(lib);
+}
+
+/**
+ * xmlParseCRNG_XXX:
+ * @ctxt: a compact RNG parser context
+ *
+ * Parse XXX of the RELAX NG Compact Syntax Appendix A
+ *
+ * Returns 0 in case of success and -1 in case of error
+ */
+static int
+xmlParseCRNG_XXX(xmlCRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED)
+{
+ return(0);
+}
+
+static int xmlParseCRNG_pattern(xmlCRelaxNGParserCtxtPtr ctxt);
+static int xmlParseCRNG_nameClass(xmlCRelaxNGParserCtxtPtr ctxt);
+
+/**
+ * xmlParseCRNG_params:
+ * @ctxt: a compact RNG parser context
+ *
+ * Parse params of the RELAX NG Compact Syntax Appendix A
+ *
+ * Returns 0 in case of success and -1 in case of error
+ */
+static int
+xmlParseCRNG_params(xmlCRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED)
+{
+ TODO
+ return(0);
+}
+
+/**
+ * xmlParseCRNG_exceptNameClass:
+ * @ctxt: a compact RNG parser context
+ *
+ * Parse exceptNameClass of the RELAX NG Compact Syntax Appendix A
+ *
+ * Returns 0 in case of success and -1 in case of error
+ */
+static int
+xmlParseCRNG_exceptNameClass(xmlCRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED)
+{
+ tokenPtr token;
+ xmlNodePtr insert = ctxt->insert, cur;
+
+ token = xmlParseCRNGGetToken(ctxt, 1);
+ if ((token->toktype == CRNG_OP) &&
+ (token->token[0] == '-') && (token->token[1] == 0)) {
+ xmlParseCRNGDropTokens(ctxt, 1);
+ cur = xmlNewNode(NULL, BAD_CAST "except");
+ if (cur == NULL) CRNG_MEM_ERROR0();
+ if (ctxt->insert != NULL)
+ xmlAddChild(ctxt->insert, cur);
+ ctxt->insert = cur;
+ xmlParseCRNG_nameClass(ctxt);
+ }
+ ctxt->insert = insert;
+ return(0);
+}
+
+/**
+ * xmlParseCRNG_innerNameClass:
+ * @ctxt: a compact RNG parser context
+ *
+ * Parse innerNameClass of the RELAX NG Compact Syntax Appendix A
+ *
+ * Returns 0 in case of success and -1 in case of error
+ */
+static int
+xmlParseCRNG_innerNameClass(xmlCRelaxNGParserCtxtPtr ctxt)
+{
+ tokenPtr token;
+ xmlNodePtr cur;
+
+ token = xmlParseCRNGGetToken(ctxt, 1);
+ if (token->toktype == CRNG_OP) {
+ if ((token->token[0] == '(') && (token->token[1] == 0)) {
+ xmlParseCRNGDropTokens(ctxt, 1);
+ xmlParseCRNG_nameClass(ctxt);
+ token = xmlParseCRNGGetToken(ctxt, 1);
+ if ((token->toktype != CRNG_OP) ||
+ (token->token[0] != ')') || (token->token[1] != 0)) {
+ ERROR("Expecting \")\" here");
+ }
+ xmlParseCRNGDropTokens(ctxt, 1);
+ } else if ((token->token[0] == '*') && (token->token[1] == 0)) {
+ xmlParseCRNGDropTokens(ctxt, 1);
+ cur = xmlNewNode(NULL, BAD_CAST "anyName");
+ if (cur == NULL) CRNG_MEM_ERROR0();
+ if (ctxt->insert != NULL)
+ xmlAddChild(ctxt->insert, cur);
+ ctxt->insert = cur;
+ xmlParseCRNG_exceptNameClass(ctxt);
+ } else {
+ TODO
+ }
+ } else if ((token->toktype == CRNG_IDENTIFIER) ||
+ (token->toktype == CRNG_KEYWORD)) {
+ cur = xmlNewNode(NULL, BAD_CAST "name");
+ if (cur == NULL) CRNG_MEM_ERROR0();
+ if (ctxt->isElem) {
+ xmlSetProp(cur, BAD_CAST "ns",
+ xmlParseCRNG_lookupPrefix(ctxt, NULL));
+ } else {
+ xmlSetProp(cur, BAD_CAST "ns", BAD_CAST "");
+ }
+ xmlNodeAddContent(cur, token->token);
+ if (ctxt->insert != NULL)
+ xmlAddChild(ctxt->insert, cur);
+ ctxt->insert = cur;
+ xmlParseCRNGDropTokens(ctxt, 1);
+ } else if (token->toktype == CRNG_CNAME) {
+ TODO
+ } else if (token->toktype == CRNG_NSNAME) {
+ cur = xmlNewNode(NULL, BAD_CAST "nsName");
+ if (cur == NULL) CRNG_MEM_ERROR0();
+ xmlSetProp(cur, BAD_CAST "ns",
+ xmlParseCRNG_lookupPrefix(ctxt, token->token));
+ if (ctxt->insert != NULL)
+ xmlAddChild(ctxt->insert, cur);
+ ctxt->insert = cur;
+ xmlParseCRNGDropTokens(ctxt, 1);
+ xmlParseCRNG_exceptNameClass(ctxt);
+ } else {
+ TODO /* probably an error */
+ }
+
+ return(0);
+}
+
+/**
+ * xmlParseCRNG_nameClass:
+ * @ctxt: a compact RNG parser context
+ *
+ * Parse nameClass of the RELAX NG Compact Syntax Appendix A
+ *
+ * Returns 0 in case of success and -1 in case of error
+ */
+static int
+xmlParseCRNG_nameClass(xmlCRelaxNGParserCtxtPtr ctxt)
+{
+ tokenPtr token;
+ xmlNodePtr insert = ctxt->insert, last, choice;
+
+ ctxt->insert = NULL;
+ xmlParseCRNG_innerNameClass(ctxt);
+ last = ctxt->insert;
+ token = xmlParseCRNGGetToken(ctxt, 1);
+ while ((token->toktype == CRNG_OP) &&
+ (token->token[0] == '|') && (token->token[1] == 0)) {
+ choice = xmlNewNodeEatName(NULL, (xmlChar *) ctxt->key_choice);
+ xmlParseCRNGDropTokens(ctxt, 1);
+ if (choice == NULL) CRNG_MEM_ERROR0();
+ ctxt->insert = NULL;
+ xmlParseCRNG_innerNameClass(ctxt);
+ xmlAddChild(choice, last);
+ xmlAddChild(choice, ctxt->insert);
+ last = choice;
+ token = xmlParseCRNGGetToken(ctxt, 1);
+ }
+ xmlAddChild(insert, last);
+
+ ctxt->insert = insert;
+ return(0);
+}
+
+/**
+ * xmlParseCRNG_patternBlock:
+ * @ctxt: a compact RNG parser context
+ *
+ * Parse a pattern block of the RELAX NG Compact Syntax Appendix A
+ *
+ * Returns 0 in case of success and -1 in case of error
+ */
+static int
+xmlParseCRNG_patternBlock(xmlCRelaxNGParserCtxtPtr ctxt)
+{
+ tokenPtr token;
+
+ token = xmlParseCRNGGetToken(ctxt, 1);
+ if ((token->toktype != CRNG_OP) ||
+ (token->token[0] != '{') || (token->token[1] != 0)) {
+ ERROR("Expecting \"{\" here");
+ }
+ xmlParseCRNGDropTokens(ctxt, 1);
+ xmlParseCRNG_pattern(ctxt);
+ token = xmlParseCRNGGetToken(ctxt, 1);
+ if ((token->toktype != CRNG_OP) ||
+ (token->token[0] != '}') || (token->token[1] != 0)) {
+ ERROR("Expecting \"}\" here");
+ }
+ xmlParseCRNGDropTokens(ctxt, 1);
+ return(0);
+}
+
+/**
+ * xmlParseCRNG_datatype:
+ * @ctxt: a compact RNG parser context
+ *
+ * Parse datatype of the RELAX NG Compact Syntax Appendix A
+ *
+ * Returns 0 in case of success and -1 in case of error
+ */
+static int
+xmlParseCRNG_datatype(xmlCRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED)
+{
+ tokenPtr token;
+ xmlAttrPtr attrs = NULL;
+
+ token = xmlParseCRNGGetToken(ctxt, 1);
+ if (token->toktype == CRNG_KEYWORD) {
+ if (token->token == ctxt->key_string) {
+ attrs = xmlParseCRNG_datatypeAttributes(ctxt, BAD_CAST "",
+ token->token);
+ xmlParseCRNGDropTokens(ctxt, 1);
+ } else if (token->token == ctxt->key_token) {
+ attrs = xmlParseCRNG_datatypeAttributes(ctxt, BAD_CAST "",
+ token->token);
+ xmlParseCRNGDropTokens(ctxt, 1);
+ } else {
+ TODO /* probably an error */
+ }
+ } else if (token->toktype == CRNG_LITERAL_SEGMENT) {
+ ctxt->insert = xmlNewNode(NULL, BAD_CAST "value");
+ xmlParseCRNGDropTokens(ctxt, 1);
+ if (ctxt->insert == NULL) CRNG_MEM_ERROR0();
+ xmlNodeAddContent(ctxt->insert, token->token);
+ } else if (token->toktype == CRNG_QNAME) {
+ attrs = xmlParseCRNG_datatypeAttributes(ctxt,
+ xmlParseCRNG_lookupDatatypePrefix(ctxt, token->prefix),
+ token->token);
+ } else {
+ TODO
+ }
+ if (attrs != NULL) {
+ token = xmlParseCRNGGetToken(ctxt, 1);
+ if (token->toktype == CRNG_LITERAL_SEGMENT) {
+ ctxt->insert = xmlNewNode(NULL, BAD_CAST "value");
+ xmlParseCRNGDropTokens(ctxt, 1);
+ if (ctxt->insert == NULL) {
+ xmlFreePropList(attrs);
+ CRNG_MEM_ERROR0();
+ }
+ ctxt->insert->properties = attrs;
+ xmlNodeAddContent(ctxt->insert, token->token);
+ } else if ((token->toktype == CRNG_OP) &&
+ (token->token[0] == '{') && (token->token[0] == 0)) {
+ ctxt->insert = xmlNewNode(NULL, BAD_CAST "data");
+ xmlParseCRNGDropTokens(ctxt, 1);
+ if (ctxt->insert == NULL) {
+ xmlFreePropList(attrs);
+ CRNG_MEM_ERROR0();
+ }
+ ctxt->insert->properties = attrs;
+ xmlParseCRNG_params(ctxt);
+ } else {
+ ctxt->insert = xmlNewNode(NULL, BAD_CAST "data");
+ xmlParseCRNGDropTokens(ctxt, 1);
+ if (ctxt->insert == NULL) {
+ xmlFreePropList(attrs);
+ CRNG_MEM_ERROR0();
+ }
+ ctxt->insert->properties = attrs;
+ xmlNodeAddContent(ctxt->insert, token->token);
+ }
+ }
+ return(0);
+}
+
+/**
+ * xmlParseCRNG_primary:
+ * @ctxt: a compact RNG parser context
+ *
+ * Parse primary of the RELAX NG Compact Syntax Appendix A
+ *
+ * Returns 0 in case of success and -1 in case of error
+ */
+static int
+xmlParseCRNG_primary(xmlCRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED)
+{
+ tokenPtr token;
+
+ token = xmlParseCRNGGetToken(ctxt, 1);
+ if (token == NULL)
+ return(0);
+ if (token->toktype == CRNG_KEYWORD) {
+ if (token->token == ctxt->key_element) {
+ ctxt->insert = xmlNewNodeEatName(NULL, (xmlChar *) token->token);
+ xmlParseCRNGDropTokens(ctxt, 1);
+ if (ctxt->insert == NULL) CRNG_MEM_ERROR0();
+ ctxt->isElem = 1;
+ xmlParseCRNG_nameClass(ctxt);
+ xmlParseCRNG_patternBlock(ctxt);
+ } else if (token->token == ctxt->key_attribute) {
+ ctxt->insert = xmlNewNodeEatName(NULL, (xmlChar *) token->token);
+ xmlParseCRNGDropTokens(ctxt, 1);
+ if (ctxt->insert == NULL) CRNG_MEM_ERROR0();
+ ctxt->isElem = 0;
+ xmlParseCRNG_nameClass(ctxt);
+ xmlParseCRNG_patternBlock(ctxt);
+ } else if (token->token == ctxt->key_mixed) {
+ ctxt->insert = xmlNewNodeEatName(NULL, (xmlChar *) token->token);
+ xmlParseCRNGDropTokens(ctxt, 1);
+ if (ctxt->insert == NULL) CRNG_MEM_ERROR0();
+ xmlParseCRNG_patternBlock(ctxt);
+ } else if (token->token == ctxt->key_list) {
+ ctxt->insert = xmlNewNodeEatName(NULL, (xmlChar *) token->token);
+ xmlParseCRNGDropTokens(ctxt, 1);
+ if (ctxt->insert == NULL) CRNG_MEM_ERROR0();
+ xmlParseCRNG_patternBlock(ctxt);
+ } else if (token->token == ctxt->key_empty) {
+ ctxt->insert = xmlNewNodeEatName(NULL, (xmlChar *) token->token);
+ xmlParseCRNGDropTokens(ctxt, 1);
+ if (ctxt->insert == NULL) CRNG_MEM_ERROR0();
+ } else if (token->token == ctxt->key_notAllowed) {
+ ctxt->insert = xmlNewNodeEatName(NULL, (xmlChar *) token->token);
+ xmlParseCRNGDropTokens(ctxt, 1);
+ if (ctxt->insert == NULL) CRNG_MEM_ERROR0();
+ } else if (token->token == ctxt->key_text) {
+ ctxt->insert = xmlNewNodeEatName(NULL, (xmlChar *) token->token);
+ xmlParseCRNGDropTokens(ctxt, 1);
+ if (ctxt->insert == NULL) CRNG_MEM_ERROR0();
+ } else if (token->token == ctxt->key_parent) {
+ ctxt->insert = xmlNewNodeEatName(NULL, (xmlChar *) token->token);
+ xmlParseCRNGDropTokens(ctxt, 1);
+ if (ctxt->insert == NULL) CRNG_MEM_ERROR0();
+ TODO
+ } else if (token->token == ctxt->key_grammar) {
+ ctxt->insert = xmlNewNodeEatName(NULL, (xmlChar *) token->token);
+ xmlParseCRNGDropTokens(ctxt, 1);
+ if (ctxt->insert == NULL) CRNG_MEM_ERROR0();
+ TODO
+ } else if (token->token == ctxt->key_external) {
+ ctxt->insert = xmlNewNode(NULL, BAD_CAST "externalRef");
+ xmlParseCRNGDropTokens(ctxt, 1);
+ if (ctxt->insert == NULL) CRNG_MEM_ERROR0();
+ TODO
+ } else {
+ TODO
+ }
+ } else if (token->toktype == CRNG_IDENTIFIER) {
+ ctxt->insert = xmlNewNodeEatName(NULL, (xmlChar *) ctxt->key_ref);
+ if (ctxt->insert == NULL) CRNG_MEM_ERROR0();
+ xmlSetProp(ctxt->insert, BAD_CAST "name", token->token);
+ xmlParseCRNGDropTokens(ctxt, 1);
+ } else if (token->toktype == CRNG_QNAME) {
+ xmlParseCRNG_datatype(ctxt);
+ } else if (token->toktype == CRNG_LITERAL_SEGMENT) {
+ xmlParseCRNG_datatype(ctxt);
+ } else if ((token->toktype == CRNG_OP) &&
+ (token->token[0] == '(') && (token->token[1] == 0)) {
+ xmlParseCRNGDropTokens(ctxt, 1);
+ xmlParseCRNG_pattern(ctxt);
+ token = xmlParseCRNGGetToken(ctxt, 1);
+ if ((token->toktype != CRNG_OP) ||
+ (token->token[0] != ')') || (token->token[1] != 0)) {
+ ERROR("Expecting \")\" here");
+ }
+ xmlParseCRNGDropTokens(ctxt, 1);
+ }
+ return(0);
+}
+
+/**
+ * xmlParseCRNG_particle:
+ * @ctxt: a compact RNG parser context
+ *
+ * Parse particle of the RELAX NG Compact Syntax Appendix A
+ *
+ * Returns 0 in case of success and -1 in case of error
+ */
+static int
+xmlParseCRNG_particle(xmlCRelaxNGParserCtxtPtr ctxt)
+{
+ tokenPtr token;
+ xmlNodePtr insert = ctxt->insert, res, tmp = NULL;
+
+ ctxt->insert = NULL;
+ xmlParseCRNG_primary(ctxt);
+ res = ctxt->insert;
+ token = xmlParseCRNGGetToken(ctxt, 1);
+ if ((token != NULL) && (token->toktype == CRNG_OP)) {
+ if ((token->token[0] == '*') && (token->token[1] == 0)) {
+ tmp = xmlNewNode(NULL, BAD_CAST "zeroOrMore");
+ if (tmp == NULL) CRNG_MEM_ERROR0();
+ } else if ((token->token[0] == '+') && (token->token[1] == 0)) {
+ tmp = xmlNewNode(NULL, BAD_CAST "oneOrMore");
+ if (tmp == NULL) CRNG_MEM_ERROR0();
+ } else if ((token->token[0] == '?') && (token->token[1] == 0)) {
+ tmp = xmlNewNode(NULL, BAD_CAST "optional");
+ if (tmp == NULL) CRNG_MEM_ERROR0();
+ }
+ if (tmp != NULL) {
+ xmlAddChild(tmp, res);
+ res = tmp;
+ xmlParseCRNGDropTokens(ctxt, 1);
+ }
+ }
+ if (insert != NULL) {
+ xmlAddChild(insert, res);
+ ctxt->insert = insert;
+ } else
+ ctxt->insert = res;
+ return(0);
+}
+
+/**
+ * xmlParseCRNG_pattern:
+ * @ctxt: a compact RNG parser context
+ *
+ * Parse pattern of the RELAX NG Compact Syntax Appendix A
+ *
+ * Returns 0 in case of success and -1 in case of error
+ */
+static int
+xmlParseCRNG_pattern(xmlCRelaxNGParserCtxtPtr ctxt)
+{
+ tokenPtr token;
+ xmlNodePtr insert = ctxt->insert, prev, grp;
+
+ ctxt->insert = NULL;
+ xmlParseCRNG_particle(ctxt);
+ prev = ctxt->insert;
+ token = xmlParseCRNGGetToken(ctxt, 1);
+ while ((prev != NULL) && (token != NULL) && (token->toktype == CRNG_OP)) {
+ if (token->token == ctxt->key_or) {
+ grp = xmlNewNodeEatName(NULL, (xmlChar *) ctxt->key_choice);
+ if (grp == NULL) CRNG_MEM_ERROR0();
+ } else if (token->token == ctxt->key_and) {
+ grp = xmlNewNodeEatName(NULL, (xmlChar *) ctxt->key_interleave);
+ if (grp == NULL) CRNG_MEM_ERROR0();
+ } else if (token->token == ctxt->key_comma) {
+ grp = xmlNewNodeEatName(NULL, (xmlChar *) ctxt->key_group);
+ if (grp == NULL) CRNG_MEM_ERROR0();
+ } else
+ break;
+ xmlParseCRNGDropTokens(ctxt, 1);
+ ctxt->insert = NULL;
+ xmlParseCRNG_particle(ctxt);
+ xmlAddChild(grp, prev);
+ xmlAddChild(grp, ctxt->insert);
+ prev = grp;
+ token = xmlParseCRNGGetToken(ctxt, 1);
+ }
+ if (insert != NULL) {
+ xmlAddChild(insert, prev);
+ ctxt->insert = insert;
+ } else {
+ ctxt->insert = prev;
+ }
+
+ return(0);
+}
+
+/**
+ * xmlParseCRNG_component:
+ * @ctxt: a compact RNG parser context
+ *
+ * Parse component of the RELAX NG Compact Syntax Appendix A
+ *
+ * Returns 0 in case of success and -1 in case of error
+ */
+static int
+xmlParseCRNG_component(xmlCRelaxNGParserCtxtPtr ctxt)
+{
+ tokenPtr token, tok2;
+ xmlNodePtr insert = ctxt->insert;
+
+ token = xmlParseCRNGGetToken(ctxt, 1);
+ if (token == NULL)
+ return(0);
+ if (token->toktype == CRNG_KEYWORD) {
+ if (token->token == ctxt->key_start) {
+ xmlNodePtr start;
+
+ start = xmlNewNodeEatName(NULL, (xmlChar *) ctxt->key_start);
+ if (start == NULL) CRNG_MEM_ERROR0();
+ if (ctxt->insert != NULL)
+ xmlAddChild(ctxt->insert, start);
+ ctxt->insert = start;
+ xmlParseCRNGDropTokens(ctxt, 1);
+ token = xmlParseCRNGGetToken(ctxt, 1);
+
+ if ((token->toktype == CRNG_OP) &&
+ (token->token == ctxt->key_equal)) {
+ } else if ((token->toktype == CRNG_OP) &&
+ (token->token == ctxt->key_orequal)) {
+ xmlParseCRNG_attribute(ctxt, ctxt->key_combine, NULL,
+ BAD_CAST "choice");
+ } else if ((token->toktype == CRNG_OP) &&
+ (token->token == ctxt->key_andequal)) {
+ xmlParseCRNG_attribute(ctxt, ctxt->key_combine, NULL,
+ BAD_CAST "interleave");
+ } else {
+ ERROR("expecting \"=\" or \"&=\" or \"|=\" here")
+ return(-1);
+ }
+ start->properties = ctxt->attrs;
+ ctxt->attrs = NULL;
+ xmlParseCRNGDropTokens(ctxt, 1);
+ xmlParseCRNG_pattern(ctxt);
+
+ } else if (token->token == ctxt->key_include) {
+ TODO
+ } else if (token->token == ctxt->key_div) {
+ TODO
+ } else {
+ return(-1);
+ }
+ } else if (token->toktype == CRNG_IDENTIFIER) {
+ xmlNodePtr define;
+ const xmlChar *identifier;
+
+ identifier = token->token;
+ tok2 = xmlParseCRNGGetToken(ctxt, 2);
+ if ((tok2->toktype == CRNG_OP) &&
+ (tok2->token == ctxt->key_equal)) {
+ } else if ((tok2->toktype == CRNG_OP) &&
+ (tok2->token == ctxt->key_orequal)) {
+ xmlParseCRNG_attribute(ctxt, ctxt->key_combine, NULL,
+ BAD_CAST "choice");
+ } else if ((tok2->toktype == CRNG_OP) &&
+ (tok2->token == ctxt->key_andequal)) {
+ xmlParseCRNG_attribute(ctxt, ctxt->key_combine, NULL,
+ BAD_CAST "interleave");
+ } else {
+ ERROR("expecting \"=\" or \"&=\" or \"|=\" here")
+ return(-1);
+ }
+ xmlParseCRNGDropTokens(ctxt, 2);
+
+ define = xmlNewNodeEatName(NULL, (xmlChar *) ctxt->key_define);
+ if (define == NULL) CRNG_MEM_ERROR0();
+ define->properties = ctxt->attrs;
+ ctxt->attrs = NULL;
+ xmlSetProp(define, BAD_CAST "name", identifier);
+ if (ctxt->insert != NULL)
+ xmlAddChild(ctxt->insert, define);
+ ctxt->insert = define;
+ xmlParseCRNG_pattern(ctxt);
+ } else {
+ return(-1);
+ }
+ ctxt->insert = insert;
+ return(0);
+}
+
+/**
+ * xmlParseCRNG_grammar:
+ * @ctxt: a compact RNG parser context
+ *
+ * Parse grammar of the RELAX NG Compact Syntax Appendix A
+ *
+ * Returns 0 in case of success and -1 in case of error
+ */
+static int
+xmlParseCRNG_grammar(xmlCRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED)
+{
+ tokenPtr token;
+ int ret;
+
+ token = xmlParseCRNGGetToken(ctxt, 1);
+ while (token != NULL) {
+ ret = xmlParseCRNG_component(ctxt);
+ if (ret != 0)
+ break;
+ token = xmlParseCRNGGetToken(ctxt, 1);
+ }
+ return(0);
+}
+
+/**
+ * xmlParseCRNG_topLevelBody:
+ * @ctxt: a compact RNG parser context
+ *
+ * Parse topLevelBody of the RELAX NG Compact Syntax Appendix A
+ *
+ * Returns 0 in case of success and -1 in case of error
+ */
+static int
+xmlParseCRNG_topLevelBody(xmlCRelaxNGParserCtxtPtr ctxt)
+{
+ tokenPtr token, tok2;
+
+ token = xmlParseCRNGGetToken(ctxt, 1);
+ if (token->toktype == CRNG_KEYWORD) {
+ if ((token->token == ctxt->key_start) ||
+ (token->token == ctxt->key_include) ||
+ (token->token == ctxt->key_div)) {
+ xmlNodePtr grammar;
+
+ grammar = xmlNewNodeEatName(NULL, (xmlChar *) ctxt->key_grammar);
+ if (grammar == NULL) CRNG_MEM_ERROR0();
+ xmlDocSetRootElement(ctxt->doc, grammar);
+ ctxt->insert = grammar;
+
+ xmlParseCRNG_grammar(ctxt);
+ } else {
+ xmlParseCRNG_pattern(ctxt);
+ }
+ } else {
+ tok2 = xmlParseCRNGGetToken(ctxt, 2);
+ if ((tok2->toktype == CRNG_OP) &&
+ ((tok2->token == ctxt->key_equal) ||
+ (tok2->token == ctxt->key_orequal) ||
+ (tok2->token == ctxt->key_andequal))) {
+ xmlNodePtr grammar;
+
+ grammar = xmlNewNodeEatName(NULL, (xmlChar *) ctxt->key_grammar);
+ if (grammar == NULL) CRNG_MEM_ERROR0();
+ xmlDocSetRootElement(ctxt->doc, grammar);
+ ctxt->insert = grammar;
+
+ xmlParseCRNG_grammar(ctxt);
+ } else {
+ xmlParseCRNG_pattern(ctxt);
+ }
+ }
+ return(0);
+}
+
+/**
+ * xmlParseCRNG_namespacePrefix:
+ * @ctxt: a compact RNG parser context
+ *
+ * Parse namespacePrefix of the RELAX NG Compact Syntax Appendix A
+ *
+ * Returns the prefix or NULL in case of error
+ */
+static const xmlChar *
+xmlParseCRNG_namespacePrefix(xmlCRelaxNGParserCtxtPtr ctxt)
+{
+ tokenPtr token;
+ const xmlChar *prefix = NULL;
+
+ token = xmlParseCRNGGetToken(ctxt, 1);
+ if (token->toktype == CRNG_IDENTIFIER) {
+ prefix = token->token;
+ } else if (token->toktype == CRNG_OP) {
+ if ((token->token[0] == '=') && (token->token[1] == 0))
+ return(NULL);
+ prefix = token->token;
+ } else {
+ ERROR("Expecting a namespace prefix");
+ return(NULL);
+ }
+ xmlParseCRNGDropTokens(ctxt, 1);
+
+ if (xmlStrEqual(prefix, BAD_CAST "xmlns")) {
+ ERROR("Namespace prefix \"xmlns\" is forbidden");
+ }
+ return(prefix);
+}
+
+/**
+ * xmlParseCRNG_decl:
+ * @ctxt: a compact RNG parser context
+ *
+ * Parse decl of the RELAX NG Compact Syntax Appendix A
+ *
+ * Returns 0 in case of success and -1 in case of error
+ */
+static int
+xmlParseCRNG_decl(xmlCRelaxNGParserCtxtPtr ctxt)
+{
+ const xmlChar *prefix = NULL;
+ const xmlChar *namespace = NULL;
+ tokenPtr token;
+
+ token = xmlParseCRNGGetToken(ctxt, 1);
+ if (token->toktype != CRNG_KEYWORD) return(-1);
+ if (token->token == ctxt->key_default) {
+ xmlParseCRNGDropTokens(ctxt, 1);
+ token = xmlParseCRNGGetToken(ctxt, 1);
+ if ((token->toktype != CRNG_KEYWORD) ||
+ (token->token != ctxt->key_namespace)) {
+ ERROR("Expecting keyword \"namespace\" after \"default\"");
+ }
+ xmlParseCRNGDropTokens(ctxt, 1);
+ prefix = xmlParseCRNG_namespacePrefix(ctxt);
+ token = xmlParseCRNGGetToken(ctxt, 1);
+ if ((token->toktype != CRNG_OP) ||
+ (token->token[0] != '=') || (token->token[1] != 0)) {
+ ERROR("Expecting keyword \"=\" here");
+ }
+ xmlParseCRNGDropTokens(ctxt, 1);
+ token = xmlParseCRNGGetToken(ctxt, 1);
+ if ((token->toktype == CRNG_KEYWORD) &&
+ (token->token == ctxt->key_inherit)) {
+ namespace = xmlCRelaxNGInherit;
+ } else if (token->toktype == CRNG_LITERAL_SEGMENT) {
+ namespace = token->token;
+ } else {
+ ERROR("Expecting an URI or \"inherit\" value");
+ }
+ xmlParseCRNGDropTokens(ctxt, 1);
+ if (namespace != NULL) {
+ if (prefix != NULL)
+ xmlParseCRNG_bindPrefix(ctxt, prefix, namespace);
+ xmlParseCRNG_bindPrefix(ctxt, NULL, namespace);
+ }
+ } else if (token->token == ctxt->key_namespace) {
+ xmlParseCRNGDropTokens(ctxt, 1);
+ prefix = xmlParseCRNG_namespacePrefix(ctxt);
+ token = xmlParseCRNGGetToken(ctxt, 1);
+ if ((token->toktype != CRNG_OP) ||
+ (token->token[0] != '=') || (token->token[1] != 0)) {
+ ERROR("Expecting keyword \"=\" here");
+ }
+ xmlParseCRNGDropTokens(ctxt, 1);
+ token = xmlParseCRNGGetToken(ctxt, 1);
+ if ((token->toktype == CRNG_KEYWORD) &&
+ (token->token == ctxt->key_inherit)) {
+ namespace = xmlCRelaxNGInherit;
+ } else if (token->toktype == CRNG_LITERAL_SEGMENT) {
+ namespace = token->token;
+ } else {
+ ERROR("Expecting an URI or \"inherit\" value");
+ }
+ xmlParseCRNGDropTokens(ctxt, 1);
+ if (namespace != NULL)
+ xmlParseCRNG_bindPrefix(ctxt, prefix, namespace);
+ } else if (token->token == ctxt->key_datatypes) {
+ xmlParseCRNGDropTokens(ctxt, 1);
+
+ token = xmlParseCRNGGetToken(ctxt, 1);
+ if ((token->toktype != CRNG_KEYWORD) &&
+ (token->toktype != CRNG_IDENTIFIER)) {
+ ERROR("Expecting a datatype prefix identifier here");
+ } else
+ prefix = token->token;
+ xmlParseCRNGDropTokens(ctxt, 1);
+ token = xmlParseCRNGGetToken(ctxt, 1);
+ if ((token->toktype != CRNG_OP) ||
+ (token->token[0] != '=') || (token->token[1] != 0)) {
+ ERROR("Expecting keyword \"=\" here");
+ }
+ xmlParseCRNGDropTokens(ctxt, 1);
+ token = xmlParseCRNGGetToken(ctxt, 1);
+ if (token->toktype == CRNG_LITERAL_SEGMENT) {
+ namespace = token->token;
+ } else {
+ ERROR("Expecting a literal value for the datatype identifier");
+ }
+ xmlParseCRNGDropTokens(ctxt, 1);
+ if ((namespace != NULL) && (prefix != NULL))
+ xmlParseCRNG_bindDatatypePrefix(ctxt, prefix, namespace);
+ }
+
+ return(0);
+}
+
+/**
+ * xmlParseCRNG_preamble:
+ * @ctxt: a compact RNG parser context
+ *
+ * Parse preamble of the RELAX NG Compact Syntax Appendix A
+ *
+ * Returns 0 in case of success and -1 in case of error
+ */
+static int
+xmlParseCRNG_preamble(xmlCRelaxNGParserCtxtPtr ctxt)
+{
+ tokenPtr token;
+
+ token = xmlParseCRNGGetToken(ctxt, 1);
+ while (token != NULL) {
+ if (token == NULL) return(-1);
+ if ((token->toktype == CRNG_KEYWORD) &&
+ ((token->token == ctxt->key_default) ||
+ (token->token == ctxt->key_namespace) ||
+ (token->token == ctxt->key_datatypes))) {
+ xmlParseCRNG_decl(ctxt);
+ } else
+ break;
+ token = xmlParseCRNGGetToken(ctxt, 1);
+ }
+ return(0);
+}
+
+/**
+ * xmlParseCRNG_topLevel:
+ * @ctxt: a compact RNG parser context
+ *
+ * Parse topLevel of the RELAX NG Compact Syntax Appendix A
+ *
+ * Returns 0 in case of success and -1 in case of error
+ */
+static int
+xmlParseCRNG_topLevel(xmlCRelaxNGParserCtxtPtr ctxt)
+{
+ xmlParseCRNG_preamble(ctxt);
+ xmlParseCRNG_topLevelBody(ctxt);
+ return(0);
+}
+
+/**
+ * xmlParseCRNG:
+ * @schemas: pointer to the text of the compact schemas
+ * @len: length of the schemas in bytes (or 0)
+ *
+ * Compiles the schemas into the equivalent Relax-NG XML structure
+ *
+ * Returns the xmlDocPtr resulting from the compilation or
+ * NULL in case of error
+ */
+static xmlDocPtr
+xmlParseCRNG(const xmlChar *schemas, int len) {
+ struct _xmlCRelaxNGParserCtxt ctxt;
+ xmlDocPtr ret = NULL;
+
+ if (schemas == NULL) return(NULL);
+ if (len <= 5) len = xmlStrlen(schemas);
+ if (len <= 0) return(NULL);
+
+ memset(&ctxt, 0, sizeof(ctxt));
+ ctxt.compact = schemas;
+ ctxt.cur = schemas;
+ ctxt.end = &schemas[len];
+ ctxt.dict = xmlDictCreate();
+ if (ctxt.dict == NULL)
+ return(NULL);
+ ctxt.doc = xmlNewDoc(NULL);
+ if (ctxt.doc == NULL) {
+ xmlDictFree(ctxt.dict);
+ return(NULL);
+ }
+ ctxt.doc->dict = ctxt.dict;
+ xmlDictReference(ctxt.dict);
+
+ ctxt.nbTokens = 0;
+ ctxt.firstToken = 0;
+ ctxt.key_attribute = xmlDictLookup(ctxt.dict, BAD_CAST "attribute", -1);
+ ctxt.key_default = xmlDictLookup(ctxt.dict, BAD_CAST "default", -1);
+ ctxt.key_datatypes = xmlDictLookup(ctxt.dict, BAD_CAST "datatypes", -1);
+ ctxt.key_div = xmlDictLookup(ctxt.dict, BAD_CAST "div", -1);
+ ctxt.key_element = xmlDictLookup(ctxt.dict, BAD_CAST "element", -1);
+ ctxt.key_empty = xmlDictLookup(ctxt.dict, BAD_CAST "empty", -1);
+ ctxt.key_external = xmlDictLookup(ctxt.dict, BAD_CAST "external", -1);
+ ctxt.key_grammar = xmlDictLookup(ctxt.dict, BAD_CAST "grammar", -1);
+ ctxt.key_include = xmlDictLookup(ctxt.dict, BAD_CAST "include", -1);
+ ctxt.key_inherit = xmlDictLookup(ctxt.dict, BAD_CAST "inherit", -1);
+ ctxt.key_list = xmlDictLookup(ctxt.dict, BAD_CAST "list", -1);
+ ctxt.key_mixed = xmlDictLookup(ctxt.dict, BAD_CAST "mixed", -1);
+ ctxt.key_namespace = xmlDictLookup(ctxt.dict, BAD_CAST "namespace", -1);
+ ctxt.key_notAllowed = xmlDictLookup(ctxt.dict, BAD_CAST "notAllowed", -1);
+ ctxt.key_parent = xmlDictLookup(ctxt.dict, BAD_CAST "parent", -1);
+ ctxt.key_start = xmlDictLookup(ctxt.dict, BAD_CAST "start", -1);
+ ctxt.key_string = xmlDictLookup(ctxt.dict, BAD_CAST "string", -1);
+ ctxt.key_text = xmlDictLookup(ctxt.dict, BAD_CAST "text", -1);
+ ctxt.key_token = xmlDictLookup(ctxt.dict, BAD_CAST "token", -1);
+ ctxt.key_equal = xmlDictLookup(ctxt.dict, BAD_CAST "=", 1);
+ ctxt.key_orequal = xmlDictLookup(ctxt.dict, BAD_CAST "|=", 2);
+ ctxt.key_andequal = xmlDictLookup(ctxt.dict, BAD_CAST "&=", 2);
+ ctxt.key_combine = xmlDictLookup(ctxt.dict, BAD_CAST "&=", 2);
+ ctxt.key_or = xmlDictLookup(ctxt.dict, BAD_CAST "|", 1);
+ ctxt.key_comma = xmlDictLookup(ctxt.dict, BAD_CAST ",", 1);
+ ctxt.key_and = xmlDictLookup(ctxt.dict, BAD_CAST "&", 1);
+ ctxt.key_choice = xmlDictLookup(ctxt.dict, BAD_CAST "choice", -1);
+ ctxt.key_group = xmlDictLookup(ctxt.dict, BAD_CAST "group", -1);
+ ctxt.key_interleave = xmlDictLookup(ctxt.dict, BAD_CAST "interleave", -1);
+ ctxt.key_ref = xmlDictLookup(ctxt.dict, BAD_CAST "ref", 3);
+ ctxt.key_define = xmlDictLookup(ctxt.dict, BAD_CAST "define", 6);
+
+ /* xmlParseCRNGTokenize(&ctxt); */
+ xmlParseCRNG_topLevel(&ctxt);
+
+ xmlDictFree(ctxt.dict);
+
+ ret = ctxt.doc;
+ return(ret);
+}
+
+const xmlChar *schemas =
+"# RELAX NG XML syntax specified in compact syntax.\n\
+\n\
+default namespace rng = \"http://relaxng.org/ns/structure/1.0\"\n\
+namespace local = \"\"\n\
+datatypes xsd = \"http://www.w3.org/2001/XMLSchema-datatypes\"\n\
+\n\
+start = pattern\n\
+\n\
+pattern =\n\
+ element element { (nameQName | nameClass), (common & pattern+) }\n\
+ | element attribute { (nameQName | nameClass), (common & pattern?) }\n\
+ | element group|interleave|choice|optional\n\
+ |zeroOrMore|oneOrMore|list|mixed { common & pattern+ }\n\
+ | element ref|parentRef { nameNCName, common }\n\
+ | element empty|notAllowed|text { common }\n\
+ | element data { type, param*, (common & exceptPattern?) }\n\
+ | element value { commonAttributes, type?, xsd:string }\n\
+ | element externalRef { href, common }\n\
+ | element grammar { common & grammarContent* }\n\
+\n\
+param = element param { commonAttributes, nameNCName, xsd:string }\n\
+\n\
+exceptPattern = element except { common & pattern+ }\n\
+\n\
+grammarContent =\n\
+ definition\n\
+ | element div { common & grammarContent* }\n\
+ | element include { href, (common & includeContent*) }\n\
+\n\
+includeContent =\n\
+ definition\n\
+ | element div { common & includeContent* }\n\
+\n\
+definition =\n\
+ element start { combine?, (common & pattern+) }\n\
+ | element define { nameNCName, combine?, (common & pattern+) }\n\
+\n\
+combine = attribute combine { \"choice\" | \"interleave\" }\n\
+\n\
+nameClass =\n\
+ element name { commonAttributes, xsd:QName }\n\
+ | element anyName { common & exceptNameClass? }\n\
+ | element nsName { common & exceptNameClass? }\n\
+ | element choice { common & nameClass+ }\n\
+\n\
+exceptNameClass = element except { common & nameClass+ }\n\
+\n\
+nameQName = attribute name { xsd:QName }\n\
+nameNCName = attribute name { xsd:NCName }\n\
+href = attribute href { xsd:anyURI }\n\
+type = attribute type { xsd:NCName }\n\
+\n\
+common = commonAttributes, foreignElement*\n\
+\n\
+commonAttributes =\n\
+ attribute ns { xsd:string }?,\n\
+ attribute datatypeLibrary { xsd:anyURI }?,\n\
+ foreignAttribute*\n\
+\n\
+foreignElement = element * - rng:* { (anyAttribute | text | anyElement)* }\n\
+foreignAttribute = attribute * - (rng:*|local:*) { text }\n\
+anyElement = element * { (anyAttribute | text | anyElement)* }\n\
+anyAttribute = attribute * { text }\n\
+";
+
+int main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) {
+ xmlDocPtr res;
+
+ res = xmlParseCRNG(schemas, -1);
+ if (res != NULL) {
+ xmlDocFormatDump(stdout, res, 1);
+ xmlFreeDoc(res);
+ }
+ return(0);
+}