/** * 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 */ #include #include #include #include #include #define TODO \ xmlGenericError(xmlGenericErrorContext, \ "Unimplemented block at %s:%d\n", \ __FILE__, __LINE__); #define MAX_TOKEN 10 typedef enum { CRNG_NONE = 0, CRNG_OP = 1, CRNG_KEYWORD, CRNG_IDENTIFIER, CRNG_LITERAL_SEGMENT, CRNG_CNAME, CRNG_QNAME, CRNG_NSNAME, CRNG_DOCUMENTATION } xmlCRNGTokType; typedef enum { CRNG_OKAY = 0, CRNG_MEMORY_ERROR, CRNG_INVALID_CHAR_ERROR, CRNG_END_ERROR, CRNG_ENCODING_ERROR } xmlCRNGError; typedef enum { XML_CRNG_ERROR = -1, XML_CRNG_OK = 0, XML_CRNG_EOF = 1 } xmlCRelaxNGParserState; typedef struct _token _token; typedef _token *tokenPtr; struct _token { xmlCRNGTokType toktype; int toklen; const xmlChar *token; const xmlChar *prefix; }; typedef struct _xmlCRelaxNGParserCtxt xmlCRelaxNGParserCtxt; typedef xmlCRelaxNGParserCtxt *xmlCRelaxNGParserCtxtPtr; struct _xmlCRelaxNGParserCtxt { void *userData; /* user specific data block */ xmlRelaxNGValidityErrorFunc error; /* the callback in case of errors */ xmlRelaxNGValidityWarningFunc warning;/* the callback in case of warning */ xmlRelaxNGValidErr err; const xmlChar *compact; const xmlChar *end; const xmlChar *cur; int isElem; int lineno; const xmlChar *linestart; const char *filename; int nbTokens; int firstToken; _token tokens[MAX_TOKEN]; int totalToken; xmlCRelaxNGParserState state; int nbErrors; xmlDocPtr res; /* the result */ xmlNodePtr ins; /* the current insertion node */ xmlNsPtr nsDef; tokenPtr token; xmlHashTablePtr namespaces; xmlHashTablePtr datatypes; /* * dictionnary and keywords */ xmlDictPtr dict; const xmlChar *key_attribute; const xmlChar *key_default; const xmlChar *key_datatypes; const xmlChar *key_div; const xmlChar *key_element; const xmlChar *key_empty; const xmlChar *key_external; const xmlChar *key_grammar; const xmlChar *key_include; const xmlChar *key_inherit; const xmlChar *key_list; const xmlChar *key_mixed; const xmlChar *key_namespace; const xmlChar *key_notAllowed; const xmlChar *key_parent; const xmlChar *key_start; const xmlChar *key_string; const xmlChar *key_text; const xmlChar *key_token; const xmlChar *key_equal; const xmlChar *key_orequal; const xmlChar *key_andequal; const xmlChar *key_combine; const xmlChar *key_or; const xmlChar *key_comma; const xmlChar *key_and; const xmlChar *key_choice; const xmlChar *key_group; const xmlChar *key_interleave; const xmlChar *key_ref; const xmlChar *key_define; /* results */ xmlDocPtr doc; /* the resulting doc */ xmlNodePtr insert; /* the insertion point */ xmlAttrPtr attrs; /* pending attributes */ }; static const xmlChar *xmlCRelaxNGInherit = BAD_CAST "Inherit string"; static const xmlChar *xmlCRelaxNGDefault = BAD_CAST "Default string"; #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l) /** * IS_BLANK: * @c: an UNICODE value (int) * * Macro to check the following production in the XML spec: * * [3] S ::= (#x20 | #x9 | #xD | #xA)+ */ #ifndef IS_BLANK #define IS_BLANK(c) (((c) == 0x20) || ((c) == 0x09) || ((c) == 0xA) || \ ((c) == 0x0D)) #endif #define IS_SEPARATOR(c) (((c) == 0x20) || ((c) == 0x09) || ((c) == 0xA) || \ ((c) == 0x0D) || (c == '#')) #define CRNG_ERROR0(X) \ { xmlCRNGErr(ctxt, X, NULL); return(0); } #define CRNG_ERROR(X) \ { xmlCRNGErr(ctxt, X, NULL); } #define CRNG_MEM_ERROR0() \ { xmlCRNGErr(ctxt, CRNG_MEMORY_ERROR, NULL); return(0); } #define CRNG_MEM_ERROR() \ { xmlCRNGErr(ctxt, CRNG_MEMORY_ERROR, NULL); } #define ERROR(str) xmlCRNGErr(ctxt, 0, str); static void xmlCRNGErr(xmlCRelaxNGParserCtxtPtr ctxt, int err_no, const char *err_msg) { const xmlChar *cur; xmlChar buffer[150]; int i, l; if (ctxt != NULL) { if (ctxt->filename != NULL) fprintf(stderr, "%s:%d ", ctxt->filename, ctxt->lineno); } if (err_msg != NULL) { fprintf(stderr, "error: %s\n", err_msg); } else if (err_no != 0) fprintf(stderr, "error %d\n", err_no); cur = ctxt->cur; while ((*cur != '\n') && (*cur != '\r') && (ctxt->cur - cur < 80)) cur--; l = ctxt->cur - cur; cur++; for (i = 0; i < 100;i++) { if ((*cur == '\n') || (*cur == '\r')) break; buffer[i] = *cur++; } buffer[i] = 0; fprintf(stderr, "%s\n", buffer); for (i = 0; i < l;i++) buffer[i] = ' '; buffer[i++] = '^'; buffer[i++] = 0; fprintf(stderr, "%s\n", buffer); } /** * IS_OP * @c: an UNICODE value (int) * * Macro to check for operator value */ #ifndef IS_OP #define IS_OP(c) (((c) == ',') || ((c) == '&') || ((c) == '|') || \ ((c) == '?') || ((c) == '-') || ((c) == '*') || \ ((c) == '{') || ((c) == '}') || ((c) == '(') || \ ((c) == ')') || ((c) == '+') || ((c) == '=') || \ ((c) == ':')) #endif static int xmlCRNGIsKeyword(xmlCRelaxNGParserCtxtPtr ctxt, const xmlChar *str) { if ((str == ctxt->key_attribute) || (str == ctxt->key_default) || (str == ctxt->key_datatypes) || (str == ctxt->key_div) || (str == ctxt->key_element) || (str == ctxt->key_empty) || (str == ctxt->key_external) || (str == ctxt->key_grammar) || (str == ctxt->key_include) || (str == ctxt->key_inherit) || (str == ctxt->key_list) || (str == ctxt->key_mixed) || (str == ctxt->key_namespace) || (str == ctxt->key_notAllowed) || (str == ctxt->key_parent) || (str == ctxt->key_start) || (str == ctxt->key_string) || (str == ctxt->key_text) || (str == ctxt->key_token)) return(1); return(0); } /* * xmlCRNGNextToken: * ctxt: a compact RNG parser context * * Scan the schema to get the next token * * Return 0 if success and -1 in case of error */ static int xmlCRNGNextToken(xmlCRelaxNGParserCtxtPtr ctxt) { const xmlChar *cur; tokenPtr token; if (ctxt == NULL) return(-1); if (ctxt->nbTokens >= MAX_TOKEN) return(-1); token = &(ctxt->tokens[(ctxt->firstToken + ctxt->nbTokens) % MAX_TOKEN]); token->toktype = CRNG_NONE; if (ctxt->cur == NULL) { ctxt->cur = ctxt->compact; } retry: if (ctxt->cur >= ctxt->end) { ctxt->state = XML_CRNG_EOF; return(-1); } while ((ctxt->cur < ctxt->end) && (IS_BLANK(*ctxt->cur))) ctxt->cur++; if (ctxt->cur >= ctxt->end) { ctxt->state = XML_CRNG_EOF; return(-1); } if (*ctxt->cur == '#') { cur = ctxt->cur; cur++; while ((cur < ctxt->end) && (*cur != '\n') && (*cur != '\r')) cur++; ctxt->cur = cur; goto retry; } else if (*ctxt->cur == '"') { /* string, check for '"""' */ ctxt->cur++; if (ctxt->cur >= ctxt->end) goto eof; cur = ctxt->cur; if ((ctxt->end - ctxt->end > 2) && (*cur == '"') && (cur[1] == '"')) { TODO } else { while ((cur < ctxt->end) && (*cur != '"')) cur++; if (cur >= ctxt->end) goto eof; token->toklen = cur - ctxt->cur; token->token = xmlDictLookup(ctxt->dict, ctxt->cur, token->toklen); token->toktype = CRNG_LITERAL_SEGMENT; token->prefix = NULL; cur++; ctxt->cur = cur; } } else if (*ctxt->cur == '\'') { /* string, check for "'''" */ TODO } else if ((IS_OP(*ctxt->cur)) || (*ctxt->cur == ':')) { cur = ctxt->cur; cur++; if ((cur < ctxt->end) && (((*cur == '=') && ((*ctxt->cur == '|') || (*ctxt->cur == '&'))) || ((*cur == '*') && (*ctxt->cur == ':')))) { token->toklen = 2; } else { token->toklen = 1; } token->token = xmlDictLookup(ctxt->dict, ctxt->cur, token->toklen); token->toktype = CRNG_OP; token->prefix = NULL; ctxt->cur += token->toklen; } else { int escape = 0; cur = ctxt->cur; if (*cur == '\\') { escape = 1; cur++; ctxt->cur++; } while ((cur < ctxt->end) && (!(IS_SEPARATOR(*cur))) && (!(IS_OP(*cur)))) cur++; token->toklen = cur - ctxt->cur; token->token = xmlDictLookup(ctxt->dict, ctxt->cur, token->toklen); token->prefix = NULL; ctxt->cur = cur; if ((escape == 0) && (xmlCRNGIsKeyword(ctxt, token->token))) token->toktype = CRNG_KEYWORD; else { token->toktype = CRNG_IDENTIFIER; } if (*ctxt->cur == ':') { ctxt->cur++; if (*ctxt->cur == '*') { ctxt->cur++; token->toktype = CRNG_NSNAME; } else { cur = ctxt->cur; while ((cur < ctxt->end) && (!(IS_SEPARATOR(*cur))) && (!(IS_OP(*cur)))) cur++; token->prefix = token->token; token->toklen = cur - ctxt->cur; token->token = xmlDictLookup(ctxt->dict, ctxt->cur, token->toklen); ctxt->cur = cur; if (xmlValidateNCName(token->token, 0) == 0) token->toktype = CRNG_QNAME; else { TODO /* sounds like an error ! */ token->toktype = CRNG_IDENTIFIER; } } } } ctxt->nbTokens++; return(0); eof: ctxt->state = XML_CRNG_EOF; CRNG_ERROR(CRNG_END_ERROR); return(-1); } /** * xmlParseCRNGGetToken: * @ctxt: a compact RNG parser context * @no: the number of the token from 1 for the first one * and 2, 3 ... for read-ahead * * Token reading interface * * returns a pointer to the new token, or NULL in case of error or EOF */ static tokenPtr xmlParseCRNGGetToken(xmlCRelaxNGParserCtxtPtr ctxt, int no) { tokenPtr ret; int res; if ((no <= 0) || (no >= MAX_TOKEN)) return(NULL); no--; while (ctxt->nbTokens <= no) { res = xmlCRNGNextToken(ctxt); if (res < 0) return(NULL); } ret = &(ctxt->tokens[(ctxt->firstToken + no) % MAX_TOKEN]); return(ret); } /** * xmlParseCRNGDropTokens: * @ctxt: a compact RNG parser context * @nr: the number of token marked as read * * mark a number of token as read and consumed. * * Returns -1 in case of error and 0 otherwise */ static int xmlParseCRNGDropTokens(xmlCRelaxNGParserCtxtPtr ctxt, int nr) { if ((nr <= 0) || (nr >= MAX_TOKEN)) return(-1); while ((ctxt->nbTokens >0) && (nr > 0)) { ctxt->firstToken++; nr--; ctxt->nbTokens--; ctxt->totalToken++; if (ctxt->totalToken == 384) fprintf(stderr, "found\n"); } ctxt->firstToken = ctxt->firstToken % MAX_TOKEN; return(0); } static void xmlParseCRNGTokenize(xmlCRelaxNGParserCtxtPtr ctxt) { tokenPtr token; token = xmlParseCRNGGetToken(ctxt, 1); while (token != NULL) { switch (token->toktype) { case CRNG_NONE: printf("none"); break; case CRNG_OP: printf("op"); break; case CRNG_KEYWORD: printf("keyword"); break; case CRNG_IDENTIFIER: printf("identifier"); break; case CRNG_LITERAL_SEGMENT: printf("literal"); break; case CRNG_CNAME: printf("cname"); break; case CRNG_QNAME: printf("qname"); break; case CRNG_NSNAME: printf("nsname"); break; case CRNG_DOCUMENTATION: printf("doc"); break; } printf(":%s\n", token->token); xmlParseCRNGDropTokens(ctxt, 1); token = xmlParseCRNGGetToken(ctxt, 1); } } /** * xmlParseCRNG_attribute: * @ctxt: a compact RNG parser context * @name: the attribute name * @ns: the attribute namespace * @value: the attribute value * * implements attribute of the RELAX NG Compact Syntax Appendix A * * Returns 0 in case of success and -1 in case of error */ static int xmlParseCRNG_attribute(xmlCRelaxNGParserCtxtPtr ctxt, const xmlChar *name, xmlNsPtr ns, const xmlChar *value) { xmlAttrPtr attr; attr = xmlNewNsPropEatName(NULL, ns, (xmlChar *) name, value); if (attr == NULL) CRNG_MEM_ERROR0(); attr->next = ctxt->attrs; if (ctxt->attrs != NULL) ctxt->attrs->prev = attr; ctxt->attrs = attr; return(0); } /** * xmlParseCRNG_bindPrefix: * @ctxt: a compact RNG parser context * @prefix: the namespace prefix or NULL * @namespace: the namespace name * * implements bindPrefix of the RELAX NG Compact Syntax Appendix A * * Returns 0 in case of success and -1 in case of error */ static int xmlParseCRNG_bindPrefix(xmlCRelaxNGParserCtxtPtr ctxt, const xmlChar *prefix, const xmlChar *namespace) { int ret; if ((prefix != NULL) && (xmlStrEqual(prefix, BAD_CAST "xml")) && (!xmlStrEqual(namespace, XML_XML_NAMESPACE))) { ERROR("The \"xml\" prefix must be bound to \"http://www.w3.org/XML/1998/namespace\""); return(-1); } else if ((xmlStrEqual(namespace, XML_XML_NAMESPACE)) && (!xmlStrEqual(prefix, BAD_CAST "xml"))) { ERROR("The \"http://www.w3.org/XML/1998/namespace\" name must be bound to \"xml\" prefix"); return(-1); } if (ctxt->namespaces == NULL) ctxt->namespaces = xmlHashCreate(10); if (ctxt->namespaces == NULL) { ERROR("Failed to create namespace hash table"); return(-1); } if (prefix == NULL) ret = xmlHashAddEntry(ctxt->namespaces, xmlCRelaxNGDefault, (void *) namespace); else ret = xmlHashAddEntry(ctxt->namespaces, prefix, (void *) namespace); if (ret < 0) { if (prefix == NULL) { ERROR("Redefinition of default namespace"); } else { ERROR("Redefinition of namespace"); } return(-1); } return(0); } /** * xmlParseCRNG_bindDatatypePrefix: * @ctxt: a compact RNG parser context * @prefix: the datatype prefix * @namespace: the datatype identifier * * implements bindDatatypePrefix of the RELAX NG Compact Syntax Appendix A * * Returns 0 in case of success and -1 in case of error */ static int xmlParseCRNG_bindDatatypePrefix(xmlCRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED, const xmlChar *prefix, const xmlChar *namespace) { int ret; if ((prefix != NULL) && (xmlStrEqual(prefix, BAD_CAST "xsd")) && (!xmlStrEqual(namespace, BAD_CAST "http://www.w3.org/2001/XMLSchema-datatypes"))) { ERROR("The \"xsd\" prefix must be bound to \"http://www.w3.org/2001/XMLSchema-datatypes\""); return(-1); } if (ctxt->datatypes == NULL) ctxt->datatypes = xmlHashCreate(10); if (ctxt->datatypes == NULL) { ERROR("Failed to create namespace hash table"); return(-1); } ret = xmlHashAddEntry(ctxt->datatypes, prefix, (void *) namespace); if (ret < 0) { ERROR("Redefinition of datatype"); return(-1); } return(0); } /** * xmlParseCRNG_lookupPrefix: * @ctxt: a compact RNG parser context * @prefix: the namespace prefix or NULL * * implements lookupPrefix of the RELAX NG Compact Syntax Appendix A * * Returns the prefix in case of success or NULL in case of error */ static const xmlChar * xmlParseCRNG_lookupPrefix(xmlCRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED, const xmlChar *prefix) { const xmlChar *ret; if (prefix == NULL) ret = xmlHashLookup(ctxt->namespaces, xmlCRelaxNGDefault); else ret = xmlHashLookup(ctxt->namespaces, prefix); return(ret); } /** * xmlParseCRNG_lookupDatatypePrefix: * @ctxt: a compact RNG parser context * @prefix: the namespace prefix or NULL * * implements lookupDatatypePrefix of the RELAX NG Compact Syntax Appendix A * * Returns the prefix in case of success or NULL in case of error */ static const xmlChar * xmlParseCRNG_lookupDatatypePrefix(xmlCRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED, const xmlChar *prefix) { const xmlChar *ret; ret = xmlHashLookup(ctxt->datatypes, prefix); return(ret); } /** * xmlParseCRNG_datatypeAttributes: * @ctxt: a compact RNG parser context * @prefix: the namespace prefix or NULL * * implements lookupPrefix of the RELAX NG Compact Syntax Appendix A * * Returns the prefix in case of success or NULL in case of error */ static xmlAttrPtr xmlParseCRNG_datatypeAttributes(xmlCRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED, const xmlChar *library, const xmlChar *type) { xmlAttrPtr lib, typ; lib = xmlNewNsProp(NULL, NULL, BAD_CAST "datatypeLibrary", library); if (lib == NULL) { CRNG_MEM_ERROR(); return(NULL); } typ = xmlNewNsProp(NULL, NULL, BAD_CAST "type", type); if (typ == NULL) { CRNG_MEM_ERROR(); return(lib); } lib->next = typ; return(lib); } /** * xmlParseCRNG_XXX: * @ctxt: a compact RNG parser context * * Parse XXX of the RELAX NG Compact Syntax Appendix A * * Returns 0 in case of success and -1 in case of error */ static int xmlParseCRNG_XXX(xmlCRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED) { return(0); } static int xmlParseCRNG_pattern(xmlCRelaxNGParserCtxtPtr ctxt); static int xmlParseCRNG_nameClass(xmlCRelaxNGParserCtxtPtr ctxt); /** * xmlParseCRNG_params: * @ctxt: a compact RNG parser context * * Parse params of the RELAX NG Compact Syntax Appendix A * * Returns 0 in case of success and -1 in case of error */ static int xmlParseCRNG_params(xmlCRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED) { TODO return(0); } /** * xmlParseCRNG_exceptNameClass: * @ctxt: a compact RNG parser context * * Parse exceptNameClass of the RELAX NG Compact Syntax Appendix A * * Returns 0 in case of success and -1 in case of error */ static int xmlParseCRNG_exceptNameClass(xmlCRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED) { tokenPtr token; xmlNodePtr insert = ctxt->insert, cur; token = xmlParseCRNGGetToken(ctxt, 1); if ((token->toktype == CRNG_OP) && (token->token[0] == '-') && (token->token[1] == 0)) { xmlParseCRNGDropTokens(ctxt, 1); cur = xmlNewNode(NULL, BAD_CAST "except"); if (cur == NULL) CRNG_MEM_ERROR0(); if (ctxt->insert != NULL) xmlAddChild(ctxt->insert, cur); ctxt->insert = cur; xmlParseCRNG_nameClass(ctxt); } ctxt->insert = insert; return(0); } /** * xmlParseCRNG_innerNameClass: * @ctxt: a compact RNG parser context * * Parse innerNameClass of the RELAX NG Compact Syntax Appendix A * * Returns 0 in case of success and -1 in case of error */ static int xmlParseCRNG_innerNameClass(xmlCRelaxNGParserCtxtPtr ctxt) { tokenPtr token; xmlNodePtr cur; token = xmlParseCRNGGetToken(ctxt, 1); if (token->toktype == CRNG_OP) { if ((token->token[0] == '(') && (token->token[1] == 0)) { xmlParseCRNGDropTokens(ctxt, 1); xmlParseCRNG_nameClass(ctxt); token = xmlParseCRNGGetToken(ctxt, 1); if ((token->toktype != CRNG_OP) || (token->token[0] != ')') || (token->token[1] != 0)) { ERROR("Expecting \")\" here"); } xmlParseCRNGDropTokens(ctxt, 1); } else if ((token->token[0] == '*') && (token->token[1] == 0)) { xmlParseCRNGDropTokens(ctxt, 1); cur = xmlNewNode(NULL, BAD_CAST "anyName"); if (cur == NULL) CRNG_MEM_ERROR0(); if (ctxt->insert != NULL) xmlAddChild(ctxt->insert, cur); ctxt->insert = cur; xmlParseCRNG_exceptNameClass(ctxt); } else { TODO } } else if ((token->toktype == CRNG_IDENTIFIER) || (token->toktype == CRNG_KEYWORD)) { cur = xmlNewNode(NULL, BAD_CAST "name"); if (cur == NULL) CRNG_MEM_ERROR0(); if (ctxt->isElem) { xmlSetProp(cur, BAD_CAST "ns", xmlParseCRNG_lookupPrefix(ctxt, NULL)); } else { xmlSetProp(cur, BAD_CAST "ns", BAD_CAST ""); } xmlNodeAddContent(cur, token->token); if (ctxt->insert != NULL) xmlAddChild(ctxt->insert, cur); ctxt->insert = cur; xmlParseCRNGDropTokens(ctxt, 1); } else if (token->toktype == CRNG_CNAME) { TODO } else if (token->toktype == CRNG_NSNAME) { cur = xmlNewNode(NULL, BAD_CAST "nsName"); if (cur == NULL) CRNG_MEM_ERROR0(); xmlSetProp(cur, BAD_CAST "ns", xmlParseCRNG_lookupPrefix(ctxt, token->token)); if (ctxt->insert != NULL) xmlAddChild(ctxt->insert, cur); ctxt->insert = cur; xmlParseCRNGDropTokens(ctxt, 1); xmlParseCRNG_exceptNameClass(ctxt); } else { TODO /* probably an error */ } return(0); } /** * xmlParseCRNG_nameClass: * @ctxt: a compact RNG parser context * * Parse nameClass of the RELAX NG Compact Syntax Appendix A * * Returns 0 in case of success and -1 in case of error */ static int xmlParseCRNG_nameClass(xmlCRelaxNGParserCtxtPtr ctxt) { tokenPtr token; xmlNodePtr insert = ctxt->insert, last, choice; ctxt->insert = NULL; xmlParseCRNG_innerNameClass(ctxt); last = ctxt->insert; token = xmlParseCRNGGetToken(ctxt, 1); while ((token->toktype == CRNG_OP) && (token->token[0] == '|') && (token->token[1] == 0)) { choice = xmlNewNodeEatName(NULL, (xmlChar *) ctxt->key_choice); xmlParseCRNGDropTokens(ctxt, 1); if (choice == NULL) CRNG_MEM_ERROR0(); ctxt->insert = NULL; xmlParseCRNG_innerNameClass(ctxt); xmlAddChild(choice, last); xmlAddChild(choice, ctxt->insert); last = choice; token = xmlParseCRNGGetToken(ctxt, 1); } xmlAddChild(insert, last); ctxt->insert = insert; return(0); } /** * xmlParseCRNG_patternBlock: * @ctxt: a compact RNG parser context * * Parse a pattern block of the RELAX NG Compact Syntax Appendix A * * Returns 0 in case of success and -1 in case of error */ static int xmlParseCRNG_patternBlock(xmlCRelaxNGParserCtxtPtr ctxt) { tokenPtr token; token = xmlParseCRNGGetToken(ctxt, 1); if ((token->toktype != CRNG_OP) || (token->token[0] != '{') || (token->token[1] != 0)) { ERROR("Expecting \"{\" here"); } xmlParseCRNGDropTokens(ctxt, 1); xmlParseCRNG_pattern(ctxt); token = xmlParseCRNGGetToken(ctxt, 1); if ((token->toktype != CRNG_OP) || (token->token[0] != '}') || (token->token[1] != 0)) { ERROR("Expecting \"}\" here"); } xmlParseCRNGDropTokens(ctxt, 1); return(0); } /** * xmlParseCRNG_datatype: * @ctxt: a compact RNG parser context * * Parse datatype of the RELAX NG Compact Syntax Appendix A * * Returns 0 in case of success and -1 in case of error */ static int xmlParseCRNG_datatype(xmlCRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED) { tokenPtr token; xmlAttrPtr attrs = NULL; token = xmlParseCRNGGetToken(ctxt, 1); if (token->toktype == CRNG_KEYWORD) { if (token->token == ctxt->key_string) { attrs = xmlParseCRNG_datatypeAttributes(ctxt, BAD_CAST "", token->token); xmlParseCRNGDropTokens(ctxt, 1); } else if (token->token == ctxt->key_token) { attrs = xmlParseCRNG_datatypeAttributes(ctxt, BAD_CAST "", token->token); xmlParseCRNGDropTokens(ctxt, 1); } else { TODO /* probably an error */ } } else if (token->toktype == CRNG_LITERAL_SEGMENT) { ctxt->insert = xmlNewNode(NULL, BAD_CAST "value"); xmlParseCRNGDropTokens(ctxt, 1); if (ctxt->insert == NULL) CRNG_MEM_ERROR0(); xmlNodeAddContent(ctxt->insert, token->token); } else if (token->toktype == CRNG_QNAME) { attrs = xmlParseCRNG_datatypeAttributes(ctxt, xmlParseCRNG_lookupDatatypePrefix(ctxt, token->prefix), token->token); } else { TODO } if (attrs != NULL) { token = xmlParseCRNGGetToken(ctxt, 1); if (token->toktype == CRNG_LITERAL_SEGMENT) { ctxt->insert = xmlNewNode(NULL, BAD_CAST "value"); xmlParseCRNGDropTokens(ctxt, 1); if (ctxt->insert == NULL) { xmlFreePropList(attrs); CRNG_MEM_ERROR0(); } ctxt->insert->properties = attrs; xmlNodeAddContent(ctxt->insert, token->token); } else if ((token->toktype == CRNG_OP) && (token->token[0] == '{') && (token->token[0] == 0)) { ctxt->insert = xmlNewNode(NULL, BAD_CAST "data"); xmlParseCRNGDropTokens(ctxt, 1); if (ctxt->insert == NULL) { xmlFreePropList(attrs); CRNG_MEM_ERROR0(); } ctxt->insert->properties = attrs; xmlParseCRNG_params(ctxt); } else { ctxt->insert = xmlNewNode(NULL, BAD_CAST "data"); xmlParseCRNGDropTokens(ctxt, 1); if (ctxt->insert == NULL) { xmlFreePropList(attrs); CRNG_MEM_ERROR0(); } ctxt->insert->properties = attrs; xmlNodeAddContent(ctxt->insert, token->token); } } return(0); } /** * xmlParseCRNG_primary: * @ctxt: a compact RNG parser context * * Parse primary of the RELAX NG Compact Syntax Appendix A * * Returns 0 in case of success and -1 in case of error */ static int xmlParseCRNG_primary(xmlCRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED) { tokenPtr token; token = xmlParseCRNGGetToken(ctxt, 1); if (token == NULL) return(0); if (token->toktype == CRNG_KEYWORD) { if (token->token == ctxt->key_element) { ctxt->insert = xmlNewNodeEatName(NULL, (xmlChar *) token->token); xmlParseCRNGDropTokens(ctxt, 1); if (ctxt->insert == NULL) CRNG_MEM_ERROR0(); ctxt->isElem = 1; xmlParseCRNG_nameClass(ctxt); xmlParseCRNG_patternBlock(ctxt); } else if (token->token == ctxt->key_attribute) { ctxt->insert = xmlNewNodeEatName(NULL, (xmlChar *) token->token); xmlParseCRNGDropTokens(ctxt, 1); if (ctxt->insert == NULL) CRNG_MEM_ERROR0(); ctxt->isElem = 0; xmlParseCRNG_nameClass(ctxt); xmlParseCRNG_patternBlock(ctxt); } else if (token->token == ctxt->key_mixed) { ctxt->insert = xmlNewNodeEatName(NULL, (xmlChar *) token->token); xmlParseCRNGDropTokens(ctxt, 1); if (ctxt->insert == NULL) CRNG_MEM_ERROR0(); xmlParseCRNG_patternBlock(ctxt); } else if (token->token == ctxt->key_list) { ctxt->insert = xmlNewNodeEatName(NULL, (xmlChar *) token->token); xmlParseCRNGDropTokens(ctxt, 1); if (ctxt->insert == NULL) CRNG_MEM_ERROR0(); xmlParseCRNG_patternBlock(ctxt); } else if (token->token == ctxt->key_empty) { ctxt->insert = xmlNewNodeEatName(NULL, (xmlChar *) token->token); xmlParseCRNGDropTokens(ctxt, 1); if (ctxt->insert == NULL) CRNG_MEM_ERROR0(); } else if (token->token == ctxt->key_notAllowed) { ctxt->insert = xmlNewNodeEatName(NULL, (xmlChar *) token->token); xmlParseCRNGDropTokens(ctxt, 1); if (ctxt->insert == NULL) CRNG_MEM_ERROR0(); } else if (token->token == ctxt->key_text) { ctxt->insert = xmlNewNodeEatName(NULL, (xmlChar *) token->token); xmlParseCRNGDropTokens(ctxt, 1); if (ctxt->insert == NULL) CRNG_MEM_ERROR0(); } else if (token->token == ctxt->key_parent) { ctxt->insert = xmlNewNodeEatName(NULL, (xmlChar *) token->token); xmlParseCRNGDropTokens(ctxt, 1); if (ctxt->insert == NULL) CRNG_MEM_ERROR0(); TODO } else if (token->token == ctxt->key_grammar) { ctxt->insert = xmlNewNodeEatName(NULL, (xmlChar *) token->token); xmlParseCRNGDropTokens(ctxt, 1); if (ctxt->insert == NULL) CRNG_MEM_ERROR0(); TODO } else if (token->token == ctxt->key_external) { ctxt->insert = xmlNewNode(NULL, BAD_CAST "externalRef"); xmlParseCRNGDropTokens(ctxt, 1); if (ctxt->insert == NULL) CRNG_MEM_ERROR0(); TODO } else { TODO } } else if (token->toktype == CRNG_IDENTIFIER) { ctxt->insert = xmlNewNodeEatName(NULL, (xmlChar *) ctxt->key_ref); if (ctxt->insert == NULL) CRNG_MEM_ERROR0(); xmlSetProp(ctxt->insert, BAD_CAST "name", token->token); xmlParseCRNGDropTokens(ctxt, 1); } else if (token->toktype == CRNG_QNAME) { xmlParseCRNG_datatype(ctxt); } else if (token->toktype == CRNG_LITERAL_SEGMENT) { xmlParseCRNG_datatype(ctxt); } else if ((token->toktype == CRNG_OP) && (token->token[0] == '(') && (token->token[1] == 0)) { xmlParseCRNGDropTokens(ctxt, 1); xmlParseCRNG_pattern(ctxt); token = xmlParseCRNGGetToken(ctxt, 1); if ((token->toktype != CRNG_OP) || (token->token[0] != ')') || (token->token[1] != 0)) { ERROR("Expecting \")\" here"); } xmlParseCRNGDropTokens(ctxt, 1); } return(0); } /** * xmlParseCRNG_particle: * @ctxt: a compact RNG parser context * * Parse particle of the RELAX NG Compact Syntax Appendix A * * Returns 0 in case of success and -1 in case of error */ static int xmlParseCRNG_particle(xmlCRelaxNGParserCtxtPtr ctxt) { tokenPtr token; xmlNodePtr insert = ctxt->insert, res, tmp = NULL; ctxt->insert = NULL; xmlParseCRNG_primary(ctxt); res = ctxt->insert; token = xmlParseCRNGGetToken(ctxt, 1); if ((token != NULL) && (token->toktype == CRNG_OP)) { if ((token->token[0] == '*') && (token->token[1] == 0)) { tmp = xmlNewNode(NULL, BAD_CAST "zeroOrMore"); if (tmp == NULL) CRNG_MEM_ERROR0(); } else if ((token->token[0] == '+') && (token->token[1] == 0)) { tmp = xmlNewNode(NULL, BAD_CAST "oneOrMore"); if (tmp == NULL) CRNG_MEM_ERROR0(); } else if ((token->token[0] == '?') && (token->token[1] == 0)) { tmp = xmlNewNode(NULL, BAD_CAST "optional"); if (tmp == NULL) CRNG_MEM_ERROR0(); } if (tmp != NULL) { xmlAddChild(tmp, res); res = tmp; xmlParseCRNGDropTokens(ctxt, 1); } } if (insert != NULL) { xmlAddChild(insert, res); ctxt->insert = insert; } else ctxt->insert = res; return(0); } /** * xmlParseCRNG_pattern: * @ctxt: a compact RNG parser context * * Parse pattern of the RELAX NG Compact Syntax Appendix A * * Returns 0 in case of success and -1 in case of error */ static int xmlParseCRNG_pattern(xmlCRelaxNGParserCtxtPtr ctxt) { tokenPtr token; xmlNodePtr insert = ctxt->insert, prev, grp; ctxt->insert = NULL; xmlParseCRNG_particle(ctxt); prev = ctxt->insert; token = xmlParseCRNGGetToken(ctxt, 1); while ((prev != NULL) && (token != NULL) && (token->toktype == CRNG_OP)) { if (token->token == ctxt->key_or) { grp = xmlNewNodeEatName(NULL, (xmlChar *) ctxt->key_choice); if (grp == NULL) CRNG_MEM_ERROR0(); } else if (token->token == ctxt->key_and) { grp = xmlNewNodeEatName(NULL, (xmlChar *) ctxt->key_interleave); if (grp == NULL) CRNG_MEM_ERROR0(); } else if (token->token == ctxt->key_comma) { grp = xmlNewNodeEatName(NULL, (xmlChar *) ctxt->key_group); if (grp == NULL) CRNG_MEM_ERROR0(); } else break; xmlParseCRNGDropTokens(ctxt, 1); ctxt->insert = NULL; xmlParseCRNG_particle(ctxt); xmlAddChild(grp, prev); xmlAddChild(grp, ctxt->insert); prev = grp; token = xmlParseCRNGGetToken(ctxt, 1); } if (insert != NULL) { xmlAddChild(insert, prev); ctxt->insert = insert; } else { ctxt->insert = prev; } return(0); } /** * xmlParseCRNG_component: * @ctxt: a compact RNG parser context * * Parse component of the RELAX NG Compact Syntax Appendix A * * Returns 0 in case of success and -1 in case of error */ static int xmlParseCRNG_component(xmlCRelaxNGParserCtxtPtr ctxt) { tokenPtr token, tok2; xmlNodePtr insert = ctxt->insert; token = xmlParseCRNGGetToken(ctxt, 1); if (token == NULL) return(0); if (token->toktype == CRNG_KEYWORD) { if (token->token == ctxt->key_start) { xmlNodePtr start; start = xmlNewNodeEatName(NULL, (xmlChar *) ctxt->key_start); if (start == NULL) CRNG_MEM_ERROR0(); if (ctxt->insert != NULL) xmlAddChild(ctxt->insert, start); ctxt->insert = start; xmlParseCRNGDropTokens(ctxt, 1); token = xmlParseCRNGGetToken(ctxt, 1); if ((token->toktype == CRNG_OP) && (token->token == ctxt->key_equal)) { } else if ((token->toktype == CRNG_OP) && (token->token == ctxt->key_orequal)) { xmlParseCRNG_attribute(ctxt, ctxt->key_combine, NULL, BAD_CAST "choice"); } else if ((token->toktype == CRNG_OP) && (token->token == ctxt->key_andequal)) { xmlParseCRNG_attribute(ctxt, ctxt->key_combine, NULL, BAD_CAST "interleave"); } else { ERROR("expecting \"=\" or \"&=\" or \"|=\" here") return(-1); } start->properties = ctxt->attrs; ctxt->attrs = NULL; xmlParseCRNGDropTokens(ctxt, 1); xmlParseCRNG_pattern(ctxt); } else if (token->token == ctxt->key_include) { TODO } else if (token->token == ctxt->key_div) { TODO } else { return(-1); } } else if (token->toktype == CRNG_IDENTIFIER) { xmlNodePtr define; const xmlChar *identifier; identifier = token->token; tok2 = xmlParseCRNGGetToken(ctxt, 2); if ((tok2->toktype == CRNG_OP) && (tok2->token == ctxt->key_equal)) { } else if ((tok2->toktype == CRNG_OP) && (tok2->token == ctxt->key_orequal)) { xmlParseCRNG_attribute(ctxt, ctxt->key_combine, NULL, BAD_CAST "choice"); } else if ((tok2->toktype == CRNG_OP) && (tok2->token == ctxt->key_andequal)) { xmlParseCRNG_attribute(ctxt, ctxt->key_combine, NULL, BAD_CAST "interleave"); } else { ERROR("expecting \"=\" or \"&=\" or \"|=\" here") return(-1); } xmlParseCRNGDropTokens(ctxt, 2); define = xmlNewNodeEatName(NULL, (xmlChar *) ctxt->key_define); if (define == NULL) CRNG_MEM_ERROR0(); define->properties = ctxt->attrs; ctxt->attrs = NULL; xmlSetProp(define, BAD_CAST "name", identifier); if (ctxt->insert != NULL) xmlAddChild(ctxt->insert, define); ctxt->insert = define; xmlParseCRNG_pattern(ctxt); } else { return(-1); } ctxt->insert = insert; return(0); } /** * xmlParseCRNG_grammar: * @ctxt: a compact RNG parser context * * Parse grammar of the RELAX NG Compact Syntax Appendix A * * Returns 0 in case of success and -1 in case of error */ static int xmlParseCRNG_grammar(xmlCRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED) { tokenPtr token; int ret; token = xmlParseCRNGGetToken(ctxt, 1); while (token != NULL) { ret = xmlParseCRNG_component(ctxt); if (ret != 0) break; token = xmlParseCRNGGetToken(ctxt, 1); } return(0); } /** * xmlParseCRNG_topLevelBody: * @ctxt: a compact RNG parser context * * Parse topLevelBody of the RELAX NG Compact Syntax Appendix A * * Returns 0 in case of success and -1 in case of error */ static int xmlParseCRNG_topLevelBody(xmlCRelaxNGParserCtxtPtr ctxt) { tokenPtr token, tok2; token = xmlParseCRNGGetToken(ctxt, 1); if (token->toktype == CRNG_KEYWORD) { if ((token->token == ctxt->key_start) || (token->token == ctxt->key_include) || (token->token == ctxt->key_div)) { xmlNodePtr grammar; grammar = xmlNewNodeEatName(NULL, (xmlChar *) ctxt->key_grammar); if (grammar == NULL) CRNG_MEM_ERROR0(); xmlDocSetRootElement(ctxt->doc, grammar); ctxt->insert = grammar; xmlParseCRNG_grammar(ctxt); } else { xmlParseCRNG_pattern(ctxt); } } else { tok2 = xmlParseCRNGGetToken(ctxt, 2); if ((tok2->toktype == CRNG_OP) && ((tok2->token == ctxt->key_equal) || (tok2->token == ctxt->key_orequal) || (tok2->token == ctxt->key_andequal))) { xmlNodePtr grammar; grammar = xmlNewNodeEatName(NULL, (xmlChar *) ctxt->key_grammar); if (grammar == NULL) CRNG_MEM_ERROR0(); xmlDocSetRootElement(ctxt->doc, grammar); ctxt->insert = grammar; xmlParseCRNG_grammar(ctxt); } else { xmlParseCRNG_pattern(ctxt); } } return(0); } /** * xmlParseCRNG_namespacePrefix: * @ctxt: a compact RNG parser context * * Parse namespacePrefix of the RELAX NG Compact Syntax Appendix A * * Returns the prefix or NULL in case of error */ static const xmlChar * xmlParseCRNG_namespacePrefix(xmlCRelaxNGParserCtxtPtr ctxt) { tokenPtr token; const xmlChar *prefix = NULL; token = xmlParseCRNGGetToken(ctxt, 1); if (token->toktype == CRNG_IDENTIFIER) { prefix = token->token; } else if (token->toktype == CRNG_OP) { if ((token->token[0] == '=') && (token->token[1] == 0)) return(NULL); prefix = token->token; } else { ERROR("Expecting a namespace prefix"); return(NULL); } xmlParseCRNGDropTokens(ctxt, 1); if (xmlStrEqual(prefix, BAD_CAST "xmlns")) { ERROR("Namespace prefix \"xmlns\" is forbidden"); } return(prefix); } /** * xmlParseCRNG_decl: * @ctxt: a compact RNG parser context * * Parse decl of the RELAX NG Compact Syntax Appendix A * * Returns 0 in case of success and -1 in case of error */ static int xmlParseCRNG_decl(xmlCRelaxNGParserCtxtPtr ctxt) { const xmlChar *prefix = NULL; const xmlChar *namespace = NULL; tokenPtr token; token = xmlParseCRNGGetToken(ctxt, 1); if (token->toktype != CRNG_KEYWORD) return(-1); if (token->token == ctxt->key_default) { xmlParseCRNGDropTokens(ctxt, 1); token = xmlParseCRNGGetToken(ctxt, 1); if ((token->toktype != CRNG_KEYWORD) || (token->token != ctxt->key_namespace)) { ERROR("Expecting keyword \"namespace\" after \"default\""); } xmlParseCRNGDropTokens(ctxt, 1); prefix = xmlParseCRNG_namespacePrefix(ctxt); token = xmlParseCRNGGetToken(ctxt, 1); if ((token->toktype != CRNG_OP) || (token->token[0] != '=') || (token->token[1] != 0)) { ERROR("Expecting keyword \"=\" here"); } xmlParseCRNGDropTokens(ctxt, 1); token = xmlParseCRNGGetToken(ctxt, 1); if ((token->toktype == CRNG_KEYWORD) && (token->token == ctxt->key_inherit)) { namespace = xmlCRelaxNGInherit; } else if (token->toktype == CRNG_LITERAL_SEGMENT) { namespace = token->token; } else { ERROR("Expecting an URI or \"inherit\" value"); } xmlParseCRNGDropTokens(ctxt, 1); if (namespace != NULL) { if (prefix != NULL) xmlParseCRNG_bindPrefix(ctxt, prefix, namespace); xmlParseCRNG_bindPrefix(ctxt, NULL, namespace); } } else if (token->token == ctxt->key_namespace) { xmlParseCRNGDropTokens(ctxt, 1); prefix = xmlParseCRNG_namespacePrefix(ctxt); token = xmlParseCRNGGetToken(ctxt, 1); if ((token->toktype != CRNG_OP) || (token->token[0] != '=') || (token->token[1] != 0)) { ERROR("Expecting keyword \"=\" here"); } xmlParseCRNGDropTokens(ctxt, 1); token = xmlParseCRNGGetToken(ctxt, 1); if ((token->toktype == CRNG_KEYWORD) && (token->token == ctxt->key_inherit)) { namespace = xmlCRelaxNGInherit; } else if (token->toktype == CRNG_LITERAL_SEGMENT) { namespace = token->token; } else { ERROR("Expecting an URI or \"inherit\" value"); } xmlParseCRNGDropTokens(ctxt, 1); if (namespace != NULL) xmlParseCRNG_bindPrefix(ctxt, prefix, namespace); } else if (token->token == ctxt->key_datatypes) { xmlParseCRNGDropTokens(ctxt, 1); token = xmlParseCRNGGetToken(ctxt, 1); if ((token->toktype != CRNG_KEYWORD) && (token->toktype != CRNG_IDENTIFIER)) { ERROR("Expecting a datatype prefix identifier here"); } else prefix = token->token; xmlParseCRNGDropTokens(ctxt, 1); token = xmlParseCRNGGetToken(ctxt, 1); if ((token->toktype != CRNG_OP) || (token->token[0] != '=') || (token->token[1] != 0)) { ERROR("Expecting keyword \"=\" here"); } xmlParseCRNGDropTokens(ctxt, 1); token = xmlParseCRNGGetToken(ctxt, 1); if (token->toktype == CRNG_LITERAL_SEGMENT) { namespace = token->token; } else { ERROR("Expecting a literal value for the datatype identifier"); } xmlParseCRNGDropTokens(ctxt, 1); if ((namespace != NULL) && (prefix != NULL)) xmlParseCRNG_bindDatatypePrefix(ctxt, prefix, namespace); } return(0); } /** * xmlParseCRNG_preamble: * @ctxt: a compact RNG parser context * * Parse preamble of the RELAX NG Compact Syntax Appendix A * * Returns 0 in case of success and -1 in case of error */ static int xmlParseCRNG_preamble(xmlCRelaxNGParserCtxtPtr ctxt) { tokenPtr token; token = xmlParseCRNGGetToken(ctxt, 1); while (token != NULL) { if (token == NULL) return(-1); if ((token->toktype == CRNG_KEYWORD) && ((token->token == ctxt->key_default) || (token->token == ctxt->key_namespace) || (token->token == ctxt->key_datatypes))) { xmlParseCRNG_decl(ctxt); } else break; token = xmlParseCRNGGetToken(ctxt, 1); } return(0); } /** * xmlParseCRNG_topLevel: * @ctxt: a compact RNG parser context * * Parse topLevel of the RELAX NG Compact Syntax Appendix A * * Returns 0 in case of success and -1 in case of error */ static int xmlParseCRNG_topLevel(xmlCRelaxNGParserCtxtPtr ctxt) { xmlParseCRNG_preamble(ctxt); xmlParseCRNG_topLevelBody(ctxt); return(0); } /** * 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"