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