| /** | |
| * 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" |